diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 23 | ||||
-rw-r--r-- | drivers/char/Makefile | 2 | ||||
-rw-r--r-- | drivers/char/agp/sgi-agp.c | 5 | ||||
-rw-r--r-- | drivers/char/drm/drm_memory_debug.h | 2 | ||||
-rw-r--r-- | drivers/char/drm/via_dmablit.c | 2 | ||||
-rw-r--r-- | drivers/char/epca.c | 2 | ||||
-rw-r--r-- | drivers/char/hvcs.c | 11 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 3 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 2 | ||||
-rw-r--r-- | drivers/char/moxa.c | 2 | ||||
-rw-r--r-- | drivers/char/nsc_gpio.c | 142 | ||||
-rw-r--r-- | drivers/char/pc8736x_gpio.c | 340 | ||||
-rw-r--r-- | drivers/char/scx200_gpio.c | 162 | ||||
-rw-r--r-- | drivers/char/specialix.c | 2 | ||||
-rw-r--r-- | drivers/char/stallion.c | 208 | ||||
-rw-r--r-- | drivers/char/sx.c | 2 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 7 |
17 files changed, 690 insertions, 227 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 3610c572955..410d70cb76f 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -939,12 +939,35 @@ config MWAVE config SCx200_GPIO tristate "NatSemi SCx200 GPIO Support" depends on SCx200 + select NSC_GPIO help Give userspace access to the GPIO pins on the National Semiconductor SCx200 processors. If compiled as a module, it will be called scx200_gpio. +config PC8736x_GPIO + tristate "NatSemi PC8736x GPIO Support" + depends on X86 + default SCx200_GPIO # mostly N + select NSC_GPIO # needed for support routines + help + Give userspace access to the GPIO pins on the National + Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip + has multiple functional units, inc several managed by + hwmon/pc87360 driver. Tested with PC-87366 + + If compiled as a module, it will be called pc8736x_gpio. + +config NSC_GPIO + tristate "NatSemi Base GPIO Support" + # selected by SCx200_GPIO and PC8736x_GPIO + # what about 2 selectors differing: m != y + help + Common support used (and needed) by scx200_gpio and + pc8736x_gpio drivers. If those drivers are built as + modules, this one will be too, named nsc_gpio + config CS5535_GPIO tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" depends on X86_32 diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 524105597ea..6e0f4469d8b 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -82,6 +82,8 @@ obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o +obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o +obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_TANBAC_TB0219) += tb0219.o diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index cfa7922cb43..d73be4c2db8 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void) static void __devexit agp_sgi_cleanup(void) { - if (sgi_tioca_agp_bridges) - kfree(sgi_tioca_agp_bridges); - sgi_tioca_agp_bridges=NULL; + kfree(sgi_tioca_agp_bridges); + sgi_tioca_agp_bridges = NULL; } module_init(agp_sgi_init); diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 6543b9a14c4..d117cc99719 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -43,7 +43,7 @@ typedef struct drm_mem_stats { unsigned long bytes_freed; } drm_mem_stats_t; -static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(drm_mem_lock); static unsigned long drm_ram_available = 0; /* In pages */ static unsigned long drm_ram_used = 0; static drm_mem_stats_t drm_mem_stats[] = diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index b7f17457b42..78a81a4a99c 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -557,7 +557,7 @@ via_init_dmablit(drm_device_t *dev) blitq->num_outstanding = 0; blitq->is_active = 0; blitq->aborting = 0; - blitq->blit_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&blitq->blit_lock); for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) { DRM_INIT_WAITQUEUE(blitq->blit_queue + j); } diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 9cad8501d62..dc0602ae850 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -80,7 +80,7 @@ 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; +static DEFINE_SPINLOCK(epca_lock); /* ----------------------------------------------------------------------- MAXBOARDS is typically 12, but ISA and EISA cards are restricted to diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 8d97b391129..afa26b65dac 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = { static int hvcs_alloc_index_list(int n) { int i; + hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL); if (!hvcs_index_list) return -ENOMEM; hvcs_index_count = n; - for(i = 0; i < hvcs_index_count; i++) + for (i = 0; i < hvcs_index_count; i++) hvcs_index_list[i] = -1; return 0; } @@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n) static void hvcs_free_index_list(void) { /* Paranoia check to be thorough. */ - if (hvcs_index_list) { - kfree(hvcs_index_list); - hvcs_index_list = NULL; - hvcs_index_count = 0; - } + kfree(hvcs_index_list); + hvcs_index_list = NULL; + hvcs_index_count = 0; } static int __init hvcs_module_init(void) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index b03ddab1bef..83ed6ae466a 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -57,8 +57,7 @@ static int ipmi_init_msghandler(void); static int initialized = 0; #ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_ipmi_root = NULL; -EXPORT_SYMBOL(proc_ipmi_root); +static struct proc_dir_entry *proc_ipmi_root = NULL; #endif /* CONFIG_PROC_FS */ #define MAX_EVENTS_IN_QUEUE 25 diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 02a7dd7a8a5..101c14b9b26 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -809,7 +809,7 @@ static int ipmi_thread(void *data) /* do nothing */ } else if (smi_result == SI_SM_CALL_WITH_DELAY) - udelay(1); + schedule(); else schedule_timeout_interruptible(1); } diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index f43c2e04ead..01247cccb89 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -301,7 +301,7 @@ static struct tty_operations moxa_ops = { .tiocmset = moxa_tiocmset, }; -static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(moxa_lock); #ifdef CONFIG_PCI static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board) diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c new file mode 100644 index 00000000000..5b91e4e2564 --- /dev/null +++ b/drivers/char/nsc_gpio.c @@ -0,0 +1,142 @@ +/* linux/drivers/char/nsc_gpio.c + + National Semiconductor common GPIO device-file/VFS methods. + Allows a user space process to control the GPIO pins. + + Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> + Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com> +*/ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/nsc_gpio.h> +#include <linux/platform_device.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +#define NAME "nsc_gpio" + +void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index) +{ + /* retrieve current config w/o changing it */ + u32 config = amp->gpio_config(index, ~0, 0); + + /* user requested via 'v' command, so its INFO */ + dev_info(amp->dev, "io%02u: 0x%04x %s %s %s %s %s %s %s\tio:%d/%d\n", + index, config, + (config & 1) ? "OE" : "TS", /* output-enabled/tristate */ + (config & 2) ? "PP" : "OD", /* push pull / open drain */ + (config & 4) ? "PUE" : "PUD", /* pull up enabled/disabled */ + (config & 8) ? "LOCKED" : "", /* locked / unlocked */ + (config & 16) ? "LEVEL" : "EDGE",/* level/edge input */ + (config & 32) ? "HI" : "LO", /* trigger on rise/fall edge */ + (config & 64) ? "DEBOUNCE" : "", /* debounce */ + + amp->gpio_get(index), amp->gpio_current(index)); +} + +ssize_t nsc_gpio_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + unsigned m = iminor(file->f_dentry->d_inode); + struct nsc_gpio_ops *amp = file->private_data; + struct device *dev = amp->dev; + size_t i; + int err = 0; + + for (i = 0; i < len; ++i) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + switch (c) { + case '0': + amp->gpio_set(m, 0); + break; + case '1': + amp->gpio_set(m, 1); + break; + case 'O': + dev_dbg(dev, "GPIO%d output enabled\n", m); + amp->gpio_config(m, ~1, 1); + break; + case 'o': + dev_dbg(dev, "GPIO%d output disabled\n", m); + amp->gpio_config(m, ~1, 0); + break; + case 'T': + dev_dbg(dev, "GPIO%d output is push pull\n", + m); + amp->gpio_config(m, ~2, 2); + break; + case 't': + dev_dbg(dev, "GPIO%d output is open drain\n", + m); + amp->gpio_config(m, ~2, 0); + break; + case 'P': + dev_dbg(dev, "GPIO%d pull up enabled\n", m); + amp->gpio_config(m, ~4, 4); + break; + case 'p': + dev_dbg(dev, "GPIO%d pull up disabled\n", m); + amp->gpio_config(m, ~4, 0); + break; + case 'v': + /* View Current pin settings */ + amp->gpio_dump(amp, m); + break; + case '\n': + /* end of settings string, do nothing */ + break; + default: + dev_err(dev, "io%2d bad setting: chr<0x%2x>\n", + m, (int)c); + err++; + } + } + if (err) + return -EINVAL; /* full string handled, report error */ + + return len; +} + +ssize_t nsc_gpio_read(struct file *file, char __user * buf, + size_t len, loff_t * ppos) +{ + unsigned m = iminor(file->f_dentry->d_inode); + int value; + struct nsc_gpio_ops *amp = file->private_data; + + value = amp->gpio_get(m); + if (put_user(value ? '1' : '0', buf)) + return -EFAULT; + + return 1; +} + +/* common file-ops routines for both scx200_gpio and pc87360_gpio */ +EXPORT_SYMBOL(nsc_gpio_write); +EXPORT_SYMBOL(nsc_gpio_read); +EXPORT_SYMBOL(nsc_gpio_dump); + +static int __init nsc_gpio_init(void) +{ + printk(KERN_DEBUG NAME " initializing\n"); + return 0; +} + +static void __exit nsc_gpio_cleanup(void) +{ + printk(KERN_DEBUG NAME " cleanup\n"); +} + +module_init(nsc_gpio_init); +module_exit(nsc_gpio_cleanup); + +MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); +MODULE_DESCRIPTION("NatSemi GPIO Common Methods"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c new file mode 100644 index 00000000000..1c706ccfdbb --- /dev/null +++ b/drivers/char/pc8736x_gpio.c @@ -0,0 +1,340 @@ +/* linux/drivers/char/pc8736x_gpio.c + + National Semiconductor PC8736x GPIO driver. Allows a user space + process to play with the GPIO pins. + + Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com> + + adapted from linux/drivers/char/scx200_gpio.c + Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>, +*/ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/mutex.h> +#include <linux/nsc_gpio.h> +#include <linux/platform_device.h> +#include <asm/uaccess.h> + +#define DEVNAME "pc8736x_gpio" + +MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>"); +MODULE_DESCRIPTION("NatSemi PC-8736x GPIO Pin Driver"); +MODULE_LICENSE("GPL"); + +static int major; /* default to dynamic major */ +module_param(major, int, 0); +MODULE_PARM_DESC(major, "Major device number"); + +static DEFINE_MUTEX(pc8736x_gpio_config_lock); +static unsigned pc8736x_gpio_base; +static u8 pc8736x_gpio_shadow[4]; + +#define SIO_BASE1 0x2E /* 1st command-reg to check */ +#define SIO_BASE2 0x4E /* alt command-reg to check */ +#define SIO_BASE_OFFSET 0x20 + +#define SIO_SID 0x20 /* SuperI/O ID Register */ +#define SIO_SID_VALUE 0xe9 /* Expected value in SuperI/O ID Register */ + +#define SIO_CF1 0x21 /* chip config, bit0 is chip enable */ + +#define PC8736X_GPIO_SIZE 16 + +#define SIO_UNIT_SEL 0x7 /* unit select reg */ +#define SIO_UNIT_ACT 0x30 /* unit enable */ +#define SIO_GPIO_UNIT 0x7 /* unit number of GPIO */ +#define SIO_VLM_UNIT 0x0D +#define SIO_TMS_UNIT 0x0E + +/* config-space addrs to read/write each unit's runtime addr */ +#define SIO_BASE_HADDR 0x60 +#define SIO_BASE_LADDR 0x61 + +/* GPIO config-space pin-control addresses */ +#define SIO_GPIO_PIN_SELECT 0xF0 +#define SIO_GPIO_PIN_CONFIG 0xF1 +#define SIO_GPIO_PIN_EVENT 0xF2 + +static unsigned char superio_cmd = 0; +static unsigned char selected_device = 0xFF; /* bogus start val */ + +/* GPIO port runtime access, functionality */ +static int port_offset[] = { 0, 4, 8, 10 }; /* non-uniform offsets ! */ +/* static int event_capable[] = { 1, 1, 0, 0 }; ports 2,3 are hobbled */ + +#define PORT_OUT 0 +#define PORT_IN 1 +#define PORT_EVT_EN 2 +#define PORT_EVT_STST 3 + +static struct platform_device *pdev; /* use in dev_*() */ + +static inline void superio_outb(int addr, int val) +{ + outb_p(addr, superio_cmd); + outb_p(val, superio_cmd + 1); +} + +static inline int superio_inb(int addr) +{ + outb_p(addr, superio_cmd); + return inb_p(superio_cmd + 1); +} + +static int pc8736x_superio_present(void) +{ + /* try the 2 possible values, read a hardware reg to verify */ + superio_cmd = SIO_BASE1; + if (superio_inb(SIO_SID) == SIO_SID_VALUE) + return superio_cmd; + + superio_cmd = SIO_BASE2; + if (superio_inb(SIO_SID) == SIO_SID_VALUE) + return superio_cmd; + + return 0; +} + +static void device_select(unsigned devldn) +{ + superio_outb(SIO_UNIT_SEL, devldn); + selected_device = devldn; +} + +static void select_pin(unsigned iminor) +{ + /* select GPIO port/pin from device minor number */ + device_select(SIO_GPIO_UNIT); + superio_outb(SIO_GPIO_PIN_SELECT, + ((iminor << 1) & 0xF0) | (iminor & 0x7)); +} + +static inline u32 pc8736x_gpio_configure_fn(unsigned index, u32 mask, u32 bits, + u32 func_slct) +{ + u32 config, new_config; + + mutex_lock(&pc8736x_gpio_config_lock); + + device_select(SIO_GPIO_UNIT); + select_pin(index); + + /* read current config value */ + config = superio_inb(func_slct); + + /* set new config */ + new_config = (config & mask) | bits; + superio_outb(func_slct, new_config); + + mutex_unlock(&pc8736x_gpio_config_lock); + + return config; +} + +static u32 pc8736x_gpio_configure(unsigned index, u32 mask, u32 bits) +{ + return pc8736x_gpio_configure_fn(index, mask, bits, + SIO_GPIO_PIN_CONFIG); +} + +static int pc8736x_gpio_get(unsigned minor) +{ + int port, bit, val; + + port = minor >> 3; + bit = minor & 7; + val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN); + val >>= bit; + val &= 1; + + dev_dbg(&pdev->dev, "_gpio_get(%d from %x bit %d) == val %d\n", + minor, pc8736x_gpio_base + port_offset[port] + PORT_IN, bit, + val); + + return val; +} + +static void pc8736x_gpio_set(unsigned minor, int val) +{ + int port, bit, curval; + + minor &= 0x1f; + port = minor >> 3; + bit = minor & 7; + curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT); + + dev_dbg(&pdev->dev, "addr:%x cur:%x bit-pos:%d cur-bit:%x + new:%d -> bit-new:%d\n", + pc8736x_gpio_base + port_offset[port] + PORT_OUT, + curval, bit, (curval & ~(1 << bit)), val, (val << bit)); + + val = (curval & ~(1 << bit)) | (val << bit); + + dev_dbg(&pdev->dev, "gpio_set(minor:%d port:%d bit:%d)" + " %2x -> %2x\n", minor, port, bit, curval, val); + + outb_p(val, pc8736x_gpio_base + port_offset[port] + PORT_OUT); + + curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT); + val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN); + + dev_dbg(&pdev->dev, "wrote %x, read: %x\n", curval, val); + pc8736x_gpio_shadow[port] = val; +} + +static void pc8736x_gpio_set_high(unsigned index) +{ + pc8736x_gpio_set(index, 1); +} + +static void pc8736x_gpio_set_low(unsigned index) +{ + pc8736x_gpio_set(index, 0); +} + +static int pc8736x_gpio_current(unsigned minor) +{ + int port, bit; + minor &= 0x1f; + port = minor >> 3; + bit = minor & 7; + return ((pc8736x_gpio_shadow[port] >> bit) & 0x01); +} + +static void pc8736x_gpio_change(unsigned index) +{ + pc8736x_gpio_set(index, !pc8736x_gpio_current(index)); +} + +static struct nsc_gpio_ops pc8736x_access = { + .owner = THIS_MODULE, + .gpio_config = pc8736x_gpio_configure, + .gpio_dump = nsc_gpio_dump, + .gpio_get = pc8736x_gpio_get, + .gpio_set = pc8736x_gpio_set, + .gpio_set_high = pc8736x_gpio_set_high, + .gpio_set_low = pc8736x_gpio_set_low, + .gpio_change = pc8736x_gpio_change, + .gpio_current = pc8736x_gpio_current +}; + +static int pc8736x_gpio_open(struct inode *inode, struct file *file) +{ + unsigned m = iminor(inode); + file->private_data = &pc8736x_access; + + dev_dbg(&pdev->dev, "open %d\n", m); + + if (m > 63) + return -EINVAL; + return nonseekable_open(inode, file); +} + +static struct file_operations pc8736x_gpio_fops = { + .owner = THIS_MODULE, + .open = pc8736x_gpio_open, + .write = nsc_gpio_write, + .read = nsc_gpio_read, +}; + +static void __init pc8736x_init_shadow(void) +{ + int port; + + /* read the current values driven on the GPIO signals */ + for (port = 0; port < 4; ++port) + pc8736x_gpio_shadow[port] + = inb_p(pc8736x_gpio_base + port_offset[port] + + PORT_OUT); + +} + +static int __init pc8736x_gpio_init(void) +{ + int rc = 0; + + pdev = platform_device_alloc(DEVNAME, 0); + if (!pdev) + return -ENOMEM; + + rc = platform_device_add(pdev); + if (rc) { + rc = -ENODEV; + goto undo_platform_dev_alloc; + } + dev_info(&pdev->dev, "NatSemi pc8736x GPIO Driver Initializing\n"); + + if (!pc8736x_superio_present()) { + rc = -ENODEV; + dev_err(&pdev->dev, "no device found\n"); + goto undo_platform_dev_add; + } + pc8736x_access.dev = &pdev->dev; + + /* Verify that chip and it's GPIO unit are both enabled. + My BIOS does this, so I take minimum action here + */ + rc = superio_inb(SIO_CF1); + if (!(rc & 0x01)) { + rc = -ENODEV; + dev_err(&pdev->dev, "device not enabled\n"); + goto undo_platform_dev_add; + } + device_select(SIO_GPIO_UNIT); + if (!superio_inb(SIO_UNIT_ACT)) { + rc = -ENODEV; + dev_err(&pdev->dev, "GPIO unit not enabled\n"); + goto undo_platform_dev_add; + } + + /* read the GPIO unit base addr that chip responds to */ + pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8 + | superio_inb(SIO_BASE_LADDR)); + + if (!request_region(pc8736x_gpio_base, 16, DEVNAME)) { + rc = -ENODEV; + dev_err(&pdev->dev, "GPIO ioport %x busy\n", + pc8736x_gpio_base); + goto undo_platform_dev_add; + } + dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base); + + rc = register_chrdev(major, DEVNAME, &pc8736x_gpio_fops); + if (rc < 0) { + dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc); + goto undo_platform_dev_add; + } + if (!major) { + major = rc; + dev_dbg(&pdev->dev, "got dynamic major %d\n", major); + } + + pc8736x_init_shadow(); + return 0; + +undo_platform_dev_add: + platform_device_put(pdev); +undo_platform_dev_alloc: + kfree(pdev); + return rc; +} + +static void __exit pc8736x_gpio_cleanup(void) +{ + dev_dbg(&pdev->dev, " cleanup\n"); + + release_region(pc8736x_gpio_base, 16); + + unregister_chrdev(major, DEVNAME); +} + +EXPORT_SYMBOL(pc8736x_access); + +module_init(pc8736x_gpio_init); +module_exit(pc8736x_gpio_cleanup); diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 664a6e97eb1..5a280a33040 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -1,4 +1,4 @@ -/* linux/drivers/char/scx200_gpio.c +/* linux/drivers/char/scx200_gpio.c National Semiconductor SCx200 GPIO driver. Allows a user space process to play with the GPIO pins. @@ -6,17 +6,26 @@ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */ #include <linux/config.h> +#include <linux/device.h> #include <linux/fs.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <asm/uaccess.h> #include <asm/io.h> +#include <linux/types.h> +#include <linux/cdev.h> + #include <linux/scx200_gpio.h> +#include <linux/nsc_gpio.h> #define NAME "scx200_gpio" +#define DEVNAME NAME + +static struct platform_device *pdev; MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver"); @@ -26,70 +35,23 @@ static int major = 0; /* default to dynamic major */ module_param(major, int, 0); MODULE_PARM_DESC(major, "Major device number"); -static ssize_t scx200_gpio_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - unsigned m = iminor(file->f_dentry->d_inode); - size_t i; - - for (i = 0; i < len; ++i) { - char c; - if (get_user(c, data+i)) - return -EFAULT; - switch (c) - { - case '0': - scx200_gpio_set(m, 0); - break; - case '1': - scx200_gpio_set(m, 1); - break; - case 'O': - printk(KERN_INFO NAME ": GPIO%d output enabled\n", m); - scx200_gpio_configure(m, ~1, 1); - break; - case 'o': - printk(KERN_INFO NAME ": GPIO%d output disabled\n", m); - scx200_gpio_configure(m, ~1, 0); - break; - case 'T': - printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m); - scx200_gpio_configure(m, ~2, 2); - break; - case 't': - printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m); - scx200_gpio_configure(m, ~2, 0); - break; - case 'P': - printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m); - scx200_gpio_configure(m, ~4, 4); - break; - case 'p': - printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m); - scx200_gpio_configure(m, ~4, 0); - break; - } - } - - return len; -} - -static ssize_t scx200_gpio_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos) -{ - unsigned m = iminor(file->f_dentry->d_inode); - int value; - - value = scx200_gpio_get(m); - if (put_user(value ? '1' : '0', buf)) - return -EFAULT; - - return 1; -} +struct nsc_gpio_ops scx200_access = { + .owner = THIS_MODULE, + .gpio_config = scx200_gpio_configure, + .gpio_dump = nsc_gpio_dump, + .gpio_get = scx200_gpio_get, + .gpio_set = scx200_gpio_set, + .gpio_set_high = scx200_gpio_set_high, + .gpio_set_low = scx200_gpio_set_low, + .gpio_change = scx200_gpio_change, + .gpio_current = scx200_gpio_current +}; static int scx200_gpio_open(struct inode *inode, struct file *file) { unsigned m = iminor(inode); + file->private_data = &scx200_access; + if (m > 63) return -EINVAL; return nonseekable_open(inode, file); @@ -103,47 +65,81 @@ static int scx200_gpio_release(struct inode *inode, struct file *file) static struct file_operations scx200_gpio_fops = { .owner = THIS_MODULE, - .write = scx200_gpio_write, - .read = scx200_gpio_read, + .write = nsc_gpio_write, + .read = nsc_gpio_read, .open = scx200_gpio_open, .release = scx200_gpio_release, }; +struct cdev *scx200_devices; +static int num_pins = 32; + static int __init scx200_gpio_init(void) { - int r; - - printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n"); + int rc, i; + dev_t dev = MKDEV(major, 0); if (!scx200_gpio_present()) { - printk(KERN_ERR NAME ": no SCx200 gpio pins available\n"); + printk(KERN_ERR NAME ": no SCx200 gpio present\n"); return -ENODEV; } - r = register_chrdev(major, NAME, &scx200_gpio_fops); - if (r < 0) { - printk(KERN_ERR NAME ": unable to register character device\n"); - return r; + /* support dev_dbg() with pdev->dev */ + pdev = platform_device_alloc(DEVNAME, 0); + if (!pdev) + return -ENOMEM; + + rc = platform_device_add(pdev); + if (rc) + goto undo_malloc; + + /* nsc_gpio uses dev_dbg(), so needs this */ + scx200_access.dev = &pdev->dev; + + if (major) + rc = register_chrdev_region(dev, num_pins, "scx200_gpio"); + else { + rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio"); + major = MAJOR(dev); } - if (!major) { - major = r; - printk(KERN_DEBUG NAME ": got dynamic major %d\n", major); + if (rc < 0) { + dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc); + goto undo_platform_device_add; + } + scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL); + if (!scx200_devices) { + rc = -ENOMEM; + goto undo_chrdev_region; + } + for (i = 0; i < num_pins; i++) { + struct cdev *cdev = &scx200_devices[i]; + cdev_init(cdev, &scx200_gpio_fops); + cdev->owner = THIS_MODULE; + rc = cdev_add(cdev, MKDEV(major, i), 1); + /* tolerate 'minor' errors */ + if (rc) + dev_err(&pdev->dev, "Error %d on minor %d", rc, i); } - return 0; + return 0; /* succeed */ + +undo_chrdev_region: + unregister_chrdev_region(dev, num_pins); +undo_platform_device_add: + platform_device_put(pdev); +undo_malloc: + kfree(pdev); + return rc; } static void __exit scx200_gpio_cleanup(void) { - unregister_chrdev(major, NAME); + kfree(scx200_devices); + unregister_chrdev_region(MKDEV(major, 0), num_pins); + platform_device_put(pdev); + platform_device_unregister(pdev); + /* kfree(pdev); */ } module_init(scx200_gpio_init); module_exit(scx200_gpio_cleanup); - -/* - Local variables: - compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" - c-basic-offset: 8 - End: -*/ diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 1b5330299e3..d2d6b01dcd0 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -2477,7 +2477,7 @@ static int __init specialix_init(void) #endif for (i = 0; i < SX_NBOARD; i++) - sx_board[i].lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&sx_board[i].lock); if (sx_init_drivers()) { func_exit(); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index a9c5a7230f8..bf361a5ba70 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -141,15 +141,6 @@ static char *stl_drvversion = "5.6.0"; static struct tty_driver *stl_serial; /* - * We will need to allocate a temporary write buffer for chars that - * come direct from user space. The problem is that a copy from user - * space might cause a page fault (typically on a system that is - * swapping!). All ports will share one buffer - since if the system - * is already swapping a shared buffer won't make things any worse. - */ -static char *stl_tmpwritebuf; - -/* * Define a local default termios struct. All ports will be created * with this termios initially. Basically all it defines is a raw port * at 9600, 8 data bits, 1 stop bit. @@ -363,6 +354,14 @@ static unsigned char stl_vecmap[] = { }; /* + * Lock ordering is that you may not take stallion_lock holding + * brd_lock. + */ + +static spinlock_t brd_lock; /* Guard the board mapping */ +static spinlock_t stallion_lock; /* Guard the tty driver */ + +/* * Set up enable and disable macros for the ECH boards. They require * the secondary io address space to be activated and deactivated. * This way all ECH boards can share their secondary io region. @@ -725,17 +724,7 @@ static struct class *stallion_class; static int __init stallion_module_init(void) { - unsigned long flags; - -#ifdef DEBUG - printk("init_module()\n"); -#endif - - save_flags(flags); - cli(); stl_init(); - restore_flags(flags); - return 0; } @@ -746,7 +735,6 @@ static void __exit stallion_module_exit(void) stlbrd_t *brdp; stlpanel_t *panelp; stlport_t *portp; - unsigned long flags; int i, j, k; #ifdef DEBUG @@ -756,9 +744,6 @@ static void __exit stallion_module_exit(void) printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle, stl_drvversion); - save_flags(flags); - cli(); - /* * Free up all allocated resources used by the ports. This includes * memory and interrupts. As part of this process we will also do @@ -770,7 +755,6 @@ static void __exit stallion_module_exit(void) if (i) { printk("STALLION: failed to un-register tty driver, " "errno=%d\n", -i); - restore_flags(flags); return; } for (i = 0; i < 4; i++) { @@ -783,8 +767,6 @@ static void __exit stallion_module_exit(void) "errno=%d\n", -i); class_destroy(stallion_class); - kfree(stl_tmpwritebuf); - for (i = 0; (i < stl_nrbrds); i++) { if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) continue; @@ -814,8 +796,6 @@ static void __exit stallion_module_exit(void) kfree(brdp); stl_brds[i] = (stlbrd_t *) NULL; } - - restore_flags(flags); } module_init(stallion_module_init); @@ -948,7 +928,7 @@ static stlbrd_t *stl_allocbrd(void) brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL); if (!brdp) { - printk("STALLION: failed to allocate memory (size=%d)\n", + printk("STALLION: failed to allocate memory (size=%Zd)\n", sizeof(stlbrd_t)); return NULL; } @@ -1066,16 +1046,17 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp) rc = 0; doclocal = 0; + spin_lock_irqsave(&stallion_lock, flags); + if (portp->tty->termios->c_cflag & CLOCAL) doclocal++; - save_flags(flags); - cli(); portp->openwaitcnt++; if (! tty_hung_up_p(filp)) portp->refcount--; for (;;) { + /* Takes brd_lock internally */ stl_setsignals(portp, 1, 1); if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) { @@ -1093,13 +1074,14 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp) rc = -ERESTARTSYS; break; } + /* FIXME */ interruptible_sleep_on(&portp->open_wait); } if (! tty_hung_up_p(filp)) portp->refcount++; portp->openwaitcnt--; - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); return rc; } @@ -1119,16 +1101,15 @@ static void stl_close(struct tty_struct *tty, struct file *filp) if (portp == (stlport_t *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&stallion_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); return; } if ((tty->count == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); return; } @@ -1142,11 +1123,18 @@ static void stl_close(struct tty_struct *tty, struct file *filp) * (The sc26198 has no "end-of-data" interrupt only empty FIFO) */ tty->closing = 1; + + spin_unlock_irqrestore(&stallion_lock, flags); + if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, portp->closing_wait); stl_waituntilsent(tty, (HZ / 2)); + + spin_lock_irqsave(&stallion_lock, flags); portp->flags &= ~ASYNC_INITIALIZED; + spin_unlock_irqrestore(&stallion_lock, flags); + stl_disableintrs(portp); if (tty->termios->c_cflag & HUPCL) stl_setsignals(portp, 0, 0); @@ -1173,7 +1161,6 @@ static void stl_close(struct tty_struct *tty, struct file *filp) portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); - restore_flags(flags); } /*****************************************************************************/ @@ -1195,9 +1182,6 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count (int) tty, (int) buf, count); #endif - if ((tty == (struct tty_struct *) NULL) || - (stl_tmpwritebuf == (char *) NULL)) - return 0; portp = tty->driver_data; if (portp == (stlport_t *) NULL) return 0; @@ -1302,11 +1286,6 @@ static void stl_flushchars(struct tty_struct *tty) if (portp->tx.buf == (char *) NULL) return; -#if 0 - if (tty->stopped || tty->hw_stopped || - (portp->tx.head == portp->tx.tail)) - return; -#endif stl_startrxtx(portp, -1, 1); } @@ -1977,12 +1956,14 @@ static int stl_eiointr(stlbrd_t *brdp) unsigned int iobase; int handled = 0; + spin_lock(&brd_lock); panelp = brdp->panels[0]; iobase = panelp->iobase; while (inb(brdp->iostatus) & EIO_INTRPEND) { handled = 1; (* panelp->isr)(panelp, iobase); } + spin_unlock(&brd_lock); return handled; } @@ -2168,7 +2149,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) portp = kzalloc(sizeof(stlport_t), GFP_KERNEL); if (!portp) { printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlport_t)); + "(size=%Zd)\n", sizeof(stlport_t)); break; } @@ -2304,7 +2285,7 @@ static inline int stl_initeio(stlbrd_t *brdp) panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); if (!panelp) { printk(KERN_WARNING "STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlpanel_t)); + "(size=%Zd)\n", sizeof(stlpanel_t)); return -ENOMEM; } @@ -2478,7 +2459,7 @@ static inline int stl_initech(stlbrd_t *brdp) panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); if (!panelp) { printk("STALLION: failed to allocate memory " - "(size=%d)\n", sizeof(stlpanel_t)); + "(size=%Zd)\n", sizeof(stlpanel_t)); break; } panelp->magic = STL_PANELMAGIC; @@ -2879,8 +2860,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) portp->stats.lflags = 0; portp->stats.rxbuffered = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&stallion_lock, flags); if (portp->tty != (struct tty_struct *) NULL) { if (portp->tty->driver_data == portp) { portp->stats.ttystate = portp->tty->flags; @@ -2894,7 +2874,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp) } } } - restore_flags(flags); + spin_unlock_irqrestore(&stallion_lock, flags); head = portp->tx.head; tail = portp->tx.tail; @@ -3056,14 +3036,6 @@ static int __init stl_init(void) return -1; /* - * Allocate a temporary write buffer. - */ - stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); - if (!stl_tmpwritebuf) - printk("STALLION: failed to allocate memory (size=%d)\n", - STL_TXBUFSIZE); - -/* * Set up a character driver for per board stuff. This is mainly used * to do stats ioctls on the ports. */ @@ -3147,11 +3119,13 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) unsigned int gfrcr; int chipmask, i, j; int nrchips, uartaddr, ioaddr; + unsigned long flags; #ifdef DEBUG printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp); #endif + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(panelp->brdnr, panelp->pagenr); /* @@ -3189,6 +3163,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) } BRDDISABLE(panelp->brdnr); + spin_unlock_irqrestore(&brd_lock, flags); return chipmask; } @@ -3200,6 +3175,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp) static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp) { + unsigned long flags; #ifdef DEBUG printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n", (int) brdp, (int) panelp, (int) portp); @@ -3209,6 +3185,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po (portp == (stlport_t *) NULL)) return; + spin_lock_irqsave(&brd_lock, flags); portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) || (portp->portnr < 8)) ? 0 : EREG_BANKSIZE); portp->uartaddr = (portp->portnr & 0x04) << 5; @@ -3219,6 +3196,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po stl_cd1400setreg(portp, LIVR, (portp->portnr << 3)); portp->hwid = stl_cd1400getreg(portp, GFRCR); BRDDISABLE(portp->brdnr); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3428,8 +3406,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3)); srer = stl_cd1400getreg(portp, SRER); @@ -3466,7 +3443,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp) portp->sigs &= ~TIOCM_CD; stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron)); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3492,8 +3469,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) if (rts > 0) msvr2 = MSVR2_RTS; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); if (rts >= 0) @@ -3501,7 +3477,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts) if (dtr >= 0) stl_cd1400setreg(portp, MSVR1, msvr1); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3520,14 +3496,13 @@ static int stl_cd1400getsignals(stlport_t *portp) printk("stl_cd1400getsignals(portp=%x)\n", (int) portp); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); msvr1 = stl_cd1400getreg(portp, MSVR1); msvr2 = stl_cd1400getreg(portp, MSVR2); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); sigs = 0; sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; @@ -3569,15 +3544,14 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) ccr |= CCR_RXENABLE; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400ccrwait(portp); stl_cd1400setreg(portp, CCR, ccr); stl_cd1400ccrwait(portp); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3609,8 +3583,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) sreron |= SRER_RXDATA; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400setreg(portp, SRER, @@ -3618,7 +3591,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx) BRDDISABLE(portp->brdnr); if (tx > 0) set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3634,13 +3607,12 @@ static void stl_cd1400disableintrs(stlport_t *portp) #ifdef DEBUG printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400setreg(portp, SRER, 0); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3653,8 +3625,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400setreg(portp, SRER, @@ -3664,7 +3635,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len) portp->brklen = len; if (len == 1) portp->stats.txbreaks++; - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3688,8 +3659,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) if (tty == (struct tty_struct *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); @@ -3729,7 +3699,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state) } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3753,8 +3723,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state) if (tty == (struct tty_struct *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); if (state) { @@ -3769,7 +3738,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state) stl_cd1400ccrwait(portp); } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3785,8 +3754,7 @@ static void stl_cd1400flush(stlport_t *portp) if (portp == (stlport_t *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03)); stl_cd1400ccrwait(portp); @@ -3794,7 +3762,7 @@ static void stl_cd1400flush(stlport_t *portp) stl_cd1400ccrwait(portp); portp->tx.tail = portp->tx.head; BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -3833,6 +3801,7 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) (int) panelp, iobase); #endif + spin_lock(&brd_lock); outb(SVRR, iobase); svrtype = inb(iobase + EREG_DATA); if (panelp->nrports > 4) { @@ -3846,6 +3815,8 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase) stl_cd1400txisr(panelp, iobase); else if (svrtype & SVRR_MDM) stl_cd1400mdmisr(panelp, iobase); + + spin_unlock(&brd_lock); } /*****************************************************************************/ @@ -4433,8 +4404,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, IMR, 0); stl_sc26198updatereg(portp, MR0, mr0); @@ -4461,7 +4431,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp) portp->imr = (portp->imr & ~imroff) | imron; stl_sc26198setreg(portp, IMR, portp->imr); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4491,13 +4461,12 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts) else if (rts > 0) iopioron |= IPR_RTS; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, IOPIOR, ((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron)); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4516,12 +4485,11 @@ static int stl_sc26198getsignals(stlport_t *portp) printk("stl_sc26198getsignals(portp=%x)\n", (int) portp); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); ipr = stl_sc26198getreg(portp, IPR); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); sigs = 0; sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD; @@ -4558,13 +4526,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) ccr |= CR_RXENABLE; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, SCCR, ccr); BRDDISABLE(portp->brdnr); portp->crenable = ccr; - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4593,15 +4560,14 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx) else if (rx > 0) imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, IMR, imr); BRDDISABLE(portp->brdnr); portp->imr = imr; if (tx > 0) set_bit(ASYI_TXBUSY, &portp->istate); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4618,13 +4584,12 @@ static void stl_sc26198disableintrs(stlport_t *portp) printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); portp->imr = 0; stl_sc26198setreg(portp, IMR, 0); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4637,8 +4602,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len) printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); if (len == 1) { stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK); @@ -4647,7 +4611,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len) stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK); } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4672,8 +4636,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) if (tty == (struct tty_struct *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); if (state) { @@ -4719,7 +4682,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state) } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4744,8 +4707,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state) if (tty == (struct tty_struct *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); if (state) { mr0 = stl_sc26198getreg(portp, MR0); @@ -4765,7 +4727,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state) stl_sc26198setreg(portp, MR0, mr0); } BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4781,14 +4743,13 @@ static void stl_sc26198flush(stlport_t *portp) if (portp == (stlport_t *) NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); stl_sc26198setreg(portp, SCCR, CR_TXRESET); stl_sc26198setreg(portp, SCCR, portp->crenable); BRDDISABLE(portp->brdnr); portp->tx.tail = portp->tx.head; - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); } /*****************************************************************************/ @@ -4815,12 +4776,11 @@ static int stl_sc26198datastate(stlport_t *portp) if (test_bit(ASYI_TXBUSY, &portp->istate)) return 1; - save_flags(flags); - cli(); + spin_lock_irqsave(&brd_lock, flags); BRDENABLE(portp->brdnr, portp->pagenr); sr = stl_sc26198getreg(portp, SR); BRDDISABLE(portp->brdnr); - restore_flags(flags); + spin_unlock_irqrestore(&brd_lock, flags); return (sr & SR_TXEMPTY) ? 0 : 1; } @@ -4878,6 +4838,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) stlport_t *portp; unsigned int iack; + spin_lock(&brd_lock); + /* * Work around bug in sc26198 chip... Cannot have A6 address * line of UART high, else iack will be returned as 0. @@ -4893,6 +4855,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase) stl_sc26198txisr(portp); else stl_sc26198otherisr(portp, iack); + + spin_unlock(&brd_lock); } /*****************************************************************************/ diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 3b474723027..76b9107f7f8 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2320,7 +2320,7 @@ static int sx_init_portstructs (int nboards, int nports) #ifdef NEW_WRITE_LOCKING port->gs.port_write_mutex = MUTEX; #endif - port->gs.driver_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&port->gs.driver_lock); /* * Initializing wait queue */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 8b2a5996986..bd74e82d8a7 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2621,10 +2621,9 @@ int tty_ioctl(struct inode * inode, struct file * file, tty->driver->break_ctl(tty, 0); return 0; case TCSBRK: /* SVID version: non-zero arg --> no break */ - /* - * XXX is the above comment correct, or the - * code below correct? Is this ioctl used at - * all by anyone? + /* non-zero arg means wait for all output data + * to be sent (performed above) but don't send break. + * This is used by the tcdrain() termios function. */ if (!arg) return send_break(tty, 250); |