TTY/Serial merge for 3.11-rc1

Here is the big TTY / Serial driver merge for 3.11-rc1.
 
 It's not all that big, nothing major changed in the tty api, which is a
 nice change, just a number of serial driver fixes and updates and new
 drivers, along with some n_tty fixes to help resolve some reported
 issues.
 
 All of these have been in the linux-next releases for a while, with the
 exception of the last revert patch, which was reported this past weekend
 by two different people as being needed.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iEYEABECAAYFAlHRtNIACgkQMUfUDdst+ymYgwCeKdyv9wRJ5cIWZt7Jz8ou3P/C
 76YAoIvMv+fwoFBpyud/sC8eAKGTQ6KB
 =Sjk6
 -----END PGP SIGNATURE-----

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

Pull tty/serial updates from Greg KH:
 "Here is the big TTY / Serial driver merge for 3.11-rc1.

  It's not all that big, nothing major changed in the tty api, which is
  a nice change, just a number of serial driver fixes and updates and
  new drivers, along with some n_tty fixes to help resolve some reported
  issues.

  All of these have been in the linux-next releases for a while, with
  the exception of the last revert patch, which was reported this past
  weekend by two different people as being needed."

* tag 'tty-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (51 commits)
  Revert "serial: 8250_pci: add support for another kind of NetMos Technology PCI 9835 Multi-I/O Controller"
  pch_uart: Add uart_clk selection for the MinnowBoard
  tty: atmel_serial: prepare clk before calling enable
  tty: Reset itty for other pty
  n_tty: Buffer work should not reschedule itself
  n_tty: Fix unsafe update of available buffer space
  n_tty: Untangle read completion variables
  n_tty: Encapsulate minimum_to_wake within N_TTY
  serial: omap: Fix device tree based PM runtime
  serial: imx: Fix serial clock unbalance
  serial/mpc52xx_uart: fix kernel panic when system reboot
  serial: mfd: Add sysrq support
  serial: imx: enable the clocks for console
  tty: serial: add Freescale lpuart driver support
  serial: imx: Improve Kconfig text
  serial: imx: Allow module build
  serial: imx: Fix warning when !CONFIG_SERIAL_IMX_CONSOLE
  tty/serial/sirf: fix error propagation in sirfsoc_uart_probe()
  serial: omap: fix potential NULL pointer dereference in serial_omap_runtime_suspend()
  tty: serial: Enable uartlite for ARM zynq
  ...
This commit is contained in:
Linus Torvalds 2013-07-02 11:32:06 -07:00
commit 0de10f9ea6
57 changed files with 2144 additions and 797 deletions

View File

@ -12,20 +12,20 @@ The second type has to be explicitly loaded and unloaded. This will be called
any time with each driver sharing the console with other drivers including
the system driver. However, modular drivers cannot take over the console
that is currently occupied by another modular driver. (Exception: Drivers that
call take_over_console() will succeed in the takeover regardless of the type
call do_take_over_console() will succeed in the takeover regardless of the type
of driver occupying the consoles.) They can only take over the console that is
occupied by the system driver. In the same token, if the modular driver is
released by the console, the system driver will take over.
Modular drivers, from the programmer's point of view, has to call:
take_over_console() - load and bind driver to console layer
give_up_console() - unbind and unload driver
do_take_over_console() - load and bind driver to console layer
give_up_console() - unload driver, it will only work if driver is fully unbond
In newer kernels, the following are also available:
register_con_driver()
unregister_con_driver()
do_register_con_driver()
do_unregister_con_driver()
If sysfs is enabled, the contents of /sys/class/vtconsole can be
examined. This shows the console backends currently registered by the
@ -94,12 +94,12 @@ for more details).
Notes for developers:
=====================
take_over_console() is now broken up into:
do_take_over_console() is now broken up into:
register_con_driver()
bind_con_driver() - private function
do_register_con_driver()
do_bind_con_driver() - private function
give_up_console() is a wrapper to unregister_con_driver(), and a driver must
give_up_console() is a wrapper to do_unregister_con_driver(), and a driver must
be fully unbound for this call to succeed. con_is_bound() will check if the
driver is bound or not.
@ -109,10 +109,10 @@ Guidelines for console driver writers:
In order for binding to and unbinding from the console to properly work,
console drivers must follow these guidelines:
1. All drivers, except system drivers, must call either register_con_driver()
or take_over_console(). register_con_driver() will just add the driver to
1. All drivers, except system drivers, must call either do_register_con_driver()
or do_take_over_console(). do_register_con_driver() will just add the driver to
the console's internal list. It won't take over the
console. take_over_console(), as it name implies, will also take over (or
console. do_take_over_console(), as it name implies, will also take over (or
bind to) the console.
2. All resources allocated during con->con_init() must be released in
@ -128,10 +128,10 @@ console drivers must follow these guidelines:
rebind the driver to the console arrives.
4. Upon exit of the driver, ensure that the driver is totally unbound. If the
condition is satisfied, then the driver must call unregister_con_driver()
condition is satisfied, then the driver must call do_unregister_con_driver()
or give_up_console().
5. unregister_con_driver() can also be called on conditions which make it
5. do_unregister_con_driver() can also be called on conditions which make it
impossible for the driver to service console requests. This can happen
with the framebuffer console that suddenly lost all of its drivers.

View File

@ -8,6 +8,8 @@ Required properties:
Optional properties:
- fsl,uart-has-rtscts : Indicate the uart has rts and cts
- fsl,irda-mode : Indicate the uart supports irda mode
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
is DCE mode by default.
Example:
@ -16,4 +18,5 @@ serial@73fbc000 {
reg = <0x73fbc000 0x4000>;
interrupts = <31>;
fsl,uart-has-rtscts;
fsl,dte-mode;
};

View File

@ -0,0 +1,14 @@
* Freescale low power universal asynchronous receiver/transmitter (lpuart)
Required properties:
- compatible : Should be "fsl,<soc>-lpuart"
- reg : Address and length of the register set for the device
- interrupts : Should contain uart interrupt
Example:
uart0: serial@40027000 {
compatible = "fsl,vf610-lpuart";
reg = <0x40027000 0x1000>;
interrupts = <0 61 0x00>;
};

View File

@ -16,8 +16,6 @@ serial-rs485.txt
- info about RS485 structures and support in the kernel.
specialix.txt
- info on hardware/driver for specialix IO8+ multiport serial card.
stallion.txt
- info on using the Stallion multiport serial driver.
sx.txt
- info on the Specialix SX/SI multiport serial driver.
tty.txt

View File

@ -1,392 +0,0 @@
* NOTE - This is an unmaintained driver. Lantronix, which bought Stallion
technologies, is not active in driver maintenance, and they have no information
on when or if they will have a 2.6 driver.
James Nelson <james4765@gmail.com> - 12-12-2004
Stallion Multiport Serial Driver Readme
---------------------------------------
Copyright (C) 1994-1999, Stallion Technologies.
Version: 5.5.1
Date: 28MAR99
1. INTRODUCTION
There are two drivers that work with the different families of Stallion
multiport serial boards. One is for the Stallion smart boards - that is
EasyIO, EasyConnection 8/32 and EasyConnection 8/64-PCI, the other for
the true Stallion intelligent multiport boards - EasyConnection 8/64
(ISA, EISA), EasyConnection/RA-PCI, ONboard and Brumby.
If you are using any of the Stallion intelligent multiport boards (Brumby,
ONboard, EasyConnection 8/64 (ISA, EISA), EasyConnection/RA-PCI) with
Linux you will need to get the driver utility package. This contains a
firmware loader and the firmware images necessary to make the devices operate.
The Stallion Technologies ftp site, ftp.stallion.com, will always have
the latest version of the driver utility package.
ftp://ftp.stallion.com/drivers/ata5/Linux/ata-linux-550.tar.gz
As of the printing of this document the latest version of the driver
utility package is 5.5.0. If a later version is now available then you
should use the latest version.
If you are using the EasyIO, EasyConnection 8/32 or EasyConnection 8/64-PCI
boards then you don't need this package, although it does have a serial stats
display program.
If you require DIP switch settings, or EISA configuration files, or any
other information related to Stallion boards then have a look at Stallion's
web pages at http://www.stallion.com.
2. INSTALLATION
The drivers can be used as loadable modules or compiled into the kernel.
You can choose which when doing a "config" on the kernel.
All ISA, and EISA boards that you want to use need to be configured into
the driver(s). All PCI boards will be automatically detected when you load
the driver - so they do not need to be entered into the driver(s)
configuration structure. Note that kernel PCI support is required to use PCI
boards.
There are two methods of configuring ISA and EISA boards into the drivers.
If using the driver as a loadable module then the simplest method is to pass
the driver configuration as module arguments. The other method is to modify
the driver source to add configuration lines for each board in use.
If you have pre-built Stallion driver modules then the module argument
configuration method should be used. A lot of Linux distributions come with
pre-built driver modules in /lib/modules/X.Y.Z/misc for the kernel in use.
That makes things pretty simple to get going.
2.1 MODULE DRIVER CONFIGURATION:
The simplest configuration for modules is to use the module load arguments
to configure any ISA or EISA boards. PCI boards are automatically
detected, so do not need any additional configuration at all.
If using EasyIO, EasyConnection 8/32 ISA, or EasyConnection 8/63-PCI
boards then use the "stallion" driver module, Otherwise if you are using
an EasyConnection 8/64 ISA or EISA, EasyConnection/RA-PCI, ONboard,
Brumby or original Stallion board then use the "istallion" driver module.
Typically to load up the smart board driver use:
modprobe stallion
This will load the EasyIO and EasyConnection 8/32 driver. It will output a
message to say that it loaded and print the driver version number. It will
also print out whether it found the configured boards or not. These messages
may not appear on the console, but typically are always logged to
/var/adm/messages or /var/log/syslog files - depending on how the klogd and
syslogd daemons are setup on your system.
To load the intelligent board driver use:
modprobe istallion
It will output similar messages to the smart board driver.
If not using an auto-detectable board type (that is a PCI board) then you
will also need to supply command line arguments to the modprobe command
when loading the driver. The general form of the configuration argument is
board?=<name>[,<ioaddr>[,<addr>][,<irq>]]
where:
board? -- specifies the arbitrary board number of this board,
can be in the range 0 to 3.
name -- textual name of this board. The board name is the common
board name, or any "shortened" version of that. The board
type number may also be used here.
ioaddr -- specifies the I/O address of this board. This argument is
optional, but should generally be specified.
addr -- optional second address argument. Some board types require
a second I/O address, some require a memory address. The
exact meaning of this argument depends on the board type.
irq -- optional IRQ line used by this board.
Up to 4 board configuration arguments can be specified on the load line.
Here is some examples:
modprobe stallion board0=easyio,0x2a0,5
This configures an EasyIO board as board 0 at I/O address 0x2a0 and IRQ 5.
modprobe istallion board3=ec8/64,0x2c0,0xcc000
This configures an EasyConnection 8/64 ISA as board 3 at I/O address 0x2c0 at
memory address 0xcc000.
modprobe stallion board1=ec8/32-at,0x2a0,0x280,10
This configures an EasyConnection 8/32 ISA board at primary I/O address 0x2a0,
secondary address 0x280 and IRQ 10.
You will probably want to enter this module load and configuration information
into your system startup scripts so that the drivers are loaded and configured
on each system boot. Typically configuration files are put in the
/etc/modprobe.d/ directory.
2.2 STATIC DRIVER CONFIGURATION:
For static driver configuration you need to modify the driver source code.
Entering ISA and EISA boards into the driver(s) configuration structure
involves editing the driver(s) source file. It's pretty easy if you follow
the instructions below. Both drivers can support up to 4 boards. The smart
card driver (the stallion.c driver) supports any combination of EasyIO and
EasyConnection 8/32 boards (up to a total of 4). The intelligent driver
supports any combination of ONboards, Brumbys, Stallions and EasyConnection
8/64 (ISA and EISA) boards (up to a total of 4).
To set up the driver(s) for the boards that you want to use you need to
edit the appropriate driver file and add configuration entries.
If using EasyIO or EasyConnection 8/32 ISA boards,
In drivers/char/stallion.c:
- find the definition of the stl_brdconf array (of structures)
near the top of the file
- modify this to match the boards you are going to install
(the comments before this structure should help)
- save and exit
If using ONboard, Brumby, Stallion or EasyConnection 8/64 (ISA or EISA)
boards,
In drivers/char/istallion.c:
- find the definition of the stli_brdconf array (of structures)
near the top of the file
- modify this to match the boards you are going to install
(the comments before this structure should help)
- save and exit
Once you have set up the board configurations then you are ready to build
the kernel or modules.
When the new kernel is booted, or the loadable module loaded then the
driver will emit some kernel trace messages about whether the configured
boards were detected or not. Depending on how your system logger is set
up these may come out on the console, or just be logged to
/var/adm/messages or /var/log/syslog. You should check the messages to
confirm that all is well.
2.3 SHARING INTERRUPTS
It is possible to share interrupts between multiple EasyIO and
EasyConnection 8/32 boards in an EISA system. To do this you must be using
static driver configuration, modifying the driver source code to add driver
configuration. Then a couple of extra things are required:
1. When entering the board resources into the stallion.c file you need to
mark the boards as using level triggered interrupts. Do this by replacing
the "0" entry at field position 6 (the last field) in the board
configuration structure with a "1". (This is the structure that defines
the board type, I/O locations, etc. for each board). All boards that are
sharing an interrupt must be set this way, and each board should have the
same interrupt number specified here as well. Now build the module or
kernel as you would normally.
2. When physically installing the boards into the system you must enter
the system EISA configuration utility. You will need to install the EISA
configuration files for *all* the EasyIO and EasyConnection 8/32 boards
that are sharing interrupts. The Stallion EasyIO and EasyConnection 8/32
EISA configuration files required are supplied by Stallion Technologies
on the EASY Utilities floppy diskette (usually supplied in the box with
the board when purchased. If not, you can pick it up from Stallion's FTP
site, ftp.stallion.com). You will need to edit the board resources to
choose level triggered interrupts, and make sure to set each board's
interrupt to the same IRQ number.
You must complete both the above steps for this to work. When you reboot
or load the driver your EasyIO and EasyConnection 8/32 boards will be
sharing interrupts.
2.4 USING HIGH SHARED MEMORY
The EasyConnection 8/64-EI, ONboard and Stallion boards are capable of
using shared memory addresses above the usual 640K - 1Mb range. The ONboard
ISA and the Stallion boards can be programmed to use memory addresses up to
16Mb (the ISA bus addressing limit), and the EasyConnection 8/64-EI and
ONboard/E can be programmed for memory addresses up to 4Gb (the EISA bus
addressing limit).
The higher than 1Mb memory addresses are fully supported by this driver.
Just enter the address as you normally would for a lower than 1Mb address
(in the driver's board configuration structure).
2.5 TROUBLE SHOOTING
If a board is not found by the driver but is actually in the system then the
most likely problem is that the I/O address is wrong. Change the module load
argument for the loadable module form. Or change it in the driver stallion.c
or istallion.c configuration structure and rebuild the kernel or modules, or
change it on the board.
On EasyIO and EasyConnection 8/32 boards the IRQ is software programmable, so
if there is a conflict you may need to change the IRQ used for a board. There
are no interrupts to worry about for ONboard, Brumby or EasyConnection 8/64
(ISA and EISA) boards. The memory region on EasyConnection 8/64 and
ONboard boards is software programmable, but not on the Brumby boards.
3. USING THE DRIVERS
3.1 INTELLIGENT DRIVER OPERATION
The intelligent boards also need to have their "firmware" code downloaded
to them. This is done via a user level application supplied in the driver
utility package called "stlload". Compile this program wherever you dropped
the package files, by typing "make". In its simplest form you can then type
./stlload -i cdk.sys
in this directory and that will download board 0 (assuming board 0 is an
EasyConnection 8/64 or EasyConnection/RA board). To download to an
ONboard, Brumby or Stallion do:
./stlload -i 2681.sys
Normally you would want all boards to be downloaded as part of the standard
system startup. To achieve this, add one of the lines above into the
/etc/rc.d/rc.S or /etc/rc.d/rc.serial file. To download each board just add
the "-b <brd-number>" option to the line. You will need to download code for
every board. You should probably move the stlload program into a system
directory, such as /usr/sbin. Also, the default location of the cdk.sys image
file in the stlload down-loader is /usr/lib/stallion. Create that directory
and put the cdk.sys and 2681.sys files in it. (It's a convenient place to put
them anyway). As an example your /etc/rc.d/rc.S file might have the
following lines added to it (if you had 3 boards):
/usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys
/usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys
/usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys
The image files cdk.sys and 2681.sys are specific to the board types. The
cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly
the 2681.sys image fill only operate on ONboard, Brumby and Stallion boards.
If you load the wrong image file into a board it will fail to start up, and
of course the ports will not be operational!
If you are using the modularized version of the driver you might want to put
the modprobe calls in the startup script as well (before the download lines
obviously).
3.2 USING THE SERIAL PORTS
Once the driver is installed you will need to setup some device nodes to
access the serial ports. The simplest method is to use the /dev/MAKEDEV program.
It will automatically create device entries for Stallion boards. This will
create the normal serial port devices as /dev/ttyE# where# is the port number
starting from 0. A bank of 64 minor device numbers is allocated to each board,
so the first port on the second board is port 64,etc. A set of callout type
devices may also be created. They are created as the devices /dev/cue# where #
is the same as for the ttyE devices.
For the most part the Stallion driver tries to emulate the standard PC system
COM ports and the standard Linux serial driver. The idea is that you should
be able to use Stallion board ports and COM ports interchangeably without
modifying anything but the device name. Anything that doesn't work like that
should be considered a bug in this driver!
If you look at the driver code you will notice that it is fairly closely
based on the Linux serial driver (linux/drivers/char/serial.c). This is
intentional, obviously this is the easiest way to emulate its behavior!
Since this driver tries to emulate the standard serial ports as much as
possible, most system utilities should work as they do for the standard
COM ports. Most importantly "stty" works as expected and "setserial" can
also be used (excepting the ability to auto-configure the I/O and IRQ
addresses of boards). Higher baud rates are supported in the usual fashion
through setserial or using the CBAUDEX extensions. Note that the EasyIO and
EasyConnection (all types) support at least 57600 and 115200 baud. The newer
EasyConnection XP modules and new EasyIO boards support 230400 and 460800
baud as well. The older boards including ONboard and Brumby support a
maximum baud rate of 38400.
If you are unfamiliar with how to use serial ports, then get the Serial-HOWTO
by Greg Hankins. It will explain everything you need to know!
4. NOTES
You can use both drivers at once if you have a mix of board types installed
in a system. However to do this you will need to change the major numbers
used by one of the drivers. Currently both drivers use major numbers 24, 25
and 28 for their devices. Change one driver to use some other major numbers,
and then modify the mkdevnods script to make device nodes based on those new
major numbers. For example, you could change the istallion.c driver to use
major numbers 60, 61 and 62. You will also need to create device nodes with
different names for the ports, for example ttyF# and cuf#.
The original Stallion board is no longer supported by Stallion Technologies.
Although it is known to work with the istallion driver.
Finding a free physical memory address range can be a problem. The older
boards like the Stallion and ONboard need large areas (64K or even 128K), so
they can be very difficult to get into a system. If you have 16 Mb of RAM
then you have no choice but to put them somewhere in the 640K -> 1Mb range.
ONboards require 64K, so typically 0xd0000 is good, or 0xe0000 on some
systems. If you have an original Stallion board, "V4.0" or Rev.O, then you
need a 64K memory address space, so again 0xd0000 and 0xe0000 are good.
Older Stallion boards are a much bigger problem. They need 128K of address
space and must be on a 128K boundary. If you don't have a VGA card then
0xc0000 might be usable - there is really no other place you can put them
below 1Mb.
Both the ONboard and old Stallion boards can use higher memory addresses as
well, but you must have less than 16Mb of RAM to be able to use them. Usual
high memory addresses used include 0xec0000 and 0xf00000.
The Brumby boards only require 16Kb of address space, so you can usually
squeeze them in somewhere. Common addresses are 0xc8000, 0xcc000, or in
the 0xd0000 range. EasyConnection 8/64 boards are even better, they only
require 4Kb of address space, again usually 0xc8000, 0xcc000 or 0xd0000
are good.
If you are using an EasyConnection 8/64-EI or ONboard/E then usually the
0xd0000 or 0xe0000 ranges are the best options below 1Mb. If neither of
them can be used then the high memory support to use the really high address
ranges is the best option. Typically the 2Gb range is convenient for them,
and gets them well out of the way.
The ports of the EasyIO-8M board do not have DCD or DTR signals. So these
ports cannot be used as real modem devices. Generally, when using these
ports you should only use the cueX devices.
The driver utility package contains a couple of very useful programs. One
is a serial port statistics collection and display program - very handy
for solving serial port problems. The other is an extended option setting
program that works with the intelligent boards.
5. DISCLAIMER
The information contained in this document is believed to be accurate and
reliable. However, no responsibility is assumed by Stallion Technologies
Pty. Ltd. for its use, nor any infringements of patents or other rights
of third parties resulting from its use. Stallion Technologies reserves
the right to modify the design of its products and will endeavour to change
the information in manuals and accompanying documentation accordingly.

View File

@ -4577,7 +4577,7 @@ F: fs/jbd2/
F: include/linux/jbd2.h
JSM Neo PCI based serial card
M: Lucas Tavares <lucaskt@linux.vnet.ibm.com>
M: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/jsm/

View File

@ -61,7 +61,9 @@ locate_and_init_vga(void *(*sel_func)(void *, void *))
/* Set the VGA hose and init the new console. */
pci_vga_hose = hose;
take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
console_lock();
do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
console_unlock();
}
void __init

View File

@ -117,7 +117,9 @@ common_shutdown_1(void *generic_ptr)
if (in_interrupt())
irq_exit();
/* This has the effect of resetting the VGA video origin. */
take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
console_lock();
do_take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
console_unlock();
#endif
pci_restore_srm_config();
set_hae(srm_hae);

View File

@ -257,7 +257,9 @@ static int __init bcm1480_pcibios_init(void)
register_pci_controller(&bcm1480_controller);
#ifdef CONFIG_VGA_CONSOLE
take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
console_lock();
do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1);
console_unlock();
#endif
return 0;
}

View File

@ -283,7 +283,9 @@ static int __init sb1250_pcibios_init(void)
register_pci_controller(&sb1250_controller);
#ifdef CONFIG_VGA_CONSOLE
take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1);
console_lock();
do_take_over_console(&vga_con, 0, MAX_NR_CONSOLES - 1, 1);
console_unlock();
#endif
return 0;
}

View File

@ -156,7 +156,7 @@ void __init setup_arch(char **cmdline_p)
#endif
#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con; /* we use take_over_console() later ! */
conswitchp = &dummy_con; /* we use do_take_over_console() later ! */
#endif
}

View File

@ -299,4 +299,53 @@ struct mpc512x_psc_fifo {
#define rxdata_32 rxdata.rxdata_32
};
struct mpc5125_psc {
u8 mr1; /* PSC + 0x00 */
u8 reserved0[3];
u8 mr2; /* PSC + 0x04 */
u8 reserved1[3];
struct {
u16 status; /* PSC + 0x08 */
u8 reserved2[2];
u8 clock_select; /* PSC + 0x0c */
u8 reserved3[3];
} sr_csr;
u8 command; /* PSC + 0x10 */
u8 reserved4[3];
union { /* PSC + 0x14 */
u8 buffer_8;
u16 buffer_16;
u32 buffer_32;
} buffer;
struct {
u8 ipcr; /* PSC + 0x18 */
u8 reserved5[3];
u8 acr; /* PSC + 0x1c */
u8 reserved6[3];
} ipcr_acr;
struct {
u16 isr; /* PSC + 0x20 */
u8 reserved7[2];
u16 imr; /* PSC + 0x24 */
u8 reserved8[2];
} isr_imr;
u8 ctur; /* PSC + 0x28 */
u8 reserved9[3];
u8 ctlr; /* PSC + 0x2c */
u8 reserved10[3];
u32 ccr; /* PSC + 0x30 */
u32 ac97slots; /* PSC + 0x34 */
u32 ac97cmd; /* PSC + 0x38 */
u32 ac97data; /* PSC + 0x3c */
u8 reserved11[4];
u8 ip; /* PSC + 0x44 */
u8 reserved12[3];
u8 op1; /* PSC + 0x48 */
u8 reserved13[3];
u8 op0; /* PSC + 0x4c */
u8 reserved14[3];
u32 sicr; /* PSC + 0x50 */
u8 reserved15[4]; /* make eq. sizeof(mpc52xx_psc) */
};
#endif /* __ASM_MPC52xx_PSC_H__ */

View File

@ -15,18 +15,6 @@ config DEVKMEM
kind of kernel debugging operations.
When in doubt, say "N".
config STALDRV
bool "Stallion multiport serial support"
depends on SERIAL_NONSTANDARD
help
Stallion cards give you many serial ports. You would need something
like this to connect more than two modems to your Linux box, for
instance in order to become a dial-in server. If you say Y here,
you will be asked for your specific card model in the next
questions. Make sure to read <file:Documentation/serial/stallion.txt>
in this case. If you have never heard about all this, it's safe to
say N.
config SGI_SNSC
bool "SGI Altix system controller communication support"
depends on (IA64_SGI_SN2 || IA64_GENERIC)

View File

@ -1,5 +1,5 @@
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
tty_buffer.o tty_port.o tty_mutex.o
tty_buffer.o tty_port.o tty_mutex.o tty_ldsem.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-$(CONFIG_AUDIT) += tty_audit.o

View File

@ -1328,7 +1328,7 @@ out_error:
*/
static int __init hvc_iucv_config(char *val)
{
return strict_strtoul(val, 10, &hvc_iucv_devices);
return kstrtoul(val, 10, &hvc_iucv_devices);
}

View File

@ -89,6 +89,7 @@ struct n_tty_data {
int read_head;
int read_tail;
int read_cnt;
int minimum_to_wake;
unsigned char *echo_buf;
unsigned int echo_pos;
@ -114,22 +115,25 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
}
/**
* n_tty_set__room - receive space
* n_tty_set_room - receive space
* @tty: terminal
*
* Called by the driver to find out how much data it is
* permitted to feed to the line discipline without any being lost
* and thus to manage flow control. Not serialized. Answers for the
* "instant".
* Updates tty->receive_room to reflect the currently available space
* in the input buffer, and re-schedules the flip buffer work if space
* just became available.
*
* Locks: Concurrent update is protected with read_lock
*/
static void n_tty_set_room(struct tty_struct *tty)
static int set_room(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
int left;
int old_left;
unsigned long flags;
raw_spin_lock_irqsave(&ldata->read_lock, flags);
/* ldata->read_cnt is not read locked ? */
if (I_PARMRK(tty)) {
/* Multiply read_cnt by 3, since each byte might take up to
* three times as many spaces when PARMRK is set (depending on
@ -149,8 +153,15 @@ static void n_tty_set_room(struct tty_struct *tty)
old_left = tty->receive_room;
tty->receive_room = left;
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
return left && !old_left;
}
static void n_tty_set_room(struct tty_struct *tty)
{
/* Did this open up the receive buffer? We may need to flip */
if (left && !old_left) {
if (set_room(tty)) {
WARN_RATELIMIT(tty->port->itty == NULL,
"scheduling with invalid itty\n");
/* see if ldisc has been killed - if so, this means that
@ -647,8 +658,7 @@ static void process_echoes(struct tty_struct *tty)
if (no_space_left)
break;
} else {
if (O_OPOST(tty) &&
!(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
if (O_OPOST(tty)) {
int retval = do_output_char(c, tty, space);
if (retval < 0)
break;
@ -1454,9 +1464,9 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
tty->ops->flush_chars(tty);
}
n_tty_set_room(tty);
set_room(tty);
if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) ||
if ((!ldata->icanon && (ldata->read_cnt >= ldata->minimum_to_wake)) ||
L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
@ -1516,12 +1526,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
wake_up_interruptible(&tty->read_wait);
ldata->icanon = (L_ICANON(tty) != 0);
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
ldata->raw = 1;
ldata->real_raw = 1;
n_tty_set_room(tty);
return;
}
if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
@ -1642,7 +1647,7 @@ static int n_tty_open(struct tty_struct *tty)
tty->disc_data = ldata;
reset_buffer_flags(tty->disc_data);
ldata->column = 0;
tty->minimum_to_wake = 1;
ldata->minimum_to_wake = 1;
tty->closing = 0;
/* indicate buffer work may resume */
clear_bit(TTY_LDISC_HALTED, &tty->flags);
@ -1806,21 +1811,17 @@ do_it_again:
minimum = time = 0;
timeout = MAX_SCHEDULE_TIMEOUT;
if (!ldata->icanon) {
time = (HZ / 10) * TIME_CHAR(tty);
minimum = MIN_CHAR(tty);
if (minimum) {
time = (HZ / 10) * TIME_CHAR(tty);
if (time)
tty->minimum_to_wake = 1;
ldata->minimum_to_wake = 1;
else if (!waitqueue_active(&tty->read_wait) ||
(tty->minimum_to_wake > minimum))
tty->minimum_to_wake = minimum;
(ldata->minimum_to_wake > minimum))
ldata->minimum_to_wake = minimum;
} else {
timeout = 0;
if (time) {
timeout = time;
time = 0;
}
tty->minimum_to_wake = minimum = 1;
timeout = (HZ / 10) * TIME_CHAR(tty);
ldata->minimum_to_wake = minimum = 1;
}
}
@ -1860,9 +1861,9 @@ do_it_again:
TASK_RUNNING. */
set_current_state(TASK_INTERRUPTIBLE);
if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
if (((minimum - (b - buf)) < ldata->minimum_to_wake) &&
((minimum - (b - buf)) >= 1))
tty->minimum_to_wake = (minimum - (b - buf));
ldata->minimum_to_wake = (minimum - (b - buf));
if (!input_available_p(tty, 0)) {
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
@ -1881,7 +1882,6 @@ do_it_again:
retval = -ERESTARTSYS;
break;
}
/* FIXME: does n_tty_set_room need locking ? */
n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
continue;
@ -1979,7 +1979,7 @@ do_it_again:
remove_wait_queue(&tty->read_wait, &wait);
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = minimum;
ldata->minimum_to_wake = minimum;
__set_current_state(TASK_RUNNING);
size = b - buf;
@ -2045,7 +2045,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
retval = -EIO;
break;
}
if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
if (O_OPOST(tty)) {
while (nr > 0) {
ssize_t num = process_output_block(tty, b, nr);
if (num < 0) {
@ -2111,6 +2111,7 @@ break_out:
static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_table *wait)
{
struct n_tty_data *ldata = tty->disc_data;
unsigned int mask = 0;
poll_wait(file, &tty->read_wait, wait);
@ -2125,9 +2126,9 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
mask |= POLLHUP;
if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
if (MIN_CHAR(tty) && !TIME_CHAR(tty))
tty->minimum_to_wake = MIN_CHAR(tty);
ldata->minimum_to_wake = MIN_CHAR(tty);
else
tty->minimum_to_wake = 1;
ldata->minimum_to_wake = 1;
}
if (tty->ops->write && !tty_is_writelocked(tty) &&
tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
@ -2175,6 +2176,18 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
}
}
static void n_tty_fasync(struct tty_struct *tty, int on)
{
struct n_tty_data *ldata = tty->disc_data;
if (!waitqueue_active(&tty->read_wait)) {
if (on)
ldata->minimum_to_wake = 1;
else if (!tty->fasync)
ldata->minimum_to_wake = N_TTY_BUF_SIZE;
}
}
struct tty_ldisc_ops tty_ldisc_N_TTY = {
.magic = TTY_LDISC_MAGIC,
.name = "n_tty",
@ -2188,7 +2201,8 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.set_termios = n_tty_set_termios,
.poll = n_tty_poll,
.receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup
.write_wakeup = n_tty_write_wakeup,
.fasync = n_tty_fasync,
};
/**

View File

@ -4797,10 +4797,6 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_VENDOR_ID_IBM, 0x0299,
0, 0, pbn_b0_bt_2_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
0x1000, 0x0012,
0, 0, pbn_b0_bt_2_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
0xA000, 0x1000,
0, 0, pbn_b0_1_115200 },

View File

@ -12,9 +12,8 @@ config SERIAL_8250
here are those that are setting up dedicated Ethernet WWW/FTP
servers, or users that have one of the various bus mice instead of a
serial mouse and don't intend to use their machine's standard serial
port for anything. (Note that the Cyclades and Stallion multi
serial port drivers do not need this driver built in for them to
work.)
port for anything. (Note that the Cyclades multi serial port driver
does not need this driver built in for it to work.)
To compile this driver as a module, choose M here: the
module will be called 8250.

View File

@ -551,7 +551,7 @@ config BFIN_UART3_CTSRTS
Enable hardware flow control in the driver.
config SERIAL_IMX
bool "IMX serial port support"
tristate "IMX serial port support"
depends on ARCH_MXC
select SERIAL_CORE
select RATIONAL
@ -561,22 +561,21 @@ config SERIAL_IMX
config SERIAL_IMX_CONSOLE
bool "Console on IMX serial port"
depends on SERIAL_IMX
depends on SERIAL_IMX=y
select SERIAL_CORE_CONSOLE
help
If you have enabled the serial port on the Motorola IMX
If you have enabled the serial port on the Freescale IMX
CPU you can make it the console by answering Y to this option.
Even if you say Y here, the currently visible virtual console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttySA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
"console=ttymxc0". (Try "man bootparam" or see the documentation of
your bootloader about how to pass options to the kernel at boot time.)
config SERIAL_UARTLITE
tristate "Xilinx uartlite serial port support"
depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE || ARCH_ZYNQ
select SERIAL_CORE
help
Say Y here if you want to use the Xilinx uartlite serial controller.
@ -1484,6 +1483,20 @@ config SERIAL_RP2_NR_UARTS
If multiple cards are present, the default limit of 32 ports may
need to be increased.
config SERIAL_FSL_LPUART
tristate "Freescale lpuart serial port support"
select SERIAL_CORE
help
Support for the on-chip lpuart on some Freescale SOCs.
config SERIAL_FSL_LPUART_CONSOLE
bool "Console on Freescale lpuart serial port"
depends on SERIAL_FSL_LPUART=y
select SERIAL_CORE_CONSOLE
help
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
endmenu
endif # TTY

View File

@ -85,3 +85,4 @@ obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o

View File

@ -604,7 +604,6 @@ static int altera_uart_remove(struct platform_device *pdev)
if (port) {
uart_remove_one_port(&altera_uart_driver, port);
platform_set_drvdata(pdev, NULL);
port->mapbase = 0;
}

View File

@ -79,13 +79,12 @@ struct vendor_data {
bool dma_threshold;
bool cts_event_workaround;
unsigned int (*get_fifosize)(unsigned int periphid);
unsigned int (*get_fifosize)(struct amba_device *dev);
};
static unsigned int get_fifosize_arm(unsigned int periphid)
static unsigned int get_fifosize_arm(struct amba_device *dev)
{
unsigned int rev = (periphid >> 20) & 0xf;
return rev < 3 ? 16 : 32;
return amba_rev(dev) < 3 ? 16 : 32;
}
static struct vendor_data vendor_arm = {
@ -98,7 +97,7 @@ static struct vendor_data vendor_arm = {
.get_fifosize = get_fifosize_arm,
};
static unsigned int get_fifosize_st(unsigned int periphid)
static unsigned int get_fifosize_st(struct amba_device *dev)
{
return 64;
}
@ -2157,7 +2156,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
uap->fifosize = vendor->get_fifosize(dev->periphid);
uap->fifosize = vendor->get_fifosize(dev);
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;

View File

@ -1100,7 +1100,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
* Enable the peripheral clock for this serial port.
* This is called on uart_open() or a resume event.
*/
clk_enable(atmel_port->clk);
clk_prepare_enable(atmel_port->clk);
/* re-enable interrupts if we disabled some on suspend */
UART_PUT_IER(port, atmel_port->backup_imr);
@ -1114,7 +1114,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
* Disable the peripheral clock for this serial port.
* This is called on uart_close() or a suspend event.
*/
clk_disable(atmel_port->clk);
clk_disable_unprepare(atmel_port->clk);
break;
default:
printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
@ -1458,9 +1458,10 @@ static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
/*
* Configure the port from the platform device resource info.
*/
static void atmel_init_port(struct atmel_uart_port *atmel_port,
static int atmel_init_port(struct atmel_uart_port *atmel_port,
struct platform_device *pdev)
{
int ret;
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *pdata = pdev->dev.platform_data;
@ -1496,9 +1497,19 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
/* for console, the clock could already be configured */
if (!atmel_port->clk) {
atmel_port->clk = clk_get(&pdev->dev, "usart");
clk_enable(atmel_port->clk);
if (IS_ERR(atmel_port->clk)) {
ret = PTR_ERR(atmel_port->clk);
atmel_port->clk = NULL;
return ret;
}
ret = clk_prepare_enable(atmel_port->clk);
if (ret) {
clk_put(atmel_port->clk);
atmel_port->clk = NULL;
return ret;
}
port->uartclk = clk_get_rate(atmel_port->clk);
clk_disable(atmel_port->clk);
clk_disable_unprepare(atmel_port->clk);
/* only enable clock when USART is in use */
}
@ -1511,6 +1522,8 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
} else {
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
}
return 0;
}
struct platform_device *atmel_default_console_device; /* the serial console device */
@ -1601,6 +1614,7 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud,
static int __init atmel_console_setup(struct console *co, char *options)
{
int ret;
struct uart_port *port = &atmel_ports[co->index].uart;
int baud = 115200;
int bits = 8;
@ -1612,7 +1626,9 @@ static int __init atmel_console_setup(struct console *co, char *options)
return -ENODEV;
}
clk_enable(atmel_ports[co->index].clk);
ret = clk_prepare_enable(atmel_ports[co->index].clk);
if (ret)
return ret;
UART_PUT_IDR(port, -1);
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
@ -1645,6 +1661,7 @@ static struct console atmel_console = {
*/
static int __init atmel_console_init(void)
{
int ret;
if (atmel_default_console_device) {
struct atmel_uart_data *pdata =
atmel_default_console_device->dev.platform_data;
@ -1655,7 +1672,9 @@ static int __init atmel_console_init(void)
port->uart.line = id;
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
atmel_init_port(port, atmel_default_console_device);
ret = atmel_init_port(port, atmel_default_console_device);
if (ret)
return ret;
register_console(&atmel_console);
}
@ -1786,7 +1805,9 @@ static int atmel_serial_probe(struct platform_device *pdev)
port->backup_imr = 0;
port->uart.line = ret;
atmel_init_port(port, pdev);
ret = atmel_init_port(port, pdev);
if (ret)
goto err;
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
@ -1812,9 +1833,9 @@ static int atmel_serial_probe(struct platform_device *pdev)
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
/*
* The serial core enabled the clock for us, so undo
* the clk_enable() in atmel_console_setup()
* the clk_prepare_enable() in atmel_console_setup()
*/
clk_disable(port->clk);
clk_disable_unprepare(port->clk);
}
#endif

View File

@ -1384,7 +1384,7 @@ static int cpm_uart_probe(struct platform_device *ofdev)
if (index >= UART_NR)
return -ENODEV;
dev_set_drvdata(&ofdev->dev, pinfo);
platform_set_drvdata(ofdev, pinfo);
/* initialize the device pointer for the port */
pinfo->port.dev = &ofdev->dev;
@ -1398,7 +1398,7 @@ static int cpm_uart_probe(struct platform_device *ofdev)
static int cpm_uart_remove(struct platform_device *ofdev)
{
struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev);
return uart_remove_one_port(&cpm_reg, &pinfo->port);
}

View File

@ -0,0 +1,874 @@
/*
* Freescale lpuart serial port driver
*
* Copyright 2012-2013 Freescale Semiconductor, Inc.
*
* 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.
*/
#if defined(CONFIG_SERIAL_FSL_LPUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/tty_flip.h>
/* All registers are 8-bit width */
#define UARTBDH 0x00
#define UARTBDL 0x01
#define UARTCR1 0x02
#define UARTCR2 0x03
#define UARTSR1 0x04
#define UARTCR3 0x06
#define UARTDR 0x07
#define UARTCR4 0x0a
#define UARTCR5 0x0b
#define UARTMODEM 0x0d
#define UARTPFIFO 0x10
#define UARTCFIFO 0x11
#define UARTSFIFO 0x12
#define UARTTWFIFO 0x13
#define UARTTCFIFO 0x14
#define UARTRWFIFO 0x15
#define UARTBDH_LBKDIE 0x80
#define UARTBDH_RXEDGIE 0x40
#define UARTBDH_SBR_MASK 0x1f
#define UARTCR1_LOOPS 0x80
#define UARTCR1_RSRC 0x20
#define UARTCR1_M 0x10
#define UARTCR1_WAKE 0x08
#define UARTCR1_ILT 0x04
#define UARTCR1_PE 0x02
#define UARTCR1_PT 0x01
#define UARTCR2_TIE 0x80
#define UARTCR2_TCIE 0x40
#define UARTCR2_RIE 0x20
#define UARTCR2_ILIE 0x10
#define UARTCR2_TE 0x08
#define UARTCR2_RE 0x04
#define UARTCR2_RWU 0x02
#define UARTCR2_SBK 0x01
#define UARTSR1_TDRE 0x80
#define UARTSR1_TC 0x40
#define UARTSR1_RDRF 0x20
#define UARTSR1_IDLE 0x10
#define UARTSR1_OR 0x08
#define UARTSR1_NF 0x04
#define UARTSR1_FE 0x02
#define UARTSR1_PE 0x01
#define UARTCR3_R8 0x80
#define UARTCR3_T8 0x40
#define UARTCR3_TXDIR 0x20
#define UARTCR3_TXINV 0x10
#define UARTCR3_ORIE 0x08
#define UARTCR3_NEIE 0x04
#define UARTCR3_FEIE 0x02
#define UARTCR3_PEIE 0x01
#define UARTCR4_MAEN1 0x80
#define UARTCR4_MAEN2 0x40
#define UARTCR4_M10 0x20
#define UARTCR4_BRFA_MASK 0x1f
#define UARTCR4_BRFA_OFF 0
#define UARTCR5_TDMAS 0x80
#define UARTCR5_RDMAS 0x20
#define UARTMODEM_RXRTSE 0x08
#define UARTMODEM_TXRTSPOL 0x04
#define UARTMODEM_TXRTSE 0x02
#define UARTMODEM_TXCTSE 0x01
#define UARTPFIFO_TXFE 0x80
#define UARTPFIFO_FIFOSIZE_MASK 0x7
#define UARTPFIFO_TXSIZE_OFF 4
#define UARTPFIFO_RXFE 0x08
#define UARTPFIFO_RXSIZE_OFF 0
#define UARTCFIFO_TXFLUSH 0x80
#define UARTCFIFO_RXFLUSH 0x40
#define UARTCFIFO_RXOFE 0x04
#define UARTCFIFO_TXOFE 0x02
#define UARTCFIFO_RXUFE 0x01
#define UARTSFIFO_TXEMPT 0x80
#define UARTSFIFO_RXEMPT 0x40
#define UARTSFIFO_RXOF 0x04
#define UARTSFIFO_TXOF 0x02
#define UARTSFIFO_RXUF 0x01
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
#define UART_NR 6
struct lpuart_port {
struct uart_port port;
struct clk *clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
};
static struct of_device_id lpuart_dt_ids[] = {
{
.compatible = "fsl,vf610-lpuart",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
static void lpuart_stop_tx(struct uart_port *port)
{
unsigned char temp;
temp = readb(port->membase + UARTCR2);
temp &= ~(UARTCR2_TIE | UARTCR2_TCIE);
writeb(temp, port->membase + UARTCR2);
}
static void lpuart_stop_rx(struct uart_port *port)
{
unsigned char temp;
temp = readb(port->membase + UARTCR2);
writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2);
}
static void lpuart_enable_ms(struct uart_port *port)
{
}
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
while (!uart_circ_empty(xmit) &&
(readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) {
writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit))
lpuart_stop_tx(&sport->port);
}
static void lpuart_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned char temp;
temp = readb(port->membase + UARTCR2);
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
lpuart_transmit_buffer(sport);
}
static irqreturn_t lpuart_txint(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
if (sport->port.x_char) {
writeb(sport->port.x_char, sport->port.membase + UARTDR);
goto out;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
lpuart_stop_tx(&sport->port);
goto out;
}
lpuart_transmit_buffer(sport);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
out:
spin_unlock_irqrestore(&sport->port.lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t lpuart_rxint(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
unsigned int flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
unsigned long flags;
unsigned char rx, sr;
spin_lock_irqsave(&sport->port.lock, flags);
while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) {
flg = TTY_NORMAL;
sport->port.icount.rx++;
/*
* to clear the FE, OR, NF, FE, PE flags,
* read SR1 then read DR
*/
sr = readb(sport->port.membase + UARTSR1);
rx = readb(sport->port.membase + UARTDR);
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
continue;
if (sr & (UARTSR1_PE | UARTSR1_OR | UARTSR1_FE)) {
if (sr & UARTSR1_PE)
sport->port.icount.parity++;
else if (sr & UARTSR1_FE)
sport->port.icount.frame++;
if (sr & UARTSR1_OR)
sport->port.icount.overrun++;
if (sr & sport->port.ignore_status_mask) {
if (++ignored > 100)
goto out;
continue;
}
sr &= sport->port.read_status_mask;
if (sr & UARTSR1_PE)
flg = TTY_PARITY;
else if (sr & UARTSR1_FE)
flg = TTY_FRAME;
if (sr & UARTSR1_OR)
flg = TTY_OVERRUN;
#ifdef SUPPORT_SYSRQ
sport->port.sysrq = 0;
#endif
}
tty_insert_flip_char(port, rx, flg);
}
out:
spin_unlock_irqrestore(&sport->port.lock, flags);
tty_flip_buffer_push(port);
return IRQ_HANDLED;
}
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
unsigned char sts;
sts = readb(sport->port.membase + UARTSR1);
if (sts & UARTSR1_RDRF)
lpuart_rxint(irq, dev_id);
if (sts & UARTSR1_TDRE &&
!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS))
lpuart_txint(irq, dev_id);
return IRQ_HANDLED;
}
/* return TIOCSER_TEMT when transmitter is not busy */
static unsigned int lpuart_tx_empty(struct uart_port *port)
{
return (readb(port->membase + UARTSR1) & UARTSR1_TC) ?
TIOCSER_TEMT : 0;
}
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
unsigned int temp = 0;
unsigned char reg;
reg = readb(port->membase + UARTMODEM);
if (reg & UARTMODEM_TXCTSE)
temp |= TIOCM_CTS;
if (reg & UARTMODEM_RXRTSE)
temp |= TIOCM_RTS;
return temp;
}
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned char temp;
temp = readb(port->membase + UARTMODEM) &
~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
if (mctrl & TIOCM_RTS)
temp |= UARTMODEM_RXRTSE;
if (mctrl & TIOCM_CTS)
temp |= UARTMODEM_TXCTSE;
writeb(temp, port->membase + UARTMODEM);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
{
unsigned char temp;
temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
if (break_state != 0)
temp |= UARTCR2_SBK;
writeb(temp, port->membase + UARTCR2);
}
static void lpuart_setup_watermark(struct lpuart_port *sport)
{
unsigned char val, cr2;
cr2 = readb(sport->port.membase + UARTCR2);
cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_TE |
UARTCR2_RIE | UARTCR2_RE);
writeb(cr2, sport->port.membase + UARTCR2);
/* determine FIFO size and enable FIFO mode */
val = readb(sport->port.membase + UARTPFIFO);
sport->txfifo_size = 0x1 << (((val >> UARTPFIFO_TXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
sport->rxfifo_size = 0x1 << (((val >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
sport->port.membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
sport->port.membase + UARTCFIFO);
writeb(2, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
}
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
int ret;
unsigned long flags;
unsigned char temp;
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
DRIVER_NAME, sport);
if (ret)
return ret;
spin_lock_irqsave(&sport->port.lock, flags);
lpuart_setup_watermark(sport);
temp = readb(sport->port.membase + UARTCR2);
temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
writeb(temp, sport->port.membase + UARTCR2);
spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
static void lpuart_shutdown(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned char temp;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* disable Rx/Tx and interrupts */
temp = readb(port->membase + UARTCR2);
temp &= ~(UARTCR2_TE | UARTCR2_RE |
UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE);
writeb(temp, port->membase + UARTCR2);
spin_unlock_irqrestore(&port->lock, flags);
devm_free_irq(port->dev, port->irq, sport);
}
static void
lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long flags;
unsigned char cr1, old_cr1, old_cr2, cr4, bdh, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
unsigned int sbr, brfa;
cr1 = old_cr1 = readb(sport->port.membase + UARTCR1);
old_cr2 = readb(sport->port.membase + UARTCR2);
cr4 = readb(sport->port.membase + UARTCR4);
bdh = readb(sport->port.membase + UARTBDH);
modem = readb(sport->port.membase + UARTMODEM);
/*
* only support CS8 and CS7, and for CS7 must enable PE.
* supported mode:
* - (7,e/o,1)
* - (8,n,1)
* - (8,m/s,1)
* - (8,e/o,1)
*/
while ((termios->c_cflag & CSIZE) != CS8 &&
(termios->c_cflag & CSIZE) != CS7) {
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= old_csize;
old_csize = CS8;
}
if ((termios->c_cflag & CSIZE) == CS8 ||
(termios->c_cflag & CSIZE) == CS7)
cr1 = old_cr1 & ~UARTCR1_M;
if (termios->c_cflag & CMSPAR) {
if ((termios->c_cflag & CSIZE) != CS8) {
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
}
cr1 |= UARTCR1_M;
}
if (termios->c_cflag & CRTSCTS) {
modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
} else {
termios->c_cflag &= ~CRTSCTS;
modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
}
if (termios->c_cflag & CSTOPB)
termios->c_cflag &= ~CSTOPB;
/* parity must be enabled when CS7 to match 8-bits format */
if ((termios->c_cflag & CSIZE) == CS7)
termios->c_cflag |= PARENB;
if ((termios->c_cflag & PARENB)) {
if (termios->c_cflag & CMSPAR) {
cr1 &= ~UARTCR1_PE;
cr1 |= UARTCR1_M;
} else {
cr1 |= UARTCR1_PE;
if ((termios->c_cflag & CSIZE) == CS8)
cr1 |= UARTCR1_M;
if (termios->c_cflag & PARODD)
cr1 |= UARTCR1_PT;
else
cr1 &= ~UARTCR1_PT;
}
}
/* ask the core to calculate the divisor */
baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
spin_lock_irqsave(&sport->port.lock, flags);
sport->port.read_status_mask = 0;
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE);
if (termios->c_iflag & (BRKINT | PARMRK))
sport->port.read_status_mask |= UARTSR1_FE;
/* characters to ignore */
sport->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= UARTSR1_PE;
if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |= UARTSR1_FE;
/*
* if we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
sport->port.ignore_status_mask |= UARTSR1_OR;
}
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
/* wait transmit engin complete */
while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC))
barrier();
/* disable transmit and receive */
writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE),
sport->port.membase + UARTCR2);
sbr = sport->port.uartclk / (16 * baud);
brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud;
bdh &= ~UARTBDH_SBR_MASK;
bdh |= (sbr >> 8) & 0x1F;
cr4 &= ~UARTCR4_BRFA_MASK;
brfa &= UARTCR4_BRFA_MASK;
writeb(cr4 | brfa, sport->port.membase + UARTCR4);
writeb(bdh, sport->port.membase + UARTBDH);
writeb(sbr & 0xFF, sport->port.membase + UARTBDL);
writeb(cr1, sport->port.membase + UARTCR1);
writeb(modem, sport->port.membase + UARTMODEM);
/* restore control register */
writeb(old_cr2, sport->port.membase + UARTCR2);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static const char *lpuart_type(struct uart_port *port)
{
return "FSL_LPUART";
}
static void lpuart_release_port(struct uart_port *port)
{
/* nothing to do */
}
static int lpuart_request_port(struct uart_port *port)
{
return 0;
}
/* configure/autoconfigure the port */
static void lpuart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_LPUART;
}
static int lpuart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_LPUART)
ret = -EINVAL;
if (port->irq != ser->irq)
ret = -EINVAL;
if (ser->io_type != UPIO_MEM)
ret = -EINVAL;
if (port->uartclk / 16 != ser->baud_base)
ret = -EINVAL;
if (port->iobase != ser->port)
ret = -EINVAL;
if (ser->hub6 != 0)
ret = -EINVAL;
return ret;
}
static struct uart_ops lpuart_pops = {
.tx_empty = lpuart_tx_empty,
.set_mctrl = lpuart_set_mctrl,
.get_mctrl = lpuart_get_mctrl,
.stop_tx = lpuart_stop_tx,
.start_tx = lpuart_start_tx,
.stop_rx = lpuart_stop_rx,
.enable_ms = lpuart_enable_ms,
.break_ctl = lpuart_break_ctl,
.startup = lpuart_startup,
.shutdown = lpuart_shutdown,
.set_termios = lpuart_set_termios,
.type = lpuart_type,
.request_port = lpuart_request_port,
.release_port = lpuart_release_port,
.config_port = lpuart_config_port,
.verify_port = lpuart_verify_port,
};
static struct lpuart_port *lpuart_ports[UART_NR];
#ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE
static void lpuart_console_putchar(struct uart_port *port, int ch)
{
while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE))
barrier();
writeb(ch, port->membase + UARTDR);
}
static void
lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
unsigned char old_cr2, cr2;
/* first save CR2 and then disable interrupts */
cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
cr2 |= (UARTCR2_TE | UARTCR2_RE);
cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE);
writeb(cr2, sport->port.membase + UARTCR2);
uart_console_write(&sport->port, s, count, lpuart_console_putchar);
/* wait for transmitter finish complete and restore CR2 */
while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC))
barrier();
writeb(old_cr2, sport->port.membase + UARTCR2);
}
/*
* if the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
*/
static void __init
lpuart_console_get_options(struct lpuart_port *sport, int *baud,
int *parity, int *bits)
{
unsigned char cr, bdh, bdl, brfa;
unsigned int sbr, uartclk, baud_raw;
cr = readb(sport->port.membase + UARTCR2);
cr &= UARTCR2_TE | UARTCR2_RE;
if (!cr)
return;
/* ok, the port was enabled */
cr = readb(sport->port.membase + UARTCR1);
*parity = 'n';
if (cr & UARTCR1_PE) {
if (cr & UARTCR1_PT)
*parity = 'o';
else
*parity = 'e';
}
if (cr & UARTCR1_M)
*bits = 9;
else
*bits = 8;
bdh = readb(sport->port.membase + UARTBDH);
bdh &= UARTBDH_SBR_MASK;
bdl = readb(sport->port.membase + UARTBDL);
sbr = bdh;
sbr <<= 8;
sbr |= bdl;
brfa = readb(sport->port.membase + UARTCR4);
brfa &= UARTCR4_BRFA_MASK;
uartclk = clk_get_rate(sport->clk);
/*
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
*/
baud_raw = uartclk / (16 * (sbr + brfa / 32));
if (*baud != baud_raw)
printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
"from %d to %d\n", baud_raw, *baud);
}
static int __init lpuart_console_setup(struct console *co, char *options)
{
struct lpuart_port *sport;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index == -1 || co->index >= ARRAY_SIZE(lpuart_ports))
co->index = 0;
sport = lpuart_ports[co->index];
if (sport == NULL)
return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
lpuart_console_get_options(sport, &baud, &parity, &bits);
lpuart_setup_watermark(sport);
return uart_set_options(&sport->port, co, baud, parity, bits, flow);
}
static struct uart_driver lpuart_reg;
static struct console lpuart_console = {
.name = DEV_NAME,
.write = lpuart_console_write,
.device = uart_console_device,
.setup = lpuart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &lpuart_reg,
};
#define LPUART_CONSOLE (&lpuart_console)
#else
#define LPUART_CONSOLE NULL
#endif
static struct uart_driver lpuart_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = DEV_NAME,
.nr = ARRAY_SIZE(lpuart_ports),
.cons = LPUART_CONSOLE,
};
static int lpuart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct lpuart_port *sport;
struct resource *res;
int ret;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
if (!sport)
return -ENOMEM;
pdev->dev.coherent_dma_mask = 0;
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return ret;
}
sport->port.line = ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
sport->port.mapbase = res->start;
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sport->port.membase))
return PTR_ERR(sport->port.membase);
sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART;
sport->port.iotype = UPIO_MEM;
sport->port.irq = platform_get_irq(pdev, 0);
sport->port.ops = &lpuart_pops;
sport->port.flags = UPF_BOOT_AUTOCONF;
sport->clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk)) {
ret = PTR_ERR(sport->clk);
dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(sport->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
return ret;
}
sport->port.uartclk = clk_get_rate(sport->clk);
lpuart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, &sport->port);
ret = uart_add_one_port(&lpuart_reg, &sport->port);
if (ret) {
clk_disable_unprepare(sport->clk);
return ret;
}
return 0;
}
static int lpuart_remove(struct platform_device *pdev)
{
struct lpuart_port *sport = platform_get_drvdata(pdev);
uart_remove_one_port(&lpuart_reg, &sport->port);
clk_disable_unprepare(sport->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
uart_suspend_port(&lpuart_reg, &sport->port);
return 0;
}
static int lpuart_resume(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
uart_resume_port(&lpuart_reg, &sport->port);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
static struct platform_driver lpuart_driver = {
.probe = lpuart_probe,
.remove = lpuart_remove,
.driver = {
.name = "fsl-lpuart",
.owner = THIS_MODULE,
.of_match_table = lpuart_dt_ids,
.pm = &lpuart_pm_ops,
},
};
static int __init lpuart_serial_init(void)
{
int ret;
pr_info("serial: Freescale lpuart driver\n");
ret = uart_register_driver(&lpuart_reg);
if (ret)
return ret;
ret = platform_driver_register(&lpuart_driver);
if (ret)
uart_unregister_driver(&lpuart_reg);
return 0;
}
static void __exit lpuart_serial_exit(void)
{
platform_driver_unregister(&lpuart_driver);
uart_unregister_driver(&lpuart_reg);
}
module_init(lpuart_serial_init);
module_exit(lpuart_serial_exit);
MODULE_DESCRIPTION("Freescale lpuart serial port driver");
MODULE_LICENSE("GPL v2");

View File

@ -201,6 +201,7 @@ struct imx_port {
unsigned int old_status;
int txirq, rxirq, rtsirq;
unsigned int have_rtscts:1;
unsigned int dte_mode:1;
unsigned int use_irda:1;
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
@ -271,6 +272,7 @@ static inline int is_imx21_uart(struct imx_port *sport)
/*
* Save and restore functions for UCR1, UCR2 and UCR3 registers
*/
#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_port_ucrs_save(struct uart_port *port,
struct imx_port_ucrs *ucr)
{
@ -288,6 +290,7 @@ static void imx_port_ucrs_restore(struct uart_port *port,
writel(ucr->ucr2, port->membase + UCR2);
writel(ucr->ucr3, port->membase + UCR3);
}
#endif
/*
* Handle any change of modem status signal since we were last called.
@ -449,6 +452,13 @@ static void imx_start_tx(struct uart_port *port)
temp &= ~(UCR1_RRDYEN);
writel(temp, sport->port.membase + UCR1);
}
/* Clear any pending ORE flag before enabling interrupt */
temp = readl(sport->port.membase + USR2);
writel(temp | USR2_ORE, sport->port.membase + USR2);
temp = readl(sport->port.membase + UCR4);
temp |= UCR4_OREN;
writel(temp, sport->port.membase + UCR4);
temp = readl(sport->port.membase + UCR1);
writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
@ -582,6 +592,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned int sts;
unsigned int sts2;
sts = readl(sport->port.membase + USR1);
@ -598,6 +609,13 @@ static irqreturn_t imx_int(int irq, void *dev_id)
if (sts & USR1_AWAKE)
writel(USR1_AWAKE, sport->port.membase + USR1);
sts2 = readl(sport->port.membase + USR2);
if (sts2 & USR2_ORE) {
dev_err(sport->port.dev, "Rx FIFO overrun\n");
sport->port.icount.overrun++;
writel(sts2 | USR2_ORE, sport->port.membase + USR2);
}
return IRQ_HANDLED;
}
@ -684,6 +702,17 @@ static int imx_startup(struct uart_port *port)
int retval;
unsigned long flags, temp;
if (!uart_console(port)) {
retval = clk_prepare_enable(sport->clk_per);
if (retval)
goto error_out1;
retval = clk_prepare_enable(sport->clk_ipg);
if (retval) {
clk_disable_unprepare(sport->clk_per);
goto error_out1;
}
}
imx_setup_ufcr(sport, 0);
/* disable the DREN bit (Data Ready interrupt enable) before
@ -871,6 +900,11 @@ static void imx_shutdown(struct uart_port *port)
writel(temp, sport->port.membase + UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
if (!uart_console(&sport->port)) {
clk_disable_unprepare(sport->clk_per);
clk_disable_unprepare(sport->clk_ipg);
}
}
static void
@ -1007,6 +1041,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
ufcr = readl(sport->port.membase + UFCR);
ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
if (sport->dte_mode)
ufcr |= UFCR_DCEDTE;
writel(ufcr, sport->port.membase + UFCR);
writel(num, sport->port.membase + UBIR);
@ -1431,6 +1467,9 @@ static int serial_imx_probe_dt(struct imx_port *sport,
if (of_get_property(np, "fsl,irda-mode", NULL))
sport->use_irda = 1;
if (of_get_property(np, "fsl,dte-mode", NULL))
sport->dte_mode = 1;
sport->devdata = of_id->data;
return 0;
@ -1544,6 +1583,11 @@ static int serial_imx_probe(struct platform_device *pdev)
goto deinit;
platform_set_drvdata(pdev, sport);
if (!uart_console(&sport->port)) {
clk_disable_unprepare(sport->clk_per);
clk_disable_unprepare(sport->clk_ipg);
}
return 0;
deinit:
if (pdata && pdata->exit)
@ -1565,9 +1609,6 @@ static int serial_imx_remove(struct platform_device *pdev)
uart_remove_one_port(&imx_reg, &sport->port);
clk_disable_unprepare(sport->clk_per);
clk_disable_unprepare(sport->clk_ipg);
if (pdata && pdata->exit)
pdata->exit(pdev);

View File

@ -21,6 +21,10 @@
* be triggered
*/
#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>

View File

@ -84,16 +84,6 @@ static void mpc52xx_uart_of_enumerate(void);
static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
/* Simple macro to test if a port is console or not. This one is taken
* for serial_core.c and maybe should be moved to serial_core.h ? */
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) \
((port)->cons && (port)->cons->index == (port)->line)
#else
#define uart_console(port) (0)
#endif
/* ======================================================================== */
/* PSC fifo operations for isolating differences between 52xx and 512x */
/* ======================================================================== */
@ -122,6 +112,15 @@ struct psc_ops {
void (*fifoc_uninit)(void);
void (*get_irq)(struct uart_port *, struct device_node *);
irqreturn_t (*handle_irq)(struct uart_port *port);
u16 (*get_status)(struct uart_port *port);
u8 (*get_ipcr)(struct uart_port *port);
void (*command)(struct uart_port *port, u8 cmd);
void (*set_mode)(struct uart_port *port, u8 mr1, u8 mr2);
void (*set_rts)(struct uart_port *port, int state);
void (*enable_ms)(struct uart_port *port);
void (*set_sicr)(struct uart_port *port, u32 val);
void (*set_imr)(struct uart_port *port, u16 val);
u8 (*get_mr1)(struct uart_port *port);
};
/* setting the prescaler and divisor reg is common for all chips */
@ -134,6 +133,65 @@ static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
out_8(&psc->ctlr, divisor & 0xff);
}
static u16 mpc52xx_psc_get_status(struct uart_port *port)
{
return in_be16(&PSC(port)->mpc52xx_psc_status);
}
static u8 mpc52xx_psc_get_ipcr(struct uart_port *port)
{
return in_8(&PSC(port)->mpc52xx_psc_ipcr);
}
static void mpc52xx_psc_command(struct uart_port *port, u8 cmd)
{
out_8(&PSC(port)->command, cmd);
}
static void mpc52xx_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2)
{
out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&PSC(port)->mode, mr1);
out_8(&PSC(port)->mode, mr2);
}
static void mpc52xx_psc_set_rts(struct uart_port *port, int state)
{
if (state)
out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
else
out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
}
static void mpc52xx_psc_enable_ms(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
/* clear D_*-bits by reading them */
in_8(&psc->mpc52xx_psc_ipcr);
/* enable CTS and DCD as IPC interrupts */
out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
static void mpc52xx_psc_set_sicr(struct uart_port *port, u32 val)
{
out_be32(&PSC(port)->sicr, val);
}
static void mpc52xx_psc_set_imr(struct uart_port *port, u16 val)
{
out_be16(&PSC(port)->mpc52xx_psc_imr, val);
}
static u8 mpc52xx_psc_get_mr1(struct uart_port *port)
{
out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1);
return in_8(&PSC(port)->mode);
}
#ifdef CONFIG_PPC_MPC52xx
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
static void mpc52xx_psc_fifo_init(struct uart_port *port)
@ -304,6 +362,15 @@ static struct psc_ops mpc52xx_psc_ops = {
.set_baudrate = mpc5200_psc_set_baudrate,
.get_irq = mpc52xx_psc_get_irq,
.handle_irq = mpc52xx_psc_handle_irq,
.get_status = mpc52xx_psc_get_status,
.get_ipcr = mpc52xx_psc_get_ipcr,
.command = mpc52xx_psc_command,
.set_mode = mpc52xx_psc_set_mode,
.set_rts = mpc52xx_psc_set_rts,
.enable_ms = mpc52xx_psc_enable_ms,
.set_sicr = mpc52xx_psc_set_sicr,
.set_imr = mpc52xx_psc_set_imr,
.get_mr1 = mpc52xx_psc_get_mr1,
};
static struct psc_ops mpc5200b_psc_ops = {
@ -325,6 +392,15 @@ static struct psc_ops mpc5200b_psc_ops = {
.set_baudrate = mpc5200b_psc_set_baudrate,
.get_irq = mpc52xx_psc_get_irq,
.handle_irq = mpc52xx_psc_handle_irq,
.get_status = mpc52xx_psc_get_status,
.get_ipcr = mpc52xx_psc_get_ipcr,
.command = mpc52xx_psc_command,
.set_mode = mpc52xx_psc_set_mode,
.set_rts = mpc52xx_psc_set_rts,
.enable_ms = mpc52xx_psc_enable_ms,
.set_sicr = mpc52xx_psc_set_sicr,
.set_imr = mpc52xx_psc_set_imr,
.get_mr1 = mpc52xx_psc_get_mr1,
};
#endif /* CONFIG_MPC52xx */
@ -572,6 +648,246 @@ static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np)
port->irqflags = IRQF_SHARED;
port->irq = psc_fifoc_irq;
}
#endif
#ifdef CONFIG_PPC_MPC512x
#define PSC_5125(port) ((struct mpc5125_psc __iomem *)((port)->membase))
#define FIFO_5125(port) ((struct mpc512x_psc_fifo __iomem *)(PSC_5125(port)+1))
static void mpc5125_psc_fifo_init(struct uart_port *port)
{
/* /32 prescaler */
out_8(&PSC_5125(port)->mpc52xx_psc_clock_select, 0xdd);
out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
out_be32(&FIFO_5125(port)->txalarm, 1);
out_be32(&FIFO_5125(port)->tximr, 0);
out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
out_be32(&FIFO_5125(port)->rxalarm, 1);
out_be32(&FIFO_5125(port)->rximr, 0);
out_be32(&FIFO_5125(port)->tximr, MPC512x_PSC_FIFO_ALARM);
out_be32(&FIFO_5125(port)->rximr, MPC512x_PSC_FIFO_ALARM);
}
static int mpc5125_psc_raw_rx_rdy(struct uart_port *port)
{
return !(in_be32(&FIFO_5125(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
}
static int mpc5125_psc_raw_tx_rdy(struct uart_port *port)
{
return !(in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_FULL);
}
static int mpc5125_psc_rx_rdy(struct uart_port *port)
{
return in_be32(&FIFO_5125(port)->rxsr) &
in_be32(&FIFO_5125(port)->rximr) & MPC512x_PSC_FIFO_ALARM;
}
static int mpc5125_psc_tx_rdy(struct uart_port *port)
{
return in_be32(&FIFO_5125(port)->txsr) &
in_be32(&FIFO_5125(port)->tximr) & MPC512x_PSC_FIFO_ALARM;
}
static int mpc5125_psc_tx_empty(struct uart_port *port)
{
return in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_EMPTY;
}
static void mpc5125_psc_stop_rx(struct uart_port *port)
{
unsigned long rx_fifo_imr;
rx_fifo_imr = in_be32(&FIFO_5125(port)->rximr);
rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
out_be32(&FIFO_5125(port)->rximr, rx_fifo_imr);
}
static void mpc5125_psc_start_tx(struct uart_port *port)
{
unsigned long tx_fifo_imr;
tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr);
tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr);
}
static void mpc5125_psc_stop_tx(struct uart_port *port)
{
unsigned long tx_fifo_imr;
tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr);
tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr);
}
static void mpc5125_psc_rx_clr_irq(struct uart_port *port)
{
out_be32(&FIFO_5125(port)->rxisr, in_be32(&FIFO_5125(port)->rxisr));
}
static void mpc5125_psc_tx_clr_irq(struct uart_port *port)
{
out_be32(&FIFO_5125(port)->txisr, in_be32(&FIFO_5125(port)->txisr));
}
static void mpc5125_psc_write_char(struct uart_port *port, unsigned char c)
{
out_8(&FIFO_5125(port)->txdata_8, c);
}
static unsigned char mpc5125_psc_read_char(struct uart_port *port)
{
return in_8(&FIFO_5125(port)->rxdata_8);
}
static void mpc5125_psc_cw_disable_ints(struct uart_port *port)
{
port->read_status_mask =
in_be32(&FIFO_5125(port)->tximr) << 16 |
in_be32(&FIFO_5125(port)->rximr);
out_be32(&FIFO_5125(port)->tximr, 0);
out_be32(&FIFO_5125(port)->rximr, 0);
}
static void mpc5125_psc_cw_restore_ints(struct uart_port *port)
{
out_be32(&FIFO_5125(port)->tximr,
(port->read_status_mask >> 16) & 0x7f);
out_be32(&FIFO_5125(port)->rximr, port->read_status_mask & 0x7f);
}
static inline void mpc5125_set_divisor(struct mpc5125_psc __iomem *psc,
u8 prescaler, unsigned int divisor)
{
/* select prescaler */
out_8(&psc->mpc52xx_psc_clock_select, prescaler);
out_8(&psc->ctur, divisor >> 8);
out_8(&psc->ctlr, divisor & 0xff);
}
static unsigned int mpc5125_psc_set_baudrate(struct uart_port *port,
struct ktermios *new,
struct ktermios *old)
{
unsigned int baud;
unsigned int divisor;
/*
* Calculate with a /16 prescaler here.
*/
/* uartclk contains the ips freq */
baud = uart_get_baud_rate(port, new, old,
port->uartclk / (16 * 0xffff) + 1,
port->uartclk / 16);
divisor = (port->uartclk + 8 * baud) / (16 * baud);
/* enable the /16 prescaler and set the divisor */
mpc5125_set_divisor(PSC_5125(port), 0xdd, divisor);
return baud;
}
/*
* MPC5125 have compatible PSC FIFO Controller.
* Special init not needed.
*/
static u16 mpc5125_psc_get_status(struct uart_port *port)
{
return in_be16(&PSC_5125(port)->mpc52xx_psc_status);
}
static u8 mpc5125_psc_get_ipcr(struct uart_port *port)
{
return in_8(&PSC_5125(port)->mpc52xx_psc_ipcr);
}
static void mpc5125_psc_command(struct uart_port *port, u8 cmd)
{
out_8(&PSC_5125(port)->command, cmd);
}
static void mpc5125_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2)
{
out_8(&PSC_5125(port)->mr1, mr1);
out_8(&PSC_5125(port)->mr2, mr2);
}
static void mpc5125_psc_set_rts(struct uart_port *port, int state)
{
if (state & TIOCM_RTS)
out_8(&PSC_5125(port)->op1, MPC52xx_PSC_OP_RTS);
else
out_8(&PSC_5125(port)->op0, MPC52xx_PSC_OP_RTS);
}
static void mpc5125_psc_enable_ms(struct uart_port *port)
{
struct mpc5125_psc __iomem *psc = PSC_5125(port);
/* clear D_*-bits by reading them */
in_8(&psc->mpc52xx_psc_ipcr);
/* enable CTS and DCD as IPC interrupts */
out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
static void mpc5125_psc_set_sicr(struct uart_port *port, u32 val)
{
out_be32(&PSC_5125(port)->sicr, val);
}
static void mpc5125_psc_set_imr(struct uart_port *port, u16 val)
{
out_be16(&PSC_5125(port)->mpc52xx_psc_imr, val);
}
static u8 mpc5125_psc_get_mr1(struct uart_port *port)
{
return in_8(&PSC_5125(port)->mr1);
}
static struct psc_ops mpc5125_psc_ops = {
.fifo_init = mpc5125_psc_fifo_init,
.raw_rx_rdy = mpc5125_psc_raw_rx_rdy,
.raw_tx_rdy = mpc5125_psc_raw_tx_rdy,
.rx_rdy = mpc5125_psc_rx_rdy,
.tx_rdy = mpc5125_psc_tx_rdy,
.tx_empty = mpc5125_psc_tx_empty,
.stop_rx = mpc5125_psc_stop_rx,
.start_tx = mpc5125_psc_start_tx,
.stop_tx = mpc5125_psc_stop_tx,
.rx_clr_irq = mpc5125_psc_rx_clr_irq,
.tx_clr_irq = mpc5125_psc_tx_clr_irq,
.write_char = mpc5125_psc_write_char,
.read_char = mpc5125_psc_read_char,
.cw_disable_ints = mpc5125_psc_cw_disable_ints,
.cw_restore_ints = mpc5125_psc_cw_restore_ints,
.set_baudrate = mpc5125_psc_set_baudrate,
.clock = mpc512x_psc_clock,
.fifoc_init = mpc512x_psc_fifoc_init,
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
.get_irq = mpc512x_psc_get_irq,
.handle_irq = mpc512x_psc_handle_irq,
.get_status = mpc5125_psc_get_status,
.get_ipcr = mpc5125_psc_get_ipcr,
.command = mpc5125_psc_command,
.set_mode = mpc5125_psc_set_mode,
.set_rts = mpc5125_psc_set_rts,
.enable_ms = mpc5125_psc_enable_ms,
.set_sicr = mpc5125_psc_set_sicr,
.set_imr = mpc5125_psc_set_imr,
.get_mr1 = mpc5125_psc_get_mr1,
};
static struct psc_ops mpc512x_psc_ops = {
.fifo_init = mpc512x_psc_fifo_init,
@ -595,8 +911,18 @@ static struct psc_ops mpc512x_psc_ops = {
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
.get_irq = mpc512x_psc_get_irq,
.handle_irq = mpc512x_psc_handle_irq,
.get_status = mpc52xx_psc_get_status,
.get_ipcr = mpc52xx_psc_get_ipcr,
.command = mpc52xx_psc_command,
.set_mode = mpc52xx_psc_set_mode,
.set_rts = mpc52xx_psc_set_rts,
.enable_ms = mpc52xx_psc_enable_ms,
.set_sicr = mpc52xx_psc_set_sicr,
.set_imr = mpc52xx_psc_set_imr,
.get_mr1 = mpc52xx_psc_get_mr1,
};
#endif
#endif /* CONFIG_PPC_MPC512x */
static const struct psc_ops *psc_ops;
@ -613,17 +939,14 @@ mpc52xx_uart_tx_empty(struct uart_port *port)
static void
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
if (mctrl & TIOCM_RTS)
out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
else
out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
psc_ops->set_rts(port, mctrl & TIOCM_RTS);
}
static unsigned int
mpc52xx_uart_get_mctrl(struct uart_port *port)
{
unsigned int ret = TIOCM_DSR;
u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
u8 status = psc_ops->get_ipcr(port);
if (!(status & MPC52xx_PSC_CTS))
ret |= TIOCM_CTS;
@ -673,15 +996,7 @@ mpc52xx_uart_stop_rx(struct uart_port *port)
static void
mpc52xx_uart_enable_ms(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
/* clear D_*-bits by reading them */
in_8(&psc->mpc52xx_psc_ipcr);
/* enable CTS and DCD as IPC interrupts */
out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
psc_ops->enable_ms(port);
}
static void
@ -691,9 +1006,9 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
spin_lock_irqsave(&port->lock, flags);
if (ctl == -1)
out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
psc_ops->command(port, MPC52xx_PSC_START_BRK);
else
out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
psc_ops->command(port, MPC52xx_PSC_STOP_BRK);
spin_unlock_irqrestore(&port->lock, flags);
}
@ -701,7 +1016,6 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
static int
mpc52xx_uart_startup(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
int ret;
if (psc_ops->clock) {
@ -717,15 +1031,15 @@ mpc52xx_uart_startup(struct uart_port *port)
return ret;
/* Reset/activate the port, clear and enable interrupts */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX);
psc_ops->command(port, MPC52xx_PSC_RST_RX);
psc_ops->command(port, MPC52xx_PSC_RST_TX);
out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
psc_ops->set_sicr(port, 0); /* UART mode DCD ignored */
psc_ops->fifo_init(port);
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
psc_ops->command(port, MPC52xx_PSC_TX_ENABLE);
psc_ops->command(port, MPC52xx_PSC_RX_ENABLE);
return 0;
}
@ -733,19 +1047,20 @@ mpc52xx_uart_startup(struct uart_port *port)
static void
mpc52xx_uart_shutdown(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
/* Shut down the port. Leave TX active if on a console port */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
psc_ops->command(port, MPC52xx_PSC_RST_RX);
if (!uart_console(port))
out_8(&psc->command, MPC52xx_PSC_RST_TX);
psc_ops->command(port, MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
psc_ops->set_imr(port, port->read_status_mask);
if (psc_ops->clock)
psc_ops->clock(port, 0);
/* Disable interrupt */
psc_ops->cw_disable_ints(port);
/* Release interrupt */
free_irq(port->irq, port);
}
@ -754,7 +1069,6 @@ static void
mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
struct ktermios *old)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
unsigned char mr1, mr2;
unsigned int j;
@ -818,13 +1132,11 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
"Some chars may have been lost.\n");
/* Reset the TX & RX */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX);
psc_ops->command(port, MPC52xx_PSC_RST_RX);
psc_ops->command(port, MPC52xx_PSC_RST_TX);
/* Send new mode settings */
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&psc->mode, mr1);
out_8(&psc->mode, mr2);
psc_ops->set_mode(port, mr1, mr2);
baud = psc_ops->set_baudrate(port, new, old);
/* Update the per-port timeout */
@ -834,8 +1146,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
mpc52xx_uart_enable_ms(port);
/* Reenable TX & RX */
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
psc_ops->command(port, MPC52xx_PSC_TX_ENABLE);
psc_ops->command(port, MPC52xx_PSC_RX_ENABLE);
/* We're all set, release the lock */
spin_unlock_irqrestore(&port->lock, flags);
@ -963,7 +1275,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
flag = TTY_NORMAL;
port->icount.rx++;
status = in_be16(&PSC(port)->mpc52xx_psc_status);
status = psc_ops->get_status(port);
if (status & (MPC52xx_PSC_SR_PE |
MPC52xx_PSC_SR_FE |
@ -983,7 +1295,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
}
/* Clear error condition */
out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
psc_ops->command(port, MPC52xx_PSC_RST_ERR_STAT);
}
tty_insert_flip_char(tport, ch, flag);
@ -1066,7 +1378,7 @@ mpc5xxx_uart_process_int(struct uart_port *port)
if (psc_ops->tx_rdy(port))
keepgoing |= mpc52xx_uart_int_tx_chars(port);
status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
status = psc_ops->get_ipcr(port);
if (status & MPC52xx_PSC_D_DCD)
uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
@ -1107,14 +1419,12 @@ static void __init
mpc52xx_console_get_options(struct uart_port *port,
int *baud, int *parity, int *bits, int *flow)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned char mr1;
pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
/* Read the mode registers */
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
mr1 = in_8(&psc->mode);
mr1 = psc_ops->get_mr1(port);
/* CT{U,L}R are write-only ! */
*baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
@ -1304,6 +1614,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
#endif
#ifdef CONFIG_PPC_MPC512x
{ .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
{ .compatible = "fsl,mpc5125-psc-uart", .data = &mpc5125_psc_ops, },
#endif
{},
};
@ -1372,15 +1683,14 @@ static int mpc52xx_uart_of_probe(struct platform_device *op)
if (ret)
return ret;
dev_set_drvdata(&op->dev, (void *)port);
platform_set_drvdata(op, (void *)port);
return 0;
}
static int
mpc52xx_uart_of_remove(struct platform_device *op)
{
struct uart_port *port = dev_get_drvdata(&op->dev);
dev_set_drvdata(&op->dev, NULL);
struct uart_port *port = platform_get_drvdata(op);
if (port)
uart_remove_one_port(&mpc52xx_uart_driver, port);
@ -1392,7 +1702,7 @@ mpc52xx_uart_of_remove(struct platform_device *op)
static int
mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
{
struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
struct uart_port *port = (struct uart_port *) platform_get_drvdata(op);
if (port)
uart_suspend_port(&mpc52xx_uart_driver, port);
@ -1403,7 +1713,7 @@ mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
static int
mpc52xx_uart_of_resume(struct platform_device *op)
{
struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
struct uart_port *port = (struct uart_port *) platform_get_drvdata(op);
if (port)
uart_resume_port(&mpc52xx_uart_driver, port);

View File

@ -204,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
info->type = port_type;
info->line = ret;
dev_set_drvdata(&ofdev->dev, info);
platform_set_drvdata(ofdev, info);
return 0;
out:
kfree(info);
@ -217,7 +217,7 @@ out:
*/
static int of_platform_serial_remove(struct platform_device *ofdev)
{
struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
struct of_serial_info *info = platform_get_drvdata(ofdev);
switch (info->type) {
#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:

View File

@ -161,6 +161,7 @@ struct uart_omap_port {
u32 calc_latency;
struct work_struct qos_work;
struct pinctrl *pins;
bool is_suspending;
};
#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port)))
@ -197,7 +198,7 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
struct omap_uart_port_info *pdata = up->dev->platform_data;
if (!pdata || !pdata->get_context_loss_count)
return 0;
return -EINVAL;
return pdata->get_context_loss_count(up->dev);
}
@ -1289,6 +1290,22 @@ static struct uart_driver serial_omap_reg = {
};
#ifdef CONFIG_PM_SLEEP
static int serial_omap_prepare(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
up->is_suspending = true;
return 0;
}
static void serial_omap_complete(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
up->is_suspending = false;
}
static int serial_omap_suspend(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
@ -1307,7 +1324,10 @@ static int serial_omap_resume(struct device *dev)
return 0;
}
#endif
#else
#define serial_omap_prepare NULL
#define serial_omap_complete NULL
#endif /* CONFIG_PM_SLEEP */
static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
@ -1482,6 +1502,9 @@ static int serial_omap_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, up);
pm_runtime_enable(&pdev->dev);
if (omap_up_info->autosuspend_timeout == 0)
omap_up_info->autosuspend_timeout = -1;
device_init_wakeup(up->dev, true);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
omap_up_info->autosuspend_timeout);
@ -1591,13 +1614,19 @@ static void serial_omap_restore_context(struct uart_omap_port *up)
static int serial_omap_runtime_suspend(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
struct omap_uart_port_info *pdata = dev->platform_data;
if (!up)
return -EINVAL;
if (!pdata)
return 0;
/*
* When using 'no_console_suspend', the console UART must not be
* suspended. Since driver suspend is managed by runtime suspend,
* preventing runtime suspend (by returning error) will keep device
* active during suspend.
*/
if (up->is_suspending && !console_suspend_enabled &&
uart_console(&up->port))
return -EBUSY;
up->context_loss_cnt = serial_omap_get_context_loss_count(up);
@ -1626,7 +1655,7 @@ static int serial_omap_runtime_resume(struct device *dev)
int loss_cnt = serial_omap_get_context_loss_count(up);
if (loss_cnt < 0) {
dev_err(dev, "serial_omap_get_context_loss_count failed : %d\n",
dev_dbg(dev, "serial_omap_get_context_loss_count failed : %d\n",
loss_cnt);
serial_omap_restore_context(up);
} else if (up->context_loss_cnt != loss_cnt) {
@ -1643,6 +1672,8 @@ static const struct dev_pm_ops serial_omap_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume)
SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend,
serial_omap_runtime_resume, NULL)
.prepare = serial_omap_prepare,
.complete = serial_omap_complete,
};
#if defined(CONFIG_OF)

View File

@ -217,6 +217,7 @@ enum {
#define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */
#define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */
#define NTC1_UARTCLK 64000000 /* 64.0000 MHz */
#define MINNOW_UARTCLK 50000000 /* 50.0000 MHz */
struct pch_uart_buffer {
unsigned char *buf;
@ -398,6 +399,10 @@ static int pch_uart_get_uartclk(void)
strstr(cmp, "nanoETXexpress-TT")))
return NTC1_UARTCLK;
cmp = dmi_get_system_info(DMI_BOARD_NAME);
if (cmp && strstr(cmp, "MinnowBoard"))
return MINNOW_UARTCLK;
return DEFAULT_UARTCLK;
}

View File

@ -1811,7 +1811,13 @@ static int __init s3c24xx_serial_modinit(void)
return ret;
}
return platform_driver_register(&samsung_serial_driver);
ret = platform_driver_register(&samsung_serial_driver);
if (ret < 0) {
pr_err("Failed to register platform driver\n");
uart_unregister_driver(&s3c24xx_uart_drv);
}
return ret;
}
static void __exit s3c24xx_serial_modexit(void)

View File

@ -696,7 +696,7 @@ static int sc26xx_probe(struct platform_device *dev)
if (err)
goto out_remove_ports;
dev_set_drvdata(&dev->dev, up);
platform_set_drvdata(dev, up);
return 0;
out_remove_ports:
@ -716,7 +716,7 @@ out_free_port:
static int __exit sc26xx_driver_remove(struct platform_device *dev)
{
struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev);
struct uart_sc26xx_port *up = platform_get_drvdata(dev);
free_irq(up->port[0].irq, up);
@ -728,7 +728,6 @@ static int __exit sc26xx_driver_remove(struct platform_device *dev)
kfree(up);
sc26xx_port = NULL;
dev_set_drvdata(&dev->dev, NULL);
return 0;
}

View File

@ -50,12 +50,6 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
#else
#define uart_console(port) (0)
#endif
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);

View File

@ -687,9 +687,10 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
if (sirfport->hw_flow_ctrl) {
sirfport->p = pinctrl_get_select_default(&pdev->dev);
ret = IS_ERR(sirfport->p);
if (ret)
if (IS_ERR(sirfport->p)) {
ret = PTR_ERR(sirfport->p);
goto err;
}
}
sirfport->clk = clk_get(&pdev->dev, NULL);

View File

@ -577,7 +577,7 @@ static int hv_probe(struct platform_device *op)
if (err)
goto out_remove_port;
dev_set_drvdata(&op->dev, port);
platform_set_drvdata(op, port);
return 0;
@ -601,7 +601,7 @@ out_free_port:
static int hv_remove(struct platform_device *dev)
{
struct uart_port *port = dev_get_drvdata(&dev->dev);
struct uart_port *port = platform_get_drvdata(dev);
free_irq(port->irq, port);
@ -612,8 +612,6 @@ static int hv_remove(struct platform_device *dev)
kfree(port);
sunhv_port = NULL;
dev_set_drvdata(&dev->dev, NULL);
return 0;
}

View File

@ -1037,7 +1037,7 @@ static int sab_probe(struct platform_device *op)
if (err)
goto out3;
dev_set_drvdata(&op->dev, &up[0]);
platform_set_drvdata(op, &up[0]);
inst++;
@ -1059,7 +1059,7 @@ out:
static int sab_remove(struct platform_device *op)
{
struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
struct uart_sunsab_port *up = platform_get_drvdata(op);
uart_remove_one_port(&sunsab_reg, &up[1].port);
uart_remove_one_port(&sunsab_reg, &up[0].port);
@ -1070,8 +1070,6 @@ static int sab_remove(struct platform_device *op)
up[0].port.membase,
sizeof(union sab82532_async_regs));
dev_set_drvdata(&op->dev, NULL);
return 0;
}

View File

@ -1454,7 +1454,7 @@ static int su_probe(struct platform_device *op)
kfree(up);
return err;
}
dev_set_drvdata(&op->dev, up);
platform_set_drvdata(op, up);
nr_inst++;
@ -1483,7 +1483,7 @@ static int su_probe(struct platform_device *op)
if (err)
goto out_unmap;
dev_set_drvdata(&op->dev, up);
platform_set_drvdata(op, up);
nr_inst++;
@ -1496,7 +1496,7 @@ out_unmap:
static int su_remove(struct platform_device *op)
{
struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
struct uart_sunsu_port *up = platform_get_drvdata(op);
bool kbdms = false;
if (up->su_type == SU_PORT_MS ||
@ -1516,8 +1516,6 @@ static int su_remove(struct platform_device *op)
if (kbdms)
kfree(up);
dev_set_drvdata(&op->dev, NULL);
return 0;
}

View File

@ -1495,7 +1495,7 @@ static int zs_probe(struct platform_device *op)
kbm_inst++;
}
dev_set_drvdata(&op->dev, &up[0]);
platform_set_drvdata(op, &up[0]);
return 0;
}
@ -1512,7 +1512,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up)
static int zs_remove(struct platform_device *op)
{
struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
struct uart_sunzilog_port *up = platform_get_drvdata(op);
struct zilog_layout __iomem *regs;
zs_remove_one(&up[0]);
@ -1521,8 +1521,6 @@ static int zs_remove(struct platform_device *op)
regs = sunzilog_chip_regs[up[0].port.line / 2];
of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
dev_set_drvdata(&op->dev, NULL);
return 0;
}

View File

@ -1451,7 +1451,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
goto out_np;
}
dev_set_drvdata(&ofdev->dev, qe_port);
platform_set_drvdata(ofdev, qe_port);
dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n",
qe_port->ucc_num + 1, qe_port->port.line);
@ -1471,13 +1471,12 @@ out_free:
static int ucc_uart_remove(struct platform_device *ofdev)
{
struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
struct uart_qe_port *qe_port = platform_get_drvdata(ofdev);
dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line);
uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
dev_set_drvdata(&ofdev->dev, NULL);
kfree(qe_port);
return 0;
@ -1518,9 +1517,11 @@ static int __init ucc_uart_init(void)
}
ret = platform_driver_register(&ucc_uart_of_driver);
if (ret)
if (ret) {
printk(KERN_ERR
"ucc-uart: could not register platform driver\n");
uart_unregister_driver(&ucc_uart_driver);
}
return ret;
}

View File

@ -648,7 +648,7 @@ static struct platform_driver vt8500_platform_driver = {
.driver = {
.name = "vt8500_serial",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(wmt_dt_ids),
.of_match_table = wmt_dt_ids,
},
};

View File

@ -974,12 +974,11 @@ static int xuartps_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
port->uartclk = clk_get_rate(clk);
port->private_data = clk;
dev_set_drvdata(&pdev->dev, port);
platform_set_drvdata(pdev, port);
rc = uart_add_one_port(&xuartps_uart_driver, port);
if (rc) {
dev_err(&pdev->dev,
"uart_add_one_port() failed; err=%i\n", rc);
dev_set_drvdata(&pdev->dev, NULL);
return rc;
}
return 0;
@ -994,46 +993,17 @@ static int xuartps_probe(struct platform_device *pdev)
**/
static int xuartps_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uart_port *port = platform_get_drvdata(pdev);
struct clk *clk = port->private_data;
int rc;
/* Remove the xuartps port from the serial core */
rc = uart_remove_one_port(&xuartps_uart_driver, port);
dev_set_drvdata(&pdev->dev, NULL);
port->mapbase = 0;
clk_disable_unprepare(clk);
return rc;
}
/**
* xuartps_suspend - suspend event
* @pdev: Pointer to the platform device structure
* @state: State of the device
*
* Returns 0
**/
static int xuartps_suspend(struct platform_device *pdev, pm_message_t state)
{
/* Call the API provided in serial_core.c file which handles
* the suspend.
*/
uart_suspend_port(&xuartps_uart_driver, &xuartps_port[pdev->id]);
return 0;
}
/**
* xuartps_resume - Resume after a previous suspend
* @pdev: Pointer to the platform device structure
*
* Returns 0
**/
static int xuartps_resume(struct platform_device *pdev)
{
uart_resume_port(&xuartps_uart_driver, &xuartps_port[pdev->id]);
return 0;
}
/* Match table for of_platform binding */
static struct of_device_id xuartps_of_match[] = {
{ .compatible = "xlnx,xuartps", },
@ -1044,8 +1014,6 @@ MODULE_DEVICE_TABLE(of, xuartps_of_match);
static struct platform_driver xuartps_platform_driver = {
.probe = xuartps_probe, /* Probe method */
.remove = xuartps_remove, /* Detach method */
.suspend = xuartps_suspend, /* Suspend */
.resume = xuartps_resume, /* Resume after a suspend */
.driver = {
.owner = THIS_MODULE,
.name = XUARTPS_NAME, /* Driver name */

View File

@ -932,7 +932,7 @@ static int sysrq_reset_seq_param_set(const char *buffer,
unsigned long val;
int error;
error = strict_strtoul(buffer, 0, &val);
error = kstrtoul(buffer, 0, &val);
if (error < 0)
return error;

View File

@ -1618,6 +1618,8 @@ static void release_tty(struct tty_struct *tty, int idx)
tty_free_termios(tty);
tty_driver_remove_tty(tty->driver, tty);
tty->port->itty = NULL;
if (tty->link)
tty->link->port->itty = NULL;
cancel_work_sync(&tty->port->buf.work);
if (tty->link)
@ -2138,6 +2140,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
static int __tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty = file_tty(filp);
struct tty_ldisc *ldisc;
unsigned long flags;
int retval = 0;
@ -2148,11 +2151,17 @@ static int __tty_fasync(int fd, struct file *filp, int on)
if (retval <= 0)
goto out;
ldisc = tty_ldisc_ref(tty);
if (ldisc) {
if (ldisc->ops->fasync)
ldisc->ops->fasync(tty, on);
tty_ldisc_deref(ldisc);
}
if (on) {
enum pid_type type;
struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp) {
pid = tty->pgrp;
@ -2165,13 +2174,7 @@ static int __tty_fasync(int fd, struct file *filp, int on)
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0);
put_pid(pid);
if (retval)
goto out;
} else {
if (!tty->fasync && !waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = N_TTY_BUF_SIZE;
}
retval = 0;
out:
return retval;
}

453
drivers/tty/tty_ldsem.c Normal file
View File

@ -0,0 +1,453 @@
/*
* Ldisc rw semaphore
*
* The ldisc semaphore is semantically a rw_semaphore but which enforces
* an alternate policy, namely:
* 1) Supports lock wait timeouts
* 2) Write waiter has priority
* 3) Downgrading is not supported
*
* Implementation notes:
* 1) Upper half of semaphore count is a wait count (differs from rwsem
* in that rwsem normalizes the upper half to the wait bias)
* 2) Lacks overflow checking
*
* The generic counting was copied and modified from include/asm-generic/rwsem.h
* by Paul Mackerras <paulus@samba.org>.
*
* The scheduling policy was copied and modified from lib/rwsem.c
* Written by David Howells (dhowells@redhat.com).
*
* This implementation incorporates the write lock stealing work of
* Michel Lespinasse <walken@google.com>.
*
* Copyright (C) 2013 Peter Hurley <peter@hurleysoftware.com>
*
* This file may be redistributed under the terms of the GNU General Public
* License v2.
*/
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
#include <linux/tty.h>
#include <linux/sched.h>
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define __acq(l, s, t, r, c, n, i) \
lock_acquire(&(l)->dep_map, s, t, r, c, n, i)
# define __rel(l, n, i) \
lock_release(&(l)->dep_map, n, i)
# ifdef CONFIG_PROVE_LOCKING
# define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 2, NULL, i)
# define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 2, n, i)
# define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 2, NULL, i)
# define lockdep_release(l, n, i) __rel(l, n, i)
# else
# define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i)
# define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i)
# define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i)
# define lockdep_release(l, n, i) __rel(l, n, i)
# endif
#else
# define lockdep_acquire(l, s, t, i) do { } while (0)
# define lockdep_acquire_nest(l, s, t, n, i) do { } while (0)
# define lockdep_acquire_read(l, s, t, i) do { } while (0)
# define lockdep_release(l, n, i) do { } while (0)
#endif
#ifdef CONFIG_LOCK_STAT
# define lock_stat(_lock, stat) lock_##stat(&(_lock)->dep_map, _RET_IP_)
#else
# define lock_stat(_lock, stat) do { } while (0)
#endif
#if BITS_PER_LONG == 64
# define LDSEM_ACTIVE_MASK 0xffffffffL
#else
# define LDSEM_ACTIVE_MASK 0x0000ffffL
#endif
#define LDSEM_UNLOCKED 0L
#define LDSEM_ACTIVE_BIAS 1L
#define LDSEM_WAIT_BIAS (-LDSEM_ACTIVE_MASK-1)
#define LDSEM_READ_BIAS LDSEM_ACTIVE_BIAS
#define LDSEM_WRITE_BIAS (LDSEM_WAIT_BIAS + LDSEM_ACTIVE_BIAS)
struct ldsem_waiter {
struct list_head list;
struct task_struct *task;
};
static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem)
{
return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
}
static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem)
{
long tmp = *old;
*old = atomic_long_cmpxchg(&sem->count, *old, new);
return *old == tmp;
}
/*
* Initialize an ldsem:
*/
void __init_ldsem(struct ld_semaphore *sem, const char *name,
struct lock_class_key *key)
{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
/*
* Make sure we are not reinitializing a held semaphore:
*/
debug_check_no_locks_freed((void *)sem, sizeof(*sem));
lockdep_init_map(&sem->dep_map, name, key, 0);
#endif
sem->count = LDSEM_UNLOCKED;
sem->wait_readers = 0;
raw_spin_lock_init(&sem->wait_lock);
INIT_LIST_HEAD(&sem->read_wait);
INIT_LIST_HEAD(&sem->write_wait);
}
static void __ldsem_wake_readers(struct ld_semaphore *sem)
{
struct ldsem_waiter *waiter, *next;
struct task_struct *tsk;
long adjust, count;
/* Try to grant read locks to all readers on the read wait list.
* Note the 'active part' of the count is incremented by
* the number of readers before waking any processes up.
*/
adjust = sem->wait_readers * (LDSEM_ACTIVE_BIAS - LDSEM_WAIT_BIAS);
count = ldsem_atomic_update(adjust, sem);
do {
if (count > 0)
break;
if (ldsem_cmpxchg(&count, count - adjust, sem))
return;
} while (1);
list_for_each_entry_safe(waiter, next, &sem->read_wait, list) {
tsk = waiter->task;
smp_mb();
waiter->task = NULL;
wake_up_process(tsk);
put_task_struct(tsk);
}
INIT_LIST_HEAD(&sem->read_wait);
sem->wait_readers = 0;
}
static inline int writer_trylock(struct ld_semaphore *sem)
{
/* only wake this writer if the active part of the count can be
* transitioned from 0 -> 1
*/
long count = ldsem_atomic_update(LDSEM_ACTIVE_BIAS, sem);
do {
if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS)
return 1;
if (ldsem_cmpxchg(&count, count - LDSEM_ACTIVE_BIAS, sem))
return 0;
} while (1);
}
static void __ldsem_wake_writer(struct ld_semaphore *sem)
{
struct ldsem_waiter *waiter;
waiter = list_entry(sem->write_wait.next, struct ldsem_waiter, list);
wake_up_process(waiter->task);
}
/*
* handle the lock release when processes blocked on it that can now run
* - if we come here from up_xxxx(), then:
* - the 'active part' of count (&0x0000ffff) reached 0 (but may have changed)
* - the 'waiting part' of count (&0xffff0000) is -ve (and will still be so)
* - the spinlock must be held by the caller
* - woken process blocks are discarded from the list after having task zeroed
*/
static void __ldsem_wake(struct ld_semaphore *sem)
{
if (!list_empty(&sem->write_wait))
__ldsem_wake_writer(sem);
else if (!list_empty(&sem->read_wait))
__ldsem_wake_readers(sem);
}
static void ldsem_wake(struct ld_semaphore *sem)
{
unsigned long flags;
raw_spin_lock_irqsave(&sem->wait_lock, flags);
__ldsem_wake(sem);
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
}
/*
* wait for the read lock to be granted
*/
static struct ld_semaphore __sched *
down_read_failed(struct ld_semaphore *sem, long count, long timeout)
{
struct ldsem_waiter waiter;
struct task_struct *tsk = current;
long adjust = -LDSEM_ACTIVE_BIAS + LDSEM_WAIT_BIAS;
/* set up my own style of waitqueue */
raw_spin_lock_irq(&sem->wait_lock);
/* Try to reverse the lock attempt but if the count has changed
* so that reversing fails, check if there are are no waiters,
* and early-out if not */
do {
if (ldsem_cmpxchg(&count, count + adjust, sem))
break;
if (count > 0) {
raw_spin_unlock_irq(&sem->wait_lock);
return sem;
}
} while (1);
list_add_tail(&waiter.list, &sem->read_wait);
sem->wait_readers++;
waiter.task = tsk;
get_task_struct(tsk);
/* if there are no active locks, wake the new lock owner(s) */
if ((count & LDSEM_ACTIVE_MASK) == 0)
__ldsem_wake(sem);
raw_spin_unlock_irq(&sem->wait_lock);
/* wait to be given the lock */
for (;;) {
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!waiter.task)
break;
if (!timeout)
break;
timeout = schedule_timeout(timeout);
}
__set_task_state(tsk, TASK_RUNNING);
if (!timeout) {
/* lock timed out but check if this task was just
* granted lock ownership - if so, pretend there
* was no timeout; otherwise, cleanup lock wait */
raw_spin_lock_irq(&sem->wait_lock);
if (waiter.task) {
ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem);
list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock);
put_task_struct(waiter.task);
return NULL;
}
raw_spin_unlock_irq(&sem->wait_lock);
}
return sem;
}
/*
* wait for the write lock to be granted
*/
static struct ld_semaphore __sched *
down_write_failed(struct ld_semaphore *sem, long count, long timeout)
{
struct ldsem_waiter waiter;
struct task_struct *tsk = current;
long adjust = -LDSEM_ACTIVE_BIAS;
int locked = 0;
/* set up my own style of waitqueue */
raw_spin_lock_irq(&sem->wait_lock);
/* Try to reverse the lock attempt but if the count has changed
* so that reversing fails, check if the lock is now owned,
* and early-out if so */
do {
if (ldsem_cmpxchg(&count, count + adjust, sem))
break;
if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) {
raw_spin_unlock_irq(&sem->wait_lock);
return sem;
}
} while (1);
list_add_tail(&waiter.list, &sem->write_wait);
waiter.task = tsk;
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
for (;;) {
if (!timeout)
break;
raw_spin_unlock_irq(&sem->wait_lock);
timeout = schedule_timeout(timeout);
raw_spin_lock_irq(&sem->wait_lock);
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if ((locked = writer_trylock(sem)))
break;
}
if (!locked)
ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem);
list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock);
__set_task_state(tsk, TASK_RUNNING);
/* lock wait may have timed out */
if (!locked)
return NULL;
return sem;
}
static inline int __ldsem_down_read_nested(struct ld_semaphore *sem,
int subclass, long timeout)
{
long count;
lockdep_acquire_read(sem, subclass, 0, _RET_IP_);
count = ldsem_atomic_update(LDSEM_READ_BIAS, sem);
if (count <= 0) {
lock_stat(sem, contended);
if (!down_read_failed(sem, count, timeout)) {
lockdep_release(sem, 1, _RET_IP_);
return 0;
}
}
lock_stat(sem, acquired);
return 1;
}
static inline int __ldsem_down_write_nested(struct ld_semaphore *sem,
int subclass, long timeout)
{
long count;
lockdep_acquire(sem, subclass, 0, _RET_IP_);
count = ldsem_atomic_update(LDSEM_WRITE_BIAS, sem);
if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
lock_stat(sem, contended);
if (!down_write_failed(sem, count, timeout)) {
lockdep_release(sem, 1, _RET_IP_);
return 0;
}
}
lock_stat(sem, acquired);
return 1;
}
/*
* lock for reading -- returns 1 if successful, 0 if timed out
*/
int __sched ldsem_down_read(struct ld_semaphore *sem, long timeout)
{
might_sleep();
return __ldsem_down_read_nested(sem, 0, timeout);
}
/*
* trylock for reading -- returns 1 if successful, 0 if contention
*/
int ldsem_down_read_trylock(struct ld_semaphore *sem)
{
long count = sem->count;
while (count >= 0) {
if (ldsem_cmpxchg(&count, count + LDSEM_READ_BIAS, sem)) {
lockdep_acquire_read(sem, 0, 1, _RET_IP_);
lock_stat(sem, acquired);
return 1;
}
}
return 0;
}
/*
* lock for writing -- returns 1 if successful, 0 if timed out
*/
int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout)
{
might_sleep();
return __ldsem_down_write_nested(sem, 0, timeout);
}
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
int ldsem_down_write_trylock(struct ld_semaphore *sem)
{
long count = sem->count;
while ((count & LDSEM_ACTIVE_MASK) == 0) {
if (ldsem_cmpxchg(&count, count + LDSEM_WRITE_BIAS, sem)) {
lockdep_acquire(sem, 0, 1, _RET_IP_);
lock_stat(sem, acquired);
return 1;
}
}
return 0;
}
/*
* release a read lock
*/
void ldsem_up_read(struct ld_semaphore *sem)
{
long count;
lockdep_release(sem, 1, _RET_IP_);
count = ldsem_atomic_update(-LDSEM_READ_BIAS, sem);
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
ldsem_wake(sem);
}
/*
* release a write lock
*/
void ldsem_up_write(struct ld_semaphore *sem)
{
long count;
lockdep_release(sem, 1, _RET_IP_);
count = ldsem_atomic_update(-LDSEM_WRITE_BIAS, sem);
if (count < 0)
ldsem_wake(sem);
}
#ifdef CONFIG_DEBUG_LOCK_ALLOC
int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, long timeout)
{
might_sleep();
return __ldsem_down_read_nested(sem, subclass, timeout);
}
int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
long timeout)
{
might_sleep();
return __ldsem_down_write_nested(sem, subclass, timeout);
}
#endif

View File

@ -3086,17 +3086,6 @@ err:
};
static int bind_con_driver(const struct consw *csw, int first, int last,
int deflt)
{
int ret;
console_lock();
ret = do_bind_con_driver(csw, first, last, deflt);
console_unlock();
return ret;
}
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
static int con_is_graphics(const struct consw *csw, int first, int last)
{
@ -3114,34 +3103,6 @@ static int con_is_graphics(const struct consw *csw, int first, int last)
return retval;
}
/**
* unbind_con_driver - unbind a console driver
* @csw: pointer to console driver to unregister
* @first: first in range of consoles that @csw should be unbound from
* @last: last in range of consoles that @csw should be unbound from
* @deflt: should next bound console driver be default after @csw is unbound?
*
* To unbind a driver from all possible consoles, pass 0 as @first and
* %MAX_NR_CONSOLES as @last.
*
* @deflt controls whether the console that ends up replacing @csw should be
* the default console.
*
* RETURNS:
* -ENODEV if @csw isn't a registered console driver or can't be unregistered
* or 0 on success.
*/
int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
int retval;
console_lock();
retval = do_unbind_con_driver(csw, first, last, deflt);
console_unlock();
return retval;
}
EXPORT_SYMBOL(unbind_con_driver);
/* unlocked version of unbind_con_driver() */
int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
@ -3262,8 +3223,11 @@ static int vt_bind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
if (first != -1)
bind_con_driver(csw, first, last, deflt);
if (first != -1) {
console_lock();
do_bind_con_driver(csw, first, last, deflt);
console_unlock();
}
first = -1;
last = -1;
@ -3301,8 +3265,11 @@ static int vt_unbind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
if (first != -1)
unbind_con_driver(csw, first, last, deflt);
if (first != -1) {
console_lock();
do_unbind_con_driver(csw, first, last, deflt);
console_unlock();
}
first = -1;
last = -1;
@ -3574,29 +3541,9 @@ err:
return retval;
}
/**
* register_con_driver - register console driver to console layer
* @csw: console driver
* @first: the first console to take over, minimum value is 0
* @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
*
* DESCRIPTION: This function registers a console driver which can later
* bind to a range of consoles specified by @first and @last. It will
* also initialize the console driver by calling con_startup().
*/
int register_con_driver(const struct consw *csw, int first, int last)
{
int retval;
console_lock();
retval = do_register_con_driver(csw, first, last);
console_unlock();
return retval;
}
EXPORT_SYMBOL(register_con_driver);
/**
* unregister_con_driver - unregister console driver from console layer
* do_unregister_con_driver - unregister console driver from console layer
* @csw: console driver
*
* DESCRIPTION: All drivers that registers to the console layer must
@ -3606,17 +3553,6 @@ EXPORT_SYMBOL(register_con_driver);
*
* The driver must unbind first prior to unregistration.
*/
int unregister_con_driver(const struct consw *csw)
{
int retval;
console_lock();
retval = do_unregister_con_driver(csw);
console_unlock();
return retval;
}
EXPORT_SYMBOL(unregister_con_driver);
int do_unregister_con_driver(const struct consw *csw)
{
int i, retval = -ENODEV;
@ -3654,7 +3590,7 @@ EXPORT_SYMBOL_GPL(do_unregister_con_driver);
* when a driver wants to take over some existing consoles
* and become default driver for newly opened ones.
*
* take_over_console is basically a register followed by unbind
* do_take_over_console is basically a register followed by unbind
*/
int do_take_over_console(const struct consw *csw, int first, int last, int deflt)
{
@ -3675,30 +3611,6 @@ int do_take_over_console(const struct consw *csw, int first, int last, int deflt
}
EXPORT_SYMBOL_GPL(do_take_over_console);
/*
* If we support more console drivers, this function is used
* when a driver wants to take over some existing consoles
* and become default driver for newly opened ones.
*
* take_over_console is basically a register followed by unbind
*/
int take_over_console(const struct consw *csw, int first, int last, int deflt)
{
int err;
err = register_con_driver(csw, first, last);
/*
* If we get an busy error we still want to bind the console driver
* and return success, as we may have unbound the console driver
* but not unregistered it.
*/
if (err == -EBUSY)
err = 0;
if (!err)
bind_con_driver(csw, first, last, deflt);
return err;
}
/*
* give_up_console is a wrapper to unregister_con_driver. It will only
@ -3706,7 +3618,9 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
*/
void give_up_console(const struct consw *csw)
{
unregister_con_driver(csw);
console_lock();
do_unregister_con_driver(csw);
console_unlock();
}
static int __init vtconsole_class_init(void)
@ -4262,6 +4176,5 @@ EXPORT_SYMBOL(console_blanked);
EXPORT_SYMBOL(vc_cons);
EXPORT_SYMBOL(global_cursor_default);
#ifndef VT_SINGLE_DRIVER
EXPORT_SYMBOL(take_over_console);
EXPORT_SYMBOL(give_up_console);
#endif

View File

@ -208,7 +208,7 @@ sisusbcon_init(struct vc_data *c, int init)
struct sisusb_usb_data *sisusb;
int cols, rows;
/* This is called by take_over_console(),
/* This is called by do_take_over_console(),
* ie by us/under our control. It is
* only called after text mode and fonts
* are set up/restored.
@ -273,7 +273,7 @@ sisusbcon_deinit(struct vc_data *c)
struct sisusb_usb_data *sisusb;
int i;
/* This is called by take_over_console()
/* This is called by do_take_over_console()
* and others, ie not under our control.
*/
@ -1490,8 +1490,9 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
mutex_unlock(&sisusb->lock);
/* Now grab the desired console(s) */
ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
console_lock();
ret = do_take_over_console(&sisusb_con, first - 1, last - 1, 0);
console_unlock();
if (!ret)
sisusb->haveconsole = 1;
else {
@ -1535,11 +1536,14 @@ sisusb_console_exit(struct sisusb_usb_data *sisusb)
if (sisusb->haveconsole) {
for (i = 0; i < MAX_NR_CONSOLES; i++)
if (sisusb->havethisconsole[i])
take_over_console(&sisusb_dummy_con, i, i, 0);
if (sisusb->havethisconsole[i]) {
console_lock();
do_take_over_console(&sisusb_dummy_con, i, i, 0);
console_unlock();
/* At this point, con_deinit for all our
* consoles is executed by take_over_console().
* consoles is executed by do_take_over_console().
*/
}
sisusb->haveconsole = 0;
}

View File

@ -556,34 +556,6 @@ static int do_fbcon_takeover(int show_logo)
return err;
}
static int fbcon_takeover(int show_logo)
{
int err, i;
if (!num_registered_fb)
return -ENODEV;
if (!show_logo)
logo_shown = FBCON_LOGO_DONTSHOW;
for (i = first_fb_vc; i <= last_fb_vc; i++)
con2fb_map[i] = info_idx;
err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
fbcon_is_default);
if (err) {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
con2fb_map[i] = -1;
}
info_idx = -1;
} else {
fbcon_has_console_bind = 1;
}
return err;
}
#ifdef MODULE
static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
int cols, int rows, int new_cols, int new_rows)
@ -901,7 +873,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
/*
* Low Level Operations
*/
/* NOTE: fbcon cannot be __init: it may be called from take_over_console later */
/* NOTE: fbcon cannot be __init: it may be called from do_take_over_console later */
static int var_to_display(struct display *disp,
struct fb_var_screeninfo *var,
struct fb_info *info)
@ -3543,8 +3515,9 @@ static void fbcon_start(void)
}
}
do_fbcon_takeover(0);
console_unlock();
fbcon_takeover(0);
}
}
@ -3648,8 +3621,8 @@ static void __exit fb_console_exit(void)
fbcon_deinit_device();
device_destroy(fb_class, MKDEV(0, 0));
fbcon_exit();
do_unregister_con_driver(&fb_con);
console_unlock();
unregister_con_driver(&fb_con);
}
module_exit(fb_console_exit);

View File

@ -585,10 +585,14 @@ static const struct consw mda_con = {
int __init mda_console_init(void)
{
int err;
if (mda_first_vc > mda_last_vc)
return 1;
return take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
console_lock();
err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
console_unlock();
return err;
}
static void __exit mda_console_exit(void)

View File

@ -297,7 +297,7 @@ static void newport_exit(void)
newport_set_def_font(i, NULL);
}
/* Can't be __init, take_over_console may call it later */
/* Can't be __init, do_take_over_console may call it later */
static const char *newport_startup(void)
{
int i;
@ -746,6 +746,7 @@ static int newport_probe(struct gio_device *dev,
const struct gio_device_id *id)
{
unsigned long newport_addr;
int err;
if (!dev->resource.start)
return -EINVAL;
@ -759,8 +760,10 @@ static int newport_probe(struct gio_device *dev,
npregs = (struct newport_regs *)/* ioremap cannot fail */
ioremap(newport_addr, sizeof(struct newport_regs));
return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
console_lock();
err = do_take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
console_unlock();
return err;
}
static void newport_remove(struct gio_device *dev)

View File

@ -372,6 +372,7 @@ static const struct consw sti_con = {
static int __init sticonsole_init(void)
{
int err;
/* already initialized ? */
if (sticon_sti)
return 0;
@ -382,7 +383,10 @@ static int __init sticonsole_init(void)
if (conswitchp == &dummy_con) {
printk(KERN_INFO "sticon: Initializing STI text console.\n");
return take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
console_lock();
err = do_take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
console_unlock();
return err;
}
return 0;
}

View File

@ -75,10 +75,7 @@ extern const struct consw newport_con; /* SGI Newport console */
extern const struct consw prom_con; /* SPARC PROM console */
int con_is_bound(const struct consw *csw);
int register_con_driver(const struct consw *csw, int first, int last);
int unregister_con_driver(const struct consw *csw);
int do_unregister_con_driver(const struct consw *csw);
int take_over_console(const struct consw *sw, int first, int last, int deflt);
int do_take_over_console(const struct consw *sw, int first, int last, int deflt);
void give_up_console(const struct consw *sw);
#ifdef CONFIG_HW_CONSOLE

View File

@ -31,6 +31,13 @@
#include <linux/sysrq.h>
#include <uapi/linux/serial_core.h>
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) \
((port)->cons && (port)->cons->index == (port)->line)
#else
#define uart_console(port) (0)
#endif
struct uart_port;
struct serial_struct;
struct device;

View File

@ -272,7 +272,6 @@ struct tty_struct {
#define N_TTY_BUF_SIZE 4096
unsigned char closing:1;
unsigned short minimum_to_wake;
unsigned char *write_buf;
int write_cnt;
/* If the tty has a pending do_SAK, queue it here - akpm */
@ -309,8 +308,6 @@ struct tty_file_private {
#define TTY_LDISC 9 /* Line discipline attached */
#define TTY_LDISC_CHANGING 10 /* Line discipline changing */
#define TTY_LDISC_OPEN 11 /* Line discipline is open */
#define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */
#define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */
#define TTY_PTY_LOCK 16 /* pty private */
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
#define TTY_HUPPED 18 /* Post driver->hangup() */

View File

@ -100,6 +100,11 @@
* seek to perform this action quickly but should wait until
* any pending driver I/O is completed.
*
* void (*fasync)(struct tty_struct *, int on)
*
* Notify line discipline when signal-driven I/O is enabled or
* disabled.
*
* void (*dcd_change)(struct tty_struct *tty, unsigned int status)
*
* Tells the discipline that the DCD pin has changed its status.
@ -110,6 +115,52 @@
#include <linux/wait.h>
#include <linux/wait.h>
/*
* the semaphore definition
*/
struct ld_semaphore {
long count;
raw_spinlock_t wait_lock;
unsigned int wait_readers;
struct list_head read_wait;
struct list_head write_wait;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};
extern void __init_ldsem(struct ld_semaphore *sem, const char *name,
struct lock_class_key *key);
#define init_ldsem(sem) \
do { \
static struct lock_class_key __key; \
\
__init_ldsem((sem), #sem, &__key); \
} while (0)
extern int ldsem_down_read(struct ld_semaphore *sem, long timeout);
extern int ldsem_down_read_trylock(struct ld_semaphore *sem);
extern int ldsem_down_write(struct ld_semaphore *sem, long timeout);
extern int ldsem_down_write_trylock(struct ld_semaphore *sem);
extern void ldsem_up_read(struct ld_semaphore *sem);
extern void ldsem_up_write(struct ld_semaphore *sem);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
extern int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass,
long timeout);
extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
long timeout);
#else
# define ldsem_down_read_nested(sem, subclass, timeout) \
ldsem_down_read(sem, timeout)
# define ldsem_down_write_nested(sem, subclass, timeout) \
ldsem_down_write(sem, timeout)
#endif
struct tty_ldisc_ops {
int magic;
char *name;
@ -143,6 +194,7 @@ struct tty_ldisc_ops {
char *fp, int count);
void (*write_wakeup)(struct tty_struct *);
void (*dcd_change)(struct tty_struct *, unsigned int);
void (*fasync)(struct tty_struct *tty, int on);
struct module *owner;

View File

@ -133,8 +133,6 @@ void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
extern int do_unbind_con_driver(const struct consw *csw, int first, int last,
int deflt);
extern int unbind_con_driver(const struct consw *csw, int first, int last,
int deflt);
int vty_init(const struct file_operations *console_fops);
static inline bool vt_force_oops_output(struct vc_data *vc)

View File

@ -226,4 +226,7 @@
/* Rocketport EXPRESS/INFINITY */
#define PORT_RP2 102
/* Freescale lpuart */
#define PORT_LPUART 103
#endif /* _UAPILINUX_SERIAL_CORE_H */