tty and serial merge for 3.4-rc1

Here's the big serial and tty merge for the 3.4-rc1 tree.
 
 There's loads of fixes and reworks in here from Jiri for the tty layer,
 and a number of patches from Alan to help try to wrestle the vt layer
 into a sane model.
 
 Other than that, lots of driver updates and fixes, and other minor
 stuff, all detailed in the shortlog.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.18 (GNU/Linux)
 
 iEYEABECAAYFAk9nihQACgkQMUfUDdst+ylXTQCdFuwVuZgjCts+xDVa1jX2ac84
 UogAn3Wr+P7NYFN6gvaGm52KbGbZs405
 =2b/l
 -----END PGP SIGNATURE-----

Merge tag 'tty-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull TTY/serial patches from Greg KH:
 "tty and serial merge for 3.4-rc1

  Here's the big serial and tty merge for the 3.4-rc1 tree.

  There's loads of fixes and reworks in here from Jiri for the tty
  layer, and a number of patches from Alan to help try to wrestle the vt
  layer into a sane model.

  Other than that, lots of driver updates and fixes, and other minor
  stuff, all detailed in the shortlog."

* tag 'tty-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (132 commits)
  serial: pxa: add clk_prepare/clk_unprepare calls
  TTY: Wrong unicode value copied in con_set_unimap()
  serial: PL011: clear pending interrupts
  serial: bfin-uart: Don't access tty circular buffer in TX DMA interrupt after it is reset.
  vt: NULL dereference in vt_do_kdsk_ioctl()
  tty: serial: vt8500: fix annotations for probe/remove
  serial: remove back and forth conversions in serial_out_sync
  serial: use serial_port_in/out vs serial_in/out in 8250
  serial: introduce generic port in/out helpers
  serial: reduce number of indirections in 8250 code
  serial: delete useless void casts in 8250.c
  serial: make 8250's serial_in shareable to other drivers.
  serial: delete last unused traces of pausing I/O in 8250
  pch_uart: Add module parameter descriptions
  pch_uart: Use existing default_baud in setup_console
  pch_uart: Add user_uartclk parameter
  pch_uart: Add Fish River Island II uart clock quirks
  pch_uart: Use uartclk instead of base_baud
  mpc5200b/uart: select more tolerant uart prescaler on low baudrates
  tty: moxa: fix bit test in moxa_start()
  ...
This commit is contained in:
Linus Torvalds 2012-03-20 11:24:39 -07:00
commit 843ec558f9
117 changed files with 3206 additions and 3138 deletions

View File

@ -0,0 +1,14 @@
* Energymicro efm32 UART
Required properties:
- compatible : Should be "efm32,uart"
- reg : Address and length of the register set
- interrupts : Should contain uart interrupt
Example:
uart@0x4000c400 {
compatible = "efm32,uart";
reg = <0x4000c400 0x400>;
interrupts = <15>;
};

View File

@ -6212,8 +6212,8 @@ L: sparclinux@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
S: Maintained S: Maintained
F: include/linux/sunserialcore.h
F: drivers/tty/serial/suncore.c F: drivers/tty/serial/suncore.c
F: drivers/tty/serial/suncore.h
F: drivers/tty/serial/sunhv.c F: drivers/tty/serial/sunhv.c
F: drivers/tty/serial/sunsab.c F: drivers/tty/serial/sunsab.c
F: drivers/tty/serial/sunsab.h F: drivers/tty/serial/sunsab.h

View File

@ -30,10 +30,9 @@ static int srm_is_registered_console = 0;
#define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */ #define MAX_SRM_CONSOLE_DEVICES 1 /* only support 1 console device */
struct srmcons_private { struct srmcons_private {
struct tty_struct *tty; struct tty_port port;
struct timer_list timer; struct timer_list timer;
spinlock_t lock; } srmcons_singleton;
};
typedef union _srmcons_result { typedef union _srmcons_result {
struct { struct {
@ -68,22 +67,21 @@ static void
srmcons_receive_chars(unsigned long data) srmcons_receive_chars(unsigned long data)
{ {
struct srmcons_private *srmconsp = (struct srmcons_private *)data; struct srmcons_private *srmconsp = (struct srmcons_private *)data;
struct tty_port *port = &srmconsp->port;
unsigned long flags; unsigned long flags;
int incr = 10; int incr = 10;
local_irq_save(flags); local_irq_save(flags);
if (spin_trylock(&srmcons_callback_lock)) { if (spin_trylock(&srmcons_callback_lock)) {
if (!srmcons_do_receive_chars(srmconsp->tty)) if (!srmcons_do_receive_chars(port->tty))
incr = 100; incr = 100;
spin_unlock(&srmcons_callback_lock); spin_unlock(&srmcons_callback_lock);
} }
spin_lock(&srmconsp->lock); spin_lock(&port->lock);
if (srmconsp->tty) { if (port->tty)
srmconsp->timer.expires = jiffies + incr; mod_timer(&srmconsp->timer, jiffies + incr);
add_timer(&srmconsp->timer); spin_unlock(&port->lock);
}
spin_unlock(&srmconsp->lock);
local_irq_restore(flags); local_irq_restore(flags);
} }
@ -155,57 +153,23 @@ srmcons_chars_in_buffer(struct tty_struct *tty)
return 0; return 0;
} }
static int
srmcons_get_private_struct(struct srmcons_private **ps)
{
static struct srmcons_private *srmconsp = NULL;
static DEFINE_SPINLOCK(srmconsp_lock);
unsigned long flags;
int retval = 0;
if (srmconsp == NULL) {
srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
spin_lock_irqsave(&srmconsp_lock, flags);
if (srmconsp == NULL)
retval = -ENOMEM;
else {
srmconsp->tty = NULL;
spin_lock_init(&srmconsp->lock);
init_timer(&srmconsp->timer);
}
spin_unlock_irqrestore(&srmconsp_lock, flags);
}
*ps = srmconsp;
return retval;
}
static int static int
srmcons_open(struct tty_struct *tty, struct file *filp) srmcons_open(struct tty_struct *tty, struct file *filp)
{ {
struct srmcons_private *srmconsp; struct srmcons_private *srmconsp = &srmcons_singleton;
struct tty_port *port = &srmconsp->port;
unsigned long flags; unsigned long flags;
int retval;
retval = srmcons_get_private_struct(&srmconsp); spin_lock_irqsave(&port->lock, flags);
if (retval)
return retval;
spin_lock_irqsave(&srmconsp->lock, flags); if (!port->tty) {
if (!srmconsp->tty) {
tty->driver_data = srmconsp; tty->driver_data = srmconsp;
tty->port = port;
srmconsp->tty = tty; port->tty = tty; /* XXX proper refcounting */
srmconsp->timer.function = srmcons_receive_chars; mod_timer(&srmconsp->timer, jiffies + 10);
srmconsp->timer.data = (unsigned long)srmconsp;
srmconsp->timer.expires = jiffies + 10;
add_timer(&srmconsp->timer);
} }
spin_unlock_irqrestore(&srmconsp->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
return 0; return 0;
} }
@ -214,16 +178,17 @@ static void
srmcons_close(struct tty_struct *tty, struct file *filp) srmcons_close(struct tty_struct *tty, struct file *filp)
{ {
struct srmcons_private *srmconsp = tty->driver_data; struct srmcons_private *srmconsp = tty->driver_data;
struct tty_port *port = &srmconsp->port;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&srmconsp->lock, flags); spin_lock_irqsave(&port->lock, flags);
if (tty->count == 1) { if (tty->count == 1) {
srmconsp->tty = NULL; port->tty = NULL;
del_timer(&srmconsp->timer); del_timer(&srmconsp->timer);
} }
spin_unlock_irqrestore(&srmconsp->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
@ -240,6 +205,9 @@ static const struct tty_operations srmcons_ops = {
static int __init static int __init
srmcons_init(void) srmcons_init(void)
{ {
tty_port_init(&srmcons_singleton.port);
setup_timer(&srmcons_singleton.timer, srmcons_receive_chars,
(unsigned long)&srmcons_singleton);
if (srm_is_registered_console) { if (srm_is_registered_console) {
struct tty_driver *driver; struct tty_driver *driver;
int err; int err;

View File

@ -160,28 +160,19 @@ sal_emulator (long index, unsigned long in1, unsigned long in2,
*/ */
status = 0; status = 0;
if (index == SAL_FREQ_BASE) { if (index == SAL_FREQ_BASE) {
switch (in1) { if (in1 == SAL_FREQ_BASE_PLATFORM)
case SAL_FREQ_BASE_PLATFORM:
r9 = 200000000; r9 = 200000000;
break; else if (in1 == SAL_FREQ_BASE_INTERVAL_TIMER) {
case SAL_FREQ_BASE_INTERVAL_TIMER:
/* /*
* Is this supposed to be the cr.itc frequency * Is this supposed to be the cr.itc frequency
* or something platform specific? The SAL * or something platform specific? The SAL
* doc ain't exactly clear on this... * doc ain't exactly clear on this...
*/ */
r9 = 700000000; r9 = 700000000;
break; } else if (in1 == SAL_FREQ_BASE_REALTIME_CLOCK)
case SAL_FREQ_BASE_REALTIME_CLOCK:
r9 = 1; r9 = 1;
break; else
default:
status = -1; status = -1;
break;
}
} else if (index == SAL_SET_VECTORS) { } else if (index == SAL_SET_VECTORS) {
; ;
} else if (index == SAL_GET_STATE_INFO) { } else if (index == SAL_GET_STATE_INFO) {

View File

@ -10,6 +10,8 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/irq.h> #include <linux/irq.h>
#include "hpsim_ssc.h"
static unsigned int static unsigned int
hpsim_irq_startup(struct irq_data *data) hpsim_irq_startup(struct irq_data *data)
{ {
@ -37,15 +39,37 @@ static struct irq_chip irq_type_hp_sim = {
.irq_set_affinity = hpsim_set_affinity_noop, .irq_set_affinity = hpsim_set_affinity_noop,
}; };
static void hpsim_irq_set_chip(int irq)
{
struct irq_chip *chip = irq_get_chip(irq);
if (chip == &no_irq_chip)
irq_set_chip(irq, &irq_type_hp_sim);
}
static void hpsim_connect_irq(int intr, int irq)
{
ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
}
int hpsim_get_irq(int intr)
{
int irq = assign_irq_vector(AUTO_ASSIGN);
if (irq >= 0) {
hpsim_irq_set_chip(irq);
irq_set_handler(irq, handle_simple_irq);
hpsim_connect_irq(intr, irq);
}
return irq;
}
void __init void __init
hpsim_irq_init (void) hpsim_irq_init (void)
{ {
int i; int i;
for_each_active_irq(i) { for_each_active_irq(i)
struct irq_chip *chip = irq_get_chip(i); hpsim_irq_set_chip(i);
if (chip == &no_irq_chip)
irq_set_chip(i, &irq_type_hp_sim);
}
} }

View File

@ -25,12 +25,6 @@
#include "hpsim_ssc.h" #include "hpsim_ssc.h"
void
ia64_ssc_connect_irq (long intr, long irq)
{
ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT);
}
void void
ia64_ctl_trace (long on) ia64_ctl_trace (long on)
{ {

View File

@ -128,17 +128,6 @@ netdev_probe(char *name, unsigned char *ether)
} }
static inline int
netdev_connect(int irq)
{
/* XXX Fix me
* this does not support multiple cards
* also no return value
*/
ia64_ssc_connect_irq(NETWORK_INTR, irq);
return 0;
}
static inline int static inline int
netdev_attach(int fd, int irq, unsigned int ipaddr) netdev_attach(int fd, int irq, unsigned int ipaddr)
{ {
@ -226,15 +215,13 @@ simeth_probe1(void)
return err; return err;
} }
if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
panic("%s: out of interrupt vectors!\n", __func__);
dev->irq = rc;
/* /*
* attach the interrupt in the simulator, this does enable interrupts * attach the interrupt in the simulator, this does enable interrupts
* until a netdev_attach() is called * until a netdev_attach() is called
*/ */
netdev_connect(dev->irq); if ((rc = hpsim_get_irq(NETWORK_INTR)) < 0)
panic("%s: out of interrupt vectors!\n", __func__);
dev->irq = rc;
printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr", printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr",
dev->name, simeth_device, local->simfd); dev->name, simeth_device, local->simfd);

View File

@ -4,16 +4,11 @@
* This driver is mostly used for bringup purposes and will go away. * This driver is mostly used for bringup purposes and will go away.
* It has a strong dependency on the system console. All outputs * It has a strong dependency on the system console. All outputs
* are rerouted to the same facility as the one used by printk which, in our * are rerouted to the same facility as the one used by printk which, in our
* case means sys_sim.c console (goes via the simulator). The code hereafter * case means sys_sim.c console (goes via the simulator).
* is completely leveraged from the serial.c driver.
* *
* Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com> * Stephane Eranian <eranian@hpl.hp.com>
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*
* 02/04/00 D. Mosberger Merged in serial.c bug fixes in rs_close().
* 02/25/00 D. Mosberger Synced up with 2.3.99pre-5 version of serial.c.
* 07/30/02 D. Mosberger Replace sti()/cli() with explicit spinlocks & local irq masking
*/ */
#include <linux/init.h> #include <linux/init.h>
@ -27,15 +22,17 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/circ_buf.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/uaccess.h>
#include <asm/irq.h> #include <asm/hpsim.h>
#include <asm/hw_irq.h>
#include <asm/uaccess.h> #include "hpsim_ssc.h"
#undef SIMSERIAL_DEBUG /* define this to get some debug information */ #undef SIMSERIAL_DEBUG /* define this to get some debug information */
@ -43,118 +40,44 @@
#define NR_PORTS 1 /* only one port for now */ #define NR_PORTS 1 /* only one port for now */
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) struct serial_state {
struct tty_port port;
#define SSC_GETCHAR 21 struct circ_buf xmit;
int irq;
extern long ia64_ssc (long, long, long, long, int); int x_char;
extern void ia64_ssc_connect_irq (long intr, long irq);
static char *serial_name = "SimSerial driver";
static char *serial_version = "0.6";
/*
* This has been extracted from asm/serial.h. We need one eventually but
* I don't know exactly what we're going to put in it so just fake one
* for now.
*/
#define BASE_BAUD ( 1843200 / 16 )
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
/*
* Most of the values here are meaningless to this particular driver.
* However some values must be preserved for the code (leveraged from serial.c
* to work correctly).
* port must not be 0
* type must not be UNKNOWN
* So I picked arbitrary (guess from where?) values instead
*/
static struct serial_state rs_table[NR_PORTS]={
/* UART CLK PORT IRQ FLAGS */
{ 0, BASE_BAUD, 0x3F8, 0, STD_COM_FLAGS,0,PORT_16550 } /* ttyS0 */
}; };
/* static struct serial_state rs_table[NR_PORTS];
* Just for the fun of it !
*/
static struct serial_uart_config uart_config[] = {
{ "unknown", 1, 0 },
{ "8250", 1, 0 },
{ "16450", 1, 0 },
{ "16550", 1, 0 },
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "cirrus", 1, 0 },
{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
{ NULL, 0}
};
struct tty_driver *hp_simserial_driver; struct tty_driver *hp_simserial_driver;
static struct async_struct *IRQ_ports[NR_IRQS];
static struct console *console; static struct console *console;
static unsigned char *tmp_buf; static void receive_chars(struct tty_struct *tty)
extern struct console *console_drivers; /* from kernel/printk.c */
/*
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
* This routines are called before setting or resetting tty->stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
static void rs_stop(struct tty_struct *tty)
{
#ifdef SIMSERIAL_DEBUG
printk("rs_stop: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
tty->stopped, tty->hw_stopped, tty->flow_stopped);
#endif
}
static void rs_start(struct tty_struct *tty)
{
#ifdef SIMSERIAL_DEBUG
printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
tty->stopped, tty->hw_stopped, tty->flow_stopped);
#endif
}
static void receive_chars(struct tty_struct *tty)
{ {
unsigned char ch; unsigned char ch;
static unsigned char seen_esc = 0; static unsigned char seen_esc = 0;
while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) { while ( (ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR)) ) {
if ( ch == 27 && seen_esc == 0 ) { if (ch == 27 && seen_esc == 0) {
seen_esc = 1; seen_esc = 1;
continue; continue;
} else { } else if (seen_esc == 1 && ch == 'O') {
if ( seen_esc==1 && ch == 'O' ) { seen_esc = 2;
seen_esc = 2; continue;
continue; } else if (seen_esc == 2) {
} else if ( seen_esc == 2 ) { if (ch == 'P') /* F1 */
if ( ch == 'P' ) /* F1 */ show_state();
show_state();
#ifdef CONFIG_MAGIC_SYSRQ #ifdef CONFIG_MAGIC_SYSRQ
if ( ch == 'S' ) { /* F4 */ if (ch == 'S') { /* F4 */
do do {
ch = ia64_ssc(0, 0, 0, 0, ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR);
SSC_GETCHAR); } while (!ch);
while (!ch); handle_sysrq(ch);
handle_sysrq(ch);
}
#endif
seen_esc = 0;
continue;
} }
#endif
seen_esc = 0;
continue;
} }
seen_esc = 0; seen_esc = 0;
@ -169,22 +92,19 @@ static void receive_chars(struct tty_struct *tty)
*/ */
static irqreturn_t rs_interrupt_single(int irq, void *dev_id) static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{ {
struct async_struct * info; struct serial_state *info = dev_id;
struct tty_struct *tty = tty_port_tty_get(&info->port);
/* if (!tty) {
* I don't know exactly why they don't use the dev_id opaque data printk(KERN_INFO "%s: tty=0 problem\n", __func__);
* pointer instead of this extra lookup table
*/
info = IRQ_ports[irq];
if (!info || !info->tty) {
printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info);
return IRQ_NONE; return IRQ_NONE;
} }
/* /*
* pretty simple in our case, because we only get interrupts * pretty simple in our case, because we only get interrupts
* on inbound traffic * on inbound traffic
*/ */
receive_chars(info->tty); receive_chars(tty);
tty_kref_put(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -194,17 +114,12 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
* ------------------------------------------------------------------- * -------------------------------------------------------------------
*/ */
static void do_softint(struct work_struct *private_)
{
printk(KERN_ERR "simserial: do_softint called\n");
}
static int rs_put_char(struct tty_struct *tty, unsigned char ch) static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
unsigned long flags; unsigned long flags;
if (!tty || !info->xmit.buf) if (!info->xmit.buf)
return 0; return 0;
local_irq_save(flags); local_irq_save(flags);
@ -218,12 +133,12 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
return 1; return 1;
} }
static void transmit_chars(struct async_struct *info, int *intr_done) static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
int *intr_done)
{ {
int count; int count;
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
if (info->x_char) { if (info->x_char) {
@ -231,16 +146,16 @@ static void transmit_chars(struct async_struct *info, int *intr_done)
console->write(console, &c, 1); console->write(console, &c, 1);
info->state->icount.tx++;
info->x_char = 0; info->x_char = 0;
goto out; goto out;
} }
if (info->xmit.head == info->xmit.tail || info->tty->stopped || info->tty->hw_stopped) { if (info->xmit.head == info->xmit.tail || tty->stopped ||
tty->hw_stopped) {
#ifdef SIMSERIAL_DEBUG #ifdef SIMSERIAL_DEBUG
printk("transmit_chars: head=%d, tail=%d, stopped=%d\n", printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
info->xmit.head, info->xmit.tail, info->tty->stopped); info->xmit.head, info->xmit.tail, tty->stopped);
#endif #endif
goto out; goto out;
} }
@ -272,24 +187,24 @@ out:
static void rs_flush_chars(struct tty_struct *tty) static void rs_flush_chars(struct tty_struct *tty)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped || if (info->xmit.head == info->xmit.tail || tty->stopped ||
!info->xmit.buf) tty->hw_stopped || !info->xmit.buf)
return; return;
transmit_chars(info, NULL); transmit_chars(tty, info, NULL);
} }
static int rs_write(struct tty_struct * tty, static int rs_write(struct tty_struct * tty,
const unsigned char *buf, int count) const unsigned char *buf, int count)
{ {
struct serial_state *info = tty->driver_data;
int c, ret = 0; int c, ret = 0;
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags; unsigned long flags;
if (!tty || !info->xmit.buf || !tmp_buf) return 0; if (!info->xmit.buf)
return 0;
local_irq_save(flags); local_irq_save(flags);
while (1) { while (1) {
@ -310,30 +225,30 @@ static int rs_write(struct tty_struct * tty,
/* /*
* Hey, we transmit directly from here in our case * Hey, we transmit directly from here in our case
*/ */
if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
&& !tty->stopped && !tty->hw_stopped) { !tty->stopped && !tty->hw_stopped)
transmit_chars(info, NULL); transmit_chars(tty, info, NULL);
}
return ret; return ret;
} }
static int rs_write_room(struct tty_struct *tty) static int rs_write_room(struct tty_struct *tty)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
} }
static int rs_chars_in_buffer(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
} }
static void rs_flush_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
@ -349,7 +264,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
*/ */
static void rs_send_xchar(struct tty_struct *tty, char ch) static void rs_send_xchar(struct tty_struct *tty, char ch)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
info->x_char = ch; info->x_char = ch;
if (ch) { if (ch) {
@ -357,7 +272,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
* I guess we could call console->write() directly but * I guess we could call console->write() directly but
* let's do that for now. * let's do that for now.
*/ */
transmit_chars(info, NULL); transmit_chars(tty, info, NULL);
} }
} }
@ -371,14 +286,15 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
*/ */
static void rs_throttle(struct tty_struct * tty) static void rs_throttle(struct tty_struct * tty)
{ {
if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
printk(KERN_INFO "simrs_throttle called\n"); printk(KERN_INFO "simrs_throttle called\n");
} }
static void rs_unthrottle(struct tty_struct * tty) static void rs_unthrottle(struct tty_struct * tty)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
if (I_IXOFF(tty)) { if (I_IXOFF(tty)) {
if (info->x_char) if (info->x_char)
@ -389,7 +305,6 @@ static void rs_unthrottle(struct tty_struct * tty)
printk(KERN_INFO "simrs_unthrottle called\n"); printk(KERN_INFO "simrs_unthrottle called\n");
} }
static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
{ {
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
@ -400,48 +315,21 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
} }
switch (cmd) { switch (cmd) {
case TIOCGSERIAL: case TIOCGSERIAL:
printk(KERN_INFO "simrs_ioctl TIOCGSERIAL called\n"); case TIOCSSERIAL:
return 0; case TIOCSERGSTRUCT:
case TIOCSSERIAL: case TIOCMIWAIT:
printk(KERN_INFO "simrs_ioctl TIOCSSERIAL called\n"); return 0;
return 0; case TIOCSERCONFIG:
case TIOCSERCONFIG: case TIOCSERGETLSR: /* Get line status register */
printk(KERN_INFO "rs_ioctl: TIOCSERCONFIG called\n"); return -EINVAL;
return -EINVAL; case TIOCSERGWILD:
case TIOCSERSWILD:
case TIOCSERGETLSR: /* Get line status register */ /* "setserial -W" is called in Debian boot */
printk(KERN_INFO "rs_ioctl: TIOCSERGETLSR called\n"); printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
return -EINVAL; return 0;
}
case TIOCSERGSTRUCT: return -ENOIOCTLCMD;
printk(KERN_INFO "rs_ioctl: TIOCSERGSTRUCT called\n");
#if 0
if (copy_to_user((struct async_struct *) arg,
info, sizeof(struct async_struct)))
return -EFAULT;
#endif
return 0;
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n");
return 0;
case TIOCSERGWILD:
case TIOCSERSWILD:
/* "setserial -W" is called in Debian boot */
printk (KERN_INFO "TIOCSER?WILD ioctl obsolete, ignored.\n");
return 0;
default:
return -ENOIOCTLCMD;
}
return 0;
} }
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
@ -452,220 +340,50 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if ((old_termios->c_cflag & CRTSCTS) && if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) { !(tty->termios->c_cflag & CRTSCTS)) {
tty->hw_stopped = 0; tty->hw_stopped = 0;
rs_start(tty);
} }
} }
/* /*
* This routine will shutdown a serial port; interrupts are disabled, and * This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on. * DTR is dropped if the hangup on close termio flag is on.
*/ */
static void shutdown(struct async_struct * info) static void shutdown(struct tty_port *port)
{ {
unsigned long flags; struct serial_state *info = container_of(port, struct serial_state,
struct serial_state *state; port);
int retval; unsigned long flags;
if (!(info->flags & ASYNC_INITIALIZED)) return;
state = info->state;
#ifdef SIMSERIAL_DEBUG
printk("Shutting down serial port %d (irq %d)....", info->line,
state->irq);
#endif
local_irq_save(flags); local_irq_save(flags);
{ if (info->irq)
/* free_irq(info->irq, info);
* First unlink the serial port from the IRQ chain...
*/
if (info->next_port)
info->next_port->prev_port = info->prev_port;
if (info->prev_port)
info->prev_port->next_port = info->next_port;
else
IRQ_ports[state->irq] = info->next_port;
/* if (info->xmit.buf) {
* Free the IRQ, if necessary free_page((unsigned long) info->xmit.buf);
*/ info->xmit.buf = NULL;
if (state->irq && (!IRQ_ports[state->irq] ||
!IRQ_ports[state->irq]->next_port)) {
if (IRQ_ports[state->irq]) {
free_irq(state->irq, NULL);
retval = request_irq(state->irq, rs_interrupt_single,
IRQ_T(info), "serial", NULL);
if (retval)
printk(KERN_ERR "serial shutdown: request_irq: error %d"
" Couldn't reacquire IRQ.\n", retval);
} else
free_irq(state->irq, NULL);
}
if (info->xmit.buf) {
free_page((unsigned long) info->xmit.buf);
info->xmit.buf = NULL;
}
if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
} }
local_irq_restore(flags); local_irq_restore(flags);
} }
/*
* ------------------------------------------------------------
* rs_close()
*
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
* async structure from the interrupt chain if necessary, and we free
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
static void rs_close(struct tty_struct *tty, struct file * filp) static void rs_close(struct tty_struct *tty, struct file * filp)
{ {
struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
struct serial_state *state;
unsigned long flags;
if (!info ) return; tty_port_close(&info->port, tty, filp);
state = info->state;
local_irq_save(flags);
if (tty_hung_up_p(filp)) {
#ifdef SIMSERIAL_DEBUG
printk("rs_close: hung_up\n");
#endif
local_irq_restore(flags);
return;
}
#ifdef SIMSERIAL_DEBUG
printk("rs_close ttys%d, count = %d\n", info->line, state->count);
#endif
if ((tty->count == 1) && (state->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. state->count should always
* be one in these conditions. If it's greater than
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, "
"state->count is %d\n", state->count);
state->count = 1;
}
if (--state->count < 0) {
printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
info->line, state->count);
state->count = 0;
}
if (state->count) {
local_irq_restore(flags);
return;
}
info->flags |= ASYNC_CLOSING;
local_irq_restore(flags);
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
shutdown(info);
rs_flush_buffer(tty);
tty_ldisc_flush(tty);
info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
if (info->close_delay)
schedule_timeout_interruptible(info->close_delay);
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
} }
/*
* rs_wait_until_sent() --- wait until the transmitter is empty
*/
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
}
/*
* rs_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
static void rs_hangup(struct tty_struct *tty) static void rs_hangup(struct tty_struct *tty)
{ {
struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *info = tty->driver_data;
struct serial_state *state = info->state;
#ifdef SIMSERIAL_DEBUG
printk("rs_hangup: called\n");
#endif
state = info->state;
rs_flush_buffer(tty); rs_flush_buffer(tty);
if (info->flags & ASYNC_CLOSING) tty_port_hangup(&info->port);
return;
shutdown(info);
info->event = 0;
state->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
info->tty = NULL;
wake_up_interruptible(&info->open_wait);
} }
static int activate(struct tty_port *port, struct tty_struct *tty)
static int get_async_struct(int line, struct async_struct **ret_info)
{ {
struct async_struct *info; struct serial_state *state = container_of(port, struct serial_state,
struct serial_state *sstate; port);
unsigned long flags, page;
sstate = rs_table + line; int retval = 0;
sstate->count++;
if (sstate->info) {
*ret_info = sstate->info;
return 0;
}
info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
if (!info) {
sstate->count--;
return -ENOMEM;
}
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
init_waitqueue_head(&info->delta_msr_wait);
info->magic = SERIAL_MAGIC;
info->port = sstate->port;
info->flags = sstate->flags;
info->xmit_fifo_size = sstate->xmit_fifo_size;
info->line = line;
INIT_WORK(&info->work, do_softint);
info->state = sstate;
if (sstate->info) {
kfree(info);
*ret_info = sstate->info;
return 0;
}
*ret_info = sstate->info = info;
return 0;
}
static int
startup(struct async_struct *info)
{
unsigned long flags;
int retval=0;
irq_handler_t handler;
struct serial_state *state= info->state;
unsigned long page;
page = get_zeroed_page(GFP_KERNEL); page = get_zeroed_page(GFP_KERNEL);
if (!page) if (!page)
@ -673,86 +391,31 @@ startup(struct async_struct *info)
local_irq_save(flags); local_irq_save(flags);
if (info->flags & ASYNC_INITIALIZED) { if (state->xmit.buf)
free_page(page);
goto errout;
}
if (!state->port || !state->type) {
if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
goto errout;
}
if (info->xmit.buf)
free_page(page); free_page(page);
else else
info->xmit.buf = (unsigned char *) page; state->xmit.buf = (unsigned char *) page;
#ifdef SIMSERIAL_DEBUG if (state->irq) {
printk("startup: ttys%d (irq %d)...", info->line, state->irq); retval = request_irq(state->irq, rs_interrupt_single, 0,
#endif "simserial", state);
if (retval)
/*
* Allocate the IRQ if necessary
*/
if (state->irq && (!IRQ_ports[state->irq] ||
!IRQ_ports[state->irq]->next_port)) {
if (IRQ_ports[state->irq]) {
retval = -EBUSY;
goto errout; goto errout;
} else
handler = rs_interrupt_single;
retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL);
if (retval) {
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR,
&info->tty->flags);
retval = 0;
}
goto errout;
}
} }
/* state->xmit.head = state->xmit.tail = 0;
* Insert serial port into IRQ chain.
*/
info->prev_port = NULL;
info->next_port = IRQ_ports[state->irq];
if (info->next_port)
info->next_port->prev_port = info;
IRQ_ports[state->irq] = info;
if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit.head = info->xmit.tail = 0;
#if 0
/*
* Set up serial timers...
*/
timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
timer_active |= 1 << RS_TIMER;
#endif
/* /*
* Set up the tty->alt_speed kludge * Set up the tty->alt_speed kludge
*/ */
if (info->tty) { if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) tty->alt_speed = 57600;
info->tty->alt_speed = 57600; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) tty->alt_speed = 115200;
info->tty->alt_speed = 115200; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) tty->alt_speed = 230400;
info->tty->alt_speed = 230400; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) tty->alt_speed = 460800;
info->tty->alt_speed = 460800;
}
info->flags |= ASYNC_INITIALIZED;
local_irq_restore(flags);
return 0;
errout: errout:
local_irq_restore(flags); local_irq_restore(flags);
@ -768,56 +431,11 @@ errout:
*/ */
static int rs_open(struct tty_struct *tty, struct file * filp) static int rs_open(struct tty_struct *tty, struct file * filp)
{ {
struct async_struct *info; struct serial_state *info = rs_table + tty->index;
int retval, line; struct tty_port *port = &info->port;
unsigned long page;
line = tty->index;
if ((line < 0) || (line >= NR_PORTS))
return -ENODEV;
retval = get_async_struct(line, &info);
if (retval)
return retval;
tty->driver_data = info; tty->driver_data = info;
info->tty = tty; tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
#ifdef SIMSERIAL_DEBUG
printk("rs_open %s, count = %d\n", tty->name, info->state->count);
#endif
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if (!tmp_buf) {
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
if (tmp_buf)
free_page(page);
else
tmp_buf = (unsigned char *) page;
}
/*
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
#else
return -EAGAIN;
#endif
}
/*
* Start up serial port
*/
retval = startup(info);
if (retval) {
return retval;
}
/* /*
* figure out which console to use (should be one already) * figure out which console to use (should be one already)
@ -828,30 +446,21 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
console = console->next; console = console->next;
} }
#ifdef SIMSERIAL_DEBUG return tty_port_open(port, tty, filp);
printk("rs_open ttys%d successful\n", info->line);
#endif
return 0;
} }
/* /*
* /proc fs routines.... * /proc fs routines....
*/ */
static inline void line_info(struct seq_file *m, struct serial_state *state)
{
seq_printf(m, "%d: uart:%s port:%lX irq:%d\n",
state->line, uart_config[state->type].name,
state->port, state->irq);
}
static int rs_proc_show(struct seq_file *m, void *v) static int rs_proc_show(struct seq_file *m, void *v)
{ {
int i; int i;
seq_printf(m, "simserinfo:1.0 driver:%s\n", serial_version); seq_printf(m, "simserinfo:1.0\n");
for (i = 0; i < NR_PORTS; i++) for (i = 0; i < NR_PORTS; i++)
line_info(m, &rs_table[i]); seq_printf(m, "%d: uart:16550 port:3F8 irq:%d\n",
i, rs_table[i].irq);
return 0; return 0;
} }
@ -868,25 +477,6 @@ static const struct file_operations rs_proc_fops = {
.release = single_release, .release = single_release,
}; };
/*
* ---------------------------------------------------------------------
* rs_init() and friends
*
* rs_init() is called at boot-time to initialize the serial driver.
* ---------------------------------------------------------------------
*/
/*
* This routine prints out the appropriate serial driver version
* number, and identifies which options were configured into this
* driver.
*/
static inline void show_serial_version(void)
{
printk(KERN_INFO "%s version %s with", serial_name, serial_version);
printk(KERN_INFO " no serial options enabled\n");
}
static const struct tty_operations hp_ops = { static const struct tty_operations hp_ops = {
.open = rs_open, .open = rs_open,
.close = rs_close, .close = rs_close,
@ -901,34 +491,31 @@ static const struct tty_operations hp_ops = {
.unthrottle = rs_unthrottle, .unthrottle = rs_unthrottle,
.send_xchar = rs_send_xchar, .send_xchar = rs_send_xchar,
.set_termios = rs_set_termios, .set_termios = rs_set_termios,
.stop = rs_stop,
.start = rs_start,
.hangup = rs_hangup, .hangup = rs_hangup,
.wait_until_sent = rs_wait_until_sent,
.proc_fops = &rs_proc_fops, .proc_fops = &rs_proc_fops,
}; };
/* static const struct tty_port_operations hp_port_ops = {
* The serial driver boot-time initialization code! .activate = activate,
*/ .shutdown = shutdown,
static int __init };
simrs_init (void)
static int __init simrs_init(void)
{ {
int i, rc; struct serial_state *state;
struct serial_state *state; int retval;
if (!ia64_platform_is("hpsim")) if (!ia64_platform_is("hpsim"))
return -ENODEV; return -ENODEV;
hp_simserial_driver = alloc_tty_driver(1); hp_simserial_driver = alloc_tty_driver(NR_PORTS);
if (!hp_simserial_driver) if (!hp_simserial_driver)
return -ENOMEM; return -ENOMEM;
show_serial_version(); printk(KERN_INFO "SimSerial driver with no serial options enabled\n");
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
hp_simserial_driver->owner = THIS_MODULE;
hp_simserial_driver->driver_name = "simserial"; hp_simserial_driver->driver_name = "simserial";
hp_simserial_driver->name = "ttyS"; hp_simserial_driver->name = "ttyS";
hp_simserial_driver->major = TTY_MAJOR; hp_simserial_driver->major = TTY_MAJOR;
@ -941,31 +528,33 @@ simrs_init (void)
hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW; hp_simserial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(hp_simserial_driver, &hp_ops); tty_set_operations(hp_simserial_driver, &hp_ops);
/* state = rs_table;
* Let's have a little bit of fun ! tty_port_init(&state->port);
*/ state->port.ops = &hp_port_ops;
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->port.close_delay = 0; /* XXX really 0? */
if (state->type == PORT_UNKNOWN) continue; retval = hpsim_get_irq(KEYBOARD_INTR);
if (retval < 0) {
if (!state->irq) { printk(KERN_ERR "%s: out of interrupt vectors!\n",
if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0) __func__);
panic("%s: out of interrupt vectors!\n", goto err_free_tty;
__func__);
state->irq = rc;
ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
}
printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",
state->line,
state->port, state->irq,
uart_config[state->type].name);
} }
if (tty_register_driver(hp_simserial_driver)) state->irq = retval;
panic("Couldn't register simserial driver\n");
/* the port is imaginary */
printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
retval = tty_register_driver(hp_simserial_driver);
if (retval) {
printk(KERN_ERR "Couldn't register simserial driver\n");
goto err_free_tty;
}
return 0; return 0;
err_free_tty:
put_tty_driver(hp_simserial_driver);
return retval;
} }
#ifndef MODULE #ifndef MODULE

View File

@ -10,7 +10,7 @@ int simcons_register(void);
struct tty_driver; struct tty_driver;
extern struct tty_driver *hp_simserial_driver; extern struct tty_driver *hp_simserial_driver;
void ia64_ssc_connect_irq(long intr, long irq); extern int hpsim_get_irq(int intr);
void ia64_ctl_trace(long on); void ia64_ctl_trace(long on);
#endif #endif

View File

@ -127,7 +127,6 @@ static int __init nfcon_init(void)
if (!nfcon_tty_driver) if (!nfcon_tty_driver)
return -ENOMEM; return -ENOMEM;
nfcon_tty_driver->owner = THIS_MODULE;
nfcon_tty_driver->driver_name = "nfcon"; nfcon_tty_driver->driver_name = "nfcon";
nfcon_tty_driver->name = "nfcon"; nfcon_tty_driver->name = "nfcon";
nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;

View File

@ -90,11 +90,13 @@ static int pdc_console_setup(struct console *co, char *options)
#define PDC_CONS_POLL_DELAY (30 * HZ / 1000) #define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
static struct timer_list pdc_console_timer; static void pdc_console_poll(unsigned long unused);
static DEFINE_TIMER(pdc_console_timer, pdc_console_poll, 0, 0);
static struct tty_port tty_port;
static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp) static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
{ {
tty_port_tty_set(&tty_port, tty);
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
return 0; return 0;
@ -102,8 +104,10 @@ static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp) static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
{ {
if (!tty->count) if (!tty->count) {
del_timer(&pdc_console_timer); del_timer_sync(&pdc_console_timer);
tty_port_tty_set(&tty_port, NULL);
}
} }
static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@ -122,8 +126,6 @@ static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
return 0; /* no buffer */ return 0; /* no buffer */
} }
static struct tty_driver *pdc_console_tty_driver;
static const struct tty_operations pdc_console_tty_ops = { static const struct tty_operations pdc_console_tty_ops = {
.open = pdc_console_tty_open, .open = pdc_console_tty_open,
.close = pdc_console_tty_close, .close = pdc_console_tty_close,
@ -134,10 +136,8 @@ static const struct tty_operations pdc_console_tty_ops = {
static void pdc_console_poll(unsigned long unused) static void pdc_console_poll(unsigned long unused)
{ {
int data, count = 0; int data, count = 0;
struct tty_struct *tty = tty_port_tty_get(&tty_port);
struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
if (!tty) if (!tty)
return; return;
@ -153,15 +153,17 @@ static void pdc_console_poll(unsigned long unused)
if (count) if (count)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
if (tty->count && (pdc_cons.flags & CON_ENABLED)) tty_kref_put(tty);
if (pdc_cons.flags & CON_ENABLED)
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
} }
static struct tty_driver *pdc_console_tty_driver;
static int __init pdc_console_tty_driver_init(void) static int __init pdc_console_tty_driver_init(void)
{ {
int err; int err;
struct tty_driver *drv;
/* Check if the console driver is still registered. /* Check if the console driver is still registered.
* It is unregistered if the pdc console was not selected as the * It is unregistered if the pdc console was not selected as the
@ -183,32 +185,29 @@ static int __init pdc_console_tty_driver_init(void)
printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n"); printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
pdc_cons.flags &= ~CON_BOOT; pdc_cons.flags &= ~CON_BOOT;
drv = alloc_tty_driver(1); tty_port_init(&tty_port);
if (!drv) pdc_console_tty_driver = alloc_tty_driver(1);
if (!pdc_console_tty_driver)
return -ENOMEM; return -ENOMEM;
drv->driver_name = "pdc_cons"; pdc_console_tty_driver->driver_name = "pdc_cons";
drv->name = "ttyB"; pdc_console_tty_driver->name = "ttyB";
drv->major = MUX_MAJOR; pdc_console_tty_driver->major = MUX_MAJOR;
drv->minor_start = 0; pdc_console_tty_driver->minor_start = 0;
drv->type = TTY_DRIVER_TYPE_SYSTEM; pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
drv->init_termios = tty_std_termios; pdc_console_tty_driver->init_termios = tty_std_termios;
drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
tty_set_operations(drv, &pdc_console_tty_ops); TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
err = tty_register_driver(drv); err = tty_register_driver(pdc_console_tty_driver);
if (err) { if (err) {
printk(KERN_ERR "Unable to register the PDC console TTY driver\n"); printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
return err; return err;
} }
pdc_console_tty_driver = drv;
/* No need to initialize the pdc_console_timer if tty isn't allocated */
init_timer(&pdc_console_timer);
pdc_console_timer.function = pdc_console_poll;
return 0; return 0;
} }

View File

@ -19,7 +19,6 @@
#include <linux/param.h> #include <linux/param.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serialP.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/irq.h> #include <asm/irq.h>
@ -37,6 +36,7 @@
#define SERIAL_TIMER_VALUE (20 * HZ) #define SERIAL_TIMER_VALUE (20 * HZ)
static struct tty_driver *serial_driver; static struct tty_driver *serial_driver;
static struct tty_port serial_port;
static struct timer_list serial_timer; static struct timer_list serial_timer;
static DEFINE_SPINLOCK(timer_lock); static DEFINE_SPINLOCK(timer_lock);
@ -68,17 +68,10 @@ static void rs_poll(unsigned long);
static int rs_open(struct tty_struct *tty, struct file * filp) static int rs_open(struct tty_struct *tty, struct file * filp)
{ {
int line = tty->index; tty->port = &serial_port;
if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES))
return -ENODEV;
spin_lock(&timer_lock); spin_lock(&timer_lock);
if (tty->count == 1) { if (tty->count == 1) {
init_timer(&serial_timer); setup_timer(&serial_timer, rs_poll, (unsigned long)tty);
serial_timer.data = (unsigned long) tty;
serial_timer.function = rs_poll;
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
} }
spin_unlock(&timer_lock); spin_unlock(&timer_lock);
@ -99,10 +92,10 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
*/ */
static void rs_close(struct tty_struct *tty, struct file * filp) static void rs_close(struct tty_struct *tty, struct file * filp)
{ {
spin_lock(&timer_lock); spin_lock_bh(&timer_lock);
if (tty->count == 1) if (tty->count == 1)
del_timer_sync(&serial_timer); del_timer_sync(&serial_timer);
spin_unlock(&timer_lock); spin_unlock_bh(&timer_lock);
} }
@ -210,13 +203,14 @@ static const struct tty_operations serial_ops = {
int __init rs_init(void) int __init rs_init(void)
{ {
serial_driver = alloc_tty_driver(1); tty_port_init(&serial_port);
serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
printk ("%s %s\n", serial_name, serial_version); printk ("%s %s\n", serial_name, serial_version);
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = "iss_serial"; serial_driver->driver_name = "iss_serial";
serial_driver->name = "ttyS"; serial_driver->name = "ttyS";
serial_driver->major = TTY_MAJOR; serial_driver->major = TTY_MAJOR;

View File

@ -244,16 +244,13 @@ static int keyboard_notifier_call(struct notifier_block *blk,
switch (val) { switch (val) {
case KVAL(K_CAPS): case KVAL(K_CAPS):
on_off = vc_kbd_led(kbd_table + fg_console, on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
VC_CAPSLOCK);
break; break;
case KVAL(K_NUM): case KVAL(K_NUM):
on_off = vc_kbd_led(kbd_table + fg_console, on_off = vt_get_leds(fg_console, VC_NUMLOCK);
VC_NUMLOCK);
break; break;
case KVAL(K_HOLD): case KVAL(K_HOLD):
on_off = vc_kbd_led(kbd_table + fg_console, on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
VC_SCROLLOCK);
break; break;
} }
if (on_off == 1) if (on_off == 1)

View File

@ -66,21 +66,6 @@ config TTY_PRINTK
If unsure, say N. If unsure, say N.
config BRIQ_PANEL
tristate 'Total Impact briQ front panel driver'
depends on PPC_CHRP
---help---
The briQ is a small footprint CHRP computer with a frontpanel VFD, a
tristate led and two switches. It is the size of a CDROM drive.
If you have such one and want anything showing on the VFD then you
must answer Y here.
To compile this driver as a module, choose M here: the
module will be called briq_panel.
It's safe to say N here.
config BFIN_OTP config BFIN_OTP
tristate "Blackfin On-Chip OTP Memory Support" tristate "Blackfin On-Chip OTP Memory Support"
depends on BLACKFIN && (BF51x || BF52x || BF54x) depends on BLACKFIN && (BF51x || BF52x || BF54x)

View File

@ -16,7 +16,6 @@ obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_VIOTAPE) += viotape.o
obj-$(CONFIG_IBM_BSR) += bsr.o obj-$(CONFIG_IBM_BSR) += bsr.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o obj-$(CONFIG_SGI_MBCS) += mbcs.o
obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_BFIN_OTP) += bfin-otp.o obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_PRINTER) += lp.o

View File

@ -1,266 +0,0 @@
/*
* Drivers for the Total Impact PPC based computer "BRIQ"
* by Dr. Karsten Jeppesen
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/prom.h>
#define BRIQ_PANEL_MINOR 156
#define BRIQ_PANEL_VFD_IOPORT 0x0390
#define BRIQ_PANEL_LED_IOPORT 0x0398
#define BRIQ_PANEL_VER "1.1 (04/20/2002)"
#define BRIQ_PANEL_MSG0 "Loading Linux"
static int vfd_is_open;
static unsigned char vfd[40];
static int vfd_cursor;
static unsigned char ledpb, led;
static void update_vfd(void)
{
int i;
/* cursor home */
outb(0x02, BRIQ_PANEL_VFD_IOPORT);
for (i=0; i<20; i++)
outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
/* cursor to next line */
outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
for (i=20; i<40; i++)
outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
}
static void set_led(char state)
{
if (state == 'R')
led = 0x01;
else if (state == 'G')
led = 0x02;
else if (state == 'Y')
led = 0x03;
else if (state == 'X')
led = 0x00;
outb(led, BRIQ_PANEL_LED_IOPORT);
}
static int briq_panel_open(struct inode *ino, struct file *filep)
{
tty_lock();
/* enforce single access, vfd_is_open is protected by BKL */
if (vfd_is_open) {
tty_unlock();
return -EBUSY;
}
vfd_is_open = 1;
tty_unlock();
return 0;
}
static int briq_panel_release(struct inode *ino, struct file *filep)
{
if (!vfd_is_open)
return -ENODEV;
vfd_is_open = 0;
return 0;
}
static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
unsigned short c;
unsigned char cp;
if (!vfd_is_open)
return -ENODEV;
c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
set_led(' ');
/* upper button released */
if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
cp = ' ';
ledpb = c;
if (copy_to_user(buf, &cp, 1))
return -EFAULT;
return 1;
}
/* lower button released */
else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
cp = '\r';
ledpb = c;
if (copy_to_user(buf, &cp, 1))
return -EFAULT;
return 1;
} else {
ledpb = c;
return 0;
}
}
static void scroll_vfd( void )
{
int i;
for (i=0; i<20; i++) {
vfd[i] = vfd[i+20];
vfd[i+20] = ' ';
}
vfd_cursor = 20;
}
static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
loff_t *ppos)
{
size_t indx = len;
int i, esc = 0;
if (!vfd_is_open)
return -EBUSY;
for (;;) {
char c;
if (!indx)
break;
if (get_user(c, buf))
return -EFAULT;
if (esc) {
set_led(c);
esc = 0;
} else if (c == 27) {
esc = 1;
} else if (c == 12) {
/* do a form feed */
for (i=0; i<40; i++)
vfd[i] = ' ';
vfd_cursor = 0;
} else if (c == 10) {
if (vfd_cursor < 20)
vfd_cursor = 20;
else if (vfd_cursor < 40)
vfd_cursor = 40;
else if (vfd_cursor < 60)
vfd_cursor = 60;
if (vfd_cursor > 59)
scroll_vfd();
} else {
/* just a character */
if (vfd_cursor > 39)
scroll_vfd();
vfd[vfd_cursor++] = c;
}
indx--;
buf++;
}
update_vfd();
return len;
}
static const struct file_operations briq_panel_fops = {
.owner = THIS_MODULE,
.read = briq_panel_read,
.write = briq_panel_write,
.open = briq_panel_open,
.release = briq_panel_release,
.llseek = noop_llseek,
};
static struct miscdevice briq_panel_miscdev = {
BRIQ_PANEL_MINOR,
"briq_panel",
&briq_panel_fops
};
static int __init briq_panel_init(void)
{
struct device_node *root = of_find_node_by_path("/");
const char *machine;
int i;
machine = of_get_property(root, "model", NULL);
if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
of_node_put(root);
return -ENODEV;
}
of_node_put(root);
printk(KERN_INFO
"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
BRIQ_PANEL_VER);
if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
return -EBUSY;
if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
return -EBUSY;
}
ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
if (misc_register(&briq_panel_miscdev) < 0) {
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
release_region(BRIQ_PANEL_LED_IOPORT, 2);
return -EBUSY;
}
outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */
outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */
outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */
outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */
for (i=0; i<40; i++)
vfd[i]=' ';
#ifndef MODULE
vfd[0] = 'L';
vfd[1] = 'o';
vfd[2] = 'a';
vfd[3] = 'd';
vfd[4] = 'i';
vfd[5] = 'n';
vfd[6] = 'g';
vfd[7] = ' ';
vfd[8] = '.';
vfd[9] = '.';
vfd[10] = '.';
#endif /* !MODULE */
update_vfd();
return 0;
}
static void __exit briq_panel_exit(void)
{
misc_deregister(&briq_panel_miscdev);
release_region(BRIQ_PANEL_VFD_IOPORT, 4);
release_region(BRIQ_PANEL_LED_IOPORT, 2);
}
module_init(briq_panel_init);
module_exit(briq_panel_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");

View File

@ -2484,7 +2484,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
/* verify range of specified line number */ /* verify range of specified line number */
line = tty->index; line = tty->index;
if ((line < 0) || (line >= mgslpc_device_count)) { if (line >= mgslpc_device_count) {
printk("%s(%d):mgslpc_open with invalid line #%d.\n", printk("%s(%d):mgslpc_open with invalid line #%d.\n",
__FILE__,__LINE__,line); __FILE__,__LINE__,line);
return -ENODEV; return -ENODEV;
@ -2836,7 +2836,6 @@ static int __init synclink_cs_init(void)
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = "synclink_cs"; serial_driver->driver_name = "synclink_cs";
serial_driver->name = "ttySLP"; serial_driver->name = "ttySLP";
serial_driver->major = ttymajor; serial_driver->major = ttymajor;

View File

@ -184,12 +184,10 @@ static int __init ttyprintk_init(void)
if (!ttyprintk_driver) if (!ttyprintk_driver)
return ret; return ret;
ttyprintk_driver->owner = THIS_MODULE;
ttyprintk_driver->driver_name = "ttyprintk"; ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk"; ttyprintk_driver->name = "ttyprintk";
ttyprintk_driver->major = TTYAUX_MAJOR; ttyprintk_driver->major = TTYAUX_MAJOR;
ttyprintk_driver->minor_start = 3; ttyprintk_driver->minor_start = 3;
ttyprintk_driver->num = 1;
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ttyprintk_driver->init_termios = tty_std_termios; ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;

View File

@ -1013,16 +1013,12 @@ static const struct file_operations capi_fops =
static int static int
capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty) capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
int idx = tty->index; struct capiminor *mp = capiminor_get(tty->index);
struct capiminor *mp = capiminor_get(idx); int ret = tty_standard_install(driver, tty);
int ret = tty_init_termios(tty);
if (ret == 0) { if (ret == 0)
tty_driver_kref_get(driver);
tty->count++;
tty->driver_data = mp; tty->driver_data = mp;
driver->ttys[idx] = tty; else
} else
capiminor_put(mp); capiminor_put(mp);
return ret; return ret;
} }
@ -1290,7 +1286,6 @@ static int __init capinc_tty_init(void)
kfree(capiminors); kfree(capiminors);
return -ENOMEM; return -ENOMEM;
} }
drv->owner = THIS_MODULE;
drv->driver_name = "capi_nc"; drv->driver_name = "capi_nc";
drv->name = "capi"; drv->name = "capi";
drv->major = 0; drv->major = 0;

View File

@ -720,12 +720,11 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
tasklet_init(&cs->event_tasklet, gigaset_handle_event, tasklet_init(&cs->event_tasklet, gigaset_handle_event,
(unsigned long) cs); (unsigned long) cs);
tty_port_init(&cs->port);
cs->commands_pending = 0; cs->commands_pending = 0;
cs->cur_at_seq = 0; cs->cur_at_seq = 0;
cs->gotfwver = -1; cs->gotfwver = -1;
cs->open_count = 0;
cs->dev = NULL; cs->dev = NULL;
cs->tty = NULL;
cs->tty_dev = NULL; cs->tty_dev = NULL;
cs->cidmode = cidmode != 0; cs->cidmode = cidmode != 0;
cs->tabnocid = gigaset_tab_nocid; cs->tabnocid = gigaset_tab_nocid;
@ -1051,8 +1050,6 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
{ {
if (tty->index < 0 || tty->index >= tty->driver->num)
return NULL;
return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
} }

View File

@ -433,8 +433,7 @@ struct cardstate {
spinlock_t cmdlock; spinlock_t cmdlock;
unsigned curlen, cmdbytes; unsigned curlen, cmdbytes;
unsigned open_count; struct tty_port port;
struct tty_struct *tty;
struct tasklet_struct if_wake_tasklet; struct tasklet_struct if_wake_tasklet;
unsigned control_state; unsigned control_state;

View File

@ -146,13 +146,10 @@ static const struct tty_operations if_ops = {
static int if_open(struct tty_struct *tty, struct file *filp) static int if_open(struct tty_struct *tty, struct file *filp)
{ {
struct cardstate *cs; struct cardstate *cs;
unsigned long flags;
gig_dbg(DEBUG_IF, "%d+%d: %s()", gig_dbg(DEBUG_IF, "%d+%d: %s()",
tty->driver->minor_start, tty->index, __func__); tty->driver->minor_start, tty->index, __func__);
tty->driver_data = NULL;
cs = gigaset_get_cs_by_tty(tty); cs = gigaset_get_cs_by_tty(tty);
if (!cs || !try_module_get(cs->driver->owner)) if (!cs || !try_module_get(cs->driver->owner))
return -ENODEV; return -ENODEV;
@ -163,12 +160,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
} }
tty->driver_data = cs; tty->driver_data = cs;
++cs->open_count; ++cs->port.count;
if (cs->open_count == 1) { if (cs->port.count == 1) {
spin_lock_irqsave(&cs->lock, flags); tty_port_tty_set(&cs->port, tty);
cs->tty = tty;
spin_unlock_irqrestore(&cs->lock, flags);
tty->low_latency = 1; tty->low_latency = 1;
} }
@ -178,12 +173,10 @@ static int if_open(struct tty_struct *tty, struct file *filp)
static void if_close(struct tty_struct *tty, struct file *filp) static void if_close(struct tty_struct *tty, struct file *filp)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
unsigned long flags;
cs = (struct cardstate *) tty->driver_data; if (!cs) { /* happens if we didn't find cs in open */
if (!cs) { printk(KERN_DEBUG "%s: no cardstate\n", __func__);
pr_err("%s: no cardstate\n", __func__);
return; return;
} }
@ -193,15 +186,10 @@ static void if_close(struct tty_struct *tty, struct file *filp)
if (!cs->connected) if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else if (!cs->open_count) else if (!cs->port.count)
dev_warn(cs->dev, "%s: device not opened\n", __func__); dev_warn(cs->dev, "%s: device not opened\n", __func__);
else { else if (!--cs->port.count)
if (!--cs->open_count) { tty_port_tty_set(&cs->port, NULL);
spin_lock_irqsave(&cs->lock, flags);
cs->tty = NULL;
spin_unlock_irqrestore(&cs->lock, flags);
}
}
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
@ -211,18 +199,12 @@ static void if_close(struct tty_struct *tty, struct file *filp)
static int if_ioctl(struct tty_struct *tty, static int if_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
int retval = -ENODEV; int retval = -ENODEV;
int int_arg; int int_arg;
unsigned char buf[6]; unsigned char buf[6];
unsigned version[4]; unsigned version[4];
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return -ENODEV;
}
gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
@ -231,9 +213,7 @@ static int if_ioctl(struct tty_struct *tty,
if (!cs->connected) { if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV; retval = -ENODEV;
} else if (!cs->open_count) } else {
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else {
retval = 0; retval = 0;
switch (cmd) { switch (cmd) {
case GIGASET_REDIR: case GIGASET_REDIR:
@ -285,15 +265,9 @@ static int if_ioctl(struct tty_struct *tty,
static int if_tiocmget(struct tty_struct *tty) static int if_tiocmget(struct tty_struct *tty)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
int retval; int retval;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return -ENODEV;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
@ -309,16 +283,10 @@ static int if_tiocmget(struct tty_struct *tty)
static int if_tiocmset(struct tty_struct *tty, static int if_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear) unsigned int set, unsigned int clear)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
int retval; int retval;
unsigned mc; unsigned mc;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return -ENODEV;
}
gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
cs->minor_index, __func__, set, clear); cs->minor_index, __func__, set, clear);
@ -341,16 +309,10 @@ static int if_tiocmset(struct tty_struct *tty,
static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
struct cmdbuf_t *cb; struct cmdbuf_t *cb;
int retval; int retval;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return -ENODEV;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
@ -361,11 +323,6 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
retval = -ENODEV; retval = -ENODEV;
goto done; goto done;
} }
if (!cs->open_count) {
dev_warn(cs->dev, "%s: device not opened\n", __func__);
retval = -ENODEV;
goto done;
}
if (cs->mstate != MS_LOCKED) { if (cs->mstate != MS_LOCKED) {
dev_warn(cs->dev, "can't write to unlocked device\n"); dev_warn(cs->dev, "can't write to unlocked device\n");
retval = -EBUSY; retval = -EBUSY;
@ -397,15 +354,9 @@ done:
static int if_write_room(struct tty_struct *tty) static int if_write_room(struct tty_struct *tty)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
int retval = -ENODEV; int retval = -ENODEV;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return -ENODEV;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
if (mutex_lock_interruptible(&cs->mutex)) if (mutex_lock_interruptible(&cs->mutex))
@ -414,9 +365,7 @@ static int if_write_room(struct tty_struct *tty)
if (!cs->connected) { if (!cs->connected) {
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
retval = -ENODEV; retval = -ENODEV;
} else if (!cs->open_count) } else if (cs->mstate != MS_LOCKED) {
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else if (cs->mstate != MS_LOCKED) {
dev_warn(cs->dev, "can't write to unlocked device\n"); dev_warn(cs->dev, "can't write to unlocked device\n");
retval = -EBUSY; retval = -EBUSY;
} else } else
@ -429,23 +378,15 @@ static int if_write_room(struct tty_struct *tty)
static int if_chars_in_buffer(struct tty_struct *tty) static int if_chars_in_buffer(struct tty_struct *tty)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
int retval = 0; int retval = 0;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return 0;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex); mutex_lock(&cs->mutex);
if (!cs->connected) if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); gig_dbg(DEBUG_IF, "not connected");
else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else if (cs->mstate != MS_LOCKED) else if (cs->mstate != MS_LOCKED)
dev_warn(cs->dev, "can't write to unlocked device\n"); dev_warn(cs->dev, "can't write to unlocked device\n");
else else
@ -458,13 +399,7 @@ static int if_chars_in_buffer(struct tty_struct *tty)
static void if_throttle(struct tty_struct *tty) static void if_throttle(struct tty_struct *tty)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
@ -472,8 +407,6 @@ static void if_throttle(struct tty_struct *tty)
if (!cs->connected) if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else else
gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
@ -482,13 +415,7 @@ static void if_throttle(struct tty_struct *tty)
static void if_unthrottle(struct tty_struct *tty) static void if_unthrottle(struct tty_struct *tty)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
@ -496,8 +423,6 @@ static void if_unthrottle(struct tty_struct *tty)
if (!cs->connected) if (!cs->connected)
gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */
else if (!cs->open_count)
dev_warn(cs->dev, "%s: device not opened\n", __func__);
else else
gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
@ -506,18 +431,12 @@ static void if_unthrottle(struct tty_struct *tty)
static void if_set_termios(struct tty_struct *tty, struct ktermios *old) static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
{ {
struct cardstate *cs; struct cardstate *cs = tty->driver_data;
unsigned int iflag; unsigned int iflag;
unsigned int cflag; unsigned int cflag;
unsigned int old_cflag; unsigned int old_cflag;
unsigned int control_state, new_state; unsigned int control_state, new_state;
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
pr_err("%s: no cardstate\n", __func__);
return;
}
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
mutex_lock(&cs->mutex); mutex_lock(&cs->mutex);
@ -527,11 +446,6 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
goto out; goto out;
} }
if (!cs->open_count) {
dev_warn(cs->dev, "%s: device not opened\n", __func__);
goto out;
}
iflag = tty->termios->c_iflag; iflag = tty->termios->c_iflag;
cflag = tty->termios->c_cflag; cflag = tty->termios->c_cflag;
old_cflag = old ? old->c_cflag : cflag; old_cflag = old ? old->c_cflag : cflag;
@ -588,10 +502,13 @@ out:
/* wakeup tasklet for the write operation */ /* wakeup tasklet for the write operation */
static void if_wake(unsigned long data) static void if_wake(unsigned long data)
{ {
struct cardstate *cs = (struct cardstate *) data; struct cardstate *cs = (struct cardstate *)data;
struct tty_struct *tty = tty_port_tty_get(&cs->port);
if (cs->tty) if (tty) {
tty_wakeup(cs->tty); tty_wakeup(tty);
tty_kref_put(tty);
}
} }
/*** interface to common ***/ /*** interface to common ***/
@ -644,18 +561,16 @@ void gigaset_if_free(struct cardstate *cs)
void gigaset_if_receive(struct cardstate *cs, void gigaset_if_receive(struct cardstate *cs,
unsigned char *buffer, size_t len) unsigned char *buffer, size_t len)
{ {
unsigned long flags; struct tty_struct *tty = tty_port_tty_get(&cs->port);
struct tty_struct *tty;
spin_lock_irqsave(&cs->lock, flags); if (tty == NULL) {
tty = cs->tty;
if (tty == NULL)
gig_dbg(DEBUG_IF, "receive on closed device"); gig_dbg(DEBUG_IF, "receive on closed device");
else { return;
tty_insert_flip_string(tty, buffer, len);
tty_flip_buffer_push(tty);
} }
spin_unlock_irqrestore(&cs->lock, flags);
tty_insert_flip_string(tty, buffer, len);
tty_flip_buffer_push(tty);
tty_kref_put(tty);
} }
EXPORT_SYMBOL_GPL(gigaset_if_receive); EXPORT_SYMBOL_GPL(gigaset_if_receive);
@ -669,17 +584,15 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive);
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
const char *devname) const char *devname)
{ {
unsigned minors = drv->minors;
int ret; int ret;
struct tty_driver *tty; struct tty_driver *tty;
drv->have_tty = 0; drv->have_tty = 0;
drv->tty = tty = alloc_tty_driver(minors); drv->tty = tty = alloc_tty_driver(drv->minors);
if (tty == NULL) if (tty == NULL)
goto enomem; goto enomem;
tty->magic = TTY_DRIVER_MAGIC,
tty->type = TTY_DRIVER_TYPE_SERIAL, tty->type = TTY_DRIVER_TYPE_SERIAL,
tty->subtype = SERIAL_TYPE_NORMAL, tty->subtype = SERIAL_TYPE_NORMAL,
tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
@ -687,9 +600,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
tty->driver_name = procname; tty->driver_name = procname;
tty->name = devname; tty->name = devname;
tty->minor_start = drv->minor; tty->minor_start = drv->minor;
tty->num = drv->minors;
tty->owner = THIS_MODULE;
tty->init_termios = tty_std_termios; tty->init_termios = tty_std_termios;
tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;

View File

@ -1590,12 +1590,9 @@ static int
isdn_tty_open(struct tty_struct *tty, struct file *filp) isdn_tty_open(struct tty_struct *tty, struct file *filp)
{ {
modem_info *info; modem_info *info;
int retval, line; int retval;
line = tty->index; info = &dev->mdm.info[tty->index];
if (line < 0 || line >= ISDN_MAX_CHANNELS)
return -ENODEV;
info = &dev->mdm.info[line];
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
return -ENODEV; return -ENODEV;
if (!try_module_get(info->owner)) { if (!try_module_get(info->owner)) {

View File

@ -481,13 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
int idx = tty->index; int idx = tty->index;
struct pti_tty *pti_tty_data; struct pti_tty *pti_tty_data;
int ret = tty_init_termios(tty); int ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0) {
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[idx] = tty;
pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL); pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
if (pti_tty_data == NULL) if (pti_tty_data == NULL)
return -ENOMEM; return -ENOMEM;
@ -911,21 +907,17 @@ static int __init pti_init(void)
/* First register module as tty device */ /* First register module as tty device */
pti_tty_driver = alloc_tty_driver(1); pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM);
if (pti_tty_driver == NULL) { if (pti_tty_driver == NULL) {
pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n", pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n",
__func__, __LINE__); __func__, __LINE__);
return -ENOMEM; return -ENOMEM;
} }
pti_tty_driver->owner = THIS_MODULE;
pti_tty_driver->magic = TTY_DRIVER_MAGIC;
pti_tty_driver->driver_name = DRIVERNAME; pti_tty_driver->driver_name = DRIVERNAME;
pti_tty_driver->name = TTYNAME; pti_tty_driver->name = TTYNAME;
pti_tty_driver->major = 0; pti_tty_driver->major = 0;
pti_tty_driver->minor_start = PTITTY_MINOR_START; pti_tty_driver->minor_start = PTITTY_MINOR_START;
pti_tty_driver->minor_num = PTITTY_MINOR_NUM;
pti_tty_driver->num = PTITTY_MINOR_NUM;
pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS; pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS;
pti_tty_driver->flags = TTY_DRIVER_REAL_RAW | pti_tty_driver->flags = TTY_DRIVER_REAL_RAW |

View File

@ -750,15 +750,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
{ {
int idx = tty->index; int idx = tty->index;
struct sdio_uart_port *port = sdio_uart_port_get(idx); struct sdio_uart_port *port = sdio_uart_port_get(idx);
int ret = tty_init_termios(tty); int ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0)
tty_driver_kref_get(driver);
tty->count++;
/* This is the ref sdio_uart_port get provided */ /* This is the ref sdio_uart_port get provided */
tty->driver_data = port; tty->driver_data = port;
driver->ttys[idx] = tty; else
} else
sdio_uart_port_put(port); sdio_uart_port_put(port);
return ret; return ret;
} }
@ -1178,7 +1175,6 @@ static int __init sdio_uart_init(void)
if (!tty_drv) if (!tty_drv)
return -ENOMEM; return -ENOMEM;
tty_drv->owner = THIS_MODULE;
tty_drv->driver_name = "sdio_uart"; tty_drv->driver_name = "sdio_uart";
tty_drv->name = "ttySDIO"; tty_drv->name = "ttySDIO";
tty_drv->major = 0; /* dynamically allocated */ tty_drv->major = 0; /* dynamically allocated */

View File

@ -3313,7 +3313,6 @@ static int __init hso_init(void)
/* fill in all needed values */ /* fill in all needed values */
tty_drv->magic = TTY_DRIVER_MAGIC; tty_drv->magic = TTY_DRIVER_MAGIC;
tty_drv->owner = THIS_MODULE;
tty_drv->driver_name = driver_name; tty_drv->driver_name = driver_name;
tty_drv->name = tty_filename; tty_drv->name = tty_filename;
@ -3322,7 +3321,6 @@ static int __init hso_init(void)
tty_drv->major = tty_major; tty_drv->major = tty_major;
tty_drv->minor_start = 0; tty_drv->minor_start = 0;
tty_drv->num = HSO_SERIAL_TTY_MINORS;
tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->subtype = SERIAL_TYPE_NORMAL;
tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;

View File

@ -299,7 +299,6 @@ void cpc_tty_init(pc300dev_t * dev);
void cpc_tty_unregister_service(pc300dev_t * pc300dev); void cpc_tty_unregister_service(pc300dev_t * pc300dev);
void cpc_tty_receive(pc300dev_t * pc300dev); void cpc_tty_receive(pc300dev_t * pc300dev);
void cpc_tty_trigger_poll(pc300dev_t * pc300dev); void cpc_tty_trigger_poll(pc300dev_t * pc300dev);
void cpc_tty_reset_var(void);
#endif #endif
/************************/ /************************/
@ -3232,7 +3231,7 @@ static void plx_init(pc300_t * card)
} }
static inline void show_version(void) static void show_version(void)
{ {
char *rcsvers, *rcsdate, *tmp; char *rcsvers, *rcsdate, *tmp;
@ -3413,19 +3412,10 @@ static void cpc_init_card(pc300_t * card)
static int __devinit static int __devinit
cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
static int first_time = 1;
int err, eeprom_outdated = 0; int err, eeprom_outdated = 0;
u16 device_id; u16 device_id;
pc300_t *card; pc300_t *card;
if (first_time) {
first_time = 0;
show_version();
#ifdef CONFIG_PC300_MLPPP
cpc_tty_reset_var();
#endif
}
if ((err = pci_enable_device(pdev)) < 0) if ((err = pci_enable_device(pdev)) < 0)
return err; return err;
@ -3661,6 +3651,7 @@ static struct pci_driver cpc_driver = {
static int __init cpc_init(void) static int __init cpc_init(void)
{ {
show_version();
return pci_register_driver(&cpc_driver); return pci_register_driver(&cpc_driver);
} }

View File

@ -139,7 +139,6 @@ void cpc_tty_init(pc300dev_t *dev);
void cpc_tty_unregister_service(pc300dev_t *pc300dev); void cpc_tty_unregister_service(pc300dev_t *pc300dev);
void cpc_tty_receive(pc300dev_t *pc300dev); void cpc_tty_receive(pc300dev_t *pc300dev);
void cpc_tty_trigger_poll(pc300dev_t *pc300dev); void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
void cpc_tty_reset_var(void);
/* /*
* PC300 TTY clear "signal" * PC300 TTY clear "signal"
@ -1078,20 +1077,3 @@ void cpc_tty_trigger_poll(pc300dev_t *pc300dev)
} }
schedule_work(&(cpc_tty->tty_tx_work)); schedule_work(&(cpc_tty->tty_tx_work));
} }
/*
* PC300 TTY reset var routine
* This routine is called by pc300driver to init the TTY area.
*/
void cpc_tty_reset_var(void)
{
int i ;
CPC_TTY_DBG("hdlcX-tty: reset variables\n");
/* reset the tty_driver structure - serial_drv */
memset(&serial_drv, 0, sizeof(struct tty_driver));
for (i=0; i < CPC_TTY_NPORTS; i++){
memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area));
}
}

View File

@ -933,13 +933,9 @@ console_initcall(con3215_init);
static int tty3215_open(struct tty_struct *tty, struct file * filp) static int tty3215_open(struct tty_struct *tty, struct file * filp)
{ {
struct raw3215_info *raw; struct raw3215_info *raw;
int retval, line; int retval;
line = tty->index; raw = raw3215[tty->index];
if ((line < 0) || (line >= NR_3215))
return -ENODEV;
raw = raw3215[line];
if (raw == NULL) if (raw == NULL)
return -ENODEV; return -ENODEV;
@ -1145,7 +1141,6 @@ static int __init tty3215_init(void)
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
*/ */
driver->owner = THIS_MODULE;
driver->driver_name = "tty3215"; driver->driver_name = "tty3215";
driver->name = "ttyS"; driver->name = "ttyS";
driver->major = TTY_MAJOR; driver->major = TTY_MAJOR;

View File

@ -551,7 +551,6 @@ sclp_tty_init(void)
return rc; return rc;
} }
driver->owner = THIS_MODULE;
driver->driver_name = "sclp_line"; driver->driver_name = "sclp_line";
driver->name = "sclp_line"; driver->name = "sclp_line";
driver->major = TTY_MAJOR; driver->major = TTY_MAJOR;

View File

@ -685,7 +685,6 @@ static int __init sclp_vt220_tty_init(void)
if (rc) if (rc)
goto out_driver; goto out_driver;
driver->owner = THIS_MODULE;
driver->driver_name = SCLP_VT220_DRIVER_NAME; driver->driver_name = SCLP_VT220_DRIVER_NAME;
driver->name = SCLP_VT220_DEVICE_NAME; driver->name = SCLP_VT220_DEVICE_NAME;
driver->major = SCLP_VT220_MAJOR; driver->major = SCLP_VT220_MAJOR;

View File

@ -1784,7 +1784,6 @@ static int __init tty3270_init(void)
* Entries in tty3270_driver that are NOT initialized: * Entries in tty3270_driver that are NOT initialized:
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
*/ */
driver->owner = THIS_MODULE;
driver->driver_name = "ttyTUB"; driver->driver_name = "ttyTUB";
driver->name = "ttyTUB"; driver->name = "ttyTUB";
driver->major = IBM_TTY3270_MAJOR; driver->major = IBM_TTY3270_MAJOR;

View File

@ -1731,15 +1731,15 @@ static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
switch (value) { switch (value) {
case KVAL(K_CAPS): case KVAL(K_CAPS):
label = msg_get(MSG_KEYNAME_CAPSLOCK); label = msg_get(MSG_KEYNAME_CAPSLOCK);
on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK)); on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
break; break;
case KVAL(K_NUM): case KVAL(K_NUM):
label = msg_get(MSG_KEYNAME_NUMLOCK); label = msg_get(MSG_KEYNAME_NUMLOCK);
on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK)); on_off = vt_get_leds(fg_console, VC_NUMLOCK);
break; break;
case KVAL(K_HOLD): case KVAL(K_HOLD):
label = msg_get(MSG_KEYNAME_SCROLLLOCK); label = msg_get(MSG_KEYNAME_SCROLLLOCK);
on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK)); on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
if (speakup_console[vc->vc_num]) if (speakup_console[vc->vc_num])
speakup_console[vc->vc_num]->tty_stopped = on_off; speakup_console[vc->vc_num]->tty_stopped = on_off;
break; break;
@ -2020,7 +2020,7 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
if (type >= 0xf0) if (type >= 0xf0)
type -= 0xf0; type -= 0xf0;
if (type == KT_PAD if (type == KT_PAD
&& (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) { && (vt_get_leds(fg_console, VC_NUMLOCK))) {
if (up_flag) { if (up_flag) {
spk_keydown = 0; spk_keydown = 0;
goto out; goto out;

View File

@ -8,21 +8,20 @@
static void start_serial_interrupt(int irq); static void start_serial_interrupt(int irq);
static struct serial_state rs_table[] = { static const struct old_serial_port rs_table[] = {
SERIAL_PORT_DFNS SERIAL_PORT_DFNS
}; };
static struct serial_state *serstate; static const struct old_serial_port *serstate;
static int timeouts; static int timeouts;
struct serial_state *spk_serial_init(int index) const struct old_serial_port *spk_serial_init(int index)
{ {
int baud = 9600, quot = 0; int baud = 9600, quot = 0;
unsigned int cval = 0; unsigned int cval = 0;
int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
struct serial_state *ser = NULL; const struct old_serial_port *ser = rs_table + index;
int err; int err;
ser = rs_table + index;
/* Divisor, bytesize and parity */ /* Divisor, bytesize and parity */
quot = ser->baud_base / baud; quot = ser->baud_base / baud;
cval = cflag & (CSIZE | CSTOPB); cval = cflag & (CSIZE | CSTOPB);
@ -41,7 +40,7 @@ struct serial_state *spk_serial_init(int index)
__release_region(&ioport_resource, ser->port, 8); __release_region(&ioport_resource, ser->port, 8);
err = synth_request_region(ser->port, 8); err = synth_request_region(ser->port, 8);
if (err) { if (err) {
pr_warn("Unable to allocate port at %lx, errno %i", pr_warn("Unable to allocate port at %x, errno %i",
ser->port, err); ser->port, err);
return NULL; return NULL;
} }

View File

@ -4,11 +4,22 @@
#include <linux/serial.h> /* for rs_table, serial constants & #include <linux/serial.h> /* for rs_table, serial constants &
serial_uart_config */ serial_uart_config */
#include <linux/serial_reg.h> /* for more serial constants */ #include <linux/serial_reg.h> /* for more serial constants */
#include <linux/serialP.h> /* for struct serial_state */
#ifndef __sparc__ #ifndef __sparc__
#include <asm/serial.h> #include <asm/serial.h>
#endif #endif
/*
* this is cut&paste from 8250.h. Get rid of the structure, the definitions
* and this whole broken driver.
*/
struct old_serial_port {
unsigned int uart; /* unused */
unsigned int baud_base;
unsigned int port;
unsigned int irq;
unsigned int flags; /* unused */
};
/* countdown values for serial timeouts in us */ /* countdown values for serial timeouts in us */
#define SPK_SERIAL_TIMEOUT 100000 #define SPK_SERIAL_TIMEOUT 100000
/* countdown values transmitter/dsr timeouts in us */ /* countdown values transmitter/dsr timeouts in us */

View File

@ -44,7 +44,7 @@
#define KT_SPKUP 15 #define KT_SPKUP 15
extern struct serial_state *spk_serial_init(int index); extern const struct old_serial_port *spk_serial_init(int index);
extern void stop_serial_interrupt(void); extern void stop_serial_interrupt(void);
extern int wait_for_xmitr(void); extern int wait_for_xmitr(void);
extern unsigned char spk_serial_in(void); extern unsigned char spk_serial_in(void);

View File

@ -34,7 +34,7 @@ static int do_synth_init(struct spk_synth *in_synth);
int serial_synth_probe(struct spk_synth *synth) int serial_synth_probe(struct spk_synth *synth)
{ {
struct serial_state *ser; const struct old_serial_port *ser;
int failed = 0; int failed = 0;
if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) { if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {

File diff suppressed because it is too large Load Diff

View File

@ -257,7 +257,6 @@ static int __init bfin_jc_init(void)
if (!bfin_jc_driver) if (!bfin_jc_driver)
goto err_driver; goto err_driver;
bfin_jc_driver->owner = THIS_MODULE;
bfin_jc_driver->driver_name = DRV_NAME; bfin_jc_driver->driver_name = DRV_NAME;
bfin_jc_driver->name = DEV_NAME; bfin_jc_driver->name = DEV_NAME;
bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL; bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL;

View File

@ -1515,13 +1515,9 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
static int cy_open(struct tty_struct *tty, struct file *filp) static int cy_open(struct tty_struct *tty, struct file *filp)
{ {
struct cyclades_port *info; struct cyclades_port *info;
unsigned int i, line; unsigned int i, line = tty->index;
int retval; int retval;
line = tty->index;
if (tty->index < 0 || NR_PORTS <= line)
return -ENODEV;
for (i = 0; i < NR_CARDS; i++) for (i = 0; i < NR_CARDS; i++)
if (line < cy_card[i].first_line + cy_card[i].nports && if (line < cy_card[i].first_line + cy_card[i].nports &&
line >= cy_card[i].first_line) line >= cy_card[i].first_line)
@ -2413,7 +2409,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
/* Not supported yet */ /* Not supported yet */
return -EINVAL; return -EINVAL;
} }
return put_user(result, (unsigned long __user *)value); return put_user(result, value);
} }
static int cy_tiocmget(struct tty_struct *tty) static int cy_tiocmget(struct tty_struct *tty)
@ -4090,7 +4086,6 @@ static int __init cy_init(void)
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
cy_serial_driver->owner = THIS_MODULE;
cy_serial_driver->driver_name = "cyclades"; cy_serial_driver->driver_name = "cyclades";
cy_serial_driver->name = "ttyC"; cy_serial_driver->name = "ttyC";
cy_serial_driver->major = CYCLADES_MAJOR; cy_serial_driver->major = CYCLADES_MAJOR;

View File

@ -825,7 +825,6 @@ static int __init ehv_bc_init(void)
goto error; goto error;
} }
ehv_bc_driver->owner = THIS_MODULE;
ehv_bc_driver->driver_name = "ehv-bc"; ehv_bc_driver->driver_name = "ehv-bc";
ehv_bc_driver->name = ehv_bc_console.name; ehv_bc_driver->name = ehv_bc_console.name;
ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE; ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;

View File

@ -113,7 +113,7 @@ static int __init hvc_beat_init(void)
if (!firmware_has_feature(FW_FEATURE_BEAT)) if (!firmware_has_feature(FW_FEATURE_BEAT))
return -ENODEV; return -ENODEV;
hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16); hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
if (IS_ERR(hp)) if (IS_ERR(hp))
return PTR_ERR(hp); return PTR_ERR(hp);
hvc_beat_dev = hp; hvc_beat_dev = hp;

View File

@ -917,7 +917,6 @@ static int hvc_init(void)
goto out; goto out;
} }
drv->owner = THIS_MODULE;
drv->driver_name = "hvc"; drv->driver_name = "hvc";
drv->name = "hvc"; drv->name = "hvc";
drv->major = HVC_MAJOR; drv->major = HVC_MAJOR;

View File

@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void)
/* Allocate an hvc_struct for the console device we instantiated /* Allocate an hvc_struct for the console device we instantiated
* earlier. Save off hp so that we can return it on exit */ * earlier. Save off hp so that we can return it on exit */
hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16); hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
if (IS_ERR(hp)) if (IS_ERR(hp))
return PTR_ERR(hp); return PTR_ERR(hp);

View File

@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void)
BUG_ON(hvc_udbg_dev); BUG_ON(hvc_udbg_dev);
hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
if (IS_ERR(hp)) if (IS_ERR(hp))
return PTR_ERR(hp); return PTR_ERR(hp);

View File

@ -176,7 +176,7 @@ static int __init xen_hvc_init(void)
xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
} }
if (xencons_irq < 0) if (xencons_irq < 0)
xencons_irq = 0; /* NO_IRQ */ xencons_irq = 0;
else else
irq_set_noprobe(xencons_irq); irq_set_noprobe(xencons_irq);

View File

@ -1090,27 +1090,23 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
*/ */
static struct hvcs_struct *hvcs_get_by_index(int index) static struct hvcs_struct *hvcs_get_by_index(int index)
{ {
struct hvcs_struct *hvcsd = NULL; struct hvcs_struct *hvcsd;
unsigned long flags; unsigned long flags;
spin_lock(&hvcs_structs_lock); spin_lock(&hvcs_structs_lock);
/* We can immediately discard OOB requests */ list_for_each_entry(hvcsd, &hvcs_structs, next) {
if (index >= 0 && index < HVCS_MAX_SERVER_ADAPTERS) { spin_lock_irqsave(&hvcsd->lock, flags);
list_for_each_entry(hvcsd, &hvcs_structs, next) { if (hvcsd->index == index) {
spin_lock_irqsave(&hvcsd->lock, flags); kref_get(&hvcsd->kref);
if (hvcsd->index == index) {
kref_get(&hvcsd->kref);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
return hvcsd;
}
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
return hvcsd;
} }
hvcsd = NULL; spin_unlock_irqrestore(&hvcsd->lock, flags);
} }
spin_unlock(&hvcs_structs_lock); spin_unlock(&hvcs_structs_lock);
return hvcsd;
return NULL;
} }
/* /*
@ -1203,7 +1199,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
{ {
struct hvcs_struct *hvcsd; struct hvcs_struct *hvcsd;
unsigned long flags; unsigned long flags;
int irq = NO_IRQ; int irq;
/* /*
* Is someone trying to close the file associated with this device after * Is someone trying to close the file associated with this device after
@ -1264,7 +1260,7 @@ static void hvcs_hangup(struct tty_struct * tty)
struct hvcs_struct *hvcsd = tty->driver_data; struct hvcs_struct *hvcsd = tty->driver_data;
unsigned long flags; unsigned long flags;
int temp_open_count; int temp_open_count;
int irq = NO_IRQ; int irq;
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */ /* Preserve this so that we know how many kref refs to put */
@ -1499,8 +1495,6 @@ static int __devinit hvcs_initialize(void)
goto index_fail; goto index_fail;
} }
hvcs_tty_driver->owner = THIS_MODULE;
hvcs_tty_driver->driver_name = hvcs_driver_name; hvcs_tty_driver->driver_name = hvcs_driver_name;
hvcs_tty_driver->name = hvcs_device_node; hvcs_tty_driver->name = hvcs_device_node;

View File

@ -737,14 +737,11 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
{ {
struct hvsi_struct *hp; struct hvsi_struct *hp;
unsigned long flags; unsigned long flags;
int line = tty->index;
int ret; int ret;
pr_debug("%s\n", __func__); pr_debug("%s\n", __func__);
if (line < 0 || line >= hvsi_count) hp = &hvsi_ports[tty->index];
return -ENODEV;
hp = &hvsi_ports[line];
tty->driver_data = hp; tty->driver_data = hp;
@ -1088,7 +1085,6 @@ static int __init hvsi_init(void)
if (!hvsi_driver) if (!hvsi_driver)
return -ENOMEM; return -ENOMEM;
hvsi_driver->owner = THIS_MODULE;
hvsi_driver->driver_name = "hvsi"; hvsi_driver->driver_name = "hvsi";
hvsi_driver->name = "hvsi"; hvsi_driver->name = "hvsi";
hvsi_driver->major = HVSI_MAJOR; hvsi_driver->major = HVSI_MAJOR;
@ -1237,7 +1233,7 @@ static int __init hvsi_console_init(void)
hp->state = HVSI_CLOSED; hp->state = HVSI_CLOSED;
hp->vtermno = *vtermno; hp->vtermno = *vtermno;
hp->virq = irq_create_mapping(NULL, irq[0]); hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) { if (hp->virq == 0) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
__func__, irq[0]); __func__, irq[0]);
continue; continue;

View File

@ -90,33 +90,23 @@ static void report_deregistering(struct ipw_tty *tty)
tty->index); tty->index);
} }
static struct ipw_tty *get_tty(int minor) static struct ipw_tty *get_tty(int index)
{ {
if (minor < ipw_tty_driver->minor_start /*
|| minor >= ipw_tty_driver->minor_start + * The 'ras_raw' channel is only available when 'loopback' mode
IPWIRELESS_PCMCIA_MINORS) * is enabled.
* Number of minor starts with 16 (_RANGE * _RAS_RAW).
*/
if (!ipwireless_loopback && index >=
IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
return NULL; return NULL;
else {
int minor_offset = minor - ipw_tty_driver->minor_start;
/* return ttys[index];
* The 'ras_raw' channel is only available when 'loopback' mode
* is enabled.
* Number of minor starts with 16 (_RANGE * _RAS_RAW).
*/
if (!ipwireless_loopback &&
minor_offset >=
IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
return NULL;
return ttys[minor_offset];
}
} }
static int ipw_open(struct tty_struct *linux_tty, struct file *filp) static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
{ {
int minor = linux_tty->index; struct ipw_tty *tty = get_tty(linux_tty->index);
struct ipw_tty *tty = get_tty(minor);
if (!tty) if (!tty)
return -ENODEV; return -ENODEV;
@ -510,7 +500,7 @@ static int add_tty(int j,
ipwireless_associate_network_tty(network, ipwireless_associate_network_tty(network,
secondary_channel_idx, secondary_channel_idx,
ttys[j]); ttys[j]);
if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) if (get_tty(j) == ttys[j])
report_registering(ttys[j]); report_registering(ttys[j]);
return 0; return 0;
} }
@ -570,7 +560,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)
if (ttyj) { if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex); mutex_lock(&ttyj->ipw_tty_mutex);
if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) if (get_tty(j) == ttyj)
report_deregistering(ttyj); report_deregistering(ttyj);
ttyj->closing = 1; ttyj->closing = 1;
if (ttyj->linux_tty != NULL) { if (ttyj->linux_tty != NULL) {
@ -614,7 +604,6 @@ int ipwireless_tty_init(void)
if (!ipw_tty_driver) if (!ipw_tty_driver)
return -ENOMEM; return -ENOMEM;
ipw_tty_driver->owner = THIS_MODULE;
ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
ipw_tty_driver->name = "ttyIPWp"; ipw_tty_driver->name = "ttyIPWp";
ipw_tty_driver->major = 0; ipw_tty_driver->major = 0;

View File

@ -849,8 +849,6 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty)
unsigned int board; unsigned int board;
int line = tty->index; int line = tty->index;
if (line < 0 || line > PORT_COUNT-1)
return NULL;
board = BOARD(line); board = BOARD(line);
card = &isi_card[board]; card = &isi_card[board];
@ -1678,7 +1676,6 @@ static int __init isicom_init(void)
goto error; goto error;
} }
isicom_normal->owner = THIS_MODULE;
isicom_normal->name = "ttyM"; isicom_normal->name = "ttyM";
isicom_normal->major = ISICOM_NMAJOR; isicom_normal->major = ISICOM_NMAJOR;
isicom_normal->minor_start = 0; isicom_normal->minor_start = 0;

View File

@ -1036,7 +1036,6 @@ static int __init moxa_init(void)
if (!moxaDriver) if (!moxaDriver)
return -ENOMEM; return -ENOMEM;
moxaDriver->owner = THIS_MODULE;
moxaDriver->name = "ttyMX"; moxaDriver->name = "ttyMX";
moxaDriver->major = ttymajor; moxaDriver->major = ttymajor;
moxaDriver->minor_start = 0; moxaDriver->minor_start = 0;
@ -1331,7 +1330,7 @@ static void moxa_start(struct tty_struct *tty)
if (ch == NULL) if (ch == NULL)
return; return;
if (!(ch->statusflags & TXSTOPPED)) if (!test_bit(TXSTOPPED, &ch->statusflags))
return; return;
MoxaPortTxEnable(ch); MoxaPortTxEnable(ch);

View File

@ -1010,8 +1010,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
line = tty->index; line = tty->index;
if (line == MXSER_PORTS) if (line == MXSER_PORTS)
return 0; return 0;
if (line < 0 || line > MXSER_PORTS)
return -ENODEV;
info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD]; info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
if (!info->ioaddr) if (!info->ioaddr)
return -ENODEV; return -ENODEV;
@ -2658,12 +2656,9 @@ static int __init mxser_module_init(void)
MXSER_VERSION); MXSER_VERSION);
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
mxvar_sdriver->owner = THIS_MODULE;
mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->name = "ttyMI";
mxvar_sdriver->major = ttymajor; mxvar_sdriver->major = ttymajor;
mxvar_sdriver->minor_start = 0; mxvar_sdriver->minor_start = 0;
mxvar_sdriver->num = MXSER_PORTS + 1;
mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios; mxvar_sdriver->init_termios = tty_std_termios;

View File

@ -3120,7 +3120,6 @@ static int __init gsm_init(void)
pr_err("gsm_init: tty allocation failed.\n"); pr_err("gsm_init: tty allocation failed.\n");
return -EINVAL; return -EINVAL;
} }
gsm_tty_driver->owner = THIS_MODULE;
gsm_tty_driver->driver_name = "gsmtty"; gsm_tty_driver->driver_name = "gsmtty";
gsm_tty_driver->name = "gsmtty"; gsm_tty_driver->name = "gsmtty";
gsm_tty_driver->major = 0; /* Dynamic */ gsm_tty_driver->major = 0; /* Dynamic */

View File

@ -1602,13 +1602,9 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
int ret; int ret;
if (!port || !dc || dc->state != NOZOMI_STATE_READY) if (!port || !dc || dc->state != NOZOMI_STATE_READY)
return -ENODEV; return -ENODEV;
ret = tty_init_termios(tty); ret = tty_standard_install(driver, tty);
if (ret == 0) { if (ret == 0)
tty_driver_kref_get(driver);
tty->count++;
tty->driver_data = port; tty->driver_data = port;
driver->ttys[tty->index] = tty;
}
return ret; return ret;
} }
@ -1920,7 +1916,6 @@ static __init int nozomi_init(void)
if (!ntty_driver) if (!ntty_driver)
return -ENOMEM; return -ENOMEM;
ntty_driver->owner = THIS_MODULE;
ntty_driver->driver_name = NOZOMI_NAME_TTY; ntty_driver->driver_name = NOZOMI_NAME_TTY;
ntty_driver->name = "noz"; ntty_driver->name = "noz";
ntty_driver->major = 0; ntty_driver->major = 0;

View File

@ -21,7 +21,6 @@
#include <linux/major.h> #include <linux/major.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sysctl.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/bitops.h> #include <linux/bitops.h>
@ -394,7 +393,6 @@ static void __init legacy_pty_init(void)
if (!pty_slave_driver) if (!pty_slave_driver)
panic("Couldn't allocate pty slave driver"); panic("Couldn't allocate pty slave driver");
pty_driver->owner = THIS_MODULE;
pty_driver->driver_name = "pty_master"; pty_driver->driver_name = "pty_master";
pty_driver->name = "pty"; pty_driver->name = "pty";
pty_driver->major = PTY_MASTER_MAJOR; pty_driver->major = PTY_MASTER_MAJOR;
@ -412,7 +410,6 @@ static void __init legacy_pty_init(void)
pty_driver->other = pty_slave_driver; pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &master_pty_ops_bsd); tty_set_operations(pty_driver, &master_pty_ops_bsd);
pty_slave_driver->owner = THIS_MODULE;
pty_slave_driver->driver_name = "pty_slave"; pty_slave_driver->driver_name = "pty_slave";
pty_slave_driver->name = "ttyp"; pty_slave_driver->name = "ttyp";
pty_slave_driver->major = PTY_SLAVE_MAJOR; pty_slave_driver->major = PTY_SLAVE_MAJOR;
@ -439,55 +436,9 @@ static inline void legacy_pty_init(void) { }
/* Unix98 devices */ /* Unix98 devices */
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
/*
* sysctl support for setting limits on the number of Unix98 ptys allocated.
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
*/
int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
static int pty_count;
static struct cdev ptmx_cdev; static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = {
{
.procname = "max",
.maxlen = sizeof(int),
.mode = 0644,
.data = &pty_limit,
.proc_handler = proc_dointvec_minmax,
.extra1 = &pty_limit_min,
.extra2 = &pty_limit_max,
}, {
.procname = "nr",
.maxlen = sizeof(int),
.mode = 0444,
.data = &pty_count,
.proc_handler = proc_dointvec,
},
{}
};
static struct ctl_table pty_kern_table[] = {
{
.procname = "pty",
.mode = 0555,
.child = pty_table,
},
{}
};
static struct ctl_table pty_root_table[] = {
{
.procname = "kernel",
.mode = 0555,
.child = pty_kern_table,
},
{}
};
static int pty_unix98_ioctl(struct tty_struct *tty, static int pty_unix98_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
@ -515,10 +466,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
struct inode *ptm_inode, int idx) struct inode *ptm_inode, int idx)
{ {
struct tty_struct *tty = devpts_get_tty(ptm_inode, idx); /* Master must be open via /dev/ptmx */
if (tty) return ERR_PTR(-EIO);
tty = tty->link;
return tty;
} }
/** /**
@ -589,7 +538,6 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
*/ */
tty_driver_kref_get(driver); tty_driver_kref_get(driver);
tty->count++; tty->count++;
pty_count++;
return 0; return 0;
err_free_mem: err_free_mem:
deinitialize_tty_struct(o_tty); deinitialize_tty_struct(o_tty);
@ -603,7 +551,6 @@ err_free_tty:
static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{ {
pty_count--;
} }
static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
@ -677,7 +624,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
tty_lock(); tty_lock();
tty = tty_init_dev(ptm_driver, index, 1); tty = tty_init_dev(ptm_driver, index);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
@ -722,7 +669,6 @@ static void __init unix98_pty_init(void)
if (!pts_driver) if (!pts_driver)
panic("Couldn't allocate Unix98 pts driver"); panic("Couldn't allocate Unix98 pts driver");
ptm_driver->owner = THIS_MODULE;
ptm_driver->driver_name = "pty_master"; ptm_driver->driver_name = "pty_master";
ptm_driver->name = "ptm"; ptm_driver->name = "ptm";
ptm_driver->major = UNIX98_PTY_MASTER_MAJOR; ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
@ -741,7 +687,6 @@ static void __init unix98_pty_init(void)
ptm_driver->other = pts_driver; ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &ptm_unix98_ops); tty_set_operations(ptm_driver, &ptm_unix98_ops);
pts_driver->owner = THIS_MODULE;
pts_driver->driver_name = "pty_slave"; pts_driver->driver_name = "pty_slave";
pts_driver->name = "pts"; pts_driver->name = "pts";
pts_driver->major = UNIX98_PTY_SLAVE_MAJOR; pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
@ -762,8 +707,6 @@ static void __init unix98_pty_init(void)
if (tty_register_driver(pts_driver)) if (tty_register_driver(pts_driver))
panic("Couldn't register Unix98 pts driver"); panic("Couldn't register Unix98 pts driver");
register_sysctl_table(pty_root_table);
/* Now create the /dev/ptmx special device */ /* Now create the /dev/ptmx special device */
tty_default_fops(&ptmx_fops); tty_default_fops(&ptmx_fops);
ptmx_fops.open = ptmx_open; ptmx_fops.open = ptmx_open;

View File

@ -892,12 +892,12 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
{ {
struct r_port *info; struct r_port *info;
struct tty_port *port; struct tty_port *port;
int line = 0, retval; int retval;
CHANNEL_t *cp; CHANNEL_t *cp;
unsigned long page; unsigned long page;
line = tty->index; info = rp_table[tty->index];
if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL)) if (info == NULL)
return -ENXIO; return -ENXIO;
port = &info->port; port = &info->port;
@ -2277,7 +2277,6 @@ static int __init rp_init(void)
* driver with the tty layer. * driver with the tty layer.
*/ */
rocket_driver->owner = THIS_MODULE;
rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
rocket_driver->name = "ttyR"; rocket_driver->name = "ttyR";
rocket_driver->driver_name = "Comtrol RocketPort"; rocket_driver->driver_name = "Comtrol RocketPort";

View File

@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct
int ret = 0; int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
ret = -EINVAL; ret = -EINVAL;
if (ser->irq != NO_IRQ) if (ser->irq <= 0)
ret = -EINVAL; ret = -EINVAL;
if (ser->baud_base != port->uartclk / 16) if (ser->baud_base != port->uartclk / 16)
ret = -EINVAL; ret = -EINVAL;
@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = {
static struct uart_port serial21285_port = { static struct uart_port serial21285_port = {
.mapbase = 0x42000160, .mapbase = 0x42000160,
.iotype = UPIO_MEM, .iotype = UPIO_MEM,
.irq = NO_IRQ, .irq = 0,
.fifosize = 16, .fifosize = 16,
.ops = &serial21285_ops, .ops = &serial21285_ops,
.flags = UPF_BOOT_AUTOCONF, .flags = UPF_BOOT_AUTOCONF,

View File

@ -1190,14 +1190,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
int rs_open(struct tty_struct *tty, struct file * filp) int rs_open(struct tty_struct *tty, struct file * filp)
{ {
struct m68k_serial *info; struct m68k_serial *info;
int retval, line; int retval;
line = tty->index; info = &m68k_soft[tty->index];
if (line >= NR_PORTS || line < 0) /* we have exactly one */
return -ENODEV;
info = &m68k_soft[line];
if (serial_paranoia_check(info, tty->name, "rs_open")) if (serial_paranoia_check(info, tty->name, "rs_open"))
return -ENODEV; return -ENODEV;

File diff suppressed because it is too large Load Diff

View File

@ -86,6 +86,16 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0 #define SERIAL8250_SHARE_IRQS 0
#endif #endif
static inline int serial_in(struct uart_8250_port *up, int offset)
{
return up->port.serial_in(&up->port, offset);
}
static inline void serial_out(struct uart_8250_port *up, int offset, int value)
{
up->port.serial_out(&up->port, offset, value);
}
#if defined(__alpha__) && !defined(CONFIG_PCI) #if defined(__alpha__) && !defined(CONFIG_PCI)
/* /*
* Digital did something really horribly wrong with the OUT1 and OUT2 * Digital did something really horribly wrong with the OUT1 and OUT2

View File

@ -1347,4 +1347,17 @@ config SERIAL_AR933X_NR_UARTS
Set this to the number of serial ports you want the driver Set this to the number of serial ports you want the driver
to support. to support.
config SERIAL_EFM32_UART
tristate "EFM32 UART/USART port."
depends on ARCH_EFM32
select SERIAL_CORE
help
This driver support the USART and UART ports on
Energy Micro's efm32 SoCs.
config SERIAL_EFM32_UART_CONSOLE
bool "EFM32 UART/USART console support"
depends on SERIAL_EFM32_UART=y
select SERIAL_CORE_CONSOLE
endmenu endmenu

View File

@ -61,12 +61,12 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
@ -78,3 +78,4 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o

View File

@ -377,6 +377,26 @@ static int altera_uart_verify_port(struct uart_port *port,
return 0; return 0;
} }
#ifdef CONFIG_CONSOLE_POLL
static int altera_uart_poll_get_char(struct uart_port *port)
{
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_RRDY_MSK))
cpu_relax();
return altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
}
static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK))
cpu_relax();
altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
}
#endif
/* /*
* Define the basic serial functions we support. * Define the basic serial functions we support.
*/ */
@ -397,35 +417,16 @@ static struct uart_ops altera_uart_ops = {
.release_port = altera_uart_release_port, .release_port = altera_uart_release_port,
.config_port = altera_uart_config_port, .config_port = altera_uart_config_port,
.verify_port = altera_uart_verify_port, .verify_port = altera_uart_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = altera_uart_poll_get_char,
.poll_put_char = altera_uart_poll_put_char,
#endif
}; };
static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS]; static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE) #if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
{
struct uart_port *port;
int i;
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_uart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_UART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = platp[i].uartclk;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &altera_uart_ops;
port->private_data = platp;
}
return 0;
}
static void altera_uart_console_putc(struct uart_port *port, const char c) static void altera_uart_console_putc(struct uart_port *port, const char c)
{ {
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &

View File

@ -827,7 +827,12 @@ static void pl011_dma_rx_callback(void *data)
{ {
struct uart_amba_port *uap = data; struct uart_amba_port *uap = data;
struct pl011_dmarx_data *dmarx = &uap->dmarx; struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_chan *rxchan = dmarx->chan;
bool lastbuf = dmarx->use_buf_b; bool lastbuf = dmarx->use_buf_b;
struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
&dmarx->sgbuf_b : &dmarx->sgbuf_a;
size_t pending;
struct dma_tx_state state;
int ret; int ret;
/* /*
@ -838,11 +843,21 @@ static void pl011_dma_rx_callback(void *data)
* we immediately trigger the next DMA job. * we immediately trigger the next DMA job.
*/ */
spin_lock_irq(&uap->port.lock); spin_lock_irq(&uap->port.lock);
/*
* Rx data can be taken by the UART interrupts during
* the DMA irq handler. So we check the residue here.
*/
rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
pending = sgbuf->sg.length - state.residue;
BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
/* Then we terminate the transfer - we now know our residue */
dmaengine_terminate_all(rxchan);
uap->dmarx.running = false; uap->dmarx.running = false;
dmarx->use_buf_b = !lastbuf; dmarx->use_buf_b = !lastbuf;
ret = pl011_dma_rx_trigger_dma(uap); ret = pl011_dma_rx_trigger_dma(uap);
pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false); pl011_dma_rx_chars(uap, pending, lastbuf, false);
spin_unlock_irq(&uap->port.lock); spin_unlock_irq(&uap->port.lock);
/* /*
* Do this check after we picked the DMA chars so we don't * Do this check after we picked the DMA chars so we don't
@ -1381,6 +1396,10 @@ static int pl011_startup(struct uart_port *port)
uap->port.uartclk = clk_get_rate(uap->clk); uap->port.uartclk = clk_get_rate(uap->clk);
/* Clear pending error and receive interrupts */
writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
/* /*
* Allocate the IRQ * Allocate the IRQ
*/ */
@ -1417,10 +1436,6 @@ static int pl011_startup(struct uart_port *port)
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR); writew(cr, uap->port.membase + UART011_CR);
/* Clear pending error interrupts */
writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
uap->port.membase + UART011_ICR);
/* /*
* initialise the old status of the modem signals * initialise the old status of the modem signals
*/ */
@ -1435,6 +1450,9 @@ static int pl011_startup(struct uart_port *port)
* as well. * as well.
*/ */
spin_lock_irq(&uap->port.lock); spin_lock_irq(&uap->port.lock);
/* Clear out any spuriously appearing RX interrupts */
writew(UART011_RTIS | UART011_RXIS,
uap->port.membase + UART011_ICR);
uap->im = UART011_RTIM; uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap)) if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM; uap->im |= UART011_RXIM;
@ -1927,6 +1945,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto unmap; goto unmap;
} }
/* Ensure interrupts from this UART are masked and cleared */
writew(0, uap->port.membase + UART011_IMSC);
writew(0xffff, uap->port.membase + UART011_ICR);
uap->vendor = vendor; uap->vendor = vendor;
uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx; uap->lcrh_tx = vendor->lcrh_tx;

View File

@ -535,11 +535,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
* when start a new tx. * when start a new tx.
*/ */
UART_CLEAR_IER(uart, ETBEI); UART_CLEAR_IER(uart, ETBEI);
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
uart->port.icount.tx += uart->tx_count; uart->port.icount.tx += uart->tx_count;
if (!uart_circ_empty(xmit)) {
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uart->port); uart_write_wakeup(&uart->port);
}
bfin_serial_dma_tx_chars(uart); bfin_serial_dma_tx_chars(uart);
} }

View File

@ -4105,20 +4105,11 @@ static int
rs_open(struct tty_struct *tty, struct file * filp) rs_open(struct tty_struct *tty, struct file * filp)
{ {
struct e100_serial *info; struct e100_serial *info;
int retval, line; int retval;
unsigned long page; unsigned long page;
int allocated_resources = 0; int allocated_resources = 0;
/* find which port we want to open */ info = rs_table + tty->index;
line = tty->index;
if (line < 0 || line >= NR_PORTS)
return -ENODEV;
/* find the corresponding e100_serial struct in the table */
info = rs_table + line;
/* don't allow the opening of ports that are not enabled in the HW config */
if (!info->enabled) if (!info->enabled)
return -ENODEV; return -ENODEV;
@ -4131,7 +4122,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
tty->driver_data = info; tty->driver_data = info;
info->port.tty = tty; info->port.tty = tty;
info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
if (!tmp_buf) { if (!tmp_buf) {
page = get_zeroed_page(GFP_KERNEL); page = get_zeroed_page(GFP_KERNEL);

View File

@ -0,0 +1,830 @@
#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/serial_core.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_data/efm32-uart.h>
#define DRIVER_NAME "efm32-uart"
#define DEV_NAME "ttyefm"
#define UARTn_CTRL 0x00
#define UARTn_CTRL_SYNC 0x0001
#define UARTn_CTRL_TXBIL 0x1000
#define UARTn_FRAME 0x04
#define UARTn_FRAME_DATABITS__MASK 0x000f
#define UARTn_FRAME_DATABITS(n) ((n) - 3)
#define UARTn_FRAME_PARITY_NONE 0x0000
#define UARTn_FRAME_PARITY_EVEN 0x0200
#define UARTn_FRAME_PARITY_ODD 0x0300
#define UARTn_FRAME_STOPBITS_HALF 0x0000
#define UARTn_FRAME_STOPBITS_ONE 0x1000
#define UARTn_FRAME_STOPBITS_TWO 0x3000
#define UARTn_CMD 0x0c
#define UARTn_CMD_RXEN 0x0001
#define UARTn_CMD_RXDIS 0x0002
#define UARTn_CMD_TXEN 0x0004
#define UARTn_CMD_TXDIS 0x0008
#define UARTn_STATUS 0x10
#define UARTn_STATUS_TXENS 0x0002
#define UARTn_STATUS_TXC 0x0020
#define UARTn_STATUS_TXBL 0x0040
#define UARTn_STATUS_RXDATAV 0x0080
#define UARTn_CLKDIV 0x14
#define UARTn_RXDATAX 0x18
#define UARTn_RXDATAX_RXDATA__MASK 0x01ff
#define UARTn_RXDATAX_PERR 0x4000
#define UARTn_RXDATAX_FERR 0x8000
/*
* This is a software only flag used for ignore_status_mask and
* read_status_mask! It's used for breaks that the hardware doesn't report
* explicitly.
*/
#define SW_UARTn_RXDATAX_BERR 0x2000
#define UARTn_TXDATA 0x34
#define UARTn_IF 0x40
#define UARTn_IF_TXC 0x0001
#define UARTn_IF_TXBL 0x0002
#define UARTn_IF_RXDATAV 0x0004
#define UARTn_IF_RXOF 0x0010
#define UARTn_IFS 0x44
#define UARTn_IFC 0x48
#define UARTn_IEN 0x4c
#define UARTn_ROUTE 0x54
#define UARTn_ROUTE_LOCATION__MASK 0x0700
#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
#define UARTn_ROUTE_RXPEN 0x0001
#define UARTn_ROUTE_TXPEN 0x0002
struct efm32_uart_port {
struct uart_port port;
unsigned int txirq;
struct clk *clk;
};
#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
#define efm_debug(efm_port, format, arg...) \
dev_dbg(efm_port->port.dev, format, ##arg)
static void efm32_uart_write32(struct efm32_uart_port *efm_port,
u32 value, unsigned offset)
{
writel_relaxed(value, efm_port->port.membase + offset);
}
static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
unsigned offset)
{
return readl_relaxed(efm_port->port.membase + offset);
}
static unsigned int efm32_uart_tx_empty(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
if (status & UARTn_STATUS_TXC)
return TIOCSER_TEMT;
else
return 0;
}
static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* sorry, neither handshaking lines nor loop functionallity */
}
static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
{
/* sorry, no handshaking lines available */
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
}
static void efm32_uart_stop_tx(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 ien = efm32_uart_read32(efm_port, UARTn_IEN);
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
efm32_uart_write32(efm_port, ien, UARTn_IEN);
}
static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
{
struct uart_port *port = &efm_port->port;
struct circ_buf *xmit = &port->state->xmit;
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
UARTn_STATUS_TXBL) {
if (port->x_char) {
port->icount.tx++;
efm32_uart_write32(efm_port, port->x_char,
UARTn_TXDATA);
port->x_char = 0;
continue;
}
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
port->icount.tx++;
efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
UARTn_TXDATA);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
} else
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (!port->x_char && uart_circ_empty(xmit) &&
efm32_uart_read32(efm_port, UARTn_STATUS) &
UARTn_STATUS_TXC)
efm32_uart_stop_tx(port);
}
static void efm32_uart_start_tx(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 ien;
efm32_uart_write32(efm_port,
UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
ien = efm32_uart_read32(efm_port, UARTn_IEN);
efm32_uart_write32(efm_port,
ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
efm32_uart_tx_chars(efm_port);
}
static void efm32_uart_stop_rx(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
}
static void efm32_uart_enable_ms(struct uart_port *port)
{
/* no handshake lines, no modem status interrupts */
}
static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
{
/* not possible without fiddling with gpios */
}
static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
struct tty_struct *tty)
{
struct uart_port *port = &efm_port->port;
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
UARTn_STATUS_RXDATAV) {
u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
int flag = 0;
/*
* This is a reserved bit and I only saw it read as 0. But to be
* sure not to be confused too much by new devices adhere to the
* warning in the reference manual that reserverd bits might
* read as 1 in the future.
*/
rxdata &= ~SW_UARTn_RXDATAX_BERR;
port->icount.rx++;
if ((rxdata & UARTn_RXDATAX_FERR) &&
!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
rxdata |= SW_UARTn_RXDATAX_BERR;
port->icount.brk++;
if (uart_handle_break(port))
continue;
} else if (rxdata & UARTn_RXDATAX_PERR)
port->icount.parity++;
else if (rxdata & UARTn_RXDATAX_FERR)
port->icount.frame++;
rxdata &= port->read_status_mask;
if (rxdata & SW_UARTn_RXDATAX_BERR)
flag = TTY_BREAK;
else if (rxdata & UARTn_RXDATAX_PERR)
flag = TTY_PARITY;
else if (rxdata & UARTn_RXDATAX_FERR)
flag = TTY_FRAME;
else if (uart_handle_sysrq_char(port,
rxdata & UARTn_RXDATAX_RXDATA__MASK))
continue;
if (tty && (rxdata & port->ignore_status_mask) == 0)
tty_insert_flip_char(tty,
rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
}
}
static irqreturn_t efm32_uart_rxirq(int irq, void *data)
{
struct efm32_uart_port *efm_port = data;
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
int handled = IRQ_NONE;
struct uart_port *port = &efm_port->port;
struct tty_struct *tty;
spin_lock(&port->lock);
tty = tty_kref_get(port->state->port.tty);
if (irqflag & UARTn_IF_RXDATAV) {
efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
efm32_uart_rx_chars(efm_port, tty);
handled = IRQ_HANDLED;
}
if (irqflag & UARTn_IF_RXOF) {
efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
port->icount.overrun++;
if (tty)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
handled = IRQ_HANDLED;
}
if (tty) {
tty_flip_buffer_push(tty);
tty_kref_put(tty);
}
spin_unlock(&port->lock);
return handled;
}
static irqreturn_t efm32_uart_txirq(int irq, void *data)
{
struct efm32_uart_port *efm_port = data;
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
/* TXBL doesn't need to be cleared */
if (irqflag & UARTn_IF_TXC)
efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
efm32_uart_tx_chars(efm_port);
return IRQ_HANDLED;
} else
return IRQ_NONE;
}
static int efm32_uart_startup(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
u32 location = 0;
struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
int ret;
if (pdata)
location = UARTn_ROUTE_LOCATION(pdata->location);
ret = clk_enable(efm_port->clk);
if (ret) {
efm_debug(efm_port, "failed to enable clk\n");
goto err_clk_enable;
}
port->uartclk = clk_get_rate(efm_port->clk);
/* Enable pins at configured location */
efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
UARTn_ROUTE);
ret = request_irq(port->irq, efm32_uart_rxirq, 0,
DRIVER_NAME, efm_port);
if (ret) {
efm_debug(efm_port, "failed to register rxirq\n");
goto err_request_irq_rx;
}
/* disable all irqs */
efm32_uart_write32(efm_port, 0, UARTn_IEN);
ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
DRIVER_NAME, efm_port);
if (ret) {
efm_debug(efm_port, "failed to register txirq\n");
free_irq(port->irq, efm_port);
err_request_irq_rx:
clk_disable(efm_port->clk);
} else {
efm32_uart_write32(efm_port,
UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
}
err_clk_enable:
return ret;
}
static void efm32_uart_shutdown(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
efm32_uart_write32(efm_port, 0, UARTn_IEN);
free_irq(port->irq, efm_port);
clk_disable(efm_port->clk);
}
static void efm32_uart_set_termios(struct uart_port *port,
struct ktermios *new, struct ktermios *old)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
unsigned long flags;
unsigned baud;
u32 clkdiv;
u32 frame = 0;
/* no modem control lines */
new->c_cflag &= ~(CRTSCTS | CMSPAR);
baud = uart_get_baud_rate(port, new, old,
DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
DIV_ROUND_CLOSEST(port->uartclk, 16));
switch (new->c_cflag & CSIZE) {
case CS5:
frame |= UARTn_FRAME_DATABITS(5);
break;
case CS6:
frame |= UARTn_FRAME_DATABITS(6);
break;
case CS7:
frame |= UARTn_FRAME_DATABITS(7);
break;
case CS8:
frame |= UARTn_FRAME_DATABITS(8);
break;
}
if (new->c_cflag & CSTOPB)
/* the receiver only verifies the first stop bit */
frame |= UARTn_FRAME_STOPBITS_TWO;
else
frame |= UARTn_FRAME_STOPBITS_ONE;
if (new->c_cflag & PARENB) {
if (new->c_cflag & PARODD)
frame |= UARTn_FRAME_PARITY_ODD;
else
frame |= UARTn_FRAME_PARITY_EVEN;
} else
frame |= UARTn_FRAME_PARITY_NONE;
/*
* the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
* port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
*/
clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
spin_lock_irqsave(&port->lock, flags);
efm32_uart_write32(efm_port,
UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
if (new->c_iflag & INPCK)
port->read_status_mask |=
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
if (new->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
port->ignore_status_mask = 0;
if (new->c_iflag & IGNPAR)
port->ignore_status_mask |=
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
if (new->c_iflag & IGNBRK)
port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
uart_update_timeout(port, new->c_cflag, baud);
efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
efm32_uart_write32(efm_port, frame, UARTn_FRAME);
efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
UARTn_CMD);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *efm32_uart_type(struct uart_port *port)
{
return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
}
static void efm32_uart_release_port(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
clk_unprepare(efm_port->clk);
clk_put(efm_port->clk);
iounmap(port->membase);
}
static int efm32_uart_request_port(struct uart_port *port)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
int ret;
port->membase = ioremap(port->mapbase, 60);
if (!efm_port->port.membase) {
ret = -ENOMEM;
efm_debug(efm_port, "failed to remap\n");
goto err_ioremap;
}
efm_port->clk = clk_get(port->dev, NULL);
if (IS_ERR(efm_port->clk)) {
ret = PTR_ERR(efm_port->clk);
efm_debug(efm_port, "failed to get clock\n");
goto err_clk_get;
}
ret = clk_prepare(efm_port->clk);
if (ret) {
clk_put(efm_port->clk);
err_clk_get:
iounmap(port->membase);
err_ioremap:
return ret;
}
return 0;
}
static void efm32_uart_config_port(struct uart_port *port, int type)
{
if (type & UART_CONFIG_TYPE &&
!efm32_uart_request_port(port))
port->type = PORT_EFMUART;
}
static int efm32_uart_verify_port(struct uart_port *port,
struct serial_struct *serinfo)
{
int ret = 0;
if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
ret = -EINVAL;
return ret;
}
static struct uart_ops efm32_uart_pops = {
.tx_empty = efm32_uart_tx_empty,
.set_mctrl = efm32_uart_set_mctrl,
.get_mctrl = efm32_uart_get_mctrl,
.stop_tx = efm32_uart_stop_tx,
.start_tx = efm32_uart_start_tx,
.stop_rx = efm32_uart_stop_rx,
.enable_ms = efm32_uart_enable_ms,
.break_ctl = efm32_uart_break_ctl,
.startup = efm32_uart_startup,
.shutdown = efm32_uart_shutdown,
.set_termios = efm32_uart_set_termios,
.type = efm32_uart_type,
.release_port = efm32_uart_release_port,
.request_port = efm32_uart_request_port,
.config_port = efm32_uart_config_port,
.verify_port = efm32_uart_verify_port,
};
static struct efm32_uart_port *efm32_uart_ports[5];
#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
static void efm32_uart_console_putchar(struct uart_port *port, int ch)
{
struct efm32_uart_port *efm_port = to_efm_port(port);
unsigned int timeout = 0x400;
u32 status;
while (1) {
status = efm32_uart_read32(efm_port, UARTn_STATUS);
if (status & UARTn_STATUS_TXBL)
break;
if (!timeout--)
return;
}
efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
}
static void efm32_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
unsigned int timeout = 0x400;
if (!(status & UARTn_STATUS_TXENS))
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
uart_console_write(&efm_port->port, s, count,
efm32_uart_console_putchar);
/* Wait for the transmitter to become empty */
while (1) {
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
if (status & UARTn_STATUS_TXC)
break;
if (!timeout--)
break;
}
if (!(status & UARTn_STATUS_TXENS))
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
}
static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
int *baud, int *parity, int *bits)
{
u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
u32 route, clkdiv, frame;
if (ctrl & UARTn_CTRL_SYNC)
/* not operating in async mode */
return;
route = efm32_uart_read32(efm_port, UARTn_ROUTE);
if (!(route & UARTn_ROUTE_TXPEN))
/* tx pin not routed */
return;
clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
16 * (4 + (clkdiv >> 6)));
frame = efm32_uart_read32(efm_port, UARTn_FRAME);
if (frame & UARTn_FRAME_PARITY_ODD)
*parity = 'o';
else if (frame & UARTn_FRAME_PARITY_EVEN)
*parity = 'e';
else
*parity = 'n';
*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
UARTn_FRAME_DATABITS(4) + 4;
efm_debug(efm_port, "get_opts: options=%d%c%d\n",
*baud, *parity, *bits);
}
static int efm32_uart_console_setup(struct console *co, char *options)
{
struct efm32_uart_port *efm_port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
unsigned i;
for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
if (efm32_uart_ports[i]) {
pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
i, co->index);
co->index = i;
break;
}
}
}
efm_port = efm32_uart_ports[co->index];
if (!efm_port) {
pr_warn("efm32-console: No port at %d\n", co->index);
return -ENODEV;
}
ret = clk_prepare(efm_port->clk);
if (ret) {
dev_warn(efm_port->port.dev,
"console: clk_prepare failed: %d\n", ret);
return ret;
}
efm_port->port.uartclk = clk_get_rate(efm_port->clk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
efm32_uart_console_get_options(efm_port,
&baud, &parity, &bits);
return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
}
static struct uart_driver efm32_uart_reg;
static struct console efm32_uart_console = {
.name = DEV_NAME,
.write = efm32_uart_console_write,
.device = uart_console_device,
.setup = efm32_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &efm32_uart_reg,
};
#else
#define efm32_uart_console (*(struct console *)NULL)
#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
static struct uart_driver efm32_uart_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = DEV_NAME,
.nr = ARRAY_SIZE(efm32_uart_ports),
.cons = &efm32_uart_console,
};
static int efm32_uart_probe_dt(struct platform_device *pdev,
struct efm32_uart_port *efm_port)
{
struct device_node *np = pdev->dev.of_node;
int ret;
if (!np)
return 1;
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
return ret;
} else {
efm_port->port.line = ret;
return 0;
}
}
static int __devinit efm32_uart_probe(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port;
struct resource *res;
int ret;
efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
if (!efm_port) {
dev_dbg(&pdev->dev, "failed to allocate private data\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
dev_dbg(&pdev->dev, "failed to determine base address\n");
goto err_get_base;
}
if (resource_size(res) < 60) {
ret = -EINVAL;
dev_dbg(&pdev->dev, "memory resource too small\n");
goto err_too_small;
}
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_dbg(&pdev->dev, "failed to get rx irq\n");
goto err_get_rxirq;
}
efm_port->port.irq = ret;
ret = platform_get_irq(pdev, 1);
if (ret <= 0)
ret = efm_port->port.irq + 1;
efm_port->txirq = ret;
efm_port->port.dev = &pdev->dev;
efm_port->port.mapbase = res->start;
efm_port->port.type = PORT_EFMUART;
efm_port->port.iotype = UPIO_MEM32;
efm_port->port.fifosize = 2;
efm_port->port.ops = &efm32_uart_pops;
efm_port->port.flags = UPF_BOOT_AUTOCONF;
ret = efm32_uart_probe_dt(pdev, efm_port);
if (ret > 0)
/* not created by device tree */
efm_port->port.line = pdev->id;
if (efm_port->port.line >= 0 &&
efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
efm32_uart_ports[efm_port->port.line] = efm_port;
ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
if (ret) {
dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
efm32_uart_ports[pdev->id] = NULL;
err_get_rxirq:
err_too_small:
err_get_base:
kfree(efm_port);
} else {
platform_set_drvdata(pdev, efm_port);
dev_dbg(&pdev->dev, "\\o/\n");
}
return ret;
}
static int __devexit efm32_uart_remove(struct platform_device *pdev)
{
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
efm32_uart_ports[pdev->id] = NULL;
kfree(efm_port);
return 0;
}
static struct of_device_id efm32_uart_dt_ids[] = {
{
.compatible = "efm32,uart",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
static struct platform_driver efm32_uart_driver = {
.probe = efm32_uart_probe,
.remove = __devexit_p(efm32_uart_remove),
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = efm32_uart_dt_ids,
},
};
static int __init efm32_uart_init(void)
{
int ret;
ret = uart_register_driver(&efm32_uart_reg);
if (ret)
return ret;
ret = platform_driver_register(&efm32_uart_driver);
if (ret)
uart_unregister_driver(&efm32_uart_reg);
pr_info("EFM32 UART/USART driver\n");
return ret;
}
module_init(efm32_uart_init);
static void __exit efm32_uart_exit(void)
{
platform_driver_unregister(&efm32_uart_driver);
uart_unregister_driver(&efm32_uart_reg);
}
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 UART/USART driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

View File

@ -1375,12 +1375,9 @@ static int __init ifx_spi_init(void)
return -ENOMEM; return -ENOMEM;
} }
tty_drv->magic = TTY_DRIVER_MAGIC;
tty_drv->owner = THIS_MODULE;
tty_drv->driver_name = DRVNAME; tty_drv->driver_name = DRVNAME;
tty_drv->name = TTYNAME; tty_drv->name = TTYNAME;
tty_drv->minor_start = IFX_SPI_TTY_ID; tty_drv->minor_start = IFX_SPI_TTY_ID;
tty_drv->num = 1;
tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
tty_drv->subtype = SERIAL_TYPE_NORMAL; tty_drv->subtype = SERIAL_TYPE_NORMAL;
tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;

View File

@ -16,7 +16,6 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/circ_buf.h> #include <linux/circ_buf.h>
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <linux/module.h> #include <linux/module.h>
@ -975,7 +974,7 @@ intr_connect(struct ioc4_soft *soft, int type,
BUG_ON(!((type == IOC4_SIO_INTR_TYPE) BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
|| (type == IOC4_OTHER_INTR_TYPE))); || (type == IOC4_OTHER_INTR_TYPE)));
i = atomic_inc(&soft-> is_intr_type[type].is_num_intrs) - 1; i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1;
BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0))); BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
/* Save off the lower level interrupt handler */ /* Save off the lower level interrupt handler */

View File

@ -38,7 +38,6 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/m32r.h> #include <asm/m32r.h>
@ -70,13 +69,6 @@
#define PASS_LIMIT 256 #define PASS_LIMIT 256
/*
* We default to IRQ0 for the "no irq" hack. Some
* machine types want others as well - they're free
* to redefine this in their header file.
*/
#define is_real_interrupt(irq) ((irq) != 0)
#define BASE_BAUD 115200 #define BASE_BAUD 115200
/* Standard COM flags */ /* Standard COM flags */
@ -640,7 +632,7 @@ static int m32r_sio_startup(struct uart_port *port)
* hardware interrupt, we use a timer-based system. The original * hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0. * driver used to do this with IRQ0.
*/ */
if (!is_real_interrupt(up->port.irq)) { if (!up->port.irq) {
unsigned int timeout = up->port.timeout; unsigned int timeout = up->port.timeout;
timeout = timeout > 6 ? (timeout / 2 - 2) : 1; timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@ -687,7 +679,7 @@ static void m32r_sio_shutdown(struct uart_port *port)
sio_init(); sio_init();
if (!is_real_interrupt(up->port.irq)) if (!up->port.irq)
del_timer_sync(&up->timer); del_timer_sync(&up->timer);
else else
serial_unlink_irq_chain(up); serial_unlink_irq_chain(up);

View File

@ -15,6 +15,7 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#include <linux/pci.h>
struct m32r_sio_probe { struct m32r_sio_probe {
struct module *owner; struct module *owner;

View File

@ -262,8 +262,9 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
port->uartclk / 4); port->uartclk / 4);
divisor = (port->uartclk + 2 * baud) / (4 * baud); divisor = (port->uartclk + 2 * baud) / (4 * baud);
/* select the proper prescaler and set the divisor */ /* select the proper prescaler and set the divisor
if (divisor > 0xffff) { * prefer high prescaler for more tolerance on low baudrates */
if (divisor > 0xffff || baud <= 115200) {
divisor = (divisor + 4) / 8; divisor = (divisor + 4) / 8;
prescaler = 0xdd00; /* /32 */ prescaler = 0xdd00; /* /32 */
} else } else
@ -507,7 +508,7 @@ static int __init mpc512x_psc_fifoc_init(void)
psc_fifoc_irq = irq_of_parse_and_map(np, 0); psc_fifoc_irq = irq_of_parse_and_map(np, 0);
of_node_put(np); of_node_put(np);
if (psc_fifoc_irq == NO_IRQ) { if (psc_fifoc_irq == 0) {
pr_err("%s: Can't get FIFOC irq\n", __func__); pr_err("%s: Can't get FIFOC irq\n", __func__);
iounmap(psc_fifoc); iounmap(psc_fifoc);
return -ENODEV; return -ENODEV;
@ -1354,7 +1355,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
} }
psc_ops->get_irq(port, op->dev.of_node); psc_ops->get_irq(port, op->dev.of_node);
if (port->irq == NO_IRQ) { if (port->irq == 0) {
dev_dbg(&op->dev, "Could not get irq\n"); dev_dbg(&op->dev, "Could not get irq\n");
return -EINVAL; return -EINVAL;
} }

View File

@ -203,7 +203,6 @@ static int __init smd_tty_init(void)
if (smd_tty_driver == 0) if (smd_tty_driver == 0)
return -ENOMEM; return -ENOMEM;
smd_tty_driver->owner = THIS_MODULE;
smd_tty_driver->driver_name = "smd_tty_driver"; smd_tty_driver->driver_name = "smd_tty_driver";
smd_tty_driver->name = "smd"; smd_tty_driver->name = "smd";
smd_tty_driver->major = 0; smd_tty_driver->major = 0;

View File

@ -17,7 +17,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/serial.h> #include <linux/serial.h>
@ -499,7 +498,7 @@ static int __init mux_probe(struct parisc_device *dev)
port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
port->iotype = UPIO_MEM; port->iotype = UPIO_MEM;
port->type = PORT_MUX; port->type = PORT_MUX;
port->irq = NO_IRQ; port->irq = 0;
port->uartclk = 0; port->uartclk = 0;
port->fifosize = MUX_FIFO_SIZE; port->fifosize = MUX_FIFO_SIZE;
port->ops = &mux_pops; port->ops = &mux_pops;

View File

@ -159,7 +159,7 @@ static void serial_omap_stop_tx(struct uart_port *port)
serial_out(up, UART_IER, up->ier); serial_out(up, UART_IER, up->ier);
} }
if (!up->use_dma && pdata->set_forceidle) if (!up->use_dma && pdata && pdata->set_forceidle)
pdata->set_forceidle(up->pdev); pdata->set_forceidle(up->pdev);
pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_mark_last_busy(&up->pdev->dev);
@ -298,7 +298,7 @@ static void serial_omap_start_tx(struct uart_port *port)
if (!up->use_dma) { if (!up->use_dma) {
pm_runtime_get_sync(&up->pdev->dev); pm_runtime_get_sync(&up->pdev->dev);
serial_omap_enable_ier_thri(up); serial_omap_enable_ier_thri(up);
if (pdata->set_noidle) if (pdata && pdata->set_noidle)
pdata->set_noidle(up->pdev); pdata->set_noidle(up->pdev);
pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_mark_last_busy(&up->pdev->dev);
pm_runtime_put_autosuspend(&up->pdev->dev); pm_runtime_put_autosuspend(&up->pdev->dev);
@ -1613,7 +1613,7 @@ static int serial_omap_runtime_resume(struct device *dev)
struct uart_omap_port *up = dev_get_drvdata(dev); struct uart_omap_port *up = dev_get_drvdata(dev);
struct omap_uart_port_info *pdata = dev->platform_data; struct omap_uart_port_info *pdata = dev->platform_data;
if (up) { if (up && pdata) {
if (pdata->get_context_loss_count) { if (pdata->get_context_loss_count) {
u32 loss_cnt = pdata->get_context_loss_count(dev); u32 loss_cnt = pdata->get_context_loss_count(dev);

View File

@ -29,6 +29,7 @@
#include <linux/nmi.h> #include <linux/nmi.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/pch_dma.h> #include <linux/pch_dma.h>
@ -144,6 +145,8 @@ enum {
#define PCH_UART_DLL 0x00 #define PCH_UART_DLL 0x00
#define PCH_UART_DLM 0x01 #define PCH_UART_DLM 0x01
#define PCH_UART_BRCSR 0x0E
#define PCH_UART_IID_RLS (PCH_UART_IIR_REI) #define PCH_UART_IID_RLS (PCH_UART_IIR_REI)
#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI) #define PCH_UART_IID_RDR (PCH_UART_IIR_RRI)
#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI) #define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
@ -203,7 +206,10 @@ enum {
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
#define DEFAULT_BAUD_RATE 1843200 /* 1.8432MHz */ #define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */
#define CMITC_UARTCLK 192000000 /* 192.0000 MHz */
#define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */
#define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */
struct pch_uart_buffer { struct pch_uart_buffer {
unsigned char *buf; unsigned char *buf;
@ -218,7 +224,7 @@ struct eg20t_port {
unsigned int iobase; unsigned int iobase;
struct pci_dev *pdev; struct pci_dev *pdev;
int fifo_size; int fifo_size;
int base_baud; int uartclk;
int start_tx; int start_tx;
int start_rx; int start_rx;
int tx_empty; int tx_empty;
@ -243,6 +249,8 @@ struct eg20t_port {
int tx_dma_use; int tx_dma_use;
void *rx_buf_virt; void *rx_buf_virt;
dma_addr_t rx_buf_dma; dma_addr_t rx_buf_dma;
struct dentry *debugfs;
}; };
/** /**
@ -287,26 +295,100 @@ static struct pch_uart_driver_data drv_dat[] = {
static struct eg20t_port *pch_uart_ports[PCH_UART_NR]; static struct eg20t_port *pch_uart_ports[PCH_UART_NR];
#endif #endif
static unsigned int default_baud = 9600; static unsigned int default_baud = 9600;
static unsigned int user_uartclk = 0;
static const int trigger_level_256[4] = { 1, 64, 128, 224 }; static const int trigger_level_256[4] = { 1, 64, 128, 224 };
static const int trigger_level_64[4] = { 1, 16, 32, 56 }; static const int trigger_level_64[4] = { 1, 16, 32, 56 };
static const int trigger_level_16[4] = { 1, 4, 8, 14 }; static const int trigger_level_16[4] = { 1, 4, 8, 14 };
static const int trigger_level_1[4] = { 1, 1, 1, 1 }; static const int trigger_level_1[4] = { 1, 1, 1, 1 };
static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize, #ifdef CONFIG_DEBUG_FS
int base_baud)
{
struct eg20t_port *priv = pci_get_drvdata(pdev);
priv->trigger_level = 1; #define PCH_REGS_BUFSIZE 1024
priv->fcr = 0; static int pch_show_regs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
} }
static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base) static ssize_t port_show_regs(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{ {
unsigned int msr = ioread8(base + UART_MSR); struct eg20t_port *priv = file->private_data;
priv->dmsr |= msr & PCH_UART_MSR_DELTA; char *buf;
u32 len = 0;
ssize_t ret;
unsigned char lcr;
return msr; buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL);
if (!buf)
return 0;
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"PCH EG20T port[%d] regs:\n", priv->port.line);
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"=================================\n");
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"BRCSR: \t0x%02x\n",
ioread8(priv->membase + PCH_UART_BRCSR));
lcr = ioread8(priv->membase + UART_LCR);
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
iowrite8(lcr, priv->membase + UART_LCR);
if (len > PCH_REGS_BUFSIZE)
len = PCH_REGS_BUFSIZE;
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return ret;
}
static const struct file_operations port_regs_ops = {
.owner = THIS_MODULE,
.open = pch_show_regs_open,
.read = port_show_regs,
.llseek = default_llseek,
};
#endif /* CONFIG_DEBUG_FS */
/* Return UART clock, checking for board specific clocks. */
static int pch_uart_get_uartclk(void)
{
const char *cmp;
if (user_uartclk)
return user_uartclk;
cmp = dmi_get_system_info(DMI_BOARD_NAME);
if (cmp && strstr(cmp, "CM-iTC"))
return CMITC_UARTCLK;
cmp = dmi_get_system_info(DMI_BIOS_VERSION);
if (cmp && strnstr(cmp, "FRI2", 4))
return FRI2_64_UARTCLK;
cmp = dmi_get_system_info(DMI_PRODUCT_NAME);
if (cmp && strstr(cmp, "Fish River Island II"))
return FRI2_48_UARTCLK;
return DEFAULT_UARTCLK;
} }
static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv, static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
@ -332,7 +414,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
unsigned int dll, dlm, lcr; unsigned int dll, dlm, lcr;
int div; int div;
div = DIV_ROUND_CLOSEST(priv->base_baud / 16, baud); div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud);
if (div < 0 || USHRT_MAX <= div) { if (div < 0 || USHRT_MAX <= div) {
dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div); dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
return -EINVAL; return -EINVAL;
@ -442,8 +524,9 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
{ {
priv->dmsr = 0; unsigned int msr = ioread8(priv->membase + UART_MSR);
return get_msr(priv, priv->membase); priv->dmsr = msr & PCH_UART_MSR_DELTA;
return (u8)msr;
} }
static void pch_uart_hal_write(struct eg20t_port *priv, static void pch_uart_hal_write(struct eg20t_port *priv,
@ -524,7 +607,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
{ {
int ret; int ret = 0;
struct uart_port *port = &priv->port; struct uart_port *port = &priv->port;
if (port->x_char) { if (port->x_char) {
@ -533,8 +616,6 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
buf[0] = port->x_char; buf[0] = port->x_char;
port->x_char = 0; port->x_char = 0;
ret = 1; ret = 1;
} else {
ret = 0;
} }
return ret; return ret;
@ -1032,14 +1113,12 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
static unsigned int pch_uart_tx_empty(struct uart_port *port) static unsigned int pch_uart_tx_empty(struct uart_port *port)
{ {
struct eg20t_port *priv; struct eg20t_port *priv;
int ret;
priv = container_of(port, struct eg20t_port, port); priv = container_of(port, struct eg20t_port, port);
if (priv->tx_empty) if (priv->tx_empty)
ret = TIOCSER_TEMT; return TIOCSER_TEMT;
else else
ret = 0; return 0;
return ret;
} }
/* Returns the current state of modem control inputs. */ /* Returns the current state of modem control inputs. */
@ -1153,9 +1232,9 @@ static int pch_uart_startup(struct uart_port *port)
priv->tx_empty = 1; priv->tx_empty = 1;
if (port->uartclk) if (port->uartclk)
priv->base_baud = port->uartclk; priv->uartclk = port->uartclk;
else else
port->uartclk = priv->base_baud; port->uartclk = priv->uartclk;
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
ret = pch_uart_hal_set_line(priv, default_baud, ret = pch_uart_hal_set_line(priv, default_baud,
@ -1273,9 +1352,8 @@ static void pch_uart_set_termios(struct uart_port *port,
else else
parity = PCH_UART_HAL_PARITY_EVEN; parity = PCH_UART_HAL_PARITY_EVEN;
} else { } else
parity = PCH_UART_HAL_PARITY_NONE; parity = PCH_UART_HAL_PARITY_NONE;
}
/* Only UART0 has auto hardware flow function */ /* Only UART0 has auto hardware flow function */
if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256)) if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
@ -1447,7 +1525,6 @@ static void
pch_console_write(struct console *co, const char *s, unsigned int count) pch_console_write(struct console *co, const char *s, unsigned int count)
{ {
struct eg20t_port *priv; struct eg20t_port *priv;
unsigned long flags; unsigned long flags;
u8 ier; u8 ier;
int locked = 1; int locked = 1;
@ -1489,7 +1566,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
static int __init pch_console_setup(struct console *co, char *options) static int __init pch_console_setup(struct console *co, char *options)
{ {
struct uart_port *port; struct uart_port *port;
int baud = 9600; int baud = default_baud;
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
int flow = 'n'; int flow = 'n';
@ -1506,8 +1583,7 @@ static int __init pch_console_setup(struct console *co, char *options)
if (!port || (!port->iobase && !port->membase)) if (!port || (!port->iobase && !port->membase))
return -ENODEV; return -ENODEV;
/* setup uartclock */ port->uartclk = pch_uart_get_uartclk();
port->uartclk = DEFAULT_BAUD_RATE;
if (options) if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow); uart_parse_options(options, &baud, &parity, &bits, &flow);
@ -1550,10 +1626,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
unsigned int iobase; unsigned int iobase;
unsigned int mapbase; unsigned int mapbase;
unsigned char *rxbuf; unsigned char *rxbuf;
int fifosize, base_baud; int fifosize;
int port_type; int port_type;
struct pch_uart_driver_data *board; struct pch_uart_driver_data *board;
const char *board_name; char name[32]; /* for debugfs file name */
board = &drv_dat[id->driver_data]; board = &drv_dat[id->driver_data];
port_type = board->port_type; port_type = board->port_type;
@ -1566,13 +1642,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (!rxbuf) if (!rxbuf)
goto init_port_free_txbuf; goto init_port_free_txbuf;
base_baud = DEFAULT_BAUD_RATE;
/* quirk for CM-iTC board */
board_name = dmi_get_system_info(DMI_BOARD_NAME);
if (board_name && strstr(board_name, "CM-iTC"))
base_baud = 192000000; /* 192.0MHz */
switch (port_type) { switch (port_type) {
case PORT_UNKNOWN: case PORT_UNKNOWN:
fifosize = 256; /* EG20T/ML7213: UART0 */ fifosize = 256; /* EG20T/ML7213: UART0 */
@ -1597,7 +1666,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
priv->rxbuf.size = PAGE_SIZE; priv->rxbuf.size = PAGE_SIZE;
priv->fifo_size = fifosize; priv->fifo_size = fifosize;
priv->base_baud = base_baud; priv->uartclk = pch_uart_get_uartclk();
priv->port_type = PORT_MAX_8250 + port_type + 1; priv->port_type = PORT_MAX_8250 + port_type + 1;
priv->port.dev = &pdev->dev; priv->port.dev = &pdev->dev;
priv->port.iobase = iobase; priv->port.iobase = iobase;
@ -1614,7 +1683,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
spin_lock_init(&priv->port.lock); spin_lock_init(&priv->port.lock);
pci_set_drvdata(pdev, priv); pci_set_drvdata(pdev, priv);
pch_uart_hal_request(pdev, fifosize, base_baud); priv->trigger_level = 1;
priv->fcr = 0;
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[board->line_no] = priv; pch_uart_ports[board->line_no] = priv;
@ -1623,6 +1693,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (ret < 0) if (ret < 0)
goto init_port_hal_free; goto init_port_hal_free;
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof(name), "uart%d_regs", board->line_no);
priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
NULL, priv, &port_regs_ops);
#endif
return priv; return priv;
init_port_hal_free: init_port_hal_free:
@ -1639,6 +1715,11 @@ init_port_alloc_err:
static void pch_uart_exit_port(struct eg20t_port *priv) static void pch_uart_exit_port(struct eg20t_port *priv)
{ {
#ifdef CONFIG_DEBUG_FS
if (priv->debugfs)
debugfs_remove(priv->debugfs);
#endif
uart_remove_one_port(&pch_uart_driver, &priv->port); uart_remove_one_port(&pch_uart_driver, &priv->port);
pci_set_drvdata(priv->pdev, NULL); pci_set_drvdata(priv->pdev, NULL);
free_page((unsigned long)priv->rxbuf.buf); free_page((unsigned long)priv->rxbuf.buf);
@ -1646,9 +1727,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
static void pch_uart_pci_remove(struct pci_dev *pdev) static void pch_uart_pci_remove(struct pci_dev *pdev)
{ {
struct eg20t_port *priv; struct eg20t_port *priv = pci_get_drvdata(pdev);
priv = (struct eg20t_port *)pci_get_drvdata(pdev);
pci_disable_msi(pdev); pci_disable_msi(pdev);
@ -1785,3 +1864,8 @@ module_exit(pch_uart_module_exit);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver");
module_param(default_baud, uint, S_IRUGO); module_param(default_baud, uint, S_IRUGO);
MODULE_PARM_DESC(default_baud,
"Default BAUD for initial driver state and console (default 9600)");
module_param(user_uartclk, uint, S_IRUGO);
MODULE_PARM_DESC(user_uartclk,
"Override UART default or board specific UART clock");

View File

@ -1506,7 +1506,7 @@ no_dma:
* fixed up interrupt info, but we use the device-tree directly * fixed up interrupt info, but we use the device-tree directly
* here due to early probing so we need the fixup too. * here due to early probing so we need the fixup too.
*/ */
if (uap->port.irq == NO_IRQ && if (uap->port.irq == 0 &&
np->parent && np->parent->parent && np->parent && np->parent->parent &&
of_device_is_compatible(np->parent->parent, "gatwick")) { of_device_is_compatible(np->parent->parent, "gatwick")) {
/* IRQs on gatwick are offset by 64 */ /* IRQs on gatwick are offset by 64 */

View File

@ -579,9 +579,9 @@ serial_pxa_pm(struct uart_port *port, unsigned int state,
struct uart_pxa_port *up = (struct uart_pxa_port *)port; struct uart_pxa_port *up = (struct uart_pxa_port *)port;
if (!state) if (!state)
clk_enable(up->clk); clk_prepare_enable(up->clk);
else else
clk_disable(up->clk); clk_disable_unprepare(up->clk);
} }
static void serial_pxa_release_port(struct uart_port *port) static void serial_pxa_release_port(struct uart_port *port)
@ -668,7 +668,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
struct uart_pxa_port *up = serial_pxa_ports[co->index]; struct uart_pxa_port *up = serial_pxa_ports[co->index];
unsigned int ier; unsigned int ier;
clk_enable(up->clk); clk_prepare_enable(up->clk);
/* /*
* First save the IER then disable the interrupts * First save the IER then disable the interrupts
@ -685,7 +685,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(up); wait_for_xmitr(up);
serial_out(up, UART_IER, ier); serial_out(up, UART_IER, ier);
clk_disable(up->clk); clk_disable_unprepare(up->clk);
} }
static int __init static int __init

View File

@ -1507,7 +1507,7 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
#endif #endif
#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \ #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
defined(CONFIG_CPU_S3C2443) defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = { static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
.info = &(struct s3c24xx_uart_info) { .info = &(struct s3c24xx_uart_info) {
.name = "Samsung S3C2440 UART", .name = "Samsung S3C2440 UART",

View File

@ -2230,7 +2230,6 @@ int uart_register_driver(struct uart_driver *drv)
drv->tty_driver = normal; drv->tty_driver = normal;
normal->owner = drv->owner;
normal->driver_name = drv->driver_name; normal->driver_name = drv->driver_name;
normal->name = drv->dev_name; normal->name = drv->dev_name;
normal->major = drv->major; normal->major = drv->major;

View File

@ -461,12 +461,12 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
struct tty_struct *tty; struct tty_struct *tty;
if (!port) { if (!port) {
printk(KERN_ERR "sn_receive_chars - port NULL so can't receieve\n"); printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
return; return;
} }
if (!port->sc_ops) { if (!port->sc_ops) {
printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receieve\n"); printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receive\n");
return; return;
} }

View File

@ -17,11 +17,11 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/sunserialcore.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/prom.h> #include <asm/prom.h>
#include "suncore.h"
static int sunserial_current_minor = 64; static int sunserial_current_minor = 64;

View File

@ -29,8 +29,7 @@
#endif #endif
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/sunserialcore.h>
#include "suncore.h"
#define CON_BREAK ((long)-1) #define CON_BREAK ((long)-1)
#define CON_HUP ((long)-2) #define CON_HUP ((long)-2)

View File

@ -43,8 +43,8 @@
#endif #endif
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/sunserialcore.h>
#include "suncore.h"
#include "sunsab.h" #include "sunsab.h"
struct uart_sunsab_port { struct uart_sunsab_port {

View File

@ -47,8 +47,7 @@
#endif #endif
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/sunserialcore.h>
#include "suncore.h"
/* We are on a NS PC87303 clocked with 24.0 MHz, which results /* We are on a NS PC87303 clocked with 24.0 MHz, which results
* in a UART clock of 1.8462 MHz. * in a UART clock of 1.8462 MHz.

View File

@ -43,8 +43,8 @@
#endif #endif
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/sunserialcore.h>
#include "suncore.h"
#include "sunzilog.h" #include "sunzilog.h"
/* On 32-bit sparcs we need to delay after register accesses /* On 32-bit sparcs we need to delay after register accesses
@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
#endif #endif
} }
static int zilog_irq = -1; static int zilog_irq;
static int __devinit zs_probe(struct platform_device *op) static int __devinit zs_probe(struct platform_device *op)
{ {
@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op)
rp = sunzilog_chip_regs[inst]; rp = sunzilog_chip_regs[inst];
if (zilog_irq == -1) if (!zilog_irq)
zilog_irq = op->archdata.irqs[0]; zilog_irq = op->archdata.irqs[0];
up = &sunzilog_port_table[inst * 2]; up = &sunzilog_port_table[inst * 2];
@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void)
if (err) if (err)
goto out_unregister_uart; goto out_unregister_uart;
if (zilog_irq != -1) { if (!zilog_irq) {
struct uart_sunzilog_port *up = sunzilog_irq_chain; struct uart_sunzilog_port *up = sunzilog_irq_chain;
err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED, err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
"zs", sunzilog_irq_chain); "zs", sunzilog_irq_chain);
@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void)
{ {
platform_driver_unregister(&zs_driver); platform_driver_unregister(&zs_driver);
if (zilog_irq != -1) { if (!zilog_irq) {
struct uart_sunzilog_port *up = sunzilog_irq_chain; struct uart_sunzilog_port *up = sunzilog_irq_chain;
/* Disable Interrupts */ /* Disable Interrupts */
@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void)
} }
free_irq(zilog_irq, sunzilog_irq_chain); free_irq(zilog_irq, sunzilog_irq_chain);
zilog_irq = -1; zilog_irq = 0;
} }
if (sunzilog_reg.nr) { if (sunzilog_reg.nr) {

View File

@ -1360,7 +1360,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
} }
qe_port->port.irq = irq_of_parse_and_map(np, 0); qe_port->port.irq = irq_of_parse_and_map(np, 0);
if (qe_port->port.irq == NO_IRQ) { if (qe_port->port.irq == 0) {
dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
qe_port->ucc_num + 1); qe_port->ucc_num + 1);
ret = -EINVAL; ret = -EINVAL;

View File

@ -61,7 +61,7 @@
static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = { static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
[0 ... SIU_PORTS_MAX-1] = { [0 ... SIU_PORTS_MAX-1] = {
.lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock), .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
.irq = -1, .irq = 0,
}, },
}; };
@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port)
{ {
if (port->line == 0) if (port->line == 0)
return PORT_VR41XX_SIU; return PORT_VR41XX_SIU;
if (port->line == 1 && port->irq != -1) if (port->line == 1 && port->irq)
return PORT_VR41XX_DSIU; return PORT_VR41XX_DSIU;
return PORT_UNKNOWN; return PORT_UNKNOWN;

View File

@ -544,7 +544,7 @@ static struct uart_driver vt8500_uart_driver = {
.cons = VT8500_CONSOLE, .cons = VT8500_CONSOLE,
}; };
static int __init vt8500_serial_probe(struct platform_device *pdev) static int __devinit vt8500_serial_probe(struct platform_device *pdev)
{ {
struct vt8500_port *vt8500_port; struct vt8500_port *vt8500_port;
struct resource *mmres, *irqres; struct resource *mmres, *irqres;
@ -605,7 +605,7 @@ static int __devexit vt8500_serial_remove(struct platform_device *pdev)
static struct platform_driver vt8500_platform_driver = { static struct platform_driver vt8500_platform_driver = {
.probe = vt8500_serial_probe, .probe = vt8500_serial_probe,
.remove = vt8500_serial_remove, .remove = __devexit_p(vt8500_serial_remove),
.driver = { .driver = {
.name = "vt8500_serial", .name = "vt8500_serial",
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -3381,7 +3381,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
/* verify range of specified line number */ /* verify range of specified line number */
line = tty->index; line = tty->index;
if ((line < 0) || (line >= mgsl_device_count)) { if (line >= mgsl_device_count) {
printk("%s(%d):mgsl_open with invalid line #%d.\n", printk("%s(%d):mgsl_open with invalid line #%d.\n",
__FILE__,__LINE__,line); __FILE__,__LINE__,line);
return -ENODEV; return -ENODEV;
@ -4333,7 +4333,6 @@ static int mgsl_init_tty(void)
if (!serial_driver) if (!serial_driver)
return -ENOMEM; return -ENOMEM;
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = "synclink"; serial_driver->driver_name = "synclink";
serial_driver->name = "ttySL"; serial_driver->name = "ttySL";
serial_driver->major = ttymajor; serial_driver->major = ttymajor;

View File

@ -654,7 +654,7 @@ static int open(struct tty_struct *tty, struct file *filp)
unsigned long flags; unsigned long flags;
line = tty->index; line = tty->index;
if ((line < 0) || (line >= slgt_device_count)) { if (line >= slgt_device_count) {
DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); DBGERR(("%s: open with invalid line #%d.\n", driver_name, line));
return -ENODEV; return -ENODEV;
} }
@ -3795,7 +3795,6 @@ static int __init slgt_init(void)
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = tty_driver_name; serial_driver->driver_name = tty_driver_name;
serial_driver->name = tty_dev_prefix; serial_driver->name = tty_dev_prefix;
serial_driver->major = ttymajor; serial_driver->major = ttymajor;

View File

@ -721,7 +721,7 @@ static int open(struct tty_struct *tty, struct file *filp)
unsigned long flags; unsigned long flags;
line = tty->index; line = tty->index;
if ((line < 0) || (line >= synclinkmp_device_count)) { if (line >= synclinkmp_device_count) {
printk("%s(%d): open with invalid line #%d.\n", printk("%s(%d): open with invalid line #%d.\n",
__FILE__,__LINE__,line); __FILE__,__LINE__,line);
return -ENODEV; return -ENODEV;
@ -3977,7 +3977,6 @@ static int __init synclinkmp_init(void)
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = "synclinkmp"; serial_driver->driver_name = "synclinkmp";
serial_driver->name = "ttySLM"; serial_driver->name = "ttySLM";
serial_driver->major = ttymajor; serial_driver->major = ttymajor;

View File

@ -110,11 +110,9 @@ static struct sysrq_key_op sysrq_SAK_op = {
#ifdef CONFIG_VT #ifdef CONFIG_VT
static void sysrq_handle_unraw(int key) static void sysrq_handle_unraw(int key)
{ {
struct kbd_struct *kbd = &kbd_table[fg_console]; vt_reset_unicode(fg_console);
if (kbd)
kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
} }
static struct sysrq_key_op sysrq_unraw_op = { static struct sysrq_key_op sysrq_unraw_op = {
.handler = sysrq_handle_unraw, .handler = sysrq_handle_unraw,
.help_msg = "unRaw", .help_msg = "unRaw",
@ -322,11 +320,16 @@ static void send_sig_all(int sig)
{ {
struct task_struct *p; struct task_struct *p;
read_lock(&tasklist_lock);
for_each_process(p) { for_each_process(p) {
if (p->mm && !is_global_init(p)) if (p->flags & PF_KTHREAD)
/* Not swapper, init nor kernel thread */ continue;
force_sig(sig, p); if (is_global_init(p))
continue;
force_sig(sig, p);
} }
read_unlock(&tasklist_lock);
} }
static void sysrq_handle_term(int key) static void sysrq_handle_term(int key)

View File

@ -1230,13 +1230,10 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
struct inode *inode, int idx) struct inode *inode, int idx)
{ {
struct tty_struct *tty;
if (driver->ops->lookup) if (driver->ops->lookup)
return driver->ops->lookup(driver, inode, idx); return driver->ops->lookup(driver, inode, idx);
tty = driver->ttys[idx]; return driver->ttys[idx];
return tty;
} }
/** /**
@ -1271,6 +1268,19 @@ int tty_init_termios(struct tty_struct *tty)
} }
EXPORT_SYMBOL_GPL(tty_init_termios); EXPORT_SYMBOL_GPL(tty_init_termios);
int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
{
int ret = tty_init_termios(tty);
if (ret)
return ret;
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[tty->index] = tty;
return 0;
}
EXPORT_SYMBOL_GPL(tty_standard_install);
/** /**
* tty_driver_install_tty() - install a tty entry in the driver * tty_driver_install_tty() - install a tty entry in the driver
* @driver: the driver for the tty * @driver: the driver for the tty
@ -1286,21 +1296,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios);
static int tty_driver_install_tty(struct tty_driver *driver, static int tty_driver_install_tty(struct tty_driver *driver,
struct tty_struct *tty) struct tty_struct *tty)
{ {
int idx = tty->index; return driver->ops->install ? driver->ops->install(driver, tty) :
int ret; tty_standard_install(driver, tty);
if (driver->ops->install) {
ret = driver->ops->install(driver, tty);
return ret;
}
if (tty_init_termios(tty) == 0) {
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[idx] = tty;
return 0;
}
return -ENOMEM;
} }
/** /**
@ -1351,7 +1348,6 @@ static int tty_reopen(struct tty_struct *tty)
tty->link->count++; tty->link->count++;
} }
tty->count++; tty->count++;
tty->driver = driver; /* N.B. why do this every time?? */
mutex_lock(&tty->ldisc_mutex); mutex_lock(&tty->ldisc_mutex);
WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
@ -1365,7 +1361,6 @@ static int tty_reopen(struct tty_struct *tty)
* @driver: tty driver we are opening a device on * @driver: tty driver we are opening a device on
* @idx: device index * @idx: device index
* @ret_tty: returned tty structure * @ret_tty: returned tty structure
* @first_ok: ok to open a new device (used by ptmx)
* *
* Prepare a tty device. This may not be a "new" clean device but * Prepare a tty device. This may not be a "new" clean device but
* could also be an active device. The pty drivers require special * could also be an active device. The pty drivers require special
@ -1385,18 +1380,11 @@ static int tty_reopen(struct tty_struct *tty)
* relaxed for the (most common) case of reopening a tty. * relaxed for the (most common) case of reopening a tty.
*/ */
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
int first_ok)
{ {
struct tty_struct *tty; struct tty_struct *tty;
int retval; int retval;
/* Check if pty master is being opened multiple times */
if (driver->subtype == PTY_TYPE_MASTER &&
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
return ERR_PTR(-EIO);
}
/* /*
* First time open is complex, especially for PTY devices. * First time open is complex, especially for PTY devices.
* This code guarantees that either everything succeeds and the * This code guarantees that either everything succeeds and the
@ -1950,7 +1938,7 @@ retry_open:
if (retval) if (retval)
tty = ERR_PTR(retval); tty = ERR_PTR(retval);
} else } else
tty = tty_init_dev(driver, index, 0); tty = tty_init_dev(driver, index);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
if (driver) if (driver)
@ -2941,7 +2929,6 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->session = NULL; tty->session = NULL;
tty->pgrp = NULL; tty->pgrp = NULL;
tty->overrun_time = jiffies; tty->overrun_time = jiffies;
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty); tty_buffer_init(tty);
mutex_init(&tty->termios_mutex); mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex); mutex_init(&tty->ldisc_mutex);
@ -3058,7 +3045,7 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
} }
EXPORT_SYMBOL(tty_unregister_device); EXPORT_SYMBOL(tty_unregister_device);
struct tty_driver *alloc_tty_driver(int lines) struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
{ {
struct tty_driver *driver; struct tty_driver *driver;
@ -3067,11 +3054,12 @@ struct tty_driver *alloc_tty_driver(int lines)
kref_init(&driver->kref); kref_init(&driver->kref);
driver->magic = TTY_DRIVER_MAGIC; driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines; driver->num = lines;
driver->owner = owner;
/* later we'll move allocation of tables here */ /* later we'll move allocation of tables here */
} }
return driver; return driver;
} }
EXPORT_SYMBOL(alloc_tty_driver); EXPORT_SYMBOL(__alloc_tty_driver);
static void destruct_tty_driver(struct kref *kref) static void destruct_tty_driver(struct kref *kref)
{ {

View File

@ -516,6 +516,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int err = 0, err1, i; int err = 0, err1, i;
struct uni_pagedir *p, *q; struct uni_pagedir *p, *q;
/* Save original vc_unipagdir_loc in case we allocate a new one */
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p->readonly) return -EIO; if (p->readonly) return -EIO;
@ -528,26 +529,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_clear_unimap(vc, NULL); err1 = con_clear_unimap(vc, NULL);
if (err1) return err1; if (err1) return err1;
/*
* Since refcount was > 1, con_clear_unimap() allocated a
* a new uni_pagedir for this vc. Re: p != q
*/
q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
for (i = 0, l = 0; i < 32; i++)
/*
* uni_pgdir is a 32*32*64 table with rows allocated
* when its first entry is added. The unicode value must
* still be incremented for empty rows. We are copying
* entries from "p" (old) to "q" (new).
*/
l = 0; /* unicode value */
for (i = 0; i < 32; i++)
if ((p1 = p->uni_pgdir[i])) if ((p1 = p->uni_pgdir[i]))
for (j = 0; j < 32; j++) for (j = 0; j < 32; j++)
if ((p2 = p1[j])) if ((p2 = p1[j])) {
for (k = 0; k < 64; k++, l++) for (k = 0; k < 64; k++, l++)
if (p2[k] != 0xffff) { if (p2[k] != 0xffff) {
/*
* Found one, copy entry for unicode
* l with fontpos value p2[k].
*/
err1 = con_insert_unipair(q, l, p2[k]); err1 = con_insert_unipair(q, l, p2[k]);
if (err1) { if (err1) {
p->refcount++; p->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)p; *vc->vc_uni_pagedir_loc = (unsigned long)p;
con_release_unimap(q); con_release_unimap(q);
kfree(q); kfree(q);
return err1; return err1;
} }
} }
p = q; } else {
} else if (p == dflt) /* Account for row of 64 empty entries */
l += 64;
}
else
/* Account for empty table */
l += 32 * 64;
/*
* Finished copying font table, set vc_uni_pagedir to new table
*/
p = q;
} else if (p == dflt) {
dflt = NULL; dflt = NULL;
}
/*
* Insert user specified unicode pairs into new table.
*/
while (ct--) { while (ct--) {
unsigned short unicode, fontpos; unsigned short unicode, fontpos;
__get_user(unicode, &list->unicode); __get_user(unicode, &list->unicode);
@ -557,11 +589,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
list++; list++;
} }
/*
* Merge with fontmaps of any other virtual consoles.
*/
if (con_unify_unimap(vc, p)) if (con_unify_unimap(vc, p))
return err; return err;
for (i = 0; i <= 3; i++) for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update all inverse translations */ set_inverse_transl(vc, p, i); /* Update inverse translations */
set_inverse_trans_unicode(vc, p); set_inverse_trans_unicode(vc, p);
return err; return err;

View File

@ -41,6 +41,7 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/uaccess.h>
#include <asm/irq_regs.h> #include <asm/irq_regs.h>
@ -55,8 +56,8 @@ extern void ctrl_alt_del(void);
/* /*
* Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
* This seems a good reason to start with NumLock off. On HIL keyboards * This seems a good reason to start with NumLock off. On HIL keyboards
* of PARISC machines however there is no NumLock key and everyone expects the keypad * of PARISC machines however there is no NumLock key and everyone expects the
* to be used for numbers. * keypad to be used for numbers.
*/ */
#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
@ -67,8 +68,6 @@ extern void ctrl_alt_del(void);
#define KBD_DEFLOCK 0 #define KBD_DEFLOCK 0
void compute_shiftstate(void);
/* /*
* Handler Tables. * Handler Tables.
*/ */
@ -99,35 +98,29 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
* Variables exported for vt_ioctl.c * Variables exported for vt_ioctl.c
*/ */
/* maximum values each key_handler can handle */
const int max_vals[] = {
255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
255, NR_LOCK - 1, 255, NR_BRL - 1
};
const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = { struct vt_spawn_console vt_spawn_con = {
.lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
.pid = NULL, .pid = NULL,
.sig = 0, .sig = 0,
}; };
/*
* Variables exported for vt.c
*/
int shift_state = 0;
/* /*
* Internal Data. * Internal Data.
*/ */
static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
/* maximum values each key_handler can handle */
static const int max_vals[] = {
255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
255, NR_LOCK - 1, 255, NR_BRL - 1
};
static const int NR_TYPES = ARRAY_SIZE(max_vals);
static struct input_handler kbd_handler; static struct input_handler kbd_handler;
static DEFINE_SPINLOCK(kbd_event_lock); static DEFINE_SPINLOCK(kbd_event_lock);
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
@ -137,6 +130,8 @@ static int npadch = -1; /* -1 or number assembled on pad */
static unsigned int diacr; static unsigned int diacr;
static char rep; /* flag telling character repeat */ static char rep; /* flag telling character repeat */
static int shift_state = 0;
static unsigned char ledstate = 0xff; /* undefined */ static unsigned char ledstate = 0xff; /* undefined */
static unsigned char ledioctl; static unsigned char ledioctl;
@ -187,7 +182,7 @@ static int getkeycode_helper(struct input_handle *handle, void *data)
return d->error == 0; /* stop as soon as we successfully get one */ return d->error == 0; /* stop as soon as we successfully get one */
} }
int getkeycode(unsigned int scancode) static int getkeycode(unsigned int scancode)
{ {
struct getset_keycode_data d = { struct getset_keycode_data d = {
.ke = { .ke = {
@ -214,7 +209,7 @@ static int setkeycode_helper(struct input_handle *handle, void *data)
return d->error == 0; /* stop as soon as we successfully set one */ return d->error == 0; /* stop as soon as we successfully set one */
} }
int setkeycode(unsigned int scancode, unsigned int keycode) static int setkeycode(unsigned int scancode, unsigned int keycode)
{ {
struct getset_keycode_data d = { struct getset_keycode_data d = {
.ke = { .ke = {
@ -382,9 +377,11 @@ static void to_utf8(struct vc_data *vc, uint c)
/* /*
* Called after returning from RAW mode or when changing consoles - recompute * Called after returning from RAW mode or when changing consoles - recompute
* shift_down[] and shift_state from key_down[] maybe called when keymap is * shift_down[] and shift_state from key_down[] maybe called when keymap is
* undefined, so that shiftkey release is seen * undefined, so that shiftkey release is seen. The caller must hold the
* kbd_event_lock.
*/ */
void compute_shiftstate(void)
static void do_compute_shiftstate(void)
{ {
unsigned int i, j, k, sym, val; unsigned int i, j, k, sym, val;
@ -417,6 +414,15 @@ void compute_shiftstate(void)
} }
} }
/* We still have to export this method to vt.c */
void compute_shiftstate(void)
{
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
do_compute_shiftstate();
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/* /*
* We have a combining character DIACR here, followed by the character CH. * We have a combining character DIACR here, followed by the character CH.
* If the combination occurs in the table, return the corresponding value. * If the combination occurs in the table, return the corresponding value.
@ -636,7 +642,7 @@ static void fn_SAK(struct vc_data *vc)
static void fn_null(struct vc_data *vc) static void fn_null(struct vc_data *vc)
{ {
compute_shiftstate(); do_compute_shiftstate();
} }
/* /*
@ -989,6 +995,8 @@ unsigned char getledstate(void)
void setledstate(struct kbd_struct *kbd, unsigned int led) void setledstate(struct kbd_struct *kbd, unsigned int led)
{ {
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
if (!(led & ~7)) { if (!(led & ~7)) {
ledioctl = led; ledioctl = led;
kbd->ledmode = LED_SHOW_IOCTL; kbd->ledmode = LED_SHOW_IOCTL;
@ -996,6 +1004,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
kbd->ledmode = LED_SHOW_FLAGS; kbd->ledmode = LED_SHOW_FLAGS;
set_leds(); set_leds();
spin_unlock_irqrestore(&kbd_event_lock, flags);
} }
static inline unsigned char getleds(void) static inline unsigned char getleds(void)
@ -1035,6 +1044,75 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
return 0; return 0;
} }
/**
* vt_get_leds - helper for braille console
* @console: console to read
* @flag: flag we want to check
*
* Check the status of a keyboard led flag and report it back
*/
int vt_get_leds(int console, int flag)
{
unsigned long flags;
struct kbd_struct * kbd = kbd_table + console;
int ret;
spin_lock_irqsave(&kbd_event_lock, flags);
ret = vc_kbd_led(kbd, flag);
spin_unlock_irqrestore(&kbd_event_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(vt_get_leds);
/**
* vt_set_led_state - set LED state of a console
* @console: console to set
* @leds: LED bits
*
* Set the LEDs on a console. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
*/
void vt_set_led_state(int console, int leds)
{
struct kbd_struct * kbd = kbd_table + console;
setledstate(kbd, leds);
}
/**
* vt_kbd_con_start - Keyboard side of console start
* @console: console
*
* Handle console start. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
*/
void vt_kbd_con_start(int console)
{
struct kbd_struct * kbd = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
clr_vc_kbd_led(kbd, VC_SCROLLOCK);
set_leds();
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
* vt_kbd_con_stop - Keyboard side of console stop
* @console: console
*
* Handle console stop. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
*/
void vt_kbd_con_stop(int console)
{
struct kbd_struct * kbd = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
set_vc_kbd_led(kbd, VC_SCROLLOCK);
set_leds();
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/* /*
* This is the tasklet that updates LED state on all keyboards * This is the tasklet that updates LED state on all keyboards
* attached to the box. The reason we use tasklet is that we * attached to the box. The reason we use tasklet is that we
@ -1254,7 +1332,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (rc == NOTIFY_STOP || !key_map) { if (rc == NOTIFY_STOP || !key_map) {
atomic_notifier_call_chain(&keyboard_notifier_list, atomic_notifier_call_chain(&keyboard_notifier_list,
KBD_UNBOUND_KEYCODE, &param); KBD_UNBOUND_KEYCODE, &param);
compute_shiftstate(); do_compute_shiftstate();
kbd->slockstate = 0; kbd->slockstate = 0;
return; return;
} }
@ -1404,14 +1482,14 @@ static void kbd_start(struct input_handle *handle)
static const struct input_device_id kbd_ids[] = { static const struct input_device_id kbd_ids[] = {
{ {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT, .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_KEY) }, .evbit = { BIT_MASK(EV_KEY) },
}, },
{ {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT, .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_SND) }, .evbit = { BIT_MASK(EV_SND) },
}, },
{ }, /* Terminating entry */ { }, /* Terminating entry */
}; };
@ -1433,7 +1511,7 @@ int __init kbd_init(void)
int i; int i;
int error; int error;
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd_table[i].ledflagstate = KBD_DEFLEDS; kbd_table[i].ledflagstate = KBD_DEFLEDS;
kbd_table[i].default_ledflagstate = KBD_DEFLEDS; kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
kbd_table[i].ledmode = LED_SHOW_FLAGS; kbd_table[i].ledmode = LED_SHOW_FLAGS;
@ -1452,3 +1530,658 @@ int __init kbd_init(void)
return 0; return 0;
} }
/* Ioctl support code */
/**
* vt_do_diacrit - diacritical table updates
* @cmd: ioctl request
* @up: pointer to user data for ioctl
* @perm: permissions check computed by caller
*
* Update the diacritical tables atomically and safely. Lock them
* against simultaneous keypresses
*/
int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
{
struct kbdiacrs __user *a = up;
unsigned long flags;
int asize;
int ret = 0;
switch (cmd) {
case KDGKBDIACR:
{
struct kbdiacr *diacr;
int i;
diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
GFP_KERNEL);
if (diacr == NULL)
return -ENOMEM;
/* Lock the diacriticals table, make a copy and then
copy it after we unlock */
spin_lock_irqsave(&kbd_event_lock, flags);
asize = accent_table_size;
for (i = 0; i < asize; i++) {
diacr[i].diacr = conv_uni_to_8bit(
accent_table[i].diacr);
diacr[i].base = conv_uni_to_8bit(
accent_table[i].base);
diacr[i].result = conv_uni_to_8bit(
accent_table[i].result);
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt))
ret = -EFAULT;
else if (copy_to_user(a->kbdiacr, diacr,
asize * sizeof(struct kbdiacr)))
ret = -EFAULT;
kfree(diacr);
return ret;
}
case KDGKBDIACRUC:
{
struct kbdiacrsuc __user *a = up;
void *buf;
buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc),
GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
/* Lock the diacriticals table, make a copy and then
copy it after we unlock */
spin_lock_irqsave(&kbd_event_lock, flags);
asize = accent_table_size;
memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt))
ret = -EFAULT;
else if (copy_to_user(a->kbdiacruc, buf,
asize*sizeof(struct kbdiacruc)))
ret = -EFAULT;
kfree(buf);
return ret;
}
case KDSKBDIACR:
{
struct kbdiacrs __user *a = up;
struct kbdiacr *diacr = NULL;
unsigned int ct;
int i;
if (!perm)
return -EPERM;
if (get_user(ct, &a->kb_cnt))
return -EFAULT;
if (ct >= MAX_DIACR)
return -EINVAL;
if (ct) {
diacr = kmalloc(sizeof(struct kbdiacr) * ct,
GFP_KERNEL);
if (diacr == NULL)
return -ENOMEM;
if (copy_from_user(diacr, a->kbdiacr,
sizeof(struct kbdiacr) * ct)) {
kfree(diacr);
return -EFAULT;
}
}
spin_lock_irqsave(&kbd_event_lock, flags);
accent_table_size = ct;
for (i = 0; i < ct; i++) {
accent_table[i].diacr =
conv_8bit_to_uni(diacr[i].diacr);
accent_table[i].base =
conv_8bit_to_uni(diacr[i].base);
accent_table[i].result =
conv_8bit_to_uni(diacr[i].result);
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(diacr);
return 0;
}
case KDSKBDIACRUC:
{
struct kbdiacrsuc __user *a = up;
unsigned int ct;
void *buf = NULL;
if (!perm)
return -EPERM;
if (get_user(ct, &a->kb_cnt))
return -EFAULT;
if (ct >= MAX_DIACR)
return -EINVAL;
if (ct) {
buf = kmalloc(ct * sizeof(struct kbdiacruc),
GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if (copy_from_user(buf, a->kbdiacruc,
ct * sizeof(struct kbdiacruc))) {
kfree(buf);
return -EFAULT;
}
}
spin_lock_irqsave(&kbd_event_lock, flags);
if (ct)
memcpy(accent_table, buf,
ct * sizeof(struct kbdiacruc));
accent_table_size = ct;
spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(buf);
return 0;
}
}
return ret;
}
/**
* vt_do_kdskbmode - set keyboard mode ioctl
* @console: the console to use
* @arg: the requested mode
*
* Update the keyboard mode bits while holding the correct locks.
* Return 0 for success or an error code.
*/
int vt_do_kdskbmode(int console, unsigned int arg)
{
struct kbd_struct * kbd = kbd_table + console;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
switch(arg) {
case K_RAW:
kbd->kbdmode = VC_RAW;
break;
case K_MEDIUMRAW:
kbd->kbdmode = VC_MEDIUMRAW;
break;
case K_XLATE:
kbd->kbdmode = VC_XLATE;
do_compute_shiftstate();
break;
case K_UNICODE:
kbd->kbdmode = VC_UNICODE;
do_compute_shiftstate();
break;
case K_OFF:
kbd->kbdmode = VC_OFF;
break;
default:
ret = -EINVAL;
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
return ret;
}
/**
* vt_do_kdskbmeta - set keyboard meta state
* @console: the console to use
* @arg: the requested meta state
*
* Update the keyboard meta bits while holding the correct locks.
* Return 0 for success or an error code.
*/
int vt_do_kdskbmeta(int console, unsigned int arg)
{
struct kbd_struct * kbd = kbd_table + console;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
switch(arg) {
case K_METABIT:
clr_vc_kbd_mode(kbd, VC_META);
break;
case K_ESCPREFIX:
set_vc_kbd_mode(kbd, VC_META);
break;
default:
ret = -EINVAL;
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
return ret;
}
int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
int perm)
{
struct kbkeycode tmp;
int kc = 0;
if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
return -EFAULT;
switch (cmd) {
case KDGETKEYCODE:
kc = getkeycode(tmp.scancode);
if (kc >= 0)
kc = put_user(kc, &user_kbkc->keycode);
break;
case KDSETKEYCODE:
if (!perm)
return -EPERM;
kc = setkeycode(tmp.scancode, tmp.keycode);
break;
}
return kc;
}
#define i (tmp.kb_index)
#define s (tmp.kb_table)
#define v (tmp.kb_value)
int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
int console)
{
struct kbd_struct * kbd = kbd_table + console;
struct kbentry tmp;
ushort *key_map, *new_map, val, ov;
unsigned long flags;
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
return -EFAULT;
if (!capable(CAP_SYS_TTY_CONFIG))
perm = 0;
switch (cmd) {
case KDGKBENT:
/* Ensure another thread doesn't free it under us */
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[s];
if (key_map) {
val = U(key_map[i]);
if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
val = K_HOLE;
} else
val = (i ? K_HOLE : K_NOSUCHMAP);
spin_unlock_irqrestore(&kbd_event_lock, flags);
return put_user(val, &user_kbe->kb_value);
case KDSKBENT:
if (!perm)
return -EPERM;
if (!i && v == K_NOSUCHMAP) {
spin_lock_irqsave(&kbd_event_lock, flags);
/* deallocate map */
key_map = key_maps[s];
if (s && key_map) {
key_maps[s] = NULL;
if (key_map[0] == U(K_ALLOCATED)) {
kfree(key_map);
keymap_count--;
}
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
break;
}
if (KTYP(v) < NR_TYPES) {
if (KVAL(v) > max_vals[KTYP(v)])
return -EINVAL;
} else
if (kbd->kbdmode != VC_UNICODE)
return -EINVAL;
/* ++Geert: non-PC keyboards may generate keycode zero */
#if !defined(__mc68000__) && !defined(__powerpc__)
/* assignment to entry 0 only tests validity of args */
if (!i)
break;
#endif
new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
if (!new_map)
return -ENOMEM;
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[s];
if (key_map == NULL) {
int j;
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
!capable(CAP_SYS_RESOURCE)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
kfree(new_map);
return -EPERM;
}
key_maps[s] = new_map;
key_map = new_map;
key_map[0] = U(K_ALLOCATED);
for (j = 1; j < NR_KEYS; j++)
key_map[j] = U(K_HOLE);
keymap_count++;
} else
kfree(new_map);
ov = U(key_map[i]);
if (v == ov)
goto out;
/*
* Attention Key.
*/
if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
return -EPERM;
}
key_map[i] = U(v);
if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
do_compute_shiftstate();
out:
spin_unlock_irqrestore(&kbd_event_lock, flags);
break;
}
return 0;
}
#undef i
#undef s
#undef v
/* FIXME: This one needs untangling and locking */
int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
{
struct kbsentry *kbs;
char *p;
u_char *q;
u_char __user *up;
int sz;
int delta;
char *first_free, *fj, *fnw;
int i, j, k;
int ret;
if (!capable(CAP_SYS_TTY_CONFIG))
perm = 0;
kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
if (!kbs) {
ret = -ENOMEM;
goto reterr;
}
/* we mostly copy too much here (512bytes), but who cares ;) */
if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
ret = -EFAULT;
goto reterr;
}
kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
i = kbs->kb_func;
switch (cmd) {
case KDGKBSENT:
sz = sizeof(kbs->kb_string) - 1; /* sz should have been
a struct member */
up = user_kdgkb->kb_string;
p = func_table[i];
if(p)
for ( ; *p && sz; p++, sz--)
if (put_user(*p, up++)) {
ret = -EFAULT;
goto reterr;
}
if (put_user('\0', up)) {
ret = -EFAULT;
goto reterr;
}
kfree(kbs);
return ((p && *p) ? -EOVERFLOW : 0);
case KDSKBSENT:
if (!perm) {
ret = -EPERM;
goto reterr;
}
q = func_table[i];
first_free = funcbufptr + (funcbufsize - funcbufleft);
for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
;
if (j < MAX_NR_FUNC)
fj = func_table[j];
else
fj = first_free;
delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
if (delta <= funcbufleft) { /* it fits in current buf */
if (j < MAX_NR_FUNC) {
memmove(fj + delta, fj, first_free - fj);
for (k = j; k < MAX_NR_FUNC; k++)
if (func_table[k])
func_table[k] += delta;
}
if (!q)
func_table[i] = fj;
funcbufleft -= delta;
} else { /* allocate a larger buffer */
sz = 256;
while (sz < funcbufsize - funcbufleft + delta)
sz <<= 1;
fnw = kmalloc(sz, GFP_KERNEL);
if(!fnw) {
ret = -ENOMEM;
goto reterr;
}
if (!q)
func_table[i] = fj;
if (fj > funcbufptr)
memmove(fnw, funcbufptr, fj - funcbufptr);
for (k = 0; k < j; k++)
if (func_table[k])
func_table[k] = fnw + (func_table[k] - funcbufptr);
if (first_free > fj) {
memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
for (k = j; k < MAX_NR_FUNC; k++)
if (func_table[k])
func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
}
if (funcbufptr != func_buf)
kfree(funcbufptr);
funcbufptr = fnw;
funcbufleft = funcbufleft - delta + sz - funcbufsize;
funcbufsize = sz;
}
strcpy(func_table[i], kbs->kb_string);
break;
}
ret = 0;
reterr:
kfree(kbs);
return ret;
}
int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
{
struct kbd_struct * kbd = kbd_table + console;
unsigned long flags;
unsigned char ucval;
switch(cmd) {
/* the ioctls below read/set the flags usually shown in the leds */
/* don't use them - they will go away without warning */
case KDGKBLED:
spin_lock_irqsave(&kbd_event_lock, flags);
ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
spin_unlock_irqrestore(&kbd_event_lock, flags);
return put_user(ucval, (char __user *)arg);
case KDSKBLED:
if (!perm)
return -EPERM;
if (arg & ~0x77)
return -EINVAL;
spin_lock_irqsave(&kbd_event_lock, flags);
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
spin_unlock_irqrestore(&kbd_event_lock, flags);
break;
/* the ioctls below only set the lights, not the functions */
/* for those, see KDGKBLED and KDSKBLED above */
case KDGETLED:
ucval = getledstate();
return put_user(ucval, (char __user *)arg);
case KDSETLED:
if (!perm)
return -EPERM;
setledstate(kbd, arg);
return 0;
}
return -ENOIOCTLCMD;
}
int vt_do_kdgkbmode(int console)
{
struct kbd_struct * kbd = kbd_table + console;
/* This is a spot read so needs no locking */
switch (kbd->kbdmode) {
case VC_RAW:
return K_RAW;
case VC_MEDIUMRAW:
return K_MEDIUMRAW;
case VC_UNICODE:
return K_UNICODE;
case VC_OFF:
return K_OFF;
default:
return K_XLATE;
}
}
/**
* vt_do_kdgkbmeta - report meta status
* @console: console to report
*
* Report the meta flag status of this console
*/
int vt_do_kdgkbmeta(int console)
{
struct kbd_struct * kbd = kbd_table + console;
/* Again a spot read so no locking */
return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT;
}
/**
* vt_reset_unicode - reset the unicode status
* @console: console being reset
*
* Restore the unicode console state to its default
*/
void vt_reset_unicode(int console)
{
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
* vt_get_shiftstate - shift bit state
*
* Report the shift bits from the keyboard state. We have to export
* this to support some oddities in the vt layer.
*/
int vt_get_shift_state(void)
{
/* Don't lock as this is a transient report */
return shift_state;
}
/**
* vt_reset_keyboard - reset keyboard state
* @console: console to reset
*
* Reset the keyboard bits for a console as part of a general console
* reset event
*/
void vt_reset_keyboard(int console)
{
struct kbd_struct * kbd = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
set_vc_kbd_mode(kbd, VC_REPEAT);
clr_vc_kbd_mode(kbd, VC_CKMODE);
clr_vc_kbd_mode(kbd, VC_APPLIC);
clr_vc_kbd_mode(kbd, VC_CRLF);
kbd->lockstate = 0;
kbd->slockstate = 0;
kbd->ledmode = LED_SHOW_FLAGS;
kbd->ledflagstate = kbd->default_ledflagstate;
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
* vt_get_kbd_mode_bit - read keyboard status bits
* @console: console to read from
* @bit: mode bit to read
*
* Report back a vt mode bit. We do this without locking so the
* caller must be sure that there are no synchronization needs
*/
int vt_get_kbd_mode_bit(int console, int bit)
{
struct kbd_struct * kbd = kbd_table + console;
return vc_kbd_mode(kbd, bit);
}
/**
* vt_set_kbd_mode_bit - read keyboard status bits
* @console: console to read from
* @bit: mode bit to read
*
* Set a vt mode bit. We do this without locking so the
* caller must be sure that there are no synchronization needs
*/
void vt_set_kbd_mode_bit(int console, int bit)
{
struct kbd_struct * kbd = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
set_vc_kbd_mode(kbd, bit);
spin_unlock_irqrestore(&kbd_event_lock, flags);
}
/**
* vt_clr_kbd_mode_bit - read keyboard status bits
* @console: console to read from
* @bit: mode bit to read
*
* Report back a vt mode bit. We do this without locking so the
* caller must be sure that there are no synchronization needs
*/
void vt_clr_kbd_mode_bit(int console, int bit)
{
struct kbd_struct * kbd = kbd_table + console;
unsigned long flags;
spin_lock_irqsave(&kbd_event_lock, flags);
clr_vc_kbd_mode(kbd, bit);
spin_unlock_irqrestore(&kbd_event_lock, flags);
}

View File

@ -30,6 +30,7 @@
extern void poke_blanked_console(void); extern void poke_blanked_console(void);
/* FIXME: all this needs locking */
/* Variables for selection control. */ /* Variables for selection control. */
/* Use a dynamic buffer, instead of static (Dec 1994) */ /* Use a dynamic buffer, instead of static (Dec 1994) */
struct vc_data *sel_cons; /* must not be deallocated */ struct vc_data *sel_cons; /* must not be deallocated */
@ -61,10 +62,14 @@ sel_pos(int n)
use_unicode); use_unicode);
} }
/* remove the current selection highlight, if any, /**
from the console holding the selection. */ * clear_selection - remove current selection
void *
clear_selection(void) { * Remove the current selection highlight, if any from the console
* holding the selection. The caller must hold the console lock.
*/
void clear_selection(void)
{
highlight_pointer(-1); /* hide the pointer */ highlight_pointer(-1); /* hide the pointer */
if (sel_start != -1) { if (sel_start != -1) {
highlight(sel_start, sel_end); highlight(sel_start, sel_end);
@ -74,7 +79,7 @@ clear_selection(void) {
/* /*
* User settable table: what characters are to be considered alphabetic? * User settable table: what characters are to be considered alphabetic?
* 256 bits * 256 bits. Locked by the console lock.
*/ */
static u32 inwordLut[8]={ static u32 inwordLut[8]={
0x00000000, /* control chars */ 0x00000000, /* control chars */
@ -91,10 +96,20 @@ static inline int inword(const u16 c) {
return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
} }
/* set inwordLut contents. Invoked by ioctl(). */ /**
* set loadlut - load the LUT table
* @p: user table
*
* Load the LUT table from user space. The caller must hold the console
* lock. Make a temporary copy so a partial update doesn't make a mess.
*/
int sel_loadlut(char __user *p) int sel_loadlut(char __user *p)
{ {
return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0; u32 tmplut[8];
if (copy_from_user(tmplut, (u32 __user *)(p+4), 32))
return -EFAULT;
memcpy(inwordLut, tmplut, 32);
return 0;
} }
/* does screen address p correspond to character at LH/RH edge of screen? */ /* does screen address p correspond to character at LH/RH edge of screen? */
@ -130,7 +145,16 @@ static int store_utf8(u16 c, char *p)
} }
} }
/* set the current selection. Invoked by ioctl() or by kernel code. */ /**
* set_selection - set the current selection.
* @sel: user selection info
* @tty: the console tty
*
* Invoked by the ioctl handle for the vt layer.
*
* The entire selection process is managed under the console_lock. It's
* a lot under the lock but its hardly a performance path
*/
int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
{ {
struct vc_data *vc = vc_cons[fg_console].d; struct vc_data *vc = vc_cons[fg_console].d;
@ -138,7 +162,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
char *bp, *obp; char *bp, *obp;
int i, ps, pe, multiplier; int i, ps, pe, multiplier;
u16 c; u16 c;
struct kbd_struct *kbd = kbd_table + fg_console; int mode;
poke_blanked_console(); poke_blanked_console();
@ -182,7 +206,11 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
clear_selection(); clear_selection();
sel_cons = vc_cons[fg_console].d; sel_cons = vc_cons[fg_console].d;
} }
use_unicode = kbd && kbd->kbdmode == VC_UNICODE; mode = vt_do_kdgkbmode(fg_console);
if (mode == K_UNICODE)
use_unicode = 1;
else
use_unicode = 0;
switch (sel_mode) switch (sel_mode)
{ {
@ -302,7 +330,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
* queue of the tty associated with the current console. * queue of the tty associated with the current console.
* Invoked by ioctl(). * Invoked by ioctl().
* *
* Locking: always called with BTM from vt_ioctl * Locking: called without locks. Calls the ldisc wrongly with
* unsafe methods,
*/ */
int paste_selection(struct tty_struct *tty) int paste_selection(struct tty_struct *tty)
{ {
@ -317,13 +346,12 @@ int paste_selection(struct tty_struct *tty)
poke_blanked_console(); poke_blanked_console();
console_unlock(); console_unlock();
/* FIXME: wtf is this supposed to achieve ? */
ld = tty_ldisc_ref(tty); ld = tty_ldisc_ref(tty);
if (!ld) { if (!ld)
tty_unlock();
ld = tty_ldisc_ref_wait(tty); ld = tty_ldisc_ref_wait(tty);
tty_lock();
}
/* FIXME: this is completely unsafe */
add_wait_queue(&vc->paste_wait, &wait); add_wait_queue(&vc->paste_wait, &wait);
while (sel_buffer && sel_buffer_lth > pasted) { while (sel_buffer && sel_buffer_lth > pasted) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);

View File

@ -608,10 +608,10 @@ vcs_open(struct inode *inode, struct file *filp)
unsigned int currcons = iminor(inode) & 127; unsigned int currcons = iminor(inode) & 127;
int ret = 0; int ret = 0;
tty_lock(); console_lock();
if(currcons && !vc_cons_allocated(currcons-1)) if(currcons && !vc_cons_allocated(currcons-1))
ret = -ENXIO; ret = -ENXIO;
tty_unlock(); console_unlock();
return ret; return ret;
} }

View File

@ -1028,9 +1028,9 @@ void vc_deallocate(unsigned int currcons)
* VT102 emulator * VT102 emulator
*/ */
#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) #define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x))
#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) #define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x))
#define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) #define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x))
#define decarm VC_REPEAT #define decarm VC_REPEAT
#define decckm VC_CKMODE #define decckm VC_CKMODE
@ -1652,16 +1652,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_deccm = global_cursor_default; vc->vc_deccm = global_cursor_default;
vc->vc_decim = 0; vc->vc_decim = 0;
set_kbd(vc, decarm); vt_reset_keyboard(vc->vc_num);
clr_kbd(vc, decckm);
clr_kbd(vc, kbdapplic);
clr_kbd(vc, lnm);
kbd_table[vc->vc_num].lockstate = 0;
kbd_table[vc->vc_num].slockstate = 0;
kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
vc->vc_cursor_type = cur_default; vc->vc_cursor_type = cur_default;
vc->vc_complement_mask = vc->vc_s_complement_mask; vc->vc_complement_mask = vc->vc_s_complement_mask;
@ -1979,7 +1970,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
case 'q': /* DECLL - but only 3 leds */ case 'q': /* DECLL - but only 3 leds */
/* map 0,1,2,3 to 0,1,2,4 */ /* map 0,1,2,3 to 0,1,2,4 */
if (vc->vc_par[0] < 4) if (vc->vc_par[0] < 4)
setledstate(kbd_table + vc->vc_num, vt_set_led_state(vc->vc_num,
(vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
return; return;
case 'r': case 'r':
@ -2632,7 +2623,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
console_unlock(); console_unlock();
break; break;
case TIOCL_SELLOADLUT: case TIOCL_SELLOADLUT:
console_lock();
ret = sel_loadlut(p); ret = sel_loadlut(p);
console_unlock();
break; break;
case TIOCL_GETSHIFTSTATE: case TIOCL_GETSHIFTSTATE:
@ -2642,15 +2635,19 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
* kernel-internal variable; programs not closely * kernel-internal variable; programs not closely
* related to the kernel should not use this. * related to the kernel should not use this.
*/ */
data = shift_state; data = vt_get_shift_state();
ret = __put_user(data, p); ret = __put_user(data, p);
break; break;
case TIOCL_GETMOUSEREPORTING: case TIOCL_GETMOUSEREPORTING:
console_lock(); /* May be overkill */
data = mouse_reporting(); data = mouse_reporting();
console_unlock();
ret = __put_user(data, p); ret = __put_user(data, p);
break; break;
case TIOCL_SETVESABLANK: case TIOCL_SETVESABLANK:
console_lock();
ret = set_vesa_blanking(p); ret = set_vesa_blanking(p);
console_unlock();
break; break;
case TIOCL_GETKMSGREDIRECT: case TIOCL_GETKMSGREDIRECT:
data = vt_get_kmsg_redirect(); data = vt_get_kmsg_redirect();
@ -2667,13 +2664,21 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
} }
break; break;
case TIOCL_GETFGCONSOLE: case TIOCL_GETFGCONSOLE:
/* No locking needed as this is a transiently
correct return anyway if the caller hasn't
disabled switching */
ret = fg_console; ret = fg_console;
break; break;
case TIOCL_SCROLLCONSOLE: case TIOCL_SCROLLCONSOLE:
if (get_user(lines, (s32 __user *)(p+4))) { if (get_user(lines, (s32 __user *)(p+4))) {
ret = -EFAULT; ret = -EFAULT;
} else { } else {
/* Need the console lock here. Note that lots
of other calls need fixing before the lock
is actually useful ! */
console_lock();
scrollfront(vc_cons[fg_console].d, lines); scrollfront(vc_cons[fg_console].d, lines);
console_unlock();
ret = 0; ret = 0;
} }
break; break;
@ -2753,8 +2758,7 @@ static void con_stop(struct tty_struct *tty)
console_num = tty->index; console_num = tty->index;
if (!vc_cons_allocated(console_num)) if (!vc_cons_allocated(console_num))
return; return;
set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); vt_kbd_con_stop(console_num);
set_leds();
} }
/* /*
@ -2768,8 +2772,7 @@ static void con_start(struct tty_struct *tty)
console_num = tty->index; console_num = tty->index;
if (!vc_cons_allocated(console_num)) if (!vc_cons_allocated(console_num))
return; return;
clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); vt_kbd_con_start(console_num);
set_leds();
} }
static void con_flush_chars(struct tty_struct *tty) static void con_flush_chars(struct tty_struct *tty)
@ -2991,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops)
console_driver = alloc_tty_driver(MAX_NR_CONSOLES); console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
if (!console_driver) if (!console_driver)
panic("Couldn't allocate console driver\n"); panic("Couldn't allocate console driver\n");
console_driver->owner = THIS_MODULE;
console_driver->name = "tty"; console_driver->name = "tty";
console_driver->name_base = 1; console_driver->name_base = 1;
console_driver->major = TTY_MAJOR; console_driver->major = TTY_MAJOR;
@ -3980,9 +3983,6 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
int rc = -EINVAL; int rc = -EINVAL;
int c; int c;
if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (op->data) { if (op->data) {
font.data = kmalloc(max_font_size, GFP_KERNEL); font.data = kmalloc(max_font_size, GFP_KERNEL);
if (!font.data) if (!font.data)
@ -3991,7 +3991,9 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
font.data = NULL; font.data = NULL;
console_lock(); console_lock();
if (vc->vc_sw->con_font_get) if (vc->vc_mode != KD_TEXT)
rc = -EINVAL;
else if (vc->vc_sw->con_font_get)
rc = vc->vc_sw->con_font_get(vc, &font); rc = vc->vc_sw->con_font_get(vc, &font);
else else
rc = -ENOSYS; rc = -ENOSYS;
@ -4073,7 +4075,9 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
if (IS_ERR(font.data)) if (IS_ERR(font.data))
return PTR_ERR(font.data); return PTR_ERR(font.data);
console_lock(); console_lock();
if (vc->vc_sw->con_font_set) if (vc->vc_mode != KD_TEXT)
rc = -EINVAL;
else if (vc->vc_sw->con_font_set)
rc = vc->vc_sw->con_font_set(vc, &font, op->flags); rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
else else
rc = -ENOSYS; rc = -ENOSYS;
@ -4089,8 +4093,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
char *s = name; char *s = name;
int rc; int rc;
if (vc->vc_mode != KD_TEXT)
return -EINVAL;
if (!op->data) if (!op->data)
s = NULL; s = NULL;
@ -4100,6 +4102,10 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
name[MAX_FONT_NAME - 1] = 0; name[MAX_FONT_NAME - 1] = 0;
console_lock(); console_lock();
if (vc->vc_mode != KD_TEXT) {
console_unlock();
return -EINVAL;
}
if (vc->vc_sw->con_font_default) if (vc->vc_sw->con_font_default)
rc = vc->vc_sw->con_font_default(vc, &font, s); rc = vc->vc_sw->con_font_default(vc, &font, s);
else else
@ -4117,11 +4123,11 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
int con = op->height; int con = op->height;
int rc; int rc;
if (vc->vc_mode != KD_TEXT)
return -EINVAL;
console_lock(); console_lock();
if (!vc->vc_sw->con_font_copy) if (vc->vc_mode != KD_TEXT)
rc = -EINVAL;
else if (!vc->vc_sw->con_font_copy)
rc = -ENOSYS; rc = -ENOSYS;
else if (con < 0 || !vc_cons_allocated(con)) else if (con < 0 || !vc_cons_allocated(con))
rc = -ENOTTY; rc = -ENOTTY;

View File

@ -130,7 +130,7 @@ static void vt_event_wait(struct vt_event_wait *vw)
list_add(&vw->list, &vt_events); list_add(&vw->list, &vt_events);
spin_unlock_irqrestore(&vt_event_lock, flags); spin_unlock_irqrestore(&vt_event_lock, flags);
/* Wait for it to pass */ /* Wait for it to pass */
wait_event_interruptible_tty(vt_event_waitqueue, vw->done); wait_event_interruptible(vt_event_waitqueue, vw->done);
/* Dequeue it */ /* Dequeue it */
spin_lock_irqsave(&vt_event_lock, flags); spin_lock_irqsave(&vt_event_lock, flags);
list_del(&vw->list); list_del(&vw->list);
@ -195,232 +195,7 @@ int vt_waitactive(int n)
#define GPLAST 0x3df #define GPLAST 0x3df
#define GPNUM (GPLAST - GPFIRST + 1) #define GPNUM (GPLAST - GPFIRST + 1)
#define i (tmp.kb_index)
#define s (tmp.kb_table)
#define v (tmp.kb_value)
static inline int
do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
{
struct kbentry tmp;
ushort *key_map, val, ov;
if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
return -EFAULT;
if (!capable(CAP_SYS_TTY_CONFIG))
perm = 0;
switch (cmd) {
case KDGKBENT:
key_map = key_maps[s];
if (key_map) {
val = U(key_map[i]);
if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
val = K_HOLE;
} else
val = (i ? K_HOLE : K_NOSUCHMAP);
return put_user(val, &user_kbe->kb_value);
case KDSKBENT:
if (!perm)
return -EPERM;
if (!i && v == K_NOSUCHMAP) {
/* deallocate map */
key_map = key_maps[s];
if (s && key_map) {
key_maps[s] = NULL;
if (key_map[0] == U(K_ALLOCATED)) {
kfree(key_map);
keymap_count--;
}
}
break;
}
if (KTYP(v) < NR_TYPES) {
if (KVAL(v) > max_vals[KTYP(v)])
return -EINVAL;
} else
if (kbd->kbdmode != VC_UNICODE)
return -EINVAL;
/* ++Geert: non-PC keyboards may generate keycode zero */
#if !defined(__mc68000__) && !defined(__powerpc__)
/* assignment to entry 0 only tests validity of args */
if (!i)
break;
#endif
if (!(key_map = key_maps[s])) {
int j;
if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
!capable(CAP_SYS_RESOURCE))
return -EPERM;
key_map = kmalloc(sizeof(plain_map),
GFP_KERNEL);
if (!key_map)
return -ENOMEM;
key_maps[s] = key_map;
key_map[0] = U(K_ALLOCATED);
for (j = 1; j < NR_KEYS; j++)
key_map[j] = U(K_HOLE);
keymap_count++;
}
ov = U(key_map[i]);
if (v == ov)
break; /* nothing to do */
/*
* Attention Key.
*/
if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
return -EPERM;
key_map[i] = U(v);
if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
compute_shiftstate();
break;
}
return 0;
}
#undef i
#undef s
#undef v
static inline int
do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
{
struct kbkeycode tmp;
int kc = 0;
if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
return -EFAULT;
switch (cmd) {
case KDGETKEYCODE:
kc = getkeycode(tmp.scancode);
if (kc >= 0)
kc = put_user(kc, &user_kbkc->keycode);
break;
case KDSETKEYCODE:
if (!perm)
return -EPERM;
kc = setkeycode(tmp.scancode, tmp.keycode);
break;
}
return kc;
}
static inline int
do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
{
struct kbsentry *kbs;
char *p;
u_char *q;
u_char __user *up;
int sz;
int delta;
char *first_free, *fj, *fnw;
int i, j, k;
int ret;
if (!capable(CAP_SYS_TTY_CONFIG))
perm = 0;
kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
if (!kbs) {
ret = -ENOMEM;
goto reterr;
}
/* we mostly copy too much here (512bytes), but who cares ;) */
if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
ret = -EFAULT;
goto reterr;
}
kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
i = kbs->kb_func;
switch (cmd) {
case KDGKBSENT:
sz = sizeof(kbs->kb_string) - 1; /* sz should have been
a struct member */
up = user_kdgkb->kb_string;
p = func_table[i];
if(p)
for ( ; *p && sz; p++, sz--)
if (put_user(*p, up++)) {
ret = -EFAULT;
goto reterr;
}
if (put_user('\0', up)) {
ret = -EFAULT;
goto reterr;
}
kfree(kbs);
return ((p && *p) ? -EOVERFLOW : 0);
case KDSKBSENT:
if (!perm) {
ret = -EPERM;
goto reterr;
}
q = func_table[i];
first_free = funcbufptr + (funcbufsize - funcbufleft);
for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
;
if (j < MAX_NR_FUNC)
fj = func_table[j];
else
fj = first_free;
delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
if (delta <= funcbufleft) { /* it fits in current buf */
if (j < MAX_NR_FUNC) {
memmove(fj + delta, fj, first_free - fj);
for (k = j; k < MAX_NR_FUNC; k++)
if (func_table[k])
func_table[k] += delta;
}
if (!q)
func_table[i] = fj;
funcbufleft -= delta;
} else { /* allocate a larger buffer */
sz = 256;
while (sz < funcbufsize - funcbufleft + delta)
sz <<= 1;
fnw = kmalloc(sz, GFP_KERNEL);
if(!fnw) {
ret = -ENOMEM;
goto reterr;
}
if (!q)
func_table[i] = fj;
if (fj > funcbufptr)
memmove(fnw, funcbufptr, fj - funcbufptr);
for (k = 0; k < j; k++)
if (func_table[k])
func_table[k] = fnw + (func_table[k] - funcbufptr);
if (first_free > fj) {
memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
for (k = j; k < MAX_NR_FUNC; k++)
if (func_table[k])
func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
}
if (funcbufptr != func_buf)
kfree(funcbufptr);
funcbufptr = fnw;
funcbufleft = funcbufleft - delta + sz - funcbufsize;
funcbufsize = sz;
}
strcpy(func_table[i], kbs->kb_string);
break;
}
ret = 0;
reterr:
kfree(kbs);
return ret;
}
static inline int static inline int
do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
@ -497,7 +272,6 @@ int vt_ioctl(struct tty_struct *tty,
{ {
struct vc_data *vc = tty->driver_data; struct vc_data *vc = tty->driver_data;
struct console_font_op op; /* used in multiple places here */ struct console_font_op op; /* used in multiple places here */
struct kbd_struct * kbd;
unsigned int console; unsigned int console;
unsigned char ucval; unsigned char ucval;
unsigned int uival; unsigned int uival;
@ -507,7 +281,6 @@ int vt_ioctl(struct tty_struct *tty,
console = vc->vc_num; console = vc->vc_num;
tty_lock();
if (!vc_cons_allocated(console)) { /* impossible? */ if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;
@ -523,19 +296,18 @@ int vt_ioctl(struct tty_struct *tty,
if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
perm = 1; perm = 1;
kbd = kbd_table + console;
switch (cmd) { switch (cmd) {
case TIOCLINUX: case TIOCLINUX:
ret = tioclinux(tty, arg); ret = tioclinux(tty, arg);
break; break;
case KIOCSOUND: case KIOCSOUND:
if (!perm) if (!perm)
goto eperm; return -EPERM;
/* /*
* The use of PIT_TICK_RATE is historic, it used to be * The use of PIT_TICK_RATE is historic, it used to be
* the platform-dependent CLOCK_TICK_RATE between 2.6.12 * the platform-dependent CLOCK_TICK_RATE between 2.6.12
* and 2.6.36, which was a minor but unfortunate ABI * and 2.6.36, which was a minor but unfortunate ABI
* change. * change. kd_mksound is locked by the input layer.
*/ */
if (arg) if (arg)
arg = PIT_TICK_RATE / arg; arg = PIT_TICK_RATE / arg;
@ -544,7 +316,7 @@ int vt_ioctl(struct tty_struct *tty,
case KDMKTONE: case KDMKTONE:
if (!perm) if (!perm)
goto eperm; return -EPERM;
{ {
unsigned int ticks, count; unsigned int ticks, count;
@ -562,10 +334,11 @@ int vt_ioctl(struct tty_struct *tty,
case KDGKBTYPE: case KDGKBTYPE:
/* /*
* this is naive. * this is naïve.
*/ */
ucval = KB_101; ucval = KB_101;
goto setchar; ret = put_user(ucval, (char __user *)arg);
break;
/* /*
* These cannot be implemented on any machine that implements * These cannot be implemented on any machine that implements
@ -579,6 +352,8 @@ int vt_ioctl(struct tty_struct *tty,
/* /*
* KDADDIO and KDDELIO may be able to add ports beyond what * KDADDIO and KDDELIO may be able to add ports beyond what
* we reject here, but to be safe... * we reject here, but to be safe...
*
* These are locked internally via sys_ioperm
*/ */
if (arg < GPFIRST || arg > GPLAST) { if (arg < GPFIRST || arg > GPLAST) {
ret = -EINVAL; ret = -EINVAL;
@ -601,7 +376,7 @@ int vt_ioctl(struct tty_struct *tty,
struct kbd_repeat kbrep; struct kbd_repeat kbrep;
if (!capable(CAP_SYS_TTY_CONFIG)) if (!capable(CAP_SYS_TTY_CONFIG))
goto eperm; return -EPERM;
if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
ret = -EFAULT; ret = -EFAULT;
@ -625,7 +400,7 @@ int vt_ioctl(struct tty_struct *tty,
* need to restore their engine state. --BenH * need to restore their engine state. --BenH
*/ */
if (!perm) if (!perm)
goto eperm; return -EPERM;
switch (arg) { switch (arg) {
case KD_GRAPHICS: case KD_GRAPHICS:
break; break;
@ -638,6 +413,7 @@ int vt_ioctl(struct tty_struct *tty,
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
/* FIXME: this needs the console lock extending */
if (vc->vc_mode == (unsigned char) arg) if (vc->vc_mode == (unsigned char) arg)
break; break;
vc->vc_mode = (unsigned char) arg; vc->vc_mode = (unsigned char) arg;
@ -669,69 +445,26 @@ int vt_ioctl(struct tty_struct *tty,
case KDSKBMODE: case KDSKBMODE:
if (!perm) if (!perm)
goto eperm; return -EPERM;
switch(arg) { ret = vt_do_kdskbmode(console, arg);
case K_RAW: if (ret == 0)
kbd->kbdmode = VC_RAW; tty_ldisc_flush(tty);
break;
case K_MEDIUMRAW:
kbd->kbdmode = VC_MEDIUMRAW;
break;
case K_XLATE:
kbd->kbdmode = VC_XLATE;
compute_shiftstate();
break;
case K_UNICODE:
kbd->kbdmode = VC_UNICODE;
compute_shiftstate();
break;
case K_OFF:
kbd->kbdmode = VC_OFF;
break;
default:
ret = -EINVAL;
goto out;
}
tty_ldisc_flush(tty);
break; break;
case KDGKBMODE: case KDGKBMODE:
switch (kbd->kbdmode) { uival = vt_do_kdgkbmode(console);
case VC_RAW: ret = put_user(uival, (int __user *)arg);
uival = K_RAW; break;
break;
case VC_MEDIUMRAW:
uival = K_MEDIUMRAW;
break;
case VC_UNICODE:
uival = K_UNICODE;
break;
case VC_OFF:
uival = K_OFF;
break;
default:
uival = K_XLATE;
break;
}
goto setint;
/* this could be folded into KDSKBMODE, but for compatibility /* this could be folded into KDSKBMODE, but for compatibility
reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
case KDSKBMETA: case KDSKBMETA:
switch(arg) { ret = vt_do_kdskbmeta(console, arg);
case K_METABIT:
clr_vc_kbd_mode(kbd, VC_META);
break;
case K_ESCPREFIX:
set_vc_kbd_mode(kbd, VC_META);
break;
default:
ret = -EINVAL;
}
break; break;
case KDGKBMETA: case KDGKBMETA:
uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); /* FIXME: should review whether this is worth locking */
uival = vt_do_kdgkbmeta(console);
setint: setint:
ret = put_user(uival, (int __user *)arg); ret = put_user(uival, (int __user *)arg);
break; break;
@ -740,133 +473,35 @@ int vt_ioctl(struct tty_struct *tty,
case KDSETKEYCODE: case KDSETKEYCODE:
if(!capable(CAP_SYS_TTY_CONFIG)) if(!capable(CAP_SYS_TTY_CONFIG))
perm = 0; perm = 0;
ret = do_kbkeycode_ioctl(cmd, up, perm); ret = vt_do_kbkeycode_ioctl(cmd, up, perm);
break; break;
case KDGKBENT: case KDGKBENT:
case KDSKBENT: case KDSKBENT:
ret = do_kdsk_ioctl(cmd, up, perm, kbd); ret = vt_do_kdsk_ioctl(cmd, up, perm, console);
break; break;
case KDGKBSENT: case KDGKBSENT:
case KDSKBSENT: case KDSKBSENT:
ret = do_kdgkb_ioctl(cmd, up, perm); ret = vt_do_kdgkb_ioctl(cmd, up, perm);
break; break;
/* Diacritical processing. Handled in keyboard.c as it has
to operate on the keyboard locks and structures */
case KDGKBDIACR: case KDGKBDIACR:
{
struct kbdiacrs __user *a = up;
struct kbdiacr diacr;
int i;
if (put_user(accent_table_size, &a->kb_cnt)) {
ret = -EFAULT;
break;
}
for (i = 0; i < accent_table_size; i++) {
diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
diacr.base = conv_uni_to_8bit(accent_table[i].base);
diacr.result = conv_uni_to_8bit(accent_table[i].result);
if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
ret = -EFAULT;
break;
}
}
break;
}
case KDGKBDIACRUC: case KDGKBDIACRUC:
{
struct kbdiacrsuc __user *a = up;
if (put_user(accent_table_size, &a->kb_cnt))
ret = -EFAULT;
else if (copy_to_user(a->kbdiacruc, accent_table,
accent_table_size*sizeof(struct kbdiacruc)))
ret = -EFAULT;
break;
}
case KDSKBDIACR: case KDSKBDIACR:
{
struct kbdiacrs __user *a = up;
struct kbdiacr diacr;
unsigned int ct;
int i;
if (!perm)
goto eperm;
if (get_user(ct,&a->kb_cnt)) {
ret = -EFAULT;
break;
}
if (ct >= MAX_DIACR) {
ret = -EINVAL;
break;
}
accent_table_size = ct;
for (i = 0; i < ct; i++) {
if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
ret = -EFAULT;
break;
}
accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
accent_table[i].base = conv_8bit_to_uni(diacr.base);
accent_table[i].result = conv_8bit_to_uni(diacr.result);
}
break;
}
case KDSKBDIACRUC: case KDSKBDIACRUC:
{ ret = vt_do_diacrit(cmd, up, perm);
struct kbdiacrsuc __user *a = up;
unsigned int ct;
if (!perm)
goto eperm;
if (get_user(ct,&a->kb_cnt)) {
ret = -EFAULT;
break;
}
if (ct >= MAX_DIACR) {
ret = -EINVAL;
break;
}
accent_table_size = ct;
if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
ret = -EFAULT;
break; break;
}
/* the ioctls below read/set the flags usually shown in the leds */ /* the ioctls below read/set the flags usually shown in the leds */
/* don't use them - they will go away without warning */ /* don't use them - they will go away without warning */
case KDGKBLED: case KDGKBLED:
ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
goto setchar;
case KDSKBLED: case KDSKBLED:
if (!perm)
goto eperm;
if (arg & ~0x77) {
ret = -EINVAL;
break;
}
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
break;
/* the ioctls below only set the lights, not the functions */
/* for those, see KDGKBLED and KDSKBLED above */
case KDGETLED: case KDGETLED:
ucval = getledstate();
setchar:
ret = put_user(ucval, (char __user *)arg);
break;
case KDSETLED: case KDSETLED:
if (!perm) ret = vt_do_kdskled(console, cmd, arg, perm);
goto eperm;
setledstate(kbd, arg);
break; break;
/* /*
@ -879,7 +514,7 @@ int vt_ioctl(struct tty_struct *tty,
case KDSIGACCEPT: case KDSIGACCEPT:
{ {
if (!perm || !capable(CAP_KILL)) if (!perm || !capable(CAP_KILL))
goto eperm; return -EPERM;
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
ret = -EINVAL; ret = -EINVAL;
else { else {
@ -897,7 +532,7 @@ int vt_ioctl(struct tty_struct *tty,
struct vt_mode tmp; struct vt_mode tmp;
if (!perm) if (!perm)
goto eperm; return -EPERM;
if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
@ -943,6 +578,7 @@ int vt_ioctl(struct tty_struct *tty,
struct vt_stat __user *vtstat = up; struct vt_stat __user *vtstat = up;
unsigned short state, mask; unsigned short state, mask;
/* Review: FIXME: Console lock ? */
if (put_user(fg_console + 1, &vtstat->v_active)) if (put_user(fg_console + 1, &vtstat->v_active))
ret = -EFAULT; ret = -EFAULT;
else { else {
@ -960,6 +596,7 @@ int vt_ioctl(struct tty_struct *tty,
* Returns the first available (non-opened) console. * Returns the first available (non-opened) console.
*/ */
case VT_OPENQRY: case VT_OPENQRY:
/* FIXME: locking ? - but then this is a stupid API */
for (i = 0; i < MAX_NR_CONSOLES; ++i) for (i = 0; i < MAX_NR_CONSOLES; ++i)
if (! VT_IS_IN_USE(i)) if (! VT_IS_IN_USE(i))
break; break;
@ -973,7 +610,7 @@ int vt_ioctl(struct tty_struct *tty,
*/ */
case VT_ACTIVATE: case VT_ACTIVATE:
if (!perm) if (!perm)
goto eperm; return -EPERM;
if (arg == 0 || arg > MAX_NR_CONSOLES) if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO; ret = -ENXIO;
else { else {
@ -992,7 +629,7 @@ int vt_ioctl(struct tty_struct *tty,
struct vt_setactivate vsa; struct vt_setactivate vsa;
if (!perm) if (!perm)
goto eperm; return -EPERM;
if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
sizeof(struct vt_setactivate))) { sizeof(struct vt_setactivate))) {
@ -1020,6 +657,7 @@ int vt_ioctl(struct tty_struct *tty,
if (ret) if (ret)
break; break;
/* Commence switch and lock */ /* Commence switch and lock */
/* Review set_console locks */
set_console(vsa.console); set_console(vsa.console);
} }
break; break;
@ -1030,7 +668,7 @@ int vt_ioctl(struct tty_struct *tty,
*/ */
case VT_WAITACTIVE: case VT_WAITACTIVE:
if (!perm) if (!perm)
goto eperm; return -EPERM;
if (arg == 0 || arg > MAX_NR_CONSOLES) if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO; ret = -ENXIO;
else else
@ -1049,16 +687,17 @@ int vt_ioctl(struct tty_struct *tty,
*/ */
case VT_RELDISP: case VT_RELDISP:
if (!perm) if (!perm)
goto eperm; return -EPERM;
console_lock();
if (vc->vt_mode.mode != VT_PROCESS) { if (vc->vt_mode.mode != VT_PROCESS) {
console_unlock();
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
/* /*
* Switching-from response * Switching-from response
*/ */
console_lock();
if (vc->vt_newvt >= 0) { if (vc->vt_newvt >= 0) {
if (arg == 0) if (arg == 0)
/* /*
@ -1135,7 +774,7 @@ int vt_ioctl(struct tty_struct *tty,
ushort ll,cc; ushort ll,cc;
if (!perm) if (!perm)
goto eperm; return -EPERM;
if (get_user(ll, &vtsizes->v_rows) || if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols)) get_user(cc, &vtsizes->v_cols))
ret = -EFAULT; ret = -EFAULT;
@ -1146,6 +785,7 @@ int vt_ioctl(struct tty_struct *tty,
if (vc) { if (vc) {
vc->vc_resize_user = 1; vc->vc_resize_user = 1;
/* FIXME: review v tty lock */
vc_resize(vc_cons[i].d, cc, ll); vc_resize(vc_cons[i].d, cc, ll);
} }
} }
@ -1159,7 +799,7 @@ int vt_ioctl(struct tty_struct *tty,
struct vt_consize __user *vtconsize = up; struct vt_consize __user *vtconsize = up;
ushort ll,cc,vlin,clin,vcol,ccol; ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm) if (!perm)
goto eperm; return -EPERM;
if (!access_ok(VERIFY_READ, vtconsize, if (!access_ok(VERIFY_READ, vtconsize,
sizeof(struct vt_consize))) { sizeof(struct vt_consize))) {
ret = -EFAULT; ret = -EFAULT;
@ -1215,7 +855,7 @@ int vt_ioctl(struct tty_struct *tty,
case PIO_FONT: { case PIO_FONT: {
if (!perm) if (!perm)
goto eperm; return -EPERM;
op.op = KD_FONT_OP_SET; op.op = KD_FONT_OP_SET;
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
op.width = 8; op.width = 8;
@ -1256,7 +896,7 @@ int vt_ioctl(struct tty_struct *tty,
case PIO_FONTRESET: case PIO_FONTRESET:
{ {
if (!perm) if (!perm)
goto eperm; return -EPERM;
#ifdef BROKEN_GRAPHICS_PROGRAMS #ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
@ -1282,7 +922,7 @@ int vt_ioctl(struct tty_struct *tty,
break; break;
} }
if (!perm && op.op != KD_FONT_OP_GET) if (!perm && op.op != KD_FONT_OP_GET)
goto eperm; return -EPERM;
ret = con_font_op(vc, &op); ret = con_font_op(vc, &op);
if (ret) if (ret)
break; break;
@ -1294,50 +934,65 @@ int vt_ioctl(struct tty_struct *tty,
case PIO_SCRNMAP: case PIO_SCRNMAP:
if (!perm) if (!perm)
ret = -EPERM; ret = -EPERM;
else else {
tty_lock();
ret = con_set_trans_old(up); ret = con_set_trans_old(up);
tty_unlock();
}
break; break;
case GIO_SCRNMAP: case GIO_SCRNMAP:
tty_lock();
ret = con_get_trans_old(up); ret = con_get_trans_old(up);
tty_unlock();
break; break;
case PIO_UNISCRNMAP: case PIO_UNISCRNMAP:
if (!perm) if (!perm)
ret = -EPERM; ret = -EPERM;
else else {
tty_lock();
ret = con_set_trans_new(up); ret = con_set_trans_new(up);
tty_unlock();
}
break; break;
case GIO_UNISCRNMAP: case GIO_UNISCRNMAP:
tty_lock();
ret = con_get_trans_new(up); ret = con_get_trans_new(up);
tty_unlock();
break; break;
case PIO_UNIMAPCLR: case PIO_UNIMAPCLR:
{ struct unimapinit ui; { struct unimapinit ui;
if (!perm) if (!perm)
goto eperm; return -EPERM;
ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
if (ret) if (ret)
ret = -EFAULT; ret = -EFAULT;
else else {
tty_lock();
con_clear_unimap(vc, &ui); con_clear_unimap(vc, &ui);
tty_unlock();
}
break; break;
} }
case PIO_UNIMAP: case PIO_UNIMAP:
case GIO_UNIMAP: case GIO_UNIMAP:
tty_lock();
ret = do_unimap_ioctl(cmd, up, perm, vc); ret = do_unimap_ioctl(cmd, up, perm, vc);
tty_unlock();
break; break;
case VT_LOCKSWITCH: case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG)) if (!capable(CAP_SYS_TTY_CONFIG))
goto eperm; return -EPERM;
vt_dont_switch = 1; vt_dont_switch = 1;
break; break;
case VT_UNLOCKSWITCH: case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG)) if (!capable(CAP_SYS_TTY_CONFIG))
goto eperm; return -EPERM;
vt_dont_switch = 0; vt_dont_switch = 0;
break; break;
case VT_GETHIFONTMASK: case VT_GETHIFONTMASK:
@ -1351,17 +1006,13 @@ int vt_ioctl(struct tty_struct *tty,
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;
} }
out: out:
tty_unlock();
return ret; return ret;
eperm:
ret = -EPERM;
goto out;
} }
void reset_vc(struct vc_data *vc) void reset_vc(struct vc_data *vc)
{ {
vc->vc_mode = KD_TEXT; vc->vc_mode = KD_TEXT;
kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; vt_reset_unicode(vc->vc_num);
vc->vt_mode.mode = VT_AUTO; vc->vt_mode.mode = VT_AUTO;
vc->vt_mode.waitv = 0; vc->vt_mode.waitv = 0;
vc->vt_mode.relsig = 0; vc->vt_mode.relsig = 0;
@ -1384,6 +1035,7 @@ void vc_SAK(struct work_struct *work)
console_lock(); console_lock();
vc = vc_con->d; vc = vc_con->d;
if (vc) { if (vc) {
/* FIXME: review tty ref counting */
tty = vc->port.tty; tty = vc->port.tty;
/* /*
* SAK should also work in all raw modes and reset * SAK should also work in all raw modes and reset
@ -1516,8 +1168,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
console = vc->vc_num; console = vc->vc_num;
tty_lock();
if (!vc_cons_allocated(console)) { /* impossible? */ if (!vc_cons_allocated(console)) { /* impossible? */
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;
goto out; goto out;
@ -1546,7 +1196,9 @@ long vt_compat_ioctl(struct tty_struct *tty,
case PIO_UNIMAP: case PIO_UNIMAP:
case GIO_UNIMAP: case GIO_UNIMAP:
tty_lock();
ret = compat_unimap_ioctl(cmd, up, perm, vc); ret = compat_unimap_ioctl(cmd, up, perm, vc);
tty_unlock();
break; break;
/* /*
@ -1583,11 +1235,9 @@ long vt_compat_ioctl(struct tty_struct *tty,
goto fallback; goto fallback;
} }
out: out:
tty_unlock();
return ret; return ret;
fallback: fallback:
tty_unlock();
return vt_ioctl(tty, cmd, arg); return vt_ioctl(tty, cmd, arg);
} }
@ -1773,13 +1423,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
return -EIO; return -EIO;
} }
console_unlock(); console_unlock();
tty_lock();
if (vt_waitactive(vt + 1)) { if (vt_waitactive(vt + 1)) {
pr_debug("Suspend: Can't switch VCs."); pr_debug("Suspend: Can't switch VCs.");
tty_unlock();
return -EINTR; return -EINTR;
} }
tty_unlock();
return prev; return prev;
} }

Some files were not shown because too many files have changed in this diff Show More