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:
commit
efb8d21b2c
110 changed files with 2099 additions and 944 deletions
31
Documentation/devicetree/bindings/serial/rs485.txt
Normal file
31
Documentation/devicetree/bindings/serial/rs485.txt
Normal 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
|
||||
};
|
||||
|
27
Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
Normal file
27
Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
Normal 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;
|
||||
};
|
||||
|
|
@ -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>;
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ menuconfig STAGING
|
|||
|
||||
if STAGING
|
||||
|
||||
source "drivers/staging/serial/Kconfig"
|
||||
|
||||
source "drivers/staging/et131x/Kconfig"
|
||||
|
||||
source "drivers/staging/slicoss/Kconfig"
|
||||
|
|
|
@ -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/
|
||||
|
|
16
drivers/staging/serial/Kconfig
Normal file
16
drivers/staging/serial/Kconfig
Normal 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
|
1
drivers/staging/serial/Makefile
Normal file
1
drivers/staging/serial/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
|
6
drivers/staging/serial/TODO
Normal file
6
drivers/staging/serial/TODO
Normal 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.
|
|
@ -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.
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
881
drivers/tty/ehv_bytechan.c
Normal 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");
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
194
drivers/tty/serial/8250_dw.c
Normal file
194
drivers/tty/serial/8250_dw.c
Normal 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");
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
|
|||
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),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
|
|||
*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -4950,7 +4950,7 @@ static bool rx_get_frame(SLMP_INFO *info)
|
|||
|
||||
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];
|
||||
|
|
|
@ -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 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|||
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 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|||
}
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_free_file(filp);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -1862,6 +1887,7 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|||
if (!driver) {
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_free_file(filp);
|
||||
return -ENODEV;
|
||||
}
|
||||
got_driver:
|
||||
|
@ -1872,6 +1898,8 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|||
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 @@ static int tty_open(struct inode *inode, struct file *filp)
|
|||
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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue