diff options
author | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-09-08 01:45:47 -0400 |
commit | 64e47488c913ac704d465a6af86a26786d1412a5 (patch) | |
tree | d3b0148592963dcde26e4bb35ddfec8b1eaf8e23 /drivers/char | |
parent | 4a35a46bf1cda4737c428380d1db5d15e2590d18 (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) | |
download | kernel_samsung_smdk4412-64e47488c913ac704d465a6af86a26786d1412a5.zip kernel_samsung_smdk4412-64e47488c913ac704d465a6af86a26786d1412a5.tar.gz kernel_samsung_smdk4412-64e47488c913ac704d465a6af86a26786d1412a5.tar.bz2 |
Merge linux-2.6 with linux-acpi-2.6
Diffstat (limited to 'drivers/char')
38 files changed, 1794 insertions, 1939 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7333b41..2bc9d64 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -138,7 +138,7 @@ config CYZ_INTR config DIGIEPCA tristate "Digiboard Intelligent Async Support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN) + depends on SERIAL_NONSTANDARD ---help--- This is a driver for Digi International's Xx, Xeve, and Xem series of cards which provide multiple serial ports. You would need @@ -735,7 +735,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 + depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -842,8 +842,7 @@ config SONYPI config TANBAC_TB0219 tristate "TANBAC TB0219 base board support" - depends TANBAC_TB0229 - + depends TANBAC_TB022X menu "Ftape, the floppy tape device driver" diff --git a/drivers/char/digi1.h b/drivers/char/digi1.h index 184378d..94d4eab 100644 --- a/drivers/char/digi1.h +++ b/drivers/char/digi1.h @@ -1,46 +1,46 @@ /* Definitions for DigiBoard ditty(1) command. */ #if !defined(TIOCMODG) -#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */ -#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */ +#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */ +#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */ #endif #if !defined(TIOCMSET) -#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */ -#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */ +#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */ +#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */ #endif #if !defined(TIOCMBIC) -#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */ -#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */ +#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */ +#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */ #endif #if !defined(TIOCSDTR) -#define TIOCSDTR ('e'<<8) | 0 /* set DTR */ -#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */ +#define TIOCSDTR (('e'<<8) | 0) /* set DTR */ +#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */ #endif /************************************************************************ * Ioctl command arguments for DIGI parameters. ************************************************************************/ -#define DIGI_GETA ('e'<<8) | 94 /* Read params */ +#define DIGI_GETA (('e'<<8) | 94) /* Read params */ -#define DIGI_SETA ('e'<<8) | 95 /* Set params */ -#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */ -#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */ +#define DIGI_SETA (('e'<<8) | 95) /* Set params */ +#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */ +#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */ -#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */ +#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */ /* control characters */ -#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */ +#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */ /* control characters */ -#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */ +#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */ /* flow control chars */ -#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */ +#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */ /* flow control chars */ -#define DIGI_GETINFO ('e'<<8) | 103 /* Fill in digi_info */ -#define DIGI_POLLER ('e'<<8) | 104 /* Turn on/off poller */ -#define DIGI_INIT ('e'<<8) | 105 /* Allow things to run. */ +#define DIGI_GETINFO (('e'<<8) | 103) /* Fill in digi_info */ +#define DIGI_POLLER (('e'<<8) | 104) /* Turn on/off poller */ +#define DIGI_INIT (('e'<<8) | 105) /* Allow things to run. */ struct digiflow_struct { diff --git a/drivers/char/digiFep1.h b/drivers/char/digiFep1.h index c47d7fc..3c1f192 100644 --- a/drivers/char/digiFep1.h +++ b/drivers/char/digiFep1.h @@ -13,88 +13,88 @@ struct global_data { - volatile ushort cin; - volatile ushort cout; - volatile ushort cstart; - volatile ushort cmax; - volatile ushort ein; - volatile ushort eout; - volatile ushort istart; - volatile ushort imax; + u16 cin; + u16 cout; + u16 cstart; + u16 cmax; + u16 ein; + u16 eout; + u16 istart; + u16 imax; }; struct board_chan { - int filler1; - int filler2; - volatile ushort tseg; - volatile ushort tin; - volatile ushort tout; - volatile ushort tmax; - - volatile ushort rseg; - volatile ushort rin; - volatile ushort rout; - volatile ushort rmax; - - volatile ushort tlow; - volatile ushort rlow; - volatile ushort rhigh; - volatile ushort incr; - - volatile ushort etime; - volatile ushort edelay; - volatile unchar *dev; - - volatile ushort iflag; - volatile ushort oflag; - volatile ushort cflag; - volatile ushort gmask; - - volatile ushort col; - volatile ushort delay; - volatile ushort imask; - volatile ushort tflush; - - int filler3; - int filler4; - int filler5; - int filler6; - - volatile unchar num; - volatile unchar ract; - volatile unchar bstat; - volatile unchar tbusy; - volatile unchar iempty; - volatile unchar ilow; - volatile unchar idata; - volatile unchar eflag; - - volatile unchar tflag; - volatile unchar rflag; - volatile unchar xmask; - volatile unchar xval; - volatile unchar mstat; - volatile unchar mchange; - volatile unchar mint; - volatile unchar lstat; - - volatile unchar mtran; - volatile unchar orun; - volatile unchar startca; - volatile unchar stopca; - volatile unchar startc; - volatile unchar stopc; - volatile unchar vnext; - volatile unchar hflow; - - volatile unchar fillc; - volatile unchar ochar; - volatile unchar omask; - - unchar filler7; - unchar filler8[28]; + u32 filler1; + u32 filler2; + u16 tseg; + u16 tin; + u16 tout; + u16 tmax; + + u16 rseg; + u16 rin; + u16 rout; + u16 rmax; + + u16 tlow; + u16 rlow; + u16 rhigh; + u16 incr; + + u16 etime; + u16 edelay; + unchar *dev; + + u16 iflag; + u16 oflag; + u16 cflag; + u16 gmask; + + u16 col; + u16 delay; + u16 imask; + u16 tflush; + + u32 filler3; + u32 filler4; + u32 filler5; + u32 filler6; + + u8 num; + u8 ract; + u8 bstat; + u8 tbusy; + u8 iempty; + u8 ilow; + u8 idata; + u8 eflag; + + u8 tflag; + u8 rflag; + u8 xmask; + u8 xval; + u8 mstat; + u8 mchange; + u8 mint; + u8 lstat; + + u8 mtran; + u8 orun; + u8 startca; + u8 stopca; + u8 startc; + u8 stopc; + u8 vnext; + u8 hflow; + + u8 fillc; + u8 ochar; + u8 omask; + + u8 filler7; + u8 filler8[28]; }; diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index e0743eb..f28e70a 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -48,8 +48,8 @@ unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource) } EXPORT_SYMBOL(drm_get_resource_len); -static drm_local_map_t *drm_find_matching_map(drm_device_t *dev, - drm_local_map_t *map) +static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, + drm_local_map_t *map) { struct list_head *list; @@ -57,7 +57,7 @@ static drm_local_map_t *drm_find_matching_map(drm_device_t *dev, drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); if (entry->map && map->type == entry->map->type && entry->map->offset == map->offset) { - return entry->map; + return entry; } } @@ -114,14 +114,13 @@ static __inline__ unsigned int HandleID(unsigned long lhandle, drm_device_t *dev * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where * applicable and if supported by the kernel. */ -int drm_addmap(drm_device_t * dev, unsigned int offset, - unsigned int size, drm_map_type_t type, - drm_map_flags_t flags, drm_local_map_t ** map_ptr) +int drm_addmap_core(drm_device_t * dev, unsigned int offset, + unsigned int size, drm_map_type_t type, + drm_map_flags_t flags, drm_map_list_t **maplist) { drm_map_t *map; drm_map_list_t *list; drm_dma_handle_t *dmah; - drm_local_map_t *found_map; map = drm_alloc( sizeof(*map), DRM_MEM_MAPS ); if ( !map ) @@ -166,17 +165,17 @@ int drm_addmap(drm_device_t * dev, unsigned int offset, * needing to be aware of it. Therefore, we just return success * when the server tries to create a duplicate map. */ - found_map = drm_find_matching_map(dev, map); - if (found_map != NULL) { - if (found_map->size != map->size) { + list = drm_find_matching_map(dev, map); + if (list != NULL) { + if (list->map->size != map->size) { DRM_DEBUG("Matching maps of type %d with " "mismatched sizes, (%ld vs %ld)\n", - map->type, map->size, found_map->size); - found_map->size = map->size; + map->type, map->size, list->map->size); + list->map->size = map->size; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); - *map_ptr = found_map; + *maplist = list; return 0; } @@ -264,9 +263,22 @@ int drm_addmap(drm_device_t * dev, unsigned int offset, : map->offset, dev); up(&dev->struct_sem); - *map_ptr = map; + *maplist = list; return 0; } + +int drm_addmap(drm_device_t *dev, unsigned int offset, + unsigned int size, drm_map_type_t type, + drm_map_flags_t flags, drm_local_map_t **map_ptr) +{ + drm_map_list_t *list; + int rc; + + rc = drm_addmap_core(dev, offset, size, type, flags, &list); + if (!rc) + *map_ptr = list->map; + return rc; +} EXPORT_SYMBOL(drm_addmap); int drm_addmap_ioctl(struct inode *inode, struct file *filp, @@ -275,10 +287,9 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_map_t map; - drm_map_t *map_ptr; + drm_map_list_t *maplist; drm_map_t __user *argp = (void __user *)arg; int err; - unsigned long handle = 0; if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */ @@ -287,26 +298,15 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp, return -EFAULT; } - err = drm_addmap(dev, map.offset, map.size, map.type, map.flags, - &map_ptr); + err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags, + &maplist); - if (err) { + if (err) return err; - } - - { - drm_map_list_t *_entry; - list_for_each_entry(_entry, &dev->maplist->head, head) { - if (_entry->map == map_ptr) - handle = _entry->user_token; - } - if (!handle) - return -EFAULT; - } - if (copy_to_user(argp, map_ptr, sizeof(*map_ptr))) + if (copy_to_user(argp, maplist->map, sizeof(drm_map_t))) return -EFAULT; - if (put_user(handle, &argp->handle)) + if (put_user(maplist->user_token, &argp->handle)) return -EFAULT; return 0; } @@ -1041,7 +1041,7 @@ static int drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request) return 0; } -int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request) +static int drm_addbufs_fb(drm_device_t *dev, drm_buf_desc_t *request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c index f515567..5028927 100644 --- a/drivers/char/drm/drm_context.c +++ b/drivers/char/drm/drm_context.c @@ -308,7 +308,7 @@ found: * * Attempt to set drm_device::context_flag. */ -int drm_context_switch( drm_device_t *dev, int old, int new ) +static int drm_context_switch( drm_device_t *dev, int old, int new ) { if ( test_and_set_bit( 0, &dev->context_flag ) ) { DRM_ERROR( "Reentering -- FIXME\n" ); diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 2fc10c4..475cc5e 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -17,6 +17,7 @@ #include <linux/err.h> #include "drm_core.h" +#include "drmP.h" struct drm_sysfs_class { struct class_device_attribute attr; diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 567b425..fc7d4a5 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c @@ -417,6 +417,7 @@ int mga_driver_preinit(drm_device_t *dev, unsigned long flags) return 0; } +#if __OS_HAS_AGP /** * Bootstrap the driver for AGP DMA. * @@ -560,6 +561,13 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev, DRM_INFO("Initialized card for AGP DMA.\n"); return 0; } +#else +static int mga_do_agp_dma_bootstrap(drm_device_t * dev, + drm_mga_dma_bootstrap_t * dma_bs) +{ + return -EINVAL; +} +#endif /** * Bootstrap the driver for PCI DMA. @@ -697,7 +705,6 @@ static int mga_do_dma_bootstrap(drm_device_t * dev, * carve off portions of it for internal uses. The remaining memory * is returned to user-mode to be used for AGP textures. */ - if (is_agp) { err = mga_do_agp_dma_bootstrap(dev, dma_bs); } @@ -932,6 +939,7 @@ static int mga_do_cleanup_dma( drm_device_t *dev ) drm_core_ioremapfree(dev->agp_buffer_map, dev); if (dev_priv->used_new_dma_init) { +#if __OS_HAS_AGP if (dev_priv->agp_mem != NULL) { dev_priv->agp_textures = NULL; drm_unbind_agp(dev_priv->agp_mem); @@ -944,7 +952,7 @@ static int mga_do_cleanup_dma( drm_device_t *dev ) if ((dev->agp != NULL) && dev->agp->acquired) { err = drm_agp_release(dev); } - +#endif dev_priv->used_new_dma_init = 0; } @@ -965,7 +973,7 @@ static int mga_do_cleanup_dma( drm_device_t *dev ) } } - return 0; + return err; } int mga_dma_init( DRM_IOCTL_ARGS ) diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 6025e18..58d3738 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -6,6 +6,8 @@ For technical support please email digiLinux@dgii.com or call Digi tech support at (612) 912-3456 + ** This driver is no longer supported by Digi ** + Much of this design and code came from epca.c which was copyright (C) 1994, 1995 Troy De Jongh, and subsquently modified by David Nugent, Christoph Lameter, Mike McLagan. @@ -43,31 +45,19 @@ #include <linux/interrupt.h> #include <asm/uaccess.h> #include <asm/io.h> - -#ifdef CONFIG_PCI -#define ENABLE_PCI -#endif /* CONFIG_PCI */ - -#define putUser(arg1, arg2) put_user(arg1, (unsigned long __user *)arg2) -#define getUser(arg1, arg2) get_user(arg1, (unsigned __user *)arg2) - -#ifdef ENABLE_PCI +#include <linux/spinlock.h> #include <linux/pci.h> #include "digiPCI.h" -#endif /* ENABLE_PCI */ + #include "digi1.h" #include "digiFep1.h" #include "epca.h" #include "epcaconfig.h" -#if BITS_PER_LONG != 32 -# error FIXME: this driver only works on 32-bit platforms -#endif - /* ---------------------- Begin defines ------------------------ */ -#define VERSION "1.3.0.1-LK" +#define VERSION "1.3.0.1-LK2.6" /* This major needs to be submitted to Linux to join the majors list */ @@ -81,13 +71,17 @@ /* ----------------- Begin global definitions ------------------- */ -static char mesg[100]; static int nbdevs, num_cards, liloconfig; static int digi_poller_inhibited = 1 ; static int setup_error_code; static int invalid_lilo_config; +/* The ISA boards do window flipping into the same spaces so its only sane + with a single lock. It's still pretty efficient */ + +static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED; + /* ----------------------------------------------------------------------- MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. @@ -129,58 +123,58 @@ static struct timer_list epca_timer; configured. ----------------------------------------------------------------------- */ -static inline void memwinon(struct board_info *b, unsigned int win); -static inline void memwinoff(struct board_info *b, unsigned int win); -static inline void globalwinon(struct channel *ch); -static inline void rxwinon(struct channel *ch); -static inline void txwinon(struct channel *ch); -static inline void memoff(struct channel *ch); -static inline void assertgwinon(struct channel *ch); -static inline void assertmemoff(struct channel *ch); +static void memwinon(struct board_info *b, unsigned int win); +static void memwinoff(struct board_info *b, unsigned int win); +static void globalwinon(struct channel *ch); +static void rxwinon(struct channel *ch); +static void txwinon(struct channel *ch); +static void memoff(struct channel *ch); +static void assertgwinon(struct channel *ch); +static void assertmemoff(struct channel *ch); /* ---- Begin more 'specific' memory functions for cx_like products --- */ -static inline void pcxem_memwinon(struct board_info *b, unsigned int win); -static inline void pcxem_memwinoff(struct board_info *b, unsigned int win); -static inline void pcxem_globalwinon(struct channel *ch); -static inline void pcxem_rxwinon(struct channel *ch); -static inline void pcxem_txwinon(struct channel *ch); -static inline void pcxem_memoff(struct channel *ch); +static void pcxem_memwinon(struct board_info *b, unsigned int win); +static void pcxem_memwinoff(struct board_info *b, unsigned int win); +static void pcxem_globalwinon(struct channel *ch); +static void pcxem_rxwinon(struct channel *ch); +static void pcxem_txwinon(struct channel *ch); +static void pcxem_memoff(struct channel *ch); /* ------ Begin more 'specific' memory functions for the pcxe ------- */ -static inline void pcxe_memwinon(struct board_info *b, unsigned int win); -static inline void pcxe_memwinoff(struct board_info *b, unsigned int win); -static inline void pcxe_globalwinon(struct channel *ch); -static inline void pcxe_rxwinon(struct channel *ch); -static inline void pcxe_txwinon(struct channel *ch); -static inline void pcxe_memoff(struct channel *ch); +static void pcxe_memwinon(struct board_info *b, unsigned int win); +static void pcxe_memwinoff(struct board_info *b, unsigned int win); +static void pcxe_globalwinon(struct channel *ch); +static void pcxe_rxwinon(struct channel *ch); +static void pcxe_txwinon(struct channel *ch); +static void pcxe_memoff(struct channel *ch); /* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */ /* Note : pc64xe and pcxi share the same windowing routines */ -static inline void pcxi_memwinon(struct board_info *b, unsigned int win); -static inline void pcxi_memwinoff(struct board_info *b, unsigned int win); -static inline void pcxi_globalwinon(struct channel *ch); -static inline void pcxi_rxwinon(struct channel *ch); -static inline void pcxi_txwinon(struct channel *ch); -static inline void pcxi_memoff(struct channel *ch); +static void pcxi_memwinon(struct board_info *b, unsigned int win); +static void pcxi_memwinoff(struct board_info *b, unsigned int win); +static void pcxi_globalwinon(struct channel *ch); +static void pcxi_rxwinon(struct channel *ch); +static void pcxi_txwinon(struct channel *ch); +static void pcxi_memoff(struct channel *ch); /* - Begin 'specific' do nothing memory functions needed for some cards - */ -static inline void dummy_memwinon(struct board_info *b, unsigned int win); -static inline void dummy_memwinoff(struct board_info *b, unsigned int win); -static inline void dummy_globalwinon(struct channel *ch); -static inline void dummy_rxwinon(struct channel *ch); -static inline void dummy_txwinon(struct channel *ch); -static inline void dummy_memoff(struct channel *ch); -static inline void dummy_assertgwinon(struct channel *ch); -static inline void dummy_assertmemoff(struct channel *ch); +static void dummy_memwinon(struct board_info *b, unsigned int win); +static void dummy_memwinoff(struct board_info *b, unsigned int win); +static void dummy_globalwinon(struct channel *ch); +static void dummy_rxwinon(struct channel *ch); +static void dummy_txwinon(struct channel *ch); +static void dummy_memoff(struct channel *ch); +static void dummy_assertgwinon(struct channel *ch); +static void dummy_assertmemoff(struct channel *ch); /* ------------------- Begin declare functions ----------------------- */ -static inline struct channel *verifyChannel(register struct tty_struct *); -static inline void pc_sched_event(struct channel *, int); +static struct channel *verifyChannel(struct tty_struct *); +static void pc_sched_event(struct channel *, int); static void epca_error(int, char *); static void pc_close(struct tty_struct *, struct file *); static void shutdown(struct channel *); @@ -215,15 +209,11 @@ static void pc_unthrottle(struct tty_struct *tty); static void digi_send_break(struct channel *ch, int msec); static void setup_empty_event(struct tty_struct *tty, struct channel *ch); void epca_setup(char *, int *); -void console_print(const char *); static int get_termio(struct tty_struct *, struct termio __user *); static int pc_write(struct tty_struct *, const unsigned char *, int); -int pc_init(void); - -#ifdef ENABLE_PCI +static int pc_init(void); static int init_PCI(void); -#endif /* ENABLE_PCI */ /* ------------------------------------------------------------------ @@ -237,41 +227,41 @@ static int init_PCI(void); making direct calls deserves what they get. -------------------------------------------------------------------- */ -static inline void memwinon(struct board_info *b, unsigned int win) +static void memwinon(struct board_info *b, unsigned int win) { (b->memwinon)(b, win); } -static inline void memwinoff(struct board_info *b, unsigned int win) +static void memwinoff(struct board_info *b, unsigned int win) { (b->memwinoff)(b, win); } -static inline void globalwinon(struct channel *ch) +static void globalwinon(struct channel *ch) { (ch->board->globalwinon)(ch); } -static inline void rxwinon(struct channel *ch) +static void rxwinon(struct channel *ch) { (ch->board->rxwinon)(ch); } -static inline void txwinon(struct channel *ch) +static void txwinon(struct channel *ch) { (ch->board->txwinon)(ch); } -static inline void memoff(struct channel *ch) +static void memoff(struct channel *ch) { (ch->board->memoff)(ch); } -static inline void assertgwinon(struct channel *ch) +static void assertgwinon(struct channel *ch) { (ch->board->assertgwinon)(ch); } -static inline void assertmemoff(struct channel *ch) +static void assertmemoff(struct channel *ch) { (ch->board->assertmemoff)(ch); } @@ -281,66 +271,66 @@ static inline void assertmemoff(struct channel *ch) and CX series cards. ------------------------------------------------------------ */ -static inline void pcxem_memwinon(struct board_info *b, unsigned int win) +static void pcxem_memwinon(struct board_info *b, unsigned int win) { - outb_p(FEPWIN|win, (int)b->port + 1); + outb_p(FEPWIN|win, b->port + 1); } -static inline void pcxem_memwinoff(struct board_info *b, unsigned int win) +static void pcxem_memwinoff(struct board_info *b, unsigned int win) { - outb_p(0, (int)b->port + 1); + outb_p(0, b->port + 1); } -static inline void pcxem_globalwinon(struct channel *ch) +static void pcxem_globalwinon(struct channel *ch) { outb_p( FEPWIN, (int)ch->board->port + 1); } -static inline void pcxem_rxwinon(struct channel *ch) +static void pcxem_rxwinon(struct channel *ch) { outb_p(ch->rxwin, (int)ch->board->port + 1); } -static inline void pcxem_txwinon(struct channel *ch) +static void pcxem_txwinon(struct channel *ch) { outb_p(ch->txwin, (int)ch->board->port + 1); } -static inline void pcxem_memoff(struct channel *ch) +static void pcxem_memoff(struct channel *ch) { outb_p(0, (int)ch->board->port + 1); } /* ----------------- Begin pcxe memory window stuff ------------------ */ -static inline void pcxe_memwinon(struct board_info *b, unsigned int win) +static void pcxe_memwinon(struct board_info *b, unsigned int win) { - outb_p(FEPWIN | win, (int)b->port + 1); + outb_p(FEPWIN | win, b->port + 1); } -static inline void pcxe_memwinoff(struct board_info *b, unsigned int win) +static void pcxe_memwinoff(struct board_info *b, unsigned int win) { - outb_p(inb((int)b->port) & ~FEPMEM, - (int)b->port + 1); - outb_p(0, (int)b->port + 1); + outb_p(inb(b->port) & ~FEPMEM, + b->port + 1); + outb_p(0, b->port + 1); } -static inline void pcxe_globalwinon(struct channel *ch) +static void pcxe_globalwinon(struct channel *ch) { outb_p( FEPWIN, (int)ch->board->port + 1); } -static inline void pcxe_rxwinon(struct channel *ch) +static void pcxe_rxwinon(struct channel *ch) { outb_p(ch->rxwin, (int)ch->board->port + 1); } -static inline void pcxe_txwinon(struct channel *ch) +static void pcxe_txwinon(struct channel *ch) { outb_p(ch->txwin, (int)ch->board->port + 1); } -static inline void pcxe_memoff(struct channel *ch) +static void pcxe_memoff(struct channel *ch) { outb_p(0, (int)ch->board->port); outb_p(0, (int)ch->board->port + 1); @@ -348,44 +338,44 @@ static inline void pcxe_memoff(struct channel *ch) /* ------------- Begin pc64xe and pcxi memory window stuff -------------- */ -static inline void pcxi_memwinon(struct board_info *b, unsigned int win) +static void pcxi_memwinon(struct board_info *b, unsigned int win) { - outb_p(inb((int)b->port) | FEPMEM, (int)b->port); + outb_p(inb(b->port) | FEPMEM, b->port); } -static inline void pcxi_memwinoff(struct board_info *b, unsigned int win) +static void pcxi_memwinoff(struct board_info *b, unsigned int win) { - outb_p(inb((int)b->port) & ~FEPMEM, (int)b->port); + outb_p(inb(b->port) & ~FEPMEM, b->port); } -static inline void pcxi_globalwinon(struct channel *ch) +static void pcxi_globalwinon(struct channel *ch) { - outb_p(FEPMEM, (int)ch->board->port); + outb_p(FEPMEM, ch->board->port); } -static inline void pcxi_rxwinon(struct channel *ch) +static void pcxi_rxwinon(struct channel *ch) { - outb_p(FEPMEM, (int)ch->board->port); + outb_p(FEPMEM, ch->board->port); } -static inline void pcxi_txwinon(struct channel *ch) +static void pcxi_txwinon(struct channel *ch) { - outb_p(FEPMEM, (int)ch->board->port); + outb_p(FEPMEM, ch->board->port); } -static inline void pcxi_memoff(struct channel *ch) +static void pcxi_memoff(struct channel *ch) { - outb_p(0, (int)ch->board->port); + outb_p(0, ch->board->port); } -static inline void pcxi_assertgwinon(struct channel *ch) +static void pcxi_assertgwinon(struct channel *ch) { - epcaassert(inb((int)ch->board->port) & FEPMEM, "Global memory off"); + epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off"); } -static inline void pcxi_assertmemoff(struct channel *ch) +static void pcxi_assertmemoff(struct channel *ch) { - epcaassert(!(inb((int)ch->board->port) & FEPMEM), "Memory on"); + epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on"); } @@ -398,185 +388,143 @@ static inline void pcxi_assertmemoff(struct channel *ch) may or may not do anything. ---------------------------------------------------------------------------*/ -static inline void dummy_memwinon(struct board_info *b, unsigned int win) +static void dummy_memwinon(struct board_info *b, unsigned int win) { } -static inline void dummy_memwinoff(struct board_info *b, unsigned int win) +static void dummy_memwinoff(struct board_info *b, unsigned int win) { } -static inline void dummy_globalwinon(struct channel *ch) +static void dummy_globalwinon(struct channel *ch) { } -static inline void dummy_rxwinon(struct channel *ch) +static void dummy_rxwinon(struct channel *ch) { } -static inline void dummy_txwinon(struct channel *ch) +static void dummy_txwinon(struct channel *ch) { } -static inline void dummy_memoff(struct channel *ch) +static void dummy_memoff(struct channel *ch) { } -static inline void dummy_assertgwinon(struct channel *ch) +static void dummy_assertgwinon(struct channel *ch) { } -static inline void dummy_assertmemoff(struct channel *ch) +static void dummy_assertmemoff(struct channel *ch) { } /* ----------------- Begin verifyChannel function ----------------------- */ -static inline struct channel *verifyChannel(register struct tty_struct *tty) +static struct channel *verifyChannel(struct tty_struct *tty) { /* Begin verifyChannel */ - /* -------------------------------------------------------------------- This routine basically provides a sanity check. It insures that the channel returned is within the proper range of addresses as well as properly initialized. If some bogus info gets passed in through tty->driver_data this should catch it. - --------------------------------------------------------------------- */ - - if (tty) - { /* Begin if tty */ - - register struct channel *ch = (struct channel *)tty->driver_data; - - if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) - { + --------------------------------------------------------------------- */ + if (tty) { + struct channel *ch = (struct channel *)tty->driver_data; + if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) { if (ch->magic == EPCA_MAGIC) return ch; } - - } /* End if tty */ - - /* Else return a NULL for invalid */ + } return NULL; } /* End verifyChannel */ /* ------------------ Begin pc_sched_event ------------------------- */ -static inline void pc_sched_event(struct channel *ch, int event) -{ /* Begin pc_sched_event */ - - +static void pc_sched_event(struct channel *ch, int event) +{ /* ---------------------------------------------------------------------- We call this to schedule interrupt processing on some event. The kernel sees our request and calls the related routine in OUR driver. -------------------------------------------------------------------------*/ - ch->event |= 1 << event; schedule_work(&ch->tqueue); - - } /* End pc_sched_event */ /* ------------------ Begin epca_error ------------------------- */ static void epca_error(int line, char *msg) -{ /* Begin epca_error */ - +{ printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg); - return; - -} /* End epca_error */ +} /* ------------------ Begin pc_close ------------------------- */ static void pc_close(struct tty_struct * tty, struct file * filp) -{ /* Begin pc_close */ - +{ struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if ch != NULL */ - - save_flags(flags); - cli(); - - if (tty_hung_up_p(filp)) - { - restore_flags(flags); + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */ + spin_lock_irqsave(&epca_lock, flags); + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&epca_lock, flags); return; } - /* Check to see if the channel is open more than once */ - if (ch->count-- > 1) - { /* Begin channel is open more than once */ - + if (ch->count-- > 1) { + /* Begin channel is open more than once */ /* ------------------------------------------------------------- Return without doing anything. Someone might still be using the channel. ---------------------------------------------------------------- */ - - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); return; } /* End channel is open more than once */ /* Port open only once go ahead with shutdown & reset */ - - if (ch->count < 0) - { - ch->count = 0; - } + if (ch->count < 0) + BUG(); /* --------------------------------------------------------------- Let the rest of the driver know the channel is being closed. This becomes important if an open is attempted before close is finished. ------------------------------------------------------------------ */ - ch->asyncflags |= ASYNC_CLOSING; - tty->closing = 1; - if (ch->asyncflags & ASYNC_INITIALIZED) - { + spin_unlock_irqrestore(&epca_lock, flags); + + if (ch->asyncflags & ASYNC_INITIALIZED) { /* Setup an event to indicate when the transmit buffer empties */ setup_empty_event(tty, ch); tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ } - if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); shutdown(ch); + + spin_lock_irqsave(&epca_lock, flags); tty->closing = 0; ch->event = 0; ch->tty = NULL; + spin_unlock_irqrestore(&epca_lock, flags); - if (ch->blocked_open) - { /* Begin if blocked_open */ - + if (ch->blocked_open) { /* Begin if blocked_open */ if (ch->close_delay) - { msleep_interruptible(jiffies_to_msecs(ch->close_delay)); - } - wake_up_interruptible(&ch->open_wait); - } /* End if blocked_open */ - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); - - - restore_flags(flags); - } /* End if ch != NULL */ - } /* End pc_close */ /* ------------------ Begin shutdown ------------------------- */ @@ -586,15 +534,14 @@ static void shutdown(struct channel *ch) unsigned long flags; struct tty_struct *tty; - volatile struct board_chan *bc; + struct board_chan *bc; if (!(ch->asyncflags & ASYNC_INITIALIZED)) return; - save_flags(flags); - cli(); - globalwinon(ch); + spin_lock_irqsave(&epca_lock, flags); + globalwinon(ch); bc = ch->brdchan; /* ------------------------------------------------------------------ @@ -604,20 +551,17 @@ static void shutdown(struct channel *ch) --------------------------------------------------------------------- */ if (bc) - bc->idata = 0; - + writeb(0, &bc->idata); tty = ch->tty; /* ---------------------------------------------------------------- If we're a modem control device and HUPCL is on, drop RTS & DTR. ------------------------------------------------------------------ */ - if (tty->termios->c_cflag & HUPCL) - { + if (tty->termios->c_cflag & HUPCL) { ch->omodem &= ~(ch->m_rts | ch->m_dtr); fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1); } - memoff(ch); /* ------------------------------------------------------------------ @@ -628,7 +572,7 @@ static void shutdown(struct channel *ch) /* Prevent future Digi programmed interrupts from coming active */ ch->asyncflags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); } /* End shutdown */ @@ -636,7 +580,6 @@ static void shutdown(struct channel *ch) static void pc_hangup(struct tty_struct *tty) { /* Begin pc_hangup */ - struct channel *ch; /* --------------------------------------------------------- @@ -644,25 +587,21 @@ static void pc_hangup(struct tty_struct *tty) if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if ch != NULL */ - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */ unsigned long flags; - save_flags(flags); - cli(); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); shutdown(ch); + spin_lock_irqsave(&epca_lock, flags); ch->tty = NULL; ch->event = 0; ch->count = 0; - restore_flags(flags); ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); + spin_unlock_irqrestore(&epca_lock, flags); wake_up_interruptible(&ch->open_wait); - } /* End if ch != NULL */ } /* End pc_hangup */ @@ -672,18 +611,14 @@ static void pc_hangup(struct tty_struct *tty) static int pc_write(struct tty_struct * tty, const unsigned char *buf, int bytesAvailable) { /* Begin pc_write */ - - register unsigned int head, tail; - register int dataLen; - register int size; - register int amountCopied; - - + unsigned int head, tail; + int dataLen; + int size; + int amountCopied; struct channel *ch; unsigned long flags; int remain; - volatile struct board_chan *bc; - + struct board_chan *bc; /* ---------------------------------------------------------------- pc_write is primarily called directly by the kernel routine @@ -706,24 +641,20 @@ static int pc_write(struct tty_struct * tty, bc = ch->brdchan; size = ch->txbufsize; - amountCopied = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - head = bc->tin & (size - 1); - tail = bc->tout; + head = readw(&bc->tin) & (size - 1); + tail = readw(&bc->tout); - if (tail != bc->tout) - tail = bc->tout; + if (tail != readw(&bc->tout)) + tail = readw(&bc->tout); tail &= (size - 1); /* If head >= tail, head has not wrapped around. */ - if (head >= tail) - { /* Begin head has not wrapped */ - + if (head >= tail) { /* Begin head has not wrapped */ /* --------------------------------------------------------------- remain (much like dataLen above) represents the total amount of space available on the card for data. Here dataLen represents @@ -731,26 +662,19 @@ static int pc_write(struct tty_struct * tty, buffer. This is important because a memcpy cannot be told to automatically wrap around when it hits the buffer end. ------------------------------------------------------------------ */ - dataLen = size - head; remain = size - (head - tail) - 1; - - } /* End head has not wrapped */ - else - { /* Begin head has wrapped around */ + } else { /* Begin head has wrapped around */ remain = tail - head - 1; dataLen = remain; } /* End head has wrapped around */ - /* ------------------------------------------------------------------- Check the space on the card. If we have more data than space; reduce the amount of data to fit the space. ---------------------------------------------------------------------- */ - bytesAvailable = min(remain, bytesAvailable); - txwinon(ch); while (bytesAvailable > 0) { /* Begin while there is data to copy onto card */ @@ -767,26 +691,21 @@ static int pc_write(struct tty_struct * tty, amountCopied += dataLen; bytesAvailable -= dataLen; - if (head >= size) - { + if (head >= size) { head = 0; dataLen = tail; } - } /* End while there is data to copy onto card */ - ch->statusflags |= TXBUSY; globalwinon(ch); - bc->tin = head; + writew(head, &bc->tin); - if ((ch->statusflags & LOWWAIT) == 0) - { + if ((ch->statusflags & LOWWAIT) == 0) { ch->statusflags |= LOWWAIT; - bc->ilow = 1; + writeb(1, &bc->ilow); } memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); return(amountCopied); } /* End pc_write */ @@ -795,11 +714,7 @@ static int pc_write(struct tty_struct * tty, static void pc_put_char(struct tty_struct *tty, unsigned char c) { /* Begin pc_put_char */ - - pc_write(tty, &c, 1); - return; - } /* End pc_put_char */ /* ------------------ Begin pc_write_room ------------------------- */ @@ -811,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty) struct channel *ch; unsigned long flags; unsigned int head, tail; - volatile struct board_chan *bc; + struct board_chan *bc; remain = 0; @@ -820,33 +735,29 @@ static int pc_write_room(struct tty_struct *tty) if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - if ((ch = verifyChannel(tty)) != NULL) - { - save_flags(flags); - cli(); + if ((ch = verifyChannel(tty)) != NULL) { + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); bc = ch->brdchan; - head = bc->tin & (ch->txbufsize - 1); - tail = bc->tout; + head = readw(&bc->tin) & (ch->txbufsize - 1); + tail = readw(&bc->tout); - if (tail != bc->tout) - tail = bc->tout; + if (tail != readw(&bc->tout)) + tail = readw(&bc->tout); /* Wrap tail if necessary */ tail &= (ch->txbufsize - 1); if ((remain = tail - head - 1) < 0 ) remain += ch->txbufsize; - if (remain && (ch->statusflags & LOWWAIT) == 0) - { + if (remain && (ch->statusflags & LOWWAIT) == 0) { ch->statusflags |= LOWWAIT; - bc->ilow = 1; + writeb(1, &bc->ilow); } memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); } - /* Return how much room is left on card */ return remain; @@ -862,8 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) int remain; unsigned long flags; struct channel *ch; - volatile struct board_chan *bc; - + struct board_chan *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct @@ -873,34 +783,27 @@ static int pc_chars_in_buffer(struct tty_struct *tty) if ((ch = verifyChannel(tty)) == NULL) return(0); - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); bc = ch->brdchan; - tail = bc->tout; - head = bc->tin; - ctail = ch->mailbox->cout; + tail = readw(&bc->tout); + head = readw(&bc->tin); + ctail = readw(&ch->mailbox->cout); - if (tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0) + if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0) chars = 0; - else - { /* Begin if some space on the card has been used */ - - head = bc->tin & (ch->txbufsize - 1); + else { /* Begin if some space on the card has been used */ + head = readw(&bc->tin) & (ch->txbufsize - 1); tail &= (ch->txbufsize - 1); - /* -------------------------------------------------------------- The logic here is basically opposite of the above pc_write_room here we are finding the amount of bytes in the buffer filled. Not the amount of bytes empty. ------------------------------------------------------------------- */ - if ((remain = tail - head - 1) < 0 ) remain += ch->txbufsize; - chars = (int)(ch->txbufsize - remain); - /* ------------------------------------------------------------- Make it possible to wakeup anything waiting for output in tty_ioctl.c, etc. @@ -908,15 +811,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty) If not already set. Setup an event to indicate when the transmit buffer empties ----------------------------------------------------------------- */ - if (!(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty,ch); } /* End if some space on the card has been used */ - memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); /* Return number of characters residing on card. */ return(chars); @@ -930,67 +830,46 @@ static void pc_flush_buffer(struct tty_struct *tty) unsigned int tail; unsigned long flags; struct channel *ch; - volatile struct board_chan *bc; - - + struct board_chan *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - if ((ch = verifyChannel(tty)) == NULL) return; - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - bc = ch->brdchan; - tail = bc->tout; - + tail = readw(&bc->tout); /* Have FEP move tout pointer; effectively flushing transmit buffer */ - fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0); - memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); - } /* End pc_flush_buffer */ /* ------------------ Begin pc_flush_chars ---------------------- */ static void pc_flush_chars(struct tty_struct *tty) { /* Begin pc_flush_chars */ - struct channel * ch; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { + if ((ch = verifyChannel(tty)) != NULL) { unsigned long flags; - - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); /* ---------------------------------------------------------------- If not already set and the transmitter is busy setup an event to indicate when the transmit empties. ------------------------------------------------------------------- */ - if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty,ch); - - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); } - } /* End pc_flush_chars */ /* ------------------ Begin block_til_ready ---------------------- */ @@ -998,14 +877,11 @@ static void pc_flush_chars(struct tty_struct *tty) static int block_til_ready(struct tty_struct *tty, struct file *filp, struct channel *ch) { /* Begin block_til_ready */ - DECLARE_WAITQUEUE(wait,current); int retval, do_clocal = 0; unsigned long flags; - - if (tty_hung_up_p(filp)) - { + if (tty_hung_up_p(filp)) { if (ch->asyncflags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else @@ -1017,8 +893,7 @@ static int block_til_ready(struct tty_struct *tty, If the device is in the middle of being closed, then block until it's done, and then try again. -------------------------------------------------------------------- */ - if (ch->asyncflags & ASYNC_CLOSING) - { + if (ch->asyncflags & ASYNC_CLOSING) { interruptible_sleep_on(&ch->close_wait); if (ch->asyncflags & ASYNC_HUP_NOTIFY) @@ -1027,43 +902,29 @@ static int block_til_ready(struct tty_struct *tty, return -ERESTARTSYS; } - if (filp->f_flags & O_NONBLOCK) - { + if (filp->f_flags & O_NONBLOCK) { /* ----------------------------------------------------------------- If non-blocking mode is set, then make the check up front and then exit. -------------------------------------------------------------------- */ - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return 0; } - - if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; - - /* Block waiting for the carrier detect and the line to become free */ + /* Block waiting for the carrier detect and the line to become free */ retval = 0; add_wait_queue(&ch->open_wait, &wait); - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); /* We dec count so that pc_close will know when to free things */ if (!tty_hung_up_p(filp)) ch->count--; - - restore_flags(flags); - ch->blocked_open++; - while(1) { /* Begin forever while */ - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || !(ch->asyncflags & ASYNC_INITIALIZED)) { @@ -1073,17 +934,14 @@ static int block_til_ready(struct tty_struct *tty, retval = -ERESTARTSYS; break; } - if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || (ch->imodem & ch->dcd))) break; - - if (signal_pending(current)) - { + if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - + spin_unlock_irqrestore(&epca_lock, flags); /* --------------------------------------------------------------- Allow someone else to be scheduled. We will occasionally go through this loop until one of the above conditions change. @@ -1091,25 +949,23 @@ static int block_til_ready(struct tty_struct *tty, prevent this loop from hogging the cpu. ------------------------------------------------------------------ */ schedule(); + spin_lock_irqsave(&epca_lock, flags); } /* End forever while */ current->state = TASK_RUNNING; remove_wait_queue(&ch->open_wait, &wait); - cli(); if (!tty_hung_up_p(filp)) ch->count++; - restore_flags(flags); - ch->blocked_open--; + spin_unlock_irqrestore(&epca_lock, flags); + if (retval) return retval; ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return 0; - } /* End block_til_ready */ /* ------------------ Begin pc_open ---------------------- */ @@ -1120,17 +976,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp) struct channel *ch; unsigned long flags; int line, retval, boardnum; - volatile struct board_chan *bc; - volatile unsigned int head; + struct board_chan *bc; + unsigned int head; line = tty->index; - if (line < 0 || line >= nbdevs) - { - printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n"); - tty->driver_data = NULL; - return(-ENODEV); - } - + if (line < 0 || line >= nbdevs) + return -ENODEV; ch = &digi_channels[line]; boardnum = ch->boardnum; @@ -1143,66 +994,49 @@ static int pc_open(struct tty_struct *tty, struct file * filp) goes here. ---------------------------------------------------------------------- */ - if (invalid_lilo_config) - { + if (invalid_lilo_config) { if (setup_error_code & INVALID_BOARD_TYPE) - printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n"); if (setup_error_code & INVALID_NUM_PORTS) - printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n"); if (setup_error_code & INVALID_MEM_BASE) - printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n"); if (setup_error_code & INVALID_PORT_BASE) - printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n"); - + printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n"); if (setup_error_code & INVALID_BOARD_STATUS) - printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n"); if (setup_error_code & INVALID_ALTPIN) - printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n"); - + printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n"); tty->driver_data = NULL; /* Mark this device as 'down' */ - return(-ENODEV); + return -ENODEV; } - - if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) - { + if (boardnum >= num_cards || boards[boardnum].status == DISABLED) { tty->driver_data = NULL; /* Mark this device as 'down' */ return(-ENODEV); } - if (( bc = ch->brdchan) == 0) - { + if ((bc = ch->brdchan) == 0) { tty->driver_data = NULL; - return(-ENODEV); + return -ENODEV; } + spin_lock_irqsave(&epca_lock, flags); /* ------------------------------------------------------------------ Every time a channel is opened, increment a counter. This is necessary because we do not wish to flush and shutdown the channel until the last app holding the channel open, closes it. --------------------------------------------------------------------- */ - ch->count++; - /* ---------------------------------------------------------------- Set a kernel structures pointer to our local channel structure. This way we can get to it when passed only a tty struct. ------------------------------------------------------------------ */ - tty->driver_data = ch; - /* ---------------------------------------------------------------- If this is the first time the channel has been opened, initialize the tty->termios struct otherwise let pc_close handle it. -------------------------------------------------------------------- */ - - save_flags(flags); - cli(); - globalwinon(ch); ch->statusflags = 0; @@ -1213,8 +1047,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp) Set receive head and tail ptrs to each other. This indicates no data available to read. ----------------------------------------------------------------- */ - head = bc->rin; - bc->rout = head; + head = readw(&bc->rin); + writew(head, &bc->rout); /* Set the channels associated tty structure */ ch->tty = tty; @@ -1224,122 +1058,74 @@ static int pc_open(struct tty_struct *tty, struct file * filp) issues, etc.... It effect both control flags and input flags. -------------------------------------------------------------------- */ epcaparam(tty,ch); - ch->asyncflags |= ASYNC_INITIALIZED; memoff(ch); - - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); retval = block_til_ready(tty, filp, ch); if (retval) - { return retval; - } - /* ------------------------------------------------------------- Set this again in case a hangup set it to zero while this open() was waiting for the line... --------------------------------------------------------------- */ + spin_lock_irqsave(&epca_lock, flags); ch->tty = tty; - - save_flags(flags); - cli(); globalwinon(ch); - /* Enable Digi Data events */ - bc->idata = 1; - + writeb(1, &bc->idata); memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); return 0; - } /* End pc_open */ -#ifdef MODULE static int __init epca_module_init(void) { /* Begin init_module */ - - unsigned long flags; - - save_flags(flags); - cli(); - - pc_init(); - - restore_flags(flags); - - return(0); + return pc_init(); } module_init(epca_module_init); -#endif -#ifdef ENABLE_PCI static struct pci_driver epca_driver; -#endif - -#ifdef MODULE -/* -------------------- Begin cleanup_module ---------------------- */ static void __exit epca_module_exit(void) { - int count, crd; struct board_info *bd; struct channel *ch; - unsigned long flags; del_timer_sync(&epca_timer); - save_flags(flags); - cli(); - if ((tty_unregister_driver(pc_driver)) || (tty_unregister_driver(pc_info))) { - printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n"); - restore_flags(flags); + printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n"); return; } put_tty_driver(pc_driver); put_tty_driver(pc_info); - for (crd = 0; crd < num_cards; crd++) - { /* Begin for each card */ - + for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ bd = &boards[crd]; - if (!bd) { /* Begin sanity check */ printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n"); return; } /* End sanity check */ - - ch = card_ptr[crd]; - + ch = card_ptr[crd]; for (count = 0; count < bd->numports; count++, ch++) { /* Begin for each port */ - - if (ch) - { + if (ch) { if (ch->tty) tty_hangup(ch->tty); kfree(ch->tmp_buf); } - } /* End for each port */ } /* End for each card */ - -#ifdef ENABLE_PCI pci_unregister_driver (&epca_driver); -#endif - - restore_flags(flags); - } + module_exit(epca_module_exit); -#endif /* MODULE */ static struct tty_operations pc_ops = { .open = pc_open, @@ -1371,34 +1157,15 @@ static struct tty_operations info_ops = { /* ------------------ Begin pc_init ---------------------- */ -int __init pc_init(void) +static int __init pc_init(void) { /* Begin pc_init */ - - /* ---------------------------------------------------------------- - pc_init is called by the operating system during boot up prior to - any open calls being made. In the older versions of Linux (Prior - to 2.0.0) an entry is made into tty_io.c. A pointer to the last - memory location (from kernel space) used (kmem_start) is passed - to pc_init. It is pc_inits responsibility to modify this value - for any memory that the Digi driver might need and then return - this value to the operating system. For example if the driver - wishes to allocate 1K of kernel memory, pc_init would return - (kmem_start + 1024). This memory (Between kmem_start and kmem_start - + 1024) would then be available for use exclusively by the driver. - In this case our driver does not allocate any of this kernel - memory. - ------------------------------------------------------------------*/ - - ulong flags; int crd; struct board_info *bd; unsigned char board_id = 0; -#ifdef ENABLE_PCI int pci_boards_found, pci_count; pci_count = 0; -#endif /* ENABLE_PCI */ pc_driver = alloc_tty_driver(MAX_ALLOC); if (!pc_driver) @@ -1416,8 +1183,7 @@ int __init pc_init(void) Note : If LILO has ran epca_setup then epca_setup will handle defining num_cards as well as copying the data into the board structure. -------------------------------------------------------------------------- */ - if (!liloconfig) - { /* Begin driver has been configured via. epcaconfig */ + if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */ nbdevs = NBDEVS; num_cards = NUMCARDS; @@ -1440,8 +1206,6 @@ int __init pc_init(void) printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION); -#ifdef ENABLE_PCI - /* ------------------------------------------------------------------ NOTE : This code assumes that the number of ports found in the boards array is correct. This could be wrong if @@ -1467,8 +1231,6 @@ int __init pc_init(void) pci_boards_found += init_PCI(); num_cards += pci_boards_found; -#endif /* ENABLE_PCI */ - pc_driver->owner = THIS_MODULE; pc_driver->name = "ttyD"; pc_driver->devfs_name = "tts/D"; @@ -1499,9 +1261,6 @@ int __init pc_init(void) tty_set_operations(pc_info, &info_ops); - save_flags(flags); - cli(); - for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ @@ -1610,11 +1369,7 @@ int __init pc_init(void) if ((board_id & 0x30) == 0x30) bd->memory_seg = 0x8000; - } /* End it is an XI card */ - else - { - printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); - } + } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); break; } /* End switch on bd->type */ @@ -1634,9 +1389,6 @@ int __init pc_init(void) init_timer(&epca_timer); epca_timer.function = epcapoll; mod_timer(&epca_timer, jiffies + HZ/25); - - restore_flags(flags); - return 0; } /* End pc_init */ @@ -1647,10 +1399,10 @@ static void post_fep_init(unsigned int crd) { /* Begin post_fep_init */ int i; - unchar *memaddr; - volatile struct global_data *gd; + unsigned char *memaddr; + struct global_data *gd; struct board_info *bd; - volatile struct board_chan *bc; + struct board_chan *bc; struct channel *ch; int shrinkmem = 0, lowwater ; @@ -1669,9 +1421,7 @@ static void post_fep_init(unsigned int crd) after DIGI_INIT has been called will return the proper values. ------------------------------------------------------------------- */ - if (bd->type >= PCIXEM) /* If the board in question is PCI */ - { /* Begin get PCI number of ports */ - + if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */ /* -------------------------------------------------------------------- Below we use XEMPORTS as a memory offset regardless of which PCI card it is. This is because all of the supported PCI cards have @@ -1685,15 +1435,15 @@ static void post_fep_init(unsigned int crd) (FYI - The id should be located at 0x1ac (And may use up to 4 bytes if the box in question is a XEM or CX)). ------------------------------------------------------------------------ */ - - bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long) - (bd->re_map_membase + XEMPORTS)); - - + /* PCI cards are already remapped at this point ISA are not */ + bd->numports = readw(bd->re_map_membase + XEMPORTS); epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); nbdevs += (bd->numports); - - } /* End get PCI number of ports */ + } else { + /* Fix up the mappings for ISA/EISA etc */ + /* FIXME: 64K - can we be smarter ? */ + bd->re_map_membase = ioremap(bd->membase, 0x10000); + } if (crd != 0) card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports; @@ -1701,19 +1451,9 @@ static void post_fep_init(unsigned int crd) card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */ ch = card_ptr[crd]; - - epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range"); - memaddr = (unchar *)bd->re_map_membase; - - /* - The below command is necessary because newer kernels (2.1.x and - up) do not have a 1:1 virtual to physical mapping. The below - call adjust for that. - */ - - memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); + memaddr = bd->re_map_membase; /* ----------------------------------------------------------------- The below assignment will set bc to point at the BEGINING of @@ -1721,7 +1461,7 @@ static void post_fep_init(unsigned int crd) 8 and 64 of these structures. -------------------------------------------------------------------- */ - bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT); + bc = (struct board_chan *)(memaddr + CHANSTRUCT); /* ------------------------------------------------------------------- The below assignment will set gd to point at the BEGINING of @@ -1730,20 +1470,18 @@ static void post_fep_init(unsigned int crd) pointer begins at 0xd10. ---------------------------------------------------------------------- */ - gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL); + gd = (struct global_data *)(memaddr + GLOBAL); /* -------------------------------------------------------------------- XEPORTS (address 0xc22) points at the number of channels the card supports. (For 64XE, XI, XEM, and XR use 0xc02) ----------------------------------------------------------------------- */ - if (((bd->type == PCXEVE) | (bd->type == PCXE)) && - (*(ushort *)((ulong)memaddr + XEPORTS) < 3)) + if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3)) shrinkmem = 1; if (bd->type < PCIXEM) if (!request_region((int)bd->port, 4, board_desc[bd->type])) return; - memwinon(bd, 0); /* -------------------------------------------------------------------- @@ -1753,17 +1491,16 @@ static void post_fep_init(unsigned int crd) /* For every port on the card do ..... */ - for (i = 0; i < bd->numports; i++, ch++, bc++) - { /* Begin for each port */ + for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ + unsigned long flags; ch->brdchan = bc; ch->mailbox = gd; INIT_WORK(&ch->tqueue, do_softint, ch); ch->board = &boards[crd]; - switch (bd->type) - { /* Begin switch bd->type */ - + spin_lock_irqsave(&epca_lock, flags); + switch (bd->type) { /* ---------------------------------------------------------------- Since some of the boards use different bitmaps for their control signals we cannot hard code these values and retain @@ -1796,14 +1533,12 @@ static void post_fep_init(unsigned int crd) } /* End switch bd->type */ - if (boards[crd].altpin) - { + if (boards[crd].altpin) { ch->dsr = ch->m_dcd; ch->dcd = ch->m_dsr; ch->digiext.digi_flags |= DIGI_ALTPIN; } - else - { + else { ch->dcd = ch->m_dcd; ch->dsr = ch->m_dsr; } @@ -1813,14 +1548,12 @@ static void post_fep_init(unsigned int crd) ch->magic = EPCA_MAGIC; ch->tty = NULL; - if (shrinkmem) - { + if (shrinkmem) { fepcmd(ch, SETBUFFER, 32, 0, 0, 0); shrinkmem = 0; } - switch (bd->type) - { /* Begin switch bd->type */ + switch (bd->type) { case PCIXEM: case PCIXRJ: @@ -1878,13 +1611,13 @@ static void post_fep_init(unsigned int crd) fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0); - bc->edelay = 100; - bc->idata = 1; + writew(100, &bc->edelay); + writeb(1, &bc->idata); - ch->startc = bc->startc; - ch->stopc = bc->stopc; - ch->startca = bc->startca; - ch->stopca = bc->stopca; + ch->startc = readb(&bc->startc); + ch->stopc = readb(&bc->stopc); + ch->startca = readb(&bc->startca); + ch->stopca = readb(&bc->stopca); ch->fepcflag = 0; ch->fepiflag = 0; @@ -1899,27 +1632,23 @@ static void post_fep_init(unsigned int crd) ch->blocked_open = 0; init_waitqueue_head(&ch->open_wait); init_waitqueue_head(&ch->close_wait); + + spin_unlock_irqrestore(&epca_lock, flags); + ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL); - if (!(ch->tmp_buf)) - { + if (!ch->tmp_buf) { printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i); release_region((int)bd->port, 4); while(i-- > 0) kfree((ch--)->tmp_buf); return; - } - else + } else memset((void *)ch->tmp_buf,0,ch->txbufsize); } /* End for each port */ printk(KERN_INFO "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); - sprintf(mesg, - "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", - VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); - console_print(mesg); - memwinoff(bd, 0); } /* End post_fep_init */ @@ -1943,9 +1672,6 @@ static void epcapoll(unsigned long ignored) buffer empty) and acts on those events. ----------------------------------------------------------------------- */ - save_flags(flags); - cli(); - for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ @@ -1961,6 +1687,8 @@ static void epcapoll(unsigned long ignored) some legacy boards. ---------------------------------------------------------------- */ + spin_lock_irqsave(&epca_lock, flags); + assertmemoff(ch); globalwinon(ch); @@ -1970,21 +1698,19 @@ static void epcapoll(unsigned long ignored) the transmit or receive queue. ------------------------------------------------------------------- */ - head = ch->mailbox->ein; - tail = ch->mailbox->eout; + head = readw(&ch->mailbox->ein); + tail = readw(&ch->mailbox->eout); /* If head isn't equal to tail we have an event */ if (head != tail) doevent(crd); - memoff(ch); - } /* End for each card */ + spin_unlock_irqrestore(&epca_lock, flags); + } /* End for each card */ mod_timer(&epca_timer, jiffies + (HZ / 25)); - - restore_flags(flags); } /* End epcapoll */ /* --------------------- Begin doevent ------------------------ */ @@ -1992,53 +1718,42 @@ static void epcapoll(unsigned long ignored) static void doevent(int crd) { /* Begin doevent */ - volatile unchar *eventbuf; + void *eventbuf; struct channel *ch, *chan0; static struct tty_struct *tty; - volatile struct board_info *bd; - volatile struct board_chan *bc; - register volatile unsigned int tail, head; - register int event, channel; - register int mstat, lstat; + struct board_info *bd; + struct board_chan *bc; + unsigned int tail, head; + int event, channel; + int mstat, lstat; /* ------------------------------------------------------------------- This subroutine is called by epcapoll when an event is detected in the event queue. This routine responds to those events. --------------------------------------------------------------------- */ - bd = &boards[crd]; chan0 = card_ptr[crd]; epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range"); - assertgwinon(chan0); - - while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) + while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */ - assertgwinon(chan0); - - eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART)); - + eventbuf = bd->re_map_membase + tail + ISTART; /* Get the channel the event occurred on */ - channel = eventbuf[0]; - + channel = readb(eventbuf); /* Get the actual event code that occurred */ - event = eventbuf[1]; - + event = readb(eventbuf + 1); /* ---------------------------------------------------------------- The two assignments below get the current modem status (mstat) and the previous modem status (lstat). These are useful becuase an event could signal a change in modem signals itself. ------------------------------------------------------------------- */ - - mstat = eventbuf[2]; - lstat = eventbuf[3]; + mstat = readb(eventbuf + 2); + lstat = readb(eventbuf + 3); ch = chan0 + channel; - - if ((unsigned)channel >= bd->numports || !ch) - { + if ((unsigned)channel >= bd->numports || !ch) { if (channel >= bd->numports) ch = chan0; bc = ch->brdchan; @@ -2048,97 +1763,53 @@ static void doevent(int crd) if ((bc = ch->brdchan) == NULL) goto next; - if (event & DATA_IND) - { /* Begin DATA_IND */ - + if (event & DATA_IND) { /* Begin DATA_IND */ receive_data(ch); assertgwinon(ch); - } /* End DATA_IND */ /* else *//* Fix for DCD transition missed bug */ - if (event & MODEMCHG_IND) - { /* Begin MODEMCHG_IND */ - + if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */ /* A modem signal change has been indicated */ - ch->imodem = mstat; - - if (ch->asyncflags & ASYNC_CHECK_CD) - { + if (ch->asyncflags & ASYNC_CHECK_CD) { if (mstat & ch->dcd) /* We are now receiving dcd */ wake_up_interruptible(&ch->open_wait); else pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */ } - } /* End MODEMCHG_IND */ - tty = ch->tty; - if (tty) - { /* Begin if valid tty */ - - if (event & BREAK_IND) - { /* Begin if BREAK_IND */ - + if (tty) { /* Begin if valid tty */ + if (event & BREAK_IND) { /* Begin if BREAK_IND */ /* A break has been indicated */ - tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_BREAK; - *tty->flip.char_buf_ptr++ = 0; - tty_schedule_flip(tty); - - } /* End if BREAK_IND */ - else - if (event & LOWTX_IND) - { /* Begin LOWTX_IND */ - + } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */ if (ch->statusflags & LOWWAIT) { /* Begin if LOWWAIT */ - ch->statusflags &= ~LOWWAIT; tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); - } /* End if LOWWAIT */ - - } /* End LOWTX_IND */ - else - if (event & EMPTYTX_IND) - { /* Begin EMPTYTX_IND */ - + } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */ /* This event is generated by setup_empty_event */ - ch->statusflags &= ~TXBUSY; - if (ch->statusflags & EMPTYWAIT) - { /* Begin if EMPTYWAIT */ - + if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */ ch->statusflags &= ~EMPTYWAIT; tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } /* End if EMPTYWAIT */ - } /* End EMPTYTX_IND */ - } /* End if valid tty */ - - next: globalwinon(ch); - - if (!bc) - printk(KERN_ERR "<Error> - bc == NULL in doevent!\n"); - else - bc->idata = 1; - - chan0->mailbox->eout = (tail + 4) & (IMAX - ISTART - 4); + BUG_ON(!bc); + writew(1, &bc->idata); + writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout); globalwinon(chan0); - } /* End while something in event queue */ - } /* End doevent */ /* --------------------- Begin fepcmd ------------------------ */ @@ -2146,7 +1817,6 @@ static void doevent(int crd) static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds, int bytecmd) { /* Begin fepcmd */ - unchar *memaddr; unsigned int head, cmdTail, cmdStart, cmdMax; long count; @@ -2155,93 +1825,57 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, /* This is the routine in which commands may be passed to the card. */ if (ch->board->status == DISABLED) - { return; - } - assertgwinon(ch); - /* Remember head (As well as max) is just an offset not a base addr */ - head = ch->mailbox->cin; - + head = readw(&ch->mailbox->cin); /* cmdStart is a base address */ - cmdStart = ch->mailbox->cstart; - + cmdStart = readw(&ch->mailbox->cstart); /* ------------------------------------------------------------------ We do the addition below because we do not want a max pointer relative to cmdStart. We want a max pointer that points at the physical end of the command queue. -------------------------------------------------------------------- */ - - cmdMax = (cmdStart + 4 + (ch->mailbox->cmax)); - + cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax)); memaddr = ch->board->re_map_membase; - /* - The below command is necessary because newer kernels (2.1.x and - up) do not have a 1:1 virtual to physical mapping. The below - call adjust for that. - */ - - memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr); - - if (head >= (cmdMax - cmdStart) || (head & 03)) - { - printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, - cmd, head); - printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, - cmdMax, cmdStart); + if (head >= (cmdMax - cmdStart) || (head & 03)) { + printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head); + printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart); return; } - - if (bytecmd) - { - *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd; - - *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum; + if (bytecmd) { + writeb(cmd, memaddr + head + cmdStart + 0); + writeb(ch->channelnum, memaddr + head + cmdStart + 1); /* Below word_or_byte is bits to set */ - *(volatile unchar *)(memaddr + head + cmdStart + 2) = (unchar)word_or_byte; + writeb(word_or_byte, memaddr + head + cmdStart + 2); /* Below byte2 is bits to reset */ - *(volatile unchar *)(memaddr + head + cmdStart + 3) = (unchar)byte2; - - } - else - { - *(volatile unchar *)(memaddr + head + cmdStart + 0) = (unchar)cmd; - *(volatile unchar *)(memaddr + head + cmdStart + 1) = (unchar)ch->channelnum; - *(volatile ushort*)(memaddr + head + cmdStart + 2) = (ushort)word_or_byte; + writeb(byte2, memaddr + head + cmdStart + 3); + } else { + writeb(cmd, memaddr + head + cmdStart + 0); + writeb(ch->channelnum, memaddr + head + cmdStart + 1); + writeb(word_or_byte, memaddr + head + cmdStart + 2); } - head = (head + 4) & (cmdMax - cmdStart - 4); - ch->mailbox->cin = head; - + writew(head, &ch->mailbox->cin); count = FEPTIMEOUT; - for (;;) - { /* Begin forever loop */ - + for (;;) { /* Begin forever loop */ count--; - if (count == 0) - { + if (count == 0) { printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n"); return; } - - head = ch->mailbox->cin; - cmdTail = ch->mailbox->cout; - + head = readw(&ch->mailbox->cin); + cmdTail = readw(&ch->mailbox->cout); n = (head - cmdTail) & (cmdMax - cmdStart - 4); - /* ---------------------------------------------------------- Basically this will break when the FEP acknowledges the command by incrementing cmdTail (Making it equal to head). ------------------------------------------------------------- */ - if (n <= ncmds * (sizeof(short) * 4)) break; /* Well nearly forever :-) */ - } /* End forever loop */ - } /* End fepcmd */ /* --------------------------------------------------------------------- @@ -2255,11 +1889,9 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, static unsigned termios2digi_h(struct channel *ch, unsigned cflag) { /* Begin termios2digi_h */ - unsigned res = 0; - if (cflag & CRTSCTS) - { + if (cflag & CRTSCTS) { ch->digiext.digi_flags |= (RTSPACE | CTSPACE); res |= ((ch->m_cts) | (ch->m_rts)); } @@ -2295,7 +1927,6 @@ static unsigned termios2digi_i(struct channel *ch, unsigned iflag) unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP|IXON|IXANY|IXOFF); - if (ch->digiext.digi_flags & DIGI_AIXON) res |= IAIXON; return res; @@ -2308,28 +1939,15 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) { /* Begin termios2digi_c */ unsigned res = 0; - -#ifdef SPEED_HACK - /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */ - if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200; - if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600; -#endif /* SPEED_HACK */ - - if (cflag & CBAUDEX) - { /* Begin detected CBAUDEX */ - + if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */ ch->digiext.digi_flags |= DIGI_FAST; - /* ------------------------------------------------------------- HUPCL bit is used by FEP to indicate fast baud table is to be used. ----------------------------------------------------------------- */ - res |= FEP_HUPCL; - } /* End detected CBAUDEX */ else ch->digiext.digi_flags &= ~DIGI_FAST; - /* ------------------------------------------------------------------- CBAUD has bit position 0x1000 set these days to indicate Linux baud rate remap. Digi hardware can't handle the bit assignment. @@ -2337,7 +1955,6 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) bit out. ---------------------------------------------------------------------- */ res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); - /* ------------------------------------------------------------- This gets a little confusing. The Digi cards have their own representation of c_cflags controling baud rate. For the most @@ -2357,10 +1974,8 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) should be checked for a screened out prior to termios2digi_c returning. Since CLOCAL isn't used by the board this can be ignored as long as the returned value is used only by Digi hardware. - ----------------------------------------------------------------- */ - - if (cflag & CBAUDEX) - { + ----------------------------------------------------------------- */ + if (cflag & CBAUDEX) { /* ------------------------------------------------------------- The below code is trying to guarantee that only baud rates 115200 and 230400 are remapped. We use exclusive or because @@ -2371,138 +1986,96 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) || (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX)))) - { res += 1; - } } - return res; } /* End termios2digi_c */ /* --------------------- Begin epcaparam ----------------------- */ +/* Caller must hold the locks */ static void epcaparam(struct tty_struct *tty, struct channel *ch) { /* Begin epcaparam */ unsigned int cmdHead; struct termios *ts; - volatile struct board_chan *bc; + struct board_chan *bc; unsigned mval, hflow, cflag, iflag; bc = ch->brdchan; epcaassert(bc !=0, "bc out of range"); assertgwinon(ch); - ts = tty->termios; - - if ((ts->c_cflag & CBAUD) == 0) - { /* Begin CBAUD detected */ - - cmdHead = bc->rin; + if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ + cmdHead = readw(&bc->rin); bc->rout = cmdHead; - cmdHead = bc->tin; - + cmdHead = readw(&bc->tin); /* Changing baud in mid-stream transmission can be wonderful */ /* --------------------------------------------------------------- Flush current transmit buffer by setting cmdTail pointer (tout) to cmdHead pointer (tin). Hopefully the transmit buffer is empty. ----------------------------------------------------------------- */ - fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0); mval = 0; - - } /* End CBAUD detected */ - else - { /* Begin CBAUD not detected */ - + } else { /* Begin CBAUD not detected */ /* ------------------------------------------------------------------- c_cflags have changed but that change had nothing to do with BAUD. Propagate the change to the card. ---------------------------------------------------------------------- */ - cflag = termios2digi_c(ch, ts->c_cflag); - - if (cflag != ch->fepcflag) - { + if (cflag != ch->fepcflag) { ch->fepcflag = cflag; /* Set baud rate, char size, stop bits, parity */ fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0); } - - /* ---------------------------------------------------------------- If the user has not forced CLOCAL and if the device is not a CALLOUT device (Which is always CLOCAL) we set flags such that the driver will wait on carrier detect. ------------------------------------------------------------------- */ - if (ts->c_cflag & CLOCAL) - { /* Begin it is a cud device or a ttyD device with CLOCAL on */ ch->asyncflags &= ~ASYNC_CHECK_CD; - } /* End it is a cud device or a ttyD device with CLOCAL on */ else - { /* Begin it is a ttyD device */ ch->asyncflags |= ASYNC_CHECK_CD; - } /* End it is a ttyD device */ - mval = ch->m_dtr | ch->m_rts; - } /* End CBAUD not detected */ - iflag = termios2digi_i(ch, ts->c_iflag); - /* Check input mode flags */ - - if (iflag != ch->fepiflag) - { + if (iflag != ch->fepiflag) { ch->fepiflag = iflag; - /* --------------------------------------------------------------- Command sets channels iflag structure on the board. Such things as input soft flow control, handling of parity errors, and break handling are all set here. ------------------------------------------------------------------- */ - /* break handling, parity handling, input stripping, flow control chars */ fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0); } - /* --------------------------------------------------------------- Set the board mint value for this channel. This will cause hardware events to be generated each time the DCD signal (Described in mint) changes. ------------------------------------------------------------------- */ - bc->mint = ch->dcd; - + writeb(ch->dcd, &bc->mint); if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD)) if (ch->digiext.digi_flags & DIGI_FORCEDCD) - bc->mint = 0; - - ch->imodem = bc->mstat; - + writeb(0, &bc->mint); + ch->imodem = readb(&bc->mstat); hflow = termios2digi_h(ch, ts->c_cflag); - - if (hflow != ch->hflow) - { + if (hflow != ch->hflow) { ch->hflow = hflow; - /* -------------------------------------------------------------- Hard flow control has been selected but the board is not using it. Activate hard flow control now. ----------------------------------------------------------------- */ - fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1); } - - mval ^= ch->modemfake & (mval ^ ch->modem); - if (ch->omodem ^ mval) - { + if (ch->omodem ^ mval) { ch->omodem = mval; - /* -------------------------------------------------------------- The below command sets the DTR and RTS mstat structure. If hard flow control is NOT active these changes will drive the @@ -2514,87 +2087,65 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) /* First reset DTR & RTS; then set them */ fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1); fepcmd(ch, SETMODEM, mval, 0, 0, 1); - } - - if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) - { + if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) { ch->fepstartc = ch->startc; ch->fepstopc = ch->stopc; - /* ------------------------------------------------------------ The XON / XOFF characters have changed; propagate these changes to the card. --------------------------------------------------------------- */ - fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); } - - if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) - { + if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) { ch->fepstartca = ch->startca; ch->fepstopca = ch->stopca; - /* --------------------------------------------------------------- Similar to the above, this time the auxilarly XON / XOFF characters have changed; propagate these changes to the card. ------------------------------------------------------------------ */ - fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); } - } /* End epcaparam */ /* --------------------- Begin receive_data ----------------------- */ - +/* Caller holds lock */ static void receive_data(struct channel *ch) { /* Begin receive_data */ unchar *rptr; struct termios *ts = NULL; struct tty_struct *tty; - volatile struct board_chan *bc; - register int dataToRead, wrapgap, bytesAvailable; - register unsigned int tail, head; + struct board_chan *bc; + int dataToRead, wrapgap, bytesAvailable; + unsigned int tail, head; unsigned int wrapmask; int rc; - /* --------------------------------------------------------------- This routine is called by doint when a receive data event has taken place. ------------------------------------------------------------------- */ globalwinon(ch); - if (ch->statusflags & RXSTOPPED) return; - tty = ch->tty; if (tty) ts = tty->termios; - bc = ch->brdchan; - - if (!bc) - { - printk(KERN_ERR "<Error> - bc is NULL in receive_data!\n"); - return; - } - + BUG_ON(!bc); wrapmask = ch->rxbufsize - 1; /* --------------------------------------------------------------------- Get the head and tail pointers to the receiver queue. Wrap the head pointer if it has reached the end of the buffer. ------------------------------------------------------------------------ */ - - head = bc->rin; + head = readw(&bc->rin); head &= wrapmask; - tail = bc->rout & wrapmask; + tail = readw(&bc->rout) & wrapmask; bytesAvailable = (head - tail) & wrapmask; - if (bytesAvailable == 0) return; @@ -2602,8 +2153,7 @@ static void receive_data(struct channel *ch) If CREAD bit is off or device not open, set TX tail to head --------------------------------------------------------------------- */ - if (!tty || !ts || !(ts->c_cflag & CREAD)) - { + if (!tty || !ts || !(ts->c_cflag & CREAD)) { bc->rout = head; return; } @@ -2611,64 +2161,45 @@ static void receive_data(struct channel *ch) if (tty->flip.count == TTY_FLIPBUF_SIZE) return; - if (bc->orun) - { - bc->orun = 0; - printk(KERN_WARNING "overrun! DigiBoard device %s\n",tty->name); + if (readb(&bc->orun)) { + writeb(0, &bc->orun); + printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name); } - rxwinon(ch); rptr = tty->flip.char_buf_ptr; rc = tty->flip.count; - - while (bytesAvailable > 0) - { /* Begin while there is data on the card */ - + while (bytesAvailable > 0) { /* Begin while there is data on the card */ wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail; - /* --------------------------------------------------------------- Even if head has wrapped around only report the amount of data to be equal to the size - tail. Remember memcpy can't automaticly wrap around the receive buffer. ----------------------------------------------------------------- */ - dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable; - /* -------------------------------------------------------------- Make sure we don't overflow the buffer ----------------------------------------------------------------- */ - if ((rc + dataToRead) > TTY_FLIPBUF_SIZE) dataToRead = TTY_FLIPBUF_SIZE - rc; - if (dataToRead == 0) break; - /* --------------------------------------------------------------- Move data read from our card into the line disciplines buffer for translation if necessary. ------------------------------------------------------------------ */ - - if ((memcpy(rptr, ch->rxptr + tail, dataToRead)) != rptr) - printk(KERN_ERR "<Error> - receive_data : memcpy failed\n"); - + memcpy_fromio(rptr, ch->rxptr + tail, dataToRead); rc += dataToRead; rptr += dataToRead; tail = (tail + dataToRead) & wrapmask; bytesAvailable -= dataToRead; - } /* End while there is data on the card */ - - tty->flip.count = rc; tty->flip.char_buf_ptr = rptr; globalwinon(ch); - bc->rout = tail; - + writew(tail, &bc->rout); /* Must be called with global data */ tty_schedule_flip(ch->tty); return; - } /* End receive_data */ static int info_ioctl(struct tty_struct *tty, struct file * file, @@ -2676,17 +2207,15 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, { switch (cmd) { /* Begin switch cmd */ - case DIGI_GETINFO: { /* Begin case DIGI_GETINFO */ - struct digi_info di ; int brd; - getUser(brd, (unsigned int __user *)arg); - - if ((brd < 0) || (brd >= num_cards) || (num_cards == 0)) - return (-ENODEV); + if(get_user(brd, (unsigned int __user *)arg)) + return -EFAULT; + if (brd < 0 || brd >= num_cards || num_cards == 0) + return -ENODEV; memset(&di, 0, sizeof(di)); @@ -2694,8 +2223,9 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, di.status = boards[brd].status; di.type = boards[brd].type ; di.numports = boards[brd].numports ; - di.port = boards[brd].port ; - di.membase = boards[brd].membase ; + /* Legacy fixups - just move along nothing to see */ + di.port = (unsigned char *)boards[brd].port ; + di.membase = (unsigned char *)boards[brd].membase ; if (copy_to_user((void __user *)arg, &di, sizeof (di))) return -EFAULT; @@ -2709,39 +2239,29 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, int brd = arg & 0xff000000 >> 16 ; unsigned char state = arg & 0xff ; - if ((brd < 0) || (brd >= num_cards)) - { - printk(KERN_ERR "<Error> - DIGI POLLER : brd not valid!\n"); + if (brd < 0 || brd >= num_cards) { + printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n"); return (-ENODEV); } - digi_poller_inhibited = state ; break ; - } /* End case DIGI_POLLER */ case DIGI_INIT: { /* Begin case DIGI_INIT */ - /* ------------------------------------------------------------ This call is made by the apps to complete the initilization of the board(s). This routine is responsible for setting the card to its initial state and setting the drivers control fields to the sutianle settings for the card in question. ---------------------------------------------------------------- */ - int crd ; for (crd = 0; crd < num_cards; crd++) post_fep_init (crd); - break ; - } /* End case DIGI_INIT */ - - default: - return -ENOIOCTLCMD; - + return -ENOTTY; } /* End switch cmd */ return (0) ; } @@ -2750,43 +2270,33 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, static int pc_tiocmget(struct tty_struct *tty, struct file *file) { struct channel *ch = (struct channel *) tty->driver_data; - volatile struct board_chan *bc; + struct board_chan *bc; unsigned int mstat, mflag = 0; unsigned long flags; if (ch) bc = ch->brdchan; else - { - printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmget!\n"); - return(-EINVAL); - } + return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - mstat = bc->mstat; + mstat = readb(&bc->mstat); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); if (mstat & ch->m_dtr) mflag |= TIOCM_DTR; - if (mstat & ch->m_rts) mflag |= TIOCM_RTS; - if (mstat & ch->m_cts) mflag |= TIOCM_CTS; - if (mstat & ch->dsr) mflag |= TIOCM_DSR; - if (mstat & ch->m_ri) mflag |= TIOCM_RI; - if (mstat & ch->dcd) mflag |= TIOCM_CD; - return mflag; } @@ -2796,13 +2306,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, struct channel *ch = (struct channel *) tty->driver_data; unsigned long flags; - if (!ch) { - printk(KERN_ERR "<Error> - ch is NULL in pc_tiocmset!\n"); - return(-EINVAL); - } + if (!ch) + return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); /* * I think this modemfake stuff is broken. It doesn't * correctly reflect the behaviour desired by the TIOCM* @@ -2824,17 +2331,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, ch->modemfake |= ch->m_dtr; ch->modem &= ~ch->m_dtr; } - globalwinon(ch); - /* -------------------------------------------------------------- The below routine generally sets up parity, baud, flow control issues, etc.... It effect both control flags and input flags. ------------------------------------------------------------------ */ - epcaparam(tty,ch); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); return 0; } @@ -2847,19 +2351,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, unsigned long flags; unsigned int mflag, mstat; unsigned char startc, stopc; - volatile struct board_chan *bc; + struct board_chan *bc; struct channel *ch = (struct channel *) tty->driver_data; void __user *argp = (void __user *)arg; if (ch) bc = ch->brdchan; else - { - printk(KERN_ERR "<Error> - ch is NULL in pc_ioctl!\n"); - return(-EINVAL); - } - - save_flags(flags); + return -EINVAL; /* ------------------------------------------------------------------- For POSIX compliance we need to add more ioctls. See tty_ioctl.c @@ -2871,46 +2370,39 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, { /* Begin switch cmd */ case TCGETS: - if (copy_to_user(argp, - tty->termios, sizeof(struct termios))) + if (copy_to_user(argp, tty->termios, sizeof(struct termios))) return -EFAULT; - return(0); - + return 0; case TCGETA: return get_termio(tty, argp); - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); if (retval) return retval; - /* Setup an event to indicate when the transmit buffer empties */ - + spin_lock_irqsave(&epca_lock, flags); setup_empty_event(tty,ch); + spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); if (!arg) digi_send_break(ch, HZ/4); /* 1/4 second */ return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); if (retval) return retval; /* Setup an event to indicate when the transmit buffer empties */ - + spin_lock_irqsave(&epca_lock, flags); setup_empty_event(tty,ch); + spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4); return 0; - case TIOCGSOFTCAR: if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg)) return -EFAULT; return 0; - case TIOCSSOFTCAR: { unsigned int value; @@ -2922,75 +2414,63 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, (value ? CLOCAL : 0)); return 0; } - case TIOCMODG: mflag = pc_tiocmget(tty, file); if (put_user(mflag, (unsigned long __user *)argp)) return -EFAULT; break; - case TIOCMODS: if (get_user(mstat, (unsigned __user *)argp)) return -EFAULT; return pc_tiocmset(tty, file, mstat, ~mstat); - case TIOCSDTR: + spin_lock_irqsave(&epca_lock, flags); ch->omodem |= ch->m_dtr; - cli(); globalwinon(ch); fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); break; case TIOCCDTR: + spin_lock_irqsave(&epca_lock, flags); ch->omodem &= ~ch->m_dtr; - cli(); globalwinon(ch); fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); break; - case DIGI_GETA: if (copy_to_user(argp, &ch->digiext, sizeof(digi_t))) return -EFAULT; break; - case DIGI_SETAW: case DIGI_SETAF: - if ((cmd) == (DIGI_SETAW)) - { + if (cmd == DIGI_SETAW) { /* Setup an event to indicate when the transmit buffer empties */ - + spin_lock_irqsave(&epca_lock, flags); setup_empty_event(tty,ch); + spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); - } - else - { + } else { /* ldisc lock already held in ioctl */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); } - /* Fall Thru */ - case DIGI_SETA: if (copy_from_user(&ch->digiext, argp, sizeof(digi_t))) return -EFAULT; - if (ch->digiext.digi_flags & DIGI_ALTPIN) - { + if (ch->digiext.digi_flags & DIGI_ALTPIN) { ch->dcd = ch->m_dsr; ch->dsr = ch->m_dcd; - } - else - { + } else { ch->dcd = ch->m_dcd; ch->dsr = ch->m_dsr; } - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); /* ----------------------------------------------------------------- @@ -3000,25 +2480,22 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, epcaparam(tty,ch); memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); break; case DIGI_GETFLOW: case DIGI_GETAFLOW: - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - if ((cmd) == (DIGI_GETFLOW)) - { - dflow.startc = bc->startc; - dflow.stopc = bc->stopc; - } - else - { - dflow.startc = bc->startca; - dflow.stopc = bc->stopca; + if (cmd == DIGI_GETFLOW) { + dflow.startc = readb(&bc->startc); + dflow.stopc = readb(&bc->stopc); + } else { + dflow.startc = readb(&bc->startca); + dflow.stopc = readb(&bc->stopca); } memoff(ch); - restore_flags(flags); + spin_unlock_irqrestore(&epca_lock, flags); if (copy_to_user(argp, &dflow, sizeof(dflow))) return -EFAULT; @@ -3026,13 +2503,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, case DIGI_SETAFLOW: case DIGI_SETFLOW: - if ((cmd) == (DIGI_SETFLOW)) - { + if (cmd == DIGI_SETFLOW) { startc = ch->startc; stopc = ch->stopc; - } - else - { + } else { startc = ch->startca; stopc = ch->stopca; } @@ -3040,40 +2514,31 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, if (copy_from_user(&dflow, argp, sizeof(dflow))) return -EFAULT; - if (dflow.startc != startc || dflow.stopc != stopc) - { /* Begin if setflow toggled */ - cli(); + if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */ + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - if ((cmd) == (DIGI_SETFLOW)) - { + if (cmd == DIGI_SETFLOW) { ch->fepstartc = ch->startc = dflow.startc; ch->fepstopc = ch->stopc = dflow.stopc; fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); - } - else - { + } else { ch->fepstartca = ch->startca = dflow.startc; ch->fepstopca = ch->stopca = dflow.stopc; fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); } - if (ch->statusflags & TXSTOPPED) + if (ch->statusflags & TXSTOPPED) pc_start(tty); memoff(ch); - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if setflow toggled */ break; - default: return -ENOIOCTLCMD; - } /* End switch cmd */ - return 0; - } /* End pc_ioctl */ /* --------------------- Begin pc_set_termios ----------------------- */ @@ -3083,20 +2548,16 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - - save_flags(flags); - cli(); + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); epcaparam(tty, ch); memoff(ch); + spin_unlock_irqrestore(&epca_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && ((tty->termios->c_cflag & CRTSCTS) == 0)) @@ -3106,8 +2567,6 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&ch->open_wait); - restore_flags(flags); - } /* End if channel valid */ } /* End pc_set_termios */ @@ -3116,29 +2575,18 @@ static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios) static void do_softint(void *private_) { /* Begin do_softint */ - struct channel *ch = (struct channel *) private_; - - /* Called in response to a modem change event */ - - if (ch && ch->magic == EPCA_MAGIC) - { /* Begin EPCA_MAGIC */ - + if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ struct tty_struct *tty = ch->tty; - if (tty && tty->driver_data) - { - if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) - { /* Begin if clear_bit */ - + if (tty && tty->driver_data) { + if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */ tty_hangup(tty); /* FIXME: module removal race here - AKPM */ wake_up_interruptible(&ch->open_wait); ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; - } /* End if clear_bit */ } - } /* End EPCA_MAGIC */ } /* End do_softint */ @@ -3154,82 +2602,49 @@ static void pc_stop(struct tty_struct *tty) struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if valid channel */ - - save_flags(flags); - cli(); - - if ((ch->statusflags & TXSTOPPED) == 0) - { /* Begin if transmit stop requested */ - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */ + spin_lock_irqsave(&epca_lock, flags); + if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */ globalwinon(ch); - /* STOP transmitting now !! */ - fepcmd(ch, PAUSETX, 0, 0, 0, 0); - ch->statusflags |= TXSTOPPED; memoff(ch); - } /* End if transmit stop requested */ - - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if valid channel */ - } /* End pc_stop */ /* --------------------- Begin pc_start ----------------------- */ static void pc_start(struct tty_struct *tty) { /* Begin pc_start */ - struct channel *ch; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ unsigned long flags; - - save_flags(flags); - cli(); - + spin_lock_irqsave(&epca_lock, flags); /* Just in case output was resumed because of a change in Digi-flow */ - if (ch->statusflags & TXSTOPPED) - { /* Begin transmit resume requested */ - - volatile struct board_chan *bc; - + if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ + struct board_chan *bc; globalwinon(ch); bc = ch->brdchan; if (ch->statusflags & LOWWAIT) - bc->ilow = 1; - + writeb(1, &bc->ilow); /* Okay, you can start transmitting again... */ - fepcmd(ch, RESUMETX, 0, 0, 0, 0); - ch->statusflags &= ~TXSTOPPED; memoff(ch); - } /* End transmit resume requested */ - - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if channel valid */ - } /* End pc_start */ /* ------------------------------------------------------------------ @@ -3244,86 +2659,55 @@ ______________________________________________________________________ */ static void pc_throttle(struct tty_struct * tty) { /* Begin pc_throttle */ - struct channel *ch; unsigned long flags; - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - - - save_flags(flags); - cli(); - - if ((ch->statusflags & RXSTOPPED) == 0) - { + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ + spin_lock_irqsave(&epca_lock, flags); + if ((ch->statusflags & RXSTOPPED) == 0) { globalwinon(ch); fepcmd(ch, PAUSERX, 0, 0, 0, 0); - ch->statusflags |= RXSTOPPED; memoff(ch); } - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if channel valid */ - } /* End pc_throttle */ /* --------------------- Begin unthrottle ----------------------- */ static void pc_unthrottle(struct tty_struct *tty) { /* Begin pc_unthrottle */ - struct channel *ch; unsigned long flags; - volatile struct board_chan *bc; - - /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. ------------------------------------------------------------- */ - - if ((ch = verifyChannel(tty)) != NULL) - { /* Begin if channel valid */ - - + if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ /* Just in case output was resumed because of a change in Digi-flow */ - save_flags(flags); - cli(); - - if (ch->statusflags & RXSTOPPED) - { - + spin_lock_irqsave(&epca_lock, flags); + if (ch->statusflags & RXSTOPPED) { globalwinon(ch); - bc = ch->brdchan; fepcmd(ch, RESUMERX, 0, 0, 0, 0); - ch->statusflags &= ~RXSTOPPED; memoff(ch); } - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End if channel valid */ - } /* End pc_unthrottle */ /* --------------------- Begin digi_send_break ----------------------- */ void digi_send_break(struct channel *ch, int msec) { /* Begin digi_send_break */ - unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); - /* -------------------------------------------------------------------- Maybe I should send an infinite break here, schedule() for msec amount of time, and then stop the break. This way, @@ -3331,36 +2715,28 @@ void digi_send_break(struct channel *ch, int msec) to be called (i.e. via an ioctl()) more than once in msec amount of time. Try this for now... ------------------------------------------------------------------------ */ - fepcmd(ch, SENDBREAK, msec, 0, 10, 0); memoff(ch); - - restore_flags(flags); - + spin_unlock_irqrestore(&epca_lock, flags); } /* End digi_send_break */ /* --------------------- Begin setup_empty_event ----------------------- */ +/* Caller MUST hold the lock */ + static void setup_empty_event(struct tty_struct *tty, struct channel *ch) { /* Begin setup_empty_event */ - volatile struct board_chan *bc = ch->brdchan; - unsigned long int flags; + struct board_chan *bc = ch->brdchan; - save_flags(flags); - cli(); globalwinon(ch); ch->statusflags |= EMPTYWAIT; - /* ------------------------------------------------------------------ When set the iempty flag request a event to be generated when the transmit buffer is empty (If there is no BREAK in progress). --------------------------------------------------------------------- */ - - bc->iempty = 1; + writeb(1, &bc->iempty); memoff(ch); - restore_flags(flags); - } /* End setup_empty_event */ /* --------------------- Begin get_termio ----------------------- */ @@ -3369,10 +2745,10 @@ static int get_termio(struct tty_struct * tty, struct termio __user * termio) { /* Begin get_termio */ return kernel_termios_to_user_termio(termio, tty->termios); } /* End get_termio */ + /* ---------------------- Begin epca_setup -------------------------- */ void epca_setup(char *str, int *ints) { /* Begin epca_setup */ - struct board_info board; int index, loop, last; char *temp, *t2; @@ -3394,49 +2770,41 @@ void epca_setup(char *str, int *ints) for (last = 0, index = 1; index <= ints[0]; index++) switch(index) { /* Begin parse switch */ - case 1: board.status = ints[index]; - /* --------------------------------------------------------- We check for 2 (As opposed to 1; because 2 is a flag instructing the driver to ignore epcaconfig.) For this reason we check for 2. ------------------------------------------------------------ */ - if (board.status == 2) - { /* Begin ignore epcaconfig as well as lilo cmd line */ + if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */ nbdevs = 0; num_cards = 0; return; } /* End ignore epcaconfig as well as lilo cmd line */ - if (board.status > 2) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid board status 0x%x\n", board.status); + if (board.status > 2) { + printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_STATUS; return; } last = index; break; - case 2: board.type = ints[index]; - if (board.type >= PCIXEM) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid board type 0x%x\n", board.type); + if (board.type >= PCIXEM) { + printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_TYPE; return; } last = index; break; - case 3: board.altpin = ints[index]; - if (board.altpin > 1) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid board altpin 0x%x\n", board.altpin); + if (board.altpin > 1) { + printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin); invalid_lilo_config = 1; setup_error_code |= INVALID_ALTPIN; return; @@ -3446,9 +2814,8 @@ void epca_setup(char *str, int *ints) case 4: board.numports = ints[index]; - if ((board.numports < 2) || (board.numports > 256)) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid board numports 0x%x\n", board.numports); + if (board.numports < 2 || board.numports > 256) { + printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports); invalid_lilo_config = 1; setup_error_code |= INVALID_NUM_PORTS; return; @@ -3458,10 +2825,9 @@ void epca_setup(char *str, int *ints) break; case 5: - board.port = (unsigned char *)ints[index]; - if (ints[index] <= 0) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port); + board.port = ints[index]; + if (ints[index] <= 0) { + printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port); invalid_lilo_config = 1; setup_error_code |= INVALID_PORT_BASE; return; @@ -3470,10 +2836,9 @@ void epca_setup(char *str, int *ints) break; case 6: - board.membase = (unsigned char *)ints[index]; - if (ints[index] <= 0) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase); + board.membase = ints[index]; + if (ints[index] <= 0) { + printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase); invalid_lilo_config = 1; setup_error_code |= INVALID_MEM_BASE; return; @@ -3487,21 +2852,16 @@ void epca_setup(char *str, int *ints) } /* End parse switch */ - while (str && *str) - { /* Begin while there is a string arg */ - + while (str && *str) { /* Begin while there is a string arg */ /* find the next comma or terminator */ temp = str; - /* While string is not null, and a comma hasn't been found */ while (*temp && (*temp != ',')) temp++; - if (!*temp) temp = NULL; else *temp++ = 0; - /* Set index to the number of args + 1 */ index = last + 1; @@ -3511,12 +2871,10 @@ void epca_setup(char *str, int *ints) len = strlen(str); if (strncmp("Disable", str, len) == 0) board.status = 0; - else - if (strncmp("Enable", str, len) == 0) + else if (strncmp("Enable", str, len) == 0) board.status = 1; - else - { - printk(KERN_ERR "<Error> - epca_setup: Invalid status %s\n", str); + else { + printk(KERN_ERR "epca_setup: Invalid status %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_STATUS; return; @@ -3525,22 +2883,17 @@ void epca_setup(char *str, int *ints) break; case 2: - for(loop = 0; loop < EPCA_NUM_TYPES; loop++) if (strcmp(board_desc[loop], str) == 0) break; - - /* --------------------------------------------------------------- If the index incremented above refers to a legitamate board type set it here. ------------------------------------------------------------------*/ - if (index < EPCA_NUM_TYPES) board.type = loop; - else - { - printk(KERN_ERR "<Error> - epca_setup: Invalid board type: %s\n", str); + else { + printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_TYPE; return; @@ -3552,12 +2905,10 @@ void epca_setup(char *str, int *ints) len = strlen(str); if (strncmp("Disable", str, len) == 0) board.altpin = 0; - else - if (strncmp("Enable", str, len) == 0) + else if (strncmp("Enable", str, len) == 0) board.altpin = 1; - else - { - printk(KERN_ERR "<Error> - epca_setup: Invalid altpin %s\n", str); + else { + printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_ALTPIN; return; @@ -3570,9 +2921,8 @@ void epca_setup(char *str, int *ints) while (isdigit(*t2)) t2++; - if (*t2) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid port count %s\n", str); + if (*t2) { + printk(KERN_ERR "epca_setup: Invalid port count %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_NUM_PORTS; return; @@ -3601,15 +2951,14 @@ void epca_setup(char *str, int *ints) while (isxdigit(*t2)) t2++; - if (*t2) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid i/o address %s\n", str); + if (*t2) { + printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_PORT_BASE; return; } - board.port = (unsigned char *)simple_strtoul(str, NULL, 16); + board.port = simple_strtoul(str, NULL, 16); last = index; break; @@ -3618,52 +2967,38 @@ void epca_setup(char *str, int *ints) while (isxdigit(*t2)) t2++; - if (*t2) - { - printk(KERN_ERR "<Error> - epca_setup: Invalid memory base %s\n",str); + if (*t2) { + printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str); invalid_lilo_config = 1; setup_error_code |= INVALID_MEM_BASE; return; } - - board.membase = (unsigned char *)simple_strtoul(str, NULL, 16); + board.membase = simple_strtoul(str, NULL, 16); last = index; break; - default: - printk(KERN_ERR "PC/Xx: Too many string parms\n"); + printk(KERN_ERR "epca: Too many string parms\n"); return; } str = temp; - } /* End while there is a string arg */ - - if (last < 6) - { - printk(KERN_ERR "PC/Xx: Insufficient parms specified\n"); + if (last < 6) { + printk(KERN_ERR "epca: Insufficient parms specified\n"); return; } /* I should REALLY validate the stuff here */ - /* Copies our local copy of board into boards */ memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board)); - - /* Does this get called once per lilo arg are what ? */ - printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n", num_cards, board_desc[board.type], board.numports, (int)board.port, (unsigned int) board.membase); - num_cards++; - } /* End epca_setup */ - -#ifdef ENABLE_PCI /* ------------------------ Begin init_PCI --------------------------- */ enum epic_board_types { @@ -3685,7 +3020,6 @@ static struct { { PCIXRJ, 2, }, }; - static int __devinit epca_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3711,10 +3045,8 @@ static int __devinit epca_init_one (struct pci_dev *pdev, boards[board_idx].status = ENABLED; boards[board_idx].type = epca_info_tbl[info_idx].board_type; boards[board_idx].numports = 0x0; - boards[board_idx].port = - (unsigned char *)((char *) addr + PCI_IO_OFFSET); - boards[board_idx].membase = - (unsigned char *)((char *) addr); + boards[board_idx].port = addr + PCI_IO_OFFSET; + boards[board_idx].membase = addr; if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) { printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n", @@ -3775,15 +3107,13 @@ static struct pci_device_id epca_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, epca_pci_tbl); int __init init_PCI (void) -{ /* Begin init_PCI */ +{ /* Begin init_PCI */ memset (&epca_driver, 0, sizeof (epca_driver)); epca_driver.name = "epca"; epca_driver.id_table = epca_pci_tbl; epca_driver.probe = epca_init_one; return pci_register_driver(&epca_driver); -} /* End init_PCI */ - -#endif /* ENABLE_PCI */ +} MODULE_LICENSE("GPL"); diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 52205ef..20eeb5a 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -85,73 +85,73 @@ static char *board_desc[] = struct channel { long magic; - unchar boardnum; - unchar channelnum; - unchar omodem; /* FEP output modem status */ - unchar imodem; /* FEP input modem status */ - unchar modemfake; /* Modem values to be forced */ - unchar modem; /* Force values */ - unchar hflow; - unchar dsr; - unchar dcd; - unchar m_rts ; /* The bits used in whatever FEP */ - unchar m_dcd ; /* is indiginous to this board to */ - unchar m_dsr ; /* represent each of the physical */ - unchar m_cts ; /* handshake lines */ - unchar m_ri ; - unchar m_dtr ; - unchar stopc; - unchar startc; - unchar stopca; - unchar startca; - unchar fepstopc; - unchar fepstartc; - unchar fepstopca; - unchar fepstartca; - unchar txwin; - unchar rxwin; - ushort fepiflag; - ushort fepcflag; - ushort fepoflag; - ushort txbufhead; - ushort txbufsize; - ushort rxbufhead; - ushort rxbufsize; + unsigned char boardnum; + unsigned char channelnum; + unsigned char omodem; /* FEP output modem status */ + unsigned char imodem; /* FEP input modem status */ + unsigned char modemfake; /* Modem values to be forced */ + unsigned char modem; /* Force values */ + unsigned char hflow; + unsigned char dsr; + unsigned char dcd; + unsigned char m_rts ; /* The bits used in whatever FEP */ + unsigned char m_dcd ; /* is indiginous to this board to */ + unsigned char m_dsr ; /* represent each of the physical */ + unsigned char m_cts ; /* handshake lines */ + unsigned char m_ri ; + unsigned char m_dtr ; + unsigned char stopc; + unsigned char startc; + unsigned char stopca; + unsigned char startca; + unsigned char fepstopc; + unsigned char fepstartc; + unsigned char fepstopca; + unsigned char fepstartca; + unsigned char txwin; + unsigned char rxwin; + unsigned short fepiflag; + unsigned short fepcflag; + unsigned short fepoflag; + unsigned short txbufhead; + unsigned short txbufsize; + unsigned short rxbufhead; + unsigned short rxbufsize; int close_delay; int count; int blocked_open; - ulong event; + unsigned long event; int asyncflags; uint dev; - ulong statusflags; - ulong c_iflag; - ulong c_cflag; - ulong c_lflag; - ulong c_oflag; - unchar *txptr; - unchar *rxptr; - unchar *tmp_buf; + unsigned long statusflags; + unsigned long c_iflag; + unsigned long c_cflag; + unsigned long c_lflag; + unsigned long c_oflag; + unsigned char *txptr; + unsigned char *rxptr; + unsigned char *tmp_buf; struct board_info *board; - volatile struct board_chan *brdchan; + struct board_chan *brdchan; struct digi_struct digiext; struct tty_struct *tty; wait_queue_head_t open_wait; wait_queue_head_t close_wait; - struct work_struct tqueue; - volatile struct global_data *mailbox; + struct work_struct tqueue; + struct global_data *mailbox; }; struct board_info { - unchar status; - unchar type; - unchar altpin; - ushort numports; - unchar *port; - unchar *membase; - unchar __iomem *re_map_port; - unchar *re_map_membase; - ulong memory_seg; + unsigned char status; + unsigned char type; + unsigned char altpin; + unsigned short numports; + unsigned long port; + unsigned long membase; + unsigned char __iomem *re_map_port; + unsigned char *re_map_membase; + unsigned long memory_seg; void ( * memwinon ) (struct board_info *, unsigned int) ; void ( * memwinoff ) (struct board_info *, unsigned int) ; void ( * globalwinon ) (struct channel *) ; @@ -160,6 +160,6 @@ struct board_info void ( * memoff ) (struct channel *) ; void ( * assertgwinon ) (struct channel *) ; void ( * assertmemoff ) (struct channel *) ; - unchar poller_inhibited ; + unsigned char poller_inhibited ; }; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 97feb7f..5fe8461 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -44,7 +44,7 @@ /* * The High Precision Event Timer driver. * This driver is closely modelled after the rtc.c driver. - * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm + * http://www.intel.com/hardwaredesign/hpetspec.htm */ #define HPET_USER_FREQ (64) #define HPET_DRIFT (500) @@ -712,7 +712,7 @@ static void hpet_register_interpolator(struct hpets *hpetp) ti->shift = 10; ti->addr = &hpetp->hp_hpet->hpet_mc; ti->frequency = hpet_time_div(hpets->hp_period); - ti->drift = ti->frequency * HPET_DRIFT / 1000000; + ti->drift = HPET_DRIFT; ti->mask = -1; hpetp->hp_interpolator = ti; diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 5ce9c62..3386267 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -31,8 +31,6 @@ #include <linux/ipmi_msgdefs.h> /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_BT_VERSION "v33" - static int bt_debug = 0x00; /* Production value 0, see following flags */ #define BT_DEBUG_ENABLE 1 @@ -163,7 +161,8 @@ static int bt_start_transaction(struct si_sm_data *bt, { unsigned int i; - if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) return -1; + if ((size < 2) || (size > IPMI_MAX_MSG_LENGTH)) + return -1; if ((bt->state != BT_STATE_IDLE) && (bt->state != BT_STATE_HOSED)) return -2; @@ -171,7 +170,8 @@ static int bt_start_transaction(struct si_sm_data *bt, if (bt_debug & BT_DEBUG_MSG) { printk(KERN_WARNING "+++++++++++++++++++++++++++++++++++++\n"); printk(KERN_WARNING "BT: write seq=0x%02X:", bt->seq); - for (i = 0; i < size; i ++) printk (" %02x", data[i]); + for (i = 0; i < size; i ++) + printk (" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ @@ -210,15 +210,18 @@ static int bt_get_result(struct si_sm_data *bt, } else { data[0] = bt->read_data[1]; data[1] = bt->read_data[3]; - if (length < msg_len) bt->truncated = 1; + if (length < msg_len) + bt->truncated = 1; if (bt->truncated) { /* can be set in read_all_bytes() */ data[2] = IPMI_ERR_MSG_TRUNCATED; msg_len = 3; - } else memcpy(data + 2, bt->read_data + 4, msg_len - 2); + } else + memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { printk (KERN_WARNING "BT: res (raw)"); - for (i = 0; i < msg_len; i++) printk(" %02x", data[i]); + for (i = 0; i < msg_len; i++) + printk(" %02x", data[i]); printk ("\n"); } } @@ -231,8 +234,10 @@ static int bt_get_result(struct si_sm_data *bt, static void reset_flags(struct si_sm_data *bt) { - if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); - if (BT_STATUS & BT_B_BUSY) BT_CONTROL(BT_B_BUSY); + if (BT_STATUS & BT_H_BUSY) + BT_CONTROL(BT_H_BUSY); + if (BT_STATUS & BT_B_BUSY) + BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION @@ -241,7 +246,8 @@ static void reset_flags(struct si_sm_data *bt) BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_B2H_ATN); BT_CONTROL(BT_CLR_RD_PTR); - for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) BMC2HOST; + for (i = 0; i < IPMI_MAX_MSG_LENGTH + 2; i++) + BMC2HOST; BT_CONTROL(BT_H_BUSY); } #endif @@ -258,7 +264,8 @@ static inline void write_all_bytes(struct si_sm_data *bt) printk (" %02x", bt->write_data[i]); printk ("\n"); } - for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); + for (i = 0; i < bt->write_count; i++) + HOST2BMC(bt->write_data[i]); } static inline int read_all_bytes(struct si_sm_data *bt) @@ -278,7 +285,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) bt->truncated = 1; return 1; /* let next XACTION START clean it up */ } - for (i = 1; i <= bt->read_count; i++) bt->read_data[i] = BMC2HOST; + for (i = 1; i <= bt->read_count; i++) + bt->read_data[i] = BMC2HOST; bt->read_count++; /* account for the length byte */ if (bt_debug & BT_DEBUG_MSG) { @@ -295,7 +303,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) return 1; - if (bt_debug & BT_DEBUG_MSG) printk(KERN_WARNING "BT: bad packet: " + if (bt_debug & BT_DEBUG_MSG) + printk(KERN_WARNING "BT: bad packet: " "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", bt->write_data[1], bt->write_data[2], bt->write_data[3], bt->read_data[1], bt->read_data[2], bt->read_data[3]); @@ -359,7 +368,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) time); bt->last_state = bt->state; - if (bt->state == BT_STATE_HOSED) return SI_SM_HOSED; + if (bt->state == BT_STATE_HOSED) + return SI_SM_HOSED; if (bt->state != BT_STATE_IDLE) { /* do timeout test */ @@ -371,7 +381,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) /* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT (noticed in ipmi_smic_sm.c January 2004) */ - if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) time = 100; + if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) + time = 100; bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { error_recovery(bt, "timed out"); @@ -393,12 +404,14 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_CONTROL(BT_H_BUSY); break; } - if (status & BT_B2H_ATN) break; + if (status & BT_B2H_ATN) + break; bt->state = BT_STATE_WRITE_BYTES; return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ case BT_STATE_WRITE_BYTES: - if (status & (BT_B_BUSY | BT_H2B_ATN)) break; + if (status & (BT_B_BUSY | BT_H2B_ATN)) + break; BT_CONTROL(BT_CLR_WR_PTR); write_all_bytes(bt); BT_CONTROL(BT_H2B_ATN); /* clears too fast to catch? */ @@ -406,7 +419,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) return SI_SM_CALL_WITHOUT_DELAY; /* it MIGHT sail through */ case BT_STATE_WRITE_CONSUME: /* BMCs usually blow right thru here */ - if (status & (BT_H2B_ATN | BT_B_BUSY)) break; + if (status & (BT_H2B_ATN | BT_B_BUSY)) + break; bt->state = BT_STATE_B2H_WAIT; /* fall through with status */ @@ -415,15 +429,18 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) generation of B2H_ATN so ALWAYS return CALL_WITH_DELAY. */ case BT_STATE_B2H_WAIT: - if (!(status & BT_B2H_ATN)) break; + if (!(status & BT_B2H_ATN)) + break; /* Assume ordered, uncached writes: no need to wait */ - if (!(status & BT_H_BUSY)) BT_CONTROL(BT_H_BUSY); /* set */ + if (!(status & BT_H_BUSY)) + BT_CONTROL(BT_H_BUSY); /* set */ BT_CONTROL(BT_B2H_ATN); /* clear it, ACK to the BMC */ BT_CONTROL(BT_CLR_RD_PTR); /* reset the queue */ i = read_all_bytes(bt); BT_CONTROL(BT_H_BUSY); /* clear */ - if (!i) break; /* Try this state again */ + if (!i) /* Try this state again */ + break; bt->state = BT_STATE_READ_END; return SI_SM_CALL_WITHOUT_DELAY; /* for logging */ @@ -436,7 +453,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) #ifdef MAKE_THIS_TRUE_IF_NECESSARY - if (status & BT_H_BUSY) break; + if (status & BT_H_BUSY) + break; #endif bt->seq++; bt->state = BT_STATE_IDLE; @@ -459,7 +477,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) break; case BT_STATE_RESET3: - if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY; + if (bt->timeout > 0) + return SI_SM_CALL_WITH_DELAY; bt->state = BT_STATE_RESTART; /* printk in debug modes */ break; @@ -485,7 +504,8 @@ static int bt_detect(struct si_sm_data *bt) but that's what you get from reading a bogus address, so we test that first. The calling routine uses negative logic. */ - if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1; + if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) + return 1; reset_flags(bt); return 0; } @@ -501,7 +521,6 @@ static int bt_size(void) struct si_sm_handlers bt_smi_handlers = { - .version = IPMI_BT_VERSION, .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index e0a5357..883ac43 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -47,8 +47,6 @@ #include <linux/device.h> #include <linux/compat.h> -#define IPMI_DEVINTF_VERSION "v33" - struct ipmi_file_private { ipmi_user_t user; @@ -411,6 +409,7 @@ static int ipmi_ioctl(struct inode *inode, break; } + /* The next four are legacy, not per-channel. */ case IPMICTL_SET_MY_ADDRESS_CMD: { unsigned int val; @@ -420,22 +419,25 @@ static int ipmi_ioctl(struct inode *inode, break; } - ipmi_set_my_address(priv->user, val); - rv = 0; + rv = ipmi_set_my_address(priv->user, 0, val); break; } case IPMICTL_GET_MY_ADDRESS_CMD: { - unsigned int val; + unsigned int val; + unsigned char rval; + + rv = ipmi_get_my_address(priv->user, 0, &rval); + if (rv) + break; - val = ipmi_get_my_address(priv->user); + val = rval; if (copy_to_user(arg, &val, sizeof(val))) { rv = -EFAULT; break; } - rv = 0; break; } @@ -448,24 +450,94 @@ static int ipmi_ioctl(struct inode *inode, break; } - ipmi_set_my_LUN(priv->user, val); - rv = 0; + rv = ipmi_set_my_LUN(priv->user, 0, val); break; } case IPMICTL_GET_MY_LUN_CMD: { - unsigned int val; + unsigned int val; + unsigned char rval; - val = ipmi_get_my_LUN(priv->user); + rv = ipmi_get_my_LUN(priv->user, 0, &rval); + if (rv) + break; + + val = rval; + + if (copy_to_user(arg, &val, sizeof(val))) { + rv = -EFAULT; + break; + } + break; + } + + case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + return ipmi_set_my_address(priv->user, val.channel, val.value); + break; + } + + case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_get_my_address(priv->user, val.channel, &val.value); + if (rv) + break; + + if (copy_to_user(arg, &val, sizeof(val))) { + rv = -EFAULT; + break; + } + break; + } + + case IPMICTL_SET_MY_CHANNEL_LUN_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_set_my_LUN(priv->user, val.channel, val.value); + break; + } + + case IPMICTL_GET_MY_CHANNEL_LUN_CMD: + { + struct ipmi_channel_lun_address_set val; + + if (copy_from_user(&val, arg, sizeof(val))) { + rv = -EFAULT; + break; + } + + rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value); + if (rv) + break; if (copy_to_user(arg, &val, sizeof(val))) { rv = -EFAULT; break; } - rv = 0; break; } + case IPMICTL_SET_TIMING_PARMS_CMD: { struct ipmi_timing_parms parms; @@ -748,8 +820,7 @@ static __init int init_ipmi_devintf(void) if (ipmi_major < 0) return -EINVAL; - printk(KERN_INFO "ipmi device interface version " - IPMI_DEVINTF_VERSION "\n"); + printk(KERN_INFO "ipmi device interface\n"); ipmi_class = class_create(THIS_MODULE, "ipmi"); if (IS_ERR(ipmi_class)) { @@ -792,3 +863,5 @@ static __exit void cleanup_ipmi(void) module_exit(cleanup_ipmi); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); +MODULE_DESCRIPTION("Linux device interface for the IPMI message handler."); diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 48cce24..d21853a 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -42,8 +42,6 @@ #include <linux/ipmi_msgdefs.h> /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_KCS_VERSION "v33" - /* Set this if you want a printout of why the state machine was hosed when it gets hosed. */ #define DEBUG_HOSED_REASON @@ -489,7 +487,6 @@ static void kcs_cleanup(struct si_sm_data *kcs) struct si_sm_handlers kcs_smi_handlers = { - .version = IPMI_KCS_VERSION, .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e16c13f..463351d 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -47,7 +47,8 @@ #include <linux/proc_fs.h> #define PFX "IPMI message handler: " -#define IPMI_MSGHANDLER_VERSION "v33" + +#define IPMI_DRIVER_VERSION "36.0" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -116,7 +117,7 @@ struct seq_table do { \ seq = ((msgid >> 26) & 0x3f); \ seqid = (msgid & 0x3fffff); \ - } while(0) + } while (0) #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff) @@ -124,6 +125,14 @@ struct ipmi_channel { unsigned char medium; unsigned char protocol; + + /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, + but may be changed by the user. */ + unsigned char address; + + /* My LUN. This should generally stay the SMS LUN, but just in + case... */ + unsigned char lun; }; #ifdef CONFIG_PROC_FS @@ -135,7 +144,7 @@ struct ipmi_proc_entry #endif #define IPMI_IPMB_NUM_SEQ 64 -#define IPMI_MAX_CHANNELS 8 +#define IPMI_MAX_CHANNELS 16 struct ipmi_smi { /* What interface number are we? */ @@ -193,20 +202,6 @@ struct ipmi_smi struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ - /* This will be non-null if someone registers to receive all - IPMI commands (this is for interface emulation). There - may not be any things in the cmd_rcvrs list above when - this is registered. */ - ipmi_user_t all_cmd_rcvr; - - /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, - but may be changed by the user. */ - unsigned char my_address; - - /* My LUN. This should generally stay the SMS LUN, but just in - case... */ - unsigned char my_lun; - /* The event receiver for my BMC, only really used at panic shutdown as a place to store this. */ unsigned char event_receiver; @@ -218,7 +213,7 @@ struct ipmi_smi interface comes in with a NULL user, call this routine with it. Note that the message will still be freed by the caller. This only works on the system interface. */ - void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg); + void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); /* When we are scanning the channels for an SMI, this will tell which channel we are scanning. */ @@ -325,7 +320,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) down_read(&interfaces_sem); down_write(&smi_watchers_sem); list_add(&(watcher->link), &smi_watchers); - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] != NULL) { watcher->new_smi(i); } @@ -458,7 +453,27 @@ unsigned int ipmi_addr_length(int addr_type) static void deliver_response(struct ipmi_recv_msg *msg) { - msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data); + if (! msg->user) { + ipmi_smi_t intf = msg->user_msg_data; + unsigned long flags; + + /* Special handling for NULL users. */ + if (intf->null_user_handler) { + intf->null_user_handler(intf, msg); + spin_lock_irqsave(&intf->counter_lock, flags); + intf->handled_local_responses++; + spin_unlock_irqrestore(&intf->counter_lock, flags); + } else { + /* No handler, so give up. */ + spin_lock_irqsave(&intf->counter_lock, flags); + intf->unhandled_local_responses++; + spin_unlock_irqrestore(&intf->counter_lock, flags); + } + ipmi_free_recv_msg(msg); + } else { + msg->user->handler->ipmi_recv_hndl(msg, + msg->user->handler_data); + } } /* Find the next sequence number not being used and add the given @@ -475,9 +490,9 @@ static int intf_next_seq(ipmi_smi_t intf, int rv = 0; unsigned int i; - for (i=intf->curr_seq; + for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; - i=(i+1)%IPMI_IPMB_NUM_SEQ) + i = (i+1)%IPMI_IPMB_NUM_SEQ) { if (! intf->seq_table[i].inuse) break; @@ -712,7 +727,7 @@ static int ipmi_destroy_user_nolock(ipmi_user_t user) /* Remove the user from the interfaces sequence table. */ spin_lock_irqsave(&(user->intf->seq_lock), flags); - for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) { + for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if (user->intf->seq_table[i].inuse && (user->intf->seq_table[i].recv_msg->user == user)) { @@ -766,26 +781,44 @@ void ipmi_get_version(ipmi_user_t user, *minor = user->intf->version_minor; } -void ipmi_set_my_address(ipmi_user_t user, - unsigned char address) +int ipmi_set_my_address(ipmi_user_t user, + unsigned int channel, + unsigned char address) { - user->intf->my_address = address; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + user->intf->channels[channel].address = address; + return 0; } -unsigned char ipmi_get_my_address(ipmi_user_t user) +int ipmi_get_my_address(ipmi_user_t user, + unsigned int channel, + unsigned char *address) { - return user->intf->my_address; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + *address = user->intf->channels[channel].address; + return 0; } -void ipmi_set_my_LUN(ipmi_user_t user, - unsigned char LUN) +int ipmi_set_my_LUN(ipmi_user_t user, + unsigned int channel, + unsigned char LUN) { - user->intf->my_lun = LUN & 0x3; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + user->intf->channels[channel].lun = LUN & 0x3; + return 0; } -unsigned char ipmi_get_my_LUN(ipmi_user_t user) +int ipmi_get_my_LUN(ipmi_user_t user, + unsigned int channel, + unsigned char *address) { - return user->intf->my_lun; + if (channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + *address = user->intf->channels[channel].lun; + return 0; } int ipmi_set_gets_events(ipmi_user_t user, int val) @@ -828,11 +861,6 @@ int ipmi_register_for_cmd(ipmi_user_t user, read_lock(&(user->intf->users_lock)); write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); - if (user->intf->all_cmd_rcvr != NULL) { - rv = -EBUSY; - goto out_unlock; - } - /* Make sure the command/netfn is not already registered. */ list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) { if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) { @@ -847,7 +875,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, rcvr->user = user; list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs)); } - out_unlock: + write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); read_unlock(&(user->intf->users_lock)); @@ -1213,7 +1241,7 @@ static inline int i_ipmi_request(ipmi_user_t user, unsigned char ipmb_seq; long seqid; - if (addr->channel > IPMI_NUM_CHANNELS) { + if (addr->channel >= IPMI_NUM_CHANNELS) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); @@ -1331,7 +1359,7 @@ static inline int i_ipmi_request(ipmi_user_t user, #ifdef DEBUG_MSGING { int m; - for (m=0; m<smi_msg->data_size; m++) + for (m = 0; m < smi_msg->data_size; m++) printk(" %2.2x", smi_msg->data[m]); printk("\n"); } @@ -1346,6 +1374,18 @@ static inline int i_ipmi_request(ipmi_user_t user, return rv; } +static int check_addr(ipmi_smi_t intf, + struct ipmi_addr *addr, + unsigned char *saddr, + unsigned char *lun) +{ + if (addr->channel >= IPMI_MAX_CHANNELS) + return -EINVAL; + *lun = intf->channels[addr->channel].lun; + *saddr = intf->channels[addr->channel].address; + return 0; +} + int ipmi_request_settime(ipmi_user_t user, struct ipmi_addr *addr, long msgid, @@ -1355,6 +1395,14 @@ int ipmi_request_settime(ipmi_user_t user, int retries, unsigned int retry_time_ms) { + unsigned char saddr, lun; + int rv; + + if (! user) + return -EINVAL; + rv = check_addr(user->intf, addr, &saddr, &lun); + if (rv) + return rv; return i_ipmi_request(user, user->intf, addr, @@ -1363,8 +1411,8 @@ int ipmi_request_settime(ipmi_user_t user, user_msg_data, NULL, NULL, priority, - user->intf->my_address, - user->intf->my_lun, + saddr, + lun, retries, retry_time_ms); } @@ -1378,6 +1426,14 @@ int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_recv_msg *supplied_recv, int priority) { + unsigned char saddr, lun; + int rv; + + if (! user) + return -EINVAL; + rv = check_addr(user->intf, addr, &saddr, &lun); + if (rv) + return rv; return i_ipmi_request(user, user->intf, addr, @@ -1387,8 +1443,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user, supplied_smi, supplied_recv, priority, - user->intf->my_address, - user->intf->my_lun, + saddr, + lun, -1, 0); } @@ -1397,8 +1453,15 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off, { char *out = (char *) page; ipmi_smi_t intf = data; + int i; + int rv= 0; - return sprintf(out, "%x\n", intf->my_address); + for (i = 0; i < IPMI_MAX_CHANNELS; i++) + rv += sprintf(out+rv, "%x ", intf->channels[i].address); + out[rv-1] = '\n'; /* Replace the final space with a newline */ + out[rv] = '\0'; + rv++; + return rv; } static int version_file_read_proc(char *page, char **start, off_t off, @@ -1588,29 +1651,30 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan) (struct ipmi_addr *) &si, 0, &msg, - NULL, + intf, NULL, NULL, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, -1, 0); } static void -channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) +channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { int rv = 0; int chan; - if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) - && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD)) + if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) + && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ - if (msg->rsp[2] != 0) { + if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ - if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) { + if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) { /* If the MC does not support this command, that is legal. We just assume it has one IPMB at channel @@ -1627,13 +1691,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg) } goto next_channel; } - if (msg->rsp_size < 6) { + if (msg->msg.data_len < 4) { /* Message not big enough, just go on. */ goto next_channel; } chan = intf->curr_channel; - intf->channels[chan].medium = msg->rsp[4] & 0x7f; - intf->channels[chan].protocol = msg->rsp[5] & 0x1f; + intf->channels[chan].medium = msg->msg.data[2] & 0x7f; + intf->channels[chan].protocol = msg->msg.data[3] & 0x1f; next_channel: intf->curr_channel++; @@ -1691,22 +1755,24 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, rv = -ENOMEM; down_write(&interfaces_sem); - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == NULL) { new_intf->intf_num = i; new_intf->version_major = version_major; new_intf->version_minor = version_minor; - if (slave_addr == 0) - new_intf->my_address = IPMI_BMC_SLAVE_ADDR; - else - new_intf->my_address = slave_addr; - new_intf->my_lun = 2; /* the SMS LUN. */ + for (j = 0; j < IPMI_MAX_CHANNELS; j++) { + new_intf->channels[j].address + = IPMI_BMC_SLAVE_ADDR; + new_intf->channels[j].lun = 2; + } + if (slave_addr != 0) + new_intf->channels[0].address = slave_addr; rwlock_init(&(new_intf->users_lock)); INIT_LIST_HEAD(&(new_intf->users)); new_intf->handlers = handlers; new_intf->send_info = send_info; spin_lock_init(&(new_intf->seq_lock)); - for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) { + for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { new_intf->seq_table[j].inuse = 0; new_intf->seq_table[j].seqid = 0; } @@ -1722,7 +1788,6 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, rwlock_init(&(new_intf->cmd_rcvr_lock)); init_waitqueue_head(&new_intf->waitq); INIT_LIST_HEAD(&(new_intf->cmd_rcvrs)); - new_intf->all_cmd_rcvr = NULL; spin_lock_init(&(new_intf->counter_lock)); @@ -1814,7 +1879,7 @@ static void clean_up_interface_data(ipmi_smi_t intf) free_recv_msg_list(&(intf->waiting_events)); free_cmd_rcvr_list(&(intf->cmd_rcvrs)); - for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) { + for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if ((intf->seq_table[i].inuse) && (intf->seq_table[i].recv_msg)) { @@ -1833,7 +1898,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf) down_write(&interfaces_sem); if (list_empty(&(intf->users))) { - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == intf) { remove_proc_entries(intf); spin_lock_irqsave(&interfaces_lock, flags); @@ -1960,15 +2025,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, read_lock(&(intf->cmd_rcvr_lock)); - if (intf->all_cmd_rcvr) { - user = intf->all_cmd_rcvr; - } else { - /* Find the command/netfn. */ - list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - user = rcvr->user; - break; - } + /* Find the command/netfn. */ + list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { + user = rcvr->user; + break; } } read_unlock(&(intf->cmd_rcvr_lock)); @@ -1985,7 +2046,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, msg->data[3] = msg->rsp[6]; msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); - msg->data[6] = intf->my_address; + msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; /* rqseq/lun */ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ @@ -1997,7 +2058,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, { int m; printk("Invalid command:"); - for (m=0; m<msg->data_size; m++) + for (m = 0; m < msg->data_size; m++) printk(" %2.2x", msg->data[m]); printk("\n"); } @@ -2145,15 +2206,11 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, read_lock(&(intf->cmd_rcvr_lock)); - if (intf->all_cmd_rcvr) { - user = intf->all_cmd_rcvr; - } else { - /* Find the command/netfn. */ - list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - user = rcvr->user; - break; - } + /* Find the command/netfn. */ + list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { + user = rcvr->user; + break; } } read_unlock(&(intf->cmd_rcvr_lock)); @@ -2330,6 +2387,14 @@ static int handle_bmc_rsp(ipmi_smi_t intf, unsigned long flags; recv_msg = (struct ipmi_recv_msg *) msg->user_data; + if (recv_msg == NULL) + { + printk(KERN_WARNING"IPMI message received with no owner. This\n" + "could be because of a malformed message, or\n" + "because of a hardware error. Contact your\n" + "hardware vender for assistance\n"); + return 0; + } /* Make sure the user still exists. */ list_for_each_entry(user, &(intf->users), link) { @@ -2340,19 +2405,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf, } } - if (!found) { - /* Special handling for NULL users. */ - if (!recv_msg->user && intf->null_user_handler){ - intf->null_user_handler(intf, msg); - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); - }else{ - /* The user for the message went away, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); - } + if ((! found) && recv_msg->user) { + /* The user for the message went away, so give up. */ + spin_lock_irqsave(&intf->counter_lock, flags); + intf->unhandled_local_responses++; + spin_unlock_irqrestore(&intf->counter_lock, flags); ipmi_free_recv_msg(recv_msg); } else { struct ipmi_system_interface_addr *smi_addr; @@ -2392,7 +2449,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf, #ifdef DEBUG_MSGING int m; printk("Recv:"); - for (m=0; m<msg->rsp_size; m++) + for (m = 0; m < msg->rsp_size; m++) printk(" %2.2x", msg->rsp[m]); printk("\n"); #endif @@ -2626,7 +2683,7 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, { int m; printk("Resend: "); - for (m=0; m<smi_msg->data_size; m++) + for (m = 0; m < smi_msg->data_size; m++) printk(" %2.2x", smi_msg->data[m]); printk("\n"); } @@ -2647,7 +2704,7 @@ ipmi_timeout_handler(long timeout_period) INIT_LIST_HEAD(&timeouts); spin_lock(&interfaces_lock); - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; if (intf == NULL) continue; @@ -2672,7 +2729,7 @@ ipmi_timeout_handler(long timeout_period) have timed out, putting them in the timeouts list. */ spin_lock_irqsave(&(intf->seq_lock), flags); - for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) { + for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { struct seq_table *ent = &(intf->seq_table[j]); if (!ent->inuse) continue; @@ -2712,7 +2769,7 @@ ipmi_timeout_handler(long timeout_period) spin_unlock(&intf->counter_lock); smi_msg = smi_from_recv_msg(intf, ent->recv_msg, j, ent->seqid); - if(!smi_msg) + if (! smi_msg) continue; spin_unlock_irqrestore(&(intf->seq_lock),flags); @@ -2743,7 +2800,7 @@ static void ipmi_request_event(void) int i; spin_lock(&interfaces_lock); - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; if (intf == NULL) continue; @@ -2838,28 +2895,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg) } #ifdef CONFIG_IPMI_PANIC_STRING -static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg) +static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { - if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2)) - && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD) - && (msg->rsp[2] == IPMI_CC_NO_ERROR)) + if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE) + && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD) + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get event receiver command, save it. */ - intf->event_receiver = msg->rsp[3]; - intf->event_receiver_lun = msg->rsp[4] & 0x3; + intf->event_receiver = msg->msg.data[1]; + intf->event_receiver_lun = msg->msg.data[2] & 0x3; } } -static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg) +static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) { - if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) - && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD) - && (msg->rsp[2] == IPMI_CC_NO_ERROR)) + if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) + && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) + && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD) + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get device id command, save if we are an event receiver or generator. */ - intf->local_sel_device = (msg->rsp[8] >> 2) & 1; - intf->local_event_generator = (msg->rsp[8] >> 5) & 1; + intf->local_sel_device = (msg->msg.data[6] >> 2) & 1; + intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } } #endif @@ -2903,7 +2962,7 @@ static void send_panic_events(char *str) recv_msg.done = dummy_recv_done_handler; /* For every registered interface, send the event. */ - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; if (intf == NULL) continue; @@ -2915,12 +2974,12 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* Don't retry, and don't wait. */ } @@ -2930,7 +2989,7 @@ static void send_panic_events(char *str) if (!str) return; - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { char *p = str; struct ipmi_ipmb_addr *ipmb; int j; @@ -2961,12 +3020,12 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* Don't retry, and don't wait. */ if (intf->local_event_generator) { @@ -2981,12 +3040,12 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } intf->null_user_handler = NULL; @@ -2996,7 +3055,7 @@ static void send_panic_events(char *str) be zero, and it must not be my address. */ if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) - && (intf->event_receiver != intf->my_address)) + && (intf->event_receiver != intf->channels[0].address)) { /* The event receiver is valid, send an IPMB message. */ @@ -3031,7 +3090,7 @@ static void send_panic_events(char *str) data[0] = 0; data[1] = 0; data[2] = 0xf0; /* OEM event without timestamp. */ - data[3] = intf->my_address; + data[3] = intf->channels[0].address; data[4] = j++; /* sequence # */ /* Always give 11 bytes, so strncpy will fill it with zeroes for me. */ @@ -3043,12 +3102,12 @@ static void send_panic_events(char *str) &addr, 0, &msg, - NULL, + intf, &smi_msg, &recv_msg, 0, - intf->my_address, - intf->my_lun, + intf->channels[0].address, + intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } } @@ -3070,7 +3129,7 @@ static int panic_event(struct notifier_block *this, has_paniced = 1; /* For every registered interface, set it to run to completion. */ - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; if (intf == NULL) continue; @@ -3099,9 +3158,9 @@ static int ipmi_init_msghandler(void) return 0; printk(KERN_INFO "ipmi message handler version " - IPMI_MSGHANDLER_VERSION "\n"); + IPMI_DRIVER_VERSION "\n"); - for (i=0; i<MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { ipmi_interfaces[i] = NULL; } @@ -3171,6 +3230,9 @@ module_exit(cleanup_ipmi); module_init(ipmi_init_msghandler_mod); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); +MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface."); +MODULE_VERSION(IPMI_DRIVER_VERSION); EXPORT_SYMBOL(ipmi_create_user); EXPORT_SYMBOL(ipmi_destroy_user); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index f951c30..e82a96b 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -42,7 +42,6 @@ #include <linux/ipmi_smi.h> #define PFX "IPMI poweroff: " -#define IPMI_POWEROFF_VERSION "v33" /* Where to we insert our poweroff function? */ extern void (*pm_power_off)(void); @@ -53,16 +52,17 @@ extern void (*pm_power_off)(void); #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ /* the IPMI data command */ -static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; +static int poweroff_powercycle; /* parameter definition to allow user to flag power cycle */ -module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); -MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); +module_param(poweroff_powercycle, int, 0); +MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); /* Stuff from the get device id command. */ static unsigned int mfg_id; static unsigned int prod_id; static unsigned char capabilities; +static unsigned char ipmi_version; /* We use our own messages for this operation, we don't let the system allocate them, since we may be in a panic situation. The whole @@ -338,6 +338,25 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) } /* + * ipmi_dell_chassis_detect() + * Dell systems with IPMI < 1.5 don't set the chassis capability bit + * but they can handle a chassis poweroff or powercycle command. + */ + +#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} +static int ipmi_dell_chassis_detect (ipmi_user_t user) +{ + const char ipmi_version_major = ipmi_version & 0xF; + const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; + const char mfr[3]=DELL_IANA_MFR_ID; + if (!memcmp(mfr, &mfg_id, sizeof(mfr)) && + ipmi_version_major <= 1 && + ipmi_version_minor < 5) + return 1; + return 0; +} + +/* * Standard chassis support */ @@ -366,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) powercyclefailed: printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", - ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); + (poweroff_powercycle ? "cycle" : "down")); /* * Power down */ send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; - data[0] = poweroff_control; + if (poweroff_powercycle) + data[0] = IPMI_CHASSIS_POWER_CYCLE; + else + data[0] = IPMI_CHASSIS_POWER_DOWN; send_msg.data = data; send_msg.data_len = sizeof(data); rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); if (rv) { - switch (poweroff_control) { - case IPMI_CHASSIS_POWER_CYCLE: - /* power cycle failed, default to power down */ - printk(KERN_ERR PFX "Unable to send chassis power " \ - "cycle message, IPMI error 0x%x\n", rv); - poweroff_control = IPMI_CHASSIS_POWER_DOWN; - goto powercyclefailed; - - case IPMI_CHASSIS_POWER_DOWN: - default: - printk(KERN_ERR PFX "Unable to send chassis power " \ - "down message, IPMI error 0x%x\n", rv); - break; + if (poweroff_powercycle) { + /* power cycle failed, default to power down */ + printk(KERN_ERR PFX "Unable to send chassis power " \ + "cycle message, IPMI error 0x%x\n", rv); + poweroff_powercycle = 0; + goto powercyclefailed; } - } - return; + printk(KERN_ERR PFX "Unable to send chassis power " \ + "down message, IPMI error 0x%x\n", rv); + } } @@ -414,6 +430,9 @@ static struct poweroff_function poweroff_functions[] = { { .platform_type = "CPI1", .detect = ipmi_cpi1_detect, .poweroff_func = ipmi_poweroff_cpi1 }, + { .platform_type = "chassis", + .detect = ipmi_dell_chassis_detect, + .poweroff_func = ipmi_poweroff_chassis }, /* Chassis should generally be last, other things should override it. */ { .platform_type = "chassis", @@ -499,10 +518,11 @@ static void ipmi_po_new_smi(int if_num) prod_id = (halt_recv_msg.msg.data[10] | (halt_recv_msg.msg.data[11] << 8)); capabilities = halt_recv_msg.msg.data[6]; + ipmi_version = halt_recv_msg.msg.data[5]; /* Scan for a poweroff method */ - for (i=0; i<NUM_PO_FUNCS; i++) { + for (i = 0; i < NUM_PO_FUNCS; i++) { if (poweroff_functions[i].detect(ipmi_user)) goto found; } @@ -538,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher = #ifdef CONFIG_PROC_FS -/* displays properties to proc */ -static int proc_read_chassctrl(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", - poweroff_control); -} +#include <linux/sysctl.h> + +static ctl_table ipmi_table[] = { + { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE, + .procname = "poweroff_powercycle", + .data = &poweroff_powercycle, + .maxlen = sizeof(poweroff_powercycle), + .mode = 0644, + .proc_handler = &proc_dointvec }, + { } +}; -/* process property writes from proc */ -static int proc_write_chassctrl(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - int rv = count; - unsigned int newval = 0; - - sscanf(buffer, "%d", &newval); - switch (newval) { - case IPMI_CHASSIS_POWER_CYCLE: - printk(KERN_INFO PFX "power cycle is now enabled\n"); - poweroff_control = newval; - break; - - case IPMI_CHASSIS_POWER_DOWN: - poweroff_control = IPMI_CHASSIS_POWER_DOWN; - break; - - default: - rv = -EINVAL; - break; - } +static ctl_table ipmi_dir_table[] = { + { .ctl_name = DEV_IPMI, + .procname = "ipmi", + .mode = 0555, + .child = ipmi_table }, + { } +}; - return rv; -} +static ctl_table ipmi_root_table[] = { + { .ctl_name = CTL_DEV, + .procname = "dev", + .mode = 0555, + .child = ipmi_dir_table }, + { } +}; + +static struct ctl_table_header *ipmi_table_header; #endif /* CONFIG_PROC_FS */ /* @@ -578,42 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer, */ static int ipmi_poweroff_init (void) { - int rv; - struct proc_dir_entry *file; + int rv; printk ("Copyright (C) 2004 MontaVista Software -" - " IPMI Powerdown via sys_reboot version " - IPMI_POWEROFF_VERSION ".\n"); - - switch (poweroff_control) { - case IPMI_CHASSIS_POWER_CYCLE: - printk(KERN_INFO PFX "Power cycle is enabled.\n"); - break; - - case IPMI_CHASSIS_POWER_DOWN: - default: - poweroff_control = IPMI_CHASSIS_POWER_DOWN; - break; + " IPMI Powerdown via sys_reboot.\n"); + + if (poweroff_powercycle) + printk(KERN_INFO PFX "Power cycle is enabled.\n"); + +#ifdef CONFIG_PROC_FS + ipmi_table_header = register_sysctl_table(ipmi_root_table, 1); + if (!ipmi_table_header) { + printk(KERN_ERR PFX "Unable to register powercycle sysctl\n"); + rv = -ENOMEM; + goto out_err; } +#endif +#ifdef CONFIG_PROC_FS rv = ipmi_smi_watcher_register(&smi_watcher); +#endif if (rv) { + unregister_sysctl_table(ipmi_table_header); printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); goto out_err; } -#ifdef CONFIG_PROC_FS - file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); - if (!file) { - printk(KERN_ERR PFX "Unable to create proc power control\n"); - } else { - file->nlink = 1; - file->read_proc = proc_read_chassctrl; - file->write_proc = proc_write_chassctrl; - file->owner = THIS_MODULE; - } -#endif - out_err: return rv; } @@ -624,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void) int rv; #ifdef CONFIG_PROC_FS - remove_proc_entry("poweroff_control", proc_ipmi_root); + unregister_sysctl_table(ipmi_table_header); #endif ipmi_smi_watcher_unregister(&smi_watcher); @@ -642,3 +648,5 @@ module_exit(ipmi_poweroff_cleanup); module_init(ipmi_poweroff_init); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); +MODULE_DESCRIPTION("IPMI Poweroff extension to sys_reboot"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index adbec73..278f841 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -61,11 +61,11 @@ # endif static inline void add_usec_to_timer(struct timer_list *t, long v) { - t->sub_expires += nsec_to_arch_cycle(v * 1000); - while (t->sub_expires >= arch_cycles_per_jiffy) + t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000); + while (t->arch_cycle_expires >= arch_cycles_per_jiffy) { t->expires++; - t->sub_expires -= arch_cycles_per_jiffy; + t->arch_cycle_expires -= arch_cycles_per_jiffy; } } #endif @@ -75,8 +75,7 @@ static inline void add_usec_to_timer(struct timer_list *t, long v) #include <asm/io.h> #include "ipmi_si_sm.h" #include <linux/init.h> - -#define IPMI_SI_VERSION "v33" +#include <linux/dmi.h> /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -109,6 +108,21 @@ enum si_type { SI_KCS, SI_SMIC, SI_BT }; +struct ipmi_device_id { + unsigned char device_id; + unsigned char device_revision; + unsigned char firmware_revision_1; + unsigned char firmware_revision_2; + unsigned char ipmi_version; + unsigned char additional_device_support; + unsigned char manufacturer_id[3]; + unsigned char product_id[2]; + unsigned char aux_firmware_revision[4]; +} __attribute__((packed)); + +#define ipmi_version_major(v) ((v)->ipmi_version & 0xf) +#define ipmi_version_minor(v) ((v)->ipmi_version >> 4) + struct smi_info { ipmi_smi_t intf; @@ -131,12 +145,24 @@ struct smi_info void (*irq_cleanup)(struct smi_info *info); unsigned int io_size; + /* Per-OEM handler, called from handle_flags(). + Returns 1 when handle_flags() needs to be re-run + or 0 indicating it set si_state itself. + */ + int (*oem_data_avail_handler)(struct smi_info *smi_info); + /* Flags from the last GET_MSG_FLAGS command, used when an ATTN is set to hold the flags until we are done handling everything from the flags. */ #define RECEIVE_MSG_AVAIL 0x01 #define EVENT_MSG_BUFFER_FULL 0x02 #define WDT_PRE_TIMEOUT_INT 0x08 +#define OEM0_DATA_AVAIL 0x20 +#define OEM1_DATA_AVAIL 0x40 +#define OEM2_DATA_AVAIL 0x80 +#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \ + OEM1_DATA_AVAIL | \ + OEM2_DATA_AVAIL) unsigned char msg_flags; /* If set to true, this will request events the next time the @@ -175,11 +201,7 @@ struct smi_info interrupts. */ int interrupt_disabled; - unsigned char ipmi_si_dev_rev; - unsigned char ipmi_si_fw_rev_major; - unsigned char ipmi_si_fw_rev_minor; - unsigned char ipmi_version_major; - unsigned char ipmi_version_minor; + struct ipmi_device_id device_id; /* Slave address, could be reported from DMI. */ unsigned char slave_addr; @@ -245,7 +267,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) entry = smi_info->xmit_msgs.next; } - if (!entry) { + if (! entry) { smi_info->curr_msg = NULL; rv = SI_SM_IDLE; } else { @@ -306,7 +328,7 @@ static void start_clear_flags(struct smi_info *smi_info) memory, we will re-enable the interrupt. */ static inline void disable_si_irq(struct smi_info *smi_info) { - if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { + if ((smi_info->irq) && (! smi_info->interrupt_disabled)) { disable_irq_nosync(smi_info->irq); smi_info->interrupt_disabled = 1; } @@ -322,6 +344,7 @@ static inline void enable_si_irq(struct smi_info *smi_info) static void handle_flags(struct smi_info *smi_info) { + retry: if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) { /* Watchdog pre-timeout */ spin_lock(&smi_info->count_lock); @@ -336,7 +359,7 @@ static void handle_flags(struct smi_info *smi_info) } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) { /* Messages available. */ smi_info->curr_msg = ipmi_alloc_smi_msg(); - if (!smi_info->curr_msg) { + if (! smi_info->curr_msg) { disable_si_irq(smi_info); smi_info->si_state = SI_NORMAL; return; @@ -355,7 +378,7 @@ static void handle_flags(struct smi_info *smi_info) } else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) { /* Events available. */ smi_info->curr_msg = ipmi_alloc_smi_msg(); - if (!smi_info->curr_msg) { + if (! smi_info->curr_msg) { disable_si_irq(smi_info); smi_info->si_state = SI_NORMAL; return; @@ -371,6 +394,10 @@ static void handle_flags(struct smi_info *smi_info) smi_info->curr_msg->data, smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; + } else if (smi_info->msg_flags & OEM_DATA_AVAIL) { + if (smi_info->oem_data_avail_handler) + if (smi_info->oem_data_avail_handler(smi_info)) + goto retry; } else { smi_info->si_state = SI_NORMAL; } @@ -387,7 +414,7 @@ static void handle_transaction_done(struct smi_info *smi_info) #endif switch (smi_info->si_state) { case SI_NORMAL: - if (!smi_info->curr_msg) + if (! smi_info->curr_msg) break; smi_info->curr_msg->rsp_size @@ -761,18 +788,20 @@ static void si_restart_short_timer(struct smi_info *smi_info) #if defined(CONFIG_HIGH_RES_TIMERS) unsigned long flags; unsigned long jiffies_now; + unsigned long seq; if (del_timer(&(smi_info->si_timer))) { /* If we don't delete the timer, then it will go off immediately, anyway. So we only process if we actually delete the timer. */ - /* We already have irqsave on, so no need for it - here. */ - read_lock(&xtime_lock); - jiffies_now = jiffies; - smi_info->si_timer.expires = jiffies_now; - smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now); + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + jiffies_now = jiffies; + smi_info->si_timer.expires = jiffies_now; + smi_info->si_timer.arch_cycle_expires + = get_arch_cycles(jiffies_now); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC); @@ -826,15 +855,19 @@ static void smi_timeout(unsigned long data) /* If the state machine asks for a short delay, then shorten the timer timeout. */ if (smi_result == SI_SM_CALL_WITH_DELAY) { +#if defined(CONFIG_HIGH_RES_TIMERS) + unsigned long seq; +#endif spin_lock_irqsave(&smi_info->count_lock, flags); smi_info->short_timeouts++; spin_unlock_irqrestore(&smi_info->count_lock, flags); #if defined(CONFIG_HIGH_RES_TIMERS) - read_lock(&xtime_lock); - smi_info->si_timer.expires = jiffies; - smi_info->si_timer.sub_expires - = get_arch_cycles(smi_info->si_timer.expires); - read_unlock(&xtime_lock); + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + smi_info->si_timer.expires = jiffies; + smi_info->si_timer.arch_cycle_expires + = get_arch_cycles(smi_info->si_timer.expires); + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC); #else smi_info->si_timer.expires = jiffies + 1; @@ -845,7 +878,7 @@ static void smi_timeout(unsigned long data) spin_unlock_irqrestore(&smi_info->count_lock, flags); smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; #if defined(CONFIG_HIGH_RES_TIMERS) - smi_info->si_timer.sub_expires = 0; + smi_info->si_timer.arch_cycle_expires = 0; #endif } @@ -1014,7 +1047,7 @@ static int std_irq_setup(struct smi_info *info) { int rv; - if (!info->irq) + if (! info->irq) return 0; if (info->si_type == SI_BT) { @@ -1023,7 +1056,7 @@ static int std_irq_setup(struct smi_info *info) SA_INTERRUPT, DEVICE_NAME, info); - if (!rv) + if (! rv) /* Enable the interrupt in the BT interface. */ info->io.outputb(&info->io, IPMI_BT_INTMASK_REG, IPMI_BT_INTMASK_ENABLE_IRQ_BIT); @@ -1048,7 +1081,7 @@ static int std_irq_setup(struct smi_info *info) static void std_irq_cleanup(struct smi_info *info) { - if (!info->irq) + if (! info->irq) return; if (info->si_type == SI_BT) @@ -1121,7 +1154,7 @@ static int port_setup(struct smi_info *info) unsigned int *addr = info->io.info; int mapsize; - if (!addr || (!*addr)) + if (! addr || (! *addr)) return -ENODEV; info->io_cleanup = port_cleanup; @@ -1164,15 +1197,15 @@ static int try_init_port(int intf_num, struct smi_info **new_info) { struct smi_info *info; - if (!ports[intf_num]) + if (! ports[intf_num]) return -ENODEV; - if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE, + if (! is_new_interface(intf_num, IPMI_IO_ADDR_SPACE, ports[intf_num])) return -ENODEV; info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n"); return -ENOMEM; } @@ -1182,10 +1215,10 @@ static int try_init_port(int intf_num, struct smi_info **new_info) info->io.info = &(ports[intf_num]); info->io.addr = NULL; info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = regsizes[intf_num]; - if (!info->io.regsize) + if (! info->io.regsize) info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; info->irq = 0; @@ -1270,7 +1303,7 @@ static int mem_setup(struct smi_info *info) unsigned long *addr = info->io.info; int mapsize; - if (!addr || (!*addr)) + if (! addr || (! *addr)) return -ENODEV; info->io_cleanup = mem_cleanup; @@ -1325,15 +1358,15 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) { struct smi_info *info; - if (!addrs[intf_num]) + if (! addrs[intf_num]) return -ENODEV; - if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE, + if (! is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE, addrs[intf_num])) return -ENODEV; info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n"); return -ENOMEM; } @@ -1343,10 +1376,10 @@ static int try_init_mem(int intf_num, struct smi_info **new_info) info->io.info = &addrs[intf_num]; info->io.addr = NULL; info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = regsizes[intf_num]; - if (!info->io.regsize) + if (! info->io.regsize) info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; info->irq = 0; @@ -1404,7 +1437,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info) { acpi_status status; - if (!info->irq) + if (! info->irq) return 0; /* FIXME - is level triggered right? */ @@ -1428,7 +1461,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info) static void acpi_gpe_irq_cleanup(struct smi_info *info) { - if (!info->irq) + if (! info->irq) return; acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe); @@ -1507,10 +1540,10 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) addr_space = IPMI_MEM_ADDR_SPACE; else addr_space = IPMI_IO_ADDR_SPACE; - if (!is_new_interface(-1, addr_space, spmi->addr.address)) + if (! is_new_interface(-1, addr_space, spmi->addr.address)) return -ENODEV; - if (!spmi->addr.register_bit_width) { + if (! spmi->addr.register_bit_width) { acpi_failure = 1; return -ENODEV; } @@ -1537,7 +1570,7 @@ static int try_init_acpi(int intf_num, struct smi_info **new_info) } info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n"); return -ENOMEM; } @@ -1613,22 +1646,15 @@ typedef struct dmi_ipmi_data static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS]; static int dmi_data_entries; -typedef struct dmi_header -{ - u8 type; - u8 length; - u16 handle; -} dmi_header_t; - -static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) +static int __init decode_dmi(struct dmi_header *dm, int intf_num) { - u8 __iomem *data = (u8 __iomem *)dm; + u8 *data = (u8 *)dm; unsigned long base_addr; u8 reg_spacing; - u8 len = readb(&dm->length); + u8 len = dm->length; dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; - ipmi_data->type = readb(&data[4]); + ipmi_data->type = data[4]; memcpy(&base_addr, data+8, sizeof(unsigned long)); if (len >= 0x11) { @@ -1643,12 +1669,12 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) } /* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ - ipmi_data->base_addr = base_addr | ((readb(&data[0x10]) & 0x10) >> 4); + ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); - ipmi_data->irq = readb(&data[0x11]); + ipmi_data->irq = data[0x11]; /* The top two bits of byte 0x10 hold the register spacing. */ - reg_spacing = (readb(&data[0x10]) & 0xC0) >> 6; + reg_spacing = (data[0x10] & 0xC0) >> 6; switch(reg_spacing){ case 0x00: /* Byte boundaries */ ipmi_data->offset = 1; @@ -1676,7 +1702,7 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) ipmi_data->offset = 1; } - ipmi_data->slave_addr = readb(&data[6]); + ipmi_data->slave_addr = data[6]; if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) { dmi_data_entries++; @@ -1688,94 +1714,29 @@ static int decode_dmi(dmi_header_t __iomem *dm, int intf_num) return -1; } -static int dmi_table(u32 base, int len, int num) +static void __init dmi_find_bmc(void) { - u8 __iomem *buf; - struct dmi_header __iomem *dm; - u8 __iomem *data; - int i=1; - int status=-1; + struct dmi_device *dev = NULL; int intf_num = 0; - buf = ioremap(base, len); - if(buf==NULL) - return -1; - - data = buf; - - while(i<num && (data - buf) < len) - { - dm=(dmi_header_t __iomem *)data; - - if((data-buf+readb(&dm->length)) >= len) - break; - - if (readb(&dm->type) == 38) { - if (decode_dmi(dm, intf_num) == 0) { - intf_num++; - if (intf_num >= SI_MAX_DRIVERS) - break; - } - } - - data+=readb(&dm->length); - while((data-buf) < len && (readb(data)||readb(data+1))) - data++; - data+=2; - i++; - } - iounmap(buf); - - return status; -} - -static inline int dmi_checksum(u8 *buf) -{ - u8 sum=0; - int a; - - for(a=0; a<15; a++) - sum+=buf[a]; - return (sum==0); -} - -static int dmi_decode(void) -{ - u8 buf[15]; - u32 fp=0xF0000; - -#ifdef CONFIG_SIMNOW - return -1; -#endif - - while(fp < 0xFFFFF) - { - isa_memcpy_fromio(buf, fp, 15); - if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) - { - u16 num=buf[13]<<8|buf[12]; - u16 len=buf[7]<<8|buf[6]; - u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; + while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { + if (intf_num >= SI_MAX_DRIVERS) + break; - if(dmi_table(base, len, num) == 0) - return 0; - } - fp+=16; + decode_dmi((struct dmi_header *) dev->device_data, intf_num++); } - - return -1; } static int try_init_smbios(int intf_num, struct smi_info **new_info) { - struct smi_info *info; - dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; - char *io_type; + struct smi_info *info; + dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; + char *io_type; if (intf_num >= dmi_data_entries) return -ENODEV; - switch(ipmi_data->type) { + switch (ipmi_data->type) { case 0x01: /* KCS */ si_type[intf_num] = "kcs"; break; @@ -1790,7 +1751,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info) } info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n"); return -ENOMEM; } @@ -1814,7 +1775,7 @@ static int try_init_smbios(int intf_num, struct smi_info **new_info) regspacings[intf_num] = ipmi_data->offset; info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; @@ -1856,14 +1817,14 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) pci_smic_checked = 1; - if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, - NULL))) - ; - else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) && - pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID) - fe_rmc = 1; - else - return -ENODEV; + pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL); + if (! pci_dev) { + pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL); + if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID)) + fe_rmc = 1; + else + return -ENODEV; + } error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr); if (error) @@ -1876,7 +1837,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) } /* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */ - if (!(base_addr & 0x0001)) + if (! (base_addr & 0x0001)) { pci_dev_put(pci_dev); printk(KERN_ERR @@ -1886,17 +1847,17 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) } base_addr &= 0xFFFE; - if (!fe_rmc) + if (! fe_rmc) /* Data register starts at base address + 1 in eRMC */ ++base_addr; - if (!is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) { + if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) { pci_dev_put(pci_dev); return -ENODEV; } info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { + if (! info) { pci_dev_put(pci_dev); printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n"); return -ENOMEM; @@ -1907,7 +1868,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) ports[intf_num] = base_addr; info->io.info = &(ports[intf_num]); info->io.regspacing = regspacings[intf_num]; - if (!info->io.regspacing) + if (! info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshifts[intf_num]; @@ -1928,7 +1889,7 @@ static int find_pci_smic(int intf_num, struct smi_info **new_info) static int try_init_plug_and_play(int intf_num, struct smi_info **new_info) { #ifdef CONFIG_PCI - if (find_pci_smic(intf_num, new_info)==0) + if (find_pci_smic(intf_num, new_info) == 0) return 0; #endif /* Include other methods here. */ @@ -1946,7 +1907,7 @@ static int try_get_dev_id(struct smi_info *smi_info) int rv = 0; resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); - if (!resp) + if (! resp) return -ENOMEM; /* Do a Get Device ID command, since it comes back with some @@ -1995,11 +1956,8 @@ static int try_get_dev_id(struct smi_info *smi_info) } /* Record info from the get device id, in case we need it. */ - smi_info->ipmi_si_dev_rev = resp[4] & 0xf; - smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f; - smi_info->ipmi_si_fw_rev_minor = resp[6]; - smi_info->ipmi_version_major = resp[7] & 0xf; - smi_info->ipmi_version_minor = resp[7] >> 4; + memcpy(&smi_info->device_id, &resp[3], + min_t(unsigned long, resp_len-3, sizeof(smi_info->device_id))); out: kfree(resp); @@ -2031,7 +1989,7 @@ static int stat_file_read_proc(char *page, char **start, off_t off, struct smi_info *smi = data; out += sprintf(out, "interrupts_enabled: %d\n", - smi->irq && !smi->interrupt_disabled); + smi->irq && ! smi->interrupt_disabled); out += sprintf(out, "short_timeouts: %ld\n", smi->short_timeouts); out += sprintf(out, "long_timeouts: %ld\n", @@ -2060,6 +2018,73 @@ static int stat_file_read_proc(char *page, char **start, off_t off, return (out - ((char *) page)); } +/* + * oem_data_avail_to_receive_msg_avail + * @info - smi_info structure with msg_flags set + * + * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL + * Returns 1 indicating need to re-run handle_flags(). + */ +static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) +{ + smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) | + RECEIVE_MSG_AVAIL); + return 1; +} + +/* + * setup_dell_poweredge_oem_data_handler + * @info - smi_info.device_id must be populated + * + * Systems that match, but have firmware version < 1.40 may assert + * OEM0_DATA_AVAIL on their own, without being told via Set Flags that + * it's safe to do so. Such systems will de-assert OEM1_DATA_AVAIL + * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags + * as RECEIVE_MSG_AVAIL instead. + * + * As Dell has no plans to release IPMI 1.5 firmware that *ever* + * assert the OEM[012] bits, and if it did, the driver would have to + * change to handle that properly, we don't actually check for the + * firmware version. + * Device ID = 0x20 BMC on PowerEdge 8G servers + * Device Revision = 0x80 + * Firmware Revision1 = 0x01 BMC version 1.40 + * Firmware Revision2 = 0x40 BCD encoded + * IPMI Version = 0x51 IPMI 1.5 + * Manufacturer ID = A2 02 00 Dell IANA + * + */ +#define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20 +#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80 +#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51 +#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} +static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) +{ + struct ipmi_device_id *id = &smi_info->device_id; + const char mfr[3]=DELL_IANA_MFR_ID; + if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) + && (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID) + && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV) + && (id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION)) + { + smi_info->oem_data_avail_handler = + oem_data_avail_to_receive_msg_avail; + } +} + +/* + * setup_oem_data_handler + * @info - smi_info.device_id must be filled in already + * + * Fills in smi_info.device_id.oem_data_available_handler + * when we know what function to use there. + */ + +static void setup_oem_data_handler(struct smi_info *smi_info) +{ + setup_dell_poweredge_oem_data_handler(smi_info); +} + /* Returns 0 if initialized, or negative on an error. */ static int init_one_smi(int intf_num, struct smi_info **smi) { @@ -2071,19 +2096,15 @@ static int init_one_smi(int intf_num, struct smi_info **smi) if (rv) rv = try_init_port(intf_num, &new_smi); #ifdef CONFIG_ACPI - if ((rv) && (si_trydefaults)) { + if (rv && si_trydefaults) rv = try_init_acpi(intf_num, &new_smi); - } #endif #ifdef CONFIG_X86 - if ((rv) && (si_trydefaults)) { + if (rv && si_trydefaults) rv = try_init_smbios(intf_num, &new_smi); - } #endif - if ((rv) && (si_trydefaults)) { + if (rv && si_trydefaults) rv = try_init_plug_and_play(intf_num, &new_smi); - } - if (rv) return rv; @@ -2093,7 +2114,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) new_smi->si_sm = NULL; new_smi->handlers = NULL; - if (!new_smi->irq_setup) { + if (! new_smi->irq_setup) { new_smi->irq = irqs[intf_num]; new_smi->irq_setup = std_irq_setup; new_smi->irq_cleanup = std_irq_cleanup; @@ -2127,7 +2148,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); - if (!new_smi->si_sm) { + if (! new_smi->si_sm) { printk(" Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; @@ -2158,6 +2179,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) if (rv) goto out_err; + setup_oem_data_handler(new_smi); + /* Try to claim any interrupts. */ new_smi->irq_setup(new_smi); @@ -2191,8 +2214,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) rv = ipmi_register_smi(&handlers, new_smi, - new_smi->ipmi_version_major, - new_smi->ipmi_version_minor, + ipmi_version_major(&new_smi->device_id), + ipmi_version_minor(&new_smi->device_id), new_smi->slave_addr, &(new_smi->intf)); if (rv) { @@ -2233,7 +2256,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (!new_smi->timer_stopped) { + while (! new_smi->timer_stopped) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } @@ -2273,7 +2296,7 @@ static __init int init_ipmi_si(void) /* Parse out the si_type string into its components. */ str = si_type_str; if (*str != '\0') { - for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) { + for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) { si_type[i] = str; str = strchr(str, ','); if (str) { @@ -2285,22 +2308,14 @@ static __init int init_ipmi_si(void) } } - printk(KERN_INFO "IPMI System Interface driver version " - IPMI_SI_VERSION); - if (kcs_smi_handlers.version) - printk(", KCS version %s", kcs_smi_handlers.version); - if (smic_smi_handlers.version) - printk(", SMIC version %s", smic_smi_handlers.version); - if (bt_smi_handlers.version) - printk(", BT version %s", bt_smi_handlers.version); - printk("\n"); + printk(KERN_INFO "IPMI System Interface driver.\n"); #ifdef CONFIG_X86 - dmi_decode(); + dmi_find_bmc(); #endif rv = init_one_smi(0, &(smi_infos[pos])); - if (rv && !ports[0] && si_trydefaults) { + if (rv && ! ports[0] && si_trydefaults) { /* If we are trying defaults and the initial port is not set, then set it. */ si_type[0] = "kcs"; @@ -2322,7 +2337,7 @@ static __init int init_ipmi_si(void) if (rv == 0) pos++; - for (i=1; i < SI_MAX_PARMS; i++) { + for (i = 1; i < SI_MAX_PARMS; i++) { rv = init_one_smi(i, &(smi_infos[pos])); if (rv == 0) pos++; @@ -2364,14 +2379,14 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) /* Wait for the timer to stop. This avoids problems with race conditions removing the timer here. */ - while (!to_clean->timer_stopped) { + while (! to_clean->timer_stopped) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } /* Interrupts and timeouts are stopped, now make sure the interface is in a clean state. */ - while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) { + while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { poll(to_clean); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); @@ -2395,13 +2410,15 @@ static __exit void cleanup_ipmi_si(void) { int i; - if (!initialized) + if (! initialized) return; - for (i=0; i<SI_MAX_DRIVERS; i++) { + for (i = 0; i < SI_MAX_DRIVERS; i++) { cleanup_one_si(smi_infos[i]); } } module_exit(cleanup_ipmi_si); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); +MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces."); diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index ae18747..add2aa2 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -46,8 +46,6 @@ #include <linux/ipmi_msgdefs.h> /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_SMIC_VERSION "v33" - /* smic_debug is a bit-field * SMIC_DEBUG_ENABLE - turned on for now * SMIC_DEBUG_MSG - commands and their responses @@ -588,7 +586,6 @@ static int smic_size(void) struct si_sm_handlers smic_smi_handlers = { - .version = IPMI_SMIC_VERSION, .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index d35a953..e71aaae 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -53,8 +53,6 @@ #define PFX "IPMI Watchdog: " -#define IPMI_WATCHDOG_VERSION "v33" - /* * The IPMI command/response information for the watchdog timer. */ @@ -259,7 +257,7 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, data[1] = 0; WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state); - if (pretimeout > 0) { + if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) { WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val); data[2] = pretimeout; } else { @@ -659,19 +657,18 @@ static ssize_t ipmi_read(struct file *file, static int ipmi_open(struct inode *ino, struct file *filep) { - switch (iminor(ino)) - { - case WATCHDOG_MINOR: - if(test_and_set_bit(0, &ipmi_wdog_open)) + switch (iminor(ino)) { + case WATCHDOG_MINOR: + if (test_and_set_bit(0, &ipmi_wdog_open)) return -EBUSY; - /* Don't start the timer now, let it start on the - first heartbeat. */ - ipmi_start_timer_on_heartbeat = 1; - return nonseekable_open(ino, filep); + /* Don't start the timer now, let it start on the + first heartbeat. */ + ipmi_start_timer_on_heartbeat = 1; + return nonseekable_open(ino, filep); - default: - return (-ENODEV); + default: + return (-ENODEV); } } @@ -817,15 +814,19 @@ static void ipmi_register_watchdog(int ipmi_intf) static int ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) { + /* If we are not expecting a timeout, ignore it. */ + if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) + return NOTIFY_DONE; + /* If no one else handled the NMI, we assume it was the IPMI watchdog. */ - if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) + if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) { + /* On some machines, the heartbeat will give + an error and not work unless we re-enable + the timer. So do so. */ + pretimeout_since_last_heartbeat = 1; panic(PFX "pre-timeout"); - - /* On some machines, the heartbeat will give - an error and not work unless we re-enable - the timer. So do so. */ - pretimeout_since_last_heartbeat = 1; + } return NOTIFY_DONE; } @@ -924,9 +925,6 @@ static int __init ipmi_wdog_init(void) { int rv; - printk(KERN_INFO PFX "driver version " - IPMI_WATCHDOG_VERSION "\n"); - if (strcmp(action, "reset") == 0) { action_val = WDOG_TIMEOUT_RESET; } else if (strcmp(action, "none") == 0) { @@ -1011,6 +1009,8 @@ static int __init ipmi_wdog_init(void) register_reboot_notifier(&wdog_reboot_notifier); notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier); + printk(KERN_INFO PFX "driver initialized\n"); + return 0; } @@ -1062,3 +1062,5 @@ static void __exit ipmi_wdog_exit(void) module_exit(ipmi_wdog_exit); module_init(ipmi_wdog_init); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); +MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface."); diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 115dbb3..3fa64c6 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -750,7 +750,7 @@ static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id) dev->soft = NULL; - soft = kcalloc(1, sizeof(struct mbcs_soft), GFP_KERNEL); + soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL); if (soft == NULL) return -ENOMEM; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 850a78c..f182752 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -35,10 +35,6 @@ # include <linux/efi.h> #endif -#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) -extern void tapechar_init(void); -#endif - /* * Architectures vary in how they handle caching for addresses * outside of main memory. diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 931efd5..0c83751 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -63,8 +63,6 @@ static DECLARE_MUTEX(misc_sem); #define DYNAMIC_MINORS 64 /* like dynamic majors */ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; -extern int rtc_DP8570A_init(void); -extern int rtc_MK48T08_init(void); extern int pmu_device_init(void); #ifdef CONFIG_PROC_FS @@ -303,12 +301,7 @@ static int __init misc_init(void) misc_class = class_create(THIS_MODULE, "misc"); if (IS_ERR(misc_class)) return PTR_ERR(misc_class); -#ifdef CONFIG_MVME16x - rtc_MK48T08_init(); -#endif -#ifdef CONFIG_BVME6000 - rtc_DP8570A_init(); -#endif + if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 95f7046..79e490e 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -339,7 +339,7 @@ static int __init moxa_init(void) init_MUTEX(&moxaBuffSem); moxaDriver->owner = THIS_MODULE; - moxaDriver->name = "ttya"; + moxaDriver->name = "ttyMX"; moxaDriver->devfs_name = "tts/a"; moxaDriver->major = ttymajor; moxaDriver->minor_start = 0; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index f022f09..d0ef1ae 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -63,7 +63,6 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/segment.h> #include <asm/bitops.h> #include <asm/uaccess.h> diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index cd4fe8b..63fff7c 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -938,10 +938,9 @@ found: /* * XXX Interrupt pin #7 in Espresso is shared between RTC and - * PCI Slot 2 INTA# (and some INTx# in Slot 1). SA_INTERRUPT here - * is asking for trouble with add-on boards. Change to SA_SHIRQ. + * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ - if (request_irq(rtc_irq, rtc_interrupt, SA_INTERRUPT, "rtc", (void *)&rtc_port)) { + if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) { /* * Standard way for sparc to print irq's is to use * __irq_itoa(). I think for EBus it's ok to use %d. diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index cefbe98..36ae9ad 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -98,12 +98,13 @@ MODULE_PARM_DESC(useinput, #define SONYPI_DEVICE_MODEL_TYPE1 1 #define SONYPI_DEVICE_MODEL_TYPE2 2 +#define SONYPI_DEVICE_MODEL_TYPE3 3 /* type1 models use those */ #define SONYPI_IRQ_PORT 0x8034 #define SONYPI_IRQ_SHIFT 22 -#define SONYPI_BASE 0x50 -#define SONYPI_G10A (SONYPI_BASE+0x14) +#define SONYPI_TYPE1_BASE 0x50 +#define SONYPI_G10A (SONYPI_TYPE1_BASE+0x14) #define SONYPI_TYPE1_REGION_SIZE 0x08 #define SONYPI_TYPE1_EVTYPE_OFFSET 0x04 @@ -114,6 +115,13 @@ MODULE_PARM_DESC(useinput, #define SONYPI_TYPE2_REGION_SIZE 0x20 #define SONYPI_TYPE2_EVTYPE_OFFSET 0x12 +/* type3 series specifics */ +#define SONYPI_TYPE3_BASE 0x40 +#define SONYPI_TYPE3_GID2 (SONYPI_TYPE3_BASE+0x48) /* 16 bits */ +#define SONYPI_TYPE3_MISC (SONYPI_TYPE3_BASE+0x6d) /* 8 bits */ +#define SONYPI_TYPE3_REGION_SIZE 0x20 +#define SONYPI_TYPE3_EVTYPE_OFFSET 0x12 + /* battery / brightness addresses */ #define SONYPI_BAT_FLAGS 0x81 #define SONYPI_LCD_LIGHT 0x96 @@ -159,6 +167,10 @@ static struct sonypi_ioport_list sonypi_type2_ioport_list[] = { { 0x0, 0x0 } }; +/* same as in type 2 models */ +static struct sonypi_ioport_list *sonypi_type3_ioport_list = + sonypi_type2_ioport_list; + /* The set of possible interrupts */ struct sonypi_irq_list { u16 irq; @@ -180,6 +192,9 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = { { 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */ }; +/* same as in type2 models */ +static struct sonypi_irq_list *sonypi_type3_irq_list = sonypi_type2_irq_list; + #define SONYPI_CAMERA_BRIGHTNESS 0 #define SONYPI_CAMERA_CONTRAST 1 #define SONYPI_CAMERA_HUE 2 @@ -223,6 +238,7 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = { #define SONYPI_MEYE_MASK 0x00000400 #define SONYPI_MEMORYSTICK_MASK 0x00000800 #define SONYPI_BATTERY_MASK 0x00001000 +#define SONYPI_WIRELESS_MASK 0x00002000 struct sonypi_event { u8 data; @@ -305,6 +321,13 @@ static struct sonypi_event sonypi_blueev[] = { { 0, 0 } }; +/* The set of possible wireless events */ +static struct sonypi_event sonypi_wlessev[] = { + { 0x59, SONYPI_EVENT_WIRELESS_ON }, + { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, + { 0, 0 } +}; + /* The set of possible back button events */ static struct sonypi_event sonypi_backev[] = { { 0x20, SONYPI_EVENT_BACK_PRESSED }, @@ -383,7 +406,6 @@ static struct sonypi_eventtypes { { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, - { SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, @@ -391,6 +413,12 @@ static struct sonypi_eventtypes { { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0, 0xffffffff, sonypi_releaseev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, + { SONYPI_DEVICE_MODEL_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, { 0 } }; @@ -563,6 +591,23 @@ static void sonypi_type2_srs(void) udelay(10); } +static void sonypi_type3_srs(void) +{ + u16 v16; + u8 v8; + + /* This model type uses the same initialiazation of + * the embedded controller as the type2 models. */ + sonypi_type2_srs(); + + /* Initialization of PCI config space of the LPC interface bridge. */ + v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01; + pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16); + pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8); + v8 = (v8 & 0xCF) | 0x10; + pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8); +} + /* Disables the device - this comes from the AML code in the ACPI bios */ static void sonypi_type1_dis(void) { @@ -587,6 +632,13 @@ static void sonypi_type2_dis(void) printk(KERN_WARNING "ec_write failed\n"); } +static void sonypi_type3_dis(void) +{ + sonypi_type2_dis(); + udelay(10); + pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0); +} + static u8 sonypi_call1(u8 dev) { u8 v1, v2; @@ -1067,10 +1119,17 @@ static struct miscdevice sonypi_misc_device = { static void sonypi_enable(unsigned int camera_on) { - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) - sonypi_type2_srs(); - else + switch (sonypi_device.model) { + case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_srs(); + break; + case SONYPI_DEVICE_MODEL_TYPE2: + sonypi_type2_srs(); + break; + case SONYPI_DEVICE_MODEL_TYPE3: + sonypi_type3_srs(); + break; + } sonypi_call1(0x82); sonypi_call2(0x81, 0xff); @@ -1094,10 +1153,18 @@ static int sonypi_disable(void) if (!SONYPI_ACPI_ACTIVE && fnkeyinit) outb(0xf1, 0xb2); - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) - sonypi_type2_dis(); - else + switch (sonypi_device.model) { + case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_dis(); + break; + case SONYPI_DEVICE_MODEL_TYPE2: + sonypi_type2_dis(); + break; + case SONYPI_DEVICE_MODEL_TYPE3: + sonypi_type3_dis(); + break; + } + return 0; } @@ -1143,12 +1210,16 @@ static int __devinit sonypi_probe(void) struct sonypi_irq_list *irq_list; struct pci_dev *pcidev; - pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1; + else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_ICH6_1, NULL))) + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3; + else + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; sonypi_device.dev = pcidev; - sonypi_device.model = pcidev ? - SONYPI_DEVICE_MODEL_TYPE1 : SONYPI_DEVICE_MODEL_TYPE2; spin_lock_init(&sonypi_device.fifo_lock); sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, @@ -1176,16 +1247,22 @@ static int __devinit sonypi_probe(void) goto out_miscreg; } - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { + ioport_list = sonypi_type1_ioport_list; + sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; + irq_list = sonypi_type1_irq_list; + } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { ioport_list = sonypi_type2_ioport_list; sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; irq_list = sonypi_type2_irq_list; } else { - ioport_list = sonypi_type1_ioport_list; - sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; - sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; - irq_list = sonypi_type1_irq_list; + ioport_list = sonypi_type3_ioport_list; + sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; + irq_list = sonypi_type3_irq_list; } for (i = 0; ioport_list[i].port1; i++) { @@ -1274,11 +1351,10 @@ static int __devinit sonypi_probe(void) printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver" "v%s.\n", SONYPI_DRIVER_VERSION); - printk(KERN_INFO "sonypi: detected %s model, " + printk(KERN_INFO "sonypi: detected type%d model, " "verbose = %d, fnkeyinit = %s, camera = %s, " "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n", - (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ? - "type1" : "type2", + sonypi_device.model, verbose, fnkeyinit ? "on" : "off", camera ? "on" : "off", diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index cc2cc77..c0d6491 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -206,6 +206,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, {0,} diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index dc8c540..939e51e 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -14,7 +14,6 @@ * License. */ -#include <acpi/acpi_bus.h> #include <linux/pnp.h> #include "tpm.h" @@ -29,9 +28,10 @@ #define TPM_MAX_TRIES 5000 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 -/* These values will be filled after ACPI-call */ +/* These values will be filled after PnP-call */ static int TPM_INF_DATA = 0; static int TPM_INF_ADDR = 0; +static int pnp_registered = 0; /* TPM header definitions */ enum infineon_tpm_header { @@ -356,24 +356,26 @@ static const struct pnp_device_id tpm_pnp_tbl[] = { {"IFX0102", 0}, {"", 0} }; +MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); -static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev, +static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { - TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); - TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); - tpm_inf.base = pnp_port_start(dev, 1); - dev_info(&dev->dev, "Found %s with ID %s\n", - dev->name, dev_id->id); - if (!((tpm_inf.base >> 8) & 0xff)) - tpm_inf.base = 0; - return 0; + if (pnp_port_valid(dev, 0)) { + TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); + TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); + tpm_inf.base = pnp_port_start(dev, 1); + dev_info(&dev->dev, "Found %s with ID %s\n", + dev->name, dev_id->id); + return 0; + } + return -ENODEV; } static struct pnp_driver tpm_inf_pnp = { .name = "tpm_inf_pnp", .id_table = tpm_pnp_tbl, - .probe = tpm_inf_acpi_probe, + .probe = tpm_inf_pnp_probe, }; static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, @@ -386,19 +388,30 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, int productid[2]; char chipname[20]; - if (pci_enable_device(pci_dev)) - return -EIO; + rc = pci_enable_device(pci_dev); + if (rc) + return rc; dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); - /* read IO-ports from ACPI */ - pnp_register_driver(&tpm_inf_pnp); - pnp_unregister_driver(&tpm_inf_pnp); + /* read IO-ports from PnP */ + rc = pnp_register_driver(&tpm_inf_pnp); + if (rc < 0) { + dev_err(&pci_dev->dev, + "Error %x from pnp_register_driver!\n",rc); + goto error2; + } + if (!rc) { + dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); + goto error; + } else { + pnp_registered = 1; + } /* Make sure, we have received valid config ports */ if (!TPM_INF_ADDR) { - pci_disable_device(pci_dev); - return -EIO; + dev_err(&pci_dev->dev, "No valid IO-ports received!\n"); + goto error; } /* query chip for its vendor, its version number a.s.o. */ @@ -418,23 +431,21 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, switch ((productid[0] << 8) | productid[1]) { case 6: - sprintf(chipname, " (SLD 9630 TT 1.1)"); + snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)"); break; case 11: - sprintf(chipname, " (SLB 9635 TT 1.2)"); + snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)"); break; default: - sprintf(chipname, " (unknown chip)"); + snprintf(chipname, sizeof(chipname), " (unknown chip)"); break; } - chipname[19] = 0; if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { if (tpm_inf.base == 0) { dev_err(&pci_dev->dev, "No IO-ports found!\n"); - pci_disable_device(pci_dev); - return -EIO; + goto error; } /* configure TPM with IO-ports */ outb(IOLIMH, TPM_INF_ADDR); @@ -452,8 +463,7 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, dev_err(&pci_dev->dev, "Could not set IO-ports to %04x\n", tpm_inf.base); - pci_disable_device(pci_dev); - return -EIO; + goto error; } /* activate register */ @@ -479,14 +489,16 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, productid[0], productid[1], chipname); rc = tpm_register_hardware(pci_dev, &tpm_inf); - if (rc < 0) { - pci_disable_device(pci_dev); - return -ENODEV; - } + if (rc < 0) + goto error; return 0; } else { dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); +error: + pnp_unregister_driver(&tpm_inf_pnp); +error2: pci_disable_device(pci_dev); + pnp_registered = 0; return -ENODEV; } } @@ -521,6 +533,8 @@ static int __init init_inf(void) static void __exit cleanup_inf(void) { + if (pnp_registered) + pnp_unregister_driver(&tpm_inf_pnp); pci_unregister_driver(&inf_pci_driver); } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6e4be3b..9d65712 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -153,7 +153,6 @@ static int tty_release(struct inode *, struct file *); int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); -extern void rs_360_init(void); static void release_mem(struct tty_struct *tty, int idx); @@ -2911,11 +2910,6 @@ void __init console_init(void) #ifdef CONFIG_EARLY_PRINTK disable_early_printk(); #endif -#ifdef CONFIG_SERIAL_68360 - /* This is not a console initcall. I know not what it's doing here. - So I haven't moved it. dwmw2 */ - rs_360_init(); -#endif call = __con_initcall_start; while (call < __con_initcall_end) { (*call)(); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 665103c..b8d0c29 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -434,21 +434,25 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed) /* used by selection: complement pointer position */ void complement_pos(struct vc_data *vc, int offset) { - static unsigned short *p; + static int old_offset = -1; static unsigned short old; static unsigned short oldx, oldy; WARN_CONSOLE_UNLOCKED(); - if (p) { - scr_writew(old, p); + if (old_offset != -1 && old_offset >= 0 && + old_offset < vc->vc_screenbuf_size) { + scr_writew(old, screenpos(vc, old_offset, 1)); if (DO_UPDATE(vc)) vc->vc_sw->con_putc(vc, old, oldy, oldx); } - if (offset == -1) - p = NULL; - else { + + old_offset = offset; + + if (offset != -1 && offset >= 0 && + offset < vc->vc_screenbuf_size) { unsigned short new; + unsigned short *p; p = screenpos(vc, offset, 1); old = scr_readw(p); new = old ^ vc->vc_complement_mask; @@ -459,6 +463,7 @@ void complement_pos(struct vc_data *vc, int offset) vc->vc_sw->con_putc(vc, new, oldy, oldx); } } + } static void insert_char(struct vc_data *vc, unsigned int nr) @@ -2272,7 +2277,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = paste_selection(tty); break; case TIOCL_UNBLANKSCREEN: + acquire_console_sem(); unblank_screen(); + release_console_sem(); break; case TIOCL_SELLOADLUT: ret = sel_loadlut(p); @@ -2317,8 +2324,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) } break; case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */ + acquire_console_sem(); ignore_poke = 1; do_blank_screen(0); + release_console_sem(); break; case TIOCL_BLANKEDSCREEN: ret = console_blanked; diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index b53e2e2..c3898af 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -346,6 +346,13 @@ config 8xx_WDT tristate "MPC8xx Watchdog Timer" depends on WATCHDOG && 8xx +config BOOKE_WDT + tristate "PowerPC Book-E Watchdog Timer" + depends on WATCHDOG && (BOOKE || 4xx) + ---help--- + Please see Documentation/watchdog/watchdog-api.txt for + more information. + # MIPS Architecture config INDYDOG diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index c183883..cfeac6f 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -2,42 +2,68 @@ # Makefile for the WatchDog device drivers. # +# Only one watchdog can succeed. We probe the ISA/PCI/USB based +# watchdog-cards first, then the architecture specific watchdog +# drivers and then the architecture independant "softdog" driver. +# This means that if your ISA/PCI/USB card isn't detected that +# you can fall back to an architecture specific driver and if +# that also fails then you can fall back to the software watchdog +# to give you some cover. + +# ISA-based Watchdog Cards obj-$(CONFIG_PCWATCHDOG) += pcwd.o -obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o -obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o -obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o -obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o -obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_WDT) += wdt.o + +# PCI-based Watchdog Cards +obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o obj-$(CONFIG_WDTPCI) += wdt_pci.o + +# USB-based Watchdog Cards +obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o + +# ARM Architecture obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o -obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o -obj-$(CONFIG_MACHZ_WDT) += machzwd.o -obj-$(CONFIG_SH_WDT) += shwdt.o +obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o +obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o -obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o -obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o -obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o -obj-$(CONFIG_SC520_WDT) += sc520_wdt.o -obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o + +# X86 (i386 + ia64 + x86_64) Architecture +obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o -obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_SC520_WDT) += sc520_wdt.o +obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_IB700_WDT) += ib700wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o +obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o +obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o -obj-$(CONFIG_INDYDOG) += indydog.o -obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o -obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o -obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o -obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o +obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o +obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_MACHZ_WDT) += machzwd.o + +# PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o + +# PPC64 Architecture obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o +obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o + +# MIPS Architecture +obj-$(CONFIG_INDYDOG) += indydog.o + +# S390 Architecture + +# SUPERH Architecture +obj-$(CONFIG_SH_WDT) += shwdt.o -# Only one watchdog can succeed. We probe the hardware watchdog -# drivers first, then the softdog driver. This means if your hardware -# watchdog dies or is 'borrowed' for some reason the software watchdog -# still gives you some cover. +# SPARC64 Architecture +# Architecture Independant obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c new file mode 100644 index 0000000..abc30cc --- /dev/null +++ b/drivers/char/watchdog/booke_wdt.c @@ -0,0 +1,192 @@ +/* + * drivers/char/watchdog/booke_wdt.c + * + * Watchdog timer for PowerPC Book-E systems + * + * Author: Matthew McClintock + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2005 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/notifier.h> +#include <linux/watchdog.h> + +#include <asm/reg_booke.h> +#include <asm/uaccess.h> +#include <asm/system.h> + +/* If the kernel parameter wdt_enable=1, the watchdog will be enabled at boot. + * Also, the wdt_period sets the watchdog timer period timeout. + * For E500 cpus the wdt_period sets which bit changing from 0->1 will + * trigger a watchog timeout. This watchdog timeout will occur 3 times, the + * first time nothing will happen, the second time a watchdog exception will + * occur, and the final time the board will reset. + */ + +#ifdef CONFIG_FSL_BOOKE +#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */ +#else +#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */ +#endif /* for timing information */ + +u32 booke_wdt_enabled = 0; +u32 booke_wdt_period = WDT_PERIOD_DEFAULT; + +#ifdef CONFIG_FSL_BOOKE +#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15)) +#else +#define WDTP(x) (TCR_WP(x)) +#endif + +/* + * booke_wdt_enable: + */ +static __inline__ void booke_wdt_enable(void) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); + + mtspr(SPRN_TCR, val); +} + +/* + * booke_wdt_ping: + */ +static __inline__ void booke_wdt_ping(void) +{ + mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); +} + +/* + * booke_wdt_write: + */ +static ssize_t booke_wdt_write (struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + booke_wdt_ping(); + return count; +} + +static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "PowerPC Book-E Watchdog", +}; + +/* + * booke_wdt_ioctl: + */ +static int booke_wdt_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + u32 tmp = 0; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user ((struct watchdog_info *) arg, &ident, + sizeof(struct watchdog_info))) + return -EFAULT; + case WDIOC_GETSTATUS: + return put_user(ident.options, (u32 *) arg); + case WDIOC_GETBOOTSTATUS: + /* XXX: something is clearing TSR */ + tmp = mfspr(SPRN_TSR) & TSR_WRS(3); + /* returns 1 if last reset was caused by the WDT */ + return (tmp ? 1 : 0); + case WDIOC_KEEPALIVE: + booke_wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(booke_wdt_period, (u32 *) arg)) + return -EFAULT; + mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period)); + return 0; + case WDIOC_GETTIMEOUT: + return put_user(booke_wdt_period, (u32 *) arg); + case WDIOC_SETOPTIONS: + if (get_user(tmp, (u32 *) arg)) + return -EINVAL; + if (tmp == WDIOS_ENABLECARD) { + booke_wdt_ping(); + break; + } else + return -EINVAL; + return 0; + default: + return -ENOIOCTLCMD; + } + + return 0; +} +/* + * booke_wdt_open: + */ +static int booke_wdt_open (struct inode *inode, struct file *file) +{ + if (booke_wdt_enabled == 0) { + booke_wdt_enabled = 1; + booke_wdt_enable(); + printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", + booke_wdt_period); + } + + return 0; +} + +static struct file_operations booke_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = booke_wdt_write, + .ioctl = booke_wdt_ioctl, + .open = booke_wdt_open, +}; + +static struct miscdevice booke_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &booke_wdt_fops, +}; + +static void __exit booke_wdt_exit(void) +{ + misc_deregister(&booke_wdt_miscdev); +} + +/* + * booke_wdt_init: + */ +static int __init booke_wdt_init(void) +{ + int ret = 0; + + printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n"); + ident.firmware_version = cpu_specs[0].pvr_value; + + ret = misc_register(&booke_wdt_miscdev); + if (ret) { + printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + return ret; + } + + if (booke_wdt_enabled == 1) { + printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n", + booke_wdt_period); + booke_wdt_enable(); + } + + return ret; +} +device_initcall(booke_wdt_init); diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index e7640bc..0cfb9b9 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -182,7 +182,7 @@ static struct file_operations ixp2000_wdt_fops = static struct miscdevice ixp2000_wdt_miscdev = { .minor = WATCHDOG_MINOR, - .name = "IXP2000 Watchdog", + .name = "watchdog", .fops = &ixp2000_wdt_fops, }; diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index 8d916af..b5be8b1 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -176,7 +176,7 @@ static struct file_operations ixp4xx_wdt_fops = static struct miscdevice ixp4xx_wdt_miscdev = { .minor = WATCHDOG_MINOR, - .name = "IXP4xx Watchdog", + .name = "watchdog", .fops = &ixp4xx_wdt_fops, }; diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index f85ac89..8b292bf 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -27,7 +27,10 @@ * Fixed tmr_count / wdt_count confusion * Added configurable debug * - * 11-Jan-2004 BJD Fixed divide-by-2 in timeout code + * 11-Jan-2005 BJD Fixed divide-by-2 in timeout code + * + * 25-Jan-2005 DA Added suspend/resume support + * Replaced reboot notifier with .shutdown method * * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA */ @@ -40,8 +43,6 @@ #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/fs.h> -#include <linux/notifier.h> -#include <linux/reboot.h> #include <linux/init.h> #include <linux/device.h> #include <linux/interrupt.h> @@ -317,20 +318,6 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file, } } -/* - * Notifier for system down - */ - -static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) { - /* Turn the WDT off */ - s3c2410wdt_stop(); - } - return NOTIFY_DONE; -} - /* kernel interface */ static struct file_operations s3c2410wdt_fops = { @@ -348,10 +335,6 @@ static struct miscdevice s3c2410wdt_miscdev = { .fops = &s3c2410wdt_fops, }; -static struct notifier_block s3c2410wdt_notifier = { - .notifier_call = s3c2410wdt_notify_sys, -}; - /* interrupt handler code */ static irqreturn_t s3c2410wdt_irq(int irqno, void *param, @@ -432,18 +415,10 @@ static int s3c2410wdt_probe(struct device *dev) } } - ret = register_reboot_notifier(&s3c2410wdt_notifier); - if (ret) { - printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n", - ret); - return ret; - } - ret = misc_register(&s3c2410wdt_miscdev); if (ret) { printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", WATCHDOG_MINOR, ret); - unregister_reboot_notifier(&s3c2410wdt_notifier); return ret; } @@ -479,15 +454,63 @@ static int s3c2410wdt_remove(struct device *dev) return 0; } +static void s3c2410wdt_shutdown(struct device *dev) +{ + s3c2410wdt_stop(); +} + +#ifdef CONFIG_PM + +static unsigned long wtcon_save; +static unsigned long wtdat_save; + +static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level) +{ + if (level == SUSPEND_POWER_DOWN) { + /* Save watchdog state, and turn it off. */ + wtcon_save = readl(wdt_base + S3C2410_WTCON); + wtdat_save = readl(wdt_base + S3C2410_WTDAT); + + /* Note that WTCNT doesn't need to be saved. */ + s3c2410wdt_stop(); + } + + return 0; +} + +static int s3c2410wdt_resume(struct device *dev, u32 level) +{ + if (level == RESUME_POWER_ON) { + /* Restore watchdog state. */ + + writel(wtdat_save, wdt_base + S3C2410_WTDAT); + writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ + writel(wtcon_save, wdt_base + S3C2410_WTCON); + + printk(KERN_INFO PFX "watchdog %sabled\n", + (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); + } + + return 0; +} + +#else +#define s3c2410wdt_suspend NULL +#define s3c2410wdt_resume NULL +#endif /* CONFIG_PM */ + + static struct device_driver s3c2410wdt_driver = { .name = "s3c2410-wdt", .bus = &platform_bus_type, .probe = s3c2410wdt_probe, .remove = s3c2410wdt_remove, + .shutdown = s3c2410wdt_shutdown, + .suspend = s3c2410wdt_suspend, + .resume = s3c2410wdt_resume, }; - static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n"; static int __init watchdog_init(void) @@ -499,13 +522,13 @@ static int __init watchdog_init(void) static void __exit watchdog_exit(void) { driver_unregister(&s3c2410wdt_driver); - unregister_reboot_notifier(&s3c2410wdt_notifier); } module_init(watchdog_init); module_exit(watchdog_exit); -MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); +MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, " + "Dimitry Andric <dimitry.andric@tomtom.com>"); MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c index c456856..b4a102a 100644 --- a/drivers/char/watchdog/scx200_wdt.c +++ b/drivers/char/watchdog/scx200_wdt.c @@ -206,7 +206,7 @@ static struct file_operations scx200_wdt_fops = { static struct miscdevice scx200_wdt_miscdev = { .minor = WATCHDOG_MINOR, - .name = NAME, + .name = "watchdog", .fops = &scx200_wdt_fops, }; diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c index 4d7ed93..20e5eb8 100644 --- a/drivers/char/watchdog/softdog.c +++ b/drivers/char/watchdog/softdog.c @@ -77,7 +77,7 @@ static void watchdog_fire(unsigned long); static struct timer_list watchdog_ticktock = TIMER_INITIALIZER(watchdog_fire, 0, 0); -static unsigned long timer_alive; +static unsigned long driver_open, orphan_timer; static char expect_close; @@ -87,6 +87,9 @@ static char expect_close; static void watchdog_fire(unsigned long data) { + if (test_and_clear_bit(0, &orphan_timer)) + module_put(THIS_MODULE); + if (soft_noboot) printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); else @@ -128,9 +131,9 @@ static int softdog_set_heartbeat(int t) static int softdog_open(struct inode *inode, struct file *file) { - if(test_and_set_bit(0, &timer_alive)) + if (test_and_set_bit(0, &driver_open)) return -EBUSY; - if (nowayout) + if (!test_and_clear_bit(0, &orphan_timer)) __module_get(THIS_MODULE); /* * Activate timer @@ -147,11 +150,13 @@ static int softdog_release(struct inode *inode, struct file *file) */ if (expect_close == 42) { softdog_stop(); + module_put(THIS_MODULE); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + set_bit(0, &orphan_timer); softdog_keepalive(); } - clear_bit(0, &timer_alive); + clear_bit(0, &driver_open); expect_close = 0; return 0; } diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index 465e0fd..b5d8210 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -93,6 +93,12 @@ w83627hf_init(void) w83627hf_select_wd_register(); + outb_p(0xF6, WDT_EFER); /* Select CRF6 */ + t=inb_p(WDT_EFDR); /* read CRF6 */ + if (t != 0) { + printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout); + outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ + } outb_p(0xF5, WDT_EFER); /* Select CRF5 */ t=inb_p(WDT_EFDR); /* read CRF5 */ t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */ |