dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits)
  TTY: serial_core: Fix crash if DCD drop during suspend
  tty/serial: atmel_serial: bootconsole removed from auto-enumerates
  Revert "TTY: call tty_driver_lookup_tty unconditionally"
  tty/serial: atmel_serial: add device tree support
  tty/serial: atmel_serial: auto-enumerate ports
  tty/serial: atmel_serial: whitespace and braces modifications
  tty/serial: atmel_serial: change platform_data variable name
  tty/serial: RS485 bindings for device tree
  TTY: call tty_driver_lookup_tty unconditionally
  TTY: pty, release tty in all ptmx_open fail paths
  TTY: make tty_add_file non-failing
  TTY: drop driver reference in tty_open fail path
  8250_pci: Fix kernel panic when pch_uart is disabled
  h8300: drivers/serial/Kconfig was moved
  parport_pc: release IO region properly if unsupported ITE887x card is found
  tty: Support compat_ioctl get/set termios_locked
  hvc_console: display printk messages on console.
  TTY: snyclinkmp: forever loop in tx_load_dma_buffer()
  tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output
  tty/n_gsm: fix a bug in gsm_dlci_data_output (adaption = 2 case)
  ...

Fix up Conflicts in:
 - drivers/tty/serial/8250_pci.c
	Trivial conflict with removed duplicate device ID
 - drivers/tty/serial/atmel_serial.c
	Annoying silly conflict between "specify the port num via
	platform_data" and other changes to atmel_console_init
This commit is contained in:
Linus Torvalds 2011-10-26 15:11:09 +02:00
commit efb8d21b2c
110 changed files with 2099 additions and 944 deletions

View File

@ -0,0 +1,31 @@
* RS485 serial communications
The RTS signal is capable of automatically controlling line direction for
the built-in half-duplex mode.
The properties described hereafter shall be given to a half-duplex capable
UART node.
Required properties:
- rs485-rts-delay: prop-encoded-array <a b> where:
* a is the delay beteween rts signal and beginning of data sent in milliseconds.
it corresponds to the delay before sending data.
* b is the delay between end of data sent and rts signal in milliseconds
it corresponds to the delay after sending data and actual release of the line.
Optional properties:
- linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485
feature at boot time. It can be disabled later with proper ioctl.
- rs485-rx-during-tx: empty property that enables the receiving of data even
whilst sending data.
RS485 example for Atmel USART:
usart0: serial@fff8c000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfff8c000 0x4000>;
interrupts = <7>;
atmel,use-dma-rx;
atmel,use-dma-tx;
linux,rs485-enabled-at-boot-time;
rs485-rts-delay = <0 200>; // in milliseconds
};

View File

@ -0,0 +1,27 @@
* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
Required properties:
- compatible: Should be "atmel,<chip>-usart"
The compatible <chip> indicated will be the first SoC to support an
additional mode or an USART new feature.
- reg: Should contain registers location and length
- interrupts: Should contain interrupt
Optional properties:
- atmel,use-dma-rx: use of PDC or DMA for receiving data
- atmel,use-dma-tx: use of PDC or DMA for transmitting data
<chip> compatible description:
- at91rm9200: legacy USART support
- at91sam9260: generic USART implementation for SAM9 SoCs
Example:
usart0: serial@fff8c000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfff8c000 0x4000>;
interrupts = <7>;
atmel,use-dma-rx;
atmel,use-dma-tx;
};

View File

@ -0,0 +1,25 @@
* Synopsys DesignWare ABP UART
Required properties:
- compatible : "snps,dw-apb-uart"
- reg : offset and length of the register set for the device.
- interrupts : should contain uart interrupt.
- clock-frequency : the input clock frequency for the UART.
Optional properties:
- reg-shift : quantity to shift the register offsets by. If this property is
not present then the register offsets are not shifted.
- reg-io-width : the size (in bytes) of the IO accesses that should be
performed on the device. If this property is not present then single byte
accesses are used.
Example:
uart@80230000 {
compatible = "snps,dw-apb-uart";
reg = <0x80230000 0x100>;
clock-frequency = <3686400>;
interrupts = <10>;
reg-shift = <2>;
reg-io-width = <4>;
};

View File

@ -28,6 +28,10 @@
RS485 communications. This data structure is used to set and configure RS485
parameters in the platform data and in ioctls.
The device tree can also provide RS485 boot time parameters (see [2]
for bindings). The driver is in charge of filling this data structure from
the values given by the device tree.
Any driver for devices capable of working both as RS232 and RS485 should
provide at least the following ioctls:
@ -104,6 +108,9 @@
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
rs485conf.delay_rts_after_send = ...;
/* Set this flag if you want to receive data even whilst sending data */
rs485conf.flags |= SER_RS485_RX_DURING_TX;
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
/* Error handling. See errno. */
}
@ -118,3 +125,4 @@
5. REFERENCES
[1] include/linux/serial.h
[2] Documentation/devicetree/bindings/serial/rs485.txt

View File

@ -727,7 +727,6 @@ config ARCH_S3C64XX
select ARCH_REQUIRE_GPIOLIB
select SAMSUNG_CLKSRC
select SAMSUNG_IRQ_VIC_TIMER
select SAMSUNG_IRQ_UART
select S3C_GPIO_TRACK
select S3C_GPIO_PULL_UPDOWN
select S3C_GPIO_CFG_S3C24XX

View File

@ -37,21 +37,10 @@ static struct resource s3c64xx_uart0_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX0,
.end = IRQ_S3CUART_RX0,
.start = IRQ_UART0,
.end = IRQ_UART0,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S3CUART_TX0,
.end = IRQ_S3CUART_TX0,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S3CUART_ERR0,
.end = IRQ_S3CUART_ERR0,
.flags = IORESOURCE_IRQ,
}
};
static struct resource s3c64xx_uart1_resource[] = {
@ -61,19 +50,8 @@ static struct resource s3c64xx_uart1_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX1,
.end = IRQ_S3CUART_RX1,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S3CUART_TX1,
.end = IRQ_S3CUART_TX1,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S3CUART_ERR1,
.end = IRQ_S3CUART_ERR1,
.start = IRQ_UART1,
.end = IRQ_UART1,
.flags = IORESOURCE_IRQ,
},
};
@ -85,19 +63,8 @@ static struct resource s3c6xx_uart2_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX2,
.end = IRQ_S3CUART_RX2,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S3CUART_TX2,
.end = IRQ_S3CUART_TX2,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S3CUART_ERR2,
.end = IRQ_S3CUART_ERR2,
.start = IRQ_UART2,
.end = IRQ_UART2,
.flags = IORESOURCE_IRQ,
},
};
@ -109,19 +76,8 @@ static struct resource s3c64xx_uart3_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX3,
.end = IRQ_S3CUART_RX3,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S3CUART_TX3,
.end = IRQ_S3CUART_TX3,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S3CUART_ERR3,
.end = IRQ_S3CUART_ERR3,
.start = IRQ_UART3,
.end = IRQ_UART3,
.flags = IORESOURCE_IRQ,
},
};

View File

@ -27,36 +27,6 @@
#define IRQ_VIC0_BASE S3C_IRQ(0)
#define IRQ_VIC1_BASE S3C_IRQ(32)
/* UART interrupts, each UART has 4 intterupts per channel so
* use the space between the ISA and S3C main interrupts. Note, these
* are not in the same order as the S3C24XX series! */
#define IRQ_S3CUART_BASE0 (16)
#define IRQ_S3CUART_BASE1 (20)
#define IRQ_S3CUART_BASE2 (24)
#define IRQ_S3CUART_BASE3 (28)
#define UART_IRQ_RXD (0)
#define UART_IRQ_ERR (1)
#define UART_IRQ_TXD (2)
#define UART_IRQ_MODEM (3)
#define IRQ_S3CUART_RX0 (IRQ_S3CUART_BASE0 + UART_IRQ_RXD)
#define IRQ_S3CUART_TX0 (IRQ_S3CUART_BASE0 + UART_IRQ_TXD)
#define IRQ_S3CUART_ERR0 (IRQ_S3CUART_BASE0 + UART_IRQ_ERR)
#define IRQ_S3CUART_RX1 (IRQ_S3CUART_BASE1 + UART_IRQ_RXD)
#define IRQ_S3CUART_TX1 (IRQ_S3CUART_BASE1 + UART_IRQ_TXD)
#define IRQ_S3CUART_ERR1 (IRQ_S3CUART_BASE1 + UART_IRQ_ERR)
#define IRQ_S3CUART_RX2 (IRQ_S3CUART_BASE2 + UART_IRQ_RXD)
#define IRQ_S3CUART_TX2 (IRQ_S3CUART_BASE2 + UART_IRQ_TXD)
#define IRQ_S3CUART_ERR2 (IRQ_S3CUART_BASE2 + UART_IRQ_ERR)
#define IRQ_S3CUART_RX3 (IRQ_S3CUART_BASE3 + UART_IRQ_RXD)
#define IRQ_S3CUART_TX3 (IRQ_S3CUART_BASE3 + UART_IRQ_TXD)
#define IRQ_S3CUART_ERR3 (IRQ_S3CUART_BASE3 + UART_IRQ_ERR)
/* VIC based IRQs */
#define S3C64XX_IRQ_VIC0(x) (IRQ_VIC0_BASE + (x))

View File

@ -25,29 +25,6 @@
#include <plat/irq-uart.h>
#include <plat/cpu.h>
static struct s3c_uart_irq uart_irqs[] = {
[0] = {
.regs = S3C_VA_UART0,
.base_irq = IRQ_S3CUART_BASE0,
.parent_irq = IRQ_UART0,
},
[1] = {
.regs = S3C_VA_UART1,
.base_irq = IRQ_S3CUART_BASE1,
.parent_irq = IRQ_UART1,
},
[2] = {
.regs = S3C_VA_UART2,
.base_irq = IRQ_S3CUART_BASE2,
.parent_irq = IRQ_UART2,
},
[3] = {
.regs = S3C_VA_UART3,
.base_irq = IRQ_S3CUART_BASE3,
.parent_irq = IRQ_UART3,
},
};
/* setup the sources the vic should advertise resume for, even though it
* is not doing the wake (set_irq_wake needs to be valid) */
#define IRQ_VIC0_RESUME (1 << (IRQ_RTC_TIC - IRQ_VIC0_BASE))
@ -67,6 +44,4 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
/* add the timer sub-irqs */
s3c_init_vic_timer_irq(5, IRQ_TIMER0);
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
}

View File

@ -22,7 +22,6 @@ config PLAT_S5P
select PLAT_SAMSUNG
select SAMSUNG_CLKSRC
select SAMSUNG_IRQ_VIC_TIMER
select SAMSUNG_IRQ_UART
help
Base platform code for Samsung's S5P series SoC.

View File

@ -32,20 +32,10 @@ static struct resource s5p_uart0_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S5P_UART_RX0,
.end = IRQ_S5P_UART_RX0,
.start = IRQ_UART0,
.end = IRQ_UART0,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S5P_UART_TX0,
.end = IRQ_S5P_UART_TX0,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S5P_UART_ERR0,
.end = IRQ_S5P_UART_ERR0,
.flags = IORESOURCE_IRQ,
}
};
static struct resource s5p_uart1_resource[] = {
@ -55,18 +45,8 @@ static struct resource s5p_uart1_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S5P_UART_RX1,
.end = IRQ_S5P_UART_RX1,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S5P_UART_TX1,
.end = IRQ_S5P_UART_TX1,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S5P_UART_ERR1,
.end = IRQ_S5P_UART_ERR1,
.start = IRQ_UART1,
.end = IRQ_UART1,
.flags = IORESOURCE_IRQ,
},
};
@ -78,18 +58,8 @@ static struct resource s5p_uart2_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S5P_UART_RX2,
.end = IRQ_S5P_UART_RX2,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S5P_UART_TX2,
.end = IRQ_S5P_UART_TX2,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S5P_UART_ERR2,
.end = IRQ_S5P_UART_ERR2,
.start = IRQ_UART2,
.end = IRQ_UART2,
.flags = IORESOURCE_IRQ,
},
};
@ -102,18 +72,8 @@ static struct resource s5p_uart3_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S5P_UART_RX3,
.end = IRQ_S5P_UART_RX3,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S5P_UART_TX3,
.end = IRQ_S5P_UART_TX3,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S5P_UART_ERR3,
.end = IRQ_S5P_UART_ERR3,
.start = IRQ_UART3,
.end = IRQ_UART3,
.flags = IORESOURCE_IRQ,
},
#endif
@ -127,18 +87,8 @@ static struct resource s5p_uart4_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S5P_UART_RX4,
.end = IRQ_S5P_UART_RX4,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S5P_UART_TX4,
.end = IRQ_S5P_UART_TX4,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S5P_UART_ERR4,
.end = IRQ_S5P_UART_ERR4,
.start = IRQ_UART4,
.end = IRQ_UART4,
.flags = IORESOURCE_IRQ,
},
#endif
@ -152,18 +102,8 @@ static struct resource s5p_uart5_resource[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S5P_UART_RX5,
.end = IRQ_S5P_UART_RX5,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_S5P_UART_TX5,
.end = IRQ_S5P_UART_TX5,
.flags = IORESOURCE_IRQ,
},
[3] = {
.start = IRQ_S5P_UART_ERR5,
.end = IRQ_S5P_UART_ERR5,
.start = IRQ_UART5,
.end = IRQ_UART5,
.flags = IORESOURCE_IRQ,
},
#endif

View File

@ -37,41 +37,6 @@
#define IRQ_VIC1_BASE S5P_VIC1_BASE
#define IRQ_VIC2_BASE S5P_VIC2_BASE
/* UART interrupts, each UART has 4 intterupts per channel so
* use the space between the ISA and S3C main interrupts. Note, these
* are not in the same order as the S3C24XX series! */
#define IRQ_S5P_UART_BASE0 (16)
#define IRQ_S5P_UART_BASE1 (20)
#define IRQ_S5P_UART_BASE2 (24)
#define IRQ_S5P_UART_BASE3 (28)
#define UART_IRQ_RXD (0)
#define UART_IRQ_ERR (1)
#define UART_IRQ_TXD (2)
#define IRQ_S5P_UART_RX0 (IRQ_S5P_UART_BASE0 + UART_IRQ_RXD)
#define IRQ_S5P_UART_TX0 (IRQ_S5P_UART_BASE0 + UART_IRQ_TXD)
#define IRQ_S5P_UART_ERR0 (IRQ_S5P_UART_BASE0 + UART_IRQ_ERR)
#define IRQ_S5P_UART_RX1 (IRQ_S5P_UART_BASE1 + UART_IRQ_RXD)
#define IRQ_S5P_UART_TX1 (IRQ_S5P_UART_BASE1 + UART_IRQ_TXD)
#define IRQ_S5P_UART_ERR1 (IRQ_S5P_UART_BASE1 + UART_IRQ_ERR)
#define IRQ_S5P_UART_RX2 (IRQ_S5P_UART_BASE2 + UART_IRQ_RXD)
#define IRQ_S5P_UART_TX2 (IRQ_S5P_UART_BASE2 + UART_IRQ_TXD)
#define IRQ_S5P_UART_ERR2 (IRQ_S5P_UART_BASE2 + UART_IRQ_ERR)
#define IRQ_S5P_UART_RX3 (IRQ_S5P_UART_BASE3 + UART_IRQ_RXD)
#define IRQ_S5P_UART_TX3 (IRQ_S5P_UART_BASE3 + UART_IRQ_TXD)
#define IRQ_S5P_UART_ERR3 (IRQ_S5P_UART_BASE3 + UART_IRQ_ERR)
/* S3C compatibilty defines */
#define IRQ_S3CUART_RX0 IRQ_S5P_UART_RX0
#define IRQ_S3CUART_RX1 IRQ_S5P_UART_RX1
#define IRQ_S3CUART_RX2 IRQ_S5P_UART_RX2
#define IRQ_S3CUART_RX3 IRQ_S5P_UART_RX3
/* VIC based IRQs */
#define S5P_IRQ_VIC0(x) (S5P_VIC0_BASE + (x))

View File

@ -17,42 +17,10 @@
#include <asm/hardware/vic.h>
#include <linux/serial_core.h>
#include <mach/map.h>
#include <plat/regs-timer.h>
#include <plat/regs-serial.h>
#include <plat/cpu.h>
#include <plat/irq-vic-timer.h>
#include <plat/irq-uart.h>
/*
* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
* are consecutive when looking up the interrupt in the demux routines.
*/
static struct s3c_uart_irq uart_irqs[] = {
[0] = {
.regs = S5P_VA_UART0,
.base_irq = IRQ_S5P_UART_BASE0,
.parent_irq = IRQ_UART0,
},
[1] = {
.regs = S5P_VA_UART1,
.base_irq = IRQ_S5P_UART_BASE1,
.parent_irq = IRQ_UART1,
},
[2] = {
.regs = S5P_VA_UART2,
.base_irq = IRQ_S5P_UART_BASE2,
.parent_irq = IRQ_UART2,
},
#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
[3] = {
.regs = S5P_VA_UART3,
.base_irq = IRQ_S5P_UART_BASE3,
.parent_irq = IRQ_UART3,
},
#endif
};
void __init s5p_init_irq(u32 *vic, u32 num_vic)
{
@ -65,6 +33,4 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
#endif
s3c_init_vic_timer_irq(5, IRQ_TIMER0);
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
}

View File

@ -65,11 +65,6 @@ config SAMSUNG_IRQ_VIC_TIMER
help
Internal configuration to build the VIC timer interrupt code.
config SAMSUNG_IRQ_UART
bool
help
Internal configuration to build the IRQ UART demux code.
# options for gpio configuration support
config SAMSUNG_GPIOLIB_4BIT

View File

@ -21,7 +21,6 @@ obj-y += dev-asocdma.o
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
obj-$(CONFIG_SAMSUNG_IRQ_UART) += irq-uart.o
obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
# ADC

View File

@ -186,6 +186,11 @@
#define S3C64XX_UINTSP 0x34
#define S3C64XX_UINTM 0x38
#define S3C64XX_UINTM_RXD (0)
#define S3C64XX_UINTM_TXD (2)
#define S3C64XX_UINTM_RXD_MSK (1 << S3C64XX_UINTM_RXD)
#define S3C64XX_UINTM_TXD_MSK (1 << S3C64XX_UINTM_TXD)
/* Following are specific to S5PV210 */
#define S5PV210_UCON_CLKMASK (1<<10)
#define S5PV210_UCON_PCLK (0<<10)

View File

@ -1,96 +0,0 @@
/* arch/arm/plat-samsung/irq-uart.c
* originally part of arch/arm/plat-s3c64xx/irq.c
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* Samsung- UART Interrupt handling
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/mach/irq.h>
#include <mach/map.h>
#include <plat/irq-uart.h>
#include <plat/regs-serial.h>
#include <plat/cpu.h>
/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
* are consecutive when looking up the interrupt in the demux routines.
*/
static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
{
struct s3c_uart_irq *uirq = desc->irq_data.handler_data;
struct irq_chip *chip = irq_get_chip(irq);
u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
int base = uirq->base_irq;
chained_irq_enter(chip, desc);
if (pend & (1 << 0))
generic_handle_irq(base);
if (pend & (1 << 1))
generic_handle_irq(base + 1);
if (pend & (1 << 2))
generic_handle_irq(base + 2);
if (pend & (1 << 3))
generic_handle_irq(base + 3);
chained_irq_exit(chip, desc);
}
static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
{
void __iomem *reg_base = uirq->regs;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
/* mask all interrupts at the start. */
__raw_writel(0xf, reg_base + S3C64XX_UINTM);
gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base,
handle_level_irq);
if (!gc) {
pr_err("%s: irq_alloc_generic_chip for IRQ %u failed\n",
__func__, uirq->base_irq);
return;
}
ct = gc->chip_types;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->regs.ack = S3C64XX_UINTP;
ct->regs.mask = S3C64XX_UINTM;
irq_setup_generic_chip(gc, IRQ_MSK(4), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
irq_set_handler_data(uirq->parent_irq, uirq);
irq_set_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
}
/**
* s3c_init_uart_irqs() - initialise UART IRQs and the necessary demuxing
* @irq: The interrupt data for registering
* @nr_irqs: The number of interrupt descriptions in @irq.
*
* Register the UART interrupts specified by @irq including the demuxing
* routines. This supports the S3C6400 and newer style of devices.
*/
void __init s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs)
{
for (; nr_irqs > 0; nr_irqs--, irq++)
s3c_init_uart_irq(irq);
}

View File

@ -195,7 +195,7 @@ config UNIX98_PTYS
source "drivers/char/pcmcia/Kconfig"
source "drivers/serial/Kconfig"
source "drivers/tty/serial/Kconfig"
source "drivers/i2c/Kconfig"

View File

@ -27,6 +27,7 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/slab.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
@ -38,6 +39,55 @@
#include <msp_int.h>
#include <msp_regs.h>
struct msp_uart_data {
int last_lcr;
};
static void msp_serial_out(struct uart_port *p, int offset, int value)
{
struct msp_uart_data *d = p->private_data;
if (offset == UART_LCR)
d->last_lcr = value;
offset <<= p->regshift;
writeb(value, p->membase + offset);
}
static unsigned int msp_serial_in(struct uart_port *p, int offset)
{
offset <<= p->regshift;
return readb(p->membase + offset);
}
static int msp_serial_handle_irq(struct uart_port *p)
{
struct msp_uart_data *d = p->private_data;
unsigned int iir = readb(p->membase + (UART_IIR << p->regshift));
if (serial8250_handle_irq(p, iir)) {
return 1;
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/*
* The DesignWare APB UART has an Busy Detect (0x07) interrupt
* meaning an LCR write attempt occurred while the UART was
* busy. The interrupt must be cleared by reading the UART
* status register (USR) and the LCR re-written.
*
* Note: MSP reserves 0x20 bytes of address space for the UART
* and the USR is mapped in a separate block at an offset of
* 0xc0 from the start of the UART.
*/
(void)readb(p->membase + 0xc0);
writeb(d->last_lcr, p->membase + (UART_LCR << p->regshift));
return 1;
}
return 0;
}
void __init msp_serial_setup(void)
{
char *s;
@ -59,13 +109,22 @@ void __init msp_serial_setup(void)
up.irq = MSP_INT_UART0;
up.uartclk = uartclk;
up.regshift = 2;
up.iotype = UPIO_DWAPB; /* UPIO_MEM like */
up.iotype = UPIO_MEM;
up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
up.type = PORT_16550A;
up.line = 0;
up.private_data = (void*)UART0_STATUS_REG;
if (early_serial_setup(&up))
printk(KERN_ERR "Early serial init of port 0 failed\n");
up.serial_out = msp_serial_out;
up.serial_in = msp_serial_in;
up.handle_irq = msp_serial_handle_irq;
up.private_data = kzalloc(sizeof(struct msp_uart_data), GFP_KERNEL);
if (!up.private_data) {
pr_err("failed to allocate uart private data\n");
return;
}
if (early_serial_setup(&up)) {
kfree(up.private_data);
pr_err("Early serial init of port 0 failed\n");
}
/* Initialize the second serial port, if one exists */
switch (mips_machtype) {
@ -88,6 +147,8 @@ void __init msp_serial_setup(void)
up.irq = MSP_INT_UART1;
up.line = 1;
up.private_data = (void*)UART1_STATUS_REG;
if (early_serial_setup(&up))
printk(KERN_ERR "Early serial init of port 1 failed\n");
if (early_serial_setup(&up)) {
kfree(up.private_data);
pr_err("Early serial init of port 1 failed\n");
}
}

View File

@ -54,6 +54,7 @@ extern void __init udbg_init_40x_realmode(void);
extern void __init udbg_init_cpm(void);
extern void __init udbg_init_usbgecko(void);
extern void __init udbg_init_wsp(void);
extern void __init udbg_init_ehv_bc(void);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UDBG_H */

View File

@ -67,6 +67,8 @@ void __init udbg_early_init(void)
udbg_init_usbgecko();
#elif defined(CONFIG_PPC_EARLY_DEBUG_WSP)
udbg_init_wsp();
#elif defined(CONFIG_PPC_EARLY_DEBUG_EHV_BC)
udbg_init_ehv_bc();
#endif
#ifdef CONFIG_PPC_EARLY_DEBUG

View File

@ -14,6 +14,8 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/scatterlist.h>
#include <linux/sfi.h>
#include <linux/intel_pmic_gpio.h>
#include <linux/spi/spi.h>
@ -392,6 +394,7 @@ static void __init *max3111_platform_data(void *info)
struct spi_board_info *spi_info = info;
int intr = get_gpio_by_name("max3111_int");
spi_info->mode = SPI_MODE_0;
if (intr == -1)
return NULL;
spi_info->irq = intr + MRST_IRQ_OFFSET;

View File

@ -1693,7 +1693,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
* line status register.
*/
if (info->flags & ISDN_ASYNC_INITIALIZED) {
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
tty_wait_until_sent_from_close(tty, 3000); /* 30 seconds timeout */
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially

View File

@ -2595,14 +2595,17 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
break;
case 0x6:
printk(KERN_INFO "parport_pc: ITE8873 found (1S)\n");
release_region(inta_addr[i], 32);
return 0;
case 0x8:
printk(KERN_INFO "parport_pc: ITE8874 found (2S)\n");
release_region(inta_addr[i], 32);
return 0;
default:
printk(KERN_INFO "parport_pc: unknown ITE887x\n");
printk(KERN_INFO "parport_pc: please mail 'lspci -nvv' "
"output to Rich.Liu@ite.com.tw\n");
release_region(inta_addr[i], 32);
return 0;
}

View File

@ -24,6 +24,8 @@ menuconfig STAGING
if STAGING
source "drivers/staging/serial/Kconfig"
source "drivers/staging/et131x/Kconfig"
source "drivers/staging/slicoss/Kconfig"

View File

@ -3,6 +3,7 @@
# fix for build system bug...
obj-$(CONFIG_STAGING) += staging.o
obj-y += serial/
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_VIDEO_GO7007) += go7007/

View File

@ -0,0 +1,16 @@
config SERIAL_68360_SMC
bool "68360 SMC uart support"
depends on M68360
help
This driver supports the SMC serial ports of the Motorola 68360 CPU.
config SERIAL_68360_SCC
bool "68360 SCC uart support"
depends on M68360
help
This driver supports the SCC serial ports of the Motorola 68360 CPU.
config SERIAL_68360
bool
depends on SERIAL_68360_SMC || SERIAL_68360_SCC
default y

View File

@ -0,0 +1 @@
obj-$(CONFIG_SERIAL_68360) += 68360serial.o

View File

@ -0,0 +1,6 @@
These are a few serial drivers that either do not build, or do not work if they
do build, or if they seem to work, are for obsolete hardware, or are full of
unfixable races and no one uses them anymore.
If no one steps up to adopt any of these drivers, they will be removed
in the 3.4 release.

View File

@ -354,3 +354,37 @@ config TRACE_SINK
If you select this option, you need to select
"Trace data router for MIPI P1149.7 cJTAG standard".
config PPC_EPAPR_HV_BYTECHAN
tristate "ePAPR hypervisor byte channel driver"
depends on PPC
help
This driver creates /dev entries for each ePAPR hypervisor byte
channel, thereby allowing applications to communicate with byte
channels as if they were serial ports.
config PPC_EARLY_DEBUG_EHV_BC
bool "Early console (udbg) support for ePAPR hypervisors"
depends on PPC_EPAPR_HV_BYTECHAN
help
Select this option to enable early console (a.k.a. "udbg") support
via an ePAPR byte channel. You also need to choose the byte channel
handle below.
config PPC_EARLY_DEBUG_EHV_BC_HANDLE
int "Byte channel handle for early console (udbg)"
depends on PPC_EARLY_DEBUG_EHV_BC
default 0
help
If you want early console (udbg) output through a byte channel,
specify the handle of the byte channel to use.
For this to work, the byte channel driver must be compiled
in-kernel, not as a module.
Note that only one early console driver can be enabled, so don't
enable any others if you enable this one.
If the number you specify is not a valid byte channel handle, then
there simply will be no early console output. This is true also
if you don't boot under a hypervisor at all.

View File

@ -26,5 +26,6 @@ obj-$(CONFIG_ROCKETPORT) += rocket.o
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
obj-y += ipwireless/

View File

@ -1529,7 +1529,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct async_struct * info = tty->driver_data;
unsigned long orig_jiffies, char_time;
int tty_was_locked = tty_locked();
int lsr;
if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
@ -1540,12 +1539,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
orig_jiffies = jiffies;
/*
* tty_wait_until_sent is called from lots of places,
* with or without the BTM.
*/
if (!tty_was_locked)
tty_lock();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@ -1586,8 +1579,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
__set_current_state(TASK_RUNNING);
if (!tty_was_locked)
tty_unlock();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@ -2025,7 +2017,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
if (error)
goto fail_unregister;
error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED,
error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, 0,
"serial RX", state);
if (error)
goto fail_free_irq;

View File

@ -45,7 +45,6 @@
#undef CY_DEBUG_IO
#undef CY_DEBUG_COUNT
#undef CY_DEBUG_DTR
#undef CY_DEBUG_WAIT_UNTIL_SENT
#undef CY_DEBUG_INTERRUPTS
#undef CY_16Y_HACK
#undef CY_ENABLE_MONITORING
@ -1678,16 +1677,10 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
*/
if (!timeout || timeout > 2 * info->timeout)
timeout = 2 * info->timeout;
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
timeout, char_time, jiffies);
#endif
card = info->card;
if (!cy_is_Z(card)) {
while (cyy_readb(info, CySRER) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
#endif
if (msleep_interruptible(jiffies_to_msecs(char_time)))
break;
if (timeout && time_after(jiffies, orig_jiffies +
@ -1697,9 +1690,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
#endif
}
static void cy_flush_buffer(struct tty_struct *tty)
@ -3377,7 +3367,7 @@ static int __init cy_detect_isa(void)
/* allocate IRQ */
if (request_irq(cy_isa_irq, cyy_interrupt,
IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
0, "Cyclom-Y", &cy_card[j])) {
printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
"could not allocate IRQ#%d.\n",
(unsigned long)cy_isa_address, cy_isa_irq);

881
drivers/tty/ehv_bytechan.c Normal file
View File

@ -0,0 +1,881 @@
/* ePAPR hypervisor byte channel device driver
*
* Copyright 2009-2011 Freescale Semiconductor, Inc.
*
* Author: Timur Tabi <timur@freescale.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*
* This driver support three distinct interfaces, all of which are related to
* ePAPR hypervisor byte channels.
*
* 1) An early-console (udbg) driver. This provides early console output
* through a byte channel. The byte channel handle must be specified in a
* Kconfig option.
*
* 2) A normal console driver. Output is sent to the byte channel designated
* for stdout in the device tree. The console driver is for handling kernel
* printk calls.
*
* 3) A tty driver, which is used to handle user-space input and output. The
* byte channel used for the console is designated as the default tty.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <asm/epapr_hcalls.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/circ_buf.h>
#include <asm/udbg.h>
/* The size of the transmit circular buffer. This must be a power of two. */
#define BUF_SIZE 2048
/* Per-byte channel private data */
struct ehv_bc_data {
struct device *dev;
struct tty_port port;
uint32_t handle;
unsigned int rx_irq;
unsigned int tx_irq;
spinlock_t lock; /* lock for transmit buffer */
unsigned char buf[BUF_SIZE]; /* transmit circular buffer */
unsigned int head; /* circular buffer head */
unsigned int tail; /* circular buffer tail */
int tx_irq_enabled; /* true == TX interrupt is enabled */
};
/* Array of byte channel objects */
static struct ehv_bc_data *bcs;
/* Byte channel handle for stdout (and stdin), taken from device tree */
static unsigned int stdout_bc;
/* Virtual IRQ for the byte channel handle for stdin, taken from device tree */
static unsigned int stdout_irq;
/**************************** SUPPORT FUNCTIONS ****************************/
/*
* Enable the transmit interrupt
*
* Unlike a serial device, byte channels have no mechanism for disabling their
* own receive or transmit interrupts. To emulate that feature, we toggle
* the IRQ in the kernel.
*
* We cannot just blindly call enable_irq() or disable_irq(), because these
* calls are reference counted. This means that we cannot call enable_irq()
* if interrupts are already enabled. This can happen in two situations:
*
* 1. The tty layer makes two back-to-back calls to ehv_bc_tty_write()
* 2. A transmit interrupt occurs while executing ehv_bc_tx_dequeue()
*
* To work around this, we keep a flag to tell us if the IRQ is enabled or not.
*/
static void enable_tx_interrupt(struct ehv_bc_data *bc)
{
if (!bc->tx_irq_enabled) {
enable_irq(bc->tx_irq);
bc->tx_irq_enabled = 1;
}
}
static void disable_tx_interrupt(struct ehv_bc_data *bc)
{
if (bc->tx_irq_enabled) {
disable_irq_nosync(bc->tx_irq);
bc->tx_irq_enabled = 0;
}
}
/*
* find the byte channel handle to use for the console
*
* The byte channel to be used for the console is specified via a "stdout"
* property in the /chosen node.
*
* For compatible with legacy device trees, we also look for a "stdout" alias.
*/
static int find_console_handle(void)
{
struct device_node *np, *np2;
const char *sprop = NULL;
const uint32_t *iprop;
np = of_find_node_by_path("/chosen");
if (np)
sprop = of_get_property(np, "stdout-path", NULL);
if (!np || !sprop) {
of_node_put(np);
np = of_find_node_by_name(NULL, "aliases");
if (np)
sprop = of_get_property(np, "stdout", NULL);
}
if (!sprop) {
of_node_put(np);
return 0;
}
/* We don't care what the aliased node is actually called. We only
* care if it's compatible with "epapr,hv-byte-channel", because that
* indicates that it's a byte channel node. We use a temporary
* variable, 'np2', because we can't release 'np' until we're done with
* 'sprop'.
*/
np2 = of_find_node_by_path(sprop);
of_node_put(np);
np = np2;
if (!np) {
pr_warning("ehv-bc: stdout node '%s' does not exist\n", sprop);
return 0;
}
/* Is it a byte channel? */
if (!of_device_is_compatible(np, "epapr,hv-byte-channel")) {
of_node_put(np);
return 0;
}
stdout_irq = irq_of_parse_and_map(np, 0);
if (stdout_irq == NO_IRQ) {
pr_err("ehv-bc: no 'interrupts' property in %s node\n", sprop);
of_node_put(np);
return 0;
}
/*
* The 'hv-handle' property contains the handle for this byte channel.
*/
iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) {
pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
np->name);
of_node_put(np);
return 0;
}
stdout_bc = be32_to_cpu(*iprop);
of_node_put(np);
return 1;
}
/*************************** EARLY CONSOLE DRIVER ***************************/
#ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
/*
* send a byte to a byte channel, wait if necessary
*
* This function sends a byte to a byte channel, and it waits and
* retries if the byte channel is full. It returns if the character
* has been sent, or if some error has occurred.
*
*/
static void byte_channel_spin_send(const char data)
{
int ret, count;
do {
count = 1;
ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
&count, &data);
} while (ret == EV_EAGAIN);
}
/*
* The udbg subsystem calls this function to display a single character.
* We convert CR to a CR/LF.
*/
static void ehv_bc_udbg_putc(char c)
{
if (c == '\n')
byte_channel_spin_send('\r');
byte_channel_spin_send(c);
}
/*
* early console initialization
*
* PowerPC kernels support an early printk console, also known as udbg.
* This function must be called via the ppc_md.init_early function pointer.
* At this point, the device tree has been unflattened, so we can obtain the
* byte channel handle for stdout.
*
* We only support displaying of characters (putc). We do not support
* keyboard input.
*/
void __init udbg_init_ehv_bc(void)
{
unsigned int rx_count, tx_count;
unsigned int ret;
/* Verify the byte channel handle */
ret = ev_byte_channel_poll(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE,
&rx_count, &tx_count);
if (ret)
return;
udbg_putc = ehv_bc_udbg_putc;
register_early_udbg_console();
udbg_printf("ehv-bc: early console using byte channel handle %u\n",
CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
}
#endif
/****************************** CONSOLE DRIVER ******************************/
static struct tty_driver *ehv_bc_driver;
/*
* Byte channel console sending worker function.
*
* For consoles, if the output buffer is full, we should just spin until it
* clears.
*/
static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s,
unsigned int count)
{
unsigned int len;
int ret = 0;
while (count) {
len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES);
do {
ret = ev_byte_channel_send(handle, &len, s);
} while (ret == EV_EAGAIN);
count -= len;
s += len;
}
return ret;
}
/*
* write a string to the console
*
* This function gets called to write a string from the kernel, typically from
* a printk(). This function spins until all data is written.
*
* We copy the data to a temporary buffer because we need to insert a \r in
* front of every \n. It's more efficient to copy the data to the buffer than
* it is to make multiple hcalls for each character or each newline.
*/
static void ehv_bc_console_write(struct console *co, const char *s,
unsigned int count)
{
char s2[EV_BYTE_CHANNEL_MAX_BYTES];
unsigned int i, j = 0;
char c;
for (i = 0; i < count; i++) {
c = *s++;
if (c == '\n')
s2[j++] = '\r';
s2[j++] = c;
if (j >= (EV_BYTE_CHANNEL_MAX_BYTES - 1)) {
if (ehv_bc_console_byte_channel_send(stdout_bc, s2, j))
return;
j = 0;
}
}
if (j)
ehv_bc_console_byte_channel_send(stdout_bc, s2, j);
}
/*
* When /dev/console is opened, the kernel iterates the console list looking
* for one with ->device and then calls that method. On success, it expects
* the passed-in int* to contain the minor number to use.
*/
static struct tty_driver *ehv_bc_console_device(struct console *co, int *index)
{
*index = co->index;
return ehv_bc_driver;
}
static struct console ehv_bc_console = {
.name = "ttyEHV",
.write = ehv_bc_console_write,
.device = ehv_bc_console_device,
.flags = CON_PRINTBUFFER | CON_ENABLED,
};
/*
* Console initialization
*
* This is the first function that is called after the device tree is
* available, so here is where we determine the byte channel handle and IRQ for
* stdout/stdin, even though that information is used by the tty and character
* drivers.
*/
static int __init ehv_bc_console_init(void)
{
if (!find_console_handle()) {
pr_debug("ehv-bc: stdout is not a byte channel\n");
return -ENODEV;
}
#ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC
/* Print a friendly warning if the user chose the wrong byte channel
* handle for udbg.
*/
if (stdout_bc != CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE)
pr_warning("ehv-bc: udbg handle %u is not the stdout handle\n",
CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
#endif
/* add_preferred_console() must be called before register_console(),
otherwise it won't work. However, we don't want to enumerate all the
byte channels here, either, since we only care about one. */
add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL);
register_console(&ehv_bc_console);
pr_info("ehv-bc: registered console driver for byte channel %u\n",
stdout_bc);
return 0;
}
console_initcall(ehv_bc_console_init);
/******************************** TTY DRIVER ********************************/
/*
* byte channel receive interupt handler
*
* This ISR is called whenever data is available on a byte channel.
*/
static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
{
struct ehv_bc_data *bc = data;
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
unsigned int rx_count, tx_count, len;
int count;
char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
int ret;
/* ttys could be NULL during a hangup */
if (!ttys)
return IRQ_HANDLED;
/* Find out how much data needs to be read, and then ask the TTY layer
* if it can handle that much. We want to ensure that every byte we
* read from the byte channel will be accepted by the TTY layer.
*/
ev_byte_channel_poll(bc->handle, &rx_count, &tx_count);
count = tty_buffer_request_room(ttys, rx_count);
/* 'count' is the maximum amount of data the TTY layer can accept at
* this time. However, during testing, I was never able to get 'count'
* to be less than 'rx_count'. I'm not sure whether I'm calling it
* correctly.
*/
while (count > 0) {
len = min_t(unsigned int, count, sizeof(buffer));
/* Read some data from the byte channel. This function will
* never return more than EV_BYTE_CHANNEL_MAX_BYTES bytes.
*/
ev_byte_channel_receive(bc->handle, &len, buffer);
/* 'len' is now the amount of data that's been received. 'len'
* can't be zero, and most likely it's equal to one.
*/
/* Pass the received data to the tty layer. */
ret = tty_insert_flip_string(ttys, buffer, len);
/* 'ret' is the number of bytes that the TTY layer accepted.
* If it's not equal to 'len', then it means the buffer is
* full, which should never happen. If it does happen, we can
* exit gracefully, but we drop the last 'len - ret' characters
* that we read from the byte channel.
*/
if (ret != len)
break;
count -= len;
}
/* Tell the tty layer that we're done. */
tty_flip_buffer_push(ttys);
tty_kref_put(ttys);
return IRQ_HANDLED;
}
/*
* dequeue the transmit buffer to the hypervisor
*
* This function, which can be called in interrupt context, dequeues as much
* data as possible from the transmit buffer to the byte channel.
*/
static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)
{
unsigned int count;
unsigned int len, ret;
unsigned long flags;
do {
spin_lock_irqsave(&bc->lock, flags);
len = min_t(unsigned int,
CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE),
EV_BYTE_CHANNEL_MAX_BYTES);
ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail);
/* 'len' is valid only if the return code is 0 or EV_EAGAIN */
if (!ret || (ret == EV_EAGAIN))
bc->tail = (bc->tail + len) & (BUF_SIZE - 1);
count = CIRC_CNT(bc->head, bc->tail, BUF_SIZE);
spin_unlock_irqrestore(&bc->lock, flags);
} while (count && !ret);
spin_lock_irqsave(&bc->lock, flags);
if (CIRC_CNT(bc->head, bc->tail, BUF_SIZE))
/*
* If we haven't emptied the buffer, then enable the TX IRQ.
* We'll get an interrupt when there's more room in the
* hypervisor's output buffer.
*/
enable_tx_interrupt(bc);
else
disable_tx_interrupt(bc);
spin_unlock_irqrestore(&bc->lock, flags);
}
/*
* byte channel transmit interupt handler
*
* This ISR is called whenever space becomes available for transmitting
* characters on a byte channel.
*/
static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
{
struct ehv_bc_data *bc = data;
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
ehv_bc_tx_dequeue(bc);
if (ttys) {
tty_wakeup(ttys);
tty_kref_put(ttys);
}
return IRQ_HANDLED;
}
/*
* This function is called when the tty layer has data for us send. We store
* the data first in a circular buffer, and then dequeue as much of that data
* as possible.
*
* We don't need to worry about whether there is enough room in the buffer for
* all the data. The purpose of ehv_bc_tty_write_room() is to tell the tty
* layer how much data it can safely send to us. We guarantee that
* ehv_bc_tty_write_room() will never lie, so the tty layer will never send us
* too much data.
*/
static int ehv_bc_tty_write(struct tty_struct *ttys, const unsigned char *s,
int count)
{
struct ehv_bc_data *bc = ttys->driver_data;
unsigned long flags;
unsigned int len;
unsigned int written = 0;
while (1) {
spin_lock_irqsave(&bc->lock, flags);
len = CIRC_SPACE_TO_END(bc->head, bc->tail, BUF_SIZE);
if (count < len)
len = count;
if (len) {
memcpy(bc->buf + bc->head, s, len);
bc->head = (bc->head + len) & (BUF_SIZE - 1);
}
spin_unlock_irqrestore(&bc->lock, flags);
if (!len)
break;
s += len;
count -= len;
written += len;
}
ehv_bc_tx_dequeue(bc);
return written;
}
/*
* This function can be called multiple times for a given tty_struct, which is
* why we initialize bc->ttys in ehv_bc_tty_port_activate() instead.
*
* The tty layer will still call this function even if the device was not
* registered (i.e. tty_register_device() was not called). This happens
* because tty_register_device() is optional and some legacy drivers don't
* use it. So we need to check for that.
*/
static int ehv_bc_tty_open(struct tty_struct *ttys, struct file *filp)
{
struct ehv_bc_data *bc = &bcs[ttys->index];
if (!bc->dev)
return -ENODEV;
return tty_port_open(&bc->port, ttys, filp);
}
/*
* Amazingly, if ehv_bc_tty_open() returns an error code, the tty layer will
* still call this function to close the tty device. So we can't assume that
* the tty port has been initialized.
*/
static void ehv_bc_tty_close(struct tty_struct *ttys, struct file *filp)
{
struct ehv_bc_data *bc = &bcs[ttys->index];
if (bc->dev)
tty_port_close(&bc->port, ttys, filp);
}
/*
* Return the amount of space in the output buffer
*
* This is actually a contract between the driver and the tty layer outlining
* how much write room the driver can guarantee will be sent OR BUFFERED. This
* driver MUST honor the return value.
*/
static int ehv_bc_tty_write_room(struct tty_struct *ttys)
{
struct ehv_bc_data *bc = ttys->driver_data;
unsigned long flags;
int count;
spin_lock_irqsave(&bc->lock, flags);
count = CIRC_SPACE(bc->head, bc->tail, BUF_SIZE);
spin_unlock_irqrestore(&bc->lock, flags);
return count;
}
/*
* Stop sending data to the tty layer
*
* This function is called when the tty layer's input buffers are getting full,
* so the driver should stop sending it data. The easiest way to do this is to
* disable the RX IRQ, which will prevent ehv_bc_tty_rx_isr() from being
* called.
*
* The hypervisor will continue to queue up any incoming data. If there is any
* data in the queue when the RX interrupt is enabled, we'll immediately get an
* RX interrupt.
*/
static void ehv_bc_tty_throttle(struct tty_struct *ttys)
{
struct ehv_bc_data *bc = ttys->driver_data;
disable_irq(bc->rx_irq);
}
/*
* Resume sending data to the tty layer
*
* This function is called after previously calling ehv_bc_tty_throttle(). The
* tty layer's input buffers now have more room, so the driver can resume
* sending it data.
*/
static void ehv_bc_tty_unthrottle(struct tty_struct *ttys)
{
struct ehv_bc_data *bc = ttys->driver_data;
/* If there is any data in the queue when the RX interrupt is enabled,
* we'll immediately get an RX interrupt.
*/
enable_irq(bc->rx_irq);
}
static void ehv_bc_tty_hangup(struct tty_struct *ttys)
{
struct ehv_bc_data *bc = ttys->driver_data;
ehv_bc_tx_dequeue(bc);
tty_port_hangup(&bc->port);
}
/*
* TTY driver operations
*
* If we could ask the hypervisor how much data is still in the TX buffer, or
* at least how big the TX buffers are, then we could implement the
* .wait_until_sent and .chars_in_buffer functions.
*/
static const struct tty_operations ehv_bc_ops = {
.open = ehv_bc_tty_open,
.close = ehv_bc_tty_close,
.write = ehv_bc_tty_write,
.write_room = ehv_bc_tty_write_room,
.throttle = ehv_bc_tty_throttle,
.unthrottle = ehv_bc_tty_unthrottle,
.hangup = ehv_bc_tty_hangup,
};
/*
* initialize the TTY port
*
* This function will only be called once, no matter how many times
* ehv_bc_tty_open() is called. That's why we register the ISR here, and also
* why we initialize tty_struct-related variables here.
*/
static int ehv_bc_tty_port_activate(struct tty_port *port,
struct tty_struct *ttys)
{
struct ehv_bc_data *bc = container_of(port, struct ehv_bc_data, port);
int ret;
ttys->driver_data = bc;
ret = request_irq(bc->rx_irq, ehv_bc_tty_rx_isr, 0, "ehv-bc", bc);
if (ret < 0) {
dev_err(bc->dev, "could not request rx irq %u (ret=%i)\n",
bc->rx_irq, ret);
return ret;
}
/* request_irq also enables the IRQ */
bc->tx_irq_enabled = 1;
ret = request_irq(bc->tx_irq, ehv_bc_tty_tx_isr, 0, "ehv-bc", bc);
if (ret < 0) {
dev_err(bc->dev, "could not request tx irq %u (ret=%i)\n",
bc->tx_irq, ret);
free_irq(bc->rx_irq, bc);
return ret;
}
/* The TX IRQ is enabled only when we can't write all the data to the
* byte channel at once, so by default it's disabled.
*/
disable_tx_interrupt(bc);
return 0;
}
static void ehv_bc_tty_port_shutdown(struct tty_port *port)
{
struct ehv_bc_data *bc = container_of(port, struct ehv_bc_data, port);
free_irq(bc->tx_irq, bc);
free_irq(bc->rx_irq, bc);
}
static const struct tty_port_operations ehv_bc_tty_port_ops = {
.activate = ehv_bc_tty_port_activate,
.shutdown = ehv_bc_tty_port_shutdown,
};
static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct ehv_bc_data *bc;
const uint32_t *iprop;
unsigned int handle;
int ret;
static unsigned int index = 1;
unsigned int i;
iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) {
dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
np->name);
return -ENODEV;
}
/* We already told the console layer that the index for the console
* device is zero, so we need to make sure that we use that index when
* we probe the console byte channel node.
*/
handle = be32_to_cpu(*iprop);
i = (handle == stdout_bc) ? 0 : index++;
bc = &bcs[i];
bc->handle = handle;
bc->head = 0;
bc->tail = 0;
spin_lock_init(&bc->lock);
bc->rx_irq = irq_of_parse_and_map(np, 0);
bc->tx_irq = irq_of_parse_and_map(np, 1);
if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
np->name);
ret = -ENODEV;
goto error;
}
bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
if (IS_ERR(bc->dev)) {
ret = PTR_ERR(bc->dev);
dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
goto error;
}
tty_port_init(&bc->port);
bc->port.ops = &ehv_bc_tty_port_ops;
dev_set_drvdata(&pdev->dev, bc);
dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
ehv_bc_driver->name, i, bc->handle);
return 0;
error:
irq_dispose_mapping(bc->tx_irq);
irq_dispose_mapping(bc->rx_irq);
memset(bc, 0, sizeof(struct ehv_bc_data));
return ret;
}
static int ehv_bc_tty_remove(struct platform_device *pdev)
{
struct ehv_bc_data *bc = dev_get_drvdata(&pdev->dev);
tty_unregister_device(ehv_bc_driver, bc - bcs);
irq_dispose_mapping(bc->tx_irq);
irq_dispose_mapping(bc->rx_irq);
return 0;
}
static const struct of_device_id ehv_bc_tty_of_ids[] = {
{ .compatible = "epapr,hv-byte-channel" },
{}
};
static struct platform_driver ehv_bc_tty_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ehv-bc",
.of_match_table = ehv_bc_tty_of_ids,
},
.probe = ehv_bc_tty_probe,
.remove = ehv_bc_tty_remove,
};
/**
* ehv_bc_init - ePAPR hypervisor byte channel driver initialization
*
* This function is called when this module is loaded.
*/
static int __init ehv_bc_init(void)
{
struct device_node *np;
unsigned int count = 0; /* Number of elements in bcs[] */
int ret;
pr_info("ePAPR hypervisor byte channel driver\n");
/* Count the number of byte channels */
for_each_compatible_node(np, NULL, "epapr,hv-byte-channel")
count++;
if (!count)
return -ENODEV;
/* The array index of an element in bcs[] is the same as the tty index
* for that element. If you know the address of an element in the
* array, then you can use pointer math (e.g. "bc - bcs") to get its
* tty index.
*/
bcs = kzalloc(count * sizeof(struct ehv_bc_data), GFP_KERNEL);
if (!bcs)
return -ENOMEM;
ehv_bc_driver = alloc_tty_driver(count);
if (!ehv_bc_driver) {
ret = -ENOMEM;
goto error;
}
ehv_bc_driver->owner = THIS_MODULE;
ehv_bc_driver->driver_name = "ehv-bc";
ehv_bc_driver->name = ehv_bc_console.name;
ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ehv_bc_driver->subtype = SYSTEM_TYPE_CONSOLE;
ehv_bc_driver->init_termios = tty_std_termios;
ehv_bc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ehv_bc_driver, &ehv_bc_ops);
ret = tty_register_driver(ehv_bc_driver);
if (ret) {
pr_err("ehv-bc: could not register tty driver (ret=%i)\n", ret);
goto error;
}
ret = platform_driver_register(&ehv_bc_tty_driver);
if (ret) {
pr_err("ehv-bc: could not register platform driver (ret=%i)\n",
ret);
goto error;
}
return 0;
error:
if (ehv_bc_driver) {
tty_unregister_driver(ehv_bc_driver);
put_tty_driver(ehv_bc_driver);
}
kfree(bcs);
return ret;
}
/**
* ehv_bc_exit - ePAPR hypervisor byte channel driver termination
*
* This function is called when this driver is unloaded.
*/
static void __exit ehv_bc_exit(void)
{
tty_unregister_driver(ehv_bc_driver);
put_tty_driver(ehv_bc_driver);
kfree(bcs);
}
module_init(ehv_bc_init);
module_exit(ehv_bc_exit);
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("ePAPR hypervisor byte channel driver");
MODULE_LICENSE("GPL v2");

View File

@ -388,7 +388,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
* there is no buffered data otherwise sleeps on a wait queue
* waking periodically to check chars_in_buffer().
*/
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
} else {
if (hp->count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
@ -852,7 +852,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
* find index to use:
* see if this vterm id matches one registered for console.
*/
for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
for (i = 0; i < MAX_NR_HVC_CONSOLES; i++)
if (vtermnos[i] == hp->vtermno &&
cons_ops[i] == hp->ops)
break;
@ -862,9 +862,13 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
i = ++last_hvc;
hp->index = i;
hvc_console.index = i;
vtermnos[i] = vtermno;
cons_ops[i] = ops;
list_add_tail(&(hp->next), &hvc_structs);
spin_unlock(&hvc_structs_lock);
register_console(&hvc_console);
return hp;
}
@ -875,6 +879,7 @@ int hvc_remove(struct hvc_struct *hp)
unsigned long flags;
struct tty_struct *tty;
unregister_console(&hvc_console);
spin_lock_irqsave(&hp->lock, flags);
tty = tty_kref_get(hp->tty);

View File

@ -28,7 +28,7 @@ int notifier_add_irq(struct hvc_struct *hp, int irq)
hp->irq_requested = 0;
return 0;
}
rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
rc = request_irq(irq, hvc_handle_interrupt, 0,
"hvc_console", hp);
if (!rc)
hp->irq_requested = 1;

View File

@ -1057,7 +1057,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
* the conn was registered and now.
*/
if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
IRQF_DISABLED, "ibmhvcs", hvcsd))) {
0, "ibmhvcs", hvcsd))) {
/*
* It is possible the vty-server was removed after the irq was
* requested but before we have time to enable interrupts.
@ -1237,7 +1237,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
irq = hvcsd->vdev->irq;
spin_unlock_irqrestore(&hvcsd->lock, flags);
tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT);
/*
* This line is important because it tells hvcs_open that this

View File

@ -1105,7 +1105,7 @@ static int __init hvsi_init(void)
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;
ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp);
ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
if (ret)
printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
hp->virq, ret);

View File

@ -1598,7 +1598,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
}
retval = request_irq(board->irq, isicom_interrupt,
IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
IRQF_SHARED, ISICOM_NAME, board);
if (retval < 0) {
dev_err(&pdev->dev, "Could not install handler at Irq %d. "
"Card%d will be disabled.\n", board->irq, index + 1);

View File

@ -2005,16 +2005,9 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
*/
if (!timeout || timeout > 2 * info->timeout)
timeout = 2 * info->timeout;
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
spin_lock_irqsave(&info->slock, flags);
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
#endif
spin_unlock_irqrestore(&info->slock, flags);
schedule_timeout_interruptible(char_time);
spin_lock_irqsave(&info->slock, flags);
@ -2025,10 +2018,6 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
}
spin_unlock_irqrestore(&info->slock, flags);
set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
}
/*

View File

@ -21,7 +21,6 @@
* Mostly done: ioctls for setting modes/timing
* Partly done: hooks so you can pull off frames to non tty devs
* Restart DLCI 0 when it closes ?
* Test basic encoding
* Improve the tx engine
* Resolve tx side locking by adding a queue_head and routing
* all control traffic via it
@ -810,38 +809,41 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
{
struct gsm_msg *msg;
u8 *dp;
int len, size;
int len, total_size, size;
int h = dlci->adaption - 1;
len = kfifo_len(dlci->fifo);
if (len == 0)
return 0;
total_size = 0;
while(1) {
len = kfifo_len(dlci->fifo);
if (len == 0)
return total_size;
/* MTU/MRU count only the data bits */
if (len > gsm->mtu)
len = gsm->mtu;
/* MTU/MRU count only the data bits */
if (len > gsm->mtu)
len = gsm->mtu;
size = len + h;
size = len + h;
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
/* FIXME: need a timer or something to kick this so it can't
get stuck with no work outstanding and no buffer free */
if (msg == NULL)
return -ENOMEM;
dp = msg->data;
switch (dlci->adaption) {
case 1: /* Unstructured */
break;
case 2: /* Unstructed with modem bits. Always one byte as we never
send inline break data */
*dp += gsm_encode_modem(dlci);
len--;
break;
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
/* FIXME: need a timer or something to kick this so it can't
get stuck with no work outstanding and no buffer free */
if (msg == NULL)
return -ENOMEM;
dp = msg->data;
switch (dlci->adaption) {
case 1: /* Unstructured */
break;
case 2: /* Unstructed with modem bits. Always one byte as we never
send inline break data */
*dp++ = gsm_encode_modem(dlci);
break;
}
WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
__gsm_data_queue(dlci, msg);
total_size += size;
}
WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
__gsm_data_queue(dlci, msg);
/* Bytes of data we used up */
return size;
return total_size;
}
/**
@ -2004,6 +2006,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
int i;
struct gsm_dlci *dlci = gsm->dlci[0];
struct gsm_msg *txq;
struct gsm_control *gc;
gsm->dead = 1;
@ -2017,6 +2020,13 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
spin_unlock(&gsm_mux_lock);
WARN_ON(i == MAX_MUX);
/* In theory disconnecting DLCI 0 is sufficient but for some
modems this is apparently not the case. */
if (dlci) {
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
if (gc)
gsm_control_wait(gsm, gc);
}
del_timer_sync(&gsm->t2_timer);
/* Now we are sure T2 has stopped */
if (dlci) {
@ -2982,7 +2992,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
struct gsm_dlci *dlci = tty->driver_data;
unsigned int modem_tx = dlci->modem_tx;
modem_tx &= clear;
modem_tx &= ~clear;
modem_tx |= set;
if (modem_tx != dlci->modem_tx) {

View File

@ -670,12 +670,18 @@ static int ptmx_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
retval = tty_alloc_file(filp);
if (retval)
return retval;
/* find a device that is not in use. */
tty_lock();
index = devpts_new_index(inode);
tty_unlock();
if (index < 0)
return index;
if (index < 0) {
retval = index;
goto err_file;
}
mutex_lock(&tty_mutex);
tty_lock();
@ -689,27 +695,27 @@ static int ptmx_open(struct inode *inode, struct file *filp)
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
retval = tty_add_file(tty, filp);
if (retval)
goto out;
tty_add_file(tty, filp);
retval = devpts_pty_new(inode, tty->link);
if (retval)
goto out1;
goto err_release;
retval = ptm_driver->ops->open(tty, filp);
if (retval)
goto out2;
out1:
goto err_release;
tty_unlock();
return retval;
out2:
return 0;
err_release:
tty_unlock();
tty_release(inode, filp);
return retval;
out:
devpts_kill_index(inode, index);
tty_unlock();
err_file:
tty_free_file(filp);
return retval;
}

View File

@ -235,22 +235,6 @@ static void batten_down_hatches(void)
static void status_handle(struct m68k_serial *info, unsigned short status)
{
#if 0
if(status & DCD) {
if((info->port.tty->termios->c_cflag & CRTSCTS) &&
((info->curregs[3] & AUTO_ENAB)==0)) {
info->curregs[3] |= AUTO_ENAB;
info->pendregs[3] |= AUTO_ENAB;
write_zsreg(info->m68k_channel, 3, info->curregs[3]);
}
} else {
if((info->curregs[3] & AUTO_ENAB)) {
info->curregs[3] &= ~AUTO_ENAB;
info->pendregs[3] &= ~AUTO_ENAB;
write_zsreg(info->m68k_channel, 3, info->curregs[3]);
}
}
#endif
/* If this is console input and this is a
* 'break asserted' status change interrupt
* see if we can drop into the debugger
@ -340,9 +324,6 @@ static void transmit_chars(struct m68k_serial *info)
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt--;
if (info->xmit_cnt < WAKEUP_CHARS)
schedule_work(&info->tqueue);
if(info->xmit_cnt <= 0) {
/* All done for now... TX ints off */
uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
@ -378,21 +359,6 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void do_softint(struct work_struct *work)
{
struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue);
struct tty_struct *tty;
tty = info->tty;
if (!tty)
return;
#if 0
if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
tty_wakeup(tty);
}
#endif
}
static int startup(struct m68k_serial * info)
{
m68328_uart *uart = &uart_addr[info->line];
@ -1324,7 +1290,6 @@ rs68328_init(void)
info->event = 0;
info->count = 0;
info->blocked_open = 0;
INIT_WORK(&info->tqueue, do_softint);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
info->line = i;
@ -1341,7 +1306,7 @@ rs68328_init(void)
if (request_irq(uart_irqs[i],
rs_interrupt,
IRQF_DISABLED,
0,
"M68328_UART", info))
panic("Unable to attach 68328 serial interrupt\n");
}

View File

@ -158,7 +158,6 @@ struct m68k_serial {
int xmit_head;
int xmit_tail;
int xmit_cnt;
struct work_struct tqueue;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
};

View File

@ -309,6 +309,13 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_T_TRIG_01,
.flags = UART_CAP_FIFO | UART_CAP_RTOIE,
},
[PORT_XR17D15X] = {
.name = "XR17D15X",
.fifo_size = 64,
.tx_loadsz = 64,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
},
};
#if defined(CONFIG_MIPS_ALCHEMY)
@ -461,42 +468,6 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset);
}
/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
static inline void dwapb_save_out_value(struct uart_port *p, int offset,
int value)
{
struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port);
if (offset == UART_LCR)
up->lcr = value;
}
/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
{
if (offset == UART_TX || offset == UART_IER)
p->serial_in(p, UART_IER);
}
static void dwapb_serial_out(struct uart_port *p, int offset, int value)
{
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
dwapb_save_out_value(p, save_offset, value);
writeb(value, p->membase + offset);
dwapb_check_clear_ier(p, save_offset);
}
static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
{
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
dwapb_save_out_value(p, save_offset, value);
writel(value, p->membase + offset);
dwapb_check_clear_ier(p, save_offset);
}
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = map_8250_in_reg(p, offset) << p->regshift;
@ -509,6 +480,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
outb(value, p->iobase + offset);
}
static int serial8250_default_handle_irq(struct uart_port *port);
static void set_io_from_upio(struct uart_port *p)
{
struct uart_8250_port *up =
@ -540,16 +513,6 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = tsi_serial_out;
break;
case UPIO_DWAPB:
p->serial_in = mem_serial_in;
p->serial_out = dwapb_serial_out;
break;
case UPIO_DWAPB32:
p->serial_in = mem32_serial_in;
p->serial_out = dwapb32_serial_out;
break;
default:
p->serial_in = io_serial_in;
p->serial_out = io_serial_out;
@ -557,6 +520,7 @@ static void set_io_from_upio(struct uart_port *p)
}
/* Remember loaded iotype */
up->cur_iotype = p->iotype;
p->handle_irq = serial8250_default_handle_irq;
}
static void
@ -567,8 +531,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
case UPIO_MEM:
case UPIO_MEM32:
case UPIO_AU:
case UPIO_DWAPB:
case UPIO_DWAPB32:
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
break;
@ -1119,6 +1081,14 @@ static void autoconfig_16550a(struct uart_8250_port *up)
}
serial_outp(up, UART_IER, iersave);
/*
* Exar uarts have EFR in a weird location
*/
if (up->port.flags & UPF_EXAR_EFR) {
up->port.type = PORT_XR17D15X;
up->capabilities |= UART_CAP_AFE | UART_CAP_EFR;
}
/*
* We distinguish between 16550A and U6 16550A by counting
* how many bytes are in the FIFO.
@ -1621,6 +1591,29 @@ static void serial8250_handle_port(struct uart_8250_port *up)
spin_unlock_irqrestore(&up->port.lock, flags);
}
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
if (!(iir & UART_IIR_NO_INT)) {
serial8250_handle_port(up);
return 1;
}
return 0;
}
EXPORT_SYMBOL_GPL(serial8250_handle_irq);
static int serial8250_default_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
unsigned int iir = serial_in(up, UART_IIR);
return serial8250_handle_irq(port, iir);
}
/*
* This is the serial driver's interrupt routine.
*
@ -1648,30 +1641,13 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
l = i->head;
do {
struct uart_8250_port *up;
unsigned int iir;
struct uart_port *port;
up = list_entry(l, struct uart_8250_port, list);
port = &up->port;
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT)) {
serial8250_handle_port(up);
if (port->handle_irq(port)) {
handled = 1;
end = NULL;
} else if ((up->port.iotype == UPIO_DWAPB ||
up->port.iotype == UPIO_DWAPB32) &&
(iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* The DesignWare APB UART has an Busy Detect (0x07)
* interrupt meaning an LCR write attempt occurred while the
* UART was busy. The interrupt must be cleared by reading
* the UART status register (USR) and the LCR re-written. */
unsigned int status;
status = *(volatile u32 *)up->port.private_data;
serial_out(up, UART_LCR, up->lcr);
handled = 1;
end = NULL;
} else if (end == NULL)
end = l;
@ -2081,8 +2057,8 @@ static int serial8250_startup(struct uart_port *port)
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
(serial_inp(up, UART_LSR) == 0xff)) {
printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
serial_index(&up->port));
printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
serial_index(&up->port));
return -ENODEV;
}
@ -2458,7 +2434,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
efr |= UART_EFR_CTS;
serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(up, UART_EFR, efr);
if (up->port.flags & UPF_EXAR_EFR)
serial_outp(up, UART_XR_EFR, efr);
else
serial_outp(up, UART_EFR, efr);
}
#ifdef CONFIG_ARCH_OMAP
@ -2570,8 +2549,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM:
case UPIO_DWAPB:
case UPIO_DWAPB32:
if (!up->port.mapbase)
break;
@ -2608,8 +2585,6 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM:
case UPIO_DWAPB:
case UPIO_DWAPB32:
if (!up->port.mapbase)
break;
@ -3050,6 +3025,10 @@ int __init early_serial_setup(struct uart_port *port)
p->serial_in = port->serial_in;
if (port->serial_out)
p->serial_out = port->serial_out;
if (port->handle_irq)
p->handle_irq = port->handle_irq;
else
p->handle_irq = serial8250_default_handle_irq;
return 0;
}
@ -3118,6 +3097,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.type = p->type;
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
@ -3283,6 +3263,8 @@ int serial8250_register_port(struct uart_port *port)
uart->port.serial_in = port->serial_in;
if (port->serial_out)
uart->port.serial_out = port->serial_out;
if (port->handle_irq)
uart->port.handle_irq = port->handle_irq;
/* Possibly override set_termios call */
if (port->set_termios)
uart->port.set_termios = port->set_termios;

View File

@ -0,0 +1,194 @@
/*
* Synopsys DesignWare 8250 driver.
*
* Copyright 2011 Picochip, Jamie Iles.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The Synopsys DesignWare 8250 has an extra feature whereby it detects if the
* LCR is written whilst busy. If it is, then a busy detect interrupt is
* raised, the LCR needs to be rewritten and the uart status register read.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
struct dw8250_data {
int last_lcr;
int line;
};
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
if (offset == UART_LCR)
d->last_lcr = value;
offset <<= p->regshift;
writeb(value, p->membase + offset);
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
{
offset <<= p->regshift;
return readb(p->membase + offset);
}
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
if (offset == UART_LCR)
d->last_lcr = value;
offset <<= p->regshift;
writel(value, p->membase + offset);
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
{
offset <<= p->regshift;
return readl(p->membase + offset);
}
/* Offset for the DesignWare's UART Status Register. */
#define UART_USR 0x1f
static int dw8250_handle_irq(struct uart_port *p)
{
struct dw8250_data *d = p->private_data;
unsigned int iir = p->serial_in(p, UART_IIR);
if (serial8250_handle_irq(p, iir)) {
return 1;
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR and write the LCR again. */
(void)p->serial_in(p, UART_USR);
p->serial_out(p, d->last_lcr, UART_LCR);
return 1;
}
return 0;
}
static int __devinit dw8250_probe(struct platform_device *pdev)
{
struct uart_port port = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct device_node *np = pdev->dev.of_node;
u32 val;
struct dw8250_data *data;
if (!regs || !irq) {
dev_err(&pdev->dev, "no registers/irq defined\n");
return -EINVAL;
}
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
port.private_data = data;
spin_lock_init(&port.lock);
port.mapbase = regs->start;
port.irq = irq->start;
port.handle_irq = dw8250_handle_irq;
port.type = PORT_8250;
port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
UPF_FIXED_PORT | UPF_FIXED_TYPE;
port.dev = &pdev->dev;
port.iotype = UPIO_MEM;
port.serial_in = dw8250_serial_in;
port.serial_out = dw8250_serial_out;
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
case 4:
port.iotype = UPIO_MEM32;
port.serial_in = dw8250_serial_in32;
port.serial_out = dw8250_serial_out32;
break;
default:
dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
val);
return -EINVAL;
}
}
if (!of_property_read_u32(np, "reg-shift", &val))
port.regshift = val;
if (of_property_read_u32(np, "clock-frequency", &val)) {
dev_err(&pdev->dev, "no clock-frequency property set\n");
return -EINVAL;
}
port.uartclk = val;
data->line = serial8250_register_port(&port);
if (data->line < 0)
return data->line;
platform_set_drvdata(pdev, data);
return 0;
}
static int __devexit dw8250_remove(struct platform_device *pdev)
{
struct dw8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
return 0;
}
static const struct of_device_id dw8250_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw8250_match);
static struct platform_driver dw8250_platform_driver = {
.driver = {
.name = "dw-apb-uart",
.owner = THIS_MODULE,
.of_match_table = dw8250_match,
},
.probe = dw8250_probe,
.remove = __devexit_p(dw8250_remove),
};
static int __init dw8250_init(void)
{
return platform_driver_register(&dw8250_platform_driver);
}
module_init(dw8250_init);
static void __exit dw8250_exit(void)
{
platform_driver_unregister(&dw8250_platform_driver);
}
module_exit(dw8250_exit);
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");

View File

@ -1101,6 +1101,15 @@ static int pci_eg20t_init(struct pci_dev *dev)
#endif
}
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
port->flags |= UPF_EXAR_EFR;
return pci_default_setup(priv, board, port, idx);
}
/* This should be in linux/pci_ids.h */
#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
@ -1505,6 +1514,30 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_timedia_setup,
},
/*
* Exar cards
*/
{
.vendor = PCI_VENDOR_ID_EXAR,
.device = PCI_DEVICE_ID_EXAR_XR17C152,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_xr17c154_setup,
},
{
.vendor = PCI_VENDOR_ID_EXAR,
.device = PCI_DEVICE_ID_EXAR_XR17C154,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_xr17c154_setup,
},
{
.vendor = PCI_VENDOR_ID_EXAR,
.device = PCI_DEVICE_ID_EXAR_XR17C158,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_xr17c154_setup,
},
/*
* Xircom cards
*/
@ -1558,46 +1591,55 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8811,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8812,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8813,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8814,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8027,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8028,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8029,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x800C,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x800D,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
/*
* Cronyx Omega PCI (PLX-chip based)

View File

@ -267,6 +267,13 @@ config SERIAL_8250_RM9K
port hardware found on MIPS RM9122 and similar processors.
If unsure, say N.
config SERIAL_8250_DW
tristate "Support for Synopsys DesignWare 8250 quirks"
depends on SERIAL_8250 && OF
help
Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART.
comment "Non-8250 serial port support"
config SERIAL_AMBA_PL010
@ -522,8 +529,8 @@ config SERIAL_S3C6400
config SERIAL_S5PV210
tristate "Samsung S5PV210 Serial port support"
depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210)
select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210)
depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212)
select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212)
default y
help
Serial port support for Samsung's S5P Family of SoC's
@ -722,7 +729,7 @@ config SERIAL_BFIN
Add support for the built-in UARTs on the Blackfin.
To compile this driver as a module, choose M here: the
module will be called bfin_5xx.
module is named bfin_uart.ko.
config SERIAL_BFIN_CONSOLE
bool "Console on Blackfin serial port"
@ -1035,23 +1042,6 @@ config SERIAL_MCF_CONSOLE
help
Enable a ColdFire internal serial port to be the system console.
config SERIAL_68360_SMC
bool "68360 SMC uart support"
depends on M68360
help
This driver supports the SMC serial ports of the Motorola 68360 CPU.
config SERIAL_68360_SCC
bool "68360 SCC uart support"
depends on M68360
help
This driver supports the SCC serial ports of the Motorola 68360 CPU.
config SERIAL_68360
bool
depends on SERIAL_68360_SMC || SERIAL_68360_SCC
default y
config SERIAL_PMACZILOG
tristate "Mac or PowerMac z85c30 ESCC support"
depends on (M68K && MAC) || (PPC_OF && PPC_PMAC)

View File

@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
@ -35,7 +36,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
@ -49,7 +50,6 @@ obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_DZ) += dz.o

View File

@ -218,7 +218,7 @@ static int altera_jtaguart_startup(struct uart_port *port)
unsigned long flags;
int ret;
ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
DRV_NAME, port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "

View File

@ -315,7 +315,7 @@ static int altera_uart_startup(struct uart_port *port)
return 0;
}
ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
ret = request_irq(port->irq, altera_uart_interrupt, 0,
DRV_NAME, port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera UART %d "

View File

@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>

View File

@ -33,6 +33,8 @@
#include <linux/sysrq.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
@ -157,11 +159,22 @@ struct atmel_uart_port {
};
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
static unsigned long atmel_ports_in_use;
#ifdef SUPPORT_SYSRQ
static struct console atmel_console;
#endif
#if defined(CONFIG_OF)
static const struct of_device_id atmel_serial_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-usart" },
{ .compatible = "atmel,at91sam9260-usart" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids);
#endif
static inline struct atmel_uart_port *
to_atmel_uart_port(struct uart_port *uart)
{
@ -339,7 +352,8 @@ static void atmel_stop_tx(struct uart_port *port)
/* Disable interrupts */
UART_PUT_IDR(port, atmel_port->tx_done_mask);
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
!(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
atmel_start_rx(port);
}
@ -356,7 +370,8 @@ static void atmel_start_tx(struct uart_port *port)
really need this.*/
return;
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
!(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
atmel_stop_rx(port);
/* re-enable PDC transmit */
@ -680,7 +695,8 @@ static void atmel_tx_dma(struct uart_port *port)
/* Enable interrupts */
UART_PUT_IER(port, atmel_port->tx_done_mask);
} else {
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
!(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@ -1407,6 +1423,48 @@ static struct uart_ops atmel_pops = {
#endif
};
static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port,
struct device_node *np)
{
u32 rs485_delay[2];
/* DMA/PDC usage specification */
if (of_get_property(np, "atmel,use-dma-rx", NULL))
atmel_port->use_dma_rx = 1;
else
atmel_port->use_dma_rx = 0;
if (of_get_property(np, "atmel,use-dma-tx", NULL))
atmel_port->use_dma_tx = 1;
else
atmel_port->use_dma_tx = 0;
/* rs485 properties */
if (of_property_read_u32_array(np, "rs485-rts-delay",
rs485_delay, 2) == 0) {
struct serial_rs485 *rs485conf = &atmel_port->rs485;
rs485conf->delay_rts_before_send = rs485_delay[0];
rs485conf->delay_rts_after_send = rs485_delay[1];
rs485conf->flags = 0;
if (rs485conf->delay_rts_before_send == 0 &&
rs485conf->delay_rts_after_send == 0) {
rs485conf->flags |= SER_RS485_RTS_ON_SEND;
} else {
if (rs485conf->delay_rts_before_send)
rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND;
if (rs485conf->delay_rts_after_send)
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
}
if (of_get_property(np, "rs485-rx-during-tx", NULL))
rs485conf->flags |= SER_RS485_RX_DURING_TX;
if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
rs485conf->flags |= SER_RS485_ENABLED;
}
}
/*
* Configure the port from the platform device resource info.
*/
@ -1414,13 +1472,20 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *data = pdev->dev.platform_data;
struct atmel_uart_data *pdata = pdev->dev.platform_data;
if (pdev->dev.of_node) {
atmel_of_init_port(atmel_port, pdev->dev.of_node);
} else {
atmel_port->use_dma_rx = pdata->use_dma_rx;
atmel_port->use_dma_tx = pdata->use_dma_tx;
atmel_port->rs485 = pdata->rs485;
}
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &atmel_pops;
port->fifosize = 1;
port->line = data->num;
port->dev = &pdev->dev;
port->mapbase = pdev->resource[0].start;
port->irq = pdev->resource[1].start;
@ -1430,10 +1495,10 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
if (data->regs)
if (pdata && pdata->regs) {
/* Already mapped by setup code */
port->membase = data->regs;
else {
port->membase = pdata->regs;
} else {
port->flags |= UPF_IOREMAP;
port->membase = NULL;
}
@ -1447,9 +1512,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
/* only enable clock when USART is in use */
}
atmel_port->use_dma_rx = data->use_dma_rx;
atmel_port->use_dma_tx = data->use_dma_tx;
atmel_port->rs485 = data->rs485;
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
@ -1611,10 +1673,14 @@ static int __init atmel_console_init(void)
if (atmel_default_console_device) {
struct atmel_uart_data *pdata =
atmel_default_console_device->dev.platform_data;
int id = pdata->num;
struct atmel_uart_port *port = &atmel_ports[id];
add_preferred_console(ATMEL_DEVICENAME, pdata->num, NULL);
atmel_init_port(&atmel_ports[pdata->num],
atmel_default_console_device);
port->backup_imr = 0;
port->uart.line = id;
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
atmel_init_port(port, atmel_default_console_device);
register_console(&atmel_console);
}
@ -1711,14 +1777,39 @@ static int atmel_serial_resume(struct platform_device *pdev)
static int __devinit atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
struct device_node *np = pdev->dev.of_node;
struct atmel_uart_data *pdata = pdev->dev.platform_data;
void *data;
int ret;
int ret = -ENODEV;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
port = &atmel_ports[pdata->num];
if (np)
ret = of_alias_get_id(np, "serial");
else
if (pdata)
ret = pdata->num;
if (ret < 0)
/* port id not found in platform data nor device-tree aliases:
* auto-enumerate it */
ret = find_first_zero_bit(&atmel_ports_in_use,
sizeof(atmel_ports_in_use));
if (ret > ATMEL_MAX_UART) {
ret = -ENODEV;
goto err;
}
if (test_and_set_bit(ret, &atmel_ports_in_use)) {
/* port already in use */
ret = -EBUSY;
goto err;
}
port = &atmel_ports[ret];
port->backup_imr = 0;
port->uart.line = ret;
atmel_init_port(port, pdev);
@ -1764,7 +1855,7 @@ err_alloc_ring:
clk_put(port->clk);
port->clk = NULL;
}
err:
return ret;
}
@ -1784,6 +1875,8 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
/* "port" is allocated statically, so we shouldn't free it */
clear_bit(port->line, &atmel_ports_in_use);
clk_put(atmel_port->clk);
return ret;
@ -1797,6 +1890,7 @@ static struct platform_driver atmel_serial_driver = {
.driver = {
.name = "atmel_usart",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
},
};

View File

@ -294,7 +294,7 @@ static int sport_startup(struct uart_port *port)
if (request_irq(gpio_to_irq(up->cts_pin),
sport_mctrl_cts_int,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
0, "BFIN_SPORT_UART_CTS", up)) {
up->cts_pin = -1;
dev_info(port->dev, "Unable to attach BlackFin UART over SPORT CTS interrupt. So, disable it.\n");
}

View File

@ -234,8 +234,8 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
status = UART_GET_LSR(uart);
UART_CLEAR_LSR(uart);
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
@ -667,17 +667,17 @@ static int bfin_serial_startup(struct uart_port *port)
kgdboc_break_enabled = 0;
else {
# endif
if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
if (request_irq(uart->rx_irq, bfin_serial_rx_int, 0,
"BFIN_UART_RX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
return -EBUSY;
}
if (request_irq
(uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
(uart->tx_irq, bfin_serial_tx_int, 0,
"BFIN_UART_TX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
free_irq(uart->port.irq, uart);
free_irq(uart->rx_irq, uart);
return -EBUSY;
}
@ -692,7 +692,7 @@ static int bfin_serial_startup(struct uart_port *port)
*/
unsigned uart_dma_ch_rx, uart_dma_ch_tx;
switch (uart->port.irq) {
switch (uart->rx_irq) {
case IRQ_UART3_RX:
uart_dma_ch_rx = CH_UART3_RX;
uart_dma_ch_tx = CH_UART3_TX;
@ -709,16 +709,16 @@ static int bfin_serial_startup(struct uart_port *port)
if (uart_dma_ch_rx &&
request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) {
printk(KERN_NOTICE"Fail to attach UART interrupt\n");
free_irq(uart->port.irq, uart);
free_irq(uart->port.irq + 1, uart);
free_irq(uart->rx_irq, uart);
free_irq(uart->tx_irq, uart);
return -EBUSY;
}
if (uart_dma_ch_tx &&
request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) {
printk(KERN_NOTICE "Fail to attach UART interrupt\n");
free_dma(uart_dma_ch_rx);
free_irq(uart->port.irq, uart);
free_irq(uart->port.irq + 1, uart);
free_irq(uart->rx_irq, uart);
free_irq(uart->tx_irq, uart);
return -EBUSY;
}
}
@ -734,19 +734,18 @@ static int bfin_serial_startup(struct uart_port *port)
if (request_irq(gpio_to_irq(uart->cts_pin),
bfin_serial_mctrl_cts_int,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_DISABLED, "BFIN_UART_CTS", uart)) {
0, "BFIN_UART_CTS", uart)) {
uart->cts_pin = -1;
pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n");
}
}
if (uart->rts_pin >= 0) {
if (uart->rts_pin >= 0)
gpio_direction_output(uart->rts_pin, 0);
}
#endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
bfin_serial_mctrl_cts_int,
IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
0, "BFIN_UART_MODEM_STATUS", uart)) {
uart->cts_pin = -1;
pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
}
@ -786,8 +785,8 @@ static void bfin_serial_shutdown(struct uart_port *port)
break;
};
#endif
free_irq(uart->port.irq, uart);
free_irq(uart->port.irq+1, uart);
free_irq(uart->rx_irq, uart);
free_irq(uart->tx_irq, uart);
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
@ -1091,10 +1090,18 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
*parity = 'o';
}
switch (lcr & 0x03) {
case 0: *bits = 5; break;
case 1: *bits = 6; break;
case 2: *bits = 7; break;
case 3: *bits = 8; break;
case 0:
*bits = 5;
break;
case 1:
*bits = 6;
break;
case 2:
*bits = 7;
break;
case 3:
*bits = 8;
break;
}
/* Set DLAB in LCR to Access DLL and DLH */
UART_SET_DLAB(uart);
@ -1183,7 +1190,7 @@ static struct console bfin_serial_console = {
.index = -1,
.data = &bfin_serial_reg,
};
#define BFIN_SERIAL_CONSOLE &bfin_serial_console
#define BFIN_SERIAL_CONSOLE (&bfin_serial_console)
#else
#define BFIN_SERIAL_CONSOLE NULL
#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
@ -1312,14 +1319,22 @@ static int bfin_serial_probe(struct platform_device *pdev)
}
uart->port.mapbase = res->start;
uart->port.irq = platform_get_irq(pdev, 0);
if (uart->port.irq < 0) {
dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n");
uart->tx_irq = platform_get_irq(pdev, 0);
if (uart->tx_irq < 0) {
dev_err(&pdev->dev, "No uart TX IRQ specified\n");
ret = -ENOENT;
goto out_error_unmap;
}
uart->status_irq = platform_get_irq(pdev, 1);
uart->rx_irq = platform_get_irq(pdev, 1);
if (uart->rx_irq < 0) {
dev_err(&pdev->dev, "No uart RX IRQ specified\n");
ret = -ENOENT;
goto out_error_unmap;
}
uart->port.irq = uart->rx_irq;
uart->status_irq = platform_get_irq(pdev, 2);
if (uart->status_irq < 0) {
dev_err(&pdev->dev, "No uart status IRQ specified\n");
ret = -ENOENT;

View File

@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>

View File

@ -258,7 +258,7 @@ static struct e100_serial rs_table[] = {
.dma_out_enabled = 1,
.dma_out_nbr = SER0_TX_DMA_NBR,
.dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
.dma_out_irq_flags = IRQF_DISABLED,
.dma_out_irq_flags = 0,
.dma_out_irq_description = "serial 0 dma tr",
#else
.dma_out_enabled = 0,
@ -271,7 +271,7 @@ static struct e100_serial rs_table[] = {
.dma_in_enabled = 1,
.dma_in_nbr = SER0_RX_DMA_NBR,
.dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
.dma_in_irq_flags = IRQF_DISABLED,
.dma_in_irq_flags = 0,
.dma_in_irq_description = "serial 0 dma rec",
#else
.dma_in_enabled = 0,
@ -313,7 +313,7 @@ static struct e100_serial rs_table[] = {
.dma_out_enabled = 1,
.dma_out_nbr = SER1_TX_DMA_NBR,
.dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
.dma_out_irq_flags = IRQF_DISABLED,
.dma_out_irq_flags = 0,
.dma_out_irq_description = "serial 1 dma tr",
#else
.dma_out_enabled = 0,
@ -326,7 +326,7 @@ static struct e100_serial rs_table[] = {
.dma_in_enabled = 1,
.dma_in_nbr = SER1_RX_DMA_NBR,
.dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
.dma_in_irq_flags = IRQF_DISABLED,
.dma_in_irq_flags = 0,
.dma_in_irq_description = "serial 1 dma rec",
#else
.dma_in_enabled = 0,
@ -369,7 +369,7 @@ static struct e100_serial rs_table[] = {
.dma_out_enabled = 1,
.dma_out_nbr = SER2_TX_DMA_NBR,
.dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
.dma_out_irq_flags = IRQF_DISABLED,
.dma_out_irq_flags = 0,
.dma_out_irq_description = "serial 2 dma tr",
#else
.dma_out_enabled = 0,
@ -382,7 +382,7 @@ static struct e100_serial rs_table[] = {
.dma_in_enabled = 1,
.dma_in_nbr = SER2_RX_DMA_NBR,
.dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
.dma_in_irq_flags = IRQF_DISABLED,
.dma_in_irq_flags = 0,
.dma_in_irq_description = "serial 2 dma rec",
#else
.dma_in_enabled = 0,
@ -423,7 +423,7 @@ static struct e100_serial rs_table[] = {
.dma_out_enabled = 1,
.dma_out_nbr = SER3_TX_DMA_NBR,
.dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
.dma_out_irq_flags = IRQF_DISABLED,
.dma_out_irq_flags = 0,
.dma_out_irq_description = "serial 3 dma tr",
#else
.dma_out_enabled = 0,
@ -436,7 +436,7 @@ static struct e100_serial rs_table[] = {
.dma_in_enabled = 1,
.dma_in_nbr = SER3_RX_DMA_NBR,
.dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
.dma_in_irq_flags = IRQF_DISABLED,
.dma_in_irq_flags = 0,
.dma_in_irq_description = "serial 3 dma rec",
#else
.dma_in_enabled = 0,
@ -1788,7 +1788,7 @@ static unsigned int handle_descr_data(struct e100_serial *info,
struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
if (info->recv_cnt + recvl > 65536) {
printk(KERN_CRIT
printk(KERN_WARNING
"%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
return 0;
}
@ -3813,13 +3813,13 @@ rs_close(struct tty_struct *tty, struct file * filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk(KERN_CRIT
printk(KERN_ERR
"rs_close: bad serial port count; tty->count is 1, "
"info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n",
printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n",
info->line, info->count);
info->count = 0;
}
@ -4452,7 +4452,7 @@ static int __init rs_init(void)
#if defined(CONFIG_ETRAX_RS485_ON_PA)
if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit,
rs485_pa_bit)) {
printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
"RS485 pin\n");
put_tty_driver(driver);
return -EBUSY;
@ -4461,7 +4461,7 @@ static int __init rs_init(void)
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
rs485_port_g_bit)) {
printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
"RS485 pin\n");
put_tty_driver(driver);
return -EBUSY;
@ -4494,7 +4494,7 @@ static int __init rs_init(void)
if (info->enabled) {
if (cris_request_io_interface(info->io_if,
info->io_if_description)) {
printk(KERN_CRIT "ETRAX100LX async serial: "
printk(KERN_ERR "ETRAX100LX async serial: "
"Could not allocate IO pins for "
"%s, port %d\n",
info->io_if_description, i);
@ -4558,7 +4558,7 @@ static int __init rs_init(void)
/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
IRQF_SHARED, "serial ", driver))
panic("%s: Failed to request irq8", __func__);
#endif

View File

@ -47,6 +47,7 @@
#include <linux/serial_core.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/atomic.h>
#include <asm/bootinfo.h>

View File

@ -1554,7 +1554,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
/* save off irq and request irq line */
if ( (retval = request_irq(dev->irq, icom_interrupt,
IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
IRQF_SHARED, ICOM_DRIVER_NAME,
(void *) icom_adapter))) {
goto probe_exit2;
}

View File

@ -508,8 +508,10 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
continue;
if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
if (rx & URXD_PRERR)
if (unlikely(rx & URXD_ERR)) {
if (rx & URXD_BRK)
sport->port.icount.brk++;
else if (rx & URXD_PRERR)
sport->port.icount.parity++;
else if (rx & URXD_FRMERR)
sport->port.icount.frame++;
@ -524,7 +526,9 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
rx &= sport->port.read_status_mask;
if (rx & URXD_PRERR)
if (rx & URXD_BRK)
flg = TTY_BREAK;
else if (rx & URXD_PRERR)
flg = TTY_PARITY;
else if (rx & URXD_FRMERR)
flg = TTY_FRAME;

View File

@ -13,6 +13,7 @@
*/
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/circ_buf.h>
#include <linux/serial_reg.h>

View File

@ -14,6 +14,7 @@
*/
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/circ_buf.h>

View File

@ -88,7 +88,6 @@ enum {
/* 4 extra for alignment play space */
#define WRITEBUFLEN ((4096) + 4)
#define MYFLIPLEN N_TTY_BUF_SIZE
#define JSM_VERSION "jsm: 1.2-1-INKERNEL"
#define JSM_PARTNUM "40002438_A-INKERNEL"
@ -150,7 +149,6 @@ struct jsm_board
u32 bd_uart_offset; /* Space between each UART */
struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
char *flipbuf; /* Our flip buffer, alloced if board is found */
u32 bd_dividend; /* Board/UARTs specific dividend */
@ -177,16 +175,13 @@ struct jsm_board
#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */
#define CH_BREAK_SENDING 0x1000 /* Break is being sent */
#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */
#define CH_FLIPBUF_IN_USE 0x4000 /* Channel's flipbuf is in use */
#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */
/* Our Read/Error/Write queue sizes */
#define RQUEUEMASK 0x1FFF /* 8 K - 1 */
#define EQUEUEMASK 0x1FFF /* 8 K - 1 */
#define WQUEUEMASK 0x0FFF /* 4 K - 1 */
#define RQUEUESIZE (RQUEUEMASK + 1)
#define EQUEUESIZE RQUEUESIZE
#define WQUEUESIZE (WQUEUEMASK + 1)
/************************************************************************
@ -226,10 +221,6 @@ struct jsm_channel {
u16 ch_e_head; /* Head location of the error queue */
u16 ch_e_tail; /* Tail location of the error queue */
u8 *ch_wqueue; /* Our write queue buffer - malloc'ed */
u16 ch_w_head; /* Head location of the write queue */
u16 ch_w_tail; /* Tail location of the write queue */
u64 ch_rxcount; /* total of data received so far */
u64 ch_txcount; /* total of data transmitted so far */
@ -378,7 +369,6 @@ extern int jsm_debug;
* Prototypes for non-static functions used in more than one module
*
*************************************************************************/
int jsm_tty_write(struct uart_port *port);
int jsm_tty_init(struct jsm_board *);
int jsm_uart_port_init(struct jsm_board *);
int jsm_remove_uart_port(struct jsm_board *);

View File

@ -160,27 +160,10 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
adapter_count, brd->rev, brd->irq);
/*
* allocate flip buffer for board.
*
* Okay to malloc with GFP_KERNEL, we are not at interrupt
* context, and there are no locks held.
*/
brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
if (!brd->flipbuf) {
/* XXX: leaking all resources from jsm_tty_init and
jsm_uart_port_init here! */
dev_err(&pdev->dev, "memory allocation for flipbuf failed\n");
rc = -ENOMEM;
goto out_free_uart;
}
pci_set_drvdata(pdev, brd);
pci_save_state(pdev);
return 0;
out_free_uart:
jsm_remove_uart_port(brd);
out_free_irq:
jsm_remove_uart_port(brd);
free_irq(brd->irq, brd);
@ -211,14 +194,12 @@ static void __devexit jsm_remove_one(struct pci_dev *pdev)
if (brd->channels[i]) {
kfree(brd->channels[i]->ch_rqueue);
kfree(brd->channels[i]->ch_equeue);
kfree(brd->channels[i]->ch_wqueue);
kfree(brd->channels[i]);
}
}
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(brd->flipbuf);
kfree(brd);
}

View File

@ -496,12 +496,15 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
int s;
int qlen;
u32 len_written = 0;
struct circ_buf *circ;
if (!ch)
return;
circ = &ch->uart_port.state->xmit;
/* No data to write to the UART */
if (ch->ch_w_tail == ch->ch_w_head)
if (uart_circ_empty(circ))
return;
/* If port is "stopped", don't send any data to the UART */
@ -517,11 +520,10 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
if (ch->ch_cached_lsr & UART_LSR_THRE) {
ch->ch_cached_lsr &= ~(UART_LSR_THRE);
writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev,
"Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]);
ch->ch_w_tail++;
ch->ch_w_tail &= WQUEUEMASK;
"Tx data: %x\n", circ->buf[circ->tail]);
circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
ch->ch_txcount++;
}
return;
@ -536,36 +538,36 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
/* cache head and tail of queue */
head = ch->ch_w_head & WQUEUEMASK;
tail = ch->ch_w_tail & WQUEUEMASK;
qlen = (head - tail) & WQUEUEMASK;
head = circ->head & (UART_XMIT_SIZE - 1);
tail = circ->tail & (UART_XMIT_SIZE - 1);
qlen = uart_circ_chars_pending(circ);
/* Find minimum of the FIFO space, versus queue length */
n = min(n, qlen);
while (n > 0) {
s = ((head >= tail) ? head : WQUEUESIZE) - tail;
s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
s = min(s, n);
if (s <= 0)
break;
memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
/* Add and flip queue if needed */
tail = (tail + s) & WQUEUEMASK;
tail = (tail + s) & (UART_XMIT_SIZE - 1);
n -= s;
ch->ch_txcount += s;
len_written += s;
}
/* Update the final tail */
ch->ch_w_tail = tail & WQUEUEMASK;
circ->tail = tail & (UART_XMIT_SIZE - 1);
if (len_written >= ch->ch_t_tlevel)
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
if (!jsm_tty_write(&ch->uart_port))
if (uart_circ_empty(circ))
uart_write_wakeup(&ch->uart_port);
}
@ -946,7 +948,6 @@ static void neo_param(struct jsm_channel *ch)
if ((ch->ch_c_cflag & (CBAUD)) == 0) {
ch->ch_r_head = ch->ch_r_tail = 0;
ch->ch_e_head = ch->ch_e_tail = 0;
ch->ch_w_head = ch->ch_w_tail = 0;
neo_flush_uart_write(ch);
neo_flush_uart_read(ch);

View File

@ -118,6 +118,19 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
udelay(10);
}
/*
* jsm_tty_write()
*
* Take data from the user or kernel and send it out to the FEP.
* In here exists all the Transparent Print magic as well.
*/
static void jsm_tty_write(struct uart_port *port)
{
struct jsm_channel *channel;
channel = container_of(port, struct jsm_channel, uart_port);
channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
}
static void jsm_tty_start_tx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
@ -216,14 +229,6 @@ static int jsm_tty_open(struct uart_port *port)
return -ENOMEM;
}
}
if (!channel->ch_wqueue) {
channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
if (!channel->ch_wqueue) {
jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
"unable to allocate write queue buf");
return -ENOMEM;
}
}
channel->ch_flags &= ~(CH_OPENING);
/*
@ -237,7 +242,6 @@ static int jsm_tty_open(struct uart_port *port)
*/
channel->ch_r_head = channel->ch_r_tail = 0;
channel->ch_e_head = channel->ch_e_tail = 0;
channel->ch_w_head = channel->ch_w_tail = 0;
brd->bd_ops->flush_uart_write(channel);
brd->bd_ops->flush_uart_read(channel);
@ -836,75 +840,3 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
}
}
}
/*
* jsm_tty_write()
*
* Take data from the user or kernel and send it out to the FEP.
* In here exists all the Transparent Print magic as well.
*/
int jsm_tty_write(struct uart_port *port)
{
int bufcount;
int data_count = 0,data_count1 =0;
u16 head;
u16 tail;
u16 tmask;
u32 remain;
int temp_tail = port->state->xmit.tail;
struct jsm_channel *channel = (struct jsm_channel *)port;
tmask = WQUEUEMASK;
head = (channel->ch_w_head) & tmask;
tail = (channel->ch_w_tail) & tmask;
if ((bufcount = tail - head - 1) < 0)
bufcount += WQUEUESIZE;
bufcount = min(bufcount, 56);
remain = WQUEUESIZE - head;
data_count = 0;
if (bufcount >= remain) {
bufcount -= remain;
while ((port->state->xmit.head != temp_tail) &&
(data_count < remain)) {
channel->ch_wqueue[head++] =
port->state->xmit.buf[temp_tail];
temp_tail++;
temp_tail &= (UART_XMIT_SIZE - 1);
data_count++;
}
if (data_count == remain) head = 0;
}
data_count1 = 0;
if (bufcount > 0) {
remain = bufcount;
while ((port->state->xmit.head != temp_tail) &&
(data_count1 < remain)) {
channel->ch_wqueue[head++] =
port->state->xmit.buf[temp_tail];
temp_tail++;
temp_tail &= (UART_XMIT_SIZE - 1);
data_count1++;
}
}
port->state->xmit.tail = temp_tail;
data_count += data_count1;
if (data_count) {
head &= tmask;
channel->ch_w_head = head;
}
if (data_count) {
channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
}
return data_count;
}

View File

@ -338,21 +338,21 @@ lqasc_startup(struct uart_port *port)
ASCCON_ROEN, port->membase + LTQ_ASC_CON);
retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
IRQF_DISABLED, "asc_tx", port);
0, "asc_tx", port);
if (retval) {
pr_err("failed to request lqasc_tx_int\n");
return retval;
}
retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
IRQF_DISABLED, "asc_rx", port);
0, "asc_rx", port);
if (retval) {
pr_err("failed to request lqasc_rx_int\n");
goto err1;
}
retval = request_irq(ltq_port->err_irq, lqasc_err_int,
IRQF_DISABLED, "asc_err", port);
0, "asc_err", port);
if (retval) {
pr_err("failed to request lqasc_err_int\n");
goto err2;

View File

@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>

View File

@ -47,6 +47,8 @@
#include <linux/serial.h>
#include <linux/spi/spi.h>
#include <linux/freezer.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_max3100.h>

View File

@ -31,6 +31,8 @@
#include <linux/device.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/freezer.h>

View File

@ -380,7 +380,7 @@ static void mcf_config_port(struct uart_port *port, int flags)
/* Clear mask, so no surprise interrupts. */
writeb(0, port->membase + MCFUART_UIMR);
if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
if (request_irq(port->irq, mcf_interrupt, 0, "UART", port))
printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
"interrupt vector=%d\n", port->line, port->irq);
}

View File

@ -38,6 +38,7 @@
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
#define HSU_DMA_BUF_SIZE 2048
@ -764,6 +765,8 @@ static int serial_hsu_startup(struct uart_port *port)
container_of(port, struct uart_hsu_port, port);
unsigned long flags;
pm_runtime_get_sync(up->dev);
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
@ -871,6 +874,8 @@ static void serial_hsu_shutdown(struct uart_port *port)
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);
pm_runtime_put(up->dev);
}
static void
@ -1249,6 +1254,39 @@ static int serial_hsu_resume(struct pci_dev *pdev)
#define serial_hsu_resume NULL
#endif
#ifdef CONFIG_PM_RUNTIME
static int serial_hsu_runtime_idle(struct device *dev)
{
int err;
err = pm_schedule_suspend(dev, 500);
if (err)
return -EBUSY;
return 0;
}
static int serial_hsu_runtime_suspend(struct device *dev)
{
return 0;
}
static int serial_hsu_runtime_resume(struct device *dev)
{
return 0;
}
#else
#define serial_hsu_runtime_idle NULL
#define serial_hsu_runtime_suspend NULL
#define serial_hsu_runtime_resume NULL
#endif
static const struct dev_pm_ops serial_hsu_pm_ops = {
.runtime_suspend = serial_hsu_runtime_suspend,
.runtime_resume = serial_hsu_runtime_resume,
.runtime_idle = serial_hsu_runtime_idle,
};
/* temp global pointer before we settle down on using one or four PCI dev */
static struct hsu_port *phsu;
@ -1315,6 +1353,9 @@ static int serial_hsu_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, uport);
}
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
return 0;
err_disable:
@ -1411,6 +1452,9 @@ static void serial_hsu_remove(struct pci_dev *pdev)
if (!priv)
return;
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
/* For port 0/1/2, priv is the address of uart_hsu_port */
if (pdev->device != 0x081E) {
up = priv;
@ -1423,7 +1467,7 @@ static void serial_hsu_remove(struct pci_dev *pdev)
}
/* First 3 are UART ports, and the 4th is the DMA */
static const struct pci_device_id pci_ids[] __devinitdata = {
static const struct pci_device_id pci_ids[] __devinitconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
@ -1438,6 +1482,9 @@ static struct pci_driver hsu_pci_driver = {
.remove = __devexit_p(serial_hsu_remove),
.suspend = serial_hsu_suspend,
.resume = serial_hsu_resume,
.driver = {
.pm = &serial_hsu_pm_ops,
},
};
static int __init hsu_pci_init(void)

View File

@ -34,6 +34,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/sysrq.h>
#include <linux/console.h>
@ -273,7 +274,7 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
{
port->irqflags = IRQF_DISABLED;
port->irqflags = 0;
port->irq = irq_of_parse_and_map(np, 0);
}

View File

@ -27,6 +27,10 @@
* interrupt for a low speed UART device
*/
#ifdef CONFIG_MAGIC_SYSRQ
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/irq.h>
@ -73,9 +77,9 @@ struct uart_max3110 {
/* global data structure, may need be removed */
static struct uart_max3110 *pmax;
static void receive_chars(struct uart_max3110 *max,
unsigned char *str, int len);
static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
static int receive_chars(struct uart_max3110 *max,
unsigned short *str, int len);
static int max3110_read_multi(struct uart_max3110 *max);
static void max3110_con_receive(struct uart_max3110 *max);
static int max3110_write_then_read(struct uart_max3110 *max,
@ -108,7 +112,6 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
{
void *buf;
u16 *obuf, *ibuf;
u8 ch;
int ret;
buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
@ -125,11 +128,7 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
goto exit;
}
/* If some valid data is read back */
if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
ch = *ibuf & 0xff;
receive_chars(max, &ch, 1);
}
receive_chars(max, ibuf, 1);
exit:
kfree(buf);
@ -142,12 +141,11 @@ exit:
*
* Return how many valide bytes are read back
*/
static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
static int max3110_read_multi(struct uart_max3110 *max)
{
void *buf;
u16 *obuf, *ibuf;
u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
int i, j, blen;
int ret, blen;
blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
@ -165,19 +163,10 @@ static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
return 0;
}
/* If caller doesn't provide a buffer, then handle received char */
pbuf = rxbuf ? rxbuf : valid_str;
for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
pbuf[j++] = ibuf[i] & 0xff;
}
if (j && (pbuf == valid_str))
receive_chars(max, valid_str, j);
ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
kfree(buf);
return j;
return ret;
}
static void serial_m3110_con_putchar(struct uart_port *port, int ch)
@ -207,7 +196,7 @@ static void serial_m3110_con_write(struct console *co,
uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
wake_up_process(pmax->main_thread);
wake_up(&pmax->wq);
}
static int __init
@ -276,8 +265,7 @@ static void send_circ_buf(struct uart_max3110 *max,
{
void *buf;
u16 *obuf, *ibuf;
u8 valid_str[WORDS_PER_XFER];
int i, j, len, blen, dma_size, left, ret = 0;
int i, len, blen, dma_size, left, ret = 0;
dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
@ -301,18 +289,13 @@ static void send_circ_buf(struct uart_max3110 *max,
}
/* Fail to send msg to console is not very critical */
ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
if (ret)
pr_warning(PR_FMT "%s(): get err msg %d\n",
__func__, ret);
for (i = 0, j = 0; i < len; i++) {
if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
valid_str[j++] = ibuf[i] & 0xff;
}
if (j)
receive_chars(max, valid_str, j);
receive_chars(max, ibuf, len);
max->port.icount.tx += len;
left -= len;
@ -349,33 +332,54 @@ static void serial_m3110_start_tx(struct uart_port *port)
container_of(port, struct uart_max3110, port);
if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
wake_up_process(max->main_thread);
wake_up(&max->wq);
}
static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
static int
receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
{
struct uart_port *port = &max->port;
struct tty_struct *tty;
int usable;
char buf[M3110_RX_FIFO_DEPTH];
int r, w, usable;
/* If uart is not opened, just return */
if (!port->state)
return;
return 0;
tty = port->state->port.tty;
tty = tty_port_tty_get(&port->state->port);
if (!tty)
return;
return 0;
while (len) {
usable = tty_buffer_request_room(tty, len);
for (r = 0, w = 0; r < len; r++) {
if (str[r] & MAX3110_BREAK &&
uart_handle_break(port))
continue;
if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
if (uart_handle_sysrq_char(port, str[r] & 0xff))
continue;
buf[w++] = str[r] & 0xff;
}
}
if (!w) {
tty_kref_put(tty);
return 0;
}
for (r = 0; w; r += usable, w -= usable) {
usable = tty_buffer_request_room(tty, w);
if (usable) {
tty_insert_flip_string(tty, str, usable);
str += usable;
tty_insert_flip_string(tty, buf + r, usable);
port->icount.rx += usable;
}
len -= usable;
}
tty_flip_buffer_push(tty);
tty_kref_put(tty);
return r;
}
/*
@ -390,28 +394,15 @@ static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
*/
static void max3110_con_receive(struct uart_max3110 *max)
{
int loop = 1, num, total = 0;
u8 recv_buf[512], *pbuf;
int loop = 1, num;
pbuf = recv_buf;
do {
num = max3110_read_multi(max, pbuf);
num = max3110_read_multi(max);
if (num) {
loop = 5;
pbuf += num;
total += num;
if (total >= 504) {
receive_chars(max, recv_buf, total);
pbuf = recv_buf;
total = 0;
}
}
} while (--loop);
if (total)
receive_chars(max, recv_buf, total);
}
static int max3110_main_thread(void *_max)
@ -424,7 +415,8 @@ static int max3110_main_thread(void *_max)
pr_info(PR_FMT "start main thread\n");
do {
wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
wait_event_interruptible(*wq,
max->uart_flags || kthread_should_stop());
mutex_lock(&max->thread_mutex);
@ -452,8 +444,9 @@ static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
/* max3110's irq is a falling edge, not level triggered,
* so no need to disable the irq */
if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
wake_up_process(max->main_thread);
wake_up(&max->wq);
return IRQ_HANDLED;
}

View File

@ -7,6 +7,7 @@
/* status bits for all 4 MAX3110 operate modes */
#define MAX3110_READ_DATA_AVAILABLE (1 << 15)
#define MAX3110_WRITE_BUF_EMPTY (1 << 14)
#define MAX3110_BREAK (1 << 10)
#define WC_TAG (3 << 14)
#define RC_TAG (1 << 14)

View File

@ -804,8 +804,6 @@ static int __init msm_console_setup(struct console *co, char *options)
if (unlikely(!port->membase))
return -ENXIO;
port->cons = co;
msm_init_clock(port);
if (options)

View File

@ -30,6 +30,8 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>

View File

@ -21,6 +21,8 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/console.h>
#include <linux/delay.h> /* for udelay */
#include <linux/device.h>

View File

@ -15,6 +15,7 @@
#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/irqreturn.h>
#include <linux/mutex.h>
#include <linux/of_platform.h>

View File

@ -20,6 +20,8 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/dmi.h>

View File

@ -100,6 +100,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
int max_count = 256;
do {
/* work around Errata #20 according to
* Intel(R) PXA27x Processor Family
* Specification Update (May 2005)
*
* Step 2
* Disable the Reciever Time Out Interrupt via IER[RTOEI]
*/
up->ier &= ~UART_IER_RTOIE;
serial_out(up, UART_IER, up->ier);
ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
@ -156,6 +166,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
*status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
tty_flip_buffer_push(tty);
/* work around Errata #20 according to
* Intel(R) PXA27x Processor Family
* Specification Update (May 2005)
*
* Step 6:
* No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
*/
up->ier |= UART_IER_RTOIE;
serial_out(up, UART_IER, up->ier);
}
static void transmit_chars(struct uart_pxa_port *up)

View File

@ -83,6 +83,16 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
}
/*
* s3c64xx and later SoC's include the interrupt mask and status registers in
* the controller itself, unlike the s3c24xx SoC's which have these registers
* in the interrupt controller. Check if the port type is s3c64xx or higher.
*/
static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port)
{
return to_ourport(port)->info->type == PORT_S3C6400;
}
static void s3c24xx_serial_rx_enable(struct uart_port *port)
{
unsigned long flags;
@ -126,7 +136,11 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (tx_enabled(port)) {
disable_irq_nosync(ourport->tx_irq);
if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
disable_irq_nosync(ourport->tx_irq);
tx_enabled(port) = 0;
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_enable(port);
@ -141,19 +155,26 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
enable_irq(ourport->tx_irq);
if (s3c24xx_serial_has_interrupt_mask(port))
__clear_bit(S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM));
else
enable_irq(ourport->tx_irq);
tx_enabled(port) = 1;
}
}
static void s3c24xx_serial_stop_rx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (rx_enabled(port)) {
dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
disable_irq_nosync(ourport->rx_irq);
if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_RXD,
portaddrl(port, S3C64XX_UINTM));
else
disable_irq_nosync(ourport->rx_irq);
rx_enabled(port) = 0;
}
}
@ -320,6 +341,28 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
return IRQ_HANDLED;
}
/* interrupt handler for s3c64xx and later SoC's.*/
static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
{
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
unsigned int pend = rd_regl(port, S3C64XX_UINTP);
unsigned long flags;
irqreturn_t ret = IRQ_HANDLED;
spin_lock_irqsave(&port->lock, flags);
if (pend & S3C64XX_UINTM_RXD_MSK) {
ret = s3c24xx_serial_rx_chars(irq, id);
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
}
if (pend & S3C64XX_UINTM_TXD_MSK) {
ret = s3c24xx_serial_tx_chars(irq, id);
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
}
spin_unlock_irqrestore(&port->lock, flags);
return ret;
}
static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
{
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
@ -377,18 +420,25 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (ourport->tx_claimed) {
free_irq(ourport->tx_irq, ourport);
if (!s3c24xx_serial_has_interrupt_mask(port))
free_irq(ourport->tx_irq, ourport);
tx_enabled(port) = 0;
ourport->tx_claimed = 0;
}
if (ourport->rx_claimed) {
free_irq(ourport->rx_irq, ourport);
if (!s3c24xx_serial_has_interrupt_mask(port))
free_irq(ourport->rx_irq, ourport);
ourport->rx_claimed = 0;
rx_enabled(port) = 0;
}
}
/* Clear pending interrupts and mask all interrupts */
if (s3c24xx_serial_has_interrupt_mask(port)) {
wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTM, 0xf);
}
}
static int s3c24xx_serial_startup(struct uart_port *port)
{
@ -436,6 +486,33 @@ static int s3c24xx_serial_startup(struct uart_port *port)
return ret;
}
static int s3c64xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
if (ret) {
printk(KERN_ERR "cannot get irq %d\n", port->irq);
return ret;
}
/* For compatibility with s3c24xx Soc's */
rx_enabled(port) = 1;
ourport->rx_claimed = 1;
tx_enabled(port) = 0;
ourport->tx_claimed = 1;
/* Enable Rx Interrupt */
__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
dbg("s3c64xx_serial_startup ok\n");
return ret;
}
/* power power management control */
static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@ -879,7 +956,6 @@ static struct uart_ops s3c24xx_serial_ops = {
.verify_port = s3c24xx_serial_verify_port,
};
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
.driver_name = "s3c2410_serial",
@ -895,7 +971,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX0,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
@ -907,7 +982,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
@ -921,7 +995,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
@ -935,7 +1008,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX3,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
@ -1077,6 +1149,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
port->dev = &platdev->dev;
ourport->info = info;
/* Startup sequence is different for s3c64xx and higher SoC's */
if (s3c24xx_serial_has_interrupt_mask(port))
s3c24xx_serial_ops.startup = s3c64xx_serial_startup;
/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;
@ -1116,6 +1192,13 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ourport->clk = clk_get(&platdev->dev, "uart");
/* Keep all interrupts masked and cleared */
if (s3c24xx_serial_has_interrupt_mask(port)) {
wr_regl(port, S3C64XX_UINTM, 0xf);
wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTSP, 0xf);
}
dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
port->mapbase, port->membase, port->irq,
ourport->rx_irq, ourport->tx_irq, port->uartclk);

View File

@ -61,6 +61,7 @@ struct s3c24xx_uart_port {
/* register access controls */
#define portaddr(port, reg) ((port)->membase + (reg))
#define portaddrl(port, reg) ((unsigned long *)((port)->membase + (reg)))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))

View File

@ -37,6 +37,7 @@
#include <linux/spinlock.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/types.h>
#include <linux/atomic.h>

View File

@ -57,7 +57,7 @@ static struct lock_class_key port_lock_key;
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios);
static void __uart_wait_until_sent(struct uart_port *port, int timeout);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
static void uart_change_pm(struct uart_state *state, int pm_state);
/*
@ -72,7 +72,7 @@ void uart_write_wakeup(struct uart_port *port)
* closed. No cookie for you.
*/
BUG_ON(!state);
tasklet_schedule(&state->tlet);
tty_wakeup(state->port.tty);
}
static void uart_stop(struct tty_struct *tty)
@ -107,12 +107,6 @@ static void uart_start(struct tty_struct *tty)
spin_unlock_irqrestore(&port->lock, flags);
}
static void uart_tasklet_action(unsigned long data)
{
struct uart_state *state = (struct uart_state *)data;
tty_wakeup(state->port.tty);
}
static inline void
uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
{
@ -255,9 +249,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
}
/*
* kill off our tasklet
* It's possible for shutdown to be called after suspend if we get
* a DCD drop (hangup) at just the right time. Clear suspended bit so
* we don't try to resume a port that has been shutdown.
*/
tasklet_kill(&state->tlet);
clear_bit(ASYNCB_SUSPENDED, &port->flags);
/*
* Free the transmit buffer page.
@ -1261,8 +1257,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
struct uart_port *uport;
unsigned long flags;
BUG_ON(!tty_locked());
if (!state)
return;
@ -1271,12 +1265,11 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
pr_debug("uart_close(%d) called\n", uport->line);
mutex_lock(&port->mutex);
spin_lock_irqsave(&port->lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&port->lock, flags);
goto done;
return;
}
if ((tty->count == 1) && (port->count != 1)) {
@ -1298,7 +1291,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
}
if (port->count) {
spin_unlock_irqrestore(&port->lock, flags);
goto done;
return;
}
/*
@ -1306,19 +1299,13 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* the line discipline to only process XON/XOFF characters by
* setting tty->closing.
*/
set_bit(ASYNCB_CLOSING, &port->flags);
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
/*
* hack: open-coded tty_wait_until_sent to avoid
* recursive tty_lock
*/
long timeout = msecs_to_jiffies(port->closing_wait);
if (wait_event_interruptible_timeout(tty->write_wait,
!tty_chars_in_buffer(tty), timeout) >= 0)
__uart_wait_until_sent(uport, timeout);
}
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent_from_close(tty,
msecs_to_jiffies(port->closing_wait));
/*
* At this point, we stop accepting input. To do this, we
@ -1334,9 +1321,10 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
__uart_wait_until_sent(uport, uport->timeout);
uart_wait_until_sent(tty, uport->timeout);
}
mutex_lock(&port->mutex);
uart_shutdown(tty, state);
uart_flush_buffer(tty);
@ -1361,15 +1349,18 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* Wake up anyone trying to open this port.
*/
clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
clear_bit(ASYNCB_CLOSING, &port->flags);
spin_unlock_irqrestore(&port->lock, flags);
wake_up_interruptible(&port->open_wait);
wake_up_interruptible(&port->close_wait);
done:
mutex_unlock(&port->mutex);
}
static void __uart_wait_until_sent(struct uart_port *port, int timeout)
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
unsigned long char_time, expire;
if (port->type == PORT_UNKNOWN || port->fifosize == 0)
@ -1421,16 +1412,6 @@ static void __uart_wait_until_sent(struct uart_port *port, int timeout)
}
}
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
tty_lock();
__uart_wait_until_sent(port, timeout);
tty_unlock();
}
/*
* This is called with the BKL held in
* linux/drivers/char/tty_io.c:do_tty_hangup()
@ -1443,7 +1424,6 @@ static void uart_hangup(struct tty_struct *tty)
struct tty_port *port = &state->port;
unsigned long flags;
BUG_ON(!tty_locked());
pr_debug("uart_hangup(%d)\n", state->uart_port->line);
mutex_lock(&port->mutex);
@ -1530,7 +1510,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
struct tty_port *port;
int retval, line = tty->index;
BUG_ON(!tty_locked());
pr_debug("uart_open(%d) called\n", line);
/*
@ -2008,6 +1987,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
if (port->tty && port->tty->termios && termios.c_cflag == 0)
termios = *(port->tty->termios);
if (console_suspend_enabled)
uart_change_pm(state, 0);
uport->ops->set_termios(uport, &termios, NULL);
if (console_suspend_enabled)
console_start(uport->cons);
@ -2068,8 +2049,6 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
case UPIO_DWAPB:
case UPIO_DWAPB32:
snprintf(address, sizeof(address),
"MMIO 0x%llx", (unsigned long long)port->mapbase);
break;
@ -2298,8 +2277,6 @@ int uart_register_driver(struct uart_driver *drv)
port->ops = &uart_port_ops;
port->close_delay = 500; /* .5 seconds */
port->closing_wait = 30000; /* 30 seconds */
tasklet_init(&state->tlet, uart_tasklet_action,
(unsigned long)state);
}
retval = tty_register_driver(normal);
@ -2460,11 +2437,6 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
*/
uport->type = PORT_UNKNOWN;
/*
* Kill the tasklet, and free resources.
*/
tasklet_kill(&state->tlet);
state->uart_port = NULL;
mutex_unlock(&port_mutex);
@ -2489,8 +2461,6 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
case UPIO_DWAPB:
case UPIO_DWAPB32:
return (port1->mapbase == port2->mapbase);
}
return 0;

View File

@ -13,6 +13,7 @@
*/
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
@ -336,19 +337,19 @@ static int ks8695uart_startup(struct uart_port *port)
/*
* Allocate the IRQ
*/
retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port);
retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, 0, "UART TX", port);
if (retval)
goto err_tx;
retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port);
retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, 0, "UART RX", port);
if (retval)
goto err_rx;
retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port);
retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, 0, "UART LineStatus", port);
if (retval)
goto err_ls;
retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port);
retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, 0, "UART ModemStatus", port);
if (retval)
goto err_ms;

View File

@ -28,6 +28,8 @@
#include <linux/pci.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <asm/io.h>

View File

@ -1976,7 +1976,7 @@ static int __devinit sci_init_single(struct platform_device *dev,
* For the muxed case there's nothing more to do.
*/
port->irq = p->irqs[SCIx_RXI_IRQ];
port->irqflags = IRQF_DISABLED;
port->irqflags = 0;
port->serial_in = sci_serial_in;
port->serial_out = sci_serial_out;

View File

@ -39,6 +39,7 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/module.h>
@ -737,7 +738,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
DPRINTF("sn_console: switching to interrupt driven console\n");
if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
IRQF_DISABLED | IRQF_SHARED,
IRQF_SHARED,
"SAL console driver", port) >= 0) {
spin_lock_irqsave(&port->sc_port.lock, flags);
port->sc_port.irq = SGI_UART_VECTOR;

View File

@ -23,6 +23,8 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>

View File

@ -15,6 +15,7 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>

View File

@ -20,8 +20,10 @@
#include <linux/module.h>
#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/dma-mapping.h>

View File

@ -12,9 +12,11 @@
*/
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/console.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/console.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of.h>

View File

@ -63,6 +63,7 @@
#include <linux/spinlock.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/types.h>
#include <linux/atomic.h>

View File

@ -2124,7 +2124,6 @@ static int mgsl_write(struct tty_struct * tty,
if ( info->params.mode == MGSL_MODE_HDLC ||
info->params.mode == MGSL_MODE_RAW ) {
/* operating in synchronous (frame oriented) mode */
/* operating in synchronous (frame oriented) mode */
if (info->tx_active) {
if ( info->params.mode == MGSL_MODE_HDLC ) {

View File

@ -4950,7 +4950,7 @@ CheckAgain:
if ( debug_level >= DEBUG_LEVEL_DATA )
trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr,
min_t(int, framesize,SCABUFSIZE),0);
min_t(unsigned int, framesize, SCABUFSIZE), 0);
if (framesize) {
if (framesize > info->max_frame_size)
@ -5015,14 +5015,14 @@ static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int co
SCADESC_EX *desc_ex;
if ( debug_level >= DEBUG_LEVEL_DATA )
trace_block(info,buf, min_t(int, count,SCABUFSIZE), 1);
trace_block(info, buf, min_t(unsigned int, count, SCABUFSIZE), 1);
/* Copy source buffer to one or more DMA buffers, starting with
* the first transmit dma buffer.
*/
for(i=0;;)
{
copy_count = min_t(unsigned short,count,SCABUFSIZE);
copy_count = min_t(unsigned int, count, SCABUFSIZE);
desc = &info->tx_buf_list[i];
desc_ex = &info->tx_buf_list_ex[i];

View File

@ -194,8 +194,7 @@ static inline struct tty_struct *file_tty(struct file *file)
return ((struct tty_file_private *)file->private_data)->tty;
}
/* Associate a new file with the tty structure */
int tty_add_file(struct tty_struct *tty, struct file *file)
int tty_alloc_file(struct file *file)
{
struct tty_file_private *priv;
@ -203,15 +202,36 @@ int tty_add_file(struct tty_struct *tty, struct file *file)
if (!priv)
return -ENOMEM;
file->private_data = priv;
return 0;
}
/* Associate a new file with the tty structure */
void tty_add_file(struct tty_struct *tty, struct file *file)
{
struct tty_file_private *priv = file->private_data;
priv->tty = tty;
priv->file = file;
file->private_data = priv;
spin_lock(&tty_files_lock);
list_add(&priv->list, &tty->tty_files);
spin_unlock(&tty_files_lock);
}
return 0;
/**
* tty_free_file - free file->private_data
*
* This shall be used only for fail path handling when tty_add_file was not
* called yet.
*/
void tty_free_file(struct file *file)
{
struct tty_file_private *priv = file->private_data;
file->private_data = NULL;
kfree(priv);
}
/* Delete file from its tty */
@ -222,8 +242,7 @@ void tty_del_file(struct file *file)
spin_lock(&tty_files_lock);
list_del(&priv->list);
spin_unlock(&tty_files_lock);
file->private_data = NULL;
kfree(priv);
tty_free_file(file);
}
@ -1811,6 +1830,10 @@ static int tty_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
retry_open:
retval = tty_alloc_file(filp);
if (retval)
return -ENOMEM;
noctty = filp->f_flags & O_NOCTTY;
index = -1;
retval = 0;
@ -1823,6 +1846,7 @@ retry_open:
if (!tty) {
tty_unlock();
mutex_unlock(&tty_mutex);
tty_free_file(filp);
return -ENXIO;
}
driver = tty_driver_kref_get(tty->driver);
@ -1855,6 +1879,7 @@ retry_open:
}
tty_unlock();
mutex_unlock(&tty_mutex);
tty_free_file(filp);
return -ENODEV;
}
@ -1862,6 +1887,7 @@ retry_open:
if (!driver) {
tty_unlock();
mutex_unlock(&tty_mutex);
tty_free_file(filp);
return -ENODEV;
}
got_driver:
@ -1872,6 +1898,8 @@ got_driver:
if (IS_ERR(tty)) {
tty_unlock();
mutex_unlock(&tty_mutex);
tty_driver_kref_put(driver);
tty_free_file(filp);
return PTR_ERR(tty);
}
}
@ -1887,15 +1915,11 @@ got_driver:
tty_driver_kref_put(driver);
if (IS_ERR(tty)) {
tty_unlock();
tty_free_file(filp);
return PTR_ERR(tty);
}
retval = tty_add_file(tty, filp);
if (retval) {
tty_unlock();
tty_release(inode, filp);
return retval;
}
tty_add_file(tty, filp);
check_tty_count(tty, "tty_open");
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@ -2716,6 +2740,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
ld = tty_ldisc_ref_wait(tty);
if (ld->ops->compat_ioctl)
retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
else
retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
tty_ldisc_deref(ld);
return retval;

View File

@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <linux/compat.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@ -1179,3 +1180,19 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
}
}
EXPORT_SYMBOL(n_tty_ioctl_helper);
#ifdef CONFIG_COMPAT
long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case TIOCGLCKTRMIOS:
case TIOCSLCKTRMIOS:
return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg));
default:
return -ENOIOCTLCMD;
}
}
EXPORT_SYMBOL(n_tty_compat_ioctl_helper);
#endif

View File

@ -450,7 +450,6 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
if (ld->ops->open) {
int ret;
/* BTM here locks versus a hangup event */
WARN_ON(!tty_locked());
ret = ld->ops->open(tty);
if (ret)
clear_bit(TTY_LDISC_OPEN, &tty->flags);

View File

@ -15,30 +15,18 @@
* Don't use in new code.
*/
static DEFINE_MUTEX(big_tty_mutex);
struct task_struct *__big_tty_mutex_owner;
EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
/*
* Getting the big tty mutex.
*/
void __lockfunc tty_lock(void)
{
struct task_struct *task = current;
WARN_ON(__big_tty_mutex_owner == task);
mutex_lock(&big_tty_mutex);
__big_tty_mutex_owner = task;
}
EXPORT_SYMBOL(tty_lock);
void __lockfunc tty_unlock(void)
{
struct task_struct *task = current;
WARN_ON(__big_tty_mutex_owner != task);
__big_tty_mutex_owner = NULL;
mutex_unlock(&big_tty_mutex);
}
EXPORT_SYMBOL(tty_unlock);

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