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:
commit
0de10f9ea6
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
14
Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt
Normal file
14
Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt
Normal 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>;
|
||||
};
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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/
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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 },
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
874
drivers/tty/serial/fsl_lpuart.c
Normal file
874
drivers/tty/serial/fsl_lpuart.c
Normal 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");
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
453
drivers/tty/tty_ldsem.c
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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() */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -226,4 +226,7 @@
|
||||
/* Rocketport EXPRESS/INFINITY */
|
||||
#define PORT_RP2 102
|
||||
|
||||
/* Freescale lpuart */
|
||||
#define PORT_LPUART 103
|
||||
|
||||
#endif /* _UAPILINUX_SERIAL_CORE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user