summaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig36
-rw-r--r--drivers/char/Makefile9
-rw-r--r--drivers/char/amiserial.c3
-rw-r--r--drivers/char/cyclades.c8
-rw-r--r--drivers/char/ds1302.c17
-rw-r--r--drivers/char/dsp56k.c23
-rw-r--r--drivers/char/efirtc.c35
-rw-r--r--drivers/char/epca.c58
-rw-r--r--drivers/char/esp.c5
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/hvc_console.c85
-rw-r--r--drivers/char/hvc_console.h35
-rw-r--r--drivers/char/hvc_irq.c44
-rw-r--r--drivers/char/hvc_iseries.c2
-rw-r--r--drivers/char/hvc_vio.c2
-rw-r--r--drivers/char/hvc_xen.c2
-rw-r--r--drivers/char/ip2/ip2main.c25
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c2
-rw-r--r--drivers/char/isicom.c30
-rw-r--r--drivers/char/istallion.c19
-rw-r--r--drivers/char/lcd.c516
-rw-r--r--drivers/char/lcd.h154
-rw-r--r--drivers/char/lp.c3
-rw-r--r--drivers/char/mem.c11
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/moxa.c3
-rw-r--r--drivers/char/mspec.c23
-rw-r--r--drivers/char/mwave/mwavedd.c39
-rw-r--r--drivers/char/mwave/mwavedd.h2
-rw-r--r--drivers/char/mwave/tp3780i.c2
-rw-r--r--drivers/char/mxser.c386
-rw-r--r--drivers/char/n_hdlc.c4
-rw-r--r--drivers/char/nvram.c1
-rw-r--r--drivers/char/nwflash.c31
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c3
-rw-r--r--drivers/char/pcmcia/synclink_cs.c5
-rw-r--r--drivers/char/ppdev.c23
-rw-r--r--drivers/char/random.c1
-rw-r--r--drivers/char/raw.c7
-rw-r--r--drivers/char/rio/rio_linux.c8
-rw-r--r--drivers/char/riscom8.c27
-rw-r--r--drivers/char/rocket.c5
-rw-r--r--drivers/char/rtc.c19
-rw-r--r--drivers/char/snsc.c3
-rw-r--r--drivers/char/specialix.c803
-rw-r--r--drivers/char/stallion.c21
-rw-r--r--drivers/char/sx.c76
-rw-r--r--drivers/char/synclink.c7
-rw-r--r--drivers/char/synclink_gt.c154
-rw-r--r--drivers/char/synclinkmp.c9
-rw-r--r--drivers/char/tty_io.c735
-rw-r--r--drivers/char/tty_ldisc.c714
-rw-r--r--drivers/char/vc_screen.c12
-rw-r--r--drivers/char/viotape.c8
-rw-r--r--drivers/char/virtio_console.c40
-rw-r--r--drivers/char/vme_scc.c5
-rw-r--r--drivers/char/vt.c22
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c6
59 files changed, 1859 insertions, 2477 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 650e6b44ce6..d0ac944e169 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -36,6 +36,14 @@ config VT
If unsure, say Y, or else you won't be able to do much with your new
shiny Linux system :-)
+config CONSOLE_TRANSLATIONS
+ depends on VT
+ default y
+ bool "Enable character translations in console" if EMBEDDED
+ ---help---
+ This enables support for font mapping and Unicode translation
+ on virtual consoles.
+
config VT_CONSOLE
bool "Support for console on virtual terminal" if EMBEDDED
depends on VT
@@ -300,16 +308,6 @@ config SPECIALIX
and compile this driver as kernel loadable module which will be
called specialix.
-config SPECIALIX_RTSCTS
- bool "Specialix DTR/RTS pin is RTS"
- depends on SPECIALIX
- help
- The Specialix IO8+ card can only support either RTS or DTR. If you
- say N here, the driver will use the pin as "DTR" when the tty is in
- software handshake mode. If you say Y here or hardware handshake is
- on, it will always be RTS. Read the file
- <file:Documentation/specialix.txt> for more information.
-
config SX
tristate "Specialix SX (and SI) card support"
depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
@@ -588,11 +586,14 @@ config HVC_DRIVER
It will automatically be selected if one of the back-end console drivers
is selected.
+config HVC_IRQ
+ bool
config HVC_CONSOLE
bool "pSeries Hypervisor Virtual Console support"
depends on PPC_PSERIES
select HVC_DRIVER
+ select HVC_IRQ
help
pSeries machines when partitioned support a hypervisor virtual
console. This driver allows each pSeries partition to have a console
@@ -603,6 +604,7 @@ config HVC_ISERIES
depends on PPC_ISERIES
default y
select HVC_DRIVER
+ select HVC_IRQ
help
iSeries machines support a hypervisor virtual console.
@@ -624,13 +626,18 @@ config HVC_XEN
bool "Xen Hypervisor Console support"
depends on XEN
select HVC_DRIVER
+ select HVC_IRQ
default y
help
Xen virtual console device driver
config VIRTIO_CONSOLE
- bool
+ tristate "Virtio console"
+ depends on VIRTIO
select HVC_DRIVER
+ help
+ Virtio console for use with lguest and other hypervisors.
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
@@ -867,13 +874,6 @@ config DS1302
endif # RTC_LIB
-config COBALT_LCD
- bool "Support for Cobalt LCD"
- depends on MIPS_COBALT
- help
- This option enables support for the LCD display and buttons found
- on Cobalt systems through a misc device.
-
config DTLK
tristate "Double Talk PC internal speech card support"
depends on ISA
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 0e0d12a0646..8a161c30e1d 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -7,13 +7,13 @@
#
FONTMAPFILE = cp437.uni
-obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
+obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-y += misc.o
-obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \
- consolemap_deftbl.o selection.o keyboard.o
+obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
obj-$(CONFIG_AUDIT) += tty_audit.o
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
@@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
+obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
@@ -63,7 +64,6 @@ obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
obj-$(CONFIG_PRINTER) += lp.o
-obj-$(CONFIG_TIPAR) += tipar.o
obj-$(CONFIG_APM_EMULATION) += apm-emulation.o
@@ -88,7 +88,6 @@ obj-$(CONFIG_TOSHIBA) += toshiba.o
obj-$(CONFIG_I8K) += i8k.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_HW_RANDOM) += hw_random/
-obj-$(CONFIG_COBALT_LCD) += lcd.o
obj-$(CONFIG_PPDEV) += ppdev.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 37457e5a4f2..3530ff417a5 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1248,7 +1248,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file,
/*
* rs_break() --- routine which turns the break handling on or off
*/
-static void rs_break(struct tty_struct *tty, int break_state)
+static int rs_break(struct tty_struct *tty, int break_state)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
unsigned long flags;
@@ -1263,6 +1263,7 @@ static void rs_break(struct tty_struct *tty, int break_state)
custom.adkcon = AC_UARTBRK;
mb();
local_irq_restore(flags);
+ return 0;
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e991dc85f2f..fe6d774fe2e 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -3700,14 +3700,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
/*
* cy_break() --- routine which turns the break handling on or off
*/
-static void cy_break(struct tty_struct *tty, int break_state)
+static int cy_break(struct tty_struct *tty, int break_state)
{
struct cyclades_port *info = tty->driver_data;
struct cyclades_card *card;
unsigned long flags;
+ int retval = 0;
if (serial_paranoia_check(info, tty->name, "cy_break"))
- return;
+ return -EINVAL;
card = info->card;
@@ -3736,8 +3737,6 @@ static void cy_break(struct tty_struct *tty, int break_state)
}
}
} else {
- int retval;
-
if (break_state == -1) {
retval = cyz_issue_cmd(card,
info->line - card->first_line,
@@ -3758,6 +3757,7 @@ static void cy_break(struct tty_struct *tty, int break_state)
}
}
spin_unlock_irqrestore(&card->card_lock, flags);
+ return retval;
} /* cy_break */
static int get_mon_info(struct cyclades_port *info,
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
index fada6ddefba..c5e67a62395 100644
--- a/drivers/char/ds1302.c
+++ b/drivers/char/ds1302.c
@@ -20,10 +20,11 @@
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/bcd.h>
+#include <linux/smp_lock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
-#include <asm/io.h>
#include <asm/rtc.h>
#if defined(CONFIG_M32R)
#include <asm/m32r.h>
@@ -153,9 +154,7 @@ static unsigned char days_in_mo[] =
/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
-static int
-rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long flags;
@@ -165,7 +164,9 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct rtc_time rtc_tm;
memset(&rtc_tm, 0, sizeof (struct rtc_time));
+ lock_kernel();
get_rtc_time(&rtc_tm);
+ unlock_kernel();
if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
return -EFAULT;
return 0;
@@ -217,6 +218,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
BIN_TO_BCD(mon);
BIN_TO_BCD(yrs);
+ lock_kernel();
local_irq_save(flags);
CMOS_WRITE(yrs, RTC_YEAR);
CMOS_WRITE(mon, RTC_MONTH);
@@ -225,6 +227,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
CMOS_WRITE(min, RTC_MINUTES);
CMOS_WRITE(sec, RTC_SECONDS);
local_irq_restore(flags);
+ unlock_kernel();
/* Notice that at this point, the RTC is updated but
* the kernel is still running with the old time.
@@ -244,8 +247,10 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
return -EFAULT;
+ lock_kernel();
tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
+ unlock_kernel();
return 0;
}
default:
@@ -282,7 +287,7 @@ get_rtc_status(char *buf)
static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
- .ioctl = rtc_ioctl,
+ .unlocked_ioctl = rtc_ioctl,
};
/* Probe for the chip by writing something to its RAM and try reading it back. */
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index b9a30c30e2b..19b88504e96 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -36,10 +36,10 @@
#include <linux/smp_lock.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/uaccess.h> /* For put_user and get_user */
#include <asm/atarihw.h>
#include <asm/traps.h>
-#include <asm/uaccess.h> /* For put_user and get_user */
#include <asm/dsp56k.h>
@@ -303,8 +303,8 @@ static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t co
}
}
-static int dsp56k_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long dsp56k_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
int dev = iminor(inode) & 0x0f;
void __user *argp = (void __user *)arg;
@@ -331,8 +331,9 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
if (len > DSP56K_MAX_BINARY_LENGTH) {
return -EINVAL;
}
-
+ lock_kernel();
r = dsp56k_upload(bin, len);
+ unlock_kernel();
if (r < 0) {
return r;
}
@@ -342,12 +343,16 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
case DSP56K_SET_TX_WSIZE:
if (arg > 4 || arg < 1)
return -EINVAL;
+ lock_kernel();
dsp56k.tx_wsize = (int) arg;
+ unlock_kernel();
break;
case DSP56K_SET_RX_WSIZE:
if (arg > 4 || arg < 1)
return -EINVAL;
+ lock_kernel();
dsp56k.rx_wsize = (int) arg;
+ unlock_kernel();
break;
case DSP56K_HOST_FLAGS:
{
@@ -359,6 +364,7 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
if(get_user(out, &hf->out) < 0)
return -EFAULT;
+ lock_kernel();
if ((dir & 0x1) && (out & 0x1))
dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
else if (dir & 0x1)
@@ -373,14 +379,16 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
-
+ unlock_kernel();
return put_user(status, &hf->status);
}
case DSP56K_HOST_CMD:
if (arg > 31 || arg < 0)
return -EINVAL;
+ lock_kernel();
dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
DSP56K_CVR_HC);
+ unlock_kernel();
break;
default:
return -EINVAL;
@@ -472,7 +480,7 @@ static const struct file_operations dsp56k_fops = {
.owner = THIS_MODULE,
.read = dsp56k_read,
.write = dsp56k_write,
- .ioctl = dsp56k_ioctl,
+ .unlocked_ioctl = dsp56k_ioctl,
.open = dsp56k_open,
.release = dsp56k_release,
};
@@ -500,7 +508,8 @@ static int __init dsp56k_init_driver(void)
err = PTR_ERR(dsp56k_class);
goto out_chrdev;
}
- device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
+ device_create_drvdata(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0),
+ NULL, "dsp56k");
printk(banner);
goto out;
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index d57ca3e4e53..67fbd7aab5d 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -37,8 +37,9 @@
#include <linux/rtc.h>
#include <linux/proc_fs.h>
#include <linux/efi.h>
+#include <linux/smp_lock.h>
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
#define EFI_RTC_VERSION "0.4"
@@ -51,8 +52,8 @@
static DEFINE_SPINLOCK(efi_rtc_lock);
-static int efi_rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+static long efi_rtc_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
#define is_leap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
@@ -146,9 +147,8 @@ convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
}
}
-static int
-efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static long efi_rtc_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
efi_status_t status;
@@ -175,13 +175,13 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EINVAL;
case RTC_RD_TIME:
-
+ lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
status = efi.get_time(&eft, &cap);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
-
+ unlock_kernel();
if (status != EFI_SUCCESS) {
/* should never happen */
printk(KERN_ERR "efitime: can't read time\n");
@@ -203,11 +203,13 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
convert_to_efi_time(&wtime, &eft);
+ lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
status = efi.set_time(&eft);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
+ unlock_kernel();
return status == EFI_SUCCESS ? 0 : -EINVAL;
@@ -223,6 +225,7 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
convert_to_efi_time(&wtime, &eft);
+ lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
/*
* XXX Fixme:
@@ -233,16 +236,19 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
status = efi.set_wakeup_time((efi_bool_t)enabled, &eft);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
+ unlock_kernel();
return status == EFI_SUCCESS ? 0 : -EINVAL;
case RTC_WKALM_RD:
+ lock_kernel();
spin_lock_irqsave(&efi_rtc_lock, flags);
status = efi.get_wakeup_time((efi_bool_t *)&enabled, (efi_bool_t *)&pending, &eft);
spin_unlock_irqrestore(&efi_rtc_lock,flags);
+ unlock_kernel();
if (status != EFI_SUCCESS) return -EINVAL;
@@ -256,7 +262,7 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return copy_to_user(&ewp->time, &wtime,
sizeof(struct rtc_time)) ? -EFAULT : 0;
}
- return -EINVAL;
+ return -ENOTTY;
}
/*
@@ -265,8 +271,7 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
* up things on a close.
*/
-static int
-efi_rtc_open(struct inode *inode, struct file *file)
+static int efi_rtc_open(struct inode *inode, struct file *file)
{
/*
* nothing special to do here
@@ -277,8 +282,7 @@ efi_rtc_open(struct inode *inode, struct file *file)
return 0;
}
-static int
-efi_rtc_close(struct inode *inode, struct file *file)
+static int efi_rtc_close(struct inode *inode, struct file *file)
{
return 0;
}
@@ -289,13 +293,12 @@ efi_rtc_close(struct inode *inode, struct file *file)
static const struct file_operations efi_rtc_fops = {
.owner = THIS_MODULE,
- .ioctl = efi_rtc_ioctl,
+ .unlocked_ioctl = efi_rtc_ioctl,
.open = efi_rtc_open,
.release = efi_rtc_close,
};
-static struct miscdevice efi_rtc_dev=
-{
+static struct miscdevice efi_rtc_dev= {
EFI_RTC_MINOR,
"efirtc",
&efi_rtc_fops
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index ac9995f6578..456e4ede049 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -184,9 +184,8 @@ static void pc_stop(struct tty_struct *);
static void pc_start(struct tty_struct *);
static void pc_throttle(struct tty_struct *tty);
static void pc_unthrottle(struct tty_struct *tty);
-static void digi_send_break(struct channel *ch, int msec);
+static int pc_send_break(struct tty_struct *tty, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
-static void epca_setup(char *, int *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void);
@@ -1040,6 +1039,7 @@ static const struct tty_operations pc_ops = {
.throttle = pc_throttle,
.unthrottle = pc_unthrottle,
.hangup = pc_hangup,
+ .break_ctl = pc_send_break
};
static int info_open(struct tty_struct *tty, struct file *filp)
@@ -1132,7 +1132,7 @@ static int __init pc_init(void)
pc_driver->init_termios.c_lflag = 0;
pc_driver->init_termios.c_ispeed = 9600;
pc_driver->init_termios.c_ospeed = 9600;
- pc_driver->flags = TTY_DRIVER_REAL_RAW;
+ pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
tty_set_operations(pc_driver, &pc_ops);
pc_info->owner = THIS_MODULE;
@@ -2177,7 +2177,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
digiflow_t dflow;
- int retval;
unsigned long flags;
unsigned int mflag, mstat;
unsigned char startc, stopc;
@@ -2189,37 +2188,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
bc = ch->brdchan;
else
return -EINVAL;
- /*
- * For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
- * /usr/src/linux/drivers/char for a good example. In particular think
- * about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
- */
switch (cmd) {
- 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 TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
@@ -2505,10 +2474,14 @@ static void pc_unthrottle(struct tty_struct *tty)
}
}
-static void digi_send_break(struct channel *ch, int msec)
+static int pc_send_break(struct tty_struct *tty, int msec)
{
+ struct channel *ch = (struct channel *) tty->driver_data;
unsigned long flags;
+ if (msec == -1)
+ return -EOPNOTSUPP;
+
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
/*
@@ -2521,6 +2494,7 @@ static void digi_send_break(struct channel *ch, int msec)
fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
+ return 0;
}
/* Caller MUST hold the lock */
@@ -2538,7 +2512,8 @@ static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
memoff(ch);
}
-static void epca_setup(char *str, int *ints)
+#ifndef MODULE
+static void __init epca_setup(char *str, int *ints)
{
struct board_info board;
int index, loop, last;
@@ -2792,6 +2767,17 @@ static void epca_setup(char *str, int *ints)
num_cards++;
}
+static int __init epca_real_setup(char *str)
+{
+ int ints[11];
+
+ epca_setup(get_options(str, 11, ints), ints);
+ return 1;
+}
+
+__setup("digiepca", epca_real_setup);
+#endif
+
enum epic_board_types {
brd_xr = 0,
brd_xem,
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 2eaf09f93e3..7f077c0097f 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1725,13 +1725,13 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file,
/*
* rs_break() --- routine which turns the break handling on or off
*/
-static void esp_break(struct tty_struct *tty, int break_state)
+static int esp_break(struct tty_struct *tty, int break_state)
{
struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "esp_break"))
- return;
+ return -EINVAL;
if (break_state == -1) {
spin_lock_irqsave(&info->lock, flags);
@@ -1747,6 +1747,7 @@ static void esp_break(struct tty_struct *tty, int break_state)
serial_out(info, UART_ESI_CMD2, 0x00);
spin_unlock_irqrestore(&info->lock, flags);
}
+ return 0;
}
static int rs_ioctl(struct tty_struct *tty, struct file *file,
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index fb0a85a1eb3..b3f5dbc6d88 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -623,6 +623,7 @@ static inline int hpet_tpcheck(struct hpet_task *tp)
return -ENXIO;
}
+#if 0
int hpet_unregister(struct hpet_task *tp)
{
struct hpet_dev *devp;
@@ -652,6 +653,7 @@ int hpet_unregister(struct hpet_task *tp)
return 0;
}
+#endif /* 0 */
static ctl_table hpet_table[] = {
{
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 2f9759d625c..02aac104842 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/kbd_kern.h>
#include <linux/kernel.h>
-#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -75,23 +74,6 @@ static int hvc_init(void);
static int sysrq_pressed;
#endif
-struct hvc_struct {
- spinlock_t lock;
- int index;
- struct tty_struct *tty;
- unsigned int count;
- int do_wakeup;
- char *outbuf;
- int outbuf_size;
- int n_outbuf;
- uint32_t vtermno;
- struct hv_ops *ops;
- int irq_requested;
- int irq;
- struct list_head next;
- struct kref kref; /* ref count & hvc_struct lifetime */
-};
-
/* dynamic list of hvc_struct instances */
static LIST_HEAD(hvc_structs);
@@ -298,27 +280,15 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
return 0;
}
+EXPORT_SYMBOL_GPL(hvc_instantiate);
/* Wake the sleeping khvcd */
-static void hvc_kick(void)
+void hvc_kick(void)
{
hvc_kicked = 1;
wake_up_process(hvc_task);
}
-
-static int hvc_poll(struct hvc_struct *hp);
-
-/*
- * NOTE: This API isn't used if the console adapter doesn't support interrupts.
- * In this case the console is poll driven.
- */
-static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
-{
- /* if hvc_poll request a repoll, then kick the hvcd thread */
- if (hvc_poll(dev_instance))
- hvc_kick();
- return IRQ_HANDLED;
-}
+EXPORT_SYMBOL_GPL(hvc_kick);
static void hvc_unthrottle(struct tty_struct *tty)
{
@@ -333,7 +303,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
unsigned long flags;
- int irq = 0;
int rc = 0;
/* Auto increments kref reference if found. */
@@ -352,18 +321,15 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */
hp->tty = tty;
- /* Save for request_irq outside of spin_lock. */
- irq = hp->irq;
- if (irq)
- hp->irq_requested = 1;
+
+ if (hp->ops->notifier_add)
+ rc = hp->ops->notifier_add(hp, hp->data);
spin_unlock_irqrestore(&hp->lock, flags);
- /* check error, fallback to non-irq */
- if (irq)
- rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
+
/*
- * If the request_irq() fails and we return an error. The tty layer
+ * If the notifier fails we return an error. The tty layer
* will call hvc_close() after a failed open but we don't want to clean
* up there so we'll clean up here and clear out the previously set
* tty fields and return the kref reference.
@@ -371,7 +337,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (rc) {
spin_lock_irqsave(&hp->lock, flags);
hp->tty = NULL;
- hp->irq_requested = 0;
spin_unlock_irqrestore(&hp->lock, flags);
tty->driver_data = NULL;
kref_put(&hp->kref, destroy_hvc_struct);
@@ -386,7 +351,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
static void hvc_close(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
- int irq = 0;
unsigned long flags;
if (tty_hung_up_p(filp))
@@ -404,9 +368,8 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
spin_lock_irqsave(&hp->lock, flags);
if (--hp->count == 0) {
- if (hp->irq_requested)
- irq = hp->irq;
- hp->irq_requested = 0;
+ if (hp->ops->notifier_del)
+ hp->ops->notifier_del(hp, hp->data);
/* We are done with the tty pointer now. */
hp->tty = NULL;
@@ -418,10 +381,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
* waking periodically to check chars_in_buffer().
*/
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
-
- if (irq)
- free_irq(irq, hp);
-
} else {
if (hp->count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
@@ -436,7 +395,6 @@ static void hvc_hangup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
- int irq = 0;
int temp_open_count;
if (!hp)
@@ -458,13 +416,12 @@ static void hvc_hangup(struct tty_struct *tty)
hp->count = 0;
hp->n_outbuf = 0;
hp->tty = NULL;
- if (hp->irq_requested)
- /* Saved for use outside of spin_lock. */
- irq = hp->irq;
- hp->irq_requested = 0;
+
+ if (hp->ops->notifier_del)
+ hp->ops->notifier_del(hp, hp->data);
+
spin_unlock_irqrestore(&hp->lock, flags);
- if (irq)
- free_irq(irq, hp);
+
while(temp_open_count) {
--temp_open_count;
kref_put(&hp->kref, destroy_hvc_struct);
@@ -575,7 +532,7 @@ static u32 timeout = MIN_TIMEOUT;
#define HVC_POLL_READ 0x00000001
#define HVC_POLL_WRITE 0x00000002
-static int hvc_poll(struct hvc_struct *hp)
+int hvc_poll(struct hvc_struct *hp)
{
struct tty_struct *tty;
int i, n, poll_mask = 0;
@@ -602,10 +559,10 @@ static int hvc_poll(struct hvc_struct *hp)
if (test_bit(TTY_THROTTLED, &tty->flags))
goto throttled;
- /* If we aren't interrupt driven and aren't throttled, we always
+ /* If we aren't notifier driven and aren't throttled, we always
* request a reschedule
*/
- if (hp->irq == 0)
+ if (!hp->irq_requested)
poll_mask |= HVC_POLL_READ;
/* Read data if any */
@@ -674,6 +631,7 @@ static int hvc_poll(struct hvc_struct *hp)
return poll_mask;
}
+EXPORT_SYMBOL_GPL(hvc_poll);
/*
* This kthread is either polling or interrupt driven. This is determined by
@@ -733,7 +691,7 @@ static const struct tty_operations hvc_ops = {
.chars_in_buffer = hvc_chars_in_buffer,
};
-struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
+struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size)
{
struct hvc_struct *hp;
@@ -754,7 +712,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
memset(hp, 0x00, sizeof(*hp));
hp->vtermno = vtermno;
- hp->irq = irq;
+ hp->data = data;
hp->ops = ops;
hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
@@ -784,6 +742,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
return hp;
}
+EXPORT_SYMBOL_GPL(hvc_alloc);
int __devexit hvc_remove(struct hvc_struct *hp)
{
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 42ffb17e15d..d9ce1091562 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -26,6 +26,7 @@
#ifndef HVC_CONSOLE_H
#define HVC_CONSOLE_H
+#include <linux/kref.h>
/*
* This is the max number of console adapters that can/will be found as
@@ -42,24 +43,50 @@
*/
#define HVC_ALLOC_TTY_ADAPTERS 8
+struct hvc_struct {
+ spinlock_t lock;
+ int index;
+ struct tty_struct *tty;
+ unsigned int count;
+ int do_wakeup;
+ char *outbuf;
+ int outbuf_size;
+ int n_outbuf;
+ uint32_t vtermno;
+ struct hv_ops *ops;
+ int irq_requested;
+ int data;
+ struct list_head next;
+ struct kref kref; /* ref count & hvc_struct lifetime */
+};
/* implemented by a low level driver */
struct hv_ops {
int (*get_chars)(uint32_t vtermno, char *buf, int count);
int (*put_chars)(uint32_t vtermno, const char *buf, int count);
-};
-struct hvc_struct;
+ /* Callbacks for notification. Called in open and close */
+ int (*notifier_add)(struct hvc_struct *hp, int irq);
+ void (*notifier_del)(struct hvc_struct *hp, int irq);
+};
/* Register a vterm and a slot index for use as a console (console_init) */
extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
/* register a vterm for hvc tty operation (module_init or hotplug add) */
-extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
+extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size);
-/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
extern int __devexit hvc_remove(struct hvc_struct *hp);
+/* data available */
+int hvc_poll(struct hvc_struct *hp);
+void hvc_kick(void);
+
+/* default notifier for irq based notification */
+extern int notifier_add_irq(struct hvc_struct *hp, int data);
+extern void notifier_del_irq(struct hvc_struct *hp, int data);
+
#if defined(CONFIG_XMON) && defined(CONFIG_SMP)
#include <asm/xmon.h>
diff --git a/drivers/char/hvc_irq.c b/drivers/char/hvc_irq.c
new file mode 100644
index 00000000000..73a59cdb894
--- /dev/null
+++ b/drivers/char/hvc_irq.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright IBM Corp. 2001,2008
+ *
+ * This file contains the IRQ specific code for hvc_console
+ *
+ */
+
+#include <linux/interrupt.h>
+
+#include "hvc_console.h"
+
+static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
+{
+ /* if hvc_poll request a repoll, then kick the hvcd thread */
+ if (hvc_poll(dev_instance))
+ hvc_kick();
+ return IRQ_HANDLED;
+}
+
+/*
+ * For IRQ based systems these callbacks can be used
+ */
+int notifier_add_irq(struct hvc_struct *hp, int irq)
+{
+ int rc;
+
+ if (!irq) {
+ hp->irq_requested = 0;
+ return 0;
+ }
+ rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
+ "hvc_console", hp);
+ if (!rc)
+ hp->irq_requested = 1;
+ return rc;
+}
+
+void notifier_del_irq(struct hvc_struct *hp, int irq)
+{
+ if (!irq)
+ return;
+ free_irq(irq, hp);
+ hp->irq_requested = 0;
+}
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index a08f8f981c1..b71c610fe5a 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -200,6 +200,8 @@ done:
static struct hv_ops hvc_get_put_ops = {
.get_chars = get_chars,
.put_chars = put_chars,
+ .notifier_add = notifier_add_irq,
+ .notifier_del = notifier_del_irq,
};
static int __devinit hvc_vio_probe(struct vio_dev *vdev,
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 79711aa4b41..93f3840c168 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
static struct hv_ops hvc_get_put_ops = {
.get_chars = filtered_get_chars,
.put_chars = hvc_put_chars,
+ .notifier_add = notifier_add_irq,
+ .notifier_del = notifier_del_irq,
};
static int __devinit hvc_vio_probe(struct vio_dev *vdev,
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
index db2ae421627..6b70aa66a58 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/char/hvc_xen.c
@@ -100,6 +100,8 @@ static int read_console(uint32_t vtermno, char *buf, int len)
static struct hv_ops hvc_ops = {
.get_chars = read_console,
.put_chars = write_console,
+ .notifier_add = notifier_add_irq,
+ .notifier_del = notifier_del_irq,
};
static int __init xen_init(void)
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 5dc74404058..689f9dcd3b8 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -203,7 +203,7 @@ static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);
-static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
+static long ip2_ipl_ioctl(struct file *, UINT, ULONG);
static int ip2_ipl_open(struct inode *, struct file *);
static int DumpTraceBuffer(char __user *, int);
@@ -236,7 +236,7 @@ static const struct file_operations ip2_ipl = {
.owner = THIS_MODULE,
.read = ip2_ipl_read,
.write = ip2_ipl_write,
- .ioctl = ip2_ipl_ioctl,
+ .unlocked_ioctl = ip2_ipl_ioctl,
.open = ip2_ipl_open,
};
@@ -718,12 +718,12 @@ ip2_loadmain(int *iop, int *irqp)
}
if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
- device_create(ip2_class, NULL,
- MKDEV(IP2_IPL_MAJOR, 4 * i),
- "ipl%d", i);
- device_create(ip2_class, NULL,
- MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
- "stat%d", i);
+ device_create_drvdata(ip2_class, NULL,
+ MKDEV(IP2_IPL_MAJOR, 4 * i),
+ NULL, "ipl%d", i);
+ device_create_drvdata(ip2_class, NULL,
+ MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
+ NULL, "stat%d", i);
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
@@ -2845,10 +2845,10 @@ ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t
/* */
/* */
/******************************************************************************/
-static int
-ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
+static long
+ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
{
- unsigned int iplminor = iminor(pInode);
+ unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
int rc = 0;
void __user *argp = (void __user *)arg;
ULONG __user *pIndex = argp;
@@ -2859,6 +2859,8 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
#endif
+ lock_kernel();
+
switch ( iplminor ) {
case 0: // IPL device
rc = -EINVAL;
@@ -2919,6 +2921,7 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
rc = -ENODEV;
break;
}
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index c11a4048345..64e1c169e82 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -871,7 +871,7 @@ static void ipmi_new_smi(int if_num, struct device *device)
entry->dev = dev;
mutex_lock(&reg_list_mutex);
- device_create(ipmi_class, device, dev, "ipmi%d", if_num);
+ device_create_drvdata(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
list_add(&entry->link, &reg_list);
mutex_unlock(&reg_list_mutex);
}
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index d4281df10c2..8f7cc190b62 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1181,14 +1181,17 @@ static int isicom_chars_in_buffer(struct tty_struct *tty)
}
/* ioctl et all */
-static inline void isicom_send_break(struct isi_port *port,
- unsigned long length)
+static int isicom_send_break(struct tty_struct *tty, int length)
{
+ struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card;
unsigned long base = card->base;
+ if (length == -1)
+ return -EOPNOTSUPP;
+
if (!lock_card(card))
- return;
+ return -EINVAL;
outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
outw((length & 0xff) << 8 | 0x00, base);
@@ -1196,6 +1199,7 @@ static inline void isicom_send_break(struct isi_port *port,
InterruptTheCard(base);
unlock_card(card);
+ return 0;
}
static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
@@ -1305,28 +1309,11 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
{
struct isi_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
- int retval;
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
switch (cmd) {
- case TCSBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- isicom_send_break(port, HZ/4);
- return 0;
-
- case TCSBRKP:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
- return 0;
case TIOCGSERIAL:
return isicom_get_serial_info(port, argp);
@@ -1459,6 +1446,7 @@ static const struct tty_operations isicom_ops = {
.flush_buffer = isicom_flush_buffer,
.tiocmget = isicom_tiocmget,
.tiocmset = isicom_tiocmset,
+ .break_ctl = isicom_send_break,
};
static int __devinit reset_card(struct pci_dev *pdev,
@@ -1832,7 +1820,7 @@ static int __init isicom_init(void)
isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
isicom_normal->flags = TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV;
+ TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK;
tty_set_operations(isicom_normal, &isicom_ops);
retval = tty_register_driver(isicom_normal);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 7930fba4baf..843a2afaf20 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -609,7 +609,7 @@ static void stli_unthrottle(struct tty_struct *tty);
static void stli_stop(struct tty_struct *tty);
static void stli_start(struct tty_struct *tty);
static void stli_flushbuffer(struct tty_struct *tty);
-static void stli_breakctl(struct tty_struct *tty, int state);
+static int stli_breakctl(struct tty_struct *tty, int state);
static void stli_waituntilsent(struct tty_struct *tty, int timeout);
static void stli_sendxchar(struct tty_struct *tty, char ch);
static void stli_hangup(struct tty_struct *tty);
@@ -925,8 +925,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
set_bit(TTY_IO_ERROR, &tty->flags);
- if (tty->ldisc.ops->flush_buffer)
- (tty->ldisc.ops->flush_buffer)(tty);
+ tty_ldisc_flush(tty);
set_bit(ST_DOFLUSHRX, &portp->state);
stli_flushbuffer(tty);
@@ -1909,7 +1908,7 @@ static void stli_flushbuffer(struct tty_struct *tty)
/*****************************************************************************/
-static void stli_breakctl(struct tty_struct *tty, int state)
+static int stli_breakctl(struct tty_struct *tty, int state)
{
struct stlibrd *brdp;
struct stliport *portp;
@@ -1917,15 +1916,16 @@ static void stli_breakctl(struct tty_struct *tty, int state)
portp = tty->driver_data;
if (portp == NULL)
- return;
+ return -EINVAL;
if (portp->brdnr >= stli_nrbrds)
- return;
+ return -EINVAL;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
- return;
+ return -EINVAL;
arg = (state == -1) ? BREAKON : BREAKOFF;
stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
+ return 0;
}
/*****************************************************************************/
@@ -4599,8 +4599,9 @@ static int __init istallion_module_init(void)
istallion_class = class_create(THIS_MODULE, "staliomem");
for (i = 0; i < 4; i++)
- device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
- "staliomem%d", i);
+ device_create_drvdata(istallion_class, NULL,
+ MKDEV(STL_SIOMEMMAJOR, i),
+ NULL, "staliomem%d", i);
return 0;
err_deinit:
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
deleted file mode 100644
index 1c29b20e4f4..00000000000
--- a/drivers/char/lcd.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * LCD, LED and Button interface for Cobalt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1997 by Andrew Bose
- *
- * Linux kernel version history:
- * March 2001: Ported from 2.0.34 by Liam Davies
- *
- */
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/mc146818rtc.h>
-#include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include "lcd.h"
-
-static int lcd_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
-static unsigned int lcd_present = 1;
-
-/* used in arch/mips/cobalt/reset.c */
-int led_state = 0;
-
-#if defined(CONFIG_TULIP) && 0
-
-#define MAX_INTERFACES 8
-static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES];
-static void *linkcheck_cookies[MAX_INTERFACES];
-
-int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie)
-{
- if (iface_num < 0 ||
- iface_num >= MAX_INTERFACES ||
- linkcheck_callbacks[iface_num] != NULL)
- return -1;
- linkcheck_callbacks[iface_num] = (linkcheck_func_t) func;
- linkcheck_cookies[iface_num] = cookie;
- return 0;
-}
-#endif
-
-static int lcd_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct lcd_display button_display;
- unsigned long address, a;
-
- switch (cmd) {
- case LCD_On:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x0F);
- break;
-
- case LCD_Off:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x08);
- break;
-
- case LCD_Reset:
- udelay(150);
- LCDWriteInst(0x3F);
- udelay(150);
- LCDWriteInst(0x3F);
- udelay(150);
- LCDWriteInst(0x3F);
- udelay(150);
- LCDWriteInst(0x3F);
- udelay(150);
- LCDWriteInst(0x01);
- udelay(150);
- LCDWriteInst(0x06);
- break;
-
- case LCD_Clear:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x01);
- break;
-
- case LCD_Cursor_Left:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x10);
- break;
-
- case LCD_Cursor_Right:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x14);
- break;
-
- case LCD_Cursor_Off:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x0C);
- break;
-
- case LCD_Cursor_On:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x0F);
- break;
-
- case LCD_Blink_Off:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x0E);
- break;
-
- case LCD_Get_Cursor_Pos:{
- struct lcd_display display;
-
- udelay(150);
- BusyCheck();
- display.cursor_address = (LCDReadInst);
- display.cursor_address =
- (display.cursor_address & 0x07F);
- if (copy_to_user
- ((struct lcd_display *) arg, &display,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- break;
- }
-
-
- case LCD_Set_Cursor_Pos:{
- struct lcd_display display;
-
- if (copy_from_user
- (&display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- a = (display.cursor_address | kLCD_Addr);
-
- udelay(150);
- BusyCheck();
- LCDWriteInst(a);
-
- break;
- }
-
- case LCD_Get_Cursor:{
- struct lcd_display display;
-
- udelay(150);
- BusyCheck();
- display.character = LCDReadData;
-
- if (copy_to_user
- ((struct lcd_display *) arg, &display,
- sizeof(struct lcd_display)))
- return -EFAULT;
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x10);
-
- break;
- }
-
- case LCD_Set_Cursor:{
- struct lcd_display display;
-
- if (copy_from_user
- (&display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- udelay(150);
- BusyCheck();
- LCDWriteData(display.character);
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x10);
-
- break;
- }
-
-
- case LCD_Disp_Left:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x18);
- break;
-
- case LCD_Disp_Right:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x1C);
- break;
-
- case LCD_Home:
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x02);
- break;
-
- case LCD_Write:{
- struct lcd_display display;
- unsigned int index;
-
-
- if (copy_from_user
- (&display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- udelay(150);
- BusyCheck();
- LCDWriteInst(0x80);
- udelay(150);
- BusyCheck();
-
- for (index = 0; index < (display.size1); index++) {
- udelay(150);
- BusyCheck();
- LCDWriteData(display.line1[index]);
- BusyCheck();
- }
-
- udelay(150);
- BusyCheck();
- LCDWriteInst(0xC0);
- udelay(150);
- BusyCheck();
- for (index = 0; index < (display.size2); index++) {
- udelay(150);
- BusyCheck();
- LCDWriteData(display.line2[index]);
- }
-
- break;
- }
-
- case LCD_Read:{
- struct lcd_display display;
-
- BusyCheck();
- for (address = kDD_R00; address <= kDD_R01;
- address++) {
- a = (address | kLCD_Addr);
-
- udelay(150);
- BusyCheck();
- LCDWriteInst(a);
- udelay(150);
- BusyCheck();
- display.line1[address] = LCDReadData;
- }
-
- display.line1[0x27] = '\0';
-
- for (address = kDD_R10; address <= kDD_R11;
- address++) {
- a = (address | kLCD_Addr);
-
- udelay(150);
- BusyCheck();
- LCDWriteInst(a);
-
- udelay(150);
- BusyCheck();
- display.line2[address - 0x40] =
- LCDReadData;
- }
-
- display.line2[0x27] = '\0';
-
- if (copy_to_user
- ((struct lcd_display *) arg, &display,
- sizeof(struct lcd_display)))
- return -EFAULT;
- break;
- }
-
-// set all GPIO leds to led_display.leds
-
- case LED_Set:{
- struct lcd_display led_display;
-
-
- if (copy_from_user
- (&led_display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- led_state = led_display.leds;
- LEDSet(led_state);
-
- break;
- }
-
-
-// set only bit led_display.leds
-
- case LED_Bit_Set:{
- unsigned int i;
- int bit = 1;
- struct lcd_display led_display;
-
-
- if (copy_from_user
- (&led_display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- for (i = 0; i < (int) led_display.leds; i++) {
- bit = 2 * bit;
- }
-
- led_state = led_state | bit;
- LEDSet(led_state);
- break;
- }
-
-// clear only bit led_display.leds
-
- case LED_Bit_Clear:{
- unsigned int i;
- int bit = 1;
- struct lcd_display led_display;
-
-
- if (copy_from_user
- (&led_display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
-
- for (i = 0; i < (int) led_display.leds; i++) {
- bit = 2 * bit;
- }
-
- led_state = led_state & ~bit;
- LEDSet(led_state);
- break;
- }
-
-
- case BUTTON_Read:{
- button_display.buttons = GPIRead;
- if (copy_to_user
- ((struct lcd_display *) arg, &button_display,
- sizeof(struct lcd_display)))
- return -EFAULT;
- break;
- }
-
- case LINK_Check:{
- button_display.buttons =
- *((volatile unsigned long *) (0xB0100060));
- if (copy_to_user
- ((struct lcd_display *) arg, &button_display,
- sizeof(struct lcd_display)))
- return -EFAULT;
- break;
- }
-
- case LINK_Check_2:{
- int iface_num;
-
- /* panel-utils should pass in the desired interface status is wanted for
- * in "buttons" of the structure. We will set this to non-zero if the
- * link is in fact up for the requested interface. --DaveM
- */
- if (copy_from_user
- (&button_display, (struct lcd_display *) arg,
- sizeof(button_display)))
- return -EFAULT;
- iface_num = button_display.buttons;
-#if defined(CONFIG_TULIP) && 0
- if (iface_num >= 0 &&
- iface_num < MAX_INTERFACES &&
- linkcheck_callbacks[iface_num] != NULL) {
- button_display.buttons =
- linkcheck_callbacks[iface_num]
- (linkcheck_cookies[iface_num]);
- } else
-#endif
- button_display.buttons = 0;
-
- if (__copy_to_user
- ((struct lcd_display *) arg, &button_display,
- sizeof(struct lcd_display)))
- return -EFAULT;
- break;
- }
-
- default:
- return -EINVAL;
-
- }
-
- return 0;
-
-}
-
-static int lcd_open(struct inode *inode, struct file *file)
-{
- cycle_kernel_lock();
-
- if (!lcd_present)
- return -ENXIO;
- else
- return 0;
-}
-
-/* Only RESET or NEXT counts as button pressed */
-
-static inline int button_pressed(void)
-{
- unsigned long buttons = GPIRead;
-
- if ((buttons == BUTTON_Next) || (buttons == BUTTON_Next_B)
- || (buttons == BUTTON_Reset_B))
- return buttons;
- return 0;
-}
-
-/* LED daemon sits on this and we wake him up once a key is pressed. */
-
-static int lcd_waiters = 0;
-
-static ssize_t lcd_read(struct file *file, char *buf,
- size_t count, loff_t *ofs)
-{
- long buttons_now;
-
- if (lcd_waiters > 0)
- return -EINVAL;
-
- lcd_waiters++;
- while (((buttons_now = (long) button_pressed()) == 0) &&
- !(signal_pending(current))) {
- msleep_interruptible(2000);
- }
- lcd_waiters--;
-
- if (signal_pending(current))
- return -ERESTARTSYS;
- return buttons_now;
-}
-
-/*
- * The various file operations we support.
- */
-
-static const struct file_operations lcd_fops = {
- .read = lcd_read,
- .ioctl = lcd_ioctl,
- .open = lcd_open,
-};
-
-static struct miscdevice lcd_dev = {
- MISC_DYNAMIC_MINOR,
- "lcd",
- &lcd_fops
-};
-
-static int lcd_init(void)
-{
- int ret;
- unsigned long data;
-
- pr_info("%s\n", LCD_DRIVER);
- ret = misc_register(&lcd_dev);
- if (ret) {
- printk(KERN_WARNING LCD "Unable to register misc device.\n");
- return ret;
- }
-
- /* Check region? Naaah! Just snarf it up. */
-/* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/
-
- udelay(150);
- data = LCDReadData;
- if ((data & 0x000000FF) == (0x00)) {
- lcd_present = 0;
- pr_info(LCD "LCD Not Present\n");
- } else {
- lcd_present = 1;
- WRITE_GAL(kGal_DevBank2PReg, kGal_DevBank2Cfg);
- WRITE_GAL(kGal_DevBank3PReg, kGal_DevBank3Cfg);
- }
-
- return 0;
-}
-
-static void __exit lcd_exit(void)
-{
- misc_deregister(&lcd_dev);
-}
-
-module_init(lcd_init);
-module_exit(lcd_exit);
-
-MODULE_AUTHOR("Andrew Bose");
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/lcd.h b/drivers/char/lcd.h
deleted file mode 100644
index 290b3ff23b0..00000000000
--- a/drivers/char/lcd.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * LED, LCD and Button panel driver for Cobalt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1997 by Andrew Bose
- *
- * Linux kernel version history:
- * March 2001: Ported from 2.0.34 by Liam Davies
- *
- */
-
-// function headers
-
-#define LCD_CHARS_PER_LINE 40
-#define MAX_IDLE_TIME 120
-
-struct lcd_display {
- unsigned buttons;
- int size1;
- int size2;
- unsigned char line1[LCD_CHARS_PER_LINE];
- unsigned char line2[LCD_CHARS_PER_LINE];
- unsigned char cursor_address;
- unsigned char character;
- unsigned char leds;
- unsigned char *RomImage;
-};
-
-
-
-#define LCD_DRIVER "Cobalt LCD Driver v2.10"
-
-#define LCD "lcd: "
-
-#define kLCD_IR 0x0F000000
-#define kLCD_DR 0x0F000010
-#define kGPI 0x0D000000
-#define kLED 0x0C000000
-
-#define kDD_R00 0x00
-#define kDD_R01 0x27
-#define kDD_R10 0x40
-#define kDD_R11 0x67
-
-#define kLCD_Addr 0x00000080
-
-#define LCDTimeoutValue 0xfff
-
-
-// Macros
-
-#define LCDWriteData(x) outl((x << 24), kLCD_DR)
-#define LCDWriteInst(x) outl((x << 24), kLCD_IR)
-
-#define LCDReadData (inl(kLCD_DR) >> 24)
-#define LCDReadInst (inl(kLCD_IR) >> 24)
-
-#define GPIRead (inl(kGPI) >> 24)
-
-#define LEDSet(x) outb((char)x, kLED)
-
-#define WRITE_GAL(x,y) outl(y, 0x04000000 | (x))
-#define BusyCheck() while ((LCDReadInst & 0x80) == 0x80)
-
-
-
-/*
- * Function command codes for io_ctl.
- */
-#define LCD_On 1
-#define LCD_Off 2
-#define LCD_Clear 3
-#define LCD_Reset 4
-#define LCD_Cursor_Left 5
-#define LCD_Cursor_Right 6
-#define LCD_Disp_Left 7
-#define LCD_Disp_Right 8
-#define LCD_Get_Cursor 9
-#define LCD_Set_Cursor 10
-#define LCD_Home 11
-#define LCD_Read 12
-#define LCD_Write 13
-#define LCD_Cursor_Off 14
-#define LCD_Cursor_On 15
-#define LCD_Get_Cursor_Pos 16
-#define LCD_Set_Cursor_Pos 17
-#define LCD_Blink_Off 18
-
-#define LED_Set 40
-#define LED_Bit_Set 41
-#define LED_Bit_Clear 42
-
-
-// Button defs
-#define BUTTON_Read 50
-
-
-// Ethernet LINK check hackaroo
-#define LINK_Check 90
-#define LINK_Check_2 91
-
-// Button patterns _B - single layer lcd boards
-
-#define BUTTON_NONE 0x3F
-#define BUTTON_NONE_B 0xFE
-
-#define BUTTON_Left 0x3B
-#define BUTTON_Left_B 0xFA
-
-#define BUTTON_Right 0x37
-#define BUTTON_Right_B 0xDE
-
-#define BUTTON_Up 0x2F
-#define BUTTON_Up_B 0xF6
-
-#define BUTTON_Down 0x1F
-#define BUTTON_Down_B 0xEE
-
-#define BUTTON_Next 0x3D
-#define BUTTON_Next_B 0x7E
-
-#define BUTTON_Enter 0x3E
-#define BUTTON_Enter_B 0xBE
-
-#define BUTTON_Reset_B 0xFC
-
-
-// debounce constants
-
-#define BUTTON_SENSE 160000
-#define BUTTON_DEBOUNCE 5000
-
-
-// Galileo register stuff
-
-#define kGal_DevBank2Cfg 0x1466DB33
-#define kGal_DevBank2PReg 0x464
-#define kGal_DevBank3Cfg 0x146FDFFB
-#define kGal_DevBank3PReg 0x468
-
-// Network
-
-#define kIPADDR 1
-#define kNETMASK 2
-#define kGATEWAY 3
-#define kDNS 4
-
-#define kClassA 5
-#define kClassB 6
-#define kClassC 7
-
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 71abb4c33aa..3f2719b9f77 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -813,7 +813,8 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
- device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
+ device_create_drvdata(lp_class, port->dev, MKDEV(LP_MAJOR, nr), NULL,
+ "lp%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index b6772d65754..672b08e694d 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -327,7 +327,10 @@ static void mmap_mem_close(struct vm_area_struct *vma)
static struct vm_operations_struct mmap_mem_ops = {
.open = mmap_mem_open,
- .close = mmap_mem_close
+ .close = mmap_mem_close,
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys
+#endif
};
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
@@ -989,9 +992,9 @@ static int __init chr_dev_init(void)
mem_class = class_create(THIS_MODULE, "mem");
for (i = 0; i < ARRAY_SIZE(devlist); i++)
- device_create(mem_class, NULL,
- MKDEV(MEM_MAJOR, devlist[i].minor),
- devlist[i].name);
+ device_create_drvdata(mem_class, NULL,
+ MKDEV(MEM_MAJOR, devlist[i].minor),
+ NULL, devlist[i].name);
return 0;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 6e1563c3d30..999aa779c08 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -217,8 +217,8 @@ int misc_register(struct miscdevice * misc)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
dev = MKDEV(MISC_MAJOR, misc->minor);
- misc->this_device = device_create(misc_class, misc->parent, dev,
- "%s", misc->name);
+ misc->this_device = device_create_drvdata(misc_class, misc->parent,
+ dev, NULL, "%s", misc->name);
if (IS_ERR(misc->this_device)) {
err = PTR_ERR(misc->this_device);
goto out;
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 2bba250ffc8..d3d7864e0c1 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -374,12 +374,13 @@ copy:
return ret;
}
-static void moxa_break_ctl(struct tty_struct *tty, int state)
+static int moxa_break_ctl(struct tty_struct *tty, int state)
{
struct moxa_port *port = tty->driver_data;
moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
Magic_code);
+ return 0;
}
static const struct tty_operations moxa_ops = {
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index fe2a95b5d3c..30f095a8c2d 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -193,25 +193,23 @@ mspec_close(struct vm_area_struct *vma)
}
/*
- * mspec_nopfn
+ * mspec_fault
*
* Creates a mspec page and maps it to user space.
*/
-static unsigned long
-mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
+static int
+mspec_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
unsigned long paddr, maddr;
unsigned long pfn;
- int index;
+ pgoff_t index = vmf->pgoff;
struct vma_data *vdata = vma->vm_private_data;
- BUG_ON(address < vdata->vm_start || address >= vdata->vm_end);
- index = (address - vdata->vm_start) >> PAGE_SHIFT;
maddr = (volatile unsigned long) vdata->maddr[index];
if (maddr == 0) {
maddr = uncached_alloc_page(numa_node_id(), 1);
if (maddr == 0)
- return NOPFN_OOM;
+ return VM_FAULT_OOM;
spin_lock(&vdata->lock);
if (vdata->maddr[index] == 0) {
@@ -231,13 +229,20 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
pfn = paddr >> PAGE_SHIFT;
- return pfn;
+ /*
+ * vm_insert_pfn can fail with -EBUSY, but in that case it will
+ * be because another thread has installed the pte first, so it
+ * is no problem.
+ */
+ vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
+
+ return VM_FAULT_NOPAGE;
}
static struct vm_operations_struct mspec_vm_ops = {
.open = mspec_open,
.close = mspec_close,
- .nopfn = mspec_nopfn
+ .fault = mspec_fault,
};
/*
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 50243fcd87e..4f8d67fed29 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -86,8 +86,8 @@ module_param(mwave_uart_io, int, 0);
static int mwave_open(struct inode *inode, struct file *file);
static int mwave_close(struct inode *inode, struct file *file);
-static int mwave_ioctl(struct inode *inode, struct file *filp,
- unsigned int iocmd, unsigned long ioarg);
+static long mwave_ioctl(struct file *filp, unsigned int iocmd,
+ unsigned long ioarg);
MWAVE_DEVICE_DATA mwave_s_mdd;
@@ -119,16 +119,16 @@ static int mwave_close(struct inode *inode, struct file *file)
return retval;
}
-static int mwave_ioctl(struct inode *inode, struct file *file,
- unsigned int iocmd, unsigned long ioarg)
+static long mwave_ioctl(struct file *file, unsigned int iocmd,
+ unsigned long ioarg)
{
unsigned int retval = 0;
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
void __user *arg = (void __user *)ioarg;
- PRINTK_5(TRACE_MWAVE,
- "mwavedd::mwave_ioctl, entry inode %p file %p cmd %x arg %x\n",
- inode, file, iocmd, (int) ioarg);
+ PRINTK_4(TRACE_MWAVE,
+ "mwavedd::mwave_ioctl, entry file %p cmd %x arg %x\n",
+ file, iocmd, (int) ioarg);
switch (iocmd) {
@@ -136,7 +136,9 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
" calling tp3780I_ResetDSP\n");
+ lock_kernel();
retval = tp3780I_ResetDSP(&pDrvData->rBDData);
+ unlock_kernel();
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
" retval %x from tp3780I_ResetDSP\n",
@@ -147,7 +149,9 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
" calling tp3780I_StartDSP\n");
+ lock_kernel();
retval = tp3780I_StartDSP(&pDrvData->rBDData);
+ unlock_kernel();
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
" retval %x from tp3780I_StartDSP\n",
@@ -161,8 +165,10 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
"mwavedd::mwave_ioctl,"
" IOCTL_MW_DSP_ABILITIES calling"
" tp3780I_QueryAbilities\n");
+ lock_kernel();
retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
&rAbilities);
+ unlock_kernel();
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
" retval %x from tp3780I_QueryAbilities\n",
@@ -193,11 +199,13 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
" size %lx, ioarg %lx pusBuffer %p\n",
rReadData.ulDataLength, ioarg, pusBuffer);
+ lock_kernel();
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd,
pusBuffer,
rReadData.ulDataLength,
rReadData.usDspAddress);
+ unlock_kernel();
}
break;
@@ -215,10 +223,12 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
" size %lx, ioarg %lx pusBuffer %p\n",
rReadData.ulDataLength / 2, ioarg,
pusBuffer);
+ lock_kernel();
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd, pusBuffer,
rReadData.ulDataLength / 2,
rReadData.usDspAddress);
+ unlock_kernel();
}
break;
@@ -236,10 +246,12 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
" size %lx, ioarg %lx pusBuffer %p\n",
rWriteData.ulDataLength, ioarg,
pusBuffer);
+ lock_kernel();
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd, pusBuffer,
rWriteData.ulDataLength,
rWriteData.usDspAddress);
+ unlock_kernel();
}
break;
@@ -257,10 +269,12 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
" size %lx, ioarg %lx pusBuffer %p\n",
rWriteData.ulDataLength, ioarg,
pusBuffer);
+ lock_kernel();
retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
iocmd, pusBuffer,
rWriteData.ulDataLength,
rWriteData.usDspAddress);
+ unlock_kernel();
}
break;
@@ -281,8 +295,10 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
ipcnum);
return -EINVAL;
}
+ lock_kernel();
pDrvData->IPCs[ipcnum].bIsHere = FALSE;
pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
+ unlock_kernel();
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
@@ -307,6 +323,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
+ lock_kernel();
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
DECLARE_WAITQUEUE(wait, current);
@@ -347,6 +364,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
" processing\n",
ipcnum);
}
+ unlock_kernel();
}
break;
@@ -365,19 +383,18 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
ipcnum);
return -EINVAL;
}
+ lock_kernel();
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) {
wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
}
}
+ unlock_kernel();
}
break;
default:
- PRINTK_ERROR(KERN_ERR_MWAVE "mwavedd::mwave_ioctl:"
- " Error: Unrecognized iocmd %x\n",
- iocmd);
return -ENOTTY;
break;
} /* switch */
@@ -460,7 +477,7 @@ static const struct file_operations mwave_fops = {
.owner = THIS_MODULE,
.read = mwave_read,
.write = mwave_write,
- .ioctl = mwave_ioctl,
+ .unlocked_ioctl = mwave_ioctl,
.open = mwave_open,
.release = mwave_close
};
diff --git a/drivers/char/mwave/mwavedd.h b/drivers/char/mwave/mwavedd.h
index 8eca61e0a19..7e0d530e2e0 100644
--- a/drivers/char/mwave/mwavedd.h
+++ b/drivers/char/mwave/mwavedd.h
@@ -147,4 +147,6 @@ typedef struct _MWAVE_DEVICE_DATA {
} MWAVE_DEVICE_DATA, *pMWAVE_DEVICE_DATA;
+extern MWAVE_DEVICE_DATA mwave_s_mdd;
+
#endif
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index f282976daaa..c6896970806 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -57,8 +57,6 @@
#include "3780i.h"
#include "mwavepub.h"
-extern MWAVE_DEVICE_DATA mwave_s_mdd;
-
static unsigned short s_ausThinkpadIrqToField[16] =
{ 0xFFFF, 0xFFFF, 0xFFFF, 0x0001, 0x0002, 0x0003, 0xFFFF, 0x0004,
0xFFFF, 0xFFFF, 0x0005, 0x0006, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007 };
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 6307e301bd2..e30575e8764 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -16,7 +16,6 @@
* Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
* <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
* - Fixed x86_64 cleanness
- * - Fixed sleep with spinlock held in mxser_send_break
*/
#include <linux/module.h>
@@ -47,20 +46,14 @@
#include "mxser.h"
-#define MXSER_VERSION "2.0.3" /* 1.11 */
+#define MXSER_VERSION "2.0.4" /* 1.12 */
#define MXSERMAJOR 174
-#define MXSERCUMAJOR 175
#define MXSER_BOARDS 4 /* Max. boards */
#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
#define MXSER_ISR_PASS_LIMIT 100
-#define MXSER_ERR_IOADDR -1
-#define MXSER_ERR_IRQ -2
-#define MXSER_ERR_IRQ_CONFLIT -3
-#define MXSER_ERR_VECTOR -4
-
/*CheckIsMoxaMust return value*/
#define MOXA_OTHER_UART 0x00
#define MOXA_MUST_MU150_HWID 0x01
@@ -71,12 +64,13 @@
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
+#define PCI_DEVICE_ID_POS104UL 0x1044
#define PCI_DEVICE_ID_CB108 0x1080
+#define PCI_DEVICE_ID_CP102UF 0x1023
#define PCI_DEVICE_ID_CB114 0x1142
#define PCI_DEVICE_ID_CP114UL 0x1143
#define PCI_DEVICE_ID_CB134I 0x1341
#define PCI_DEVICE_ID_CP138U 0x1380
-#define PCI_DEVICE_ID_POS104UL 0x1044
#define C168_ASIC_ID 1
@@ -142,7 +136,8 @@ static const struct mxser_cardinfo mxser_cards[] = {
{ "CB-134I series", 4, },
{ "CP-138U series", 8, },
{ "POS-104UL series", 4, },
- { "CP-114UL series", 4, }
+ { "CP-114UL series", 4, },
+/*30*/ { "CP-102UF series", 2, }
};
/* driver_data correspond to the lines in the structure above
@@ -172,18 +167,20 @@ static struct pci_device_id mxser_pcibrds[] = {
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 },
{ }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
-static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
+static unsigned long ioaddr[MXSER_BOARDS];
static int ttymajor = MXSERMAJOR;
/* Variables for insmod */
MODULE_AUTHOR("Casper Yang");
MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
-module_param_array(ioaddr, int, NULL, 0);
+module_param_array(ioaddr, ulong, NULL, 0);
+MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board");
module_param(ttymajor, int, 0);
MODULE_LICENSE("GPL");
@@ -193,7 +190,6 @@ struct mxser_log {
unsigned long txcnt[MXSER_PORTS];
};
-
struct mxser_mon {
unsigned long rxcnt;
unsigned long txcnt;
@@ -284,19 +280,9 @@ struct mxser_mstatus {
int dcd;
};
-static struct mxser_mstatus GMStatus[MXSER_PORTS];
-
-static int mxserBoardCAP[MXSER_BOARDS] = {
- 0, 0, 0, 0
- /* 0x180, 0x280, 0x200, 0x320 */
-};
-
static struct mxser_board mxser_boards[MXSER_BOARDS];
static struct tty_driver *mxvar_sdriver;
static struct mxser_log mxvar_log;
-static int mxvar_diagflag;
-static unsigned char mxser_msr[MXSER_PORTS + 1];
-static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
static void mxser_enable_must_enchance_mode(unsigned long baseio)
@@ -540,6 +526,7 @@ static void process_txrx_fifo(struct mxser_port *info)
static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
{
+ static unsigned char mxser_msr[MXSER_PORTS + 1];
unsigned char status = 0;
status = inb(baseaddr + UART_MSR);
@@ -1316,13 +1303,9 @@ static void mxser_flush_chars(struct tty_struct *tty)
struct mxser_port *info = tty->driver_data;
unsigned long flags;
- if (info->xmit_cnt <= 0 ||
- tty->stopped ||
- !info->port.xmit_buf ||
- (tty->hw_stopped &&
- (info->type != PORT_16550A) &&
- (!info->board->chip_flag)
- ))
+ if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf ||
+ (tty->hw_stopped && info->type != PORT_16550A &&
+ !info->board->chip_flag))
return;
spin_lock_irqsave(&info->slock, flags);
@@ -1340,9 +1323,7 @@ static int mxser_write_room(struct tty_struct *tty)
int ret;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
+ return ret < 0 ? 0 : ret;
}
static int mxser_chars_in_buffer(struct tty_struct *tty)
@@ -1414,7 +1395,6 @@ static int mxser_set_serial_info(struct mxser_port *info,
info->port.closing_wait = new_serial.closing_wait * HZ / 100;
info->port.tty->low_latency =
(info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->port.tty->low_latency = 0;
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
(new_serial.baud_base != info->baud_base ||
new_serial.custom_divisor !=
@@ -1464,27 +1444,6 @@ static int mxser_get_lsr_info(struct mxser_port *info,
return put_user(result, value);
}
-/*
- * This routine sends a break character out the serial port.
- */
-static void mxser_send_break(struct mxser_port *info, int duration)
-{
- unsigned long flags;
-
- if (!info->ioaddr)
- return;
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
- info->ioaddr + UART_LCR);
- spin_unlock_irqrestore(&info->slock, flags);
- schedule_timeout(duration);
- spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
- info->ioaddr + UART_LCR);
- spin_unlock_irqrestore(&info->slock, flags);
-}
-
static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
{
struct mxser_port *info = tty->driver_data;
@@ -1653,6 +1612,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
switch (cmd) {
case MOXA_GET_MAJOR:
+ printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl %x, fix "
+ "your userspace\n", current->comm, cmd);
return put_user(ttymajor, (int __user *)argp);
case MOXA_CHKPORTENABLE:
@@ -1670,62 +1631,60 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
ret = -EFAULT;
unlock_kernel();
return ret;
- case MOXA_GETMSTATUS:
+ case MOXA_GETMSTATUS: {
+ struct mxser_mstatus ms, __user *msu = argp;
lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
+ memset(&ms, 0, sizeof(ms));
- GMStatus[i].ri = 0;
- if (!port->ioaddr) {
- GMStatus[i].dcd = 0;
- GMStatus[i].dsr = 0;
- GMStatus[i].cts = 0;
- continue;
- }
+ if (!port->ioaddr)
+ goto copy;
if (!port->port.tty || !port->port.tty->termios)
- GMStatus[i].cflag =
- port->normal_termios.c_cflag;
+ ms.cflag = port->normal_termios.c_cflag;
else
- GMStatus[i].cflag =
- port->port.tty->termios->c_cflag;
+ ms.cflag = port->port.tty->termios->c_cflag;
status = inb(port->ioaddr + UART_MSR);
- if (status & 0x80 /*UART_MSR_DCD */ )
- GMStatus[i].dcd = 1;
- else
- GMStatus[i].dcd = 0;
-
- if (status & 0x20 /*UART_MSR_DSR */ )
- GMStatus[i].dsr = 1;
- else
- GMStatus[i].dsr = 0;
-
-
- if (status & 0x10 /*UART_MSR_CTS */ )
- GMStatus[i].cts = 1;
- else
- GMStatus[i].cts = 0;
+ if (status & UART_MSR_DCD)
+ ms.dcd = 1;
+ if (status & UART_MSR_DSR)
+ ms.dsr = 1;
+ if (status & UART_MSR_CTS)
+ ms.cts = 1;
+ copy:
+ if (copy_to_user(msu, &ms, sizeof(ms))) {
+ unlock_kernel();
+ return -EFAULT;
+ }
+ msu++;
}
unlock_kernel();
- if (copy_to_user(argp, GMStatus,
- sizeof(struct mxser_mstatus) * MXSER_PORTS))
- return -EFAULT;
return 0;
+ }
case MOXA_ASPP_MON_EXT: {
- int p, shiftbit;
- unsigned long opmode;
- unsigned cflag, iflag;
+ struct mxser_mon_ext *me; /* it's 2k, stack unfriendly */
+ unsigned int cflag, iflag, p;
+ u8 opmode;
+
+ me = kzalloc(sizeof(*me), GFP_KERNEL);
+ if (!me)
+ return -ENOMEM;
lock_kernel();
- for (i = 0; i < MXSER_BOARDS; i++) {
- for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
+ if (p >= ARRAY_SIZE(me->rx_cnt)) {
+ i = MXSER_BOARDS;
+ break;
+ }
port = &mxser_boards[i].ports[j];
if (!port->ioaddr)
continue;
- status = mxser_get_msr(port->ioaddr, 0, i);
+ status = mxser_get_msr(port->ioaddr, 0, p);
if (status & UART_MSR_TERI)
port->icount.rng++;
@@ -1737,16 +1696,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
port->icount.cts++;
port->mon_data.modem_status = status;
- mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
- mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
- mon_data_ext.up_rxcnt[i] =
- port->mon_data.up_rxcnt;
- mon_data_ext.up_txcnt[i] =
- port->mon_data.up_txcnt;
- mon_data_ext.modem_status[i] =
+ me->rx_cnt[p] = port->mon_data.rxcnt;
+ me->tx_cnt[p] = port->mon_data.txcnt;
+ me->up_rxcnt[p] = port->mon_data.up_rxcnt;
+ me->up_txcnt[p] = port->mon_data.up_txcnt;
+ me->modem_status[p] =
port->mon_data.modem_status;
- mon_data_ext.baudrate[i] =
- tty_get_baud_rate(port->port.tty);
+ me->baudrate[p] = tty_get_baud_rate(port->port.tty);
if (!port->port.tty || !port->port.tty->termios) {
cflag = port->normal_termios.c_cflag;
@@ -1756,40 +1712,31 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
iflag = port->port.tty->termios->c_iflag;
}
- mon_data_ext.databits[i] = cflag & CSIZE;
-
- mon_data_ext.stopbits[i] = cflag & CSTOPB;
-
- mon_data_ext.parity[i] =
- cflag & (PARENB | PARODD | CMSPAR);
-
- mon_data_ext.flowctrl[i] = 0x00;
+ me->databits[p] = cflag & CSIZE;
+ me->stopbits[p] = cflag & CSTOPB;
+ me->parity[p] = cflag & (PARENB | PARODD |
+ CMSPAR);
if (cflag & CRTSCTS)
- mon_data_ext.flowctrl[i] |= 0x03;
+ me->flowctrl[p] |= 0x03;
if (iflag & (IXON | IXOFF))
- mon_data_ext.flowctrl[i] |= 0x0C;
+ me->flowctrl[p] |= 0x0C;
if (port->type == PORT_16550A)
- mon_data_ext.fifo[i] = 1;
- else
- mon_data_ext.fifo[i] = 0;
+ me->fifo[p] = 1;
- p = i % 4;
- shiftbit = p * 2;
- opmode = inb(port->opmode_ioaddr) >> shiftbit;
+ opmode = inb(port->opmode_ioaddr) >>
+ ((p % 4) * 2);
opmode &= OP_MODE_MASK;
-
- mon_data_ext.iftype[i] = opmode;
-
+ me->iftype[p] = opmode;
}
}
unlock_kernel();
- if (copy_to_user(argp, &mon_data_ext,
- sizeof(mon_data_ext)))
- return -EFAULT;
- return 0;
+ if (copy_to_user(argp, me, sizeof(*me)))
+ ret = -EFAULT;
+ kfree(me);
+ return ret;
}
default:
return -ENOIOCTLCMD;
@@ -1823,7 +1770,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
{
struct mxser_port *info = tty->driver_data;
struct async_icount cnow;
- struct serial_icounter_struct __user *p_cuser;
unsigned long flags;
void __user *argp = (void __user *)arg;
int retval;
@@ -1872,21 +1818,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
return -EIO;
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- mxser_send_break(info, HZ / 4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
- return 0;
case TIOCGSERIAL:
lock_kernel();
retval = mxser_get_serial_info(info, argp);
@@ -1918,30 +1849,26 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
- case TIOCGICOUNT:
+ case TIOCGICOUNT: {
+ struct serial_icounter_struct icnt = { 0 };
spin_lock_irqsave(&info->slock, flags);
cnow = info->icount;
spin_unlock_irqrestore(&info->slock, flags);
- p_cuser = argp;
- if (put_user(cnow.frame, &p_cuser->frame))
- return -EFAULT;
- if (put_user(cnow.brk, &p_cuser->brk))
- return -EFAULT;
- if (put_user(cnow.overrun, &p_cuser->overrun))
- return -EFAULT;
- if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
- return -EFAULT;
- if (put_user(cnow.parity, &p_cuser->parity))
- return -EFAULT;
- if (put_user(cnow.rx, &p_cuser->rx))
- return -EFAULT;
- if (put_user(cnow.tx, &p_cuser->tx))
- return -EFAULT;
- put_user(cnow.cts, &p_cuser->cts);
- put_user(cnow.dsr, &p_cuser->dsr);
- put_user(cnow.rng, &p_cuser->rng);
- put_user(cnow.dcd, &p_cuser->dcd);
- return 0;
+
+ icnt.frame = cnow.frame;
+ icnt.brk = cnow.brk;
+ icnt.overrun = cnow.overrun;
+ icnt.buf_overrun = cnow.buf_overrun;
+ icnt.parity = cnow.parity;
+ icnt.rx = cnow.rx;
+ icnt.tx = cnow.tx;
+ icnt.cts = cnow.cts;
+ icnt.dsr = cnow.dsr;
+ icnt.rng = cnow.rng;
+ icnt.dcd = cnow.dcd;
+
+ return copy_to_user(argp, &icnt, sizeof(icnt)) ? -EFAULT : 0;
+ }
case MOXA_HighSpeedOn:
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
case MOXA_SDS_RSTICOUNTER:
@@ -2219,7 +2146,7 @@ static void mxser_hangup(struct tty_struct *tty)
/*
* mxser_rs_break() --- routine which turns the break handling on or off
*/
-static void mxser_rs_break(struct tty_struct *tty, int break_state)
+static int mxser_rs_break(struct tty_struct *tty, int break_state)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
@@ -2232,6 +2159,7 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state)
outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
info->ioaddr + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
}
static void mxser_receive_chars(struct mxser_port *port, int *status)
@@ -2536,7 +2464,8 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
unsigned int i;
int retval;
- printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
+ printk(KERN_INFO "mxser: max. baud rate = %d bps\n",
+ brd->ports[0].max_baud);
for (i = 0; i < brd->info->nports; i++) {
info = &brd->ports[i];
@@ -2619,28 +2548,32 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
if (irq != (regs[9] & 0xFF00))
- return MXSER_ERR_IRQ_CONFLIT;
+ goto err_irqconflict;
} else if (brd->info->nports == 4) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if (irq != regs[9])
- return MXSER_ERR_IRQ_CONFLIT;
+ goto err_irqconflict;
} else if (brd->info->nports == 8) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if ((irq != regs[9]) || (irq != regs[10]))
- return MXSER_ERR_IRQ_CONFLIT;
+ goto err_irqconflict;
}
- if (!irq)
- return MXSER_ERR_IRQ;
+ if (!irq) {
+ printk(KERN_ERR "mxser: interrupt number unset\n");
+ return -EIO;
+ }
brd->irq = ((int)(irq & 0xF000) >> 12);
for (i = 0; i < 8; i++)
brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
- if ((regs[12] & 0x80) == 0)
- return MXSER_ERR_VECTOR;
+ if ((regs[12] & 0x80) == 0) {
+ printk(KERN_ERR "mxser: invalid interrupt vector\n");
+ return -EIO;
+ }
brd->vector = (int)regs[11]; /* interrupt vector */
if (id == 1)
brd->vector_mask = 0x00FF;
@@ -2667,13 +2600,26 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
else
brd->uart_type = PORT_16450;
if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
- "mxser(IO)"))
- return MXSER_ERR_IOADDR;
+ "mxser(IO)")) {
+ printk(KERN_ERR "mxser: can't request ports I/O region: "
+ "0x%.8lx-0x%.8lx\n",
+ brd->ports[0].ioaddr, brd->ports[0].ioaddr +
+ 8 * brd->info->nports - 1);
+ return -EIO;
+ }
if (!request_region(brd->vector, 1, "mxser(vector)")) {
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- return MXSER_ERR_VECTOR;
+ printk(KERN_ERR "mxser: can't request interrupt vector region: "
+ "0x%.8lx-0x%.8lx\n",
+ brd->ports[0].ioaddr, brd->ports[0].ioaddr +
+ 8 * brd->info->nports - 1);
+ return -EIO;
}
return brd->info->nports;
+
+err_irqconflict:
+ printk(KERN_ERR "mxser: invalid interrupt number\n");
+ return -EIO;
}
static int __devinit mxser_probe(struct pci_dev *pdev,
@@ -2690,20 +2636,20 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
break;
if (i >= MXSER_BOARDS) {
- printk(KERN_ERR "Too many Smartio/Industio family boards found "
- "(maximum %d), board not configured\n", MXSER_BOARDS);
+ dev_err(&pdev->dev, "too many boards found (maximum %d), board "
+ "not configured\n", MXSER_BOARDS);
goto err;
}
brd = &mxser_boards[i];
brd->idx = i * MXSER_PORTS_PER_BOARD;
- printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+ dev_info(&pdev->dev, "found MOXA %s board (BusNo=%d, DevNo=%d)\n",
mxser_cards[ent->driver_data].name,
pdev->bus->number, PCI_SLOT(pdev->devfn));
retval = pci_enable_device(pdev);
if (retval) {
- printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ dev_err(&pdev->dev, "PCI enable failed\n");
goto err;
}
@@ -2805,11 +2751,8 @@ static struct pci_driver mxser_driver = {
static int __init mxser_module_init(void)
{
struct mxser_board *brd;
- unsigned long cap;
- unsigned int i, m, isaloop;
- int retval, b;
-
- pr_debug("Loading module mxser ...\n");
+ unsigned int b, i, m;
+ int retval;
mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
if (!mxvar_sdriver)
@@ -2839,74 +2782,43 @@ static int __init mxser_module_init(void)
goto err_put;
}
- mxvar_diagflag = 0;
-
- m = 0;
/* Start finding ISA boards here */
- for (isaloop = 0; isaloop < 2; isaloop++)
- for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
- if (!isaloop)
- cap = mxserBoardCAP[b]; /* predefined */
- else
- cap = ioaddr[b]; /* module param */
+ for (m = 0, b = 0; b < MXSER_BOARDS; b++) {
+ if (!ioaddr[b])
+ continue;
+
+ brd = &mxser_boards[m];
+ retval = mxser_get_ISA_conf(!ioaddr[b], brd);
+ if (retval <= 0) {
+ brd->info = NULL;
+ continue;
+ }
- if (!cap)
- continue;
+ printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)\n",
+ brd->info->name, ioaddr[b]);
- brd = &mxser_boards[m];
- retval = mxser_get_ISA_conf(cap, brd);
-
- if (retval != 0)
- printk(KERN_INFO "Found MOXA %s board "
- "(CAP=0x%x)\n",
- brd->info->name, ioaddr[b]);
-
- if (retval <= 0) {
- if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt "
- "number, board not "
- "configured\n");
- else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt "
- "number, board not "
- "configured\n");
- else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt "
- "vector, board not "
- "configured\n");
- else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address, "
- "board not configured\n");
-
- brd->info = NULL;
- continue;
- }
-
- /* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd, NULL) < 0) {
- brd->info = NULL;
- continue;
- }
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
+ continue;
+ }
- brd->idx = m * MXSER_PORTS_PER_BOARD;
- for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i,
- NULL);
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
- m++;
- }
+ m++;
+ }
retval = pci_register_driver(&mxser_driver);
if (retval) {
- printk(KERN_ERR "Can't register pci driver\n");
+ printk(KERN_ERR "mxser: can't register pci driver\n");
if (!m) {
retval = -ENODEV;
goto err_unr;
} /* else: we have some ISA cards under control */
}
- pr_debug("Done.\n");
-
return 0;
err_unr:
tty_unregister_driver(mxvar_sdriver);
@@ -2919,8 +2831,6 @@ static void __exit mxser_module_exit(void)
{
unsigned int i, j;
- pr_debug("Unloading module mxser ...\n");
-
pci_unregister_driver(&mxser_driver);
for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
@@ -2934,8 +2844,6 @@ static void __exit mxser_module_exit(void)
for (i = 0; i < MXSER_BOARDS; i++)
if (mxser_boards[i].info != NULL)
mxser_release_res(&mxser_boards[i], NULL, 1);
-
- pr_debug("Done.\n");
}
module_init(mxser_module_init);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index ed4e03333ab..69ec6399c71 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -677,6 +677,10 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
/* Allocate transmit buffer */
/* sleep until transmit buffer available */
while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
+ if (file->f_flags & O_NONBLOCK) {
+ error = -EAGAIN;
+ break;
+ }
schedule();
n_hdlc = tty2n_hdlc (tty);
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index a22662b6a1a..39f6357e3b5 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -107,7 +107,6 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index ba012c2bdf7..f9f72a21129 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -122,35 +122,20 @@ static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cm
static ssize_t flash_read(struct file *file, char __user *buf, size_t size,
loff_t *ppos)
{
- unsigned long p = *ppos;
- unsigned int count = size;
- int ret = 0;
+ ssize_t ret;
if (flashdebug)
printk(KERN_DEBUG "flash_read: flash_read: offset=0x%lX, "
"buffer=%p, count=0x%X.\n", p, buf, count);
+ /*
+ * We now lock against reads and writes. --rmk
+ */
+ if (mutex_lock_interruptible(&nwflash_mutex))
+ return -ERESTARTSYS;
- if (count)
- ret = -ENXIO;
-
- if (p < gbFlashSize) {
- if (count > gbFlashSize - p)
- count = gbFlashSize - p;
+ ret = simple_read_from_buffer(buf, size, ppos, FLASH_BASE, gbFlashSize);
+ mutex_unlock(&nwflash_mutex);
- /*
- * We now lock against reads and writes. --rmk
- */
- if (mutex_lock_interruptible(&nwflash_mutex))
- return -ERESTARTSYS;
-
- ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
- if (ret == 0) {
- ret = count;
- *ppos += count;
- } else
- ret = -EFAULT;
- mutex_unlock(&nwflash_mutex);
- }
return ret;
}
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index e4a4fbd37d7..f070ae7bd91 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1896,7 +1896,7 @@ static int cm4000_probe(struct pcmcia_device *link)
return ret;
}
- device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
+ device_create_drvdata(cmm_class, NULL, MKDEV(major, i), NULL, "cmm%d", i);
return 0;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 6181f8a9b0b..0b5934bef7a 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -653,7 +653,8 @@ static int reader_probe(struct pcmcia_device *link)
return ret;
}
- device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
+ device_create_drvdata(cmx_class, NULL, MKDEV(major, i), NULL,
+ "cmx%d", i);
return 0;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b694d430f10..d1fceabe3ae 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2230,7 +2230,7 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
* Arguments: tty pointer to tty instance data
* break_state -1=set break condition, 0=clear
*/
-static void mgslpc_break(struct tty_struct *tty, int break_state)
+static int mgslpc_break(struct tty_struct *tty, int break_state)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
@@ -2240,7 +2240,7 @@ static void mgslpc_break(struct tty_struct *tty, int break_state)
__FILE__,__LINE__, info->device_name, break_state);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break"))
- return;
+ return -EINVAL;
spin_lock_irqsave(&info->lock,flags);
if (break_state == -1)
@@ -2248,6 +2248,7 @@ static void mgslpc_break(struct tty_struct *tty, int break_state)
else
clear_reg_bits(info, CHA+DAFO, BIT6);
spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
}
/* Service an IOCTL request
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index f6e6acadd9a..bee39fdfba7 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -67,7 +67,7 @@
#include <linux/major.h>
#include <linux/ppdev.h>
#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#define PP_VERSION "ppdev: user-space parallel port driver"
#define CHRDEV "ppdev"
@@ -328,10 +328,9 @@ static enum ieee1284_phase init_phase (int mode)
return IEEE1284_PH_FWD_IDLE;
}
-static int pp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- unsigned int minor = iminor(inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct pp_struct *pp = file->private_data;
struct parport * port;
void __user *argp = (void __user *)arg;
@@ -634,6 +633,15 @@ static int pp_ioctl(struct inode *inode, struct file *file,
return 0;
}
+static long pp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long ret;
+ lock_kernel();
+ ret = pp_do_ioctl(file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
static int pp_open (struct inode * inode, struct file * file)
{
unsigned int minor = iminor(inode);
@@ -745,15 +753,16 @@ static const struct file_operations pp_fops = {
.read = pp_read,
.write = pp_write,
.poll = pp_poll,
- .ioctl = pp_ioctl,
+ .unlocked_ioctl = pp_ioctl,
.open = pp_open,
.release = pp_release,
};
static void pp_attach(struct parport *port)
{
- device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number),
- "parport%d", port->number);
+ device_create_drvdata(ppdev_class, port->dev,
+ MKDEV(PP_MAJOR, port->number),
+ NULL, "parport%d", port->number);
}
static void pp_detach(struct parport *port)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 0cf98bd4f2d..e0d0e371909 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -236,6 +236,7 @@
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/interrupt.h>
+#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/percpu.h>
#include <linux/cryptohash.h>
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 505fcbe884a..47b8cf281d4 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -131,8 +131,8 @@ raw_ioctl(struct inode *inode, struct file *filp,
static void bind_device(struct raw_config_request *rq)
{
device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor));
- device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor),
- "raw%d", rq->raw_minor);
+ device_create_drvdata(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor),
+ NULL, "raw%d", rq->raw_minor);
}
/*
@@ -283,7 +283,8 @@ static int __init raw_init(void)
ret = PTR_ERR(raw_class);
goto error_region;
}
- device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), "rawctl");
+ device_create_drvdata(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL,
+ "rawctl");
return 0;
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 0cdfee15291..a8f68a3f14d 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -179,7 +179,7 @@ static int rio_set_real_termios(void *ptr);
static void rio_hungup(void *ptr);
static void rio_close(void *ptr);
static int rio_chars_in_buffer(void *ptr);
-static int rio_fw_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
static int rio_init_drivers(void);
static void my_hd(void *addr, int len);
@@ -240,7 +240,7 @@ static struct real_driver rio_real_driver = {
static const struct file_operations rio_fw_fops = {
.owner = THIS_MODULE,
- .ioctl = rio_fw_ioctl,
+ .unlocked_ioctl = rio_fw_ioctl,
};
static struct miscdevice rio_fw_device = {
@@ -560,13 +560,15 @@ static void rio_close(void *ptr)
-static int rio_fw_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int rc = 0;
func_enter();
/* The "dev" argument isn't used. */
+ lock_kernel();
rc = riocontrol(p, 0, cmd, arg, capable(CAP_SYS_ADMIN));
+ unlock_kernel();
func_exit();
return rc;
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 724b2b20f4b..2c6c8f33d6b 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -1250,11 +1250,15 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-static void rc_send_break(struct riscom_port *port, unsigned long length)
+static int rc_send_break(struct tty_struct *tty, int length)
{
+ struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp = port_Board(port);
unsigned long flags;
+ if (length == 0 || length == -1)
+ return -EOPNOTSUPP;
+
spin_lock_irqsave(&riscom_lock, flags);
port->break_length = RISCOM_TPS / HZ * length;
@@ -1268,6 +1272,7 @@ static void rc_send_break(struct riscom_port *port, unsigned long length)
rc_wait_CCR(bp);
spin_unlock_irqrestore(&riscom_lock, flags);
+ return 0;
}
static int rc_set_serial_info(struct riscom_port *port,
@@ -1342,27 +1347,12 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp,
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
void __user *argp = (void __user *)arg;
- int retval = 0;
+ int retval;
if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
return -ENODEV;
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- rc_send_break(port, HZ/4); /* 1/4 second */
- break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
- break;
case TIOCGSERIAL:
lock_kernel();
retval = rc_get_serial_info(port, argp);
@@ -1517,6 +1507,7 @@ static const struct tty_operations riscom_ops = {
.hangup = rc_hangup,
.tiocmget = rc_tiocmget,
.tiocmset = rc_tiocmset,
+ .break_ctl = rc_send_break,
};
static int __init rc_init_drivers(void)
@@ -1538,7 +1529,7 @@ static int __init rc_init_drivers(void)
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
riscom_driver->init_termios.c_ispeed = 9600;
riscom_driver->init_termios.c_ospeed = 9600;
- riscom_driver->flags = TTY_DRIVER_REAL_RAW;
+ riscom_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
tty_set_operations(riscom_driver, &riscom_ops);
error = tty_register_driver(riscom_driver);
if (error != 0) {
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index e670eae2f51..584d791e84a 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1236,13 +1236,13 @@ static void rp_set_termios(struct tty_struct *tty,
}
}
-static void rp_break(struct tty_struct *tty, int break_state)
+static int rp_break(struct tty_struct *tty, int break_state)
{
struct r_port *info = (struct r_port *) tty->driver_data;
unsigned long flags;
if (rocket_paranoia_check(info, "rp_break"))
- return;
+ return -EINVAL;
spin_lock_irqsave(&info->slock, flags);
if (break_state == -1)
@@ -1250,6 +1250,7 @@ static void rp_break(struct tty_struct *tty, int break_state)
else
sClrBreak(&info->channel);
spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
}
/*
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index fa92a8af5a5..dbefbb30ed4 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -78,9 +78,10 @@
#include <linux/wait.h>
#include <linux/bcd.h>
#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/uaccess.h>
#include <asm/current.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
#ifdef CONFIG_X86
@@ -120,8 +121,6 @@ static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
return 0;
}
#endif
-#else
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
#endif
/*
@@ -144,8 +143,7 @@ static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0);
static ssize_t rtc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
-static int rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#ifdef RTC_IRQ
static unsigned int rtc_poll(struct file *file, poll_table *wait);
@@ -719,10 +717,13 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
&wtime, sizeof wtime) ? -EFAULT : 0;
}
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- return rtc_do_ioctl(cmd, arg, 0);
+ long ret;
+ lock_kernel();
+ ret = rtc_do_ioctl(cmd, arg, 0);
+ unlock_kernel();
+ return ret;
}
/*
@@ -915,7 +916,7 @@ static const struct file_operations rtc_fops = {
#ifdef RTC_IRQ
.poll = rtc_poll,
#endif
- .ioctl = rtc_ioctl,
+ .unlocked_ioctl = rtc_ioctl,
.open = rtc_open,
.release = rtc_release,
.fasync = rtc_fasync,
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 0b799ac1b04..3ce60df14c0 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -444,7 +444,8 @@ scdrv_init(void)
continue;
}
- device_create(snsc_class, NULL, dev, "%s", devname);
+ device_create_drvdata(snsc_class, NULL, dev, NULL,
+ "%s", devname);
ia64_sn_irtr_intr_enable(scd->scd_nasid,
0 /*ignored */ ,
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 037dc47e4cb..242fd46fda2 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -77,7 +77,7 @@
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ioport.h>
@@ -92,7 +92,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/init.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "specialix_io8.h"
#include "cd1865.h"
@@ -110,9 +110,10 @@
static int sx_debug;
static int sx_rxfifo = SPECIALIX_RXFIFO;
+static int sx_rtscts;
#ifdef DEBUG
-#define dprintk(f, str...) if (sx_debug & f) printk (str)
+#define dprintk(f, str...) if (sx_debug & f) printk(str)
#else
#define dprintk(f, str...) /* nothing */
#endif
@@ -131,10 +132,8 @@ static int sx_rxfifo = SPECIALIX_RXFIFO;
#define SX_DEBUG_FIFO 0x0800
-#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__func__)
-#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __func__)
-
-#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
+#define func_enter() dprintk(SX_DEBUG_FLOW, "io8: enter %s\n", __func__)
+#define func_exit() dprintk(SX_DEBUG_FLOW, "io8: exit %s\n", __func__)
/* Configurable options: */
@@ -142,17 +141,6 @@ static int sx_rxfifo = SPECIALIX_RXFIFO;
/* Am I paranoid or not ? ;-) */
#define SPECIALIX_PARANOIA_CHECK
-/* Do I trust the IRQ from the card? (enabeling it doesn't seem to help)
- When the IRQ routine leaves the chip in a state that is keeps on
- requiring attention, the timer doesn't help either. */
-#undef SPECIALIX_TIMER
-
-#ifdef SPECIALIX_TIMER
-static int sx_poll = HZ;
-#endif
-
-
-
/*
* The following defines are mostly for testing purposes. But if you need
* some nice reporting in your syslog, you can define them also.
@@ -162,16 +150,6 @@ static int sx_poll = HZ;
-#ifdef CONFIG_SPECIALIX_RTSCTS
-#define SX_CRTSCTS(bla) 1
-#else
-#define SX_CRTSCTS(tty) C_CRTSCTS(tty)
-#endif
-
-
-/* Used to be outb (0xff, 0x80); */
-#define short_pause() udelay (1)
-
#define SPECIALIX_LEGAL_FLAGS \
(ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \
@@ -190,21 +168,14 @@ static struct specialix_board sx_board[SX_NBOARD] = {
static struct specialix_port sx_port[SX_NBOARD * SX_NPORT];
-#ifdef SPECIALIX_TIMER
-static struct timer_list missed_irq_timer;
-static irqreturn_t sx_interrupt(int irq, void * dev_id);
-#endif
-
-
-
-static inline int sx_paranoia_check(struct specialix_port const * port,
+static int sx_paranoia_check(struct specialix_port const *port,
char *name, const char *routine)
{
#ifdef SPECIALIX_PARANOIA_CHECK
- static const char *badmagic =
- KERN_ERR "sx: Warning: bad specialix port magic number for device %s in %s\n";
- static const char *badinfo =
- KERN_ERR "sx: Warning: null specialix port for device %s in %s\n";
+ static const char *badmagic = KERN_ERR
+ "sx: Warning: bad specialix port magic number for device %s in %s\n";
+ static const char *badinfo = KERN_ERR
+ "sx: Warning: null specialix port for device %s in %s\n";
if (!port) {
printk(badinfo, name, routine);
@@ -226,66 +197,69 @@ static inline int sx_paranoia_check(struct specialix_port const * port,
*/
/* Get board number from pointer */
-static inline int board_No (struct specialix_board * bp)
+static inline int board_No(struct specialix_board *bp)
{
return bp - sx_board;
}
/* Get port number from pointer */
-static inline int port_No (struct specialix_port const * port)
+static inline int port_No(struct specialix_port const *port)
{
return SX_PORT(port - sx_port);
}
/* Get pointer to board from pointer to port */
-static inline struct specialix_board * port_Board(struct specialix_port const * port)
+static inline struct specialix_board *port_Board(
+ struct specialix_port const *port)
{
return &sx_board[SX_BOARD(port - sx_port)];
}
/* Input Byte from CL CD186x register */
-static inline unsigned char sx_in(struct specialix_board * bp, unsigned short reg)
+static inline unsigned char sx_in(struct specialix_board *bp,
+ unsigned short reg)
{
bp->reg = reg | 0x80;
- outb (reg | 0x80, bp->base + SX_ADDR_REG);
- return inb (bp->base + SX_DATA_REG);
+ outb(reg | 0x80, bp->base + SX_ADDR_REG);
+ return inb(bp->base + SX_DATA_REG);
}
/* Output Byte to CL CD186x register */
-static inline void sx_out(struct specialix_board * bp, unsigned short reg,
+static inline void sx_out(struct specialix_board *bp, unsigned short reg,
unsigned char val)
{
bp->reg = reg | 0x80;
- outb (reg | 0x80, bp->base + SX_ADDR_REG);
- outb (val, bp->base + SX_DATA_REG);
+ outb(reg | 0x80, bp->base + SX_ADDR_REG);
+ outb(val, bp->base + SX_DATA_REG);
}
/* Input Byte from CL CD186x register */
-static inline unsigned char sx_in_off(struct specialix_board * bp, unsigned short reg)
+static inline unsigned char sx_in_off(struct specialix_board *bp,
+ unsigned short reg)
{
bp->reg = reg;
- outb (reg, bp->base + SX_ADDR_REG);
- return inb (bp->base + SX_DATA_REG);
+ outb(reg, bp->base + SX_ADDR_REG);
+ return inb(bp->base + SX_DATA_REG);
}
/* Output Byte to CL CD186x register */
-static inline void sx_out_off(struct specialix_board * bp, unsigned short reg,
- unsigned char val)
+static inline void sx_out_off(struct specialix_board *bp,
+ unsigned short reg, unsigned char val)
{
bp->reg = reg;
- outb (reg, bp->base + SX_ADDR_REG);
- outb (val, bp->base + SX_DATA_REG);
+ outb(reg, bp->base + SX_ADDR_REG);
+ outb(val, bp->base + SX_DATA_REG);
}
/* Wait for Channel Command Register ready */
-static inline void sx_wait_CCR(struct specialix_board * bp)
+static void sx_wait_CCR(struct specialix_board *bp)
{
unsigned long delay, flags;
unsigned char ccr;
@@ -296,7 +270,7 @@ static inline void sx_wait_CCR(struct specialix_board * bp)
spin_unlock_irqrestore(&bp->lock, flags);
if (!ccr)
return;
- udelay (1);
+ udelay(1);
}
printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
@@ -304,7 +278,7 @@ static inline void sx_wait_CCR(struct specialix_board * bp)
/* Wait for Channel Command Register ready */
-static inline void sx_wait_CCR_off(struct specialix_board * bp)
+static void sx_wait_CCR_off(struct specialix_board *bp)
{
unsigned long delay;
unsigned char crr;
@@ -316,7 +290,7 @@ static inline void sx_wait_CCR_off(struct specialix_board * bp)
spin_unlock_irqrestore(&bp->lock, flags);
if (!crr)
return;
- udelay (1);
+ udelay(1);
}
printk(KERN_ERR "sx%d: Timeout waiting for CCR.\n", board_No(bp));
@@ -327,7 +301,7 @@ static inline void sx_wait_CCR_off(struct specialix_board * bp)
* specialix IO8+ IO range functions.
*/
-static inline int sx_request_io_range(struct specialix_board * bp)
+static int sx_request_io_range(struct specialix_board *bp)
{
return request_region(bp->base,
bp->flags & SX_BOARD_IS_PCI ? SX_PCI_IO_SPACE : SX_IO_SPACE,
@@ -335,15 +309,15 @@ static inline int sx_request_io_range(struct specialix_board * bp)
}
-static inline void sx_release_io_range(struct specialix_board * bp)
+static void sx_release_io_range(struct specialix_board *bp)
{
- release_region(bp->base,
- bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE);
+ release_region(bp->base, bp->flags & SX_BOARD_IS_PCI ?
+ SX_PCI_IO_SPACE : SX_IO_SPACE);
}
/* Set the IRQ using the RTS lines that run to the PAL on the board.... */
-static int sx_set_irq ( struct specialix_board *bp)
+static int sx_set_irq(struct specialix_board *bp)
{
int virq;
int i;
@@ -353,15 +327,24 @@ static int sx_set_irq ( struct specialix_board *bp)
return 1;
switch (bp->irq) {
/* In the same order as in the docs... */
- case 15: virq = 0;break;
- case 12: virq = 1;break;
- case 11: virq = 2;break;
- case 9: virq = 3;break;
- default: printk (KERN_ERR "Speclialix: cannot set irq to %d.\n", bp->irq);
- return 0;
+ case 15:
+ virq = 0;
+ break;
+ case 12:
+ virq = 1;
+ break;
+ case 11:
+ virq = 2;
+ break;
+ case 9:
+ virq = 3;
+ break;
+ default:printk(KERN_ERR
+ "Speclialix: cannot set irq to %d.\n", bp->irq);
+ return 0;
}
spin_lock_irqsave(&bp->lock, flags);
- for (i=0;i<2;i++) {
+ for (i = 0; i < 2; i++) {
sx_out(bp, CD186x_CAR, i);
sx_out(bp, CD186x_MSVRTS, ((virq >> i) & 0x1)? MSVR_RTS:0);
}
@@ -371,7 +354,7 @@ static int sx_set_irq ( struct specialix_board *bp)
/* Reset and setup CD186x chip */
-static int sx_init_CD186x(struct specialix_board * bp)
+static int sx_init_CD186x(struct specialix_board *bp)
{
unsigned long flags;
int scaler;
@@ -390,7 +373,7 @@ static int sx_init_CD186x(struct specialix_board * bp)
sx_out_off(bp, CD186x_PILR2, SX_ACK_TINT); /* Prio for transmitter intr */
sx_out_off(bp, CD186x_PILR3, SX_ACK_RINT); /* Prio for receiver intr */
/* Set RegAckEn */
- sx_out_off(bp, CD186x_SRCR, sx_in (bp, CD186x_SRCR) | SRCR_REGACKEN);
+ sx_out_off(bp, CD186x_SRCR, sx_in(bp, CD186x_SRCR) | SRCR_REGACKEN);
/* Setting up prescaler. We need 4 ticks per 1 ms */
scaler = SX_OSCFREQ/SPECIALIX_TPS;
@@ -399,9 +382,9 @@ static int sx_init_CD186x(struct specialix_board * bp)
sx_out_off(bp, CD186x_PPRL, scaler & 0xff);
spin_unlock_irqrestore(&bp->lock, flags);
- if (!sx_set_irq (bp)) {
+ if (!sx_set_irq(bp)) {
/* Figure out how to pass this along... */
- printk (KERN_ERR "Cannot set irq to %d.\n", bp->irq);
+ printk(KERN_ERR "Cannot set irq to %d.\n", bp->irq);
rv = 0;
}
@@ -410,16 +393,16 @@ static int sx_init_CD186x(struct specialix_board * bp)
}
-static int read_cross_byte (struct specialix_board *bp, int reg, int bit)
+static int read_cross_byte(struct specialix_board *bp, int reg, int bit)
{
int i;
int t;
unsigned long flags;
spin_lock_irqsave(&bp->lock, flags);
- for (i=0, t=0;i<8;i++) {
- sx_out_off (bp, CD186x_CAR, i);
- if (sx_in_off (bp, reg) & bit)
+ for (i = 0, t = 0; i < 8; i++) {
+ sx_out_off(bp, CD186x_CAR, i);
+ if (sx_in_off(bp, reg) & bit)
t |= 1 << i;
}
spin_unlock_irqrestore(&bp->lock, flags);
@@ -428,37 +411,10 @@ static int read_cross_byte (struct specialix_board *bp, int reg, int bit)
}
-#ifdef SPECIALIX_TIMER
-void missed_irq (unsigned long data)
-{
- unsigned char irq;
- unsigned long flags;
- struct specialix_board *bp = (struct specialix_board *)data;
-
- spin_lock_irqsave(&bp->lock, flags);
- irq = sx_in ((struct specialix_board *)data, CD186x_SRSR) &
- (SRSR_RREQint |
- SRSR_TREQint |
- SRSR_MREQint);
- spin_unlock_irqrestore(&bp->lock, flags);
- if (irq) {
- printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
- sx_interrupt (-1, bp);
- }
- mod_timer(&missed_irq_timer, jiffies + sx_poll);
-}
-#endif
-
-
-
/* Main probing routine, also sets irq. */
static int sx_probe(struct specialix_board *bp)
{
unsigned char val1, val2;
-#if 0
- int irqs = 0;
- int retries;
-#endif
int rev;
int chip;
@@ -471,17 +427,18 @@ static int sx_probe(struct specialix_board *bp)
/* Are the I/O ports here ? */
sx_out_off(bp, CD186x_PPRL, 0x5a);
- short_pause ();
+ udelay(1);
val1 = sx_in_off(bp, CD186x_PPRL);
sx_out_off(bp, CD186x_PPRL, 0xa5);
- short_pause ();
+ udelay(1);
val2 = sx_in_off(bp, CD186x_PPRL);
- if ((val1 != 0x5a) || (val2 != 0xa5)) {
- printk(KERN_INFO "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
- board_No(bp), bp->base);
+ if (val1 != 0x5a || val2 != 0xa5) {
+ printk(KERN_INFO
+ "sx%d: specialix IO8+ Board at 0x%03x not found.\n",
+ board_No(bp), bp->base);
sx_release_io_range(bp);
func_exit();
return 1;
@@ -489,10 +446,11 @@ static int sx_probe(struct specialix_board *bp)
/* Check the DSR lines that Specialix uses as board
identification */
- val1 = read_cross_byte (bp, CD186x_MSVR, MSVR_DSR);
- val2 = read_cross_byte (bp, CD186x_MSVR, MSVR_RTS);
- dprintk (SX_DEBUG_INIT, "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
- board_No(bp), val1, val2);
+ val1 = read_cross_byte(bp, CD186x_MSVR, MSVR_DSR);
+ val2 = read_cross_byte(bp, CD186x_MSVR, MSVR_RTS);
+ dprintk(SX_DEBUG_INIT,
+ "sx%d: DSR lines are: %02x, rts lines are: %02x\n",
+ board_No(bp), val1, val2);
/* They managed to switch the bit order between the docs and
the IO8+ card. The new PCI card now conforms to old docs.
@@ -500,7 +458,8 @@ static int sx_probe(struct specialix_board *bp)
old card. */
val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2;
if (val1 != val2) {
- printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
+ printk(KERN_INFO
+ "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n",
board_No(bp), val2, bp->base, val1);
sx_release_io_range(bp);
func_exit();
@@ -508,47 +467,6 @@ static int sx_probe(struct specialix_board *bp)
}
-#if 0
- /* It's time to find IRQ for this board */
- for (retries = 0; retries < 5 && irqs <= 0; retries++) {
- irqs = probe_irq_on();
- sx_init_CD186x(bp); /* Reset CD186x chip */
- sx_out(bp, CD186x_CAR, 2); /* Select port 2 */
- sx_wait_CCR(bp);
- sx_out(bp, CD186x_CCR, CCR_TXEN); /* Enable transmitter */
- sx_out(bp, CD186x_IER, IER_TXRDY); /* Enable tx empty intr */
- msleep(50);
- irqs = probe_irq_off(irqs);
-
- dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
- dprintk (SX_DEBUG_INIT, "TRAR = %02x, ", sx_in(bp, CD186x_TRAR));
- dprintk (SX_DEBUG_INIT, "GIVR = %02x, ", sx_in(bp, CD186x_GIVR));
- dprintk (SX_DEBUG_INIT, "GICR = %02x, ", sx_in(bp, CD186x_GICR));
- dprintk (SX_DEBUG_INIT, "\n");
-
- /* Reset CD186x again */
- if (!sx_init_CD186x(bp)) {
- /* Hmmm. This is dead code anyway. */
- }
-
- dprintk (SX_DEBUG_INIT "val1 = %02x, val2 = %02x, val3 = %02x.\n",
- val1, val2, val3);
-
- }
-
-#if 0
- if (irqs <= 0) {
- printk(KERN_ERR "sx%d: Can't find IRQ for specialix IO8+ board at 0x%03x.\n",
- board_No(bp), bp->base);
- sx_release_io_range(bp);
- func_exit();
- return 1;
- }
-#endif
- printk (KERN_INFO "Started with irq=%d, but now have irq=%d.\n", bp->irq, irqs);
- if (irqs > 0)
- bp->irq = irqs;
-#endif
/* Reset CD186x again */
if (!sx_init_CD186x(bp)) {
sx_release_io_range(bp);
@@ -560,7 +478,7 @@ static int sx_probe(struct specialix_board *bp)
bp->flags |= SX_BOARD_PRESENT;
/* Chip revcode pkgtype
- GFRCR SRCR bit 7
+ GFRCR SRCR bit 7
CD180 rev B 0x81 0
CD180 rev C 0x82 0
CD1864 rev A 0x82 1
@@ -570,24 +488,32 @@ static int sx_probe(struct specialix_board *bp)
*/
switch (sx_in_off(bp, CD186x_GFRCR)) {
- case 0x82:chip = 1864;rev='A';break;
- case 0x83:chip = 1865;rev='A';break;
- case 0x84:chip = 1865;rev='B';break;
- case 0x85:chip = 1865;rev='C';break; /* Does not exist at this time */
- default:chip=-1;rev='x';
+ case 0x82:
+ chip = 1864;
+ rev = 'A';
+ break;
+ case 0x83:
+ chip = 1865;
+ rev = 'A';
+ break;
+ case 0x84:
+ chip = 1865;
+ rev = 'B';
+ break;
+ case 0x85:
+ chip = 1865;
+ rev = 'C';
+ break; /* Does not exist at this time */
+ default:
+ chip = -1;
+ rev = 'x';
}
- dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
-
-#ifdef SPECIALIX_TIMER
- setup_timer(&missed_irq_timer, missed_irq, (unsigned long)bp);
- mod_timer(&missed_irq_timer, jiffies + sx_poll);
-#endif
+ dprintk(SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR));
- printk(KERN_INFO"sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",
- board_No(bp),
- bp->base, bp->irq,
- chip, rev);
+ printk(KERN_INFO
+ "sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",
+ board_No(bp), bp->base, bp->irq, chip, rev);
func_exit();
return 0;
@@ -598,20 +524,22 @@ static int sx_probe(struct specialix_board *bp)
* Interrupt processing routines.
* */
-static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
- unsigned char const * what)
+static struct specialix_port *sx_get_port(struct specialix_board *bp,
+ unsigned char const *what)
{
unsigned char channel;
- struct specialix_port * port = NULL;
+ struct specialix_port *port = NULL;
channel = sx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF;
- dprintk (SX_DEBUG_CHAN, "channel: %d\n", channel);
+ dprintk(SX_DEBUG_CHAN, "channel: %d\n", channel);
if (channel < CD186x_NCH) {
port = &sx_port[board_No(bp) * SX_NPORT + channel];
- dprintk (SX_DEBUG_CHAN, "port: %d %p flags: 0x%lx\n",board_No(bp) * SX_NPORT + channel, port, port->port.flags & ASYNC_INITIALIZED);
+ dprintk(SX_DEBUG_CHAN, "port: %d %p flags: 0x%lx\n",
+ board_No(bp) * SX_NPORT + channel, port,
+ port->port.flags & ASYNC_INITIALIZED);
if (port->port.flags & ASYNC_INITIALIZED) {
- dprintk (SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
+ dprintk(SX_DEBUG_CHAN, "port: %d %p\n", channel, port);
func_exit();
return port;
}
@@ -622,7 +550,7 @@ static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
}
-static inline void sx_receive_exc(struct specialix_board * bp)
+static void sx_receive_exc(struct specialix_board *bp)
{
struct specialix_port *port;
struct tty_struct *tty;
@@ -633,7 +561,7 @@ static inline void sx_receive_exc(struct specialix_board * bp)
port = sx_get_port(bp, "Receive");
if (!port) {
- dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+ dprintk(SX_DEBUG_RX, "Hmm, couldn't find port.\n");
func_exit();
return;
}
@@ -641,19 +569,21 @@ static inline void sx_receive_exc(struct specialix_board * bp)
status = sx_in(bp, CD186x_RCSR);
- dprintk (SX_DEBUG_RX, "status: 0x%x\n", status);
+ dprintk(SX_DEBUG_RX, "status: 0x%x\n", status);
if (status & RCSR_OE) {
port->overrun++;
- dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Overrun. Total %ld overruns.\n",
- board_No(bp), port_No(port), port->overrun);
+ dprintk(SX_DEBUG_FIFO,
+ "sx%d: port %d: Overrun. Total %ld overruns.\n",
+ board_No(bp), port_No(port), port->overrun);
}
status &= port->mark_mask;
/* This flip buffer check needs to be below the reading of the
status register to reset the chip's IRQ.... */
if (tty_buffer_request_room(tty, 1) == 0) {
- dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
+ dprintk(SX_DEBUG_FIFO,
+ "sx%d: port %d: Working around flip buffer overflow.\n",
+ board_No(bp), port_No(port));
func_exit();
return;
}
@@ -664,8 +594,9 @@ static inline void sx_receive_exc(struct specialix_board * bp)
return;
}
if (status & RCSR_TOUT) {
- printk(KERN_INFO "sx%d: port %d: Receiver timeout. Hardware problems ?\n",
- board_No(bp), port_No(port));
+ printk(KERN_INFO
+ "sx%d: port %d: Receiver timeout. Hardware problems ?\n",
+ board_No(bp), port_No(port));
func_exit();
return;
@@ -688,13 +619,13 @@ static inline void sx_receive_exc(struct specialix_board * bp)
else
flag = TTY_NORMAL;
- if(tty_insert_flip_char(tty, ch, flag))
+ if (tty_insert_flip_char(tty, ch, flag))
tty_flip_buffer_push(tty);
func_exit();
}
-static inline void sx_receive(struct specialix_board * bp)
+static void sx_receive(struct specialix_board *bp)
{
struct specialix_port *port;
struct tty_struct *tty;
@@ -702,15 +633,16 @@ static inline void sx_receive(struct specialix_board * bp)
func_enter();
- if (!(port = sx_get_port(bp, "Receive"))) {
- dprintk (SX_DEBUG_RX, "Hmm, couldn't find port.\n");
+ port = sx_get_port(bp, "Receive");
+ if (port == NULL) {
+ dprintk(SX_DEBUG_RX, "Hmm, couldn't find port.\n");
func_exit();
return;
}
tty = port->port.tty;
count = sx_in(bp, CD186x_RDCR);
- dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
+ dprintk(SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
port->hits[count > 8 ? 9 : count]++;
tty_buffer_request_room(tty, count);
@@ -722,18 +654,19 @@ static inline void sx_receive(struct specialix_board * bp)
}
-static inline void sx_transmit(struct specialix_board * bp)
+static void sx_transmit(struct specialix_board *bp)
{
struct specialix_port *port;
struct tty_struct *tty;
unsigned char count;
func_enter();
- if (!(port = sx_get_port(bp, "Transmit"))) {
+ port = sx_get_port(bp, "Transmit");
+ if (port == NULL) {
func_exit();
return;
}
- dprintk (SX_DEBUG_TX, "port: %p\n", port);
+ dprintk(SX_DEBUG_TX, "port: %p\n", port);
tty = port->port.tty;
if (port->IER & IER_TXEMPTY) {
@@ -765,7 +698,8 @@ static inline void sx_transmit(struct specialix_board * bp)
sx_out(bp, CD186x_TDR, CD186x_C_ESC);
sx_out(bp, CD186x_TDR, CD186x_C_DELAY);
sx_out(bp, CD186x_TDR, count);
- if (!(port->break_length -= count))
+ port->break_length -= count;
+ if (port->break_length == 0)
port->break_length--;
} else {
sx_out(bp, CD186x_TDR, CD186x_C_ESC);
@@ -794,36 +728,36 @@ static inline void sx_transmit(struct specialix_board * bp)
sx_out(bp, CD186x_IER, port->IER);
}
if (port->xmit_cnt <= port->wakeup_chars)
- tty_wakeup(tty);
+ tty_wakeup(tty);
func_exit();
}
-static inline void sx_check_modem(struct specialix_board * bp)
+static void sx_check_modem(struct specialix_board *bp)
{
struct specialix_port *port;
struct tty_struct *tty;
unsigned char mcr;
int msvr_cd;
- dprintk (SX_DEBUG_SIGNALS, "Modem intr. ");
- if (!(port = sx_get_port(bp, "Modem")))
+ dprintk(SX_DEBUG_SIGNALS, "Modem intr. ");
+ port = sx_get_port(bp, "Modem");
+ if (port == NULL)
return;
tty = port->port.tty;
mcr = sx_in(bp, CD186x_MCR);
- printk ("mcr = %02x.\n", mcr);
if ((mcr & MCR_CDCHG)) {
- dprintk (SX_DEBUG_SIGNALS, "CD just changed... ");
+ dprintk(SX_DEBUG_SIGNALS, "CD just changed... ");
msvr_cd = sx_in(bp, CD186x_MSVR) & MSVR_CD;
if (msvr_cd) {
- dprintk (SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
+ dprintk(SX_DEBUG_SIGNALS, "Waking up guys in open.\n");
wake_up_interruptible(&port->port.open_wait);
} else {
- dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
+ dprintk(SX_DEBUG_SIGNALS, "Sending HUP.\n");
tty_hangup(tty);
}
}
@@ -874,9 +808,12 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
spin_lock_irqsave(&bp->lock, flags);
- dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
+ dprintk(SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__,
+ port_No(sx_get_port(bp, "INT")),
+ SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
if (!(bp->flags & SX_BOARD_ACTIVE)) {
- dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", bp->irq);
+ dprintk(SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n",
+ bp->irq);
spin_unlock_irqrestore(&bp->lock, flags);
func_exit();
return IRQ_NONE;
@@ -884,10 +821,11 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
saved_reg = bp->reg;
- while ((++loop < 16) && (status = (sx_in(bp, CD186x_SRSR) &
- (SRSR_RREQint |
- SRSR_TREQint |
- SRSR_MREQint)))) {
+ while (++loop < 16) {
+ status = sx_in(bp, CD186x_SRSR) &
+ (SRSR_RREQint | SRSR_TREQint | SRSR_MREQint);
+ if (status == 0)
+ break;
if (status & SRSR_RREQint) {
ack = sx_in(bp, CD186x_RRAR);
@@ -896,8 +834,9 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
else if (ack == (SX_ID | GIVR_IT_REXC))
sx_receive_exc(bp);
else
- printk(KERN_ERR "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
- board_No(bp), status, ack);
+ printk(KERN_ERR
+ "sx%d: status: 0x%x Bad receive ack 0x%02x.\n",
+ board_No(bp), status, ack);
} else if (status & SRSR_TREQint) {
ack = sx_in(bp, CD186x_TRAR);
@@ -906,14 +845,16 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
sx_transmit(bp);
else
printk(KERN_ERR "sx%d: status: 0x%x Bad transmit ack 0x%02x. port: %d\n",
- board_No(bp), status, ack, port_No (sx_get_port (bp, "Int")));
+ board_No(bp), status, ack,
+ port_No(sx_get_port(bp, "Int")));
} else if (status & SRSR_MREQint) {
ack = sx_in(bp, CD186x_MRAR);
if (ack == (SX_ID | GIVR_IT_MODEM))
sx_check_modem(bp);
else
- printk(KERN_ERR "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
+ printk(KERN_ERR
+ "sx%d: status: 0x%x Bad modem ack 0x%02x.\n",
board_No(bp), status, ack);
}
@@ -921,7 +862,7 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
sx_out(bp, CD186x_EOIR, 0); /* Mark end of interrupt */
}
bp->reg = saved_reg;
- outb (bp->reg, bp->base + SX_ADDR_REG);
+ outb(bp->reg, bp->base + SX_ADDR_REG);
spin_unlock_irqrestore(&bp->lock, flags);
func_exit();
return IRQ_HANDLED;
@@ -932,36 +873,26 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id)
* Routines for open & close processing.
*/
-static void turn_ints_off (struct specialix_board *bp)
+static void turn_ints_off(struct specialix_board *bp)
{
unsigned long flags;
func_enter();
- if (bp->flags & SX_BOARD_IS_PCI) {
- /* This was intended for enabeling the interrupt on the
- * PCI card. However it seems that it's already enabled
- * and as PCI interrupts can be shared, there is no real
- * reason to have to turn it off. */
- }
-
spin_lock_irqsave(&bp->lock, flags);
- (void) sx_in_off (bp, 0); /* Turn off interrupts. */
+ (void) sx_in_off(bp, 0); /* Turn off interrupts. */
spin_unlock_irqrestore(&bp->lock, flags);
func_exit();
}
-static void turn_ints_on (struct specialix_board *bp)
+static void turn_ints_on(struct specialix_board *bp)
{
unsigned long flags;
func_enter();
- if (bp->flags & SX_BOARD_IS_PCI) {
- /* play with the PCI chip. See comment above. */
- }
spin_lock_irqsave(&bp->lock, flags);
- (void) sx_in (bp, 0); /* Turn ON interrupts. */
+ (void) sx_in(bp, 0); /* Turn ON interrupts. */
spin_unlock_irqrestore(&bp->lock, flags);
func_exit();
@@ -969,7 +900,7 @@ static void turn_ints_on (struct specialix_board *bp)
/* Called with disabled interrupts */
-static inline int sx_setup_board(struct specialix_board * bp)
+static int sx_setup_board(struct specialix_board *bp)
{
int error;
@@ -977,14 +908,16 @@ static inline int sx_setup_board(struct specialix_board * bp)
return 0;
if (bp->flags & SX_BOARD_IS_PCI)
- error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED | IRQF_SHARED, "specialix IO8+", bp);
+ error = request_irq(bp->irq, sx_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "specialix IO8+", bp);
else
- error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED, "specialix IO8+", bp);
+ error = request_irq(bp->irq, sx_interrupt,
+ IRQF_DISABLED, "specialix IO8+", bp);
if (error)
return error;
- turn_ints_on (bp);
+ turn_ints_on(bp);
bp->flags |= SX_BOARD_ACTIVE;
return 0;
@@ -992,7 +925,7 @@ static inline int sx_setup_board(struct specialix_board * bp)
/* Called with disabled interrupts */
-static inline void sx_shutdown_board(struct specialix_board *bp)
+static void sx_shutdown_board(struct specialix_board *bp)
{
func_enter();
@@ -1003,22 +936,26 @@ static inline void sx_shutdown_board(struct specialix_board *bp)
bp->flags &= ~SX_BOARD_ACTIVE;
- dprintk (SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
- bp->irq, board_No (bp));
+ dprintk(SX_DEBUG_IRQ, "Freeing IRQ%d for board %d.\n",
+ bp->irq, board_No(bp));
free_irq(bp->irq, bp);
-
- turn_ints_off (bp);
-
-
+ turn_ints_off(bp);
func_exit();
}
+static unsigned int sx_crtscts(struct tty_struct *tty)
+{
+ if (sx_rtscts)
+ return C_CRTSCTS(tty);
+ return 1;
+}
/*
* Setting up port characteristics.
* Must be called with disabled interrupts
*/
-static void sx_change_speed(struct specialix_board *bp, struct specialix_port *port)
+static void sx_change_speed(struct specialix_board *bp,
+ struct specialix_port *port)
{
struct tty_struct *tty;
unsigned long baud;
@@ -1030,7 +967,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
func_enter();
- if (!(tty = port->port.tty) || !tty->termios) {
+ tty = port->port.tty;
+ if (!tty || !tty->termios) {
func_exit();
return;
}
@@ -1043,12 +981,12 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
/* The Specialix board doens't implement the RTS lines.
They are used to set the IRQ level. Don't touch them. */
- if (SX_CRTSCTS(tty))
+ if (sx_crtscts(tty))
port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
else
port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
spin_unlock_irqrestore(&bp->lock, flags);
- dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
+ dprintk(SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
baud = tty_get_baud_rate(tty);
if (baud == 38400) {
@@ -1060,21 +998,19 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
if (!baud) {
/* Drop DTR & exit */
- dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
- if (!SX_CRTSCTS (tty)) {
- port -> MSVR &= ~ MSVR_DTR;
+ dprintk(SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
+ if (!sx_crtscts(tty)) {
+ port->MSVR &= ~MSVR_DTR;
spin_lock_irqsave(&bp->lock, flags);
- sx_out(bp, CD186x_MSVR, port->MSVR );
+ sx_out(bp, CD186x_MSVR, port->MSVR);
spin_unlock_irqrestore(&bp->lock, flags);
- }
- else
- dprintk (SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
+ } else
+ dprintk(SX_DEBUG_TERMIOS, "Can't drop DTR: no DTR.\n");
return;
} else {
/* Set DTR on */
- if (!SX_CRTSCTS (tty)) {
- port ->MSVR |= MSVR_DTR;
- }
+ if (!sx_crtscts(tty))
+ port->MSVR |= MSVR_DTR;
}
/*
@@ -1083,28 +1019,27 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
/* Set baud rate for port */
tmp = port->custom_divisor ;
- if ( tmp )
- printk (KERN_INFO "sx%d: Using custom baud rate divisor %ld. \n"
- "This is an untested option, please be carefull.\n",
- port_No (port), tmp);
+ if (tmp)
+ printk(KERN_INFO
+ "sx%d: Using custom baud rate divisor %ld. \n"
+ "This is an untested option, please be careful.\n",
+ port_No(port), tmp);
else
- tmp = (((SX_OSCFREQ + baud/2) / baud +
- CD186x_TPC/2) / CD186x_TPC);
+ tmp = (((SX_OSCFREQ + baud/2) / baud + CD186x_TPC/2) /
+ CD186x_TPC);
- if ((tmp < 0x10) && time_before(again, jiffies)) {
+ if (tmp < 0x10 && time_before(again, jiffies)) {
again = jiffies + HZ * 60;
/* Page 48 of version 2.0 of the CL-CD1865 databook */
if (tmp >= 12) {
- printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
- "Performance degradation is possible.\n"
- "Read specialix.txt for more info.\n",
- port_No (port), tmp);
+ printk(KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
+ "Performance degradation is possible.\n"
+ "Read specialix.txt for more info.\n",
+ port_No(port), tmp);
} else {
- printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
- "Warning: overstressing Cirrus chip. "
- "This might not work.\n"
- "Read specialix.txt for more info.\n",
- port_No (port), tmp);
+ printk(KERN_INFO "sx%d: Baud rate divisor is %ld. \n"
+ "Warning: overstressing Cirrus chip. This might not work.\n"
+ "Read specialix.txt for more info.\n", port_No(port), tmp);
}
}
spin_lock_irqsave(&bp->lock, flags);
@@ -1114,7 +1049,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
sx_out(bp, CD186x_TBPRL, tmp & 0xff);
spin_unlock_irqrestore(&bp->lock, flags);
if (port->custom_divisor)
- baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
+ baud = (SX_OSCFREQ + port->custom_divisor/2) /
+ port->custom_divisor;
baud = (baud + 5) / 10; /* Estimated CPS */
/* Two timer ticks seems enough to wakeup something like SLIP driver */
@@ -1129,16 +1065,16 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
sx_out(bp, CD186x_RTPR, tmp);
spin_unlock_irqrestore(&bp->lock, flags);
switch (C_CSIZE(tty)) {
- case CS5:
+ case CS5:
cor1 |= COR1_5BITS;
break;
- case CS6:
+ case CS6:
cor1 |= COR1_6BITS;
break;
- case CS7:
+ case CS7:
cor1 |= COR1_7BITS;
break;
- case CS8:
+ case CS8:
cor1 |= COR1_8BITS;
break;
}
@@ -1175,7 +1111,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
spin_lock_irqsave(&bp->lock, flags);
- tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR));
+ tty->hw_stopped = !(sx_in(bp, CD186x_MSVR) &
+ (MSVR_CTS|MSVR_DSR));
spin_unlock_irqrestore(&bp->lock, flags);
#else
port->COR2 |= COR2_CTSAE;
@@ -1219,7 +1156,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
/* Setting up modem option registers */
- dprintk (SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2);
+ dprintk(SX_DEBUG_TERMIOS, "Mcor1 = %02x, mcor2 = %02x.\n",
+ mcor1, mcor2);
sx_out(bp, CD186x_MCOR1, mcor1);
sx_out(bp, CD186x_MCOR2, mcor2);
spin_unlock_irqrestore(&bp->lock, flags);
@@ -1238,7 +1176,8 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
/* Must be called with interrupts enabled */
-static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port)
+static int sx_setup_port(struct specialix_board *bp,
+ struct specialix_port *port)
{
unsigned long flags;
@@ -1253,7 +1192,8 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port
/* We may sleep in get_zeroed_page() */
unsigned long tmp;
- if (!(tmp = get_zeroed_page(GFP_KERNEL))) {
+ tmp = get_zeroed_page(GFP_KERNEL);
+ if (tmp == 0L) {
func_exit();
return -ENOMEM;
}
@@ -1284,7 +1224,8 @@ static int sx_setup_port(struct specialix_board *bp, struct specialix_port *port
/* Must be called with interrupts disabled */
-static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *port)
+static void sx_shutdown_port(struct specialix_board *bp,
+ struct specialix_port *port)
{
struct tty_struct *tty;
int i;
@@ -1298,11 +1239,11 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *
}
if (sx_debug & SX_DEBUG_FIFO) {
- dprintk(SX_DEBUG_FIFO, "sx%d: port %d: %ld overruns, FIFO hits [ ",
- board_No(bp), port_No(port), port->overrun);
- for (i = 0; i < 10; i++) {
+ dprintk(SX_DEBUG_FIFO,
+ "sx%d: port %d: %ld overruns, FIFO hits [ ",
+ board_No(bp), port_No(port), port->overrun);
+ for (i = 0; i < 10; i++)
dprintk(SX_DEBUG_FIFO, "%ld ", port->hits[i]);
- }
dprintk(SX_DEBUG_FIFO, "].\n");
}
@@ -1315,7 +1256,8 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *
spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
- if (!(tty = port->port.tty) || C_HUPCL(tty)) {
+ tty = port->port.tty;
+ if (tty == NULL || C_HUPCL(tty)) {
/* Drop DTR */
sx_out(bp, CD186x_MSVDTR, 0);
}
@@ -1338,8 +1280,8 @@ static void sx_shutdown_port(struct specialix_board *bp, struct specialix_port *
}
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct specialix_port *port)
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct specialix_port *port)
{
DECLARE_WAITQUEUE(wait, current);
struct specialix_board *bp = port_Board(port);
@@ -1389,23 +1331,22 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
retval = 0;
add_wait_queue(&port->port.open_wait, &wait);
spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp)) {
+ if (!tty_hung_up_p(filp))
port->port.count--;
- }
spin_unlock_irqrestore(&port->lock, flags);
port->port.blocked_open++;
while (1) {
spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
- if (SX_CRTSCTS (tty)) {
+ if (sx_crtscts(tty)) {
/* Activate RTS */
port->MSVR |= MSVR_DTR; /* WTF? */
- sx_out (bp, CD186x_MSVR, port->MSVR);
+ sx_out(bp, CD186x_MSVR, port->MSVR);
} else {
/* Activate DTR */
port->MSVR |= MSVR_DTR;
- sx_out (bp, CD186x_MSVR, port->MSVR);
+ sx_out(bp, CD186x_MSVR, port->MSVR);
}
spin_unlock_irqrestore(&bp->lock, flags);
set_current_state(TASK_INTERRUPTIBLE);
@@ -1430,9 +1371,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->port.open_wait, &wait);
spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp)) {
+ if (!tty_hung_up_p(filp))
port->port.count++;
- }
port->port.blocked_open--;
spin_unlock_irqrestore(&port->lock, flags);
if (retval) {
@@ -1446,12 +1386,12 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
-static int sx_open(struct tty_struct * tty, struct file * filp)
+static int sx_open(struct tty_struct *tty, struct file *filp)
{
int board;
int error;
- struct specialix_port * port;
- struct specialix_board * bp;
+ struct specialix_port *port;
+ struct specialix_board *bp;
int i;
unsigned long flags;
@@ -1468,17 +1408,19 @@ static int sx_open(struct tty_struct * tty, struct file * filp)
port = sx_port + board * SX_NPORT + SX_PORT(tty->index);
port->overrun = 0;
for (i = 0; i < 10; i++)
- port->hits[i]=0;
+ port->hits[i] = 0;
- dprintk (SX_DEBUG_OPEN, "Board = %d, bp = %p, port = %p, portno = %d.\n",
- board, bp, port, SX_PORT(tty->index));
+ dprintk(SX_DEBUG_OPEN,
+ "Board = %d, bp = %p, port = %p, portno = %d.\n",
+ board, bp, port, SX_PORT(tty->index));
if (sx_paranoia_check(port, tty->name, "sx_open")) {
func_enter();
return -ENODEV;
}
- if ((error = sx_setup_board(bp))) {
+ error = sx_setup_board(bp);
+ if (error) {
func_exit();
return error;
}
@@ -1490,12 +1432,14 @@ static int sx_open(struct tty_struct * tty, struct file * filp)
port->port.tty = tty;
spin_unlock_irqrestore(&bp->lock, flags);
- if ((error = sx_setup_port(bp, port))) {
+ error = sx_setup_port(bp, port);
+ if (error) {
func_enter();
return error;
}
- if ((error = block_til_ready(tty, filp, port))) {
+ error = block_til_ready(tty, filp, port);
+ if (error) {
func_enter();
return error;
}
@@ -1508,7 +1452,7 @@ static void sx_flush_buffer(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
- struct specialix_board * bp;
+ struct specialix_board *bp;
func_enter();
@@ -1526,9 +1470,9 @@ static void sx_flush_buffer(struct tty_struct *tty)
func_exit();
}
-static void sx_close(struct tty_struct * tty, struct file * filp)
+static void sx_close(struct tty_struct *tty, struct file *filp)
{
- struct specialix_port *port = (struct specialix_port *) tty->driver_data;
+ struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
unsigned long flags;
unsigned long timeout;
@@ -1547,7 +1491,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
bp = port_Board(port);
- if ((tty->count == 1) && (port->port.count != 1)) {
+ if (tty->count == 1 && port->port.count != 1) {
printk(KERN_ERR "sx%d: sx_close: bad port count;"
" tty->count is 1, port count is %d\n",
board_No(bp), port->port.count);
@@ -1570,17 +1514,16 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
*/
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
- dprintk (SX_DEBUG_OPEN, "Closing\n");
- if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+ dprintk(SX_DEBUG_OPEN, "Closing\n");
+ if (port->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->port.closing_wait);
- }
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
* interrupt driver to stop checking the data ready bit in the
* line status register.
*/
- dprintk (SX_DEBUG_OPEN, "Closed\n");
+ dprintk(SX_DEBUG_OPEN, "Closed\n");
port->IER &= ~IER_RXD;
if (port->port.flags & ASYNC_INITIALIZED) {
port->IER &= ~IER_TXRDY;
@@ -1595,11 +1538,11 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
* important if there is a transmit FIFO!
*/
timeout = jiffies+HZ;
- while(port->IER & IER_TXEMPTY) {
- set_current_state (TASK_INTERRUPTIBLE);
+ while (port->IER & IER_TXEMPTY) {
+ set_current_state(TASK_INTERRUPTIBLE);
msleep_interruptible(jiffies_to_msecs(port->timeout));
if (time_after(jiffies, timeout)) {
- printk (KERN_INFO "Timeout waiting for close\n");
+ printk(KERN_INFO "Timeout waiting for close\n");
break;
}
}
@@ -1607,13 +1550,15 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
if (--bp->count < 0) {
- printk(KERN_ERR "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
- board_No(bp), bp->count, tty->index);
+ printk(KERN_ERR
+ "sx%d: sx_shutdown_port: bad board count: %d port: %d\n",
+ board_No(bp), bp->count, tty->index);
bp->count = 0;
}
if (--port->port.count < 0) {
- printk(KERN_ERR "sx%d: sx_close: bad port count for tty%d: %d\n",
- board_No(bp), port_No(port), port->port.count);
+ printk(KERN_ERR
+ "sx%d: sx_close: bad port count for tty%d: %d\n",
+ board_No(bp), port_No(port), port->port.count);
port->port.count = 0;
}
@@ -1625,9 +1570,9 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
port->port.tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
if (port->port.blocked_open) {
- if (port->port.close_delay) {
- msleep_interruptible(jiffies_to_msecs(port->port.close_delay));
- }
+ if (port->port.close_delay)
+ msleep_interruptible(
+ jiffies_to_msecs(port->port.close_delay));
wake_up_interruptible(&port->port.open_wait);
}
port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
@@ -1637,8 +1582,8 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
}
-static int sx_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
+static int sx_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
@@ -1690,11 +1635,11 @@ static int sx_write(struct tty_struct * tty,
}
-static int sx_put_char(struct tty_struct * tty, unsigned char ch)
+static int sx_put_char(struct tty_struct *tty, unsigned char ch)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
- struct specialix_board * bp;
+ struct specialix_board *bp;
func_enter();
@@ -1702,7 +1647,7 @@ static int sx_put_char(struct tty_struct * tty, unsigned char ch)
func_exit();
return 0;
}
- dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
+ dprintk(SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
if (!port->xmit_buf) {
func_exit();
return 0;
@@ -1710,14 +1655,15 @@ static int sx_put_char(struct tty_struct * tty, unsigned char ch)
bp = port_Board(port);
spin_lock_irqsave(&port->lock, flags);
- dprintk (SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n", port->xmit_cnt, port->xmit_buf);
- if ((port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) || (!port->xmit_buf)) {
+ dprintk(SX_DEBUG_TX, "xmit_cnt: %d xmit_buf: %p\n",
+ port->xmit_cnt, port->xmit_buf);
+ if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1 || !port->xmit_buf) {
spin_unlock_irqrestore(&port->lock, flags);
- dprintk (SX_DEBUG_TX, "Exit size\n");
+ dprintk(SX_DEBUG_TX, "Exit size\n");
func_exit();
return 0;
}
- dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
+ dprintk(SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
@@ -1728,11 +1674,11 @@ static int sx_put_char(struct tty_struct * tty, unsigned char ch)
}
-static void sx_flush_chars(struct tty_struct * tty)
+static void sx_flush_chars(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
- struct specialix_board * bp = port_Board(port);
+ struct specialix_board *bp = port_Board(port);
func_enter();
@@ -1755,7 +1701,7 @@ static void sx_flush_chars(struct tty_struct * tty)
}
-static int sx_write_room(struct tty_struct * tty)
+static int sx_write_room(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
int ret;
@@ -1790,12 +1736,10 @@ static int sx_chars_in_buffer(struct tty_struct *tty)
return port->xmit_cnt;
}
-
-
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
- struct specialix_board * bp;
+ struct specialix_board *bp;
unsigned char status;
unsigned int result;
unsigned long flags;
@@ -1808,25 +1752,23 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file)
}
bp = port_Board(port);
- spin_lock_irqsave (&bp->lock, flags);
+ spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
status = sx_in(bp, CD186x_MSVR);
spin_unlock_irqrestore(&bp->lock, flags);
- dprintk (SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
- port_No(port), status, sx_in (bp, CD186x_CAR));
- dprintk (SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
- if (SX_CRTSCTS(port->port.tty)) {
- result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */
- | ((status & MSVR_DTR) ? TIOCM_RTS : 0)
- | ((status & MSVR_CD) ? TIOCM_CAR : 0)
- |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */
- | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
+ dprintk(SX_DEBUG_INIT, "Got msvr[%d] = %02x, car = %d.\n",
+ port_No(port), status, sx_in(bp, CD186x_CAR));
+ dprintk(SX_DEBUG_INIT, "sx_port = %p, port = %p\n", sx_port, port);
+ if (sx_crtscts(port->port.tty)) {
+ result = TIOCM_DTR | TIOCM_DSR
+ | ((status & MSVR_DTR) ? TIOCM_RTS : 0)
+ | ((status & MSVR_CD) ? TIOCM_CAR : 0)
+ | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
} else {
- result = /* (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */
- | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
- | ((status & MSVR_CD) ? TIOCM_CAR : 0)
- |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */
- | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
+ result = TIOCM_RTS | TIOCM_DSR
+ | ((status & MSVR_DTR) ? TIOCM_DTR : 0)
+ | ((status & MSVR_CD) ? TIOCM_CAR : 0)
+ | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
}
func_exit();
@@ -1852,24 +1794,14 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
bp = port_Board(port);
spin_lock_irqsave(&port->lock, flags);
- /* if (set & TIOCM_RTS)
- port->MSVR |= MSVR_RTS; */
- /* if (set & TIOCM_DTR)
- port->MSVR |= MSVR_DTR; */
-
- if (SX_CRTSCTS(port->port.tty)) {
+ if (sx_crtscts(port->port.tty)) {
if (set & TIOCM_RTS)
port->MSVR |= MSVR_DTR;
} else {
if (set & TIOCM_DTR)
port->MSVR |= MSVR_DTR;
}
-
- /* if (clear & TIOCM_RTS)
- port->MSVR &= ~MSVR_RTS; */
- /* if (clear & TIOCM_DTR)
- port->MSVR &= ~MSVR_DTR; */
- if (SX_CRTSCTS(port->port.tty)) {
+ if (sx_crtscts(port->port.tty)) {
if (clear & TIOCM_RTS)
port->MSVR &= ~MSVR_DTR;
} else {
@@ -1886,14 +1818,17 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
}
-static inline void sx_send_break(struct specialix_port * port, unsigned long length)
+static int sx_send_break(struct tty_struct *tty, int length)
{
+ struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp = port_Board(port);
unsigned long flags;
func_enter();
+ if (length == 0 || length == -1)
+ return -EOPNOTSUPP;
- spin_lock_irqsave (&port->lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
port->break_length = SPECIALIX_TPS / HZ * length;
port->COR2 |= COR2_ETC;
port->IER |= IER_TXRDY;
@@ -1902,7 +1837,7 @@ static inline void sx_send_break(struct specialix_port * port, unsigned long len
sx_out(bp, CD186x_COR2, port->COR2);
sx_out(bp, CD186x_IER, port->IER);
spin_unlock_irqrestore(&bp->lock, flags);
- spin_unlock_irqrestore (&port->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
sx_wait_CCR(bp);
spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CCR, CCR_CORCHG2);
@@ -1910,11 +1845,12 @@ static inline void sx_send_break(struct specialix_port * port, unsigned long len
sx_wait_CCR(bp);
func_exit();
+ return 0;
}
-static inline int sx_set_serial_info(struct specialix_port * port,
- struct serial_struct __user * newinfo)
+static int sx_set_serial_info(struct specialix_port *port,
+ struct serial_struct __user *newinfo)
{
struct serial_struct tmp;
struct specialix_board *bp = port_Board(port);
@@ -1943,25 +1879,25 @@ static inline int sx_set_serial_info(struct specialix_port * port,
return -EPERM;
}
port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) |
- (tmp.flags & ASYNC_USR_MASK));
+ (tmp.flags & ASYNC_USR_MASK));
port->custom_divisor = tmp.custom_divisor;
} else {
port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) |
- (tmp.flags & ASYNC_FLAGS));
+ (tmp.flags & ASYNC_FLAGS));
port->port.close_delay = tmp.close_delay;
port->port.closing_wait = tmp.closing_wait;
port->custom_divisor = tmp.custom_divisor;
}
- if (change_speed) {
+ if (change_speed)
sx_change_speed(bp, port);
- }
+
func_exit();
unlock_kernel();
return 0;
}
-static inline int sx_get_serial_info(struct specialix_port * port,
+static int sx_get_serial_info(struct specialix_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
@@ -1992,11 +1928,10 @@ static inline int sx_get_serial_info(struct specialix_port * port,
}
-static int sx_ioctl(struct tty_struct * tty, struct file * filp,
- unsigned int cmd, unsigned long arg)
+static int sx_ioctl(struct tty_struct *tty, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
- int retval;
void __user *argp = (void __user *)arg;
func_enter();
@@ -2007,34 +1942,14 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp,
}
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval) {
- func_exit();
- return retval;
- }
- tty_wait_until_sent(tty, 0);
- if (!arg)
- sx_send_break(port, HZ/4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval) {
- func_exit();
- return retval;
- }
- tty_wait_until_sent(tty, 0);
- sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
+ case TIOCGSERIAL:
func_exit();
- return 0;
- case TIOCGSERIAL:
- func_exit();
return sx_get_serial_info(port, argp);
- case TIOCSSERIAL:
- func_exit();
+ case TIOCSSERIAL:
+ func_exit();
return sx_set_serial_info(port, argp);
- default:
- func_exit();
+ default:
+ func_exit();
return -ENOIOCTLCMD;
}
func_exit();
@@ -2042,7 +1957,7 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp,
}
-static void sx_throttle(struct tty_struct * tty)
+static void sx_throttle(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
@@ -2058,15 +1973,16 @@ static void sx_throttle(struct tty_struct * tty)
bp = port_Board(port);
/* Use DTR instead of RTS ! */
- if (SX_CRTSCTS (tty))
+ if (sx_crtscts(tty))
port->MSVR &= ~MSVR_DTR;
else {
/* Auch!!! I think the system shouldn't call this then. */
/* Or maybe we're supposed (allowed?) to do our side of hw
handshake anyway, even when hardware handshake is off.
When you see this in your logs, please report.... */
- printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",
- port_No (port));
+ printk(KERN_ERR
+ "sx%d: Need to throttle, but can't (hardware hs is off)\n",
+ port_No(port));
}
spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
@@ -2086,7 +2002,7 @@ static void sx_throttle(struct tty_struct * tty)
}
-static void sx_unthrottle(struct tty_struct * tty)
+static void sx_unthrottle(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
@@ -2103,9 +2019,9 @@ static void sx_unthrottle(struct tty_struct * tty)
spin_lock_irqsave(&port->lock, flags);
/* XXXX Use DTR INSTEAD???? */
- if (SX_CRTSCTS(tty)) {
+ if (sx_crtscts(tty))
port->MSVR |= MSVR_DTR;
- } /* Else clause: see remark in "sx_throttle"... */
+ /* Else clause: see remark in "sx_throttle"... */
spin_lock_irqsave(&bp->lock, flags);
sx_out(bp, CD186x_CAR, port_No(port));
spin_unlock_irqrestore(&bp->lock, flags);
@@ -2127,7 +2043,7 @@ static void sx_unthrottle(struct tty_struct * tty)
}
-static void sx_stop(struct tty_struct * tty)
+static void sx_stop(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
@@ -2154,7 +2070,7 @@ static void sx_stop(struct tty_struct * tty)
}
-static void sx_start(struct tty_struct * tty)
+static void sx_start(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
@@ -2182,7 +2098,7 @@ static void sx_start(struct tty_struct * tty)
func_exit();
}
-static void sx_hangup(struct tty_struct * tty)
+static void sx_hangup(struct tty_struct *tty)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
struct specialix_board *bp;
@@ -2201,8 +2117,9 @@ static void sx_hangup(struct tty_struct * tty)
spin_lock_irqsave(&port->lock, flags);
bp->count -= port->port.count;
if (bp->count < 0) {
- printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
- board_No(bp), bp->count, tty->index);
+ printk(KERN_ERR
+ "sx%d: sx_hangup: bad board count: %d port: %d\n",
+ board_No(bp), bp->count, tty->index);
bp->count = 0;
}
port->port.count = 0;
@@ -2215,11 +2132,12 @@ static void sx_hangup(struct tty_struct * tty)
}
-static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
+static void sx_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
- struct specialix_board * bp;
+ struct specialix_board *bp;
if (sx_paranoia_check(port, tty->name, "sx_set_termios"))
return;
@@ -2254,6 +2172,7 @@ static const struct tty_operations sx_ops = {
.hangup = sx_hangup,
.tiocmget = sx_tiocmget,
.tiocmset = sx_tiocmset,
+ .break_ctl = sx_send_break,
};
static int sx_init_drivers(void)
@@ -2280,13 +2199,16 @@ static int sx_init_drivers(void)
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
specialix_driver->init_termios.c_ispeed = 9600;
specialix_driver->init_termios.c_ospeed = 9600;
- specialix_driver->flags = TTY_DRIVER_REAL_RAW;
+ specialix_driver->flags = TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_HARDWARE_BREAK;
tty_set_operations(specialix_driver, &sx_ops);
- if ((error = tty_register_driver(specialix_driver))) {
+ error = tty_register_driver(specialix_driver);
+ if (error) {
put_tty_driver(specialix_driver);
- printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
- error);
+ printk(KERN_ERR
+ "sx: Couldn't register specialix IO8+ driver, error = %d\n",
+ error);
func_exit();
return 1;
}
@@ -2322,11 +2244,11 @@ static int __init specialix_init(void)
printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");
printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");
-#ifdef CONFIG_SPECIALIX_RTSCTS
- printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
-#else
- printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
-#endif
+ if (sx_rtscts)
+ printk(KERN_INFO
+ "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");
+ else
+ printk(KERN_INFO "sx: DTR/RTS pin is always RTS.\n");
for (i = 0; i < SX_NBOARD; i++)
spin_lock_init(&sx_board[i].lock);
@@ -2344,27 +2266,27 @@ static int __init specialix_init(void)
{
struct pci_dev *pdev = NULL;
- i=0;
+ i = 0;
while (i < SX_NBOARD) {
if (sx_board[i].flags & SX_BOARD_PRESENT) {
i++;
continue;
}
- pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
- PCI_DEVICE_ID_SPECIALIX_IO8,
- pdev);
- if (!pdev) break;
+ pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX,
+ PCI_DEVICE_ID_SPECIALIX_IO8, pdev);
+ if (!pdev)
+ break;
if (pci_enable_device(pdev))
continue;
sx_board[i].irq = pdev->irq;
- sx_board[i].base = pci_resource_start (pdev, 2);
+ sx_board[i].base = pci_resource_start(pdev, 2);
sx_board[i].flags |= SX_BOARD_IS_PCI;
if (!sx_probe(&sx_board[i]))
- found ++;
+ found++;
}
/* May exit pci_get sequence early with lots of boards */
if (pdev != NULL)
@@ -2384,16 +2306,13 @@ static int __init specialix_init(void)
}
static int iobase[SX_NBOARD] = {0,};
-
-static int irq [SX_NBOARD] = {0,};
+static int irq[SX_NBOARD] = {0,};
module_param_array(iobase, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param(sx_debug, int, 0);
+module_param(sx_rtscts, int, 0);
module_param(sx_rxfifo, int, 0);
-#ifdef SPECIALIX_TIMER
-module_param(sx_poll, int, 0);
-#endif
/*
* You can setup up to 4 boards.
@@ -2411,10 +2330,10 @@ static int __init specialix_init_module(void)
func_enter();
if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
- for(i = 0; i < SX_NBOARD; i++) {
+ for (i = 0; i < SX_NBOARD; i++) {
sx_board[i].base = iobase[i];
sx_board[i].irq = irq[i];
- sx_board[i].count= 0;
+ sx_board[i].count = 0;
}
}
@@ -2433,10 +2352,6 @@ static void __exit specialix_exit_module(void)
for (i = 0; i < SX_NBOARD; i++)
if (sx_board[i].flags & SX_BOARD_PRESENT)
sx_release_io_range(&sx_board[i]);
-#ifdef SPECIALIX_TIMER
- del_timer_sync(&missed_irq_timer);
-#endif
-
func_exit();
}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 0243efb0be9..19db1eb87c2 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -1025,7 +1025,7 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
/*****************************************************************************/
-static void stl_putchar(struct tty_struct *tty, unsigned char ch)
+static int stl_putchar(struct tty_struct *tty, unsigned char ch)
{
struct stlport *portp;
unsigned int len;
@@ -1034,12 +1034,12 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch)
pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
if (tty == NULL)
- return;
+ return -EINVAL;
portp = tty->driver_data;
if (portp == NULL)
- return;
+ return -EINVAL;
if (portp->tx.buf == NULL)
- return;
+ return -EINVAL;
head = portp->tx.head;
tail = portp->tx.tail;
@@ -1053,6 +1053,7 @@ static void stl_putchar(struct tty_struct *tty, unsigned char ch)
head = portp->tx.buf;
}
portp->tx.head = head;
+ return 0;
}
/*****************************************************************************/
@@ -1255,7 +1256,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
struct stlport *portp;
- unsigned int ival;
int rc;
void __user *argp = (void __user *)arg;
@@ -1460,19 +1460,20 @@ static void stl_hangup(struct tty_struct *tty)
/*****************************************************************************/
-static void stl_breakctl(struct tty_struct *tty, int state)
+static int stl_breakctl(struct tty_struct *tty, int state)
{
struct stlport *portp;
pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
if (tty == NULL)
- return;
+ return -EINVAL;
portp = tty->driver_data;
if (portp == NULL)
- return;
+ return -EINVAL;
stl_sendbreak(portp, ((state == -1) ? 1 : 2));
+ return 0;
}
/*****************************************************************************/
@@ -4753,8 +4754,8 @@ static int __init stallion_module_init(void)
if (IS_ERR(stallion_class))
printk("STALLION: failed to create class\n");
for (i = 0; i < 4; i++)
- device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
- "staliomem%d", i);
+ device_create_drvdata(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ NULL, "staliomem%d", i);
return 0;
err_unrtty:
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index d5cffcd6a57..c385206f9db 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -286,8 +286,8 @@ static void sx_close(void *ptr);
static int sx_chars_in_buffer(void *ptr);
static int sx_init_board(struct sx_board *board);
static int sx_init_portstructs(int nboards, int nports);
-static int sx_fw_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
static int sx_init_drivers(void);
static struct tty_driver *sx_driver;
@@ -396,7 +396,7 @@ static struct real_driver sx_real_driver = {
static const struct file_operations sx_fw_fops = {
.owner = THIS_MODULE,
- .ioctl = sx_fw_ioctl,
+ .unlocked_ioctl = sx_fw_ioctl,
};
static struct miscdevice sx_fw_device = {
@@ -1686,10 +1686,10 @@ static int do_memtest_w(struct sx_board *board, int min, int max)
}
#endif
-static int sx_fw_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
- int rc = 0;
+ long rc = 0;
int __user *descr = (int __user *)arg;
int i;
static struct sx_board *board = NULL;
@@ -1699,13 +1699,10 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
func_enter();
-#if 0
- /* Removed superuser check: Sysops can use the permissions on the device
- file to restrict access. Recommendation: Root only. (root.root 600) */
- if (!capable(CAP_SYS_ADMIN)) {
+ if (!capable(CAP_SYS_RAWIO))
return -EPERM;
- }
-#endif
+
+ lock_kernel();
sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
@@ -1720,19 +1717,23 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
for (i = 0; i < SX_NBOARDS; i++)
sx_dprintk(SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
sx_dprintk(SX_DEBUG_FIRMWARE, "\n");
+ unlock_kernel();
return -EIO;
}
switch (cmd) {
case SXIO_SET_BOARD:
sx_dprintk(SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
+ rc = -EIO;
if (arg >= SX_NBOARDS)
- return -EIO;
+ break;
sx_dprintk(SX_DEBUG_FIRMWARE, "not out of range\n");
if (!(boards[arg].flags & SX_BOARD_PRESENT))
- return -EIO;
+ break;
sx_dprintk(SX_DEBUG_FIRMWARE, ".. and present!\n");
board = &boards[arg];
+ rc = 0;
+ /* FIXME: And this does ... nothing?? */
break;
case SXIO_GET_TYPE:
rc = -ENOENT; /* If we manage to miss one, return error. */
@@ -1746,7 +1747,7 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
rc = SX_TYPE_SI;
if (IS_EISA_BOARD(board))
rc = SX_TYPE_SI;
- sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %ld\n", rc);
break;
case SXIO_DO_RAMTEST:
if (sx_initialized) /* Already initialized: better not ramtest the board. */
@@ -1760,19 +1761,26 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
rc = do_memtest(board, 0, 0x7ff8);
/* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
}
- sx_dprintk(SX_DEBUG_FIRMWARE, "returning memtest result= %d\n",
- rc);
+ sx_dprintk(SX_DEBUG_FIRMWARE,
+ "returning memtest result= %ld\n", rc);
break;
case SXIO_DOWNLOAD:
- if (sx_initialized) /* Already initialized */
- return -EEXIST;
- if (!sx_reset(board))
- return -EIO;
+ if (sx_initialized) {/* Already initialized */
+ rc = -EEXIST;
+ break;
+ }
+ if (!sx_reset(board)) {
+ rc = -EIO;
+ break;
+ }
sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
tmp = kmalloc(SX_CHUNK_SIZE, GFP_USER);
- if (!tmp)
- return -ENOMEM;
+ if (!tmp) {
+ rc = -ENOMEM;
+ break;
+ }
+ /* FIXME: check returns */
get_user(nbytes, descr++);
get_user(offset, descr++);
get_user(data, descr++);
@@ -1782,7 +1790,8 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
(i + SX_CHUNK_SIZE > nbytes) ?
nbytes - i : SX_CHUNK_SIZE)) {
kfree(tmp);
- return -EFAULT;
+ rc = -EFAULT;
+ break;
}
memcpy_toio(board->base2 + offset + i, tmp,
(i + SX_CHUNK_SIZE > nbytes) ?
@@ -1798,13 +1807,17 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
rc = sx_nports;
break;
case SXIO_INIT:
- if (sx_initialized) /* Already initialized */
- return -EEXIST;
+ if (sx_initialized) { /* Already initialized */
+ rc = -EEXIST;
+ break;
+ }
/* This is not allowed until all boards are initialized... */
for (i = 0; i < SX_NBOARDS; i++) {
if ((boards[i].flags & SX_BOARD_PRESENT) &&
- !(boards[i].flags & SX_BOARD_INITIALIZED))
- return -EIO;
+ !(boards[i].flags & SX_BOARD_INITIALIZED)) {
+ rc = -EIO;
+ break;
+ }
}
for (i = 0; i < SX_NBOARDS; i++)
if (!(boards[i].flags & SX_BOARD_PRESENT))
@@ -1832,15 +1845,15 @@ static int sx_fw_ioctl(struct inode *inode, struct file *filp,
rc = sx_nports;
break;
default:
- printk(KERN_WARNING "Unknown ioctl on firmware device (%x).\n",
- cmd);
+ rc = -ENOTTY;
break;
}
+ unlock_kernel();
func_exit();
return rc;
}
-static void sx_break(struct tty_struct *tty, int flag)
+static int sx_break(struct tty_struct *tty, int flag)
{
struct sx_port *port = tty->driver_data;
int rv;
@@ -1857,6 +1870,7 @@ static void sx_break(struct tty_struct *tty, int flag)
read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
unlock_kernel();
func_exit();
+ return 0;
}
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 527d220aa4a..ef6706f0906 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2897,9 +2897,9 @@ static int tiocmset(struct tty_struct *tty, struct file *file,
*
* Arguments: tty pointer to tty instance data
* break_state -1=set break condition, 0=clear
- * Return Value: None
+ * Return Value: error code
*/
-static void mgsl_break(struct tty_struct *tty, int break_state)
+static int mgsl_break(struct tty_struct *tty, int break_state)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
unsigned long flags;
@@ -2909,7 +2909,7 @@ static void mgsl_break(struct tty_struct *tty, int break_state)
__FILE__,__LINE__, info->device_name, break_state);
if (mgsl_paranoia_check(info, tty->name, "mgsl_break"))
- return;
+ return -EINVAL;
spin_lock_irqsave(&info->irq_spinlock,flags);
if (break_state == -1)
@@ -2917,6 +2917,7 @@ static void mgsl_break(struct tty_struct *tty, int break_state)
else
usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7));
spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ return 0;
} /* end of mgsl_break() */
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2c3e43bb2cc..3e9058993e4 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -165,7 +165,7 @@ static int read_proc(char *page, char **start, off_t off, int count,int *eof, v
static int chars_in_buffer(struct tty_struct *tty);
static void throttle(struct tty_struct * tty);
static void unthrottle(struct tty_struct * tty);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
/*
* generic HDLC support and callbacks
@@ -214,6 +214,7 @@ struct slgt_desc
char *buf; /* virtual address of data buffer */
unsigned int pdesc; /* physical address of this descriptor */
dma_addr_t buf_dma_addr;
+ unsigned short buf_count;
};
#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))
@@ -302,7 +303,7 @@ struct slgt_info {
u32 idle_mode;
u32 max_frame_size; /* as set by device config */
- unsigned int raw_rx_size;
+ unsigned int rbuf_fill_level;
unsigned int if_mode;
/* device status */
@@ -466,6 +467,7 @@ static void tx_start(struct slgt_info *info);
static void tx_stop(struct slgt_info *info);
static void tx_set_idle(struct slgt_info *info);
static unsigned int free_tbuf_count(struct slgt_info *info);
+static unsigned int tbuf_bytes(struct slgt_info *info);
static void reset_tbufs(struct slgt_info *info);
static void tdma_reset(struct slgt_info *info);
static void tdma_start(struct slgt_info *info);
@@ -513,7 +515,7 @@ static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr);
static int tiocmget(struct tty_struct *tty, struct file *file);
static int tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
static int get_interface(struct slgt_info *info, int __user *if_mode);
static int set_interface(struct slgt_info *info, int if_mode);
static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
@@ -849,6 +851,7 @@ static int write(struct tty_struct *tty,
int ret = 0;
struct slgt_info *info = tty->driver_data;
unsigned long flags;
+ unsigned int bufs_needed;
if (sanity_check(info, tty->name, "write"))
goto cleanup;
@@ -865,25 +868,16 @@ static int write(struct tty_struct *tty,
if (!count)
goto cleanup;
- if (info->params.mode == MGSL_MODE_RAW ||
- info->params.mode == MGSL_MODE_MONOSYNC ||
- info->params.mode == MGSL_MODE_BISYNC) {
- unsigned int bufs_needed = (count/DMABUFSIZE);
- unsigned int bufs_free = free_tbuf_count(info);
- if (count % DMABUFSIZE)
- ++bufs_needed;
- if (bufs_needed > bufs_free)
- goto cleanup;
- } else {
- if (info->tx_active)
- goto cleanup;
- if (info->tx_count) {
- /* send accumulated data from send_char() calls */
- /* as frame and wait before accepting more data. */
- tx_load(info, info->tx_buf, info->tx_count);
- goto start;
- }
+ if (!info->tx_active && info->tx_count) {
+ /* send accumulated data from send_char() */
+ tx_load(info, info->tx_buf, info->tx_count);
+ goto start;
}
+ bufs_needed = (count/DMABUFSIZE);
+ if (count % DMABUFSIZE)
+ ++bufs_needed;
+ if (bufs_needed > free_tbuf_count(info))
+ goto cleanup;
ret = info->tx_count = count;
tx_load(info, buf, count);
@@ -1396,10 +1390,12 @@ done:
static int chars_in_buffer(struct tty_struct *tty)
{
struct slgt_info *info = tty->driver_data;
+ int count;
if (sanity_check(info, tty->name, "chars_in_buffer"))
return 0;
- DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count));
- return info->tx_count;
+ count = tbuf_bytes(info);
+ DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count));
+ return count;
}
/*
@@ -1452,14 +1448,14 @@ static void unthrottle(struct tty_struct * tty)
* set or clear transmit break condition
* break_state -1=set break condition, 0=clear
*/
-static void set_break(struct tty_struct *tty, int break_state)
+static int set_break(struct tty_struct *tty, int break_state)
{
struct slgt_info *info = tty->driver_data;
unsigned short value;
unsigned long flags;
if (sanity_check(info, tty->name, "set_break"))
- return;
+ return -EINVAL;
DBGINFO(("%s set_break(%d)\n", info->device_name, break_state));
spin_lock_irqsave(&info->lock,flags);
@@ -1470,6 +1466,7 @@ static void set_break(struct tty_struct *tty, int break_state)
value &= ~BIT6;
wr_reg16(info, TCR, value);
spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
}
#if SYNCLINK_GENERIC_HDLC
@@ -2679,8 +2676,31 @@ static int tx_abort(struct slgt_info *info)
static int rx_enable(struct slgt_info *info, int enable)
{
unsigned long flags;
- DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable));
+ unsigned int rbuf_fill_level;
+ DBGINFO(("%s rx_enable(%08x)\n", info->device_name, enable));
spin_lock_irqsave(&info->lock,flags);
+ /*
+ * enable[31..16] = receive DMA buffer fill level
+ * 0 = noop (leave fill level unchanged)
+ * fill level must be multiple of 4 and <= buffer size
+ */
+ rbuf_fill_level = ((unsigned int)enable) >> 16;
+ if (rbuf_fill_level) {
+ if ((rbuf_fill_level > DMABUFSIZE) || (rbuf_fill_level % 4)) {
+ spin_unlock_irqrestore(&info->lock, flags);
+ return -EINVAL;
+ }
+ info->rbuf_fill_level = rbuf_fill_level;
+ rx_stop(info); /* restart receiver to use new fill level */
+ }
+
+ /*
+ * enable[1..0] = receiver enable command
+ * 0 = disable
+ * 1 = enable
+ * 2 = enable or force hunt mode if already enabled
+ */
+ enable &= 3;
if (enable) {
if (!info->rx_enabled)
rx_start(info);
@@ -3447,7 +3467,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
- info->raw_rx_size = DMABUFSIZE;
+ info->rbuf_fill_level = DMABUFSIZE;
info->port.close_delay = 5*HZ/10;
info->port.closing_wait = 30*HZ;
init_waitqueue_head(&info->status_event_wait_q);
@@ -3934,15 +3954,7 @@ static void tdma_start(struct slgt_info *info)
/* set 1st descriptor address */
wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
- switch(info->params.mode) {
- case MGSL_MODE_RAW:
- case MGSL_MODE_MONOSYNC:
- case MGSL_MODE_BISYNC:
- wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
- break;
- default:
- wr_reg32(info, TDCSR, BIT0); /* DMA enable */
- }
+ wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
}
static void tx_stop(struct slgt_info *info)
@@ -4145,7 +4157,7 @@ static void sync_mode(struct slgt_info *info)
* 01 enable
* 00 auto-CTS enable
*/
- val = 0;
+ val = BIT2;
switch(info->params.mode) {
case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
@@ -4418,6 +4430,8 @@ static void msc_set_vcr(struct slgt_info *info)
break;
}
+ if (info->if_mode & MGSL_INTERFACE_MSB_FIRST)
+ val |= BIT4;
if (info->signals & SerialSignal_DTR)
val |= BIT3;
if (info->signals & SerialSignal_RTS)
@@ -4456,16 +4470,7 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
while(!done) {
/* reset current buffer for reuse */
info->rbufs[i].status = 0;
- switch(info->params.mode) {
- case MGSL_MODE_RAW:
- case MGSL_MODE_MONOSYNC:
- case MGSL_MODE_BISYNC:
- set_desc_count(info->rbufs[i], info->raw_rx_size);
- break;
- default:
- set_desc_count(info->rbufs[i], DMABUFSIZE);
- }
-
+ set_desc_count(info->rbufs[i], info->rbuf_fill_level);
if (i == last)
done = 1;
if (++i == info->rbuf_count)
@@ -4572,7 +4577,7 @@ check_again:
DBGBH(("%s rx frame status=%04X size=%d\n",
info->device_name, status, framesize));
- DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
+ DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, info->rbuf_fill_level), "rx");
if (framesize) {
if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
@@ -4592,7 +4597,7 @@ check_again:
info->icount.rxok++;
while(copy_count) {
- int partial_count = min(copy_count, DMABUFSIZE);
+ int partial_count = min_t(int, copy_count, info->rbuf_fill_level);
memcpy(p, info->rbufs[i].buf, partial_count);
p += partial_count;
copy_count -= partial_count;
@@ -4684,6 +4689,56 @@ static unsigned int free_tbuf_count(struct slgt_info *info)
}
/*
+ * return number of bytes in unsent transmit DMA buffers
+ * and the serial controller tx FIFO
+ */
+static unsigned int tbuf_bytes(struct slgt_info *info)
+{
+ unsigned int total_count = 0;
+ unsigned int i = info->tbuf_current;
+ unsigned int reg_value;
+ unsigned int count;
+ unsigned int active_buf_count = 0;
+
+ /*
+ * Add descriptor counts for all tx DMA buffers.
+ * If count is zero (cleared by DMA controller after read),
+ * the buffer is complete or is actively being read from.
+ *
+ * Record buf_count of last buffer with zero count starting
+ * from current ring position. buf_count is mirror
+ * copy of count and is not cleared by serial controller.
+ * If DMA controller is active, that buffer is actively
+ * being read so add to total.
+ */
+ do {
+ count = desc_count(info->tbufs[i]);
+ if (count)
+ total_count += count;
+ else if (!total_count)
+ active_buf_count = info->tbufs[i].buf_count;
+ if (++i == info->tbuf_count)
+ i = 0;
+ } while (i != info->tbuf_current);
+
+ /* read tx DMA status register */
+ reg_value = rd_reg32(info, TDCSR);
+
+ /* if tx DMA active, last zero count buffer is in use */
+ if (reg_value & BIT0)
+ total_count += active_buf_count;
+
+ /* add tx FIFO count = reg_value[15..8] */
+ total_count += (reg_value >> 8) & 0xff;
+
+ /* if transmitter active add one byte for shift register */
+ if (info->tx_active)
+ total_count++;
+
+ return total_count;
+}
+
+/*
* load transmit DMA buffer(s) with data
*/
static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
@@ -4721,6 +4776,7 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
set_desc_eof(*d, 0);
set_desc_count(*d, count);
+ d->buf_count = count;
}
info->tbuf_current = i;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 5768c413634..c0490cbd0db 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -527,7 +527,7 @@ static int read_proc(char *page, char **start, off_t off, int count,int *eof, v
static int chars_in_buffer(struct tty_struct *tty);
static void throttle(struct tty_struct * tty);
static void unthrottle(struct tty_struct * tty);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
#if SYNCLINK_GENERIC_HDLC
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
@@ -552,7 +552,7 @@ static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr);
static int tiocmget(struct tty_struct *tty, struct file *file);
static int tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
-static void set_break(struct tty_struct *tty, int break_state);
+static int set_break(struct tty_struct *tty, int break_state);
static void add_device(SLMP_INFO *info);
static void device_init(int adapter_num, struct pci_dev *pdev);
@@ -1587,7 +1587,7 @@ static void unthrottle(struct tty_struct * tty)
/* set or clear transmit break condition
* break_state -1=set break condition, 0=clear
*/
-static void set_break(struct tty_struct *tty, int break_state)
+static int set_break(struct tty_struct *tty, int break_state)
{
unsigned char RegValue;
SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;
@@ -1598,7 +1598,7 @@ static void set_break(struct tty_struct *tty, int break_state)
__FILE__,__LINE__, info->device_name, break_state);
if (sanity_check(info, tty->name, "set_break"))
- return;
+ return -EINVAL;
spin_lock_irqsave(&info->lock,flags);
RegValue = read_reg(info, CTL);
@@ -1608,6 +1608,7 @@ static void set_break(struct tty_struct *tty, int break_state)
RegValue &= ~BIT3;
write_reg(info, CTL, RegValue);
spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
}
#if SYNCLINK_GENERIC_HDLC
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 82f6a8c8633..e1b46bc7e43 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -656,558 +656,6 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
/**
- * tty_set_termios_ldisc - set ldisc field
- * @tty: tty structure
- * @num: line discipline number
- *
- * This is probably overkill for real world processors but
- * they are not on hot paths so a little discipline won't do
- * any harm.
- *
- * Locking: takes termios_mutex
- */
-
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
-{
- mutex_lock(&tty->termios_mutex);
- tty->termios->c_line = num;
- mutex_unlock(&tty->termios_mutex);
-}
-
-/*
- * This guards the refcounted line discipline lists. The lock
- * must be taken with irqs off because there are hangup path
- * callers who will do ldisc lookups and cannot sleep.
- */
-
-static DEFINE_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-/* Line disc dispatch table */
-static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
-
-/**
- * tty_register_ldisc - install a line discipline
- * @disc: ldisc number
- * @new_ldisc: pointer to the ldisc object
- *
- * Installs a new line discipline into the kernel. The discipline
- * is set up as unreferenced and then made available to the kernel
- * from this point onwards.
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
-{
- unsigned long flags;
- int ret = 0;
-
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- tty_ldiscs[disc] = new_ldisc;
- new_ldisc->num = disc;
- new_ldisc->refcount = 0;
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(tty_register_ldisc);
-
-/**
- * tty_unregister_ldisc - unload a line discipline
- * @disc: ldisc number
- * @new_ldisc: pointer to the ldisc object
- *
- * Remove a line discipline from the kernel providing it is not
- * currently in use.
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_unregister_ldisc(int disc)
-{
- unsigned long flags;
- int ret = 0;
-
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (tty_ldiscs[disc]->refcount)
- ret = -EBUSY;
- else
- tty_ldiscs[disc] = NULL;
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(tty_unregister_ldisc);
-
-
-/**
- * tty_ldisc_try_get - try and reference an ldisc
- * @disc: ldisc number
- * @ld: tty ldisc structure to complete
- *
- * Attempt to open and lock a line discipline into place. Return
- * the line discipline refcounted and assigned in ld. On an error
- * report the error code back
- */
-
-static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
-{
- unsigned long flags;
- struct tty_ldisc_ops *ldops;
- int err = -EINVAL;
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld->ops = NULL;
- ldops = tty_ldiscs[disc];
- /* Check the entry is defined */
- if (ldops) {
- /* If the module is being unloaded we can't use it */
- if (!try_module_get(ldops->owner))
- err = -EAGAIN;
- else {
- /* lock it */
- ldops->refcount++;
- ld->ops = ldops;
- err = 0;
- }
- }
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return err;
-}
-
-/**
- * tty_ldisc_get - take a reference to an ldisc
- * @disc: ldisc number
- * @ld: tty line discipline structure to use
- *
- * Takes a reference to a line discipline. Deals with refcounts and
- * module locking counts. Returns NULL if the discipline is not available.
- * Returns a pointer to the discipline and bumps the ref count if it is
- * available
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
-
-static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
-{
- int err;
-
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
- err = tty_ldisc_try_get(disc, ld);
- if (err == -EAGAIN) {
- request_module("tty-ldisc-%d", disc);
- err = tty_ldisc_try_get(disc, ld);
- }
- return err;
-}
-
-/**
- * tty_ldisc_put - drop ldisc reference
- * @disc: ldisc number
- *
- * Drop a reference to a line discipline. Manage refcounts and
- * module usage counts
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
-
-static void tty_ldisc_put(struct tty_ldisc_ops *ld)
-{
- unsigned long flags;
- int disc = ld->num;
-
- BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld = tty_ldiscs[disc];
- BUG_ON(ld->refcount == 0);
- ld->refcount--;
- module_put(ld->owner);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-}
-
-static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
- return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
- (*pos)++;
- return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
- int i = *(loff_t *)v;
- struct tty_ldisc ld;
-
- if (tty_ldisc_get(i, &ld) < 0)
- return 0;
- seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
- tty_ldisc_put(ld.ops);
- return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
- .start = tty_ldiscs_seq_start,
- .next = tty_ldiscs_seq_next,
- .stop = tty_ldiscs_seq_stop,
- .show = tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-const struct file_operations tty_ldiscs_proc_fops = {
- .owner = THIS_MODULE,
- .open = proc_tty_ldiscs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-/**
- * tty_ldisc_assign - set ldisc on a tty
- * @tty: tty to assign
- * @ld: line discipline
- *
- * Install an instance of a line discipline into a tty structure. The
- * ldisc must have a reference count above zero to ensure it remains/
- * The tty instance refcount starts at zero.
- *
- * Locking:
- * Caller must hold references
- */
-
-static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
-{
- ld->refcount = 0;
- tty->ldisc = *ld;
-}
-
-/**
- * tty_ldisc_try - internal helper
- * @tty: the tty
- *
- * Make a single attempt to grab and bump the refcount on
- * the tty ldisc. Return 0 on failure or 1 on success. This is
- * used to implement both the waiting and non waiting versions
- * of tty_ldisc_ref
- *
- * Locking: takes tty_ldisc_lock
- */
-
-static int tty_ldisc_try(struct tty_struct *tty)
-{
- unsigned long flags;
- struct tty_ldisc *ld;
- int ret = 0;
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld = &tty->ldisc;
- if (test_bit(TTY_LDISC, &tty->flags)) {
- ld->refcount++;
- ret = 1;
- }
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return ret;
-}
-
-/**
- * tty_ldisc_ref_wait - wait for the tty ldisc
- * @tty: tty device
- *
- * Dereference the line discipline for the terminal and take a
- * reference to it. If the line discipline is in flux then
- * wait patiently until it changes.
- *
- * Note: Must not be called from an IRQ/timer context. The caller
- * must also be careful not to hold other locks that will deadlock
- * against a discipline change, such as an existing ldisc reference
- * (which we check for)
- *
- * Locking: call functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
-{
- /* wait_event is a macro */
- wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
- if (tty->ldisc.refcount == 0)
- printk(KERN_ERR "tty_ldisc_ref_wait\n");
- return &tty->ldisc;
-}
-
-EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
-
-/**
- * tty_ldisc_ref - get the tty ldisc
- * @tty: tty device
- *
- * Dereference the line discipline for the terminal and take a
- * reference to it. If the line discipline is in flux then
- * return NULL. Can be called from IRQ and timer functions.
- *
- * Locking: called functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
-{
- if (tty_ldisc_try(tty))
- return &tty->ldisc;
- return NULL;
-}
-
-EXPORT_SYMBOL_GPL(tty_ldisc_ref);
-
-/**
- * tty_ldisc_deref - free a tty ldisc reference
- * @ld: reference to free up
- *
- * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
- * be called in IRQ context.
- *
- * Locking: takes tty_ldisc_lock
- */
-
-void tty_ldisc_deref(struct tty_ldisc *ld)
-{
- unsigned long flags;
-
- BUG_ON(ld == NULL);
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (ld->refcount == 0)
- printk(KERN_ERR "tty_ldisc_deref: no references.\n");
- else
- ld->refcount--;
- if (ld->refcount == 0)
- wake_up(&tty_ldisc_wait);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-}
-
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-
-/**
- * tty_ldisc_enable - allow ldisc use
- * @tty: terminal to activate ldisc on
- *
- * Set the TTY_LDISC flag when the line discipline can be called
- * again. Do necessary wakeups for existing sleepers.
- *
- * Note: nobody should set this bit except via this function. Clearing
- * directly is allowed.
- */
-
-static void tty_ldisc_enable(struct tty_struct *tty)
-{
- set_bit(TTY_LDISC, &tty->flags);
- wake_up(&tty_ldisc_wait);
-}
-
-/**
- * tty_ldisc_restore - helper for tty ldisc change
- * @tty: tty to recover
- * @old: previous ldisc
- *
- * Restore the previous line discipline or N_TTY when a line discipline
- * change fails due to an open error
- */
-
-static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
-{
- char buf[64];
- struct tty_ldisc new_ldisc;
-
- /* There is an outstanding reference here so this is safe */
- tty_ldisc_get(old->ops->num, old);
- tty_ldisc_assign(tty, old);
- tty_set_termios_ldisc(tty, old->ops->num);
- if (old->ops->open && (old->ops->open(tty) < 0)) {
- tty_ldisc_put(old->ops);
- /* This driver is always present */
- if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
- panic("n_tty: get");
- tty_ldisc_assign(tty, &new_ldisc);
- tty_set_termios_ldisc(tty, N_TTY);
- if (new_ldisc.ops->open) {
- int r = new_ldisc.ops->open(tty);
- if (r < 0)
- panic("Couldn't open N_TTY ldisc for "
- "%s --- error %d.",
- tty_name(tty, buf), r);
- }
- }
-}
-
-/**
- * tty_set_ldisc - set line discipline
- * @tty: the terminal to set
- * @ldisc: the line discipline
- *
- * Set the discipline of a tty line. Must be called from a process
- * context.
- *
- * Locking: takes tty_ldisc_lock.
- * called functions take termios_mutex
- */
-
-static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
-{
- int retval;
- struct tty_ldisc o_ldisc, new_ldisc;
- int work;
- unsigned long flags;
- struct tty_struct *o_tty;
-
-restart:
- /* This is a bit ugly for now but means we can break the 'ldisc
- is part of the tty struct' assumption later */
- retval = tty_ldisc_get(ldisc, &new_ldisc);
- if (retval)
- return retval;
-
- /*
- * Problem: What do we do if this blocks ?
- */
-
- tty_wait_until_sent(tty, 0);
-
- if (tty->ldisc.ops->num == ldisc) {
- tty_ldisc_put(new_ldisc.ops);
- return 0;
- }
-
- /*
- * No more input please, we are switching. The new ldisc
- * will update this value in the ldisc open function
- */
-
- tty->receive_room = 0;
-
- o_ldisc = tty->ldisc;
- o_tty = tty->link;
-
- /*
- * Make sure we don't change while someone holds a
- * reference to the line discipline. The TTY_LDISC bit
- * prevents anyone taking a reference once it is clear.
- * We need the lock to avoid racing reference takers.
- */
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
- if (tty->ldisc.refcount) {
- /* Free the new ldisc we grabbed. Must drop the lock
- first. */
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- tty_ldisc_put(o_ldisc.ops);
- /*
- * There are several reasons we may be busy, including
- * random momentary I/O traffic. We must therefore
- * retry. We could distinguish between blocking ops
- * and retries if we made tty_ldisc_wait() smarter.
- * That is up for discussion.
- */
- if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
- return -ERESTARTSYS;
- goto restart;
- }
- if (o_tty && o_tty->ldisc.refcount) {
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- tty_ldisc_put(o_tty->ldisc.ops);
- if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
- return -ERESTARTSYS;
- goto restart;
- }
- }
- /*
- * If the TTY_LDISC bit is set, then we are racing against
- * another ldisc change
- */
- if (!test_bit(TTY_LDISC, &tty->flags)) {
- struct tty_ldisc *ld;
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- tty_ldisc_put(new_ldisc.ops);
- ld = tty_ldisc_ref_wait(tty);
- tty_ldisc_deref(ld);
- goto restart;
- }
-
- clear_bit(TTY_LDISC, &tty->flags);
- if (o_tty)
- clear_bit(TTY_LDISC, &o_tty->flags);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
- /*
- * From this point on we know nobody has an ldisc
- * usage reference, nor can they obtain one until
- * we say so later on.
- */
-
- work = cancel_delayed_work(&tty->buf.work);
- /*
- * Wait for ->hangup_work and ->buf.work handlers to terminate
- * MUST NOT hold locks here.
- */
- flush_scheduled_work();
- /* Shutdown the current discipline. */
- if (o_ldisc.ops->close)
- (o_ldisc.ops->close)(tty);
-
- /* Now set up the new line discipline. */
- tty_ldisc_assign(tty, &new_ldisc);
- tty_set_termios_ldisc(tty, ldisc);
- if (new_ldisc.ops->open)
- retval = (new_ldisc.ops->open)(tty);
- if (retval < 0) {
- tty_ldisc_put(new_ldisc.ops);
- tty_ldisc_restore(tty, &o_ldisc);
- }
- /* At this point we hold a reference to the new ldisc and a
- a reference to the old ldisc. If we ended up flipping back
- to the existing ldisc we have two references to it */
-
- if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
- tty->ops->set_ldisc(tty);
-
- tty_ldisc_put(o_ldisc.ops);
-
- /*
- * Allow ldisc referencing to occur as soon as the driver
- * ldisc callback completes.
- */
-
- tty_ldisc_enable(tty);
- if (o_tty)
- tty_ldisc_enable(o_tty);
-
- /* Restart it in case no characters kick it off. Safe if
- already running */
- if (work)
- schedule_delayed_work(&tty->buf.work, 1);
- return retval;
-}
-
-/**
* get_tty_driver - find device of a tty
* @dev_t: device identifier
* @index: returns the index of the tty
@@ -1467,7 +915,7 @@ static void tty_reset_termios(struct tty_struct *tty)
* do_tty_hangup - actual handler for hangup events
* @work: tty device
*
-k * This can be called by the "eventd" kernel thread. That is process
+ * This can be called by the "eventd" kernel thread. That is process
* synchronous but doesn't hold any locks, so we need to make sure we
* have the appropriate locks for what we're doing.
*
@@ -1671,19 +1119,6 @@ int tty_hung_up_p(struct file *filp)
EXPORT_SYMBOL(tty_hung_up_p);
-/**
- * is_tty - checker whether file is a TTY
- * @filp: file handle that may be a tty
- *
- * Check if the file handle is a tty handle.
- */
-
-int is_tty(struct file *filp)
-{
- return filp->f_op->read == tty_read
- || filp->f_op->read == hung_up_tty_read;
-}
-
static void session_clear_tty(struct pid *session)
{
struct task_struct *p;
@@ -2193,7 +1628,6 @@ static int init_dev(struct tty_driver *driver, int idx,
struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
int retval = 0;
- struct tty_ldisc *ld;
/* check whether we're reopening an existing tty */
if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
@@ -2342,25 +1776,12 @@ static int init_dev(struct tty_driver *driver, int idx,
* If we fail here just call release_tty to clean up. No need
* to decrement the use counts, as release_tty doesn't care.
*/
-
- ld = &tty->ldisc;
- if (ld->ops->open) {
- retval = (ld->ops->open)(tty);
- if (retval)
- goto release_mem_out;
- }
- if (o_tty && o_tty->ldisc.ops->open) {
- retval = (o_tty->ldisc.ops->open)(o_tty);
- if (retval) {
- if (ld->ops->close)
- (ld->ops->close)(tty);
- goto release_mem_out;
- }
- tty_ldisc_enable(o_tty);
- }
- tty_ldisc_enable(tty);
- goto success;
+ retval = tty_ldisc_setup(tty, o_tty);
+
+ if (retval)
+ goto release_mem_out;
+ goto success;
/*
* This fast open can be used if the tty is already open.
@@ -2498,12 +1919,10 @@ static void release_tty(struct tty_struct *tty, int idx)
static void release_dev(struct file *filp)
{
struct tty_struct *tty, *o_tty;
- struct tty_ldisc ld;
int pty_master, tty_closing, o_tty_closing, do_sleep;
int devpts;
int idx;
char buf[64];
- unsigned long flags;
tty = (struct tty_struct *)filp->private_data;
if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
@@ -2705,56 +2124,9 @@ static void release_dev(struct file *filp)
printk(KERN_DEBUG "freeing tty structure...");
#endif
/*
- * Prevent flush_to_ldisc() from rescheduling the work for later. Then
- * kill any delayed work. As this is the final close it does not
- * race with the set_ldisc code path.
+ * Ask the line discipline code to release its structures
*/
- clear_bit(TTY_LDISC, &tty->flags);
- cancel_delayed_work(&tty->buf.work);
-
- /*
- * Wait for ->hangup_work and ->buf.work handlers to terminate
- */
-
- flush_scheduled_work();
-
- /*
- * Wait for any short term users (we know they are just driver
- * side waiters as the file is closing so user count on the file
- * side is zero.
- */
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- while (tty->ldisc.refcount) {
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- }
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- /*
- * Shutdown the current line discipline, and reset it to N_TTY.
- *
- * FIXME: this MUST get fixed for the new reflocking
- */
- if (tty->ldisc.ops->close)
- (tty->ldisc.ops->close)(tty);
- tty_ldisc_put(tty->ldisc.ops);
-
- /*
- * Switch the line discipline back
- */
- WARN_ON(tty_ldisc_get(N_TTY, &ld));
- tty_ldisc_assign(tty, &ld);
- tty_set_termios_ldisc(tty, N_TTY);
- if (o_tty) {
- /* FIXME: could o_tty be in setldisc here ? */
- clear_bit(TTY_LDISC, &o_tty->flags);
- if (o_tty->ldisc.ops->close)
- (o_tty->ldisc.ops->close)(o_tty);
- tty_ldisc_put(o_tty->ldisc.ops);
- WARN_ON(tty_ldisc_get(N_TTY, &ld));
- tty_ldisc_assign(o_tty, &ld);
- tty_set_termios_ldisc(o_tty, N_TTY);
- }
+ tty_ldisc_release(tty, o_tty);
/*
* The release_tty function takes care of the details of clearing
* the slots and preserving the termios structure.
@@ -3464,16 +2836,29 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
static int send_break(struct tty_struct *tty, unsigned int duration)
{
- if (tty_write_lock(tty, 0) < 0)
- return -EINTR;
- tty->ops->break_ctl(tty, -1);
- if (!signal_pending(current))
- msleep_interruptible(duration);
- tty->ops->break_ctl(tty, 0);
- tty_write_unlock(tty);
- if (signal_pending(current))
- return -EINTR;
- return 0;
+ int retval;
+
+ if (tty->ops->break_ctl == NULL)
+ return 0;
+
+ if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
+ retval = tty->ops->break_ctl(tty, duration);
+ else {
+ /* Do the work ourselves */
+ if (tty_write_lock(tty, 0) < 0)
+ return -EINTR;
+ retval = tty->ops->break_ctl(tty, -1);
+ if (retval)
+ goto out;
+ if (!signal_pending(current))
+ msleep_interruptible(duration);
+ retval = tty->ops->break_ctl(tty, 0);
+out:
+ tty_write_unlock(tty);
+ if (signal_pending(current))
+ retval = -EINTR;
+ }
+ return retval;
}
/**
@@ -3564,36 +2949,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
tty->driver->subtype == PTY_TYPE_MASTER)
real_tty = tty->link;
- /*
- * Break handling by driver
- */
-
- retval = -EINVAL;
-
- if (!tty->ops->break_ctl) {
- switch (cmd) {
- case TIOCSBRK:
- case TIOCCBRK:
- if (tty->ops->ioctl)
- retval = tty->ops->ioctl(tty, file, cmd, arg);
- if (retval != -EINVAL && retval != -ENOIOCTLCMD)
- printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
- return retval;
-
- /* These two ioctl's always return success; even if */
- /* the driver doesn't support them. */
- case TCSBRK:
- case TCSBRKP:
- if (!tty->ops->ioctl)
- return 0;
- retval = tty->ops->ioctl(tty, file, cmd, arg);
- if (retval != -EINVAL && retval != -ENOIOCTLCMD)
- printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
- if (retval == -ENOIOCTLCMD)
- retval = 0;
- return retval;
- }
- }
/*
* Factor out some common prep work
@@ -3615,6 +2970,9 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
+ /*
+ * Now do the stuff.
+ */
switch (cmd) {
case TIOCSTI:
return tiocsti(tty, p);
@@ -3658,12 +3016,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
case TIOCSBRK: /* Turn break on, unconditionally */
if (tty->ops->break_ctl)
- tty->ops->break_ctl(tty, -1);
+ return tty->ops->break_ctl(tty, -1);
return 0;
-
case TIOCCBRK: /* Turn break off, unconditionally */
if (tty->ops->break_ctl)
- tty->ops->break_ctl(tty, 0);
+ return tty->ops->break_ctl(tty, 0);
return 0;
case TCSBRK: /* SVID version: non-zero arg --> no break */
/* non-zero arg means wait for all output data
@@ -3962,12 +3319,9 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
static void initialize_tty_struct(struct tty_struct *tty)
{
- struct tty_ldisc ld;
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
- if (tty_ldisc_get(N_TTY, &ld) < 0)
- panic("n_tty: init_tty");
- tty_ldisc_assign(tty, &ld);
+ tty_ldisc_init(tty);
tty->session = NULL;
tty->pgrp = NULL;
tty->overrun_time = jiffies;
@@ -4045,7 +3399,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
else
tty_line_name(driver, index, name);
- return device_create(tty_class, device, dev, name);
+ return device_create_drvdata(tty_class, device, dev, NULL, name);
}
/**
@@ -4226,7 +3580,6 @@ void proc_clear_tty(struct task_struct *p)
p->signal->tty = NULL;
spin_unlock_irq(&p->sighand->siglock);
}
-EXPORT_SYMBOL(proc_clear_tty);
/* Called under the sighand lock */
@@ -4280,7 +3633,7 @@ void __init console_init(void)
initcall_t *call;
/* Setup the default TTY line discipline. */
- (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+ tty_ldisc_begin();
/*
* set up the console device so that later boot sequences can
@@ -4323,20 +3676,22 @@ static int __init tty_init(void)
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
panic("Couldn't register /dev/tty driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), "tty");
+ device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+ "tty");
cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), "console");
+ device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+ "console");
#ifdef CONFIG_UNIX98_PTYS
cdev_init(&ptmx_cdev, &ptmx_fops);
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
panic("Couldn't register /dev/ptmx driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), "ptmx");
+ device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
#endif
#ifdef CONFIG_VT
@@ -4344,7 +3699,7 @@ static int __init tty_init(void)
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
- device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0");
+ device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
vty_init();
#endif
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
new file mode 100644
index 00000000000..241cbdea65a
--- /dev/null
+++ b/drivers/char/tty_ldisc.c
@@ -0,0 +1,714 @@
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+/*
+ * This guards the refcounted line discipline lists. The lock
+ * must be taken with irqs off because there are hangup path
+ * callers who will do ldisc lookups and cannot sleep.
+ */
+
+static DEFINE_SPINLOCK(tty_ldisc_lock);
+static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+/* Line disc dispatch table */
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+
+/**
+ * tty_register_ldisc - install a line discipline
+ * @disc: ldisc number
+ * @new_ldisc: pointer to the ldisc object
+ *
+ * Installs a new line discipline into the kernel. The discipline
+ * is set up as unreferenced and then made available to the kernel
+ * from this point onwards.
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ tty_ldiscs[disc] = new_ldisc;
+ new_ldisc->num = disc;
+ new_ldisc->refcount = 0;
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(tty_register_ldisc);
+
+/**
+ * tty_unregister_ldisc - unload a line discipline
+ * @disc: ldisc number
+ * @new_ldisc: pointer to the ldisc object
+ *
+ * Remove a line discipline from the kernel providing it is not
+ * currently in use.
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_unregister_ldisc(int disc)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ if (tty_ldiscs[disc]->refcount)
+ ret = -EBUSY;
+ else
+ tty_ldiscs[disc] = NULL;
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(tty_unregister_ldisc);
+
+
+/**
+ * tty_ldisc_try_get - try and reference an ldisc
+ * @disc: ldisc number
+ * @ld: tty ldisc structure to complete
+ *
+ * Attempt to open and lock a line discipline into place. Return
+ * the line discipline refcounted and assigned in ld. On an error
+ * report the error code back
+ */
+
+static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
+{
+ unsigned long flags;
+ struct tty_ldisc_ops *ldops;
+ int err = -EINVAL;
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ ld->ops = NULL;
+ ldops = tty_ldiscs[disc];
+ /* Check the entry is defined */
+ if (ldops) {
+ /* If the module is being unloaded we can't use it */
+ if (!try_module_get(ldops->owner))
+ err = -EAGAIN;
+ else {
+ /* lock it */
+ ldops->refcount++;
+ ld->ops = ldops;
+ err = 0;
+ }
+ }
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ return err;
+}
+
+/**
+ * tty_ldisc_get - take a reference to an ldisc
+ * @disc: ldisc number
+ * @ld: tty line discipline structure to use
+ *
+ * Takes a reference to a line discipline. Deals with refcounts and
+ * module locking counts. Returns NULL if the discipline is not available.
+ * Returns a pointer to the discipline and bumps the ref count if it is
+ * available
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
+static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
+{
+ int err;
+
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ return -EINVAL;
+ err = tty_ldisc_try_get(disc, ld);
+ if (err == -EAGAIN) {
+ request_module("tty-ldisc-%d", disc);
+ err = tty_ldisc_try_get(disc, ld);
+ }
+ return err;
+}
+
+/**
+ * tty_ldisc_put - drop ldisc reference
+ * @disc: ldisc number
+ *
+ * Drop a reference to a line discipline. Manage refcounts and
+ * module usage counts
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
+static void tty_ldisc_put(struct tty_ldisc_ops *ld)
+{
+ unsigned long flags;
+ int disc = ld->num;
+
+ BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ ld = tty_ldiscs[disc];
+ BUG_ON(ld->refcount == 0);
+ ld->refcount--;
+ module_put(ld->owner);
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+{
+ return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+ int i = *(loff_t *)v;
+ struct tty_ldisc ld;
+
+ if (tty_ldisc_get(i, &ld) < 0)
+ return 0;
+ seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
+ tty_ldisc_put(ld.ops);
+ return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+ .start = tty_ldiscs_seq_start,
+ .next = tty_ldiscs_seq_next,
+ .stop = tty_ldiscs_seq_stop,
+ .show = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+const struct file_operations tty_ldiscs_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_tty_ldiscs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/**
+ * tty_ldisc_assign - set ldisc on a tty
+ * @tty: tty to assign
+ * @ld: line discipline
+ *
+ * Install an instance of a line discipline into a tty structure. The
+ * ldisc must have a reference count above zero to ensure it remains/
+ * The tty instance refcount starts at zero.
+ *
+ * Locking:
+ * Caller must hold references
+ */
+
+static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+ ld->refcount = 0;
+ tty->ldisc = *ld;
+}
+
+/**
+ * tty_ldisc_try - internal helper
+ * @tty: the tty
+ *
+ * Make a single attempt to grab and bump the refcount on
+ * the tty ldisc. Return 0 on failure or 1 on success. This is
+ * used to implement both the waiting and non waiting versions
+ * of tty_ldisc_ref
+ *
+ * Locking: takes tty_ldisc_lock
+ */
+
+static int tty_ldisc_try(struct tty_struct *tty)
+{
+ unsigned long flags;
+ struct tty_ldisc *ld;
+ int ret = 0;
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ ld = &tty->ldisc;
+ if (test_bit(TTY_LDISC, &tty->flags)) {
+ ld->refcount++;
+ ret = 1;
+ }
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ return ret;
+}
+
+/**
+ * tty_ldisc_ref_wait - wait for the tty ldisc
+ * @tty: tty device
+ *
+ * Dereference the line discipline for the terminal and take a
+ * reference to it. If the line discipline is in flux then
+ * wait patiently until it changes.
+ *
+ * Note: Must not be called from an IRQ/timer context. The caller
+ * must also be careful not to hold other locks that will deadlock
+ * against a discipline change, such as an existing ldisc reference
+ * (which we check for)
+ *
+ * Locking: call functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
+{
+ /* wait_event is a macro */
+ wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
+ if (tty->ldisc.refcount == 0)
+ printk(KERN_ERR "tty_ldisc_ref_wait\n");
+ return &tty->ldisc;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
+
+/**
+ * tty_ldisc_ref - get the tty ldisc
+ * @tty: tty device
+ *
+ * Dereference the line discipline for the terminal and take a
+ * reference to it. If the line discipline is in flux then
+ * return NULL. Can be called from IRQ and timer functions.
+ *
+ * Locking: called functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
+{
+ if (tty_ldisc_try(tty))
+ return &tty->ldisc;
+ return NULL;
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_ref);
+
+/**
+ * tty_ldisc_deref - free a tty ldisc reference
+ * @ld: reference to free up
+ *
+ * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
+ * be called in IRQ context.
+ *
+ * Locking: takes tty_ldisc_lock
+ */
+
+void tty_ldisc_deref(struct tty_ldisc *ld)
+{
+ unsigned long flags;
+
+ BUG_ON(ld == NULL);
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ if (ld->refcount == 0)
+ printk(KERN_ERR "tty_ldisc_deref: no references.\n");
+ else
+ ld->refcount--;
+ if (ld->refcount == 0)
+ wake_up(&tty_ldisc_wait);
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+
+/**
+ * tty_ldisc_enable - allow ldisc use
+ * @tty: terminal to activate ldisc on
+ *
+ * Set the TTY_LDISC flag when the line discipline can be called
+ * again. Do necessary wakeups for existing sleepers.
+ *
+ * Note: nobody should set this bit except via this function. Clearing
+ * directly is allowed.
+ */
+
+void tty_ldisc_enable(struct tty_struct *tty)
+{
+ set_bit(TTY_LDISC, &tty->flags);
+ wake_up(&tty_ldisc_wait);
+}
+
+/**
+ * tty_set_termios_ldisc - set ldisc field
+ * @tty: tty structure
+ * @num: line discipline number
+ *
+ * This is probably overkill for real world processors but
+ * they are not on hot paths so a little discipline won't do
+ * any harm.
+ *
+ * Locking: takes termios_mutex
+ */
+
+static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+{
+ mutex_lock(&tty->termios_mutex);
+ tty->termios->c_line = num;
+ mutex_unlock(&tty->termios_mutex);
+}
+
+
+/**
+ * tty_ldisc_restore - helper for tty ldisc change
+ * @tty: tty to recover
+ * @old: previous ldisc
+ *
+ * Restore the previous line discipline or N_TTY when a line discipline
+ * change fails due to an open error
+ */
+
+static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
+{
+ char buf[64];
+ struct tty_ldisc new_ldisc;
+
+ /* There is an outstanding reference here so this is safe */
+ tty_ldisc_get(old->ops->num, old);
+ tty_ldisc_assign(tty, old);
+ tty_set_termios_ldisc(tty, old->ops->num);
+ if (old->ops->open && (old->ops->open(tty) < 0)) {
+ tty_ldisc_put(old->ops);
+ /* This driver is always present */
+ if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
+ panic("n_tty: get");
+ tty_ldisc_assign(tty, &new_ldisc);
+ tty_set_termios_ldisc(tty, N_TTY);
+ if (new_ldisc.ops->open) {
+ int r = new_ldisc.ops->open(tty);
+ if (r < 0)
+ panic("Couldn't open N_TTY ldisc for "
+ "%s --- error %d.",
+ tty_name(tty, buf), r);
+ }
+ }
+}
+
+/**
+ * tty_set_ldisc - set line discipline
+ * @tty: the terminal to set
+ * @ldisc: the line discipline
+ *
+ * Set the discipline of a tty line. Must be called from a process
+ * context.
+ *
+ * Locking: takes tty_ldisc_lock.
+ * called functions take termios_mutex
+ */
+
+int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+{
+ int retval;
+ struct tty_ldisc o_ldisc, new_ldisc;
+ int work;
+ unsigned long flags;
+ struct tty_struct *o_tty;
+
+restart:
+ /* This is a bit ugly for now but means we can break the 'ldisc
+ is part of the tty struct' assumption later */
+ retval = tty_ldisc_get(ldisc, &new_ldisc);
+ if (retval)
+ return retval;
+
+ /*
+ * Problem: What do we do if this blocks ?
+ */
+
+ tty_wait_until_sent(tty, 0);
+
+ if (tty->ldisc.ops->num == ldisc) {
+ tty_ldisc_put(new_ldisc.ops);
+ return 0;
+ }
+
+ /*
+ * No more input please, we are switching. The new ldisc
+ * will update this value in the ldisc open function
+ */
+
+ tty->receive_room = 0;
+
+ o_ldisc = tty->ldisc;
+ o_tty = tty->link;
+
+ /*
+ * Make sure we don't change while someone holds a
+ * reference to the line discipline. The TTY_LDISC bit
+ * prevents anyone taking a reference once it is clear.
+ * We need the lock to avoid racing reference takers.
+ */
+
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
+ if (tty->ldisc.refcount) {
+ /* Free the new ldisc we grabbed. Must drop the lock
+ first. */
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ tty_ldisc_put(o_ldisc.ops);
+ /*
+ * There are several reasons we may be busy, including
+ * random momentary I/O traffic. We must therefore
+ * retry. We could distinguish between blocking ops
+ * and retries if we made tty_ldisc_wait() smarter.
+ * That is up for discussion.
+ */
+ if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
+ return -ERESTARTSYS;
+ goto restart;
+ }
+ if (o_tty && o_tty->ldisc.refcount) {
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ tty_ldisc_put(o_tty->ldisc.ops);
+ if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
+ return -ERESTARTSYS;
+ goto restart;
+ }
+ }
+ /*
+ * If the TTY_LDISC bit is set, then we are racing against
+ * another ldisc change
+ */
+ if (!test_bit(TTY_LDISC, &tty->flags)) {
+ struct tty_ldisc *ld;
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ tty_ldisc_put(new_ldisc.ops);
+ ld = tty_ldisc_ref_wait(tty);
+ tty_ldisc_deref(ld);
+ goto restart;
+ }
+
+ clear_bit(TTY_LDISC, &tty->flags);
+ if (o_tty)
+ clear_bit(TTY_LDISC, &o_tty->flags);
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ /*
+ * From this point on we know nobody has an ldisc
+ * usage reference, nor can they obtain one until
+ * we say so later on.
+ */
+
+ work = cancel_delayed_work(&tty->buf.work);
+ /*
+ * Wait for ->hangup_work and ->buf.work handlers to terminate
+ * MUST NOT hold locks here.
+ */
+ flush_scheduled_work();
+ /* Shutdown the current discipline. */
+ if (o_ldisc.ops->close)
+ (o_ldisc.ops->close)(tty);
+
+ /* Now set up the new line discipline. */
+ tty_ldisc_assign(tty, &new_ldisc);
+ tty_set_termios_ldisc(tty, ldisc);
+ if (new_ldisc.ops->open)
+ retval = (new_ldisc.ops->open)(tty);
+ if (retval < 0) {
+ tty_ldisc_put(new_ldisc.ops);
+ tty_ldisc_restore(tty, &o_ldisc);
+ }
+ /* At this point we hold a reference to the new ldisc and a
+ a reference to the old ldisc. If we ended up flipping back
+ to the existing ldisc we have two references to it */
+
+ if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
+ tty->ops->set_ldisc(tty);
+
+ tty_ldisc_put(o_ldisc.ops);
+
+ /*
+ * Allow ldisc referencing to occur as soon as the driver
+ * ldisc callback completes.
+ */
+
+ tty_ldisc_enable(tty);
+ if (o_tty)
+ tty_ldisc_enable(o_tty);
+
+ /* Restart it in case no characters kick it off. Safe if
+ already running */
+ if (work)
+ schedule_delayed_work(&tty->buf.work, 1);
+ return retval;
+}
+
+
+/**
+ * tty_ldisc_setup - open line discipline
+ * @tty: tty being shut down
+ * @o_tty: pair tty for pty/tty pairs
+ *
+ * Called during the initial open of a tty/pty pair in order to set up the
+ * line discplines and bind them to the tty.
+ */
+
+int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+ struct tty_ldisc *ld = &tty->ldisc;
+ int retval;
+
+ if (ld->ops->open) {
+ retval = (ld->ops->open)(tty);
+ if (retval)
+ return retval;
+ }
+ if (o_tty && o_tty->ldisc.ops->open) {
+ retval = (o_tty->ldisc.ops->open)(o_tty);
+ if (retval) {
+ if (ld->ops->close)
+ (ld->ops->close)(tty);
+ return retval;
+ }
+ tty_ldisc_enable(o_tty);
+ }
+ tty_ldisc_enable(tty);
+ return 0;
+}
+
+/**
+ * tty_ldisc_release - release line discipline
+ * @tty: tty being shut down
+ * @o_tty: pair tty for pty/tty pairs
+ *
+ * Called during the final close of a tty/pty pair in order to shut down the
+ * line discpline layer.
+ */
+
+void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+ unsigned long flags;
+ struct tty_ldisc ld;
+ /*
+ * Prevent flush_to_ldisc() from rescheduling the work for later. Then
+ * kill any delayed work. As this is the final close it does not
+ * race with the set_ldisc code path.
+ */
+ clear_bit(TTY_LDISC, &tty->flags);
+ cancel_delayed_work(&tty->buf.work);
+
+ /*
+ * Wait for ->hangup_work and ->buf.work handlers to terminate
+ */
+
+ flush_scheduled_work();
+
+ /*
+ * Wait for any short term users (we know they are just driver
+ * side waiters as the file is closing so user count on the file
+ * side is zero.
+ */
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ while (tty->ldisc.refcount) {
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
+ spin_lock_irqsave(&tty_ldisc_lock, flags);
+ }
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ /*
+ * Shutdown the current line discipline, and reset it to N_TTY.
+ *
+ * FIXME: this MUST get fixed for the new reflocking
+ */
+ if (tty->ldisc.ops->close)
+ (tty->ldisc.ops->close)(tty);
+ tty_ldisc_put(tty->ldisc.ops);
+
+ /*
+ * Switch the line discipline back
+ */
+ WARN_ON(tty_ldisc_get(N_TTY, &ld));
+ tty_ldisc_assign(tty, &ld);
+ tty_set_termios_ldisc(tty, N_TTY);
+ if (o_tty) {
+ /* FIXME: could o_tty be in setldisc here ? */
+ clear_bit(TTY_LDISC, &o_tty->flags);
+ if (o_tty->ldisc.ops->close)
+ (o_tty->ldisc.ops->close)(o_tty);
+ tty_ldisc_put(o_tty->ldisc.ops);
+ WARN_ON(tty_ldisc_get(N_TTY, &ld));
+ tty_ldisc_assign(o_tty, &ld);
+ tty_set_termios_ldisc(o_tty, N_TTY);
+ }
+}
+
+/**
+ * tty_ldisc_init - ldisc setup for new tty
+ * @tty: tty being allocated
+ *
+ * Set up the line discipline objects for a newly allocated tty. Note that
+ * the tty structure is not completely set up when this call is made.
+ */
+
+void tty_ldisc_init(struct tty_struct *tty)
+{
+ struct tty_ldisc ld;
+ if (tty_ldisc_get(N_TTY, &ld) < 0)
+ panic("n_tty: init_tty");
+ tty_ldisc_assign(tty, &ld);
+}
+
+void tty_ldisc_begin(void)
+{
+ /* Setup the default TTY line discipline. */
+ (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+}
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index eebfad2777d..c2ae52dd53d 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -481,10 +481,10 @@ static struct class *vc_class;
void vcs_make_sysfs(struct tty_struct *tty)
{
- device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
- "vcs%u", tty->index + 1);
- device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
- "vcsa%u", tty->index + 1);
+ device_create_drvdata(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
+ NULL, "vcs%u", tty->index + 1);
+ device_create_drvdata(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
+ NULL, "vcsa%u", tty->index + 1);
}
void vcs_remove_sysfs(struct tty_struct *tty)
@@ -499,7 +499,7 @@ int __init vcs_init(void)
panic("unable to get major %d for vcs device", VCS_MAJOR);
vc_class = class_create(THIS_MODULE, "vc");
- device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), "vcs");
- device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), "vcsa");
+ device_create_drvdata(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
+ device_create_drvdata(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
return 0;
}
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index e5da98d8f9c..7a70a40ad63 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -886,10 +886,10 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
state[i].cur_part = 0;
for (j = 0; j < MAX_PARTITIONS; ++j)
state[i].part_stat_rwi[j] = VIOT_IDLE;
- device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
- "iseries!vt%d", i);
- device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
- "iseries!nvt%d", i);
+ device_create_drvdata(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
+ NULL, "iseries!vt%d", i);
+ device_create_drvdata(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+ NULL, "iseries!nvt%d", i);
printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
"resource %10.10s type %4.4s, model %3.3s\n",
i, viotape_unitinfo[i].rsrcname,
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index dc17fe3a88b..d0f4eb6fdb7 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -46,6 +46,9 @@ static char *in, *inbuf;
/* The operations for our console. */
static struct hv_ops virtio_cons;
+/* The hvc device */
+static struct hvc_struct *hvc;
+
/*D:310 The put_chars() callback is pretty straightforward.
*
* We turn the characters into a scatter-gather list, add it to the output
@@ -134,6 +137,27 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
return hvc_instantiate(0, 0, &virtio_cons);
}
+/*
+ * we support only one console, the hvc struct is a global var
+ * There is no need to do anything
+ */
+static int notifier_add_vio(struct hvc_struct *hp, int data)
+{
+ hp->irq_requested = 1;
+ return 0;
+}
+
+static void notifier_del_vio(struct hvc_struct *hp, int data)
+{
+ hp->irq_requested = 0;
+}
+
+static void hvc_handle_input(struct virtqueue *vq)
+{
+ if (hvc_poll(hvc))
+ hvc_kick();
+}
+
/*D:370 Once we're further in boot, we get probed like any other virtio device.
* At this stage we set up the output virtqueue.
*
@@ -144,7 +168,6 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
static int __devinit virtcons_probe(struct virtio_device *dev)
{
int err;
- struct hvc_struct *hvc;
vdev = dev;
@@ -158,7 +181,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Find the input queue. */
/* FIXME: This is why we want to wean off hvc: we do nothing
* when input comes in. */
- in_vq = vdev->config->find_vq(vdev, 0, NULL);
+ in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input);
if (IS_ERR(in_vq)) {
err = PTR_ERR(in_vq);
goto free;
@@ -173,15 +196,18 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Start using the new console output. */
virtio_cons.get_chars = get_chars;
virtio_cons.put_chars = put_chars;
+ virtio_cons.notifier_add = notifier_add_vio;
+ virtio_cons.notifier_del = notifier_del_vio;
/* The first argument of hvc_alloc() is the virtual console number, so
- * we use zero. The second argument is the interrupt number; we
- * currently leave this as zero: it would be better not to use the
- * hvc mechanism and fix this (FIXME!).
+ * we use zero. The second argument is the parameter for the
+ * notification mechanism (like irq number). We currently leave this
+ * as zero, virtqueues have implicit notifications.
*
* The third argument is a "struct hv_ops" containing the put_chars()
- * and get_chars() pointers. The final argument is the output buffer
- * size: we can do any size, so we put PAGE_SIZE here. */
+ * get_chars(), notifier_add() and notifier_del() pointers.
+ * The final argument is the output buffer size: we can do any size,
+ * so we put PAGE_SIZE here. */
hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
if (IS_ERR(hvc)) {
err = PTR_ERR(hvc);
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index f17ac043b55..69c5afe97f1 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -85,7 +85,7 @@ static irqreturn_t scc_rx_int(int irq, void *data);
static irqreturn_t scc_stat_int(int irq, void *data);
static irqreturn_t scc_spcond_int(int irq, void *data);
static void scc_setsignals(struct scc_port *port, int dtr, int rts);
-static void scc_break_ctl(struct tty_struct *tty, int break_state);
+static int scc_break_ctl(struct tty_struct *tty, int break_state);
static struct tty_driver *scc_driver;
@@ -942,7 +942,7 @@ static int scc_ioctl(struct tty_struct *tty, struct file *file,
}
-static void scc_break_ctl(struct tty_struct *tty, int break_state)
+static int scc_break_ctl(struct tty_struct *tty, int break_state)
{
struct scc_port *port = (struct scc_port *)tty->driver_data;
unsigned long flags;
@@ -952,6 +952,7 @@ static void scc_break_ctl(struct tty_struct *tty, int break_state)
SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK,
break_state ? TCR_SEND_BREAK : 0);
local_irq_restore(flags);
+ return 0;
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 935f1c207a1..82a51f38a54 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -261,7 +261,7 @@ static void notify_update(struct vc_data *vc)
#ifdef VT_BUF_VRAM_ONLY
#define DO_UPDATE(vc) 0
#else
-#define DO_UPDATE(vc) CON_IS_VISIBLE(vc)
+#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked)
#endif
static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
@@ -2211,7 +2211,7 @@ rescan_last_byte:
c = 0xfffd;
tc = c;
} else { /* no utf or alternate charset mode */
- tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
+ tc = vc_translate(vc, c);
}
param.c = tc;
@@ -2749,8 +2749,8 @@ static int con_open(struct tty_struct *tty, struct file *filp)
tty->termios->c_iflag |= IUTF8;
else
tty->termios->c_iflag &= ~IUTF8;
- release_console_sem();
vcs_make_sysfs(tty);
+ release_console_sem();
return ret;
}
}
@@ -2775,8 +2775,8 @@ static void con_close(struct tty_struct *tty, struct file *filp)
if (vc)
vc->vc_tty = NULL;
tty->driver_data = NULL;
- release_console_sem();
vcs_remove_sysfs(tty);
+ release_console_sem();
mutex_unlock(&tty_mutex);
/*
* tty_mutex is released, but we still hold BKL, so there is
@@ -3425,9 +3425,10 @@ int register_con_driver(const struct consw *csw, int first, int last)
if (retval)
goto err;
- con_driver->dev = device_create(vtconsole_class, NULL,
- MKDEV(0, con_driver->node),
- "vtcon%i", con_driver->node);
+ con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
+ MKDEV(0, con_driver->node),
+ NULL, "vtcon%i",
+ con_driver->node);
if (IS_ERR(con_driver->dev)) {
printk(KERN_WARNING "Unable to create device for %s; "
@@ -3535,9 +3536,10 @@ static int __init vtconsole_class_init(void)
struct con_driver *con = &registered_con_driver[i];
if (con->con && !con->dev) {
- con->dev = device_create(vtconsole_class, NULL,
- MKDEV(0, con->node),
- "vtcon%i", con->node);
+ con->dev = device_create_drvdata(vtconsole_class, NULL,
+ MKDEV(0, con->node),
+ NULL, "vtcon%i",
+ con->node);
if (IS_ERR(con->dev)) {
printk(KERN_WARNING "Unable to create "
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 1e1b81e57cd..8bfee5fb722 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -87,7 +87,6 @@
#include <linux/mutex.h>
#include <linux/smp_lock.h>
#include <linux/sysctl.h>
-#include <linux/version.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
@@ -658,8 +657,9 @@ static int __devinit hwicap_setup(struct device *dev, int id,
dev_err(dev, "cdev_add() failed\n");
goto failed3;
}
- /* devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
- device_create(icap_class, dev, devt, "%s%d", DRIVER_NAME, id);
+
+ device_create_drvdata(icap_class, dev, devt, NULL,
+ "%s%d", DRIVER_NAME, id);
return 0; /* success */
failed3: