dect
/
linux-2.6
Archived
13
0
Fork 0

TTY merge for 3.7-rc1

As we skipped the merge window for 3.6-rc1 for the tty tree, everything
 is now settled down and working properly, so we are ready for 3.7-rc1.
 Here's the patchset, it's big, but the large changes are removing a
 firmware file and adding a staging tty driver (it depended on the tty
 core changes, so it's going through this tree instead of the staging
 tree.)
 
 All of these patches have been in the linux-next tree for a while.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iEYEABECAAYFAlBp36oACgkQMUfUDdst+yk4WgCdEy13hot8fI2Lqnc7W0LKu7GX
 4p8AoLTjzrXhLosxdijskDQ9X1OtjrxU
 =S5Ng
 -----END PGP SIGNATURE-----

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

Pull TTY changes from Greg Kroah-Hartman:
 "As we skipped the merge window for 3.6-rc1 for the tty tree,
  everything is now settled down and working properly, so we are ready
  for 3.7-rc1.  Here's the patchset, it's big, but the large changes are
  removing a firmware file and adding a staging tty driver (it depended
  on the tty core changes, so it's going through this tree instead of
  the staging tree.)

  All of these patches have been in the linux-next tree for a while.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

Fix up more-or-less trivial conflicts in
 - drivers/char/pcmcia/synclink_cs.c:
    tty NULL dereference fix vs tty_port_cts_enabled() helper function
 - drivers/staging/{Kconfig,Makefile}:
    add-add conflict (dgrp driver added close to other staging drivers)
 - drivers/staging/ipack/devices/ipoctal.c:
    "split ipoctal_channel from iopctal" vs "TTY: use tty_port_register_device"

* tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (235 commits)
  tty/serial: Add kgdb_nmi driver
  tty/serial/amba-pl011: Quiesce interrupts in poll_get_char
  tty/serial/amba-pl011: Implement poll_init callback
  tty/serial/core: Introduce poll_init callback
  kdb: Turn KGDB_KDB=n stubs into static inlines
  kdb: Implement disable_nmi command
  kernel/debug: Mask KGDB NMI upon entry
  serial: pl011: handle corruption at high clock speeds
  serial: sccnxp: Make 'default' choice in switch last
  serial: sccnxp: Remove mask termios caps for SW flow control
  serial: sccnxp: Report actual baudrate back to core
  serial: samsung: Add poll_get_char & poll_put_char
  Powerpc 8xx CPM_UART setting MAXIDL register proportionaly to baud rate
  Powerpc 8xx CPM_UART maxidl should not depend on fifo size
  Powerpc 8xx CPM_UART too many interrupts
  Powerpc 8xx CPM_UART desynchronisation
  serial: set correct baud_base for EXSYS EX-41092 Dual 16950
  serial: omap: fix the reciever line error case
  8250: blacklist Winbond CIR port
  8250_pnp: do pnp probe before legacy probe
  ...
This commit is contained in:
Linus Torvalds 2012-10-01 12:26:52 -07:00
commit 3498d13b80
201 changed files with 18052 additions and 8959 deletions

View File

@ -17,3 +17,12 @@ Description:
device, like 'tty1'.
The file supports poll() to detect virtual
console switches.
What: /sys/class/tty/ttyS0/uartclk
Date: Sep 2012
Contact: Tomas Hlavacek <tmshlvck@gmail.com>
Description:
Shows the current uartclk value associated with the
UART port in serial_core, that is bound to TTY like ttyS0.
uartclk = 16 * baud_base

View File

@ -0,0 +1,14 @@
* NXP LPC32xx SoC High Speed UART
Required properties:
- compatible: Should be "nxp,lpc3220-hsuart"
- reg: Should contain registers location and length
- interrupts: Should contain interrupt
Example:
uart1: serial@40014000 {
compatible = "nxp,lpc3220-hsuart";
reg = <0x40014000 0x1000>;
interrupts = <26 0>;
};

View File

@ -25,6 +25,8 @@ Optional properties:
accesses to the UART (e.g. TI davinci).
- used-by-rtas : set to indicate that the port is in use by the OpenFirmware
RTAS and should not be registered.
- no-loopback-test: set to indicate that the port does not implements loopback
test mode
Example:

View File

@ -2,8 +2,6 @@
- this file.
README.cycladesZ
- info on Cyclades-Z firmware loading.
computone.txt
- info on Computone Intelliport II/Plus Multiport Serial Driver.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
hayes-esp.txt

View File

@ -1,520 +0,0 @@
NOTE: This is an unmaintained driver. It is not guaranteed to work due to
changes made in the tty layer in 2.6. If you wish to take over maintenance of
this driver, contact Michael Warfield <mhw@wittsend.com>.
Changelog:
----------
11-01-2001: Original Document
10-29-2004: Minor misspelling & format fix, update status of driver.
James Nelson <james4765@gmail.com>
Computone Intelliport II/Plus Multiport Serial Driver
-----------------------------------------------------
Release Notes For Linux Kernel 2.2 and higher.
These notes are for the drivers which have already been integrated into the
kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
Version: 1.2.14
Date: 11/01/2001
Historical Author: Andrew Manison <amanison@america.net>
Primary Author: Doug McNash
This file assumes that you are using the Computone drivers which are
integrated into the kernel sources. For updating the drivers or installing
drivers into kernels which do not already have Computone drivers, please
refer to the instructions in the README.computone file in the driver patch.
1. INTRODUCTION
This driver supports the entire family of Intelliport II/Plus controllers
with the exception of the MicroChannel controllers. It does not support
products previous to the Intelliport II.
This driver was developed on the v2.0.x Linux tree and has been tested up
to v2.4.14; it will probably not work with earlier v1.X kernels,.
2. QUICK INSTALLATION
Hardware - If you have an ISA card, find a free interrupt and io port.
List those in use with `cat /proc/interrupts` and
`cat /proc/ioports`. Set the card dip switches to a free
address. You may need to configure your BIOS to reserve an
irq for an ISA card. PCI and EISA parameters are set
automagically. Insert card into computer with the power off
before or after drivers installation.
Note the hardware address from the Computone ISA cards installed into
the system. These are required for editing ip2.c or editing
/etc/modprobe.d/*.conf, or for specification on the modprobe
command line.
Note that the /etc/modules.conf should be used for older (pre-2.6)
kernels.
Software -
Module installation:
a) Determine free irq/address to use if any (configure BIOS if need be)
b) Run "make config" or "make menuconfig" or "make xconfig"
Select (m) module for CONFIG_COMPUTONE under character
devices. CONFIG_PCI and CONFIG_MODULES also may need to be set.
c) Set address on ISA cards then:
edit /usr/src/linux/drivers/char/ip2.c if needed
or
edit config file in /etc/modprobe.d/ if needed (module).
or both to match this setting.
d) Run "make modules"
e) Run "make modules_install"
f) Run "/sbin/depmod -a"
g) install driver using `modprobe ip2 <options>` (options listed below)
h) run ip2mkdev (either the script below or the binary version)
Kernel installation:
a) Determine free irq/address to use if any (configure BIOS if need be)
b) Run "make config" or "make menuconfig" or "make xconfig"
Select (y) kernel for CONFIG_COMPUTONE under character
devices. CONFIG_PCI may need to be set if you have PCI bus.
c) Set address on ISA cards then:
edit /usr/src/linux/drivers/char/ip2.c
(Optional - may be specified on kernel command line now)
d) Run "make zImage" or whatever target you prefer.
e) mv /usr/src/linux/arch/x86/boot/zImage to /boot.
f) Add new config for this kernel into /etc/lilo.conf, run "lilo"
or copy to a floppy disk and boot from that floppy disk.
g) Reboot using this kernel
h) run ip2mkdev (either the script below or the binary version)
Kernel command line options:
When compiling the driver into the kernel, io and irq may be
compiled into the driver by editing ip2.c and setting the values for
io and irq in the appropriate array. An alternative is to specify
a command line parameter to the kernel at boot up.
ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
Note that this order is very different from the specifications for the
modload parameters which have separate IRQ and IO specifiers.
The io port also selects PCI (1) and EISA (2) boards.
io=0 No board
io=1 PCI board
io=2 EISA board
else ISA board io address
You only need to specify the boards which are present.
Examples:
2 PCI boards:
ip2=1,0,1,0
1 ISA board at 0x310 irq 5:
ip2=0x310,5
This can be added to and "append" option in lilo.conf similar to this:
append="ip2=1,0,1,0"
3. INSTALLATION
Previously, the driver sources were packaged with a set of patch files
to update the character drivers' makefile and configuration file, and other
kernel source files. A build script (ip2build) was included which applies
the patches if needed, and build any utilities needed.
What you receive may be a single patch file in conventional kernel
patch format build script. That form can also be applied by
running patch -p1 < ThePatchFile. Otherwise run ip2build.
The driver can be installed as a module (recommended) or built into the
kernel. This is selected as for other drivers through the `make config`
command from the root of the Linux source tree. If the driver is built
into the kernel you will need to edit the file ip2.c to match the boards
you are installing. See that file for instructions. If the driver is
installed as a module the configuration can also be specified on the
modprobe command line as follows:
modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4
where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
12,15) and addr1-4 are the base addresses for up to four controllers. If
the irqs are not specified the driver uses the default in ip2.c (which
selects polled mode). If no base addresses are specified the defaults in
ip2.c are used. If you are autoloading the driver module with kerneld or
kmod the base addresses and interrupt number must also be set in ip2.c
and recompile or just insert and options line in /etc/modprobe.d/*.conf or both.
The options line is equivalent to the command line and takes precedence over
what is in ip2.c.
config sample to put /etc/modprobe.d/*.conf:
options ip2 io=1,0x328 irq=1,10
alias char-major-71 ip2
alias char-major-72 ip2
alias char-major-73 ip2
The equivalent in ip2.c:
static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 };
static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 };
The equivalent for the kernel command line (in lilo.conf):
append="ip2=1,1,0x328,10"
Note: Both io and irq should be updated to reflect YOUR system. An "io"
address of 1 or 2 indicates a PCI or EISA card in the board table.
The PCI or EISA irq will be assigned automatically.
Specifying an invalid or in-use irq will default the driver into
running in polled mode for that card. If all irq entries are 0 then
all cards will operate in polled mode.
If you select the driver as part of the kernel run :
make zlilo (or whatever you do to create a bootable kernel)
If you selected a module run :
make modules && make modules_install
The utility ip2mkdev (see 5 and 7 below) creates all the device nodes
required by the driver. For a device to be created it must be configured
in the driver and the board must be installed. Only devices corresponding
to real IntelliPort II ports are created. With multiple boards and expansion
boxes this will leave gaps in the sequence of device names. ip2mkdev uses
Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
cuf0 - cuf255 for callout devices.
4. USING THE DRIVERS
As noted above, the driver implements the ports in accordance with Linux
conventions, and the devices should be interchangeable with the standard
serial devices. (This is a key point for problem reporting: please make
sure that what you are trying do works on the ttySx/cuax ports first; then
tell us what went wrong with the ip2 ports!)
Higher speeds can be obtained using the setserial utility which remaps
38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed.
Intelliport II installations using the PowerPort expansion module can
use the custom speed setting to select the highest speeds: 153,600 bps,
230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
custom baud rate configuration is fixed at 921,600 for cards/expansion
modules with ST654's and 115200 for those with Cirrus CD1400's. This
corresponds to the maximum bit rates those chips are capable.
For example if the baud base is 921600 and the baud divisor is 18 then
the custom rate is 921600/18 = 51200 bps. See the setserial man page for
complete details. Of course if stty accepts the higher rates now you can
use that as well as the standard ioctls().
5. ip2mkdev and assorted utilities...
Several utilities, including the source for a binary ip2mkdev utility are
available under .../drivers/char/ip2. These can be build by changing to
that directory and typing "make" after the kernel has be built. If you do
not wish to compile the binary utilities, the shell script below can be
cut out and run as "ip2mkdev" to create the necessary device files. To
use the ip2mkdev script, you must have procfs enabled and the proc file
system mounted on /proc.
6. NOTES
This is a release version of the driver, but it is impossible to test it
in all configurations of Linux. If there is any anomalous behaviour that
does not match the standard serial port's behaviour please let us know.
7. ip2mkdev shell script
Previously, this script was simply attached here. It is now attached as a
shar archive to make it easier to extract the script from the documentation.
To create the ip2mkdev shell script change to a convenient directory (/tmp
works just fine) and run the following command:
unshar Documentation/serial/computone.txt
(This file)
You should now have a file ip2mkdev in your current working directory with
permissions set to execute. Running that script with then create the
necessary devices for the Computone boards, interfaces, and ports which
are present on you system at the time it is run.
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2001-10-29 10:32 EST by <mhw@alcove.wittsend.com>.
# Source directory was `/home2/src/tmp'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 4251 -rwxr-xr-x ip2mkdev
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
if test "$gettext_dir" = FAILED && test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
set `$dir/gettext --version 2>&1`
if test "$3" = GNU
then
gettext_dir=$dir
fi
fi
if test "$locale_dir" = FAILED && test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
echo=echo
else
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
$echo 'WARNING: not restoring timestamps. Consider getting and'
$echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh17581; then
$echo 'x -' 'creating lock directory'
else
$echo 'failed to create lock directory'
exit 1
fi
# ============= ip2mkdev ==============
if test -f 'ip2mkdev' && test "$first_param" != -c; then
$echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)'
else
$echo 'x -' extracting 'ip2mkdev' '(text)'
sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' &&
#!/bin/sh -
#
# ip2mkdev
#
# Make or remove devices as needed for Computone Intelliport drivers
#
# First rule! If the dev file exists and you need it, don't mess
# with it. That prevents us from screwing up open ttys, ownership
# and permissions on a running system!
#
# This script will NOT remove devices that no longer exist if their
# board or interface box has been removed. If you want to get rid
# of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
# before running this script. Running this script will then recreate
# all the valid devices.
#
# Michael H. Warfield
# /\/\|=mhw=|\/\/
# mhw@wittsend.com
#
# Updated 10/29/2000 for version 1.2.13 naming convention
# under devfs. /\/\|=mhw=|\/\/
#
# Updated 03/09/2000 for devfs support in ip2 drivers. /\/\|=mhw=|\/\/
#
X
if test -d /dev/ip2 ; then
# This is devfs mode... We don't do anything except create symlinks
# from the real devices to the old names!
X cd /dev
X echo "Creating symbolic links to devfs devices"
X for i in `ls ip2` ; do
X if test ! -L ip2$i ; then
X # Remove it incase it wasn't a symlink (old device)
X rm -f ip2$i
X ln -s ip2/$i ip2$i
X fi
X done
X for i in `( cd tts ; ls F* )` ; do
X if test ! -L tty$i ; then
X # Remove it incase it wasn't a symlink (old device)
X rm -f tty$i
X ln -s tts/$i tty$i
X fi
X done
X for i in `( cd cua ; ls F* )` ; do
X DEVNUMBER=`expr $i : 'F\(.*\)'`
X if test ! -L cuf$DEVNUMBER ; then
X # Remove it incase it wasn't a symlink (old device)
X rm -f cuf$DEVNUMBER
X ln -s cua/$i cuf$DEVNUMBER
X fi
X done
X exit 0
fi
X
if test ! -f /proc/tty/drivers
then
X echo "\
Unable to check driver status.
Make sure proc file system is mounted."
X
X exit 255
fi
X
if test ! -f /proc/tty/driver/ip2
then
X echo "\
Unable to locate ip2 proc file.
Attempting to load driver"
X
X if /sbin/insmod ip2
X then
X if test ! -f /proc/tty/driver/ip2
X then
X echo "\
Unable to locate ip2 proc file after loading driver.
Driver initialization failure or driver version error.
"
X exit 255
X fi
X else
X echo "Unable to load ip2 driver."
X exit 255
X fi
fi
X
# Ok... So we got the driver loaded and we can locate the procfs files.
# Next we need our major numbers.
X
TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers`
BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2`
X
echo "\
TTYMAJOR = $TTYMAJOR
CUAMAJOR = $CUAMAJOR
BRDMAJOR = $BRDMAJOR
"
X
# Ok... Now we should know our major numbers, if appropriate...
# Now we need our boards and start the device loops.
X
grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest
do
X # The test for blank "type" will catch the stats lead-in lines
X # if they exist in the file
X if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = ""
X then
X continue
X fi
X
X BOARDNO=`expr "$number" : '\([0-9]\):'`
X PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '`
X MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '`
X
X if test "$BOARDNO" = "" -o "$PORTS" = ""
X then
# This may be a bug. We should at least get this much information
X echo "Unable to process board line"
X continue
X fi
X
X if test "$MINORS" = ""
X then
# Silently skip this one. This board seems to have no boxes
X continue
X fi
X
X echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS"
X
X if test "$BRDMAJOR" != ""
X then
X BRDMINOR=`expr $BOARDNO \* 4`
X STSMINOR=`expr $BRDMINOR + 1`
X if test ! -c /dev/ip2ipl$BOARDNO ; then
X mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR
X fi
X if test ! -c /dev/ip2stat$BOARDNO ; then
X mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR
X fi
X fi
X
X if test "$TTYMAJOR" != ""
X then
X PORTNO=$BOARDBASE
X
X for PORTNO in $MINORS
X do
X if test ! -c /dev/ttyF$PORTNO ; then
X # We got the hardware but no device - make it
X mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO
X fi
X done
X fi
X
X if test "$CUAMAJOR" != ""
X then
X PORTNO=$BOARDBASE
X
X for PORTNO in $MINORS
X do
X if test ! -c /dev/cuf$PORTNO ; then
X # We got the hardware but no device - make it
X mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO
X fi
X done
X fi
done
X
Xexit 0
SHAR_EOF
(set 20 01 10 29 10 32 01 'ip2mkdev'; eval "$shar_touch") &&
chmod 0755 'ip2mkdev' ||
$echo 'restore of' 'ip2mkdev' 'failed'
if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
&& ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
md5sum -c << SHAR_EOF >/dev/null 2>&1 \
|| $echo 'ip2mkdev:' 'MD5 check failed'
cb5717134509f38bad9fde6b1f79b4a4 ip2mkdev
SHAR_EOF
else
shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`"
test 4251 -eq "$shar_count" ||
$echo 'ip2mkdev:' 'original size' '4251,' 'current size' "$shar_count!"
fi
fi
rm -fr _sh17581
exit 0

View File

@ -223,6 +223,7 @@ srmcons_init(void)
driver->subtype = SYSTEM_TYPE_SYSCONS;
driver->init_termios = tty_std_termios;
tty_set_operations(driver, &srmcons_ops);
tty_port_link_device(&srmcons_singleton.port, driver, 0);
err = tty_register_driver(driver);
if (err) {
put_tty_driver(driver);

View File

@ -81,8 +81,9 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = {
};
#ifdef CONFIG_PM
static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
static void omap_uart_enable_wakeup(struct device *dev, bool enable)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
if (!od)
@ -99,15 +100,17 @@ static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
* in Smartidle Mode When Configured for DMA Operations.
* WA: configure uart in force idle mode.
*/
static void omap_uart_set_noidle(struct platform_device *pdev)
static void omap_uart_set_noidle(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO);
}
static void omap_uart_set_smartidle(struct platform_device *pdev)
static void omap_uart_set_smartidle(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap_device *od = to_omap_device(pdev);
u8 idlemode;
@ -120,10 +123,10 @@ static void omap_uart_set_smartidle(struct platform_device *pdev)
}
#else
static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable)
static void omap_uart_enable_wakeup(struct device *dev, bool enable)
{}
static void omap_uart_set_noidle(struct platform_device *pdev) {}
static void omap_uart_set_smartidle(struct platform_device *pdev) {}
static void omap_uart_set_noidle(struct device *dev) {}
static void omap_uart_set_smartidle(struct device *dev) {}
#endif /* CONFIG_PM */
#ifdef CONFIG_OMAP_MUX
@ -304,6 +307,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
omap_up.dma_rx_timeout = info->dma_rx_timeout;
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout;
omap_up.DTR_gpio = info->DTR_gpio;
omap_up.DTR_inverted = info->DTR_inverted;
omap_up.DTR_present = info->DTR_present;
pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info);

View File

@ -524,33 +524,12 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
};
#endif
#define PRCC_K_SOFTRST_SET 0x18
#define PRCC_K_SOFTRST_CLEAR 0x1C
static void ux500_uart0_reset(void)
{
void __iomem *prcc_rst_set, *prcc_rst_clr;
prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
PRCC_K_SOFTRST_SET);
prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
PRCC_K_SOFTRST_CLEAR);
/* Activate soft reset PRCC_K_SOFTRST_CLEAR */
writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr);
udelay(1);
/* Release soft reset PRCC_K_SOFTRST_SET */
writel((readl(prcc_rst_set) | 0x1), prcc_rst_set);
udelay(1);
}
static struct amba_pl011_data uart0_plat = {
#ifdef CONFIG_STE_DMA40
.dma_filter = stedma40_filter,
.dma_rx_param = &uart0_dma_cfg_rx,
.dma_tx_param = &uart0_dma_cfg_tx,
#endif
.reset = ux500_uart0_reset,
};
static struct amba_pl011_data uart1_plat = {

View File

@ -18,7 +18,7 @@
#define __OMAP_SERIAL_H__
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/pm_qos.h>
#include <plat/mux.h>
@ -42,10 +42,10 @@
#define OMAP_UART_WER_MOD_WKUP 0X7F
/* Enable XON/XOFF flow control on output */
#define OMAP_UART_SW_TX 0x04
#define OMAP_UART_SW_TX 0x8
/* Enable XON/XOFF flow control on input */
#define OMAP_UART_SW_RX 0x04
#define OMAP_UART_SW_RX 0x2
#define OMAP_UART_SYSC_RESET 0X07
#define OMAP_UART_TCR_TRIG 0X0F
@ -69,11 +69,14 @@ struct omap_uart_port_info {
unsigned int dma_rx_timeout;
unsigned int autosuspend_timeout;
unsigned int dma_rx_poll_rate;
int DTR_gpio;
int DTR_inverted;
int DTR_present;
int (*get_context_loss_count)(struct device *);
void (*set_forceidle)(struct platform_device *);
void (*set_noidle)(struct platform_device *);
void (*enable_wakeup)(struct platform_device *, bool);
void (*set_forceidle)(struct device *);
void (*set_noidle)(struct device *);
void (*enable_wakeup)(struct device *, bool);
};
struct uart_omap_dma {
@ -102,39 +105,4 @@ struct uart_omap_dma {
unsigned int rx_timeout;
};
struct uart_omap_port {
struct uart_port port;
struct uart_omap_dma uart_dma;
struct platform_device *pdev;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned char fcr;
unsigned char efr;
unsigned char dll;
unsigned char dlh;
unsigned char mdr1;
unsigned char scr;
int use_dma;
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
unsigned int lsr_break_flag;
unsigned char msr_saved_flags;
char name[20];
unsigned long port_activity;
u32 context_loss_cnt;
u32 errata;
u8 wakeups_enabled;
struct pm_qos_request pm_qos_request;
u32 latency;
u32 calc_latency;
struct work_struct qos_work;
};
#endif /* __OMAP_SERIAL_H__ */

View File

@ -338,7 +338,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
}
}
@ -545,6 +545,7 @@ static int __init simrs_init(void)
/* the port is imaginary */
printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
tty_port_link_device(&state->port, hp_simserial_driver, 0);
retval = tty_register_driver(hp_simserial_driver);
if (retval) {
printk(KERN_ERR "Couldn't register simserial driver\n");

View File

@ -19,6 +19,7 @@
#include <asm/natfeat.h>
static int stderr_id;
static struct tty_port nfcon_tty_port;
static struct tty_driver *nfcon_tty_driver;
static void nfputs(const char *str, unsigned int count)
@ -119,6 +120,8 @@ static int __init nfcon_init(void)
{
int res;
tty_port_init(&nfcon_tty_port);
stderr_id = nf_get_id("NF_STDERR");
if (!stderr_id)
return -ENODEV;
@ -135,6 +138,7 @@ static int __init nfcon_init(void)
nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
res = tty_register_driver(nfcon_tty_driver);
if (res) {
pr_err("failed to register nfcon tty driver\n");

View File

@ -47,40 +47,40 @@ static int __devinit octeon_serial_probe(struct platform_device *pdev)
{
int irq, res;
struct resource *res_mem;
struct uart_port port;
struct uart_8250_port up;
/* All adaptors have an irq. */
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
memset(&port, 0, sizeof(port));
memset(&up, 0, sizeof(up));
port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
port.type = PORT_OCTEON;
port.iotype = UPIO_MEM;
port.regshift = 3;
port.dev = &pdev->dev;
up.port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
up.port.type = PORT_OCTEON;
up.port.iotype = UPIO_MEM;
up.port.regshift = 3;
up.port.dev = &pdev->dev;
if (octeon_is_simulation())
/* Make simulator output fast*/
port.uartclk = 115200 * 16;
up.port.uartclk = 115200 * 16;
else
port.uartclk = octeon_get_io_clock_rate();
up.port.uartclk = octeon_get_io_clock_rate();
port.serial_in = octeon_serial_in;
port.serial_out = octeon_serial_out;
port.irq = irq;
up.port.serial_in = octeon_serial_in;
up.port.serial_out = octeon_serial_out;
up.port.irq = irq;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res_mem == NULL) {
dev_err(&pdev->dev, "found no memory resource\n");
return -ENXIO;
}
port.mapbase = res_mem->start;
port.membase = ioremap(res_mem->start, resource_size(res_mem));
up.port.mapbase = res_mem->start;
up.port.membase = ioremap(res_mem->start, resource_size(res_mem));
res = serial8250_register_port(&port);
res = serial8250_register_8250_port(&up);
return res >= 0 ? 0 : res;
}

View File

@ -133,6 +133,38 @@ static struct platform_device sc26xx_pdev = {
}
};
#warning "Please try migrate to use new driver SCCNXP and report the status" \
"in the linux-serial mailing list."
/* The code bellow is a replacement of SC26XX to SCCNXP */
#if 0
#include <linux/platform_data/sccnxp.h>
static struct sccnxp_pdata sccnxp_data = {
.reg_shift = 2,
.frequency = 3686400,
.mctrl_cfg[0] = MCTRL_SIG(DTR_OP, LINE_OP7) |
MCTRL_SIG(RTS_OP, LINE_OP3) |
MCTRL_SIG(DSR_IP, LINE_IP5) |
MCTRL_SIG(DCD_IP, LINE_IP6),
.mctrl_cfg[1] = MCTRL_SIG(DTR_OP, LINE_OP2) |
MCTRL_SIG(RTS_OP, LINE_OP1) |
MCTRL_SIG(DSR_IP, LINE_IP0) |
MCTRL_SIG(CTS_IP, LINE_IP1) |
MCTRL_SIG(DCD_IP, LINE_IP2) |
MCTRL_SIG(RNG_IP, LINE_IP3),
};
static struct platform_device sc2681_pdev = {
.name = "sc2681",
.resource = sc2xxx_rsrc,
.num_resources = ARRAY_SIZE(sc2xxx_rsrc),
.dev = {
.platform_data = &sccnxp_data,
},
};
#endif
static u32 a20r_ack_hwint(void)
{
u32 status = read_c0_status();

View File

@ -202,6 +202,7 @@ static int __init pdc_console_tty_driver_init(void)
pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
tty_port_link_device(&tty_port, pdc_console_tty_driver, 0);
err = tty_register_driver(pdc_console_tty_driver);
if (err) {

View File

@ -409,7 +409,8 @@ int setup_one_line(struct line *lines, int n, char *init,
line->valid = 1;
err = parse_chan_pair(new, line, n, opts, error_out);
if (!err) {
struct device *d = tty_register_device(driver, n, NULL);
struct device *d = tty_port_register_device(&line->port,
driver, n, NULL);
if (IS_ERR(d)) {
*error_out = "Failed to register device";
err = PTR_ERR(d);

View File

@ -223,6 +223,7 @@ int __init rs_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);
tty_port_link_device(&serial_port, serial_driver, 0);
if (tty_register_driver(serial_driver))
panic("Couldn't register serial driver\n");

View File

@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty)
return status;
/* Disable Automatic RTSCTS */
memcpy(&ktermios, tty->termios, sizeof(ktermios));
ktermios = tty->termios;
ktermios.c_cflag &= ~CRTSCTS;
tty_set_termios(tty, &ktermios);

View File

@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf,
static int register_serial_portandirq(unsigned int port, int irq)
{
struct uart_port uart;
struct uart_8250_port uart;
switch ( port ) {
case 0x3f8:
@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
} /* switch */
/* irq is okay */
memset(&uart, 0, sizeof(struct uart_port));
memset(&uart, 0, sizeof(uart));
uart.uartclk = 1843200;
uart.iobase = port;
uart.irq = irq;
uart.iotype = UPIO_PORT;
uart.flags = UPF_SHARE_IRQ;
return serial8250_register_port(&uart);
uart.port.uartclk = 1843200;
uart.port.iobase = port;
uart.port.irq = irq;
uart.port.iotype = UPIO_PORT;
uart.port.flags = UPF_SHARE_IRQ;
return serial8250_register_8250_port(&uart);
}

View File

@ -1058,7 +1058,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
if (tty && (info->port.flags & ASYNC_CTS_FLOW)) {
if (tty && tty_port_cts_enabled(&info->port)) {
if (tty->hw_stopped) {
if (info->serial_signals & SerialSignal_CTS) {
if (debug_level >= DEBUG_LEVEL_ISR)
@ -1350,7 +1350,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
if (!tty || tty->termios->c_cflag & HUPCL) {
if (!tty || tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@ -1391,7 +1391,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
get_signals(info);
if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@ -1404,14 +1404,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
unsigned cflag;
int bits_per_char;
if (!tty || !tty->termios)
if (!tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
cflag = tty->termios->c_cflag;
cflag = tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@ -1734,7 +1734,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgslpc_send_xchar(tty, STOP_CHAR(tty));
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@ -1763,7 +1763,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
mgslpc_send_xchar(tty, START_CHAR(tty));
}
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@ -2299,8 +2299,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
tty->driver->name );
/* just return if nothing has changed */
if ((tty->termios->c_cflag == old_termios->c_cflag)
&& (RELEVANT_IFLAG(tty->termios->c_iflag)
if ((tty->termios.c_cflag == old_termios->c_cflag)
&& (RELEVANT_IFLAG(tty->termios.c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
@ -2308,7 +2308,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
!(tty->termios->c_cflag & CBAUD)) {
!(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@ -2317,9 +2317,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
tty->termios->c_cflag & CBAUD) {
tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
if (!(tty->termios->c_cflag & CRTSCTS) ||
if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@ -2330,7 +2330,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@ -2737,6 +2737,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
#if SYNCLINK_GENERIC_HDLC
hdlcdev_init(info);
#endif
tty_port_register_device(&info->port, serial_driver, info->line,
&info->p_dev->dev);
}
static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@ -2750,6 +2752,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
last->next_device = info->next_device;
else
mgslpc_device_list = info->next_device;
tty_unregister_device(serial_driver, info->line);
#if SYNCLINK_GENERIC_HDLC
hdlcdev_exit(info);
#endif
@ -2804,77 +2807,63 @@ static const struct tty_operations mgslpc_ops = {
.proc_fops = &mgslpc_proc_fops,
};
static void synclink_cs_cleanup(void)
static int __init synclink_cs_init(void)
{
int rc;
while(mgslpc_device_list)
mgslpc_remove_device(mgslpc_device_list);
if (serial_driver) {
if ((rc = tty_unregister_driver(serial_driver)))
printk("%s(%d) failed to unregister tty driver err=%d\n",
__FILE__,__LINE__,rc);
put_tty_driver(serial_driver);
if (break_on_load) {
mgslpc_get_text_ptr();
BREAKPOINT();
}
pcmcia_unregister_driver(&mgslpc_driver);
}
serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(serial_driver)) {
rc = PTR_ERR(serial_driver);
goto err;
}
static int __init synclink_cs_init(void)
{
int rc;
/* Initialize the tty_driver structure */
serial_driver->driver_name = "synclink_cs";
serial_driver->name = "ttySLP";
serial_driver->major = ttymajor;
serial_driver->minor_start = 64;
serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
serial_driver->subtype = SERIAL_TYPE_NORMAL;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(serial_driver, &mgslpc_ops);
if (break_on_load) {
mgslpc_get_text_ptr();
BREAKPOINT();
}
rc = tty_register_driver(serial_driver);
if (rc < 0) {
printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
__FILE__, __LINE__);
goto err_put_tty;
}
if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
return rc;
rc = pcmcia_register_driver(&mgslpc_driver);
if (rc < 0)
goto err_unreg_tty;
serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
if (!serial_driver) {
rc = -ENOMEM;
goto error;
}
printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
serial_driver->major);
/* Initialize the tty_driver structure */
serial_driver->driver_name = "synclink_cs";
serial_driver->name = "ttySLP";
serial_driver->major = ttymajor;
serial_driver->minor_start = 64;
serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
serial_driver->subtype = SERIAL_TYPE_NORMAL;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &mgslpc_ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
printk("%s(%d):Couldn't register serial driver\n",
__FILE__,__LINE__);
put_tty_driver(serial_driver);
serial_driver = NULL;
goto error;
}
printk("%s %s, tty major#%d\n",
driver_name, driver_version,
serial_driver->major);
return 0;
error:
synclink_cs_cleanup();
return rc;
return 0;
err_unreg_tty:
tty_unregister_driver(serial_driver);
err_put_tty:
put_tty_driver(serial_driver);
err:
return rc;
}
static void __exit synclink_cs_exit(void)
{
synclink_cs_cleanup();
pcmcia_unregister_driver(&mgslpc_driver);
tty_unregister_driver(serial_driver);
put_tty_driver(serial_driver);
}
module_init(synclink_cs_init);

View File

@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
if (buf[i + 1] == '\n')
if ((i + 1) < count && buf[i + 1] == '\n')
i++;
break;
case '\n':
@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver;
static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
void *rp;
ttyprintk_driver = alloc_tty_driver(1);
if (!ttyprintk_driver)
return ret;
tty_port_init(&tpk_port.port);
tpk_port.port.ops = &null_ops;
mutex_init(&tpk_port.port_write_mutex);
ttyprintk_driver = tty_alloc_driver(1,
TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_UNNUMBERED_NODE);
if (IS_ERR(ttyprintk_driver))
return PTR_ERR(ttyprintk_driver);
ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk";
@ -191,9 +197,8 @@ static int __init ttyprintk_init(void)
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);
ret = tty_register_driver(ttyprintk_driver);
if (ret < 0) {
@ -201,22 +206,10 @@ static int __init ttyprintk_init(void)
goto error;
}
/* create our unnumbered device */
rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
ttyprintk_driver->name);
if (IS_ERR(rp)) {
printk(KERN_ERR "Couldn't create ttyprintk device\n");
ret = PTR_ERR(rp);
goto error;
}
tty_port_init(&tpk_port.port);
tpk_port.port.ops = &null_ops;
mutex_init(&tpk_port.port_write_mutex);
return 0;
error:
tty_unregister_driver(ttyprintk_driver);
put_tty_driver(ttyprintk_driver);
ttyprintk_driver = NULL;
return ret;

View File

@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
mp->minor = minor;
dev = tty_register_device(capinc_tty_driver, minor, NULL);
dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
NULL);
if (IS_ERR(dev))
goto err_out2;

View File

@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
goto out;
}
iflag = tty->termios->c_iflag;
cflag = tty->termios->c_cflag;
iflag = tty->termios.c_iflag;
cflag = tty->termios.c_cflag;
old_cflag = old ? old->c_cflag : cflag;
gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
cs->minor_index, iflag, cflag, old_cflag);
@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs)
tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
mutex_lock(&cs->mutex);
cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
cs->minor_index, NULL);
if (!IS_ERR(cs->tty_dev))
dev_set_drvdata(cs->tty_dev, cs);

View File

@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info)
quot;
int i;
if (!port->tty || !port->tty->termios)
if (!port->tty)
return;
cflag = port->tty->termios->c_cflag;
cflag = port->tty->termios.c_cflag;
quot = i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
if (i < 1 || i > 2)
port->tty->termios->c_cflag &= ~CBAUDEX;
port->tty->termios.c_cflag &= ~CBAUDEX;
else
i += 15;
}
@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info)
#endif
isdn_unlock_drivers();
info->msr &= ~UART_MSR_RI;
if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!old_termios)
isdn_tty_change_speed(info);
else {
if (tty->termios->c_cflag == old_termios->c_cflag &&
tty->termios->c_ispeed == old_termios->c_ispeed &&
tty->termios->c_ospeed == old_termios->c_ospeed)
if (tty->termios.c_cflag == old_termios->c_cflag &&
tty->termios.c_ispeed == old_termios->c_ispeed &&
tty->termios.c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS))
!(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
}
}
@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* ------------------------------------------------------------
*/
static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
modem_info *info = &dev->mdm.info[tty->index];
if (isdn_tty_paranoia_check(info, tty->name, __func__))
return -ENODEV;
tty->driver_data = info;
return tty_port_install(&info->port, driver, tty);
}
/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its async structure into
@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
struct tty_port *port;
modem_info *info;
modem_info *info = tty->driver_data;
struct tty_port *port = &info->port;
int retval;
info = &dev->mdm.info[tty->index];
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
return -ENODEV;
port = &info->port;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
port->count);
#endif
port->count++;
tty->driver_data = info;
port->tty = tty;
tty->port = port;
/*
* Start up serial port
*/
@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m)
}
static const struct tty_operations modem_ops = {
.install = isdn_tty_install,
.open = isdn_tty_open,
.close = isdn_tty_close,
.write = isdn_tty_write,
@ -1782,7 +1789,7 @@ isdn_tty_modem_init(void)
m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
m->tty_modem->init_termios = tty_std_termios;
m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
m->tty_modem->driver_name = "isdn_tty";
tty_set_operations(m->tty_modem, &modem_ops);
retval = tty_register_driver(m->tty_modem);

View File

@ -33,7 +33,7 @@
void ibmasm_register_uart(struct service_processor *sp)
{
struct uart_port uport;
struct uart_8250_port uart;
void __iomem *iomem_base;
iomem_base = sp->base_address + SCOUT_COM_B_BASE;
@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp)
return;
}
memset(&uport, 0, sizeof(struct uart_port));
uport.irq = sp->irq;
uport.uartclk = 3686400;
uport.flags = UPF_SHARE_IRQ;
uport.iotype = UPIO_MEM;
uport.membase = iomem_base;
memset(&uart, 0, sizeof(uart));
uart.port.irq = sp->irq;
uart.port.uartclk = 3686400;
uart.port.flags = UPF_SHARE_IRQ;
uart.port.iotype = UPIO_MEM;
uart.port.membase = iomem_base;
sp->serial_line = serial8250_register_port(&uport);
sp->serial_line = serial8250_register_8250_port(&uart);
if (sp->serial_line < 0) {
dev_err(sp->dev, "Failed to register serial port\n");
return;

View File

@ -60,7 +60,7 @@ struct pti_tty {
};
struct pti_dev {
struct tty_port port;
struct tty_port port[PTITTY_MINOR_NUM];
unsigned long pti_addr;
unsigned long aperture_base;
void __iomem *pti_ioaddr;
@ -76,7 +76,7 @@ struct pti_dev {
*/
static DEFINE_MUTEX(alloclock);
static struct pci_device_id pci_ids[] __devinitconst = {
static const struct pci_device_id pci_ids[] __devinitconst = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
{0}
};
@ -393,25 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
}
EXPORT_SYMBOL_GPL(pti_writedata);
/**
* pti_pci_remove()- Driver exit method to remove PTI from
* PCI bus.
* @pdev: variable containing pci info of PTI.
*/
static void __devexit pti_pci_remove(struct pci_dev *pdev)
{
struct pti_dev *drv_data;
drv_data = pci_get_drvdata(pdev);
if (drv_data != NULL) {
pci_iounmap(pdev, drv_data->pti_ioaddr);
pci_set_drvdata(pdev, NULL);
kfree(drv_data);
pci_release_region(pdev, 1);
pci_disable_device(pdev);
}
}
/*
* for the tty_driver_*() basic function descriptions, see tty_driver.h.
* Specific header comments made for PTI-related specifics.
@ -446,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
* also removes a locking requirement for the actual write
* procedure.
*/
return tty_port_open(&drv_data->port, tty, filp);
return tty_port_open(tty->port, tty, filp);
}
/**
@ -462,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
*/
static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
{
tty_port_close(&drv_data->port, tty, filp);
tty_port_close(tty->port, tty, filp);
}
/**
@ -818,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = {
static int __devinit pti_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
unsigned int a;
int retval = -EINVAL;
int pci_bar = 1;
@ -830,7 +812,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
return retval;
goto err;
}
retval = pci_enable_device(pdev);
@ -838,17 +820,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s: pci_enable_device() returned error %d\n",
__func__, retval);
return retval;
goto err_unreg_misc;
}
drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
if (drv_data == NULL) {
retval = -ENOMEM;
dev_err(&pdev->dev,
"%s(%d): kmalloc() returned NULL memory.\n",
__func__, __LINE__);
return retval;
goto err_disable_pci;
}
drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
@ -857,33 +838,65 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s(%d): pci_request_region() returned error %d\n",
__func__, __LINE__, retval);
kfree(drv_data);
return retval;
goto err_free_dd;
}
drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
drv_data->pti_ioaddr =
ioremap_nocache((u32)drv_data->aperture_base,
APERTURE_LEN);
if (!drv_data->pti_ioaddr) {
pci_release_region(pdev, pci_bar);
retval = -ENOMEM;
kfree(drv_data);
return retval;
goto err_rel_reg;
}
pci_set_drvdata(pdev, drv_data);
tty_port_init(&drv_data->port);
drv_data->port.ops = &tty_port_ops;
for (a = 0; a < PTITTY_MINOR_NUM; a++) {
struct tty_port *port = &drv_data->port[a];
tty_port_init(port);
port->ops = &tty_port_ops;
tty_register_device(pti_tty_driver, 0, &pdev->dev);
tty_register_device(pti_tty_driver, 1, &pdev->dev);
tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
}
register_console(&pti_console);
return 0;
err_rel_reg:
pci_release_region(pdev, pci_bar);
err_free_dd:
kfree(drv_data);
err_disable_pci:
pci_disable_device(pdev);
err_unreg_misc:
misc_deregister(&pti_char_driver);
err:
return retval;
}
/**
* pti_pci_remove()- Driver exit method to remove PTI from
* PCI bus.
* @pdev: variable containing pci info of PTI.
*/
static void __devexit pti_pci_remove(struct pci_dev *pdev)
{
struct pti_dev *drv_data = pci_get_drvdata(pdev);
unregister_console(&pti_console);
tty_unregister_device(pti_tty_driver, 0);
tty_unregister_device(pti_tty_driver, 1);
iounmap(drv_data->pti_ioaddr);
pci_set_drvdata(pdev, NULL);
kfree(drv_data);
pci_release_region(pdev, 1);
pci_disable_device(pdev);
misc_deregister(&pti_char_driver);
}
static struct pci_driver pti_pci_driver = {
.name = PCINAME,
.id_table = pci_ids,
@ -933,25 +946,24 @@ static int __init pti_init(void)
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
pti_tty_driver = NULL;
return retval;
goto put_tty;
}
retval = pci_register_driver(&pti_pci_driver);
if (retval) {
pr_err("%s(%d): PCI registration failed of pti driver\n",
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
tty_unregister_driver(pti_tty_driver);
pr_err("%s(%d): Unregistering TTY part of pti driver\n",
__func__, __LINE__);
pti_tty_driver = NULL;
return retval;
goto unreg_tty;
}
return 0;
unreg_tty:
tty_unregister_driver(pti_tty_driver);
put_tty:
put_tty_driver(pti_tty_driver);
pti_tty_driver = NULL;
return retval;
}
@ -960,31 +972,9 @@ static int __init pti_init(void)
*/
static void __exit pti_exit(void)
{
int retval;
tty_unregister_device(pti_tty_driver, 0);
tty_unregister_device(pti_tty_driver, 1);
retval = tty_unregister_driver(pti_tty_driver);
if (retval) {
pr_err("%s(%d): TTY unregistration failed of pti driver\n",
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
}
tty_unregister_driver(pti_tty_driver);
pci_unregister_driver(&pti_pci_driver);
retval = misc_deregister(&pti_char_driver);
if (retval) {
pr_err("%s(%d): CHAR unregistration failed of pti driver\n",
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
}
unregister_console(&pti_console);
return;
put_tty_driver(pti_tty_driver);
}
module_init(pti_init);

View File

@ -518,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
if (status & UART_MSR_DCTS) {
port->icount.cts++;
tty = tty_port_tty_get(&port->port);
if (tty && (tty->termios->c_cflag & CRTSCTS)) {
if (tty && (tty->termios.c_cflag & CRTSCTS)) {
int cts = (status & UART_MSR_CTS);
if (tty->hw_stopped) {
if (cts) {
@ -671,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
port->mctrl = TIOCM_OUT2;
sdio_uart_change_speed(port, tty->termios, NULL);
sdio_uart_change_speed(port, &tty->termios, NULL);
if (tty->termios->c_cflag & CBAUD)
if (tty->termios.c_cflag & CBAUD)
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
tty->hw_stopped = 1;
@ -850,7 +850,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
return;
if (sdio_uart_claim_func(port) != 0)
@ -861,7 +861,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
sdio_uart_start_tx(port);
}
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
sdio_uart_clear_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@ -872,7 +872,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
return;
if (sdio_uart_claim_func(port) != 0)
@ -887,7 +887,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
}
}
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
sdio_uart_set_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@ -898,12 +898,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct sdio_uart_port *port = tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
unsigned int cflag = tty->termios.c_cflag;
if (sdio_uart_claim_func(port) != 0)
return;
sdio_uart_change_speed(port, tty->termios, old_termios);
sdio_uart_change_speed(port, &tty->termios, old_termios);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func,
kfree(port);
} else {
struct device *dev;
dev = tty_register_device(sdio_uart_tty_driver,
port->index, &func->dev);
dev = tty_port_register_device(&port->port,
sdio_uart_tty_driver, port->index, &func->dev);
if (IS_ERR(dev)) {
sdio_uart_port_remove(port);
ret = PTR_ERR(dev);

View File

@ -1147,15 +1147,17 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
{
#define COSMISC_CONSTANT 6
struct uart_port port = {
.irq = 0,
.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 0,
.uartclk = (22000000 << 1) / COSMISC_CONSTANT,
struct uart_8250_port port = {
.port = {
.irq = 0,
.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 0,
.uartclk = (22000000 << 1) / COSMISC_CONSTANT,
.membase = (unsigned char __iomem *) uart,
.mapbase = (unsigned long) uart,
.membase = (unsigned char __iomem *) uart,
.mapbase = (unsigned long) uart,
}
};
unsigned char lcr;
@ -1164,7 +1166,7 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
uart->iu_scr = COSMISC_CONSTANT,
uart->iu_lcr = lcr;
uart->iu_lcr;
serial8250_register_port(&port);
serial8250_register_8250_port(&port);
}
static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)

View File

@ -124,8 +124,8 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty;
mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
old_termios = tty->termios;
cflag = tty->termios.c_cflag;
tty_encode_baud_rate(tty, speed, speed);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
@ -281,15 +281,15 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
int cflag;
mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
old_termios = tty->termios;
cflag = tty->termios.c_cflag;
if (stop)
cflag &= ~CREAD;
else
cflag |= CREAD;
tty->termios->c_cflag = cflag;
tty->termios.c_cflag = cflag;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
mutex_unlock(&tty->termios_mutex);

View File

@ -1107,7 +1107,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
{
struct hso_serial *serial = tty->driver_data;
struct ktermios *termios;
if (!serial) {
printk(KERN_ERR "%s: no tty structures", __func__);
@ -1119,16 +1118,15 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
/*
* Fix up unsupported bits
*/
termios = tty->termios;
termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
termios->c_cflag &=
tty->termios.c_cflag &=
~(CSIZE /* no size */
| PARENB /* disable parity bit */
| CBAUD /* clear current baud rate */
| CBAUDEX); /* clear current buad rate */
termios->c_cflag |= CS8; /* character size 8 bits */
tty->termios.c_cflag |= CS8; /* character size 8 bits */
/* baud rate 115200 */
tty_encode_baud_rate(tty, 115200, 115200);
@ -1425,14 +1423,14 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
if (old)
D5("Termios called with: cflags new[%d] - old[%d]",
tty->termios->c_cflag, old->c_cflag);
tty->termios.c_cflag, old->c_cflag);
/* the actual setup */
spin_lock_irqsave(&serial->serial_lock, flags);
if (serial->port.count)
_hso_serial_set_termios(tty, old);
else
tty->termios = old;
tty->termios = *old;
spin_unlock_irqrestore(&serial->serial_lock, flags);
/* done */
@ -2289,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
if (minor < 0)
goto exit;
tty_port_init(&serial->port);
/* register our minor number */
serial->parent->dev = tty_register_device(tty_drv, minor,
&serial->parent->interface->dev);
serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
minor, &serial->parent->interface->dev);
dev = serial->parent->dev;
dev_set_drvdata(dev, serial->parent);
i = device_create_file(dev, &dev_attr_hsotype);
@ -2300,7 +2300,6 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->minor = minor;
serial->magic = HSO_SERIAL_MAGIC;
spin_lock_init(&serial->serial_lock);
tty_port_init(&serial->port);
serial->num_rx_urbs = num_urbs;
/* RX, allocate urb and initialize */

View File

@ -271,6 +271,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base,
if (!parport_SPP_supported (p)) {
/* No port. */
kfree (priv);
kfree(ops);
return NULL;
}
parport_PS2_supported (p);

View File

@ -62,6 +62,7 @@ enum parport_pc_pci_cards {
timedia_9079a,
timedia_9079b,
timedia_9079c,
wch_ch353_2s1p,
};
/* each element directly indexed from enum list, above */
@ -145,6 +146,7 @@ static struct parport_pc_pci cards[] __devinitdata = {
/* timedia_9079a */ { 1, { { 2, 3 }, } },
/* timedia_9079b */ { 1, { { 2, 3 }, } },
/* timedia_9079c */ { 1, { { 2, 3 }, } },
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
};
static struct pci_device_id parport_serial_pci_tbl[] = {
@ -243,7 +245,8 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
{ 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
/* WCH CARDS */
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
@ -460,6 +463,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
.base_baud = 921600,
.uart_offset = 8,
},
[wch_ch353_2s1p] = {
.flags = FL_BASE0|FL_BASE_BARS,
.num_ports = 2,
.base_baud = 115200,
.uart_offset = 8,
},
};
struct parport_serial_private {

View File

@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev)
static void raw3215_remove (struct ccw_device *cdev)
{
struct raw3215_info *raw;
unsigned int line;
ccw_device_set_offline(cdev);
raw = dev_get_drvdata(&cdev->dev);
if (raw) {
spin_lock(&raw3215_device_lock);
for (line = 0; line < NR_3215; line++)
if (raw3215[line] == raw)
break;
raw3215[line] = NULL;
spin_unlock(&raw3215_device_lock);
dev_set_drvdata(&cdev->dev, NULL);
raw3215_free_info(raw);
}
@ -935,6 +942,19 @@ static int __init con3215_init(void)
console_initcall(con3215_init);
#endif
static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct raw3215_info *raw;
raw = raw3215[tty->index];
if (raw == NULL)
return -ENODEV;
tty->driver_data = raw;
return tty_port_install(&raw->port, driver, tty);
}
/*
* tty3215_open
*
@ -942,14 +962,9 @@ console_initcall(con3215_init);
*/
static int tty3215_open(struct tty_struct *tty, struct file * filp)
{
struct raw3215_info *raw;
struct raw3215_info *raw = tty->driver_data;
int retval;
raw = raw3215[tty->index];
if (raw == NULL)
return -ENODEV;
tty->driver_data = raw;
tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */
@ -1110,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty)
}
static const struct tty_operations tty3215_ops = {
.install = tty3215_install,
.open = tty3215_open,
.close = tty3215_close,
.write = tty3215_write,

View File

@ -567,6 +567,7 @@ sclp_tty_init(void)
driver->init_termios.c_lflag = ISIG | ECHO;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_ops);
tty_port_link_device(&sclp_port, driver, 0);
rc = tty_register_driver(driver);
if (rc) {
put_tty_driver(driver);

View File

@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void)
driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_vt220_ops);
tty_port_link_device(&sclp_vt220_port, driver, 0);
rc = tty_register_driver(driver);
if (rc)

View File

@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = {
};
/*
* This routine is called whenever a 3270 tty is opened.
* This routine is called whenever a 3270 tty is opened first time.
*/
static int
tty3270_open(struct tty_struct *tty, struct file * filp)
static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct raw3270_view *view;
struct tty3270 *tp;
int i, rc;
if (tty->count > 1)
return 0;
/* Check if the tty3270 is already there. */
view = raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
/* why to reassign? */
tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT;
return 0;
return tty_port_install(&tp->port, driver, tty);
}
if (tty3270_max_index < tty->index + 1)
tty3270_max_index = tty->index + 1;
@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0;
tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols;
@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
kbd_ascebc(tp->kbd, tp->view.ascebc);
raw3270_activate_view(&tp->view);
rc = tty_port_install(&tp->port, driver, tty);
if (rc) {
raw3270_put_view(&tp->view);
return rc;
}
tty->driver_data = tp;
return 0;
}
@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
if (tp) {
tty->driver_data = NULL;
tty_port_tty_set(&tp->port, NULL);
raw3270_put_view(&tp->view);
}
}
static void tty3270_cleanup(struct tty_struct *tty)
{
struct tty3270 *tp = tty->driver_data;
if (tp)
raw3270_put_view(&tp->view);
}
/*
* We always have room.
*/
@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
#endif
static const struct tty_operations tty3270_ops = {
.open = tty3270_open,
.install = tty3270_install,
.cleanup = tty3270_cleanup,
.close = tty3270_close,
.write = tty3270_write,
.put_char = tty3270_put_char,
@ -1781,7 +1794,7 @@ static int __init tty3270_init(void)
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
driver->flags = TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver);
if (ret) {
@ -1800,6 +1813,7 @@ tty3270_exit(void)
driver = tty3270_driver;
tty3270_driver = NULL;
tty_unregister_driver(driver);
put_tty_driver(driver);
tty3270_del_views();
}

View File

@ -142,4 +142,6 @@ source "drivers/staging/ced1401/Kconfig"
source "drivers/staging/imx-drm/Kconfig"
source "drivers/staging/dgrp/Kconfig"
endif # STAGING

View File

@ -63,3 +63,4 @@ obj-$(CONFIG_ZCACHE2) += ramster/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
obj-$(CONFIG_DGRP) += dgrp/

View File

@ -0,0 +1,9 @@
config DGRP
tristate "Digi Realport driver"
default n
depends on SYSFS
---help---
Support for Digi Realport devices. These devices allow you to
access remote serial ports as if they are local tty devices. This
will build the kernel driver, you will still need the userspace
component to make your Realport device work.

View File

@ -0,0 +1,12 @@
obj-$(CONFIG_DGRP) += dgrp.o
dgrp-y := \
dgrp_common.o \
dgrp_dpa_ops.o \
dgrp_driver.o \
dgrp_mon_ops.o \
dgrp_net_ops.o \
dgrp_ports_ops.o \
dgrp_specproc.o \
dgrp_tty.o \
dgrp_sysfs.o

View File

@ -0,0 +1,2 @@
The user space code to work with this driver is located at
https://github.com/wfp5p/dgrp-utils

13
drivers/staging/dgrp/TODO Normal file
View File

@ -0,0 +1,13 @@
- Use configfs for config stuff. This will require changes to the
user space code.
- dgrp_send() and dgrp_receive() could use some refactoring
- Don't automatically create CHAN_MAX (64) channel array entries for
every device as many devices are going to have much less than 64
channels.
- The locking needs to be checked. It seems haphazardly done in most
places.
- Check Kconfig dependencies

View File

@ -0,0 +1,200 @@
/*
*
* Copyright 1999 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/*
*
* Filename:
*
* dgrp_common.c
*
* Description:
*
* Definitions of global variables and functions which are either
* shared by the tty, mon, and net drivers; or which cross them
* functionally (like the poller).
*
* Author:
*
* James A. Puzzo
*
*/
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/cred.h>
#include "dgrp_common.h"
/**
* dgrp_carrier -- check for carrier change state and act
* @ch: struct ch_struct *
*/
void dgrp_carrier(struct ch_struct *ch)
{
struct nd_struct *nd;
int virt_carrier = 0;
int phys_carrier = 0;
/* fix case when the tty has already closed. */
if (!ch)
return;
nd = ch->ch_nd;
if (!nd)
return;
/*
* If we are currently waiting to determine the status of the port,
* we don't yet know the state of the modem lines. As a result,
* we ignore state changes when we are waiting for the modem lines
* to be established. We know, as a result of code in dgrp_net_ops,
* that we will be called again immediately following the reception
* of the status message with the true modem status flags in it.
*/
if (ch->ch_expect & RR_STATUS)
return;
/*
* If CH_HANGUP is set, we gotta keep trying to get all the processes
* that have the port open to close the port.
* So lets just keep sending a hangup every time we get here.
*/
if ((ch->ch_flag & CH_HANGUP) &&
(ch->ch_tun.un_open_count > 0))
tty_hangup(ch->ch_tun.un_tty);
/*
* Compute the effective state of both the physical and virtual
* senses of carrier.
*/
if (ch->ch_s_mlast & DM_CD)
phys_carrier = 1;
if ((ch->ch_s_mlast & DM_CD) ||
(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
(ch->ch_flag & CH_CLOCAL))
virt_carrier = 1;
/*
* Test for a VIRTUAL carrier transition to HIGH.
*
* The CH_HANGUP condition is intended to prevent any action
* except for close. As a result, we ignore positive carrier
* transitions during CH_HANGUP.
*/
if (((ch->ch_flag & CH_HANGUP) == 0) &&
((ch->ch_flag & CH_VIRT_CD) == 0) &&
(virt_carrier == 1)) {
/*
* When carrier rises, wake any threads waiting
* for carrier in the open routine.
*/
nd->nd_tx_work = 1;
if (waitqueue_active(&ch->ch_flag_wait))
wake_up_interruptible(&ch->ch_flag_wait);
}
/*
* Test for a PHYSICAL transition to low, so long as we aren't
* currently ignoring physical transitions (which is what "virtual
* carrier" indicates).
*
* The transition of the virtual carrier to low really doesn't
* matter... it really only means "ignore carrier state", not
* "make pretend that carrier is there".
*/
if ((virt_carrier == 0) &&
((ch->ch_flag & CH_PHYS_CD) != 0) &&
(phys_carrier == 0)) {
/*
* When carrier drops:
*
* Do a Hard Hangup if that is called for.
*
* Drop carrier on all open units.
*
* Flush queues, waking up any task waiting in the
* line discipline.
*
* Send a hangup to the control terminal.
*
* Enable all select calls.
*/
nd->nd_tx_work = 1;
ch->ch_flag &= ~(CH_LOW | CH_EMPTY | CH_DRAIN | CH_INPUT);
if (waitqueue_active(&ch->ch_flag_wait))
wake_up_interruptible(&ch->ch_flag_wait);
if (ch->ch_tun.un_open_count > 0)
tty_hangup(ch->ch_tun.un_tty);
if (ch->ch_pun.un_open_count > 0)
tty_hangup(ch->ch_pun.un_tty);
}
/*
* Make sure that our cached values reflect the current reality.
*/
if (virt_carrier == 1)
ch->ch_flag |= CH_VIRT_CD;
else
ch->ch_flag &= ~CH_VIRT_CD;
if (phys_carrier == 1)
ch->ch_flag |= CH_PHYS_CD;
else
ch->ch_flag &= ~CH_PHYS_CD;
}
/**
* dgrp_chk_perm() -- check permissions for net device
* @inode: pointer to inode structure for the net communication device
* @op: operation to be tested
*
* The file permissions and ownerships are tested to determine whether
* the operation "op" is permitted on the file pointed to by the inode.
* Returns 0 if the operation is permitted, -EACCESS otherwise
*/
int dgrp_chk_perm(int mode, int op)
{
if (!current_euid())
mode >>= 6;
else if (in_egroup_p(0))
mode >>= 3;
if ((mode & op & 0007) == op)
return 0;
if (capable(CAP_SYS_ADMIN))
return 0;
return -EACCES;
}
/* dgrp_chk_perm wrapper for permission call in struct inode_operations */
int dgrp_inode_permission(struct inode *inode, int op)
{
return dgrp_chk_perm(inode->i_mode, op);
}

View File

@ -0,0 +1,208 @@
/*
*
* Copyright 1999 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
#ifndef __DGRP_COMMON_H
#define __DGRP_COMMON_H
#define DIGI_VERSION "1.9-29"
#include <linux/fs.h>
#include <linux/timer.h>
#include "drp.h"
#define DGRP_TTIME 100
#define DGRP_RTIME 100
/************************************************************************
* All global storage allocation.
************************************************************************/
extern int dgrp_rawreadok; /* Allow raw writing of input */
extern int dgrp_register_cudevices; /* enable legacy cu devices */
extern int dgrp_register_prdevices; /* enable transparent print devices */
extern int dgrp_poll_tick; /* Poll interval - in ms */
extern struct list_head nd_struct_list;
struct dgrp_poll_data {
spinlock_t poll_lock;
struct timer_list timer;
int poll_tick;
ulong poll_round; /* Timer rouding factor */
long node_active_count;
};
extern struct dgrp_poll_data dgrp_poll_data;
extern void dgrp_poll_handler(unsigned long arg);
/* from dgrp_mon_ops.c */
extern void dgrp_register_mon_hook(struct proc_dir_entry *de);
/* from dgrp_tty.c */
extern int dgrp_tty_init(struct nd_struct *nd);
extern void dgrp_tty_uninit(struct nd_struct *nd);
/* from dgrp_ports_ops.c */
extern void dgrp_register_ports_hook(struct proc_dir_entry *de);
/* from dgrp_net_ops.c */
extern void dgrp_register_net_hook(struct proc_dir_entry *de);
/* from dgrp_dpa_ops.c */
extern void dgrp_register_dpa_hook(struct proc_dir_entry *de);
extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int);
/* from dgrp_sysfs.c */
extern void dgrp_create_class_sysfs_files(void);
extern void dgrp_remove_class_sysfs_files(void);
extern void dgrp_create_node_class_sysfs_files(struct nd_struct *nd);
extern void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd);
extern void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c);
extern void dgrp_remove_tty_sysfs(struct device *c);
/* from dgrp_specproc.c */
/*
* The list of DGRP entries with r/w capabilities. These
* magic numbers are used for identification purposes.
*/
enum {
DGRP_CONFIG = 1, /* Configure portservers */
DGRP_NETDIR = 2, /* Directory for "net" devices */
DGRP_MONDIR = 3, /* Directory for "mon" devices */
DGRP_PORTSDIR = 4, /* Directory for "ports" devices */
DGRP_INFO = 5, /* Get info. about the running module */
DGRP_NODEINFO = 6, /* Get info. about the configured nodes */
DGRP_DPADIR = 7, /* Directory for the "dpa" devices */
};
/*
* Directions for proc handlers
*/
enum {
INBOUND = 1, /* Data being written to kernel */
OUTBOUND = 2, /* Data being read from the kernel */
};
/**
* dgrp_proc_entry: structure for dgrp proc dirs
* @id: ID number associated with this particular entry. Should be
* unique across all of DGRP.
* @name: text name associated with the /proc entry
* @mode: file access permisssions for the /proc entry
* @child: pointer to table describing a subdirectory for this entry
* @de: pointer to directory entry for this object once registered. Used
* to grab the handle of the object for unregistration
* @excl_sem: semaphore to provide exclusive to struct
* @excl_cnt: counter of current accesses
*
* Each entry in a DGRP proc directory is described with a
* dgrp_proc_entry structure. A collection of these
* entries (in an array) represents the members associated
* with a particular /proc directory, and is referred to
* as a table. All tables are terminated by an entry with
* zeros for every member.
*/
struct dgrp_proc_entry {
int id; /* Integer identifier */
const char *name; /* ASCII identifier */
mode_t mode; /* File access permissions */
struct dgrp_proc_entry *child; /* Child pointer */
/* file ops to use, pass NULL to use default */
struct file_operations *proc_file_ops;
struct proc_dir_entry *de; /* proc entry pointer */
struct semaphore excl_sem; /* Protects exclusive access var */
int excl_cnt; /* Counts number of curr accesses */
};
extern void dgrp_unregister_proc(void);
extern void dgrp_register_proc(void);
/*-----------------------------------------------------------------------*
*
* Declarations for common operations:
*
* (either used by more than one of net, mon, or tty,
* or in interrupt context (i.e. the poller))
*
*-----------------------------------------------------------------------*/
void dgrp_carrier(struct ch_struct *ch);
extern int dgrp_inode_permission(struct inode *inode, int op);
extern int dgrp_chk_perm(int mode, int op);
/*
* ID manipulation macros (where c1 & c2 are characters, i is
* a long integer, and s is a character array of at least three members
*/
static inline void ID_TO_CHAR(long i, char *s)
{
s[0] = ((i & 0xff00)>>8);
s[1] = (i & 0xff);
s[2] = 0;
}
static inline long CHAR_TO_ID(char *s)
{
return ((s[0] & 0xff) << 8) | (s[1] & 0xff);
}
static inline struct nd_struct *nd_struct_get(long major)
{
struct nd_struct *nd;
list_for_each_entry(nd, &nd_struct_list, list) {
if (major == nd->nd_major)
return nd;
}
return NULL;
}
static inline int nd_struct_add(struct nd_struct *entry)
{
struct nd_struct *ptr;
ptr = nd_struct_get(entry->nd_major);
if (ptr)
return -EBUSY;
list_add_tail(&entry->list, &nd_struct_list);
return 0;
}
static inline int nd_struct_del(struct nd_struct *entry)
{
struct nd_struct *nd;
nd = nd_struct_get(entry->nd_major);
if (!nd)
return -ENODEV;
list_del(&nd->list);
return 0;
}
#endif /* __DGRP_COMMON_H */

View File

@ -0,0 +1,556 @@
/*
*
* Copyright 1999 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/*
*
* Filename:
*
* dgrp_dpa_ops.c
*
* Description:
*
* Handle the file operations required for the "dpa" devices.
* Includes those functions required to register the "dpa" devices
* in "/proc".
*
* Author:
*
* James A. Puzzo
*
*/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/tty.h>
#include <linux/poll.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/ratelimit.h>
#include <asm/unaligned.h>
#include "dgrp_common.h"
/* File operation declarations */
static int dgrp_dpa_open(struct inode *, struct file *);
static int dgrp_dpa_release(struct inode *, struct file *);
static ssize_t dgrp_dpa_read(struct file *, char __user *, size_t, loff_t *);
static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
static unsigned int dgrp_dpa_select(struct file *, struct poll_table_struct *);
static const struct file_operations dpa_ops = {
.owner = THIS_MODULE,
.read = dgrp_dpa_read,
.poll = dgrp_dpa_select,
.unlocked_ioctl = dgrp_dpa_ioctl,
.open = dgrp_dpa_open,
.release = dgrp_dpa_release,
};
static struct inode_operations dpa_inode_ops = {
.permission = dgrp_inode_permission
};
struct digi_node {
uint nd_state; /* Node state: 1 = up, 0 = down. */
uint nd_chan_count; /* Number of channels found */
uint nd_tx_byte; /* Tx data count */
uint nd_rx_byte; /* RX data count */
u8 nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */
};
#define DIGI_GETNODE (('d'<<8) | 249) /* get board info */
struct digi_chan {
uint ch_port; /* Port number to get info on */
uint ch_open; /* 1 if open, 0 if not */
uint ch_txcount; /* TX data count */
uint ch_rxcount; /* RX data count */
uint ch_s_brate; /* Realport BRATE */
uint ch_s_estat; /* Realport ELAST */
uint ch_s_cflag; /* Realport CFLAG */
uint ch_s_iflag; /* Realport IFLAG */
uint ch_s_oflag; /* Realport OFLAG */
uint ch_s_xflag; /* Realport XFLAG */
uint ch_s_mstat; /* Realport MLAST */
};
#define DIGI_GETCHAN (('d'<<8) | 248) /* get channel info */
struct digi_vpd {
int vpd_len;
char vpd_data[VPDSIZE];
};
#define DIGI_GETVPD (('d'<<8) | 246) /* get VPD info */
struct digi_debug {
int onoff;
int port;
};
#define DIGI_SETDEBUG (('d'<<8) | 247) /* set debug info */
void dgrp_register_dpa_hook(struct proc_dir_entry *de)
{
struct nd_struct *node = de->data;
de->proc_iops = &dpa_inode_ops;
de->proc_fops = &dpa_ops;
node->nd_dpa_de = de;
spin_lock_init(&node->nd_dpa_lock);
}
/*
* dgrp_dpa_open -- open the DPA device for a particular PortServer
*/
static int dgrp_dpa_open(struct inode *inode, struct file *file)
{
struct nd_struct *nd;
int rtn = 0;
struct proc_dir_entry *de;
rtn = try_module_get(THIS_MODULE);
if (!rtn)
return -ENXIO;
rtn = 0;
if (!capable(CAP_SYS_ADMIN)) {
rtn = -EPERM;
goto done;
}
/*
* Make sure that the "private_data" field hasn't already been used.
*/
if (file->private_data) {
rtn = -EINVAL;
goto done;
}
/*
* Get the node pointer, and fail if it doesn't exist.
*/
de = PDE(inode);
if (!de) {
rtn = -ENXIO;
goto done;
}
nd = (struct nd_struct *)de->data;
if (!nd) {
rtn = -ENXIO;
goto done;
}
file->private_data = (void *) nd;
/*
* Allocate the DPA buffer.
*/
if (nd->nd_dpa_buf) {
rtn = -EBUSY;
} else {
nd->nd_dpa_buf = kmalloc(DPA_MAX, GFP_KERNEL);
if (!nd->nd_dpa_buf) {
rtn = -ENOMEM;
} else {
nd->nd_dpa_out = 0;
nd->nd_dpa_in = 0;
nd->nd_dpa_lbolt = jiffies;
}
}
done:
if (rtn)
module_put(THIS_MODULE);
return rtn;
}
/*
* dgrp_dpa_release -- close the DPA device for a particular PortServer
*/
static int dgrp_dpa_release(struct inode *inode, struct file *file)
{
struct nd_struct *nd;
u8 *buf;
unsigned long lock_flags;
/*
* Get the node pointer, and quit if it doesn't exist.
*/
nd = (struct nd_struct *)(file->private_data);
if (!nd)
goto done;
/*
* Free the dpa buffer.
*/
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
buf = nd->nd_dpa_buf;
nd->nd_dpa_buf = NULL;
nd->nd_dpa_out = nd->nd_dpa_in;
/*
* Wakeup any thread waiting for buffer space.
*/
if (nd->nd_dpa_flag & DPA_WAIT_SPACE) {
nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
wake_up_interruptible(&nd->nd_dpa_wqueue);
}
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
kfree(buf);
done:
module_put(THIS_MODULE);
file->private_data = NULL;
return 0;
}
/*
* dgrp_dpa_read
*
* Copy data from the monitoring buffer to the user, freeing space
* in the monitoring buffer for more messages
*/
static ssize_t dgrp_dpa_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct nd_struct *nd;
int n;
int r;
int offset = 0;
int res = 0;
ssize_t rtn;
unsigned long lock_flags;
/*
* Get the node pointer, and quit if it doesn't exist.
*/
nd = (struct nd_struct *)(file->private_data);
if (!nd)
return -ENXIO;
/*
* Wait for some data to appear in the buffer.
*/
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
for (;;) {
n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
if (n != 0)
break;
nd->nd_dpa_flag |= DPA_WAIT_DATA;
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
/*
* Go to sleep waiting until the condition becomes true.
*/
rtn = wait_event_interruptible(nd->nd_dpa_wqueue,
((nd->nd_dpa_flag & DPA_WAIT_DATA) == 0));
if (rtn)
return rtn;
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
}
/*
* Read whatever is there.
*/
if (n > count)
n = count;
res = n;
r = DPA_MAX - nd->nd_dpa_out;
if (r <= n) {
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
rtn = copy_to_user((void __user *)buf,
nd->nd_dpa_buf + nd->nd_dpa_out, r);
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
if (rtn) {
rtn = -EFAULT;
goto done;
}
nd->nd_dpa_out = 0;
n -= r;
offset = r;
}
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
rtn = copy_to_user((void __user *)buf + offset,
nd->nd_dpa_buf + nd->nd_dpa_out, n);
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
if (rtn) {
rtn = -EFAULT;
goto done;
}
nd->nd_dpa_out += n;
*ppos += res;
rtn = res;
/*
* Wakeup any thread waiting for buffer space.
*/
n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK;
if (nd->nd_dpa_flag & DPA_WAIT_SPACE &&
(DPA_MAX - n) > DPA_HIGH_WATER) {
nd->nd_dpa_flag &= ~DPA_WAIT_SPACE;
wake_up_interruptible(&nd->nd_dpa_wqueue);
}
done:
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
return rtn;
}
static unsigned int dgrp_dpa_select(struct file *file,
struct poll_table_struct *table)
{
unsigned int retval = 0;
struct nd_struct *nd = file->private_data;
if (nd->nd_dpa_out != nd->nd_dpa_in)
retval |= POLLIN | POLLRDNORM; /* Conditionally readable */
retval |= POLLOUT | POLLWRNORM; /* Always writeable */
return retval;
}
static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct nd_struct *nd;
struct digi_chan getchan;
struct digi_node getnode;
struct ch_struct *ch;
struct digi_debug setdebug;
struct digi_vpd vpd;
unsigned int port;
void __user *uarg = (void __user *) arg;
nd = file->private_data;
switch (cmd) {
case DIGI_GETCHAN:
if (copy_from_user(&getchan, uarg, sizeof(struct digi_chan)))
return -EFAULT;
port = getchan.ch_port;
if (port < 0 || port > nd->nd_chan_count)
return -EINVAL;
ch = nd->nd_chan + port;
getchan.ch_open = (ch->ch_open_count > 0) ? 1 : 0;
getchan.ch_txcount = ch->ch_txcount;
getchan.ch_rxcount = ch->ch_rxcount;
getchan.ch_s_brate = ch->ch_s_brate;
getchan.ch_s_estat = ch->ch_s_elast;
getchan.ch_s_cflag = ch->ch_s_cflag;
getchan.ch_s_iflag = ch->ch_s_iflag;
getchan.ch_s_oflag = ch->ch_s_oflag;
getchan.ch_s_xflag = ch->ch_s_xflag;
getchan.ch_s_mstat = ch->ch_s_mlast;
if (copy_to_user(uarg, &getchan, sizeof(struct digi_chan)))
return -EFAULT;
break;
case DIGI_GETNODE:
getnode.nd_state = (nd->nd_state & NS_READY) ? 1 : 0;
getnode.nd_chan_count = nd->nd_chan_count;
getnode.nd_tx_byte = nd->nd_tx_byte;
getnode.nd_rx_byte = nd->nd_rx_byte;
memset(&getnode.nd_ps_desc, 0, MAX_DESC_LEN);
strncpy(getnode.nd_ps_desc, nd->nd_ps_desc, MAX_DESC_LEN);
if (copy_to_user(uarg, &getnode, sizeof(struct digi_node)))
return -EFAULT;
break;
case DIGI_SETDEBUG:
if (copy_from_user(&setdebug, uarg, sizeof(struct digi_debug)))
return -EFAULT;
nd->nd_dpa_debug = setdebug.onoff;
nd->nd_dpa_port = setdebug.port;
break;
case DIGI_GETVPD:
if (nd->nd_vpd_len > 0) {
vpd.vpd_len = nd->nd_vpd_len;
memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len);
} else {
vpd.vpd_len = 0;
}
if (copy_to_user(uarg, &vpd, sizeof(struct digi_vpd)))
return -EFAULT;
break;
}
return 0;
}
/**
* dgrp_dpa() -- send data to the device monitor queue
* @nd: pointer to a node structure
* @buf: buffer of data to copy to the monitoring buffer
* @len: number of bytes to transfer to the buffer
*
* Called by the net device routines to send data to the device
* monitor queue. If the device monitor buffer is too full to
* accept the data, it waits until the buffer is ready.
*/
static void dgrp_dpa(struct nd_struct *nd, u8 *buf, int nbuf)
{
int n;
int r;
unsigned long lock_flags;
/*
* Grab DPA lock.
*/
spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags);
/*
* Loop while data remains.
*/
while (nbuf > 0 && nd->nd_dpa_buf != NULL) {
n = (nd->nd_dpa_out - nd->nd_dpa_in - 1) & DPA_MASK;
/*
* Enforce flow control on the DPA device.
*/
if (n < (DPA_MAX - DPA_HIGH_WATER))
nd->nd_dpa_flag |= DPA_WAIT_SPACE;
/*
* This should never happen, as the flow control above
* should have stopped things before they got to this point.
*/
if (n == 0) {
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
return;
}
/*
* Copy as much data as will fit.
*/
if (n > nbuf)
n = nbuf;
r = DPA_MAX - nd->nd_dpa_in;
if (r <= n) {
memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, r);
n -= r;
nd->nd_dpa_in = 0;
buf += r;
nbuf -= r;
}
memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, n);
nd->nd_dpa_in += n;
buf += n;
nbuf -= n;
if (nd->nd_dpa_in >= DPA_MAX)
pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n",
__func__, nd->nd_dpa_in);
/*
* Wakeup any thread waiting for data
*/
if (nd->nd_dpa_flag & DPA_WAIT_DATA) {
nd->nd_dpa_flag &= ~DPA_WAIT_DATA;
wake_up_interruptible(&nd->nd_dpa_wqueue);
}
}
/*
* Release the DPA lock.
*/
spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags);
}
/**
* dgrp_monitor_data() -- builds a DPA data packet
* @nd: pointer to a node structure
* @type: type of message to be logged in the DPA buffer
* @buf: buffer of data to be logged in the DPA buffer
* @size -- number of bytes in the "buf" buffer
*/
void dgrp_dpa_data(struct nd_struct *nd, int type, u8 *buf, int size)
{
u8 header[5];
header[0] = type;
put_unaligned_be32(size, header + 1);
dgrp_dpa(nd, header, sizeof(header));
dgrp_dpa(nd, buf, size);
}

View File

@ -0,0 +1,110 @@
/*
*
* Copyright 1999-2003 Digi International (www.digi.com)
* Jeff Randall
* James Puzzo <jamesp at digi dot com>
* Scott Kilau <Scott_Kilau at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/*
* Driver specific includes
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/init.h>
/*
* PortServer includes
*/
#include "dgrp_common.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Digi International, http://www.digi.com");
MODULE_DESCRIPTION("RealPort driver for Digi's ethernet-based serial connectivity product line");
MODULE_VERSION(DIGI_VERSION);
struct list_head nd_struct_list;
struct dgrp_poll_data dgrp_poll_data;
int dgrp_rawreadok = 1; /* Bypass flipbuf on input */
int dgrp_register_cudevices = 1;/* Turn on/off registering legacy cu devices */
int dgrp_register_prdevices = 1;/* Turn on/off registering transparent print */
int dgrp_poll_tick = 20; /* Poll interval - in ms */
module_param_named(rawreadok, dgrp_rawreadok, int, 0644);
MODULE_PARM_DESC(rawreadok, "Bypass flip buffers on input");
module_param_named(register_cudevices, dgrp_register_cudevices, int, 0644);
MODULE_PARM_DESC(register_cudevices, "Turn on/off registering legacy cu devices");
module_param_named(register_prdevices, dgrp_register_prdevices, int, 0644);
MODULE_PARM_DESC(register_prdevices, "Turn on/off registering transparent print devices");
module_param_named(pollrate, dgrp_poll_tick, int, 0644);
MODULE_PARM_DESC(pollrate, "Poll interval in ms");
/* Driver load/unload functions */
static int dgrp_init_module(void);
static void dgrp_cleanup_module(void);
module_init(dgrp_init_module);
module_exit(dgrp_cleanup_module);
/*
* init_module()
*
* Module load. This is where it all starts.
*/
static int dgrp_init_module(void)
{
INIT_LIST_HEAD(&nd_struct_list);
spin_lock_init(&dgrp_poll_data.poll_lock);
init_timer(&dgrp_poll_data.timer);
dgrp_poll_data.poll_tick = dgrp_poll_tick;
dgrp_poll_data.timer.function = dgrp_poll_handler;
dgrp_poll_data.timer.data = (unsigned long) &dgrp_poll_data;
dgrp_create_class_sysfs_files();
dgrp_register_proc();
return 0;
}
/*
* Module unload. This is where it all ends.
*/
static void dgrp_cleanup_module(void)
{
struct nd_struct *nd, *next;
/*
* Attempting to free resources in backwards
* order of allocation, in case that helps
* memory pool fragmentation.
*/
dgrp_unregister_proc();
dgrp_remove_class_sysfs_files();
list_for_each_entry_safe(nd, next, &nd_struct_list, list) {
dgrp_tty_uninit(nd);
kfree(nd);
}
}

View File

@ -0,0 +1,346 @@
/*****************************************************************************
*
* Copyright 1999 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/*
*
* Filename:
*
* dgrp_mon_ops.c
*
* Description:
*
* Handle the file operations required for the "monitor" devices.
* Includes those functions required to register the "mon" devices
* in "/proc".
*
* Author:
*
* James A. Puzzo
*
*/
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <asm/unaligned.h>
#include <linux/proc_fs.h>
#include "dgrp_common.h"
/* File operation declarations */
static int dgrp_mon_open(struct inode *, struct file *);
static int dgrp_mon_release(struct inode *, struct file *);
static ssize_t dgrp_mon_read(struct file *, char __user *, size_t, loff_t *);
static long dgrp_mon_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
static const struct file_operations mon_ops = {
.owner = THIS_MODULE,
.read = dgrp_mon_read,
.unlocked_ioctl = dgrp_mon_ioctl,
.open = dgrp_mon_open,
.release = dgrp_mon_release,
};
static struct inode_operations mon_inode_ops = {
.permission = dgrp_inode_permission
};
void dgrp_register_mon_hook(struct proc_dir_entry *de)
{
struct nd_struct *node = de->data;
de->proc_iops = &mon_inode_ops;
de->proc_fops = &mon_ops;
node->nd_mon_de = de;
sema_init(&node->nd_mon_semaphore, 1);
}
/**
* dgrp_mon_open() -- open /proc/dgrp/ports device for a PortServer
* @inode: struct inode *
* @file: struct file *
*
* Open function to open the /proc/dgrp/ports device for a PortServer.
*/
static int dgrp_mon_open(struct inode *inode, struct file *file)
{
struct nd_struct *nd;
struct proc_dir_entry *de;
struct timeval tv;
uint32_t time;
u8 *buf;
int rtn;
rtn = try_module_get(THIS_MODULE);
if (!rtn)
return -ENXIO;
rtn = 0;
if (!capable(CAP_SYS_ADMIN)) {
rtn = -EPERM;
goto done;
}
/*
* Make sure that the "private_data" field hasn't already been used.
*/
if (file->private_data) {
rtn = -EINVAL;
goto done;
}
/*
* Get the node pointer, and fail if it doesn't exist.
*/
de = PDE(inode);
if (!de) {
rtn = -ENXIO;
goto done;
}
nd = (struct nd_struct *)de->data;
if (!nd) {
rtn = -ENXIO;
goto done;
}
file->private_data = (void *) nd;
/*
* Allocate the monitor buffer.
*/
/*
* Grab the MON lock.
*/
down(&nd->nd_mon_semaphore);
if (nd->nd_mon_buf) {
rtn = -EBUSY;
goto done_up;
}
nd->nd_mon_buf = kmalloc(MON_MAX, GFP_KERNEL);
if (!nd->nd_mon_buf) {
rtn = -ENOMEM;
goto done_up;
}
/*
* Enter an RPDUMP file header into the buffer.
*/
buf = nd->nd_mon_buf;
strcpy(buf, RPDUMP_MAGIC);
buf += strlen(buf) + 1;
do_gettimeofday(&tv);
/*
* tv.tv_sec might be a 64 bit quantity. Pare
* it down to 32 bits before attempting to encode
* it.
*/
time = (uint32_t) (tv.tv_sec & 0xffffffff);
put_unaligned_be32(time, buf);
put_unaligned_be16(0, buf + 4);
buf += 6;
if (nd->nd_tx_module) {
buf[0] = RPDUMP_CLIENT;
put_unaligned_be32(0, buf + 1);
put_unaligned_be16(1, buf + 5);
buf[7] = 0xf0 + nd->nd_tx_module;
buf += 8;
}
if (nd->nd_rx_module) {
buf[0] = RPDUMP_SERVER;
put_unaligned_be32(0, buf + 1);
put_unaligned_be16(1, buf + 5);
buf[7] = 0xf0 + nd->nd_rx_module;
buf += 8;
}
nd->nd_mon_out = 0;
nd->nd_mon_in = buf - nd->nd_mon_buf;
nd->nd_mon_lbolt = jiffies;
done_up:
up(&nd->nd_mon_semaphore);
done:
if (rtn)
module_put(THIS_MODULE);
return rtn;
}
/**
* dgrp_mon_release() - Close the MON device for a particular PortServer
* @inode: struct inode *
* @file: struct file *
*/
static int dgrp_mon_release(struct inode *inode, struct file *file)
{
struct nd_struct *nd;
/*
* Get the node pointer, and quit if it doesn't exist.
*/
nd = (struct nd_struct *)(file->private_data);
if (!nd)
goto done;
/*
* Free the monitor buffer.
*/
down(&nd->nd_mon_semaphore);
kfree(nd->nd_mon_buf);
nd->nd_mon_buf = NULL;
nd->nd_mon_out = nd->nd_mon_in;
/*
* Wakeup any thread waiting for buffer space.
*/
if (nd->nd_mon_flag & MON_WAIT_SPACE) {
nd->nd_mon_flag &= ~MON_WAIT_SPACE;
wake_up_interruptible(&nd->nd_mon_wqueue);
}
up(&nd->nd_mon_semaphore);
/*
* Make sure there is no thread in the middle of writing a packet.
*/
down(&nd->nd_net_semaphore);
up(&nd->nd_net_semaphore);
done:
module_put(THIS_MODULE);
file->private_data = NULL;
return 0;
}
/**
* dgrp_mon_read() -- Copy data from the monitoring buffer to the user
*/
static ssize_t dgrp_mon_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct nd_struct *nd;
int r;
int offset = 0;
int res = 0;
ssize_t rtn;
/*
* Get the node pointer, and quit if it doesn't exist.
*/
nd = (struct nd_struct *)(file->private_data);
if (!nd)
return -ENXIO;
/*
* Wait for some data to appear in the buffer.
*/
down(&nd->nd_mon_semaphore);
for (;;) {
res = (nd->nd_mon_in - nd->nd_mon_out) & MON_MASK;
if (res)
break;
nd->nd_mon_flag |= MON_WAIT_DATA;
up(&nd->nd_mon_semaphore);
/*
* Go to sleep waiting until the condition becomes true.
*/
rtn = wait_event_interruptible(nd->nd_mon_wqueue,
((nd->nd_mon_flag & MON_WAIT_DATA) == 0));
if (rtn)
return rtn;
down(&nd->nd_mon_semaphore);
}
/*
* Read whatever is there.
*/
if (res > count)
res = count;
r = MON_MAX - nd->nd_mon_out;
if (r <= res) {
rtn = copy_to_user((void __user *)buf,
nd->nd_mon_buf + nd->nd_mon_out, r);
if (rtn) {
up(&nd->nd_mon_semaphore);
return -EFAULT;
}
nd->nd_mon_out = 0;
res -= r;
offset = r;
}
rtn = copy_to_user((void __user *) buf + offset,
nd->nd_mon_buf + nd->nd_mon_out, res);
if (rtn) {
up(&nd->nd_mon_semaphore);
return -EFAULT;
}
nd->nd_mon_out += res;
*ppos += res;
up(&nd->nd_mon_semaphore);
/*
* Wakeup any thread waiting for buffer space.
*/
if (nd->nd_mon_flag & MON_WAIT_SPACE) {
nd->nd_mon_flag &= ~MON_WAIT_SPACE;
wake_up_interruptible(&nd->nd_mon_wqueue);
}
return res;
}
/* ioctl is not valid on monitor device */
static long dgrp_mon_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return -EINVAL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
/*
*
* Copyright 1999-2000 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
*
* Filename:
*
* dgrp_ports_ops.c
*
* Description:
*
* Handle the file operations required for the /proc/dgrp/ports/...
* devices. Basically gathers tty status for the node and returns it.
*
* Author:
*
* James A. Puzzo
*
*/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include "dgrp_common.h"
/* File operation declarations */
static int dgrp_ports_open(struct inode *, struct file *);
static const struct file_operations ports_ops = {
.owner = THIS_MODULE,
.open = dgrp_ports_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
static struct inode_operations ports_inode_ops = {
.permission = dgrp_inode_permission
};
void dgrp_register_ports_hook(struct proc_dir_entry *de)
{
struct nd_struct *node = de->data;
de->proc_iops = &ports_inode_ops;
de->proc_fops = &ports_ops;
node->nd_ports_de = de;
}
static void *dgrp_ports_seq_start(struct seq_file *seq, loff_t *pos)
{
if (*pos == 0)
seq_puts(seq, "#num tty_open pr_open tot_wait MSTAT IFLAG OFLAG CFLAG BPS DIGIFLAGS\n");
return pos;
}
static void *dgrp_ports_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct nd_struct *nd = seq->private;
if (*pos >= nd->nd_chan_count)
return NULL;
*pos += 1;
return pos;
}
static void dgrp_ports_seq_stop(struct seq_file *seq, void *v)
{
}
static int dgrp_ports_seq_show(struct seq_file *seq, void *v)
{
loff_t *pos = v;
struct nd_struct *nd;
struct ch_struct *ch;
struct un_struct *tun, *pun;
unsigned int totcnt;
nd = seq->private;
if (!nd)
return 0;
if (*pos >= nd->nd_chan_count)
return 0;
ch = &nd->nd_chan[*pos];
tun = &ch->ch_tun;
pun = &ch->ch_pun;
/*
* If port is not open and no one is waiting to
* open it, the modem signal values can't be
* trusted, and will be zeroed.
*/
totcnt = tun->un_open_count +
pun->un_open_count +
ch->ch_wait_count[0] +
ch->ch_wait_count[1] +
ch->ch_wait_count[2];
seq_printf(seq, "%02d %02d %02d %02d 0x%04X 0x%04X 0x%04X 0x%04X %-6d 0x%04X\n",
(int) *pos,
tun->un_open_count,
pun->un_open_count,
ch->ch_wait_count[0] +
ch->ch_wait_count[1] +
ch->ch_wait_count[2],
(totcnt ? ch->ch_s_mlast : 0),
ch->ch_s_iflag,
ch->ch_s_oflag,
ch->ch_s_cflag,
(ch->ch_s_brate ? (1843200 / ch->ch_s_brate) : 0),
ch->ch_digi.digi_flags);
return 0;
}
static const struct seq_operations ports_seq_ops = {
.start = dgrp_ports_seq_start,
.next = dgrp_ports_seq_next,
.stop = dgrp_ports_seq_stop,
.show = dgrp_ports_seq_show,
};
/**
* dgrp_ports_open -- open the /proc/dgrp/ports/... device
* @inode: struct inode *
* @file: struct file *
*
* Open function to open the /proc/dgrp/ports device for a PortServer.
* This is the open function for struct file_operations
*/
static int dgrp_ports_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rtn;
rtn = seq_open(file, &ports_seq_ops);
if (!rtn) {
seq = file->private_data;
seq->private = PDE(inode)->data;
}
return rtn;
}

View File

@ -0,0 +1,822 @@
/*
*
* Copyright 1999 Digi International (www.digi.com)
* James Puzzo <jamesp at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/*
*
* Filename:
*
* dgrp_specproc.c
*
* Description:
*
* Handle the "config" proc entry for the linux realport device driver
* and provide slots for the "net" and "mon" devices
*
* Author:
*
* James A. Puzzo
*
*/
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
#include "dgrp_common.h"
static struct dgrp_proc_entry dgrp_table[];
static struct proc_dir_entry *dgrp_proc_dir_entry;
static int dgrp_add_id(long id);
static int dgrp_remove_nd(struct nd_struct *nd);
static void unregister_dgrp_device(struct proc_dir_entry *de);
static void register_dgrp_device(struct nd_struct *node,
struct proc_dir_entry *root,
void (*register_hook)(struct proc_dir_entry *de));
/* File operation declarations */
static int dgrp_gen_proc_open(struct inode *, struct file *);
static int dgrp_gen_proc_close(struct inode *, struct file *);
static int parse_write_config(char *);
static const struct file_operations dgrp_proc_file_ops = {
.owner = THIS_MODULE,
.open = dgrp_gen_proc_open,
.release = dgrp_gen_proc_close,
};
static struct inode_operations proc_inode_ops = {
.permission = dgrp_inode_permission
};
static void register_proc_table(struct dgrp_proc_entry *,
struct proc_dir_entry *);
static void unregister_proc_table(struct dgrp_proc_entry *,
struct proc_dir_entry *);
static struct dgrp_proc_entry dgrp_net_table[];
static struct dgrp_proc_entry dgrp_mon_table[];
static struct dgrp_proc_entry dgrp_ports_table[];
static struct dgrp_proc_entry dgrp_dpa_table[];
static ssize_t config_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos);
static int nodeinfo_proc_open(struct inode *inode, struct file *file);
static int info_proc_open(struct inode *inode, struct file *file);
static int config_proc_open(struct inode *inode, struct file *file);
static struct file_operations config_proc_file_ops = {
.owner = THIS_MODULE,
.open = config_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.write = config_proc_write
};
static struct file_operations info_proc_file_ops = {
.owner = THIS_MODULE,
.open = info_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static struct file_operations nodeinfo_proc_file_ops = {
.owner = THIS_MODULE,
.open = nodeinfo_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static struct dgrp_proc_entry dgrp_table[] = {
{
.id = DGRP_CONFIG,
.name = "config",
.mode = 0644,
.proc_file_ops = &config_proc_file_ops,
},
{
.id = DGRP_INFO,
.name = "info",
.mode = 0644,
.proc_file_ops = &info_proc_file_ops,
},
{
.id = DGRP_NODEINFO,
.name = "nodeinfo",
.mode = 0644,
.proc_file_ops = &nodeinfo_proc_file_ops,
},
{
.id = DGRP_NETDIR,
.name = "net",
.mode = 0500,
.child = dgrp_net_table
},
{
.id = DGRP_MONDIR,
.name = "mon",
.mode = 0500,
.child = dgrp_mon_table
},
{
.id = DGRP_PORTSDIR,
.name = "ports",
.mode = 0500,
.child = dgrp_ports_table
},
{
.id = DGRP_DPADIR,
.name = "dpa",
.mode = 0500,
.child = dgrp_dpa_table
}
};
static struct proc_dir_entry *net_entry_pointer;
static struct proc_dir_entry *mon_entry_pointer;
static struct proc_dir_entry *dpa_entry_pointer;
static struct proc_dir_entry *ports_entry_pointer;
static struct dgrp_proc_entry dgrp_net_table[] = {
{0}
};
static struct dgrp_proc_entry dgrp_mon_table[] = {
{0}
};
static struct dgrp_proc_entry dgrp_ports_table[] = {
{0}
};
static struct dgrp_proc_entry dgrp_dpa_table[] = {
{0}
};
void dgrp_unregister_proc(void)
{
unregister_proc_table(dgrp_table, dgrp_proc_dir_entry);
net_entry_pointer = NULL;
mon_entry_pointer = NULL;
dpa_entry_pointer = NULL;
ports_entry_pointer = NULL;
if (dgrp_proc_dir_entry) {
remove_proc_entry(dgrp_proc_dir_entry->name,
dgrp_proc_dir_entry->parent);
dgrp_proc_dir_entry = NULL;
}
}
void dgrp_register_proc(void)
{
/*
* Register /proc/dgrp
*/
dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL,
&dgrp_proc_file_ops);
register_proc_table(dgrp_table, dgrp_proc_dir_entry);
}
/*
* /proc/sys support
*/
static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
{
if (!de || !de->low_ino)
return 0;
if (de->namelen != len)
return 0;
return !memcmp(name, de->name, len);
}
/*
* Scan the entries in table and add them all to /proc at the position
* referred to by "root"
*/
static void register_proc_table(struct dgrp_proc_entry *table,
struct proc_dir_entry *root)
{
struct proc_dir_entry *de;
int len;
mode_t mode;
for (; table->id; table++) {
/* Can't do anything without a proc name. */
if (!table->name)
continue;
/* Maybe we can't do anything with it... */
if (!table->proc_file_ops &&
!table->child) {
pr_warn("dgrp: Can't register %s\n",
table->name);
continue;
}
len = strlen(table->name);
mode = table->mode;
de = NULL;
if (!table->child)
mode |= S_IFREG;
else {
mode |= S_IFDIR;
for (de = root->subdir; de; de = de->next) {
if (dgrp_proc_match(len, table->name, de))
break;
}
/* If the subdir exists already, de is non-NULL */
}
if (!de) {
de = create_proc_entry(table->name, mode, root);
if (!de)
continue;
de->data = (void *) table;
if (!table->child) {
de->proc_iops = &proc_inode_ops;
if (table->proc_file_ops)
de->proc_fops = table->proc_file_ops;
else
de->proc_fops = &dgrp_proc_file_ops;
}
}
table->de = de;
if (de->mode & S_IFDIR)
register_proc_table(table->child, de);
if (table->id == DGRP_NETDIR)
net_entry_pointer = de;
if (table->id == DGRP_MONDIR)
mon_entry_pointer = de;
if (table->id == DGRP_DPADIR)
dpa_entry_pointer = de;
if (table->id == DGRP_PORTSDIR)
ports_entry_pointer = de;
}
}
/*
* Unregister a /proc sysctl table and any subdirectories.
*/
static void unregister_proc_table(struct dgrp_proc_entry *table,
struct proc_dir_entry *root)
{
struct proc_dir_entry *de;
struct nd_struct *tmp;
list_for_each_entry(tmp, &nd_struct_list, list) {
if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
unregister_dgrp_device(tmp->nd_net_de);
dgrp_remove_node_class_sysfs_files(tmp);
}
if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
unregister_dgrp_device(tmp->nd_mon_de);
if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
unregister_dgrp_device(tmp->nd_dpa_de);
if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
unregister_dgrp_device(tmp->nd_ports_de);
}
for (; table->id; table++) {
de = table->de;
if (!de)
continue;
if (de->mode & S_IFDIR) {
if (!table->child) {
pr_alert("dgrp: malformed sysctl tree on free\n");
continue;
}
unregister_proc_table(table->child, de);
/* Don't unregister directories which still have entries */
if (de->subdir)
continue;
}
/* Don't unregister proc entries that are still being used.. */
if ((atomic_read(&de->count)) != 1) {
pr_alert("proc entry %s in use, not removing\n",
de->name);
continue;
}
remove_proc_entry(de->name, de->parent);
table->de = NULL;
}
}
static int dgrp_gen_proc_open(struct inode *inode, struct file *file)
{
struct proc_dir_entry *de;
struct dgrp_proc_entry *entry;
int ret = 0;
de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
if (!de || !de->data) {
ret = -ENXIO;
goto done;
}
entry = (struct dgrp_proc_entry *) de->data;
if (!entry) {
ret = -ENXIO;
goto done;
}
down(&entry->excl_sem);
if (entry->excl_cnt)
ret = -EBUSY;
else
entry->excl_cnt++;
up(&entry->excl_sem);
done:
return ret;
}
static int dgrp_gen_proc_close(struct inode *inode, struct file *file)
{
struct proc_dir_entry *de;
struct dgrp_proc_entry *entry;
de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
if (!de || !de->data)
goto done;
entry = (struct dgrp_proc_entry *) de->data;
if (!entry)
goto done;
down(&entry->excl_sem);
if (entry->excl_cnt)
entry->excl_cnt = 0;
up(&entry->excl_sem);
done:
return 0;
}
static void *config_proc_start(struct seq_file *m, loff_t *pos)
{
return seq_list_start_head(&nd_struct_list, *pos);
}
static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos)
{
return seq_list_next(v, &nd_struct_list, pos);
}
static void config_proc_stop(struct seq_file *m, void *v)
{
}
static int config_proc_show(struct seq_file *m, void *v)
{
struct nd_struct *nd;
char tmp_id[4];
if (v == &nd_struct_list) {
seq_puts(m, "#-----------------------------------------------------------------------------\n");
seq_puts(m, "# Avail\n");
seq_puts(m, "# ID Major State Ports\n");
return 0;
}
nd = list_entry(v, struct nd_struct, list);
ID_TO_CHAR(nd->nd_ID, tmp_id);
seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n",
tmp_id,
nd->nd_major,
ND_STATE_STR(nd->nd_state),
nd->nd_chan_count);
return 0;
}
static const struct seq_operations proc_config_ops = {
.start = config_proc_start,
.next = config_proc_next,
.stop = config_proc_stop,
.show = config_proc_show
};
static int config_proc_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_config_ops);
}
/*
* When writing configuration information, each "record" (i.e. each
* write) is treated as an independent request. See the "parse"
* description for more details.
*/
static ssize_t config_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *pos)
{
ssize_t retval;
char *inbuf, *sp;
char *line, *ldelim;
if (count > 32768)
return -EINVAL;
inbuf = sp = vzalloc(count + 1);
if (!inbuf)
return -ENOMEM;
if (copy_from_user(inbuf, buffer, count)) {
retval = -EFAULT;
goto done;
}
inbuf[count] = 0;
ldelim = "\n";
line = strpbrk(sp, ldelim);
while (line) {
*line = 0;
retval = parse_write_config(sp);
if (retval)
goto done;
sp = line + 1;
line = strpbrk(sp, ldelim);
}
retval = count;
done:
vfree(inbuf);
return retval;
}
/*
* ------------------------------------------------------------------------
*
* The following are the functions to parse input
*
* ------------------------------------------------------------------------
*/
static inline char *skip_past_ws(const char *str)
{
while ((*str) && !isspace(*str))
++str;
return skip_spaces(str);
}
static int parse_id(char **c, char *cID)
{
int tmp = **c;
if (isalnum(tmp) || (tmp == '_'))
cID[0] = tmp;
else
return -EINVAL;
(*c)++; tmp = **c;
if (isalnum(tmp) || (tmp == '_')) {
cID[1] = tmp;
(*c)++;
} else
cID[1] = 0;
return 0;
}
static int parse_add_config(char *buf)
{
char *c = buf;
int retval;
char cID[2];
long ID;
c = skip_past_ws(c);
retval = parse_id(&c, cID);
if (retval < 0)
return retval;
ID = CHAR_TO_ID(cID);
c = skip_past_ws(c);
return dgrp_add_id(ID);
}
static int parse_del_config(char *buf)
{
char *c = buf;
int retval;
struct nd_struct *nd;
char cID[2];
long ID;
long major;
c = skip_past_ws(c);
retval = parse_id(&c, cID);
if (retval < 0)
return retval;
ID = CHAR_TO_ID(cID);
c = skip_past_ws(c);
retval = kstrtol(c, 10, &major);
if (retval)
return retval;
nd = nd_struct_get(major);
if (!nd)
return -EINVAL;
if ((nd->nd_major != major) || (nd->nd_ID != ID))
return -EINVAL;
return dgrp_remove_nd(nd);
}
static int parse_chg_config(char *buf)
{
return -EINVAL;
}
/*
* The passed character buffer represents a single configuration request.
* If the first character is a "+", it is parsed as a request to add a
* PortServer
* If the first character is a "-", it is parsed as a request to delete a
* PortServer
* If the first character is a "*", it is parsed as a request to change a
* PortServer
* Any other character (including whitespace) causes the record to be
* ignored.
*/
static int parse_write_config(char *buf)
{
int retval;
switch (buf[0]) {
case '+':
retval = parse_add_config(buf);
break;
case '-':
retval = parse_del_config(buf);
break;
case '*':
retval = parse_chg_config(buf);
break;
default:
retval = -EINVAL;
}
return retval;
}
static int info_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "version: %s\n", DIGI_VERSION);
seq_puts(m, "register_with_sysfs: 1\n");
seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
dgrp_rawreadok, dgrp_rawreadok);
seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
dgrp_poll_tick, dgrp_poll_tick);
return 0;
}
static int info_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, info_proc_show, NULL);
}
static void *nodeinfo_start(struct seq_file *m, loff_t *pos)
{
return seq_list_start_head(&nd_struct_list, *pos);
}
static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
{
return seq_list_next(v, &nd_struct_list, pos);
}
static void nodeinfo_stop(struct seq_file *m, void *v)
{
}
static int nodeinfo_show(struct seq_file *m, void *v)
{
struct nd_struct *nd;
char hwver[8];
char swver[8];
char tmp_id[4];
if (v == &nd_struct_list) {
seq_puts(m, "#-----------------------------------------------------------------------------\n");
seq_puts(m, "# HW HW SW\n");
seq_puts(m, "# ID State Version ID Version Description\n");
return 0;
}
nd = list_entry(v, struct nd_struct, list);
ID_TO_CHAR(nd->nd_ID, tmp_id);
if (nd->nd_state == NS_READY) {
sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
nd->nd_hw_ver & 0xff);
sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
nd->nd_sw_ver & 0xff);
seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n",
tmp_id,
ND_STATE_STR(nd->nd_state),
hwver,
nd->nd_hw_id,
swver,
nd->nd_ps_desc);
} else {
seq_printf(m, " %-2.2s %-10.10s\n",
tmp_id,
ND_STATE_STR(nd->nd_state));
}
return 0;
}
static const struct seq_operations nodeinfo_ops = {
.start = nodeinfo_start,
.next = nodeinfo_next,
.stop = nodeinfo_stop,
.show = nodeinfo_show
};
static int nodeinfo_proc_open(struct inode *inode, struct file *file)
{
return seq_open(file, &nodeinfo_ops);
}
/**
* dgrp_add_id() -- creates new nd struct and adds it to list
* @id: id of device to add
*/
static int dgrp_add_id(long id)
{
struct nd_struct *nd;
int ret;
int i;
nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
if (!nd)
return -ENOMEM;
nd->nd_major = 0;
nd->nd_ID = id;
spin_lock_init(&nd->nd_lock);
init_waitqueue_head(&nd->nd_tx_waitq);
init_waitqueue_head(&nd->nd_mon_wqueue);
init_waitqueue_head(&nd->nd_dpa_wqueue);
for (i = 0; i < SEQ_MAX; i++)
init_waitqueue_head(&nd->nd_seq_wque[i]);
/* setup the structures to get the major number */
ret = dgrp_tty_init(nd);
if (ret)
goto error_out;
nd->nd_major = nd->nd_serial_ttdriver->major;
ret = nd_struct_add(nd);
if (ret)
goto error_out;
register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook);
register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook);
register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook);
register_dgrp_device(nd, ports_entry_pointer,
dgrp_register_ports_hook);
return 0;
error_out:
kfree(nd);
return ret;
}
static int dgrp_remove_nd(struct nd_struct *nd)
{
int ret;
/* Check to see if the selected structure is in use */
if (nd->nd_tty_ref_cnt)
return -EBUSY;
if (nd->nd_net_de) {
unregister_dgrp_device(nd->nd_net_de);
dgrp_remove_node_class_sysfs_files(nd);
}
if (nd->nd_mon_de)
unregister_dgrp_device(nd->nd_mon_de);
if (nd->nd_ports_de)
unregister_dgrp_device(nd->nd_ports_de);
if (nd->nd_dpa_de)
unregister_dgrp_device(nd->nd_dpa_de);
dgrp_tty_uninit(nd);
ret = nd_struct_del(nd);
if (ret)
return ret;
kfree(nd);
return 0;
}
static void register_dgrp_device(struct nd_struct *node,
struct proc_dir_entry *root,
void (*register_hook)(struct proc_dir_entry *de))
{
char buf[3];
struct proc_dir_entry *de;
ID_TO_CHAR(node->nd_ID, buf);
de = create_proc_entry(buf, 0600 | S_IFREG, root);
if (!de)
return;
de->data = (void *) node;
if (register_hook)
register_hook(de);
}
static void unregister_dgrp_device(struct proc_dir_entry *de)
{
if (!de)
return;
/* Don't unregister proc entries that are still being used.. */
if ((atomic_read(&de->count)) != 1) {
pr_alert("%s - proc entry %s in use. Not removing.\n",
__func__, de->name);
return;
}
remove_proc_entry(de->name, de->parent);
de = NULL;
}

View File

@ -0,0 +1,555 @@
/*
* Copyright 2004 Digi International (www.digi.com)
* Scott H Kilau <Scott_Kilau at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
#include "dgrp_common.h"
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/serial_reg.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#define PORTSERVER_DIVIDEND 1843200
#define SERIAL_TYPE_NORMAL 1
#define SERIAL_TYPE_CALLOUT 2
#define SERIAL_TYPE_XPRINT 3
static struct class *dgrp_class;
static struct device *dgrp_class_nodes_dev;
static struct device *dgrp_class_global_settings_dev;
static ssize_t dgrp_class_version_show(struct class *class,
struct class_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", DIGI_VERSION);
}
static CLASS_ATTR(driver_version, 0400, dgrp_class_version_show, NULL);
static ssize_t dgrp_class_register_with_sysfs_show(struct device *c,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "1\n");
}
static DEVICE_ATTR(register_with_sysfs, 0400,
dgrp_class_register_with_sysfs_show, NULL);
static ssize_t dgrp_class_rawreadok_show(struct device *c,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_rawreadok);
}
static ssize_t dgrp_class_rawreadok_store(struct device *c,
struct device_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "0x%x\n", &dgrp_rawreadok);
return count;
}
static DEVICE_ATTR(rawreadok, 0600, dgrp_class_rawreadok_show,
dgrp_class_rawreadok_store);
static ssize_t dgrp_class_pollrate_show(struct device *c,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_poll_tick);
}
static ssize_t dgrp_class_pollrate_store(struct device *c,
struct device_attribute *attr,
const char *buf, size_t count)
{
sscanf(buf, "0x%x\n", &dgrp_poll_tick);
return count;
}
static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show,
dgrp_class_pollrate_store);
static struct attribute *dgrp_sysfs_global_settings_entries[] = {
&dev_attr_pollrate.attr,
&dev_attr_rawreadok.attr,
&dev_attr_register_with_sysfs.attr,
NULL
};
static struct attribute_group dgrp_global_settings_attribute_group = {
.name = NULL,
.attrs = dgrp_sysfs_global_settings_entries,
};
void dgrp_create_class_sysfs_files(void)
{
int ret = 0;
int max_majors = 1U << (32 - MINORBITS);
dgrp_class = class_create(THIS_MODULE, "digi_realport");
ret = class_create_file(dgrp_class, &class_attr_driver_version);
dgrp_class_global_settings_dev = device_create(dgrp_class, NULL,
MKDEV(0, max_majors + 1), NULL, "driver_settings");
ret = sysfs_create_group(&dgrp_class_global_settings_dev->kobj,
&dgrp_global_settings_attribute_group);
if (ret) {
pr_alert("%s: failed to create sysfs global settings device attributes.\n",
__func__);
sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
&dgrp_global_settings_attribute_group);
return;
}
dgrp_class_nodes_dev = device_create(dgrp_class, NULL,
MKDEV(0, max_majors + 2), NULL, "nodes");
}
void dgrp_remove_class_sysfs_files(void)
{
struct nd_struct *nd;
int max_majors = 1U << (32 - MINORBITS);
list_for_each_entry(nd, &nd_struct_list, list)
dgrp_remove_node_class_sysfs_files(nd);
sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
&dgrp_global_settings_attribute_group);
class_remove_file(dgrp_class, &class_attr_driver_version);
device_destroy(dgrp_class, MKDEV(0, max_majors + 1));
device_destroy(dgrp_class, MKDEV(0, max_majors + 2));
class_destroy(dgrp_class);
}
static ssize_t dgrp_node_state_show(struct device *c,
struct device_attribute *attr, char *buf)
{
struct nd_struct *nd;
if (!c)
return 0;
nd = (struct nd_struct *) dev_get_drvdata(c);
if (!nd)
return 0;
return snprintf(buf, PAGE_SIZE, "%s\n", ND_STATE_STR(nd->nd_state));
}
static DEVICE_ATTR(state, 0600, dgrp_node_state_show, NULL);
static ssize_t dgrp_node_description_show(struct device *c,
struct device_attribute *attr,
char *buf)
{
struct nd_struct *nd;
if (!c)
return 0;
nd = (struct nd_struct *) dev_get_drvdata(c);
if (!nd)
return 0;
if (nd->nd_state == NS_READY && nd->nd_ps_desc)
return snprintf(buf, PAGE_SIZE, "%s\n", nd->nd_ps_desc);
return 0;
}
static DEVICE_ATTR(description_info, 0600, dgrp_node_description_show, NULL);
static ssize_t dgrp_node_hw_version_show(struct device *c,
struct device_attribute *attr,
char *buf)
{
struct nd_struct *nd;
if (!c)
return 0;
nd = (struct nd_struct *) dev_get_drvdata(c);
if (!nd)
return 0;
if (nd->nd_state == NS_READY)
return snprintf(buf, PAGE_SIZE, "%d.%d\n",
(nd->nd_hw_ver >> 8) & 0xff,
nd->nd_hw_ver & 0xff);
return 0;
}
static DEVICE_ATTR(hw_version_info, 0600, dgrp_node_hw_version_show, NULL);
static ssize_t dgrp_node_hw_id_show(struct device *c,
struct device_attribute *attr, char *buf)
{
struct nd_struct *nd;
if (!c)
return 0;
nd = (struct nd_struct *) dev_get_drvdata(c);
if (!nd)
return 0;
if (nd->nd_state == NS_READY)
return snprintf(buf, PAGE_SIZE, "%d\n", nd->nd_hw_id);
return 0;
}
static DEVICE_ATTR(hw_id_info, 0600, dgrp_node_hw_id_show, NULL);
static ssize_t dgrp_node_sw_version_show(struct device *c,
struct device_attribute *attr,
char *buf)
{
struct nd_struct *nd;
if (!c)
return 0;
nd = (struct nd_struct *) dev_get_drvdata(c);
if (!nd)
return 0;
if (nd->nd_state == NS_READY)
return snprintf(buf, PAGE_SIZE, "%d.%d\n",
(nd->nd_sw_ver >> 8) & 0xff,
nd->nd_sw_ver & 0xff);
return 0;
}
static DEVICE_ATTR(sw_version_info, 0600, dgrp_node_sw_version_show, NULL);
static struct attribute *dgrp_sysfs_node_entries[] = {
&dev_attr_state.attr,
&dev_attr_description_info.attr,
&dev_attr_hw_version_info.attr,
&dev_attr_hw_id_info.attr,
&dev_attr_sw_version_info.attr,
NULL
};
static struct attribute_group dgrp_node_attribute_group = {
.name = NULL,
.attrs = dgrp_sysfs_node_entries,
};
void dgrp_create_node_class_sysfs_files(struct nd_struct *nd)
{
int ret;
char name[10];
if (nd->nd_ID)
ID_TO_CHAR(nd->nd_ID, name);
else
sprintf(name, "node%ld", nd->nd_major);
nd->nd_class_dev = device_create(dgrp_class, dgrp_class_nodes_dev,
MKDEV(0, nd->nd_major), NULL, name);
ret = sysfs_create_group(&nd->nd_class_dev->kobj,
&dgrp_node_attribute_group);
if (ret) {
pr_alert("%s: failed to create sysfs node device attributes.\n",
__func__);
sysfs_remove_group(&nd->nd_class_dev->kobj,
&dgrp_node_attribute_group);
return;
}
dev_set_drvdata(nd->nd_class_dev, nd);
}
void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd)
{
if (nd->nd_class_dev) {
sysfs_remove_group(&nd->nd_class_dev->kobj,
&dgrp_node_attribute_group);
device_destroy(dgrp_class, MKDEV(0, nd->nd_major));
nd->nd_class_dev = NULL;
}
}
static ssize_t dgrp_tty_state_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
return snprintf(buf, PAGE_SIZE, "%s\n",
un->un_open_count ? "Open" : "Closed");
}
static DEVICE_ATTR(state_info, 0600, dgrp_tty_state_show, NULL);
static ssize_t dgrp_tty_baud_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%d\n",
un->un_open_count ? (PORTSERVER_DIVIDEND / ch->ch_s_brate) : 0);
}
static DEVICE_ATTR(baud_info, 0400, dgrp_tty_baud_show, NULL);
static ssize_t dgrp_tty_msignals_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
if (ch->ch_open_count) {
return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
(ch->ch_s_mlast & DM_RTS) ? "RTS" : "",
(ch->ch_s_mlast & DM_CTS) ? "CTS" : "",
(ch->ch_s_mlast & DM_DTR) ? "DTR" : "",
(ch->ch_s_mlast & DM_DSR) ? "DSR" : "",
(ch->ch_s_mlast & DM_CD) ? "DCD" : "",
(ch->ch_s_mlast & DM_RI) ? "RI" : "");
}
return 0;
}
static DEVICE_ATTR(msignals_info, 0400, dgrp_tty_msignals_show, NULL);
static ssize_t dgrp_tty_iflag_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_iflag);
}
static DEVICE_ATTR(iflag_info, 0600, dgrp_tty_iflag_show, NULL);
static ssize_t dgrp_tty_cflag_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_cflag);
}
static DEVICE_ATTR(cflag_info, 0600, dgrp_tty_cflag_show, NULL);
static ssize_t dgrp_tty_oflag_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_oflag);
}
static DEVICE_ATTR(oflag_info, 0600, dgrp_tty_oflag_show, NULL);
static ssize_t dgrp_tty_digi_flag_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
}
static DEVICE_ATTR(digi_flag_info, 0600, dgrp_tty_digi_flag_show, NULL);
static ssize_t dgrp_tty_rxcount_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_rxcount);
}
static DEVICE_ATTR(rxcount_info, 0600, dgrp_tty_rxcount_show, NULL);
static ssize_t dgrp_tty_txcount_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ch_struct *ch;
struct un_struct *un;
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_txcount);
}
static DEVICE_ATTR(txcount_info, 0600, dgrp_tty_txcount_show, NULL);
static ssize_t dgrp_tty_name_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct nd_struct *nd;
struct ch_struct *ch;
struct un_struct *un;
char name[10];
if (!d)
return 0;
un = (struct un_struct *) dev_get_drvdata(d);
if (!un)
return 0;
ch = un->un_ch;
if (!ch)
return 0;
nd = ch->ch_nd;
if (!nd)
return 0;
ID_TO_CHAR(nd->nd_ID, name);
return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
un->un_type == SERIAL_TYPE_XPRINT ? "pr" : "tty",
name, ch->ch_portnum);
}
static DEVICE_ATTR(custom_name, 0600, dgrp_tty_name_show, NULL);
static struct attribute *dgrp_sysfs_tty_entries[] = {
&dev_attr_state_info.attr,
&dev_attr_baud_info.attr,
&dev_attr_msignals_info.attr,
&dev_attr_iflag_info.attr,
&dev_attr_cflag_info.attr,
&dev_attr_oflag_info.attr,
&dev_attr_digi_flag_info.attr,
&dev_attr_rxcount_info.attr,
&dev_attr_txcount_info.attr,
&dev_attr_custom_name.attr,
NULL
};
static struct attribute_group dgrp_tty_attribute_group = {
.name = NULL,
.attrs = dgrp_sysfs_tty_entries,
};
void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c)
{
int ret;
ret = sysfs_create_group(&c->kobj, &dgrp_tty_attribute_group);
if (ret) {
pr_alert("%s: failed to create sysfs tty device attributes.\n",
__func__);
sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group);
return;
}
dev_set_drvdata(c, un);
}
void dgrp_remove_tty_sysfs(struct device *c)
{
sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
/************************************************************************
* HP-UX Realport Daemon interface file.
*
* Copyright (C) 1998, by Digi International. All Rights Reserved.
************************************************************************/
#ifndef _DIGIDRP_H
#define _DIGIDRP_H
/************************************************************************
* This file contains defines for the ioctl() interface to
* the realport driver. This ioctl() interface is used by the
* daemon to set speed setup parameters honored by the driver.
************************************************************************/
struct link_struct {
int lk_fast_rate; /* Fast line rate to be used
when the delay is less-equal
to lk_fast_delay */
int lk_fast_delay; /* Fast line rate delay in
milliseconds */
int lk_slow_rate; /* Slow line rate to be used when
the delay is greater-equal
to lk_slow_delay */
int lk_slow_delay; /* Slow line rate delay in
milliseconds */
int lk_header_size; /* Estimated packet header size
when sent across the slowest
link. */
};
#define DIGI_GETLINK _IOW('e', 103, struct link_struct) /* Get link parameters */
#define DIGI_SETLINK _IOW('e', 104, struct link_struct) /* Set link parameters */
/************************************************************************
* This module provides application access to special Digi
* serial line enhancements which are not standard UNIX(tm) features.
************************************************************************/
struct digiflow_struct {
unsigned char startc; /* flow cntl start char */
unsigned char stopc; /* flow cntl stop char */
};
/************************************************************************
* Values for digi_flags
************************************************************************/
#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
#define DIGI_FAST 0x0002 /* Fast baud rates */
#define RTSPACE 0x0004 /* RTS input flow control */
#define CTSPACE 0x0008 /* CTS output flow control */
#define DSRPACE 0x0010 /* DSR output flow control */
#define DCDPACE 0x0020 /* DCD output flow control */
#define DTRPACE 0x0040 /* DTR input flow control */
#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */
#define DIGI_FORCEDCD 0x0100 /* Force carrier */
#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl */
#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input */
#define DIGI_422 0x4000 /* Change parallel port to input */
#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */
/************************************************************************
* Values associated with transparent print
************************************************************************/
#define DIGI_PLEN 8 /* String length */
#define DIGI_TSIZ 10 /* Terminal string len */
/************************************************************************
* Structure used with ioctl commands for DIGI parameters.
************************************************************************/
struct digi_struct {
unsigned short digi_flags; /* Flags (see above) */
unsigned short digi_maxcps; /* Max printer CPS */
unsigned short digi_maxchar; /* Max chars in print queue */
unsigned short digi_bufsize; /* Buffer size */
unsigned char digi_onlen; /* Length of ON string */
unsigned char digi_offlen; /* Length of OFF string */
char digi_onstr[DIGI_PLEN]; /* Printer on string */
char digi_offstr[DIGI_PLEN]; /* Printer off string */
char digi_term[DIGI_TSIZ]; /* terminal string */
};
/************************************************************************
* Ioctl command arguments for DIGI parameters.
************************************************************************/
/* Read params */
#define DIGI_GETA _IOR('e', 94, struct digi_struct)
/* Set params */
#define DIGI_SETA _IOW('e', 95, struct digi_struct)
/* Drain & set params */
#define DIGI_SETAW _IOW('e', 96, struct digi_struct)
/* Drain, flush & set params */
#define DIGI_SETAF _IOW('e', 97, struct digi_struct)
/* Get startc/stopc flow control characters */
#define DIGI_GETFLOW _IOR('e', 99, struct digiflow_struct)
/* Set startc/stopc flow control characters */
#define DIGI_SETFLOW _IOW('e', 100, struct digiflow_struct)
/* Get Aux. startc/stopc flow control chars */
#define DIGI_GETAFLOW _IOR('e', 101, struct digiflow_struct)
/* Set Aux. startc/stopc flow control chars */
#define DIGI_SETAFLOW _IOW('e', 102, struct digiflow_struct)
/* Set integer baud rate */
#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int)
/* Get integer baud rate */
#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int)
#define DIGI_GEDELAY _IOR('d', 246, int) /* Get edelay */
#define DIGI_SEDELAY _IOW('d', 247, int) /* Get edelay */
#endif /* _DIGIDRP_H */

693
drivers/staging/dgrp/drp.h Normal file
View File

@ -0,0 +1,693 @@
/*
*
* Copyright 1999 Digi International (www.digi.com)
* Gene Olson <gene at digi dot com>
* James Puzzo <jamesp at digi dot com>
* Scott Kilau <scottk at digi dot com>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*/
/************************************************************************
* Master include file for Linux Realport Driver.
************************************************************************/
#ifndef __DRP_H
#define __DRP_H
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/semaphore.h>
#include <linux/tty.h>
#include "digirp.h"
/************************************************************************
* Tuning parameters.
************************************************************************/
#define CHAN_MAX 64 /* Max # ports per server */
#define SEQ_MAX 128 /* Max # transmit sequences (2^n) */
#define SEQ_MASK (SEQ_MAX-1) /* Sequence buffer modulus mask */
#define TBUF_MAX 4096 /* Size of transmit buffer (2^n) */
#define RBUF_MAX 4096 /* Size of receive buffer (2^n) */
#define TBUF_MASK (TBUF_MAX-1) /* Transmit buffer modulus mask */
#define RBUF_MASK (RBUF_MAX-1) /* Receive buffer modulus mask */
#define TBUF_LOW 1000 /* Transmit low water mark */
#define UIO_BASE 1000 /* Base for write operations */
#define UIO_MIN 2000 /* Minimum size application buffer */
#define UIO_MAX 8100 /* Unix I/O buffer size */
#define MON_MAX 65536 /* Monitor buffer size (2^n) */
#define MON_MASK (MON_MAX-1) /* Monitor wrap mask */
#define DPA_MAX 65536 /* DPA buffer size (2^n) */
#define DPA_MASK (DPA_MAX-1) /* DPA wrap mask */
#define DPA_HIGH_WATER 58000 /* Enforce flow control when
* over this amount
*/
#define IDLE_MAX (20 * HZ) /* Max TCP link idle time */
#define MAX_DESC_LEN 100 /* Maximum length of stored PS
* description
*/
#define WRITEBUFLEN ((4096) + 4) /* 4 extra for alignment play space */
#define VPDSIZE 512
/************************************************************************
* Minor device decoding conventions.
************************************************************************
*
* For Linux, the net and mon devices are handled via "proc", so we
* only have to mux the "tty" devices. Since every PortServer will
* have an individual major number, the PortServer number does not
* need to be encoded, and in fact, does not need to exist.
*
*/
/*
* Port device decoding conventions:
*
* Device 00 - 3f 64 dial-in modem devices. (tty)
* Device 40 - 7f 64 dial-out tty devices. (cu)
* Device 80 - bf 64 dial-out printer devices.
*
* IS_PRINT(dev) This is a printer device.
*
* OPEN_CATEGORY(dev) Specifies the device category. No two
* devices of different categories may be open
* at the same time.
*
* The following require the category returned by OPEN_CATEGORY().
*
* OPEN_WAIT_AVAIL(cat) Waits on open until the device becomes
* available. Fails if NDELAY specified.
*
* OPEN_WAIT_CARRIER(cat) Waits on open if carrier is not present.
* Succeeds if NDELAY is given.
*
* OPEN_FORCES_CARRIER(cat) Carrier is forced high on open.
*
*/
#define PORT_NUM(dev) ((dev) & 0x3f)
#define OPEN_CATEGORY(dev) ((((dev) & 0x80) & 0x40))
#define IS_PRINT(dev) (((dev) & 0xff) >= 0x80)
#define OPEN_WAIT_AVAIL(cat) (((cat) & 0x40) == 0x000)
#define OPEN_WAIT_CARRIER(cat) (((cat) & 0x40) == 0x000)
#define OPEN_FORCES_CARRIER(cat) (((cat) & 0x40) != 0x000)
/************************************************************************
* Modem signal defines for 16450/16550 compatible FEP.
* set in ch_mout, ch_mflow, ch_mlast etc
************************************************************************/
/* TODO : Re-verify that these modem signal definitions are correct */
#define DM_DTR 0x01
#define DM_RTS 0x02
#define DM_RTS_TOGGLE 0x04
#define DM_OUT1 0x04
#define DM_OUT2 0x08
#define DM_CTS 0x10
#define DM_DSR 0x20
#define DM_RI 0x40
#define DM_CD 0x80 /* This is the DCD flag */
/************************************************************************
* Realport Event Flags.
************************************************************************/
#define EV_OPU 0x0001 /* Ouput paused by client */
#define EV_OPS 0x0002 /* Output paused by XOFF */
#define EV_OPX 0x0004 /* Output paused by XXOFF */
#define EV_OPH 0x0008 /* Output paused by MFLOW */
#define EV_IPU 0x0010 /* Input paused by client */
#define EV_IPS 0x0020 /* Input paused by hi/low water */
#define EV_TXB 0x0040 /* Transmit break pending */
#define EV_TXI 0x0080 /* Transmit immediate pending */
#define EV_TXF 0x0100 /* Transmit flow control pending */
#define EV_RXB 0x0200 /* Break received */
/************************************************************************
* Realport CFLAGS.
************************************************************************/
#define CF_CS5 0x0000 /* 5 bit characters */
#define CF_CS6 0x0010 /* 6 bit characters */
#define CF_CS7 0x0020 /* 7 bit characters */
#define CF_CS8 0x0030 /* 8 bit characters */
#define CF_CSIZE 0x0030 /* Character size */
#define CF_CSTOPB 0x0040 /* Two stop bits */
#define CF_CREAD 0x0080 /* Enable receiver */
#define CF_PARENB 0x0100 /* Enable parity */
#define CF_PARODD 0x0200 /* Odd parity */
#define CF_HUPCL 0x0400 /* Drop DTR on close */
/************************************************************************
* Realport XFLAGS.
************************************************************************/
#define XF_XPAR 0x0001 /* Enable Mark/Space Parity */
#define XF_XMODEM 0x0002 /* Enable in-band modem signalling */
#define XF_XCASE 0x0004 /* Convert special characters */
#define XF_XEDATA 0x0008 /* Error data in stream */
#define XF_XTOSS 0x0010 /* Toss IXANY characters */
#define XF_XIXON 0x0020 /* xxon/xxoff enable */
/************************************************************************
* Realport IFLAGS.
************************************************************************/
#define IF_IGNBRK 0x0001 /* Ignore input break */
#define IF_BRKINT 0x0002 /* Break interrupt */
#define IF_IGNPAR 0x0004 /* Ignore error characters */
#define IF_PARMRK 0x0008 /* Error chars marked with 0xff */
#define IF_INPCK 0x0010 /* Input parity checking enabled */
#define IF_ISTRIP 0x0020 /* Input chars masked with 0x7F */
#define IF_IXON 0x0400 /* Output software flow control */
#define IF_IXANY 0x0800 /* Restart output on any char */
#define IF_IXOFF 0x1000 /* Input software flow control */
#define IF_DOSMODE 0x8000 /* 16450-compatible errors */
/************************************************************************
* Realport OFLAGS.
************************************************************************/
#define OF_OLCUC 0x0002 /* Map lower to upper case */
#define OF_ONLCR 0x0004 /* Map NL to CR-NL */
#define OF_OCRNL 0x0008 /* Map CR to NL */
#define OF_ONOCR 0x0010 /* No CR output at column 0 */
#define OF_ONLRET 0x0020 /* Assume NL does NL/CR */
#define OF_TAB3 0x1800 /* Tabs expand to 8 spaces */
#define OF_TABDLY 0x1800 /* Tab delay */
/************************************************************************
* Unit flag definitions for un_flag.
************************************************************************/
/* These are the DIGI unit flags */
#define UN_EXCL 0x00010000 /* Exclusive open */
#define UN_STICKY 0x00020000 /* TTY Settings are now sticky */
#define UN_BUSY 0x00040000 /* Some work this channel */
#define UN_PWAIT 0x00080000 /* Printer waiting for terminal */
#define UN_TIME 0x00100000 /* Waiting on time */
#define UN_EMPTY 0x00200000 /* Waiting output queue empty */
#define UN_LOW 0x00400000 /* Waiting output low water */
#define UN_DIGI_MASK 0x00FF0000 /* Waiting output low water */
/*
* Definitions for async_struct (and serial_struct) flags field
*
* these are the ASYNC flags copied from serial.h
*
*/
#define UN_HUP_NOTIFY 0x0001 /* Notify getty on hangups and
* closes on the callout port
*/
#define UN_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
#define UN_SAK 0x0004 /* Secure Attention Key (Orange book) */
#define UN_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
#define UN_SPD_MASK 0x0030
#define UN_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
#define UN_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
#define UN_SPD_CUST 0x0030 /* Use user-specified divisor */
#define UN_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
#define UN_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
#define UN_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
#define UN_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
#define UN_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
#define UN_FLAGS 0x0FFF /* Possible legal async flags */
#define UN_USR_MASK 0x0430 /* Legal flags that non-privileged
* users can set or reset
*/
#define UN_INITIALIZED 0x80000000 /* Serial port was initialized */
#define UN_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
#define UN_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
#define UN_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
#define UN_CLOSING 0x08000000 /* Serial port is closing */
#define UN_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define UN_CHECK_CD 0x02000000 /* i.e., CLOCAL */
#define UN_SHARE_IRQ 0x01000000 /* for multifunction cards */
/************************************************************************
* Structure for terminal or printer unit. struct un_struct
*
* Note that in some places the code assumes the "tty_t" is placed
* first in the structure.
************************************************************************/
struct un_struct {
struct tty_struct *un_tty; /* System TTY struct */
struct ch_struct *un_ch; /* Associated channel */
ushort un_open_count; /* Successful open count */
int un_flag; /* Unit flags */
ushort un_tbusy; /* Busy transmit count */
wait_queue_head_t un_open_wait;
wait_queue_head_t un_close_wait;
ushort un_type;
struct device *un_sysfs;
};
/************************************************************************
* Channel State Numbers for ch_state.
************************************************************************/
/*
* The ordering is important.
*
* state <= CS_WAIT_CANCEL implies the channel is definitely closed.
*
* state >= CS_WAIT_FAIL implies the channel is definitely open.
*
* state >= CS_READY implies data is allowed on the channel.
*/
enum dgrp_ch_state_t {
CS_IDLE = 0, /* Channel is idle */
CS_WAIT_OPEN = 1, /* Waiting for Immediate Open Resp */
CS_WAIT_CANCEL = 2, /* Waiting for Per/Incom Cancel Resp */
CS_WAIT_FAIL = 3, /* Waiting for Immed Open Failure */
CS_SEND_QUERY = 4, /* Ready to send Port Query */
CS_WAIT_QUERY = 5, /* Waiting for Port Query Response */
CS_READY = 6, /* Ready to accept commands and data */
CS_SEND_CLOSE = 7, /* Ready to send Close Request */
CS_WAIT_CLOSE = 8 /* Waiting for Close Response */
};
/************************************************************************
* Device flag definitions for ch_flag.
************************************************************************/
/*
* Note that the state of the two carrier based flags is key. When
* we check for carrier state transitions, we look at the current
* physical state of the DCD line and compare it with PHYS_CD (which
* was the state the last time we checked), and we also determine
* a new virtual state (composite of the physical state, FORCEDCD,
* CLOCAL, etc.) and compare it with VIRT_CD.
*
* VIRTUAL transitions high will have the side effect of waking blocked
* opens.
*
* PHYSICAL transitions low will cause hangups to occur _IF_ the virtual
* state is also low. We DON'T want to hangup on a PURE virtual drop.
*/
#define CH_HANGUP 0x00002 /* Server port ready to close */
#define CH_VIRT_CD 0x00004 /* Carrier was virtually present */
#define CH_PHYS_CD 0x00008 /* Carrier was physically present */
#define CH_CLOCAL 0x00010 /* CLOCAL set in cflags */
#define CH_BAUD0 0x00020 /* Baud rate zero hangup */
#define CH_FAST_READ 0x00040 /* Fast reads are enabled */
#define CH_FAST_WRITE 0x00080 /* Fast writes are enabled */
#define CH_PRON 0x00100 /* Printer on string active */
#define CH_RX_FLUSH 0x00200 /* Flushing receive data */
#define CH_LOW 0x00400 /* Thread waiting for LOW water */
#define CH_EMPTY 0x00800 /* Thread waiting for EMPTY */
#define CH_DRAIN 0x01000 /* Close is waiting to drain */
#define CH_INPUT 0x02000 /* Thread waiting for INPUT */
#define CH_RXSTOP 0x04000 /* Stop output to ldisc */
#define CH_PARAM 0x08000 /* A parameter was updated */
#define CH_WAITING_SYNC 0x10000 /* A pending sync was assigned
* to this port.
*/
#define CH_PORT_GONE 0x20000 /* Port has disappeared */
#define CH_TX_BREAK 0x40000 /* TX Break to be sent,
* but has not yet.
*/
/************************************************************************
* Types of Open Requests for ch_otype.
************************************************************************/
#define OTYPE_IMMEDIATE 0 /* Immediate Open */
#define OTYPE_PERSISTENT 1 /* Persistent Open */
#define OTYPE_INCOMING 2 /* Incoming Open */
/************************************************************************
* Request/Response flags.
************************************************************************/
#define RR_SEQUENCE 0x0001 /* Get server RLAST, TIN */
#define RR_STATUS 0x0002 /* Get server MINT, EINT */
#define RR_BUFFER 0x0004 /* Get server RSIZE, TSIZE */
#define RR_CAPABILITY 0x0008 /* Get server port capabilities */
#define RR_TX_FLUSH 0x0040 /* Flush output buffers */
#define RR_RX_FLUSH 0x0080 /* Flush input buffers */
#define RR_TX_STOP 0x0100 /* Pause output */
#define RR_RX_STOP 0x0200 /* Pause input */
#define RR_TX_START 0x0400 /* Start output */
#define RR_RX_START 0x0800 /* Start input */
#define RR_TX_BREAK 0x1000 /* Send BREAK */
#define RR_TX_ICHAR 0x2000 /* Send character immediate */
/************************************************************************
* Channel information structure. struct ch_struct
************************************************************************/
struct ch_struct {
struct digi_struct ch_digi; /* Digi variables */
int ch_edelay; /* Digi edelay */
struct tty_port port;
struct un_struct ch_tun; /* Terminal unit info */
struct un_struct ch_pun; /* Printer unit info */
struct nd_struct *ch_nd; /* Node pointer */
u8 *ch_tbuf; /* Local Transmit Buffer */
u8 *ch_rbuf; /* Local Receive Buffer */
ulong ch_cpstime; /* Printer CPS time */
ulong ch_waketime; /* Printer wake time */
ulong ch_flag; /* CH_* flags */
enum dgrp_ch_state_t ch_state; /* CS_* Protocol state */
ushort ch_send; /* Bit vector of RR_* requests */
ushort ch_expect; /* Bit vector of RR_* responses */
ushort ch_wait_carrier; /* Thread count waiting for carrier */
ushort ch_wait_count[3]; /* Thread count waiting by otype */
ushort ch_portnum; /* Port number */
ushort ch_open_count; /* Successful open count */
ushort ch_category; /* Device category */
ushort ch_open_error; /* Last open error number */
ushort ch_break_time; /* Pending break request time */
ushort ch_cpsrem; /* Printer CPS remainder */
ushort ch_ocook; /* Realport fastcook oflags */
ushort ch_inwait; /* Thread count in CLIST input */
ushort ch_tin; /* Local transmit buffer in ptr */
ushort ch_tout; /* Local transmit buffer out ptr */
ushort ch_s_tin; /* Realport TIN */
ushort ch_s_tpos; /* Realport TPOS */
ushort ch_s_tsize; /* Realport TSIZE */
ushort ch_s_treq; /* Realport TREQ */
ushort ch_s_elast; /* Realport ELAST */
ushort ch_rin; /* Local receive buffer in ptr */
ushort ch_rout; /* Local receive buffer out ptr */
ushort ch_s_rin; /* Realport RIN */
/* David Fries 7-13-2001, ch_s_rin should be renamed ch_s_rout because
* the variable we want to represent is the PortServer's ROUT, which is
* the sequence number for the next byte the PortServer will send us.
* RIN is the sequence number for the next byte the PortServer will
* receive from the uart. The port server will send data as long as
* ROUT is less than RWIN. What would happen is the port is opened, it
* receives data, it gives the value of RIN, we set the RWIN to
* RIN+RBUF_MAX-1, it sends us RWIN-ROUT bytes which overflows. ROUT
* is set to zero when the port is opened, so we start at zero and
* count up as data is received.
*/
ushort ch_s_rwin; /* Realport RWIN */
ushort ch_s_rsize; /* Realport RSIZE */
ushort ch_tmax; /* Local TMAX */
ushort ch_ttime; /* Local TTIME */
ushort ch_rmax; /* Local RMAX */
ushort ch_rtime; /* Local RTIME */
ushort ch_rlow; /* Local RLOW */
ushort ch_rhigh; /* Local RHIGH */
ushort ch_s_tmax; /* Realport TMAX */
ushort ch_s_ttime; /* Realport TTIME */
ushort ch_s_rmax; /* Realport RMAX */
ushort ch_s_rtime; /* Realport RTIME */
ushort ch_s_rlow; /* Realport RLOW */
ushort ch_s_rhigh; /* Realport RHIGH */
ushort ch_brate; /* Local baud rate */
ushort ch_cflag; /* Local tty cflags */
ushort ch_iflag; /* Local tty iflags */
ushort ch_oflag; /* Local tty oflags */
ushort ch_xflag; /* Local tty xflags */
ushort ch_s_brate; /* Realport BRATE */
ushort ch_s_cflag; /* Realport CFLAG */
ushort ch_s_iflag; /* Realport IFLAG */
ushort ch_s_oflag; /* Realport OFLAG */
ushort ch_s_xflag; /* Realport XFLAG */
u8 ch_otype; /* Open request type */
u8 ch_pscan_savechar; /* Last character read by parity scan */
u8 ch_pscan_state; /* PScan State based on last 2 chars */
u8 ch_otype_waiting; /* Type of open pending in server */
u8 ch_flush_seq; /* Receive flush end sequence */
u8 ch_s_mlast; /* Realport MLAST */
u8 ch_mout; /* Local MOUT */
u8 ch_mflow; /* Local MFLOW */
u8 ch_mctrl; /* Local MCTRL */
u8 ch_xon; /* Local XON */
u8 ch_xoff; /* Local XOFF */
u8 ch_lnext; /* Local LNEXT */
u8 ch_xxon; /* Local XXON */
u8 ch_xxoff; /* Local XXOFF */
u8 ch_s_mout; /* Realport MOUT */
u8 ch_s_mflow; /* Realport MFLOW */
u8 ch_s_mctrl; /* Realport MCTRL */
u8 ch_s_xon; /* Realport XON */
u8 ch_s_xoff; /* Realport XOFF */
u8 ch_s_lnext; /* Realport LNEXT */
u8 ch_s_xxon; /* Realport XXON */
u8 ch_s_xxoff; /* Realport XXOFF */
wait_queue_head_t ch_flag_wait; /* Wait queue for ch_flag changes */
wait_queue_head_t ch_sleep; /* Wait queue for my_sleep() */
int ch_custom_speed; /* Realport custom speed */
int ch_txcount; /* Running TX count */
int ch_rxcount; /* Running RX count */
};
/************************************************************************
* Node State definitions.
************************************************************************/
enum dgrp_nd_state_t {
NS_CLOSED = 0, /* Network device is closed */
NS_IDLE = 1, /* Network connection inactive */
NS_SEND_QUERY = 2, /* Send server query */
NS_WAIT_QUERY = 3, /* Wait for query response */
NS_READY = 4, /* Network ready */
NS_SEND_ERROR = 5 /* Must send error hangup */
};
#define ND_STATE_STR(x) \
((x) == NS_CLOSED ? "CLOSED" : \
((x) == NS_IDLE ? "IDLE" : \
((x) == NS_SEND_QUERY ? "SEND_QUERY" : \
((x) == NS_WAIT_QUERY ? "WAIT_QUERY" : \
((x) == NS_READY ? "READY" : \
((x) == NS_SEND_ERROR ? "SEND_ERROR" : "UNKNOWN"))))))
/************************************************************************
* Node Flag definitions.
************************************************************************/
#define ND_SELECT 0x0001 /* Multiple net read selects */
#define ND_DEB_WAIT 0x0002 /* Debug Device waiting */
/************************************************************************
* Monitoring flag definitions.
************************************************************************/
#define MON_WAIT_DATA 0x0001 /* Waiting for buffer data */
#define MON_WAIT_SPACE 0x0002 /* Waiting for buffer space */
/************************************************************************
* DPA flag definitions.
************************************************************************/
#define DPA_WAIT_DATA 0x0001 /* Waiting for buffer data */
#define DPA_WAIT_SPACE 0x0002 /* Waiting for buffer space */
/************************************************************************
* Definitions taken from Realport Dump.
************************************************************************/
#define RPDUMP_MAGIC "Digi-RealPort-1.0"
#define RPDUMP_MESSAGE 0xE2 /* Descriptive message */
#define RPDUMP_RESET 0xE7 /* Connection reset */
#define RPDUMP_CLIENT 0xE8 /* Client data */
#define RPDUMP_SERVER 0xE9 /* Server data */
/************************************************************************
* Node request/response definitions.
************************************************************************/
#define NR_ECHO 0x0001 /* Server echo packet */
#define NR_IDENT 0x0002 /* Server Product ID */
#define NR_CAPABILITY 0x0004 /* Server Capabilties */
#define NR_VPD 0x0008 /* Server VPD, if any */
#define NR_PASSWORD 0x0010 /* Server Password */
/************************************************************************
* Registration status of the node's Linux struct tty_driver structures.
************************************************************************/
#define SERIAL_TTDRV_REG 0x0001 /* nd_serial_ttdriver registered */
#define CALLOUT_TTDRV_REG 0x0002 /* nd_callout_ttdriver registered */
#define XPRINT_TTDRV_REG 0x0004 /* nd_xprint_ttdriver registered */
/************************************************************************
* Node structure. There exists one of these for each associated
* realport server.
************************************************************************/
struct nd_struct {
struct list_head list;
long nd_major; /* Node's major number */
long nd_ID; /* Node's ID code */
char nd_serial_name[50]; /* "tty_dgrp_<id>_" + null */
char nd_callout_name[50]; /* "cu_dgrp_<id>_" + null */
char nd_xprint_name[50]; /* "pr_dgrp_<id>_" + null */
char password[16]; /* Password for server, if needed */
int nd_tty_ref_cnt; /* Linux tty reference count */
struct proc_dir_entry *nd_net_de; /* Dir entry for /proc/dgrp/net */
struct proc_dir_entry *nd_mon_de; /* Dir entry for /proc/dgrp/mon */
struct proc_dir_entry *nd_ports_de; /* Dir entry for /proc/dgrp/ports*/
struct proc_dir_entry *nd_dpa_de; /* Dir entry for /proc/dgrp/dpa */
spinlock_t nd_lock; /* General node lock */
struct semaphore nd_net_semaphore; /* Net read/write lock */
struct semaphore nd_mon_semaphore; /* Monitor buffer lock */
spinlock_t nd_dpa_lock; /* DPA buffer lock */
enum dgrp_nd_state_t nd_state; /* NS_* network state */
int nd_chan_count; /* # active channels */
int nd_flag; /* Node flags */
int nd_send; /* Responses to send */
int nd_expect; /* Responses we expect */
u8 *nd_iobuf; /* Network R/W Buffer */
wait_queue_head_t nd_tx_waitq; /* Network select wait queue */
u8 *nd_inputbuf; /* Input Buffer */
u8 *nd_inputflagbuf; /* Input Flags Buffer */
int nd_tx_deposit; /* Accumulated transmit deposits */
int nd_tx_charge; /* Accumulated transmit charges */
int nd_tx_credit; /* Current TX credit */
int nd_tx_ready; /* Ready to transmit */
int nd_tx_work; /* TX work waiting */
ulong nd_tx_time; /* Last transmit time */
ulong nd_poll_time; /* Next scheduled poll time */
int nd_delay; /* Current TX delay */
int nd_rate; /* Current TX rate */
struct link_struct nd_link; /* Link speed params. */
int nd_seq_in; /* TX seq in ptr */
int nd_seq_out; /* TX seq out ptr */
int nd_unack; /* Unacknowledged byte count */
int nd_remain; /* Remaining receive bytes */
int nd_tx_module; /* Current TX module # */
int nd_rx_module; /* Current RX module # */
char *nd_error; /* Protocol error message */
int nd_write_count; /* drp_write() call count */
int nd_read_count; /* drp_read() count */
int nd_send_count; /* TCP message sent */
int nd_tx_byte; /* Transmit byte count */
int nd_rx_byte; /* Receive byte count */
ulong nd_mon_lbolt; /* Monitor start time */
int nd_mon_flag; /* Monitor flags */
int nd_mon_in; /* Monitor in pointer */
int nd_mon_out; /* Monitor out pointer */
wait_queue_head_t nd_mon_wqueue; /* Monitor wait queue (on flags) */
u8 *nd_mon_buf; /* Monitor buffer */
ulong nd_dpa_lbolt; /* DPA start time */
int nd_dpa_flag; /* DPA flags */
int nd_dpa_in; /* DPA in pointer */
int nd_dpa_out; /* DPA out pointer */
wait_queue_head_t nd_dpa_wqueue; /* DPA wait queue (on flags) */
u8 *nd_dpa_buf; /* DPA buffer */
uint nd_dpa_debug;
uint nd_dpa_port;
wait_queue_head_t nd_seq_wque[SEQ_MAX]; /* TX thread wait queues */
u8 nd_seq_wait[SEQ_MAX]; /* Transmit thread wait count */
ushort nd_seq_size[SEQ_MAX]; /* Transmit seq packet size */
ulong nd_seq_time[SEQ_MAX]; /* Transmit seq packet time */
ushort nd_hw_ver; /* HW version returned from PS */
ushort nd_sw_ver; /* SW version returned from PS */
uint nd_hw_id; /* HW ID returned from PS */
u8 nd_ps_desc[MAX_DESC_LEN+1]; /* Description from PS */
uint nd_vpd_len; /* VPD len, if any */
u8 nd_vpd[VPDSIZE]; /* VPD, if any */
ulong nd_ttdriver_flags; /* Registration status */
struct tty_driver *nd_serial_ttdriver; /* Linux TTYDRIVER structure */
struct tty_driver *nd_callout_ttdriver; /* Linux TTYDRIVER structure */
struct tty_driver *nd_xprint_ttdriver; /* Linux TTYDRIVER structure */
u8 *nd_writebuf; /* Used to cache data read
* from user
*/
struct ch_struct nd_chan[CHAN_MAX]; /* Channel array */
struct device *nd_class_dev; /* Hang our sysfs stuff off of here */
};
#endif /* __DRP_H */

View File

@ -443,7 +443,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
spin_lock_init(&channel->lock);
channel->pointer_read = 0;
channel->pointer_write = 0;
tty_dev = tty_register_device(tty, i, NULL);
tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL);
if (IS_ERR(tty_dev)) {
dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
continue;
@ -543,7 +543,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
struct ipoctal_channel *channel = tty->driver_data;
speed_t baud;
cflag = tty->termios->c_cflag;
cflag = tty->termios.c_cflag;
/* Disable and reset everything before change the setup */
iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
@ -564,7 +564,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
default:
mr1 |= MR1_CHRL_8_BITS;
/* By default, select CS8 */
tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
tty->termios.c_cflag = (cflag & ~CSIZE) | CS8;
break;
}
@ -578,7 +578,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
mr1 |= MR1_PARITY_OFF;
/* Mark or space parity is not supported */
tty->termios->c_cflag &= ~CMSPAR;
tty->termios.c_cflag &= ~CMSPAR;
/* Set stop bits */
if (cflag & CSTOPB)
@ -611,10 +611,10 @@ static void ipoctal_set_termios(struct tty_struct *tty,
}
baud = tty_get_baud_rate(tty);
tty_termios_encode_baud_rate(tty->termios, baud, baud);
tty_termios_encode_baud_rate(&tty->termios, baud, baud);
/* Set baud rate */
switch (tty->termios->c_ospeed) {
switch (baud) {
case 75:
csr |= TX_CLK_75 | RX_CLK_75;
break;
@ -655,7 +655,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
default:
csr |= TX_CLK_38400 | RX_CLK_38400;
/* In case of default, we establish 38400 bps */
tty_termios_encode_baud_rate(tty->termios, 38400, 38400);
tty_termios_encode_baud_rate(&tty->termios, 38400, 38400);
break;
}

View File

@ -313,10 +313,8 @@ static void qt_read_bulk_callback(struct urb *urb)
}
tty = tty_port_tty_get(&port->port);
if (!tty) {
dbg("%s - bad tty pointer - exiting", __func__);
if (!tty)
return;
}
data = urb->transfer_buffer;
@ -362,7 +360,7 @@ static void qt_read_bulk_callback(struct urb *urb)
goto exit;
}
if (tty && RxCount) {
if (RxCount) {
flag_data = 0;
for (i = 0; i < RxCount; ++i) {
/* Look ahead code here */
@ -426,7 +424,7 @@ static void qt_read_bulk_callback(struct urb *urb)
dbg("%s - failed resubmitting read urb, error %d",
__func__, result);
else {
if (tty && RxCount) {
if (RxCount) {
tty_flip_buffer_push(tty);
tty_schedule_flip(tty);
}
@ -895,8 +893,6 @@ static int qt_open(struct tty_struct *tty,
* Put this here to make it responsive to stty and defaults set by
* the tty layer
*/
/* FIXME: is this needed? */
/* qt_set_termios(tty, port, NULL); */
/* Check to see if we've set up our endpoint info yet */
if (port0->open_ports == 1) {
@ -1193,7 +1189,7 @@ static void qt_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
struct ktermios *termios = tty->termios;
struct ktermios *termios = &tty->termios;
unsigned char new_LCR = 0;
unsigned int cflag = termios->c_cflag;
unsigned int index;
@ -1202,7 +1198,7 @@ static void qt_set_termios(struct tty_struct *tty,
index = tty->index - port->serial->minor;
switch (cflag) {
switch (cflag & CSIZE) {
case CS5:
new_LCR |= SERIAL_5_DATA;
break;
@ -1213,6 +1209,8 @@ static void qt_set_termios(struct tty_struct *tty,
new_LCR |= SERIAL_7_DATA;
break;
default:
termios->c_cflag &= ~CSIZE;
termios->c_cflag |= CS8;
case CS8:
new_LCR |= SERIAL_8_DATA;
break;
@ -1299,7 +1297,7 @@ static void qt_set_termios(struct tty_struct *tty,
dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n");
}
tty->termios->c_cflag &= ~CMSPAR;
termios->c_cflag &= ~CMSPAR;
/* FIXME: Error cases should be returning the actual bits changed only */
}

View File

@ -1,8 +1,7 @@
#ifndef _SPEAKUP_SERIAL_H
#define _SPEAKUP_SERIAL_H
#include <linux/serial.h> /* for rs_table, serial constants &
serial_uart_config */
#include <linux/serial.h> /* for rs_table, serial constants */
#include <linux/serial_reg.h> /* for more serial constants */
#ifndef __sparc__
#include <asm/serial.h>

View File

@ -214,8 +214,8 @@ config CYCLADES
If you haven't heard about it, it's safe to say N.
config CYZ_INTR
bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)"
depends on EXPERIMENTAL && CYCLADES
bool "Cyclades-Z interrupt mode operation"
depends on CYCLADES
help
The Cyclades-Z family of multiport cards allows 2 (two) driver op
modes: polling and interrupt. In polling mode, the driver will check
@ -285,7 +285,7 @@ config SYNCLINK_GT
config NOZOMI
tristate "HSDPA Broadband Wireless Data Card - Globe Trotter"
depends on PCI && EXPERIMENTAL
depends on PCI
help
If you have a HSDPA driver Broadband Wireless Data Card -
Globe Trotter PCMCIA card, say Y here.
@ -294,7 +294,7 @@ config NOZOMI
will be called nozomi.
config ISI
tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
tristate "Multi-Tech multiport card support"
depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
@ -317,7 +317,6 @@ config N_HDLC
config N_GSM
tristate "GSM MUX line discipline support (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on NET
help
This line discipline provides support for the GSM MUX protocol and

View File

@ -420,7 +420,7 @@ static void check_modem_status(struct serial_state *info)
tty_hangup(port->tty);
}
}
if (port->flags & ASYNC_CTS_FLOW) {
if (tty_port_cts_enabled(port)) {
if (port->tty->hw_stopped) {
if (!(status & SER_CTS)) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
@ -646,7 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
custom.adkcon = AC_UARTBRK;
mb();
if (tty->termios->c_cflag & HUPCL)
if (tty->termios.c_cflag & HUPCL)
info->MCR &= ~(SER_DTR|SER_RTS);
rtsdtr_ctrl(info->MCR);
@ -670,7 +670,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
int bits;
unsigned long flags;
cflag = tty->termios->c_cflag;
cflag = tty->termios.c_cflag;
/* Byte size is always 8 bits plus parity bit if requested */
@ -707,8 +707,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
/* If the quotient is zero refuse the change */
if (!quot && old_termios) {
/* FIXME: Will need updating for new tty in the end */
tty->termios->c_cflag &= ~CBAUD;
tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
tty->termios.c_cflag &= ~CBAUD;
tty->termios.c_cflag |= (old_termios->c_cflag & CBAUD);
baud = tty_get_baud_rate(tty);
if (!baud)
baud = 9600;
@ -984,7 +984,7 @@ static void rs_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
info->MCR &= ~SER_RTS;
local_irq_save(flags);
@ -1012,7 +1012,7 @@ static void rs_unthrottle(struct tty_struct * tty)
else
rs_send_xchar(tty, START_CHAR(tty));
}
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
info->MCR |= SER_RTS;
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tty_lock();
tty_lock(tty);
tmp.line = tty->index;
tmp.port = state->port;
tmp.flags = state->tport.flags;
@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
tmp.close_delay = state->tport.close_delay;
tmp.closing_wait = state->tport.closing_wait;
tmp.custom_divisor = state->custom_divisor;
tty_unlock();
tty_unlock(tty);
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
tty_lock();
tty_lock(tty);
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
new_serial.custom_divisor != state->custom_divisor;
if (new_serial.irq || new_serial.port != state->port ||
new_serial.xmit_fifo_size != state->xmit_fifo_size) {
tty_unlock();
tty_unlock(tty);
return -EINVAL;
}
@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
(new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
tty_unlock();
tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
}
if (new_serial.baud_base < 9600) {
tty_unlock();
tty_unlock(tty);
return -EINVAL;
}
@ -1116,7 +1116,7 @@ check_and_exit:
}
} else
retval = startup(tty, state);
tty_unlock();
tty_unlock(tty);
return retval;
}
@ -1330,7 +1330,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct serial_state *info = tty->driver_data;
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
unsigned int cflag = tty->termios.c_cflag;
change_speed(tty, info, old_termios);
@ -1347,7 +1347,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!(old_termios->c_cflag & CBAUD) &&
(cflag & CBAUD)) {
info->MCR |= SER_DTR;
if (!(tty->termios->c_cflag & CRTSCTS) ||
if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= SER_RTS;
}
@ -1358,7 +1358,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@ -1371,7 +1371,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
(tty->termios.c_cflag & CLOCAL))
wake_up_interruptible(&info->open_wait);
#endif
}
@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);
error = tty_register_driver(serial_driver);
if (error)
goto fail_put_tty_driver;
state = rs_table;
state->port = (int)&custom.serdatr; /* Just to give it a value */
state->custom_divisor = 0;
@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
state->icount.overrun = state->icount.brk = 0;
tty_port_init(&state->tport);
state->tport.ops = &amiga_port_ops;
tty_port_link_device(&state->tport, serial_driver, 0);
error = tty_register_driver(serial_driver);
if (error)
goto fail_put_tty_driver;
printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");

View File

@ -263,6 +263,7 @@ static int __init bfin_jc_init(void)
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
tty_port_link_device(&port, bfin_jc_driver, 0);
ret = tty_register_driver(bfin_jc_driver);
if (ret)

View File

@ -727,7 +727,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
else
tty_hangup(tty);
}
if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) {
if (tty->hw_stopped) {
if (mdm_status & CyCTS) {
/* cy_start isn't used
@ -1459,7 +1459,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
if (tty->termios->c_cflag & HUPCL)
if (tty->termios.c_cflag & HUPCL)
cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
@ -1488,7 +1488,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
free_page((unsigned long)temp);
}
if (tty->termios->c_cflag & HUPCL)
if (tty->termios.c_cflag & HUPCL)
tty_port_lower_dtr_rts(&info->port);
set_bit(TTY_IO_ERROR, &tty->flags);
@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(info->port.close_wait,
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
@ -1999,14 +1999,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
int baud, baud_rate = 0;
int i;
if (!tty->termios) /* XXX can this happen at all? */
return;
if (info->line == -1)
return;
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
cflag = tty->termios.c_cflag;
iflag = tty->termios.c_iflag;
/*
* Set up the tty->alt_speed kludge
@ -2825,7 +2822,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
cy_set_line_char(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
cy_start(tty);
}
@ -2837,7 +2834,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
(tty->termios.c_cflag & CLOCAL))
wake_up_interruptible(&info->port.open_wait);
#endif
} /* cy_set_termios */
@ -2899,7 +2896,7 @@ static void cy_throttle(struct tty_struct *tty)
info->throttle = 1;
}
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
cyy_change_rts_dtr(info, 0, TIOCM_RTS);
@ -2938,7 +2935,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_send_xchar(tty, START_CHAR(tty));
}
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
card = info->card;
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
@ -3289,9 +3286,10 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
static int __init cy_detect_isa(void)
{
#ifdef CONFIG_ISA
struct cyclades_card *card;
unsigned short cy_isa_irq, nboard;
void __iomem *cy_isa_address;
unsigned short i, j, cy_isa_nchan;
unsigned short i, j, k, cy_isa_nchan;
int isparam = 0;
nboard = 0;
@ -3349,7 +3347,8 @@ static int __init cy_detect_isa(void)
}
/* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) {
if (cy_card[j].base_addr == NULL)
card = &cy_card[j];
if (card->base_addr == NULL)
break;
}
if (j == NR_CARDS) { /* no more cy_cards available */
@ -3363,7 +3362,7 @@ static int __init cy_detect_isa(void)
/* allocate IRQ */
if (request_irq(cy_isa_irq, cyy_interrupt,
0, "Cyclom-Y", &cy_card[j])) {
0, "Cyclom-Y", card)) {
printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
"could not allocate IRQ#%d.\n",
(unsigned long)cy_isa_address, cy_isa_irq);
@ -3372,16 +3371,16 @@ static int __init cy_detect_isa(void)
}
/* set cy_card */
cy_card[j].base_addr = cy_isa_address;
cy_card[j].ctl_addr.p9050 = NULL;
cy_card[j].irq = (int)cy_isa_irq;
cy_card[j].bus_index = 0;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
cy_card[j].nports = cy_isa_nchan;
if (cy_init_card(&cy_card[j])) {
cy_card[j].base_addr = NULL;
free_irq(cy_isa_irq, &cy_card[j]);
card->base_addr = cy_isa_address;
card->ctl_addr.p9050 = NULL;
card->irq = (int)cy_isa_irq;
card->bus_index = 0;
card->first_line = cy_next_channel;
card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
card->nports = cy_isa_nchan;
if (cy_init_card(card)) {
card->base_addr = NULL;
free_irq(cy_isa_irq, card);
iounmap(cy_isa_address);
continue;
}
@ -3393,9 +3392,10 @@ static int __init cy_detect_isa(void)
(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
cy_isa_irq, cy_isa_nchan, cy_next_channel);
for (j = cy_next_channel;
j < cy_next_channel + cy_isa_nchan; j++)
tty_register_device(cy_serial_driver, j, NULL);
for (k = 0, j = cy_next_channel;
j < cy_next_channel + cy_isa_nchan; j++, k++)
tty_port_register_device(&card->ports[k].port,
cy_serial_driver, j, NULL);
cy_next_channel += cy_isa_nchan;
}
return nboard;
@ -3695,10 +3695,11 @@ err:
static int __devinit cy_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct cyclades_card *card;
void __iomem *addr0 = NULL, *addr2 = NULL;
char *card_name = NULL;
u32 uninitialized_var(mailbox);
unsigned int device_id, nchan = 0, card_no, i;
unsigned int device_id, nchan = 0, card_no, i, j;
unsigned char plx_ver;
int retval, irq;
@ -3829,7 +3830,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* fill the next cy_card structure available */
for (card_no = 0; card_no < NR_CARDS; card_no++) {
if (cy_card[card_no].base_addr == NULL)
card = &cy_card[card_no];
if (card->base_addr == NULL)
break;
}
if (card_no == NR_CARDS) { /* no more cy_cards available */
@ -3843,27 +3845,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
/* allocate IRQ */
retval = request_irq(irq, cyy_interrupt,
IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
IRQF_SHARED, "Cyclom-Y", card);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
}
cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
card->num_chips = nchan / CyPORTS_PER_CHIP;
} else {
struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl;
zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
cy_card[card_no].hw_ver = mailbox;
cy_card[card_no].num_chips = (unsigned int)-1;
cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
card->hw_ver = mailbox;
card->num_chips = (unsigned int)-1;
card->board_ctrl = &zfw_ctrl->board_ctrl;
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
retval = request_irq(irq, cyz_interrupt,
IRQF_SHARED, "Cyclades-Z",
&cy_card[card_no]);
IRQF_SHARED, "Cyclades-Z", card);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
@ -3873,17 +3874,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* set cy_card */
cy_card[card_no].base_addr = addr2;
cy_card[card_no].ctl_addr.p9050 = addr0;
cy_card[card_no].irq = irq;
cy_card[card_no].bus_index = 1;
cy_card[card_no].first_line = cy_next_channel;
cy_card[card_no].nports = nchan;
retval = cy_init_card(&cy_card[card_no]);
card->base_addr = addr2;
card->ctl_addr.p9050 = addr0;
card->irq = irq;
card->bus_index = 1;
card->first_line = cy_next_channel;
card->nports = nchan;
retval = cy_init_card(card);
if (retval)
goto err_null;
pci_set_drvdata(pdev, &cy_card[card_no]);
pci_set_drvdata(pdev, card);
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
@ -3909,14 +3910,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
tty_register_device(cy_serial_driver, i, &pdev->dev);
for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
tty_port_register_device(&card->ports[j].port,
cy_serial_driver, i, &pdev->dev);
cy_next_channel += nchan;
return 0;
err_null:
cy_card[card_no].base_addr = NULL;
free_irq(irq, &cy_card[card_no]);
card->base_addr = NULL;
free_irq(irq, card);
err_unmap:
iounmap(addr0);
if (addr2)

View File

@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
goto error;
}
bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
tty_port_init(&bc->port);
bc->port.ops = &ehv_bc_tty_port_ops;
bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i,
&pdev->dev);
if (IS_ERR(bc->dev)) {
ret = PTR_ERR(bc->dev);
dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
goto error;
}
tty_port_init(&bc->port);
bc->port.ops = &ehv_bc_tty_port_ops;
dev_set_drvdata(&pdev->dev, bc);
dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",

View File

@ -76,7 +76,7 @@ config HVC_XEN_FRONTEND
config HVC_UDBG
bool "udbg based fake hypervisor console"
depends on PPC && EXPERIMENTAL
depends on PPC
select HVC_DRIVER
default n
help

View File

@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty)
hvc_kick();
}
static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct hvc_struct *hp;
int rc;
/* Auto increments kref reference if found. */
if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
tty->driver_data = hp;
rc = tty_port_install(&hp->port, driver, tty);
if (rc)
tty_port_put(&hp->port);
return rc;
}
/*
* The TTY interface won't be used until after the vio layer has exposed the vty
* adapter to the kernel.
*/
static int hvc_open(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
int rc = 0;
/* Auto increments kref reference if found. */
if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
if (hp->port.count++ > 0) {
@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
} /* else count == 0 */
spin_unlock_irqrestore(&hp->port.lock, flags);
tty->driver_data = hp;
tty_port_tty_set(&hp->port, tty);
if (hp->ops->notifier_add)
@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp->vtermno, hp->port.count);
spin_unlock_irqrestore(&hp->port.lock, flags);
}
}
static void hvc_cleanup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
tty_port_put(&hp->port);
}
@ -541,7 +558,7 @@ static int hvc_write_room(struct tty_struct *tty)
struct hvc_struct *hp = tty->driver_data;
if (!hp)
return -1;
return 0;
return hp->outbuf_size - hp->n_outbuf;
}
@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
#endif
static const struct tty_operations hvc_ops = {
.install = hvc_install,
.open = hvc_open,
.close = hvc_close,
.cleanup = hvc_cleanup,
.write = hvc_write,
.hangup = hvc_hangup,
.unthrottle = hvc_unthrottle,

View File

@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
return NULL;
}
/*
* This is invoked via the tty_open interface when a user app connects to the
* /dev node.
*/
static int hvcs_open(struct tty_struct *tty, struct file *filp)
static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct hvcs_struct *hvcsd;
int rc, retval = 0;
unsigned long flags;
unsigned int irq;
struct vio_dev *vdev;
unsigned long unit_address;
if (tty->driver_data)
goto fast_open;
unsigned long unit_address, flags;
unsigned int irq;
int retval;
/*
* Is there a vty-server that shares the same index?
* This function increments the kref index.
*/
if (!(hvcsd = hvcs_get_by_index(tty->index))) {
hvcsd = hvcs_get_by_index(tty->index);
if (!hvcsd) {
printk(KERN_WARNING "HVCS: open failed, no device associated"
" with tty->index %d.\n", tty->index);
return -ENODEV;
@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->connected == 0)
if ((retval = hvcs_partner_connect(hvcsd)))
goto error_release;
if (hvcsd->connected == 0) {
retval = hvcs_partner_connect(hvcsd);
if (retval) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
printk(KERN_WARNING "HVCS: partner connect failed.\n");
goto err_put;
}
}
hvcsd->port.count = 1;
hvcsd->port.count = 0;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* This must be done outside of the spinlock because it requests irqs
* and will grab the spinlock and free the connection if it fails.
*/
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
tty_port_put(&hvcsd->port);
retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
if (retval) {
printk(KERN_WARNING "HVCS: enable device failed.\n");
return rc;
goto err_put;
}
goto open_success;
retval = tty_port_install(&hvcsd->port, driver, tty);
if (retval)
goto err_irq;
fast_open:
hvcsd = tty->driver_data;
return 0;
err_irq:
spin_lock_irqsave(&hvcsd->lock, flags);
vio_disable_interrupts(hvcsd->vdev);
spin_unlock_irqrestore(&hvcsd->lock, flags);
free_irq(irq, hvcsd);
err_put:
tty_port_put(&hvcsd->port);
return retval;
}
/*
* This is invoked via the tty_open interface when a user app connects to the
* /dev node.
*/
static int hvcs_open(struct tty_struct *tty, struct file *filp)
{
struct hvcs_struct *hvcsd = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&hvcsd->lock, flags);
tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
open_success:
hvcs_kick();
printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
hvcsd->vdev->unit_address );
return 0;
error_release:
spin_unlock_irqrestore(&hvcsd->lock, flags);
tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval;
}
static void hvcs_close(struct tty_struct *tty, struct file *filp)
@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
}
static void hvcs_cleanup(struct tty_struct * tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
tty_port_put(&hvcsd->port);
}
@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
}
static const struct tty_operations hvcs_ops = {
.install = hvcs_install,
.open = hvcs_open,
.close = hvcs_close,
.cleanup = hvcs_cleanup,
.hangup = hvcs_hangup,
.write = hvcs_write,
.write_room = hvcs_write_room,

View File

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

View File

@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
spin_unlock_irqrestore(&hp->lock, flags);
/* Clear our own DTR */
if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL))
if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
hvsilib_write_mctrl(pv, 0);
/* Tear down the connection */

View File

@ -274,7 +274,12 @@ static void do_go_online(struct work_struct *work_go_online)
network->xaccm[0] = ~0U;
network->xaccm[3] = 0x60000000U;
network->raccm = ~0U;
ppp_register_channel(channel);
if (ppp_register_channel(channel) < 0) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": unable to register PPP channel\n");
kfree(channel);
return;
}
spin_lock_irqsave(&network->lock, flags);
network->ppp_channel = channel;
}

View File

@ -476,7 +476,7 @@ static int add_tty(int j,
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
tty_register_device(ipw_tty_driver, j, NULL);
tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
if (secondary_channel_idx != -1)

View File

@ -600,7 +600,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
port->status &= ~ISI_DCD;
}
if (port->port.flags & ASYNC_CTS_FLOW) {
if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (header & ISI_CTS) {
port->port.tty->hw_stopped = 0;
@ -702,7 +702,7 @@ static void isicom_config_port(struct tty_struct *tty)
/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
if (baud < 1 || baud > 4)
tty->termios->c_cflag &= ~CBAUDEX;
tty->termios.c_cflag &= ~CBAUDEX;
else
baud += 15;
}
@ -1196,8 +1196,8 @@ static void isicom_set_termios(struct tty_struct *tty,
if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
return;
if (tty->termios->c_cflag == old_termios->c_cflag &&
tty->termios->c_iflag == old_termios->c_iflag)
if (tty->termios.c_cflag == old_termios->c_cflag &&
tty->termios.c_iflag == old_termios->c_iflag)
return;
spin_lock_irqsave(&port->card->card_lock, flags);
@ -1205,7 +1205,7 @@ static void isicom_set_termios(struct tty_struct *tty,
spin_unlock_irqrestore(&port->card->card_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
isicom_start(tty);
}
@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
goto errunri;
for (index = 0; index < board->port_count; index++)
tty_register_device(isicom_normal, board->index * 16 + index,
tty_port_register_device(&board->ports[index].port,
isicom_normal, board->index * 16 + index,
&pdev->dev);
return 0;

View File

@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock);
static unsigned long baseaddr[MAX_BOARDS];
static unsigned int type[MAX_BOARDS];
static unsigned int numports[MAX_BOARDS];
static struct tty_port moxa_service_port;
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
@ -367,10 +368,10 @@ static int moxa_ioctl(struct tty_struct *tty,
tmp.dcd = 1;
ttyp = tty_port_tty_get(&p->port);
if (!ttyp || !ttyp->termios)
if (!ttyp)
tmp.cflag = p->cflag;
else
tmp.cflag = ttyp->termios->c_cflag;
tmp.cflag = ttyp->termios.c_cflag;
tty_kref_put(ttyp);
copy:
if (copy_to_user(argm, &tmp, sizeof(tmp)))
@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
const struct firmware *fw;
const char *file;
struct moxa_port *p;
unsigned int i;
unsigned int i, first_idx;
int ret;
brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
mod_timer(&moxaTimer, jiffies + HZ / 50);
spin_unlock_bh(&moxa_lock);
first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
for (i = 0; i < brd->numPorts; i++)
tty_port_register_device(&brd->ports[i].port, moxaDriver,
first_idx + i, dev);
return 0;
err_free:
kfree(brd->ports);
@ -896,7 +902,7 @@ err:
static void moxa_board_deinit(struct moxa_board_conf *brd)
{
unsigned int a, opened;
unsigned int a, opened, first_idx;
mutex_lock(&moxa_openlock);
spin_lock_bh(&moxa_lock);
@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
mutex_lock(&moxa_openlock);
}
first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
for (a = 0; a < brd->numPorts; a++)
tty_unregister_device(moxaDriver, first_idx + a);
iounmap(brd->basemem);
brd->basemem = NULL;
kfree(brd->ports);
@ -967,6 +977,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
retval = -ENOMEM;
goto err_reg;
}
@ -1031,9 +1042,14 @@ static int __init moxa_init(void)
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
if (!moxaDriver)
return -ENOMEM;
tty_port_init(&moxa_service_port);
moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(moxaDriver))
return PTR_ERR(moxaDriver);
moxaDriver->name = "ttyMX";
moxaDriver->major = ttymajor;
@ -1044,8 +1060,9 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
/* Having one more port only for ioctls is ugly */
tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
@ -1178,7 +1195,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
mutex_lock(&ch->port.mutex);
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, tty->termios);
moxa_set_tty_param(tty, &tty->termios);
MoxaPortLineCtrl(ch, 1, 1);
MoxaPortEnable(ch);
MoxaSetFifo(ch, ch->type == PORT_16550A);
@ -1193,7 +1210,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
static void moxa_close(struct tty_struct *tty, struct file *filp)
{
struct moxa_port *ch = tty->driver_data;
ch->cflag = tty->termios->c_cflag;
ch->cflag = tty->termios.c_cflag;
tty_port_close(&ch->port, tty, filp);
}
@ -1464,7 +1481,7 @@ static void moxa_poll(unsigned long ignored)
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
register struct ktermios *ts = tty->termios;
register struct ktermios *ts = &tty->termios;
struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;

View File

@ -643,7 +643,7 @@ static int mxser_change_speed(struct tty_struct *tty,
int ret = 0;
unsigned char status;
cflag = tty->termios->c_cflag;
cflag = tty->termios.c_cflag;
if (!info->ioaddr)
return ret;
@ -830,7 +830,7 @@ static void mxser_check_modem_status(struct tty_struct *tty,
wake_up_interruptible(&port->port.open_wait);
}
if (port->port.flags & ASYNC_CTS_FLOW) {
if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (status & UART_MSR_CTS) {
tty->hw_stopped = 0;
@ -1520,10 +1520,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
tty = tty_port_tty_get(port);
if (!tty || !tty->termios)
if (!tty)
ms.cflag = ip->normal_termios.c_cflag;
else
ms.cflag = tty->termios->c_cflag;
ms.cflag = tty->termios.c_cflag;
tty_kref_put(tty);
spin_lock_irq(&ip->slock);
status = inb(ip->ioaddr + UART_MSR);
@ -1589,13 +1589,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
tty = tty_port_tty_get(&ip->port);
if (!tty || !tty->termios) {
if (!tty) {
cflag = ip->normal_termios.c_cflag;
iflag = ip->normal_termios.c_iflag;
me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
} else {
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
cflag = tty->termios.c_cflag;
iflag = tty->termios.c_iflag;
me->baudrate[p] = tty_get_baud_rate(tty);
}
tty_kref_put(tty);
@ -1853,7 +1853,7 @@ static void mxser_stoprx(struct tty_struct *tty)
}
}
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@ -1890,7 +1890,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
}
}
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@ -1939,14 +1939,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
spin_unlock_irqrestore(&info->slock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
/* Handle sw stopped */
if ((old_termios->c_iflag & IXON) &&
!(tty->termios->c_iflag & IXON)) {
!(tty->termios.c_iflag & IXON)) {
tty->stopped = 0;
if (info->board->chip_flag) {
@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
static bool allow_overlapping_vector;
module_param(allow_overlapping_vector, bool, S_IRUGO);
MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");
static bool mxser_overlapping_vector(struct mxser_board *brd)
{
return allow_overlapping_vector &&
brd->vector >= brd->ports[0].ioaddr &&
brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports;
}
static int mxser_request_vector(struct mxser_board *brd)
{
if (mxser_overlapping_vector(brd))
return 0;
return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO;
}
static void mxser_release_vector(struct mxser_board *brd)
{
if (mxser_overlapping_vector(brd))
return;
release_region(brd->vector, 1);
}
static void mxser_release_ISA_res(struct mxser_board *brd)
{
free_irq(brd->irq, brd);
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
release_region(brd->vector, 1);
mxser_release_vector(brd);
}
static int __devinit mxser_initbrd(struct mxser_board *brd,
@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
{
int id, i, bits;
int id, i, bits, ret;
unsigned short regs[16], irq;
unsigned char scratch, scratch2;
@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
8 * brd->info->nports - 1);
return -EIO;
}
if (!request_region(brd->vector, 1, "mxser(vector)")) {
ret = mxser_request_vector(brd);
if (ret) {
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
printk(KERN_ERR "mxser: can't request interrupt vector region: "
"0x%.8lx-0x%.8lx\n",
brd->ports[0].ioaddr, brd->ports[0].ioaddr +
8 * brd->info->nports - 1);
return -EIO;
return ret;
}
return brd->info->nports;
@ -2598,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
goto err_rel3;
for (i = 0; i < brd->info->nports; i++)
tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
brd->idx + i, &pdev->dev);
pci_set_drvdata(pdev, brd);
@ -2695,7 +2723,8 @@ static int __init mxser_module_init(void)
brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++)
tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
tty_port_register_device(&brd->ports[i].port,
mxvar_sdriver, brd->idx + i, NULL);
m++;
}

View File

@ -108,7 +108,7 @@ struct gsm_mux_net {
*/
struct gsm_msg {
struct gsm_msg *next;
struct list_head list;
u8 addr; /* DLCI address + flags */
u8 ctrl; /* Control byte + flags */
unsigned int len; /* Length of data block (can be zero) */
@ -245,8 +245,7 @@ struct gsm_mux {
unsigned int tx_bytes; /* TX data outstanding */
#define TX_THRESH_HI 8192
#define TX_THRESH_LO 2048
struct gsm_msg *tx_head; /* Pending data packets */
struct gsm_msg *tx_tail;
struct list_head tx_list; /* Pending data packets */
/* Control messages */
struct timer_list t2_timer; /* Retransmit timer for commands */
@ -489,7 +488,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
default:
if (!(control & 0x01)) {
pr_cont("I N(S)%d N(R)%d",
(control & 0x0E) >> 1, (control & 0xE) >> 5);
(control & 0x0E) >> 1, (control & 0xE0) >> 5);
} else switch (control & 0x0F) {
case RR:
pr_cont("RR(%d)", (control & 0xE0) >> 5);
@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
m->len = len;
m->addr = addr;
m->ctrl = ctrl;
m->next = NULL;
INIT_LIST_HEAD(&m->list);
return m;
}
@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
*
* The tty device has called us to indicate that room has appeared in
* the transmit queue. Ram more data into the pipe if we have any
* If we have been flow-stopped by a CMD_FCOFF, then we can only
* send messages on DLCI0 until CMD_FCON
*
* FIXME: lock against link layer control transmissions
*/
static void gsm_data_kick(struct gsm_mux *gsm)
{
struct gsm_msg *msg = gsm->tx_head;
struct gsm_msg *msg, *nmsg;
int len;
int skip_sof = 0;
/* FIXME: We need to apply this solely to data messages */
if (gsm->constipated)
return;
while (gsm->tx_head != NULL) {
msg = gsm->tx_head;
list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
if (gsm->constipated && msg->addr)
continue;
if (gsm->encoding != 0) {
gsm->txframe[0] = GSM1_SOF;
len = gsm_stuff_frame(msg->data,
@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm)
len - skip_sof) < 0)
break;
/* FIXME: Can eliminate one SOF in many more cases */
gsm->tx_head = msg->next;
if (gsm->tx_head == NULL)
gsm->tx_tail = NULL;
gsm->tx_bytes -= msg->len;
kfree(msg);
/* For a burst of frames skip the extra SOF within the
burst */
skip_sof = 1;
list_del(&msg->list);
kfree(msg);
}
}
@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
msg->data = dp;
/* Add to the actual output queue */
if (gsm->tx_tail)
gsm->tx_tail->next = msg;
else
gsm->tx_head = msg;
gsm->tx_tail = msg;
list_add_tail(&msg->list, &gsm->tx_list);
gsm->tx_bytes += msg->len;
gsm_data_kick(gsm);
}
@ -875,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
/* dlci->skb is locked by tx_lock */
if (dlci->skb == NULL) {
dlci->skb = skb_dequeue(&dlci->skb_list);
dlci->skb = skb_dequeue_tail(&dlci->skb_list);
if (dlci->skb == NULL)
return 0;
first = 1;
@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
if (len > gsm->mtu) {
if (dlci->adaption == 3) {
/* Over long frame, bin it */
kfree_skb(dlci->skb);
dev_kfree_skb_any(dlci->skb);
dlci->skb = NULL;
return 0;
}
@ -899,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
/* FIXME: need a timer or something to kick this so it can't
get stuck with no work outstanding and no buffer free */
if (msg == NULL)
if (msg == NULL) {
skb_queue_tail(&dlci->skb_list, dlci->skb);
dlci->skb = NULL;
return -ENOMEM;
}
dp = msg->data;
if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
@ -912,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
skb_pull(dlci->skb, len);
__gsm_data_queue(dlci, msg);
if (last) {
kfree_skb(dlci->skb);
dev_kfree_skb_any(dlci->skb);
dlci->skb = NULL;
}
return size;
@ -971,16 +967,22 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
{
unsigned long flags;
int sweep;
if (dlci->constipated)
return;
spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
/* If we have nothing running then we need to fire up */
sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
if (dlci->gsm->tx_bytes == 0) {
if (dlci->net)
gsm_dlci_data_output_framed(dlci->gsm, dlci);
else
gsm_dlci_data_output(dlci->gsm, dlci);
} else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
gsm_dlci_data_sweep(dlci->gsm);
}
if (sweep)
gsm_dlci_data_sweep(dlci->gsm);
spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
}
@ -1027,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
{
int mlines = 0;
u8 brk = 0;
int fc;
/* The modem status command can either contain one octet (v.24 signals)
or two octets (v.24 signals + break signals). The length field will
@ -1038,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
else {
brk = modem & 0x7f;
modem = (modem >> 7) & 0x7f;
};
}
/* Flow control/ready to communicate */
if (modem & MDM_FC) {
fc = (modem & MDM_FC) || !(modem & MDM_RTR);
if (fc && !dlci->constipated) {
/* Need to throttle our output on this device */
dlci->constipated = 1;
}
if (modem & MDM_RTC) {
mlines |= TIOCM_DSR | TIOCM_DTR;
} else if (!fc && dlci->constipated) {
dlci->constipated = 0;
gsm_dlci_data_kick(dlci);
}
/* Map modem bits */
if (modem & MDM_RTC)
mlines |= TIOCM_DSR | TIOCM_DTR;
if (modem & MDM_RTR)
mlines |= TIOCM_RTS | TIOCM_CTS;
if (modem & MDM_IC)
@ -1061,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
/* Carrier drop -> hangup */
if (tty) {
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
if (!(tty->termios->c_cflag & CLOCAL))
if (!(tty->termios.c_cflag & CLOCAL))
tty_hangup(tty);
if (brk & 0x01)
tty_insert_flip_char(tty, 0, TTY_BREAK);
@ -1190,6 +1195,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
u8 *data, int clen)
{
u8 buf[1];
unsigned long flags;
switch (command) {
case CMD_CLD: {
struct gsm_dlci *dlci = gsm->dlci[0];
@ -1206,16 +1213,18 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
gsm_control_reply(gsm, CMD_TEST, data, clen);
break;
case CMD_FCON:
/* Modem wants us to STFU */
gsm->constipated = 1;
gsm_control_reply(gsm, CMD_FCON, NULL, 0);
break;
case CMD_FCOFF:
/* Modem can accept data again */
gsm->constipated = 0;
gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
gsm_control_reply(gsm, CMD_FCON, NULL, 0);
/* Kick the link in case it is idling */
spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
spin_unlock_irqrestore(&gsm->tx_lock, flags);
break;
case CMD_FCOFF:
/* Modem wants us to STFU */
gsm->constipated = 1;
gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
break;
case CMD_MSC:
/* Out of band modem line change indicator for a DLCI */
@ -1668,7 +1677,7 @@ static void gsm_dlci_free(struct kref *ref)
dlci->gsm->dlci[dlci->addr] = NULL;
kfifo_free(dlci->fifo);
while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
kfree_skb(dlci->skb);
dev_kfree_skb(dlci->skb);
kfree(dlci);
}
@ -2007,7 +2016,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
{
int i;
struct gsm_dlci *dlci = gsm->dlci[0];
struct gsm_msg *txq;
struct gsm_msg *txq, *ntxq;
struct gsm_control *gc;
gsm->dead = 1;
@ -2042,11 +2051,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
if (gsm->dlci[i])
gsm_dlci_release(gsm->dlci[i]);
/* Now wipe the queues */
for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
gsm->tx_head = txq->next;
list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
kfree(txq);
}
gsm->tx_tail = NULL;
INIT_LIST_HEAD(&gsm->tx_list);
}
EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
@ -2157,6 +2164,7 @@ struct gsm_mux *gsm_alloc_mux(void)
}
spin_lock_init(&gsm->lock);
kref_init(&gsm->ref);
INIT_LIST_HEAD(&gsm->tx_list);
gsm->t1 = T1;
gsm->t2 = T2;
@ -2273,7 +2281,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
gsm->error(gsm, *dp, flags);
break;
default:
WARN_ONCE("%s: unknown flag %d\n",
WARN_ONCE(1, "%s: unknown flag %d\n",
tty_name(tty, buf), flags);
break;
}
@ -2377,12 +2385,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
/* Queue poll */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
if (gsm->tx_bytes < TX_THRESH_LO) {
spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_data_sweep(gsm);
spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
@ -2868,14 +2876,14 @@ static const struct tty_port_operations gsm_port_ops = {
.dtr_rts = gsm_dtr_rts,
};
static int gsmtty_open(struct tty_struct *tty, struct file *filp)
static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct gsm_mux *gsm;
struct gsm_dlci *dlci;
struct tty_port *port;
unsigned int line = tty->index;
unsigned int mux = line >> 6;
bool alloc = false;
int ret;
line = line & 0x3F;
@ -2889,14 +2897,35 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
gsm = gsm_mux[mux];
if (gsm->dead)
return -EL2HLT;
/* If DLCI 0 is not yet fully open return an error. This is ok from a locking
perspective as we don't have to worry about this if DLCI0 is lost */
if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
return -EL2NSYNC;
dlci = gsm->dlci[line];
if (dlci == NULL)
if (dlci == NULL) {
alloc = true;
dlci = gsm_dlci_alloc(gsm, line);
}
if (dlci == NULL)
return -ENOMEM;
port = &dlci->port;
port->count++;
ret = tty_port_install(&dlci->port, driver, tty);
if (ret) {
if (alloc)
dlci_put(dlci);
return ret;
}
tty->driver_data = dlci;
return 0;
}
static int gsmtty_open(struct tty_struct *tty, struct file *filp)
{
struct gsm_dlci *dlci = tty->driver_data;
struct tty_port *port = &dlci->port;
port->count++;
dlci_get(dlci);
dlci_get(dlci->gsm->dlci[0]);
mux_get(dlci->gsm);
@ -3043,13 +3072,13 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
the RPN control message. This however rapidly gets nasty as we
then have to remap modem signals each way according to whether
our virtual cable is null modem etc .. */
tty_termios_copy_hw(tty->termios, old);
tty_termios_copy_hw(&tty->termios, old);
}
static void gsmtty_throttle(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx &= ~TIOCM_DTR;
dlci->throttled = 1;
/* Send an MSC with DTR cleared */
@ -3059,7 +3088,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
static void gsmtty_unthrottle(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
if (tty->termios->c_cflag & CRTSCTS)
if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx |= TIOCM_DTR;
dlci->throttled = 0;
/* Send an MSC with DTR set */
@ -3085,6 +3114,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
/* Virtual ttys for the demux */
static const struct tty_operations gsmtty_ops = {
.install = gsmtty_install,
.open = gsmtty_open,
.close = gsmtty_close,
.write = gsmtty_write,

View File

@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
tty_lock();
tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock;
}
/* block until there is a message: */
wait_event_interruptible_tty(pInfo->read_wait,
wait_event_interruptible_tty(tty, pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient)));
}
@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
}
ret = -EPERM;
unlock:
tty_unlock();
tty_unlock(tty);
return ret;
}
@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
tty_lock();
tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
tty_unlock();
tty_unlock(tty);
return 0;
}

View File

@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
static void n_tty_set_room(struct tty_struct *tty)
{
/* tty->read_cnt is not read locked ? */
int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
int left;
int old_left;
/* tty->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
* its flags, e.g. parity error). */
left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
} else
left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
/*
* If we are doing input canonicalization, and there are no
* pending newlines, let characters through without limit, so
@ -1432,6 +1440,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
tty_throttle(tty);
/* FIXME: there is a tiny race here if the receive room check runs
before the other work executes and empties the buffer (upping
the receiving room and unthrottling. We then throttle and get
stuck. This has been observed and traced down by Vincent Pillet/
We need to address this when we sort out out the rx path locking */
}
int is_ignored(int sig)
@ -1460,7 +1474,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
BUG_ON(!tty);
if (old)
canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
if (canon_change) {
memset(&tty->read_flags, 0, sizeof tty->read_flags);
tty->canon_head = tty->read_tail;
@ -1728,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
do_it_again:
BUG_ON(!tty->read_buf);
if (WARN_ON(!tty->read_buf))
return -EAGAIN;
c = job_control(tty, file);
if (c < 0)
@ -1832,13 +1847,13 @@ do_it_again:
if (tty->icanon && !L_EXTPROC(tty)) {
/* N.B. avoid overrun if nr == 0 */
spin_lock_irqsave(&tty->read_lock, flags);
while (nr && tty->read_cnt) {
int eol;
eol = test_and_clear_bit(tty->read_tail,
tty->read_flags);
c = tty->read_buf[tty->read_tail];
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = ((tty->read_tail+1) &
(N_TTY_BUF_SIZE-1));
tty->read_cnt--;
@ -1856,15 +1871,19 @@ do_it_again:
if (tty_put_user(tty, c, b++)) {
retval = -EFAULT;
b--;
spin_lock_irqsave(&tty->read_lock, flags);
break;
}
nr--;
}
if (eol) {
tty_audit_push(tty);
spin_lock_irqsave(&tty->read_lock, flags);
break;
}
spin_lock_irqsave(&tty->read_lock, flags);
}
spin_unlock_irqrestore(&tty->read_lock, flags);
if (retval)
break;
} else {

View File

@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
port->dc = dc;
tty_port_init(&port->port);
port->port.ops = &noz_tty_port_ops;
tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
&pdev->dev);
tty_dev = tty_port_register_device(&port->port, ntty_driver,
dc->index_start + i, &pdev->dev);
if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);

View File

@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
tty->packet = 0;
/* Review - krefs on tty_link ?? */
if (!tty->link)
return;
tty->link->packet = 0;
@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&devpts_mutex);
}
#endif
tty_unlock();
tty_unlock(tty);
tty_vhangup(tty->link);
tty_lock();
tty_lock(tty);
}
}
@ -231,8 +232,8 @@ out:
static void pty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
tty->termios->c_cflag &= ~(CSIZE | PARENB);
tty->termios->c_cflag |= (CS8 | CREAD);
tty->termios.c_cflag &= ~(CSIZE | PARENB);
tty->termios.c_cflag |= (CS8 | CREAD);
}
/**
@ -282,60 +283,110 @@ done:
return 0;
}
/* Traditional BSD devices */
#ifdef CONFIG_LEGACY_PTYS
static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
/**
* pty_common_install - set up the pty pair
* @driver: the pty driver
* @tty: the tty being instantiated
* @bool: legacy, true if this is BSD style
*
* Perform the initial set up for the tty/pty pair. Called from the
* tty layer when the port is first opened.
*
* Locking: the caller must hold the tty_mutex
*/
static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
bool legacy)
{
struct tty_struct *o_tty;
struct tty_port *ports[2];
int idx = tty->index;
int retval;
int retval = -ENOMEM;
o_tty = alloc_tty_struct();
if (!o_tty)
return -ENOMEM;
goto err;
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
if (!ports[0] || !ports[1])
goto err_free_tty;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
retval = -ENOMEM;
goto err_free_tty;
}
initialize_tty_struct(o_tty, driver->other, idx);
/* We always use new tty termios data so we can do this
the easy way .. */
retval = tty_init_termios(tty);
if (retval)
goto err_deinit_tty;
if (legacy) {
/* We always use new tty termios data so we can do this
the easy way .. */
retval = tty_init_termios(tty);
if (retval)
goto err_deinit_tty;
retval = tty_init_termios(o_tty);
if (retval)
goto err_free_termios;
retval = tty_init_termios(o_tty);
if (retval)
goto err_free_termios;
driver->other->ttys[idx] = o_tty;
driver->ttys[idx] = tty;
} else {
memset(&tty->termios_locked, 0, sizeof(tty->termios_locked));
tty->termios = driver->init_termios;
memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked));
o_tty->termios = driver->other->init_termios;
}
/*
* Everything allocated ... set up the o_tty structure.
*/
driver->other->ttys[idx] = o_tty;
tty_driver_kref_get(driver->other);
if (driver->subtype == PTY_TYPE_MASTER)
o_tty->count++;
/* Establish the links in both directions */
tty->link = o_tty;
o_tty->link = tty;
tty_port_init(ports[0]);
tty_port_init(ports[1]);
o_tty->port = ports[0];
tty->port = ports[1];
tty_driver_kref_get(driver);
tty->count++;
driver->ttys[idx] = tty;
return 0;
err_free_termios:
tty_free_termios(tty);
if (legacy)
tty_free_termios(tty);
err_deinit_tty:
deinitialize_tty_struct(o_tty);
module_put(o_tty->driver->owner);
err_free_tty:
kfree(ports[0]);
kfree(ports[1]);
free_tty_struct(o_tty);
err:
return retval;
}
static void pty_cleanup(struct tty_struct *tty)
{
kfree(tty->port);
}
/* Traditional BSD devices */
#ifdef CONFIG_LEGACY_PTYS
static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
{
return pty_common_install(driver, tty, true);
}
static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
{
struct tty_struct *pair = tty->link;
driver->ttys[tty->index] = NULL;
if (pair)
pair->driver->ttys[pair->index] = NULL;
}
static int pty_bsd_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@ -366,7 +417,9 @@ static const struct tty_operations master_pty_ops_bsd = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_bsd_ioctl,
.resize = pty_resize
.cleanup = pty_cleanup,
.resize = pty_resize,
.remove = pty_remove
};
static const struct tty_operations slave_pty_ops_bsd = {
@ -379,7 +432,9 @@ static const struct tty_operations slave_pty_ops_bsd = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.resize = pty_resize
.cleanup = pty_cleanup,
.resize = pty_resize,
.remove = pty_remove
};
static void __init legacy_pty_init(void)
@ -389,12 +444,18 @@ static void __init legacy_pty_init(void)
if (legacy_count <= 0)
return;
pty_driver = alloc_tty_driver(legacy_count);
if (!pty_driver)
pty_driver = tty_alloc_driver(legacy_count,
TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_ALLOC);
if (IS_ERR(pty_driver))
panic("Couldn't allocate pty driver");
pty_slave_driver = alloc_tty_driver(legacy_count);
if (!pty_slave_driver)
pty_slave_driver = tty_alloc_driver(legacy_count,
TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_ALLOC);
if (IS_ERR(pty_slave_driver))
panic("Couldn't allocate pty slave driver");
pty_driver->driver_name = "pty_master";
@ -410,7 +471,6 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_lflag = 0;
pty_driver->init_termios.c_ispeed = 38400;
pty_driver->init_termios.c_ospeed = 38400;
pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &master_pty_ops_bsd);
@ -424,8 +484,6 @@ static void __init legacy_pty_init(void)
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_slave_driver->init_termios.c_ispeed = 38400;
pty_slave_driver->init_termios.c_ospeed = 38400;
pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
@ -497,78 +555,22 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
return tty;
}
static void pty_unix98_shutdown(struct tty_struct *tty)
{
tty_driver_remove_tty(tty->driver, tty);
/* We have our own method as we don't use the tty index */
kfree(tty->termios);
}
/* We have no need to install and remove our tty objects as devpts does all
the work for us */
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct tty_struct *o_tty;
int idx = tty->index;
o_tty = alloc_tty_struct();
if (!o_tty)
return -ENOMEM;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
goto err_free_tty;
}
initialize_tty_struct(o_tty, driver->other, idx);
tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
if (tty->termios == NULL)
goto err_free_mem;
*tty->termios = driver->init_termios;
tty->termios_locked = tty->termios + 1;
o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
if (o_tty->termios == NULL)
goto err_free_mem;
*o_tty->termios = driver->other->init_termios;
o_tty->termios_locked = o_tty->termios + 1;
tty_driver_kref_get(driver->other);
if (driver->subtype == PTY_TYPE_MASTER)
o_tty->count++;
/* Establish the links in both directions */
tty->link = o_tty;
o_tty->link = tty;
/*
* All structures have been allocated, so now we install them.
* Failures after this point use release_tty to clean up, so
* there's no need to null out the local pointers.
*/
tty_driver_kref_get(driver);
tty->count++;
return 0;
err_free_mem:
deinitialize_tty_struct(o_tty);
kfree(o_tty->termios);
kfree(tty->termios);
module_put(o_tty->driver->owner);
err_free_tty:
free_tty_struct(o_tty);
return -ENOMEM;
return pty_common_install(driver, tty, false);
}
static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
}
static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
}
static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup,
.install = pty_unix98_install,
.remove = ptm_unix98_remove,
.remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@ -578,14 +580,14 @@ static const struct tty_operations ptm_unix98_ops = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
.shutdown = pty_unix98_shutdown,
.resize = pty_resize
.resize = pty_resize,
.cleanup = pty_cleanup
};
static const struct tty_operations pty_unix98_ops = {
.lookup = pts_unix98_lookup,
.install = pty_unix98_install,
.remove = pts_unix98_remove,
.remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@ -594,7 +596,7 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.shutdown = pty_unix98_shutdown
.cleanup = pty_cleanup,
};
/**
@ -622,26 +624,28 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval;
/* find a device that is not in use. */
tty_lock();
mutex_lock(&devpts_mutex);
index = devpts_new_index(inode);
tty_unlock();
if (index < 0) {
retval = index;
mutex_unlock(&devpts_mutex);
goto err_file;
}
mutex_lock(&tty_mutex);
mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index);
mutex_unlock(&devpts_mutex);
tty_lock();
mutex_unlock(&tty_mutex);
mutex_lock(&tty_mutex);
tty = tty_init_dev(ptm_driver, index);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
goto out;
}
/* The tty returned here is locked so we can safely
drop the mutex */
mutex_unlock(&tty_mutex);
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp);
@ -654,15 +658,15 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
tty_unlock();
tty_unlock(tty);
return 0;
err_release:
tty_unlock();
tty_unlock(tty);
tty_release(inode, filp);
return retval;
out:
mutex_unlock(&tty_mutex);
devpts_kill_index(inode, index);
tty_unlock();
err_file:
tty_free_file(filp);
return retval;
@ -672,11 +676,21 @@ static struct file_operations ptmx_fops;
static void __init unix98_pty_init(void)
{
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
if (!ptm_driver)
ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV |
TTY_DRIVER_DEVPTS_MEM |
TTY_DRIVER_DYNAMIC_ALLOC);
if (IS_ERR(ptm_driver))
panic("Couldn't allocate Unix98 ptm driver");
pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
if (!pts_driver)
pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV |
TTY_DRIVER_DEVPTS_MEM |
TTY_DRIVER_DYNAMIC_ALLOC);
if (IS_ERR(pts_driver))
panic("Couldn't allocate Unix98 pts driver");
ptm_driver->driver_name = "pty_master";
@ -692,8 +706,6 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->init_termios.c_ispeed = 38400;
ptm_driver->init_termios.c_ospeed = 38400;
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &ptm_unix98_ops);
@ -707,8 +719,6 @@ static void __init unix98_pty_init(void)
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->init_termios.c_ispeed = 38400;
pts_driver->init_termios.c_ospeed = 38400;
pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver, &pty_unix98_ops);

View File

@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
spin_lock_init(&info->slock);
mutex_init(&info->write_mtx);
rp_table[line] = info;
tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
NULL);
tty_port_register_device(&info->port, rocket_driver, line,
pci_dev ? &pci_dev->dev : NULL);
}
/*
@ -720,7 +720,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info,
unsigned rocketMode;
int bits, baud, divisor;
CHANNEL_t *cp;
struct ktermios *t = tty->termios;
struct ktermios *t = &tty->termios;
cp = &info->channel;
cflag = t->c_cflag;
@ -978,7 +978,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
tty->alt_speed = 460800;
configure_r_port(tty, info, NULL);
if (tty->termios->c_cflag & CBAUD) {
if (tty->termios.c_cflag & CBAUD) {
sSetDTR(cp);
sSetRTS(cp);
}
@ -1089,35 +1089,35 @@ static void rp_set_termios(struct tty_struct *tty,
if (rocket_paranoia_check(info, "rp_set_termios"))
return;
cflag = tty->termios->c_cflag;
cflag = tty->termios.c_cflag;
/*
* This driver doesn't support CS5 or CS6
*/
if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
tty->termios->c_cflag =
tty->termios.c_cflag =
((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
/* Or CMSPAR */
tty->termios->c_cflag &= ~CMSPAR;
tty->termios.c_cflag &= ~CMSPAR;
configure_r_port(tty, info, old_termios);
cp = &info->channel;
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
sClrDTR(cp);
sClrRTS(cp);
}
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
sSetRTS(cp);
sSetDTR(cp);
}
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rp_start(tty);
}

View File

@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
unsigned cflag;
int i;
cflag = tty->termios->c_cflag;
cflag = tty->termios.c_cflag;
if (!(port = info->port))
return;
@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
return;
info->is_cons = (tty->termios->c_line == N_TTY);
info->is_cons = (tty->termios.c_line == N_TTY);
printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
}
@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
tty->termios->c_line = N_TTY;
tty->termios.c_line = N_TTY;
if (tty->ldisc.open)
(tty->ldisc.open)(tty);
}
@ -1189,12 +1189,6 @@ rs68328_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &rs_ops);
if (tty_register_driver(serial_driver)) {
put_tty_driver(serial_driver);
printk(KERN_ERR "Couldn't register serial driver\n");
return -ENOMEM;
}
local_irq_save(flags);
for(i=0;i<NR_PORTS;i++) {
@ -1224,8 +1218,17 @@ rs68328_init(void)
0,
"M68328_UART", info))
panic("Unable to attach 68328 serial interrupt\n");
tty_port_link_device(&info->tport, serial_driver, i);
}
local_irq_restore(flags);
if (tty_register_driver(serial_driver)) {
put_tty_driver(serial_driver);
printk(KERN_ERR "Couldn't register serial driver\n");
return -ENOMEM;
}
return 0;
}

View File

@ -290,6 +290,9 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
.flags = UART_CAP_FIFO,
},
[PORT_8250_CIR] = {
.name = "CIR port"
}
};
/* Uart divisor latch read */
@ -1037,6 +1040,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
unsigned char save_lcr, save_mcr;
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int old_capabilities;
if (!port->iobase && !port->mapbase && !port->membase)
return;
@ -1087,6 +1091,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
/*
* We failed; there's nothing here
*/
spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
scratch2, scratch3);
goto out;
@ -1110,6 +1115,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
status1 = serial_in(up, UART_MSR) & 0xF0;
serial_out(up, UART_MCR, save_mcr);
if (status1 != 0x90) {
spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
status1);
goto out;
@ -1132,8 +1138,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(up, UART_IIR) >> 6;
DEBUG_AUTOCONF("iir=%d ", scratch);
switch (scratch) {
case 0:
autoconfig_8250(up);
@ -1167,19 +1171,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
serial_out(up, UART_LCR, save_lcr);
if (up->capabilities != uart_config[port->type].flags) {
printk(KERN_WARNING
"ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), up->capabilities,
uart_config[port->type].flags);
}
port->fifosize = uart_config[up->port.type].fifo_size;
old_capabilities = up->capabilities;
up->capabilities = uart_config[port->type].flags;
up->tx_loadsz = uart_config[port->type].tx_loadsz;
if (port->type == PORT_UNKNOWN)
goto out;
goto out_lock;
/*
* Reset the UART.
@ -1196,8 +1194,16 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
else
serial_out(up, UART_IER, 0);
out:
out_lock:
spin_unlock_irqrestore(&port->lock, flags);
if (up->capabilities != old_capabilities) {
printk(KERN_WARNING
"ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities,
up->capabilities);
}
out:
DEBUG_AUTOCONF("iir=%d ", scratch);
DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name);
}
@ -1897,6 +1903,9 @@ static int serial8250_startup(struct uart_port *port)
unsigned char lsr, iir;
int retval;
if (port->type == PORT_8250_CIR)
return -ENODEV;
port->fifosize = uart_config[up->port.type].fifo_size;
up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
up->capabilities = uart_config[up->port.type].flags;
@ -2202,6 +2211,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
int fifo_bug = 0;
switch (termios->c_cflag & CSIZE) {
case CS5:
@ -2221,8 +2231,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB)
if (termios->c_cflag & PARENB) {
cval |= UART_LCR_PARITY;
if (up->bugs & UART_BUG_PARITY)
fifo_bug = 1;
}
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
@ -2246,7 +2259,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
fcr = uart_config[port->type].fcr;
if (baud < 2400) {
if (baud < 2400 || fifo_bug) {
fcr &= ~UART_FCR_TRIGGER_MASK;
fcr |= UART_FCR_TRIGGER_1;
}
@ -2336,7 +2349,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
#ifdef CONFIG_ARCH_OMAP
#ifdef CONFIG_ARCH_OMAP1
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
if (cpu_is_omap1510() && is_omap_port(up)) {
if (baud == 115200) {
@ -2426,7 +2439,7 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
if (pt->port.iotype == UPIO_AU)
return 0x1000;
#ifdef CONFIG_ARCH_OMAP
#ifdef CONFIG_ARCH_OMAP1
if (is_omap_port(pt))
return 0x16 << pt->port.regshift;
#endif
@ -2550,7 +2563,10 @@ static int serial8250_request_port(struct uart_port *port)
{
struct uart_8250_port *up =
container_of(port, struct uart_8250_port, port);
int ret = 0;
int ret;
if (port->type == PORT_8250_CIR)
return -ENODEV;
ret = serial8250_request_std_resource(up);
if (ret == 0 && port->type == PORT_RSA) {
@ -2569,6 +2585,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
int probeflags = PROBE_ANY;
int ret;
if (port->type == PORT_8250_CIR)
return;
/*
* Find the region that we can probe for. This in turn
* tells us whether we can probe for the type of port.
@ -2668,6 +2687,9 @@ static void __init serial8250_isa_init_ports(void)
return;
first = 0;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
struct uart_port *port = &up->port;
@ -2677,6 +2699,7 @@ static void __init serial8250_isa_init_ports(void)
init_timer(&up->timer);
up->timer.function = serial8250_timeout;
up->cur_iotype = 0xFF;
/*
* ALPHA_KLUDGE_MCR needs to be killed.
@ -2728,13 +2751,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
up->cur_iotype = 0xFF;
}
serial8250_isa_init_ports();
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev)
continue;
up->port.dev = dev;
@ -2859,9 +2878,6 @@ static struct console serial8250_console = {
static int __init serial8250_console_init(void)
{
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
serial8250_isa_init_ports();
register_console(&serial8250_console);
return 0;
@ -2979,36 +2995,36 @@ void serial8250_resume_port(int line)
static int __devinit serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev->dev.platform_data;
struct uart_port port;
struct uart_8250_port uart;
int ret, i, irqflag = 0;
memset(&port, 0, sizeof(struct uart_port));
memset(&uart, 0, sizeof(uart));
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0; p && p->flags != 0; p++, i++) {
port.iobase = p->iobase;
port.membase = p->membase;
port.irq = p->irq;
port.irqflags = p->irqflags;
port.uartclk = p->uartclk;
port.regshift = p->regshift;
port.iotype = p->iotype;
port.flags = p->flags;
port.mapbase = p->mapbase;
port.hub6 = p->hub6;
port.private_data = p->private_data;
port.type = p->type;
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq;
port.handle_break = p->handle_break;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
port.irqflags |= irqflag;
ret = serial8250_register_port(&port);
uart.port.iobase = p->iobase;
uart.port.membase = p->membase;
uart.port.irq = p->irq;
uart.port.irqflags = p->irqflags;
uart.port.uartclk = p->uartclk;
uart.port.regshift = p->regshift;
uart.port.iotype = p->iotype;
uart.port.flags = p->flags;
uart.port.mapbase = p->mapbase;
uart.port.hub6 = p->hub6;
uart.port.private_data = p->private_data;
uart.port.type = p->type;
uart.port.serial_in = p->serial_in;
uart.port.serial_out = p->serial_out;
uart.port.handle_irq = p->handle_irq;
uart.port.handle_break = p->handle_break;
uart.port.set_termios = p->set_termios;
uart.port.pm = p->pm;
uart.port.dev = &dev->dev;
uart.port.irqflags |= irqflag;
ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
@ -3081,7 +3097,7 @@ static struct platform_driver serial8250_isa_driver = {
static struct platform_device *serial8250_isa_devs;
/*
* serial8250_register_port and serial8250_unregister_port allows for
* serial8250_register_8250_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
* modems and PCI multiport cards.
*/
@ -3143,8 +3159,9 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
mutex_lock(&serial_mutex);
uart = serial8250_find_match_or_unused(&up->port);
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
if (uart && uart->port.type != PORT_8250_CIR) {
if (uart->port.dev)
uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.iobase = up->port.iobase;
uart->port.membase = up->port.membase;
@ -3155,6 +3172,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.regshift = up->port.regshift;
uart->port.iotype = up->port.iotype;
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
uart->bugs = up->bugs;
uart->port.mapbase = up->port.mapbase;
uart->port.private_data = up->port.private_data;
if (up->port.dev)
@ -3197,29 +3215,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
}
EXPORT_SYMBOL(serial8250_register_8250_port);
/**
* serial8250_register_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
* port exists and is in use, it is hung up and unregistered
* first.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int serial8250_register_port(struct uart_port *port)
{
struct uart_8250_port up;
memset(&up, 0, sizeof(up));
memcpy(&up.port, port, sizeof(*port));
return serial8250_register_8250_port(&up);
}
EXPORT_SYMBOL(serial8250_register_port);
/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
* @line: serial line number
@ -3250,8 +3245,7 @@ static int __init serial8250_init(void)
{
int ret;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
serial8250_isa_init_ports();
printk(KERN_INFO "Serial: 8250/16550 driver, "
"%d ports, IRQ sharing %sabled\n", nr_uarts,
@ -3266,11 +3260,15 @@ static int __init serial8250_init(void)
if (ret)
goto out;
ret = serial8250_pnp_init();
if (ret)
goto unreg_uart_drv;
serial8250_isa_devs = platform_device_alloc("serial8250",
PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
goto unreg_uart_drv;
goto unreg_pnp;
}
ret = platform_device_add(serial8250_isa_devs);
@ -3286,6 +3284,8 @@ static int __init serial8250_init(void)
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_pnp:
serial8250_pnp_exit();
unreg_uart_drv:
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
@ -3310,6 +3310,8 @@ static void __exit serial8250_exit(void)
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
serial8250_pnp_exit();
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else

View File

@ -13,36 +13,6 @@
#include <linux/serial_8250.h>
struct uart_8250_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
unsigned short capabilities; /* port capabilities */
unsigned short bugs; /* port bugs */
unsigned int tx_loadsz; /* transmit fifo load size */
unsigned char acr;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned char mcr_mask; /* mask of user bits */
unsigned char mcr_force; /* mask of forced bits */
unsigned char cur_iotype; /* Running I/O type */
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
/* 8250 specific callbacks */
int (*dl_read)(struct uart_8250_port *);
void (*dl_write)(struct uart_8250_port *, int);
};
struct old_serial_port {
unsigned int uart;
unsigned int baud_base;
@ -56,9 +26,6 @@ struct old_serial_port {
unsigned long irqflags;
};
/*
* This replaces serial_uart_config in include/linux/serial.h
*/
struct serial8250_config {
const char *name;
unsigned short fifo_size;
@ -78,6 +45,7 @@ struct serial8250_config {
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
#define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
@ -129,3 +97,12 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
#else
#define ALPHA_KLUDGE_MCR 0
#endif
#ifdef CONFIG_SERIAL_8250_PNP
int serial8250_pnp_init(void);
void serial8250_pnp_exit(void);
#else
static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif

View File

@ -43,7 +43,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct serial_card_info *info;
struct serial_card_type *type = id->data;
struct uart_port port;
struct uart_8250_port uart;
unsigned long bus_addr;
unsigned int i;
@ -62,19 +62,19 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
ecard_set_drvdata(ec, info);
memset(&port, 0, sizeof(struct uart_port));
port.irq = ec->irq;
port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
port.uartclk = type->uartclk;
port.iotype = UPIO_MEM;
port.regshift = 2;
port.dev = &ec->dev;
memset(&uart, 0, sizeof(struct uart_8250_port));
uart.port.irq = ec->irq;
uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
uart.port.uartclk = type->uartclk;
uart.port.iotype = UPIO_MEM;
uart.port.regshift = 2;
uart.port.dev = &ec->dev;
for (i = 0; i < info->num_ports; i ++) {
port.membase = info->vaddr + type->offset[i];
port.mapbase = bus_addr + type->offset[i];
uart.port.membase = info->vaddr + type->offset[i];
uart.port.mapbase = bus_addr + type->offset[i];
info->ports[i] = serial8250_register_port(&port);
info->ports[i] = serial8250_register_8250_port(&uart);
}
return 0;

View File

@ -89,7 +89,7 @@ static int dw8250_handle_irq(struct uart_port *p)
static int __devinit dw8250_probe(struct platform_device *pdev)
{
struct uart_port port = {};
struct uart_8250_port uart = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct device_node *np = pdev->dev.of_node;
@ -104,28 +104,28 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
port.private_data = data;
uart.port.private_data = data;
spin_lock_init(&port.lock);
port.mapbase = regs->start;
port.irq = irq->start;
port.handle_irq = dw8250_handle_irq;
port.type = PORT_8250;
port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
spin_lock_init(&uart.port.lock);
uart.port.mapbase = regs->start;
uart.port.irq = irq->start;
uart.port.handle_irq = dw8250_handle_irq;
uart.port.type = PORT_8250;
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
UPF_FIXED_PORT | UPF_FIXED_TYPE;
port.dev = &pdev->dev;
uart.port.dev = &pdev->dev;
port.iotype = UPIO_MEM;
port.serial_in = dw8250_serial_in;
port.serial_out = dw8250_serial_out;
uart.port.iotype = UPIO_MEM;
uart.port.serial_in = dw8250_serial_in;
uart.port.serial_out = dw8250_serial_out;
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
case 4:
port.iotype = UPIO_MEM32;
port.serial_in = dw8250_serial_in32;
port.serial_out = dw8250_serial_out32;
uart.port.iotype = UPIO_MEM32;
uart.port.serial_in = dw8250_serial_in32;
uart.port.serial_out = dw8250_serial_out32;
break;
default:
dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
@ -135,15 +135,15 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
}
if (!of_property_read_u32(np, "reg-shift", &val))
port.regshift = val;
uart.port.regshift = val;
if (of_property_read_u32(np, "clock-frequency", &val)) {
dev_err(&pdev->dev, "no clock-frequency property set\n");
return -EINVAL;
}
port.uartclk = val;
uart.port.uartclk = val;
data->line = serial8250_register_port(&port);
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0)
return data->line;

View File

@ -26,7 +26,7 @@
static int __init serial_init_chip(struct parisc_device *dev)
{
struct uart_port port;
struct uart_8250_port uart;
unsigned long address;
int err;
@ -48,21 +48,21 @@ static int __init serial_init_chip(struct parisc_device *dev)
if (dev->id.sversion != 0x8d)
address += 0x800;
memset(&port, 0, sizeof(port));
port.iotype = UPIO_MEM;
memset(&uart, 0, sizeof(uart));
uart.port.iotype = UPIO_MEM;
/* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
port.uartclk = 7272727;
port.mapbase = address;
port.membase = ioremap_nocache(address, 16);
port.irq = dev->irq;
port.flags = UPF_BOOT_AUTOCONF;
port.dev = &dev->dev;
uart.port.uartclk = 7272727;
uart.port.mapbase = address;
uart.port.membase = ioremap_nocache(address, 16);
uart.port.irq = dev->irq;
uart.port.flags = UPF_BOOT_AUTOCONF;
uart.port.dev = &dev->dev;
err = serial8250_register_port(&port);
err = serial8250_register_8250_port(&uart);
if (err < 0) {
printk(KERN_WARNING
"serial8250_register_port returned error %d\n", err);
iounmap(port.membase);
"serial8250_register_8250_port returned error %d\n", err);
iounmap(uart.port.membase);
return err;
}

View File

@ -171,7 +171,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
return 0;
}
#endif
memset(&port, 0, sizeof(struct uart_port));
memset(&uart, 0, sizeof(uart));
/* Memory mapped I/O */
port.iotype = UPIO_MEM;
@ -182,7 +182,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
port.regshift = 1;
port.dev = &d->dev;
line = serial8250_register_port(&port);
line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
@ -210,7 +210,7 @@ static int __init hp300_8250_init(void)
#ifdef CONFIG_HPAPCI
int line;
unsigned long base;
struct uart_port uport;
struct uart_8250_port uart;
struct hp300_port *port;
int i;
#endif
@ -248,26 +248,26 @@ static int __init hp300_8250_init(void)
if (!port)
return -ENOMEM;
memset(&uport, 0, sizeof(struct uart_port));
memset(&uart, 0, sizeof(uart));
base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
/* Memory mapped I/O */
uport.iotype = UPIO_MEM;
uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
uart.port.iotype = UPIO_MEM;
uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
| UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
uport.irq = 0;
uport.uartclk = HPAPCI_BAUD_BASE * 16;
uport.mapbase = base;
uport.membase = (char *)(base + DIO_VIRADDRBASE);
uport.regshift = 2;
uart.port.irq = 0;
uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
uart.port.mapbase = base;
uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
uart.port.regshift = 2;
line = serial8250_register_port(&uport);
line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
" %d irq %d failed\n", i, uport.irq);
" %d irq %d failed\n", i, uart.port.irq);
kfree(port);
continue;
}

View File

@ -44,7 +44,7 @@ struct pci_serial_quirk {
int (*init)(struct pci_dev *dev);
int (*setup)(struct serial_private *,
const struct pciserial_board *,
struct uart_port *, int);
struct uart_8250_port *, int);
void (*exit)(struct pci_dev *dev);
};
@ -59,7 +59,7 @@ struct serial_private {
};
static int pci_default_setup(struct serial_private*,
const struct pciserial_board*, struct uart_port*, int);
const struct pciserial_board*, struct uart_8250_port *, int);
static void moan_device(const char *str, struct pci_dev *dev)
{
@ -74,7 +74,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
}
static int
setup_port(struct serial_private *priv, struct uart_port *port,
setup_port(struct serial_private *priv, struct uart_8250_port *port,
int bar, int offset, int regshift)
{
struct pci_dev *dev = priv->dev;
@ -93,17 +93,17 @@ setup_port(struct serial_private *priv, struct uart_port *port,
if (!priv->remapped_bar[bar])
return -ENOMEM;
port->iotype = UPIO_MEM;
port->iobase = 0;
port->mapbase = base + offset;
port->membase = priv->remapped_bar[bar] + offset;
port->regshift = regshift;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = base + offset;
port->port.membase = priv->remapped_bar[bar] + offset;
port->port.regshift = regshift;
} else {
port->iotype = UPIO_PORT;
port->iobase = base + offset;
port->mapbase = 0;
port->membase = NULL;
port->regshift = 0;
port->port.iotype = UPIO_PORT;
port->port.iobase = base + offset;
port->port.mapbase = 0;
port->port.membase = NULL;
port->port.regshift = 0;
}
return 0;
}
@ -113,7 +113,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
*/
static int addidata_apci7800_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
bar = FL_GET_BASE(board->flags);
@ -140,7 +140,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
*/
static int
afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@ -195,7 +195,7 @@ static int pci_hp_diva_init(struct pci_dev *dev)
static int
pci_hp_diva_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int offset = board->first_offset;
unsigned int bar = FL_GET_BASE(board->flags);
@ -370,7 +370,7 @@ static void __devexit pci_ni8430_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static int
sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@ -525,7 +525,7 @@ static int pci_siig_init(struct pci_dev *dev)
static int pci_siig_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
@ -619,7 +619,7 @@ static int pci_timedia_init(struct pci_dev *dev)
static int
pci_timedia_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@ -653,7 +653,7 @@ pci_timedia_setup(struct serial_private *priv,
static int
titan_400l_800l_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@ -754,7 +754,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
static int
pci_ni8430_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
void __iomem *p;
unsigned long base, len;
@ -781,7 +781,7 @@ pci_ni8430_setup(struct serial_private *priv,
static int pci_netmos_9900_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
unsigned int bar;
@ -1032,10 +1032,17 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
return number_uarts;
}
static int
pci_default_setup(struct serial_private *priv,
static int pci_asix_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
port->bugs |= UART_BUG_PARITY;
return pci_default_setup(priv, board, port, idx);
}
static int pci_default_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset, maxnr;
@ -1057,15 +1064,15 @@ pci_default_setup(struct serial_private *priv,
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
int ret;
ret = setup_port(priv, port, 0, 0, board->reg_shift);
port->iotype = UPIO_MEM32;
port->type = PORT_XSCALE;
port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
port->regshift = 2;
port->port.iotype = UPIO_MEM32;
port->port.type = PORT_XSCALE;
port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
port->port.regshift = 2;
return ret;
}
@ -1073,16 +1080,16 @@ ce4100_serial_setup(struct serial_private *priv,
static int
pci_omegapci_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
return setup_port(priv, port, 2, idx * 8, 0);
}
static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
port->flags |= UPF_NO_TXEN_TEST;
port->port.flags |= UPF_NO_TXEN_TEST;
printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
"[%04x:%04x] subsystem [%04x:%04x]\n",
priv->dev->vendor,
@ -1131,11 +1138,11 @@ static unsigned int kt_serial_in(struct uart_port *p, int offset)
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
port->flags |= UPF_BUG_THRE;
port->serial_in = kt_serial_in;
port->handle_break = kt_handle_break;
port->port.flags |= UPF_BUG_THRE;
port->port.serial_in = kt_serial_in;
port->port.handle_break = kt_handle_break;
return skip_tx_en_setup(priv, board, port, idx);
}
@ -1151,9 +1158,19 @@ static int pci_eg20t_init(struct pci_dev *dev)
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
struct uart_8250_port *port, int idx)
{
port->flags |= UPF_EXAR_EFR;
port->port.flags |= UPF_EXAR_EFR;
return pci_default_setup(priv, board, port, idx);
}
static int
pci_wch_ch353_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
return pci_default_setup(priv, board, port, idx);
}
@ -1164,6 +1181,8 @@ pci_xr17c154_setup(struct serial_private *priv,
#define PCI_SUBDEVICE_ID_OCTPRO422 0x0208
#define PCI_SUBDEVICE_ID_POCTAL232 0x0308
#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
#define PCI_SUBDEVICE_ID_SIIG_DUAL_00 0x2500
#define PCI_SUBDEVICE_ID_SIIG_DUAL_30 0x2530
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
@ -1187,6 +1206,13 @@ pci_xr17c154_setup(struct serial_private *priv,
#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
#define PCI_VENDOR_ID_WCH 0x4348
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
#define PCI_VENDOR_ID_ASIX 0x9710
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@ -1726,7 +1752,41 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
},
},
/* WCH CH353 2S1P card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
.device = PCI_DEVICE_ID_WCH_CH353_2S1P,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 4S card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
.device = PCI_DEVICE_ID_WCH_CH353_4S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 2S1PF card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
.device = PCI_DEVICE_ID_WCH_CH353_2S1PF,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/*
* ASIX devices with FIFO bug
*/
{
.vendor = PCI_VENDOR_ID_ASIX,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_asix_setup,
},
/*
* Default "match everything" terminator entry
*/
@ -1887,7 +1947,6 @@ enum pci_board_num_t {
pbn_panacom,
pbn_panacom2,
pbn_panacom4,
pbn_exsys_4055,
pbn_plx_romulus,
pbn_oxsemi,
pbn_oxsemi_1_4000000,
@ -2393,13 +2452,6 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.reg_shift = 7,
},
[pbn_exsys_4055] = {
.flags = FL_BASE2,
.num_ports = 4,
.base_baud = 115200,
.uart_offset = 8,
},
/* I think this entry is broken - the first_offset looks wrong --rmk */
[pbn_plx_romulus] = {
.flags = FL_BASE2,
@ -2624,10 +2676,14 @@ static struct pciserial_board pci_boards[] __devinitdata = {
},
};
static const struct pci_device_id softmodem_blacklist[] = {
static const struct pci_device_id blacklist[] = {
/* softmodems */
{ PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
{ PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
{ PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
/* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
};
/*
@ -2638,7 +2694,7 @@ static const struct pci_device_id softmodem_blacklist[] = {
static int __devinit
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{
const struct pci_device_id *blacklist;
const struct pci_device_id *bldev;
int num_iomem, num_port, first_port = -1, i;
/*
@ -2655,13 +2711,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
/*
* Do not access blacklisted devices that are known not to
* feature serial ports.
* feature serial ports or are handled by other modules.
*/
for (blacklist = softmodem_blacklist;
blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
blacklist++) {
if (dev->vendor == blacklist->vendor &&
dev->device == blacklist->device)
for (bldev = blacklist;
bldev < blacklist + ARRAY_SIZE(blacklist);
bldev++) {
if (dev->vendor == bldev->vendor &&
dev->device == bldev->device)
return -ENODEV;
}
@ -2728,7 +2784,7 @@ serial_pci_matches(const struct pciserial_board *board,
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
{
struct uart_port serial_port;
struct uart_8250_port uart;
struct serial_private *priv;
struct pci_serial_quirk *quirk;
int rc, nr_ports, i;
@ -2768,22 +2824,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
priv->dev = dev;
priv->quirk = quirk;
memset(&serial_port, 0, sizeof(struct uart_port));
serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
serial_port.uartclk = board->base_baud * 16;
serial_port.irq = get_pci_irq(dev, board);
serial_port.dev = &dev->dev;
memset(&uart, 0, sizeof(uart));
uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
uart.port.uartclk = board->base_baud * 16;
uart.port.irq = get_pci_irq(dev, board);
uart.port.dev = &dev->dev;
for (i = 0; i < nr_ports; i++) {
if (quirk->setup(priv, board, &serial_port, i))
if (quirk->setup(priv, board, &uart, i))
break;
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
serial_port.iobase, serial_port.irq, serial_port.iotype);
uart.port.iobase, uart.port.irq, uart.port.iotype);
#endif
priv->line[i] = serial8250_register_port(&serial_port);
priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
break;
@ -3193,7 +3249,7 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_EXSYS,
PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
pbn_exsys_4055 },
pbn_b2_4_115200 },
/*
* Megawolf Romulus PCI Serial Card, from Mike Hudson
* (Exoray@isys.ca)
@ -3232,8 +3288,11 @@ static struct pci_device_id serial_pci_tbl[] = {
* For now just used the hex ID 0x950a.
*/
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
pbn_b0_2_115200 },
PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
0, 0, pbn_b0_2_115200 },
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
0, 0, pbn_b0_2_115200 },
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_2_1130000 },
@ -4178,6 +4237,25 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_omegapci },
/*
* AgeStar as-prs2-009
*/
{ PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 },
/*
* WCH CH353 series devices: The 2S1P is handled by parport_serial
* so not listed here.
*/
{ PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_4_115200 },
{ PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 },
/*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL

View File

@ -1,5 +1,5 @@
/*
* Probe module for 8250/16550-type ISAPNP serial ports.
* Probe for 8250/16550-type ISAPNP serial ports.
*
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
@ -25,7 +25,7 @@
#include "8250.h"
#define UNKNOWN_DEV 0x3000
#define CIR_PORT 0x0800
static const struct pnp_device_id pnp_dev_table[] = {
/* Archtek America Corp. */
@ -362,6 +362,9 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
/* Winbond CIR port, should not be probed. We should keep track
of it to prevent the legacy serial driver from probing it */
{ "WEC1022", CIR_PORT },
{ "", 0 }
};
@ -409,7 +412,7 @@ static int __devinit check_resources(struct pnp_dev *dev)
* PnP modems, alternatively we must hardcode all modems in pnp_devices[]
* table.
*/
static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
static int __devinit serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
(dev->card && check_name(dev->card->name))))
@ -424,42 +427,49 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
static int __devinit
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_port port;
struct uart_8250_port uart;
int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev, &flags);
ret = serial_pnp_guess_board(dev);
if (ret < 0)
return ret;
}
memset(&port, 0, sizeof(struct uart_port));
memset(&uart, 0, sizeof(uart));
if (pnp_irq_valid(dev, 0))
port.irq = pnp_irq(dev, 0);
if (pnp_port_valid(dev, 0)) {
port.iobase = pnp_port_start(dev, 0);
port.iotype = UPIO_PORT;
uart.port.irq = pnp_irq(dev, 0);
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
uart.port.iobase = pnp_port_start(dev, 2);
uart.port.iotype = UPIO_PORT;
} else if (pnp_port_valid(dev, 0)) {
uart.port.iobase = pnp_port_start(dev, 0);
uart.port.iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
port.mapbase = pnp_mem_start(dev, 0);
port.iotype = UPIO_MEM;
port.flags = UPF_IOREMAP;
uart.port.mapbase = pnp_mem_start(dev, 0);
uart.port.iotype = UPIO_MEM;
uart.port.flags = UPF_IOREMAP;
} else
return -ENODEV;
#ifdef SERIAL_DEBUG_PNP
printk(KERN_DEBUG
"Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
port.iobase, port.mapbase, port.irq, port.iotype);
uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
#endif
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
}
port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
port.flags |= UPF_SHARE_IRQ;
port.uartclk = 1843200;
port.dev = &dev->dev;
uart.port.flags |= UPF_SHARE_IRQ;
uart.port.uartclk = 1843200;
uart.port.dev = &dev->dev;
line = serial8250_register_port(&port);
if (line < 0)
line = serial8250_register_8250_port(&uart);
if (line < 0 || (flags & CIR_PORT))
return -ENODEV;
pnp_set_drvdata(dev, (void *)((long)line + 1));
@ -507,18 +517,13 @@ static struct pnp_driver serial_pnp_driver = {
.id_table = pnp_dev_table,
};
static int __init serial8250_pnp_init(void)
int serial8250_pnp_init(void)
{
return pnp_register_driver(&serial_pnp_driver);
}
static void __exit serial8250_pnp_exit(void)
void serial8250_pnp_exit(void)
{
pnp_unregister_driver(&serial_pnp_driver);
}
module_init(serial8250_pnp_init);
module_exit(serial8250_pnp_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 PnP serial driver");

View File

@ -33,6 +33,14 @@ config SERIAL_8250
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
config SERIAL_8250_PNP
bool "8250/16550 PNP device support" if EXPERT
depends on SERIAL_8250 && PNP
default y
---help---
This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support.
config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y
@ -85,14 +93,6 @@ config SERIAL_8250_PCI
disable this feature if you only need legacy serial support.
Saves about 9K.
config SERIAL_8250_PNP
tristate "8250/16550 PNP device support" if EXPERT
depends on SERIAL_8250 && PNP
default SERIAL_8250
help
This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support.
config SERIAL_8250_HP300
tristate
depends on SERIAL_8250 && HP300

View File

@ -2,8 +2,9 @@
# Makefile for the 8250 serial device drivers.
#
obj-$(CONFIG_SERIAL_8250) += 8250.o
obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
obj-$(CONFIG_SERIAL_8250) += 8250_core.o
8250_core-y := 8250.o
8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o

View File

@ -73,7 +73,7 @@ struct serial_quirk {
unsigned int prodid;
int multi; /* 1 = multifunction, > 1 = # ports */
void (*config)(struct pcmcia_device *);
void (*setup)(struct pcmcia_device *, struct uart_port *);
void (*setup)(struct pcmcia_device *, struct uart_8250_port *);
void (*wakeup)(struct pcmcia_device *);
int (*post)(struct pcmcia_device *);
};
@ -105,9 +105,9 @@ struct serial_cfg_mem {
* Elan VPU16551 UART with 14.7456MHz oscillator
* manfid 0x015D, 0x4C45
*/
static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart)
{
port->uartclk = 14745600;
uart->port.uartclk = 14745600;
}
static int quirk_post_ibm(struct pcmcia_device *link)
@ -343,25 +343,25 @@ static void serial_detach(struct pcmcia_device *link)
static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
unsigned int iobase, int irq)
{
struct uart_port port;
struct uart_8250_port uart;
int line;
memset(&port, 0, sizeof (struct uart_port));
port.iobase = iobase;
port.irq = irq;
port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
port.uartclk = 1843200;
port.dev = &handle->dev;
memset(&uart, 0, sizeof(uart));
uart.port.iobase = iobase;
uart.port.irq = irq;
uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
uart.port.uartclk = 1843200;
uart.port.dev = &handle->dev;
if (buggy_uart)
port.flags |= UPF_BUGGY_UART;
uart.port.flags |= UPF_BUGGY_UART;
if (info->quirk && info->quirk->setup)
info->quirk->setup(handle, &port);
info->quirk->setup(handle, &uart);
line = serial8250_register_port(&port);
line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
"0x%04lx, irq %d failed\n", (u_long)iobase, irq);
pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
(unsigned long)iobase, irq);
return -EINVAL;
}

View File

@ -141,6 +141,25 @@ config SERIAL_ATMEL_TTYAT
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
config SERIAL_KGDB_NMI
bool "Serial console over KGDB NMI debugger port"
depends on KGDB_SERIAL_CONSOLE
help
This special driver allows you to temporary use NMI debugger port
as a normal console (assuming that the port is attached to KGDB).
Unlike KDB's disable_nmi command, with this driver you are always
able to go back to the debugger using KGDB escape sequence ($3#33).
This is because this console driver processes the input in NMI
context, and thus is able to intercept the magic sequence.
Note that since the console interprets input and uses polling
communication methods, for things like PPP you still must fully
detach debugger port from the KGDB NMI (i.e. disable_nmi), and
use raw console.
If unsure, say N.
config SERIAL_KS8695
bool "Micrel KS8695 (Centaur) serial port support"
depends on ARCH_KS8695
@ -257,12 +276,19 @@ config SERIAL_MAX3100
help
MAX3100 chip support
config SERIAL_MAX3107
tristate "MAX3107 support"
config SERIAL_MAX310X
bool "MAX310X support"
depends on SPI
select SERIAL_CORE
select REGMAP_SPI if SPI
default n
help
MAX3107 chip support
This selects support for an advanced UART from Maxim (Dallas).
Supported ICs are MAX3107, MAX3108.
Each IC contains 128 words each of receive and transmit FIFO
that can be controlled through I2C or high-speed SPI.
Say Y here if you want to support this ICs.
config SERIAL_DZ
bool "DECstation DZ serial driver"
@ -686,7 +712,7 @@ config SERIAL_SH_SCI_CONSOLE
config SERIAL_SH_SCI_DMA
bool "DMA support"
depends on SERIAL_SH_SCI && SH_DMAE && EXPERIMENTAL
depends on SERIAL_SH_SCI && SH_DMAE
config SERIAL_PNX8XXX
bool "Enable PNX8XXX SoCs' UART Support"
@ -704,6 +730,25 @@ config SERIAL_PNX8XXX_CONSOLE
If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
and you want to use serial console, say Y. Otherwise, say N.
config SERIAL_HS_LPC32XX
tristate "LPC32XX high speed serial port support"
depends on ARCH_LPC32XX && OF
select SERIAL_CORE
help
Support for the LPC32XX high speed serial ports (up to 900kbps).
Those are UARTs completely different from the Standard UARTs on the
LPC32XX SoC.
Choose M or Y here to build this driver.
config SERIAL_HS_LPC32XX_CONSOLE
bool "Enable LPC32XX high speed UART serial console"
depends on SERIAL_HS_LPC32XX
select SERIAL_CORE_CONSOLE
help
If you would like to be able to use one of the high speed serial
ports on the LPC32XX as the console, you can do so by answering
Y to this option.
config SERIAL_CORE
tristate
@ -1104,6 +1149,24 @@ config SERIAL_SC26XX_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
config SERIAL_SCCNXP
bool "SCCNXP serial port support"
depends on !SERIAL_SC26XX
select SERIAL_CORE
default n
help
This selects support for an advanced UART from NXP (Philips).
Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92,
SC28L202, SCC68681 and SCC68692.
Positioned as a replacement for the driver SC26XX.
config SERIAL_SCCNXP_CONSOLE
bool "Console on SCCNXP serial port"
depends on SERIAL_SCCNXP
select SERIAL_CORE_CONSOLE
help
Support for console on SCCNXP serial ports.
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
@ -1260,7 +1323,7 @@ config SERIAL_ALTERA_UART_CONSOLE
config SERIAL_IFX6X60
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
depends on GPIOLIB && SPI && EXPERIMENTAL
depends on GPIOLIB && SPI
help
Support for the IFX6x60 modem devices on Intel MID platforms.

View File

@ -28,12 +28,13 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
@ -47,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@ -59,6 +61,7 @@ obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o

View File

@ -591,7 +591,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
port->ops = &altera_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
dev_set_drvdata(&pdev->dev, port);
platform_set_drvdata(pdev, port);
uart_add_one_port(&altera_uart_driver, port);
@ -600,11 +600,11 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
static int __devexit altera_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uart_port *port = platform_get_drvdata(pdev);
if (port) {
uart_remove_one_port(&altera_uart_driver, port);
dev_set_drvdata(&pdev->dev, NULL);
platform_set_drvdata(pdev, NULL);
port->mapbase = 0;
}

View File

@ -312,16 +312,12 @@ static int pl010_startup(struct uart_port *port)
struct uart_amba_port *uap = (struct uart_amba_port *)port;
int retval;
retval = clk_prepare(uap->clk);
if (retval)
goto out;
/*
* Try to enable the clock producer.
*/
retval = clk_enable(uap->clk);
retval = clk_prepare_enable(uap->clk);
if (retval)
goto clk_unprep;
goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
@ -346,9 +342,7 @@ static int pl010_startup(struct uart_port *port)
return 0;
clk_dis:
clk_disable(uap->clk);
clk_unprep:
clk_unprepare(uap->clk);
clk_disable_unprepare(uap->clk);
out:
return retval;
}
@ -375,8 +369,7 @@ static void pl010_shutdown(struct uart_port *port)
/*
* Shut down the clock producer
*/
clk_disable(uap->clk);
clk_unprepare(uap->clk);
clk_disable_unprepare(uap->clk);
}
static void

View File

@ -52,6 +52,8 @@
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
@ -75,7 +77,6 @@ struct vendor_data {
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
bool cts_event_workaround;
};
@ -96,7 +97,6 @@ static struct vendor_data vendor_st = {
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
.interrupt_may_hang = true,
.dma_threshold = true,
.cts_event_workaround = true,
};
@ -147,7 +147,6 @@ struct uart_amba_port {
unsigned int old_cr; /* state during shutdown */
bool autorts;
char type[12];
bool interrupt_may_hang; /* vendor-specific */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@ -1215,14 +1214,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
static unsigned int pl01x_tx_empty(struct uart_port *port)
static unsigned int pl011_tx_empty(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status = readw(uap->port.membase + UART01x_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
static unsigned int pl01x_get_mctrl(struct uart_port *port)
static unsigned int pl011_get_mctrl(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int result = 0;
@ -1285,11 +1284,40 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
}
#ifdef CONFIG_CONSOLE_POLL
static int pl010_get_poll_char(struct uart_port *port)
static void pl011_quiesce_irqs(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned char __iomem *regs = uap->port.membase;
writew(readw(regs + UART011_MIS), regs + UART011_ICR);
/*
* There is no way to clear TXIM as this is "ready to transmit IRQ", so
* we simply mask it. start_tx() will unmask it.
*
* Note we can race with start_tx(), and if the race happens, the
* polling user might get another interrupt just after we clear it.
* But it should be OK and can happen even w/o the race, e.g.
* controller immediately got some new data and raised the IRQ.
*
* And whoever uses polling routines assumes that it manages the device
* (including tx queue), so we're also fine with start_tx()'s caller
* side.
*/
writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC);
}
static int pl011_get_poll_char(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status;
/*
* The caller might need IRQs lowered, e.g. if used with KDB NMI
* debugger.
*/
pl011_quiesce_irqs(port);
status = readw(uap->port.membase + UART01x_FR);
if (status & UART01x_FR_RXFE)
return NO_POLL_CHAR;
@ -1297,7 +1325,7 @@ static int pl010_get_poll_char(struct uart_port *port)
return readw(uap->port.membase + UART01x_DR);
}
static void pl010_put_poll_char(struct uart_port *port,
static void pl011_put_poll_char(struct uart_port *port,
unsigned char ch)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@ -1310,10 +1338,9 @@ static void pl010_put_poll_char(struct uart_port *port,
#endif /* CONFIG_CONSOLE_POLL */
static int pl011_startup(struct uart_port *port)
static int pl011_hwinit(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
int retval;
/* Optionaly enable pins to be muxed in and configured */
@ -1324,16 +1351,12 @@ static int pl011_startup(struct uart_port *port)
"could not set default pins\n");
}
retval = clk_prepare(uap->clk);
if (retval)
goto out;
/*
* Try to enable the clock producer.
*/
retval = clk_enable(uap->clk);
retval = clk_prepare_enable(uap->clk);
if (retval)
goto clk_unprep;
goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
@ -1341,6 +1364,37 @@ static int pl011_startup(struct uart_port *port)
writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS |
UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR);
/*
* Save interrupts enable mask, and enable RX interrupts in case if
* the interrupt is used for NMI entry.
*/
uap->im = readw(uap->port.membase + UART011_IMSC);
writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
if (uap->port.dev->platform_data) {
struct amba_pl011_data *plat;
plat = uap->port.dev->platform_data;
if (plat->init)
plat->init();
}
return 0;
out:
return retval;
}
static int pl011_startup(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
int retval;
retval = pl011_hwinit(port);
if (retval)
goto clk_dis;
writew(uap->im, uap->port.membase + UART011_IMSC);
/*
* Allocate the IRQ
*/
@ -1400,21 +1454,10 @@ static int pl011_startup(struct uart_port *port)
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);
if (uap->port.dev->platform_data) {
struct amba_pl011_data *plat;
plat = uap->port.dev->platform_data;
if (plat->init)
plat->init();
}
return 0;
clk_dis:
clk_disable(uap->clk);
clk_unprep:
clk_unprepare(uap->clk);
out:
clk_disable_unprepare(uap->clk);
return retval;
}
@ -1473,8 +1516,7 @@ static void pl011_shutdown(struct uart_port *port)
/*
* Shut down the clock producer
*/
clk_disable(uap->clk);
clk_unprepare(uap->clk);
clk_disable_unprepare(uap->clk);
/* Optionally let pins go into sleep states */
if (!IS_ERR(uap->pins_sleep)) {
retval = pinctrl_select_state(uap->pinctrl, uap->pins_sleep);
@ -1603,13 +1645,26 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
old_cr &= ~ST_UART011_CR_OVSFACT;
}
/*
* Workaround for the ST Micro oversampling variants to
* increase the bitrate slightly, by lowering the divisor,
* to avoid delayed sampling of start bit at high speeds,
* else we see data corruption.
*/
if (uap->vendor->oversampling) {
if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
quot -= 1;
else if ((baud > 3250000) && (quot > 2))
quot -= 2;
}
/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
/*
* ----------v----------v----------v----------v-----
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
* NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER
* UART011_FBRD & UART011_IBRD.
* ----------^----------^----------^----------^-----
*/
writew(lcr_h, port->membase + uap->lcrh_rx);
@ -1637,7 +1692,7 @@ static const char *pl011_type(struct uart_port *port)
/*
* Release the memory region(s) being used by 'port'
*/
static void pl010_release_port(struct uart_port *port)
static void pl011_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, SZ_4K);
}
@ -1645,7 +1700,7 @@ static void pl010_release_port(struct uart_port *port)
/*
* Request the memory region(s) being used by 'port'
*/
static int pl010_request_port(struct uart_port *port)
static int pl011_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
!= NULL ? 0 : -EBUSY;
@ -1654,18 +1709,18 @@ static int pl010_request_port(struct uart_port *port)
/*
* Configure/autoconfigure the port.
*/
static void pl010_config_port(struct uart_port *port, int flags)
static void pl011_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_AMBA;
pl010_request_port(port);
pl011_request_port(port);
}
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
@ -1678,9 +1733,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
}
static struct uart_ops amba_pl011_pops = {
.tx_empty = pl01x_tx_empty,
.tx_empty = pl011_tx_empty,
.set_mctrl = pl011_set_mctrl,
.get_mctrl = pl01x_get_mctrl,
.get_mctrl = pl011_get_mctrl,
.stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx,
@ -1691,13 +1746,14 @@ static struct uart_ops amba_pl011_pops = {
.flush_buffer = pl011_dma_flush_buffer,
.set_termios = pl011_set_termios,
.type = pl011_type,
.release_port = pl010_release_port,
.request_port = pl010_request_port,
.config_port = pl010_config_port,
.verify_port = pl010_verify_port,
.release_port = pl011_release_port,
.request_port = pl011_request_port,
.config_port = pl011_config_port,
.verify_port = pl011_verify_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = pl010_get_poll_char,
.poll_put_char = pl010_put_poll_char,
.poll_init = pl011_hwinit,
.poll_get_char = pl011_get_poll_char,
.poll_put_char = pl011_put_poll_char,
#endif
};
@ -1869,6 +1925,38 @@ static struct uart_driver amba_reg = {
.cons = AMBA_CONSOLE,
};
static int pl011_probe_dt_alias(int index, struct device *dev)
{
struct device_node *np;
static bool seen_dev_with_alias = false;
static bool seen_dev_without_alias = false;
int ret = index;
if (!IS_ENABLED(CONFIG_OF))
return ret;
np = dev->of_node;
if (!np)
return ret;
ret = of_alias_get_id(np, "serial");
if (IS_ERR_VALUE(ret)) {
seen_dev_without_alias = true;
ret = index;
} else {
seen_dev_with_alias = true;
if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) {
dev_warn(dev, "requested serial port %d not available.\n", ret);
ret = index;
}
}
if (seen_dev_with_alias && seen_dev_without_alias)
dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
return ret;
}
static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
@ -1891,6 +1979,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto out;
}
i = pl011_probe_dt_alias(i, &dev->dev);
base = ioremap(dev->res.start, resource_size(&dev->res));
if (!base) {
ret = -ENOMEM;
@ -1923,7 +2013,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
uap->fifosize = vendor->fifosize;
uap->interrupt_may_hang = vendor->interrupt_may_hang;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;

View File

@ -182,7 +182,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
* To avoid losting RX interrupt, we reset IR function
* before sending data.
*/
if (tty->termios->c_line == N_IRDA)
if (tty->termios.c_line == N_IRDA)
bfin_serial_reset_irda(port);
#ifdef CONFIG_SERIAL_BFIN_DMA

View File

@ -71,7 +71,7 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
#define HW_BUF_SPD_THRESHOLD 9600
#define HW_BUF_SPD_THRESHOLD 2400
/*
* Check, if transmit buffers are processed
@ -417,6 +417,7 @@ static int cpm_uart_startup(struct uart_port *port)
clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR);
clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
}
cpm_uart_initbd(pinfo);
cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
}
/* Install interrupt handler. */
@ -500,16 +501,28 @@ static void cpm_uart_set_termios(struct uart_port *port,
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
smc_t __iomem *smcp = pinfo->smcp;
scc_t __iomem *sccp = pinfo->sccp;
int maxidl;
pr_debug("CPM uart[%d]:set_termios\n", port->line);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
if (baud <= HW_BUF_SPD_THRESHOLD ||
if (baud < HW_BUF_SPD_THRESHOLD ||
(pinfo->port.state && pinfo->port.state->port.tty->low_latency))
pinfo->rx_fifosize = 1;
else
pinfo->rx_fifosize = RX_BUF_SIZE;
/* MAXIDL is the timeout after which a receive buffer is closed
* when not full if no more characters are received.
* We calculate it from the baudrate so that the duration is
* always the same at standard rates: about 4ms.
*/
maxidl = baud / 2400;
if (maxidl < 1)
maxidl = 1;
if (maxidl > 0x10)
maxidl = 0x10;
/* Character length programmed into the mode register is the
* sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
* 1 or 2 stop bits, minus 1.
@ -610,6 +623,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
* SMC/SCC receiver is disabled.
*/
out_be16(&pinfo->smcup->smc_mrblr, pinfo->rx_fifosize);
out_be16(&pinfo->smcup->smc_maxidl, maxidl);
/* Set the mode register. We want to keep a copy of the
* enables, because we want to put them back if they were
@ -622,6 +636,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
SMCMR_SM_UART | prev_mode);
} else {
out_be16(&pinfo->sccup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
out_be16(&pinfo->sccup->scc_maxidl, maxidl);
out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
}
@ -798,7 +813,7 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
cpm_set_scc_fcr(sup);
out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
out_be16(&sup->scc_maxidl, 0x10);
out_be16(&sup->scc_brkcr, 1);
out_be16(&sup->scc_parec, 0);
out_be16(&sup->scc_frmec, 0);
@ -872,7 +887,7 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
/* Using idle character time requires some additional tuning. */
out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
out_be16(&up->smc_maxidl, 0x10);
out_be16(&up->smc_brklen, 0);
out_be16(&up->smc_brkec, 0);
out_be16(&up->smc_brkcr, 1);

View File

@ -955,7 +955,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info)
{
tcflag_t cflags = info->port.tty->termios->c_cflag;
tcflag_t cflags = info->port.tty->termios.c_cflag;
int bits;
/* calc. number of bits / data byte */
@ -1473,7 +1473,7 @@ rs_stop(struct tty_struct *tty)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
if (tty->termios->c_iflag & IXON ) {
if (tty->termios.c_iflag & IXON ) {
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
}
@ -1496,7 +1496,7 @@ rs_start(struct tty_struct *tty)
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
if (tty->termios->c_iflag & IXON ) {
if (tty->termios.c_iflag & IXON ) {
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
}
@ -2929,7 +2929,7 @@ shutdown(struct e100_serial * info)
descr[i].buf = 0;
}
if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
/* hang up DTR and RTS if HUPCL is enabled */
e100_dtr(info, 0);
e100_rts(info, 0); /* could check CRTSCTS before doing this */
@ -2953,12 +2953,12 @@ change_speed(struct e100_serial *info)
unsigned long flags;
/* first some safety checks */
if (!info->port.tty || !info->port.tty->termios)
if (!info->port.tty)
return;
if (!info->ioport)
return;
cflag = info->port.tty->termios->c_cflag;
cflag = info->port.tty->termios.c_cflag;
/* possibly, the tx/rx should be disabled first to do this safely */
@ -3088,7 +3088,7 @@ change_speed(struct e100_serial *info)
info->ioport[REG_REC_CTRL] = info->rx_ctrl;
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
if (info->port.tty->termios->c_iflag & IXON ) {
if (info->port.tty->termios.c_iflag & IXON ) {
DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
STOP_CHAR(info->port.tty)));
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
@ -3355,7 +3355,7 @@ rs_throttle(struct tty_struct * tty)
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
/* Do RTS before XOFF since XOFF might take some time */
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
/* Turn off RTS line */
e100_rts(info, 0);
}
@ -3377,7 +3377,7 @@ rs_unthrottle(struct tty_struct * tty)
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */
if (tty->termios->c_cflag & CRTSCTS) {
if (tty->termios.c_cflag & CRTSCTS) {
/* Assert RTS line */
e100_rts(info, 1);
}
@ -3748,7 +3748,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
!(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@ -3815,7 +3815,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
* separate termios for callout and dialin.
*/
if (info->flags & ASYNC_NORMAL_ACTIVE)
info->normal_termios = *tty->termios;
info->normal_termios = tty->termios;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(info->close_wait,
wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
@ -3998,7 +3998,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
if (tty->termios->c_cflag & CLOCAL) {
if (tty->termios.c_cflag & CLOCAL) {
do_clocal = 1;
}
@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttyS%d, count = %d\n",
info->line, info->count);
#endif
tty_unlock();
tty_unlock(tty);
schedule();
tty_lock();
tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
wait_event_interruptible_tty(info->close_wait,
wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
@ -4219,7 +4219,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
}
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
*tty->termios = info->normal_termios;
tty->termios = info->normal_termios;
change_speed(info);
}
@ -4443,14 +4443,12 @@ static int __init rs_init(void)
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
driver->init_termios.c_ispeed = 115200;
driver->init_termios.c_ospeed = 115200;
driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &rs_ops);
serial_driver = driver;
if (tty_register_driver(driver))
panic("Couldn't register serial driver\n");
/* do some initializing for the separate ports */
/* do some initializing for the separate ports */
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
if (info->enabled) {
if (cris_request_io_interface(info->io_if,
@ -4502,7 +4500,12 @@ static int __init rs_init(void)
printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
serial_driver->name, info->line, info->ioport);
}
tty_port_link_device(&info->port, driver, i);
}
if (tty_register_driver(driver))
panic("Couldn't register serial driver\n");
#ifdef CONFIG_ETRAX_FAST_TIMER
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
memset(fast_timers, 0, sizeof(fast_timers));

View File

@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
tty_port_init(pport);
pport->ops = &ifx_tty_port_ops;
ifx_dev->minor = IFX_SPI_TTY_ID;
ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
&ifx_dev->spi_dev->dev);
ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv,
ifx_dev->minor, &ifx_dev->spi_dev->dev);
if (IS_ERR(ifx_dev->tty_dev)) {
dev_dbg(&ifx_dev->spi_dev->dev,
"%s: registering tty device failed", __func__);

View File

@ -207,7 +207,7 @@ struct imx_port {
unsigned short trcv_delay; /* transceiver delay */
struct clk *clk_ipg;
struct clk *clk_per;
struct imx_uart_data *devdata;
const struct imx_uart_data *devdata;
};
struct imx_port_ucrs {
@ -1373,8 +1373,7 @@ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
val |= UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
if (sport)
uart_suspend_port(&imx_reg, &sport->port);
uart_suspend_port(&imx_reg, &sport->port);
return 0;
}
@ -1389,8 +1388,7 @@ static int serial_imx_resume(struct platform_device *dev)
val &= ~UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
if (sport)
uart_resume_port(&imx_reg, &sport->port);
uart_resume_port(&imx_reg, &sport->port);
return 0;
}
@ -1505,18 +1503,21 @@ static int serial_imx_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
goto unmap;
}
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
goto unmap;
}
sport->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(sport->clk_per)) {
ret = PTR_ERR(sport->clk_per);
dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);
goto unmap;
}
@ -1537,7 +1538,7 @@ static int serial_imx_probe(struct platform_device *pdev)
ret = uart_add_one_port(&imx_reg, &sport->port);
if (ret)
goto deinit;
platform_set_drvdata(pdev, &sport->port);
platform_set_drvdata(pdev, sport);
return 0;
deinit:

View File

@ -1120,13 +1120,14 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len)
struct ioc3_port *port = get_ioc3_port(the_port);
struct ring *inring;
struct ring_entry *entry;
struct port_hooks *hooks = port->ip_hooks;
struct port_hooks *hooks;
int byte_num;
char *sc;
int loop_counter;
BUG_ON(!(len >= 0));
BUG_ON(!port);
hooks = port->ip_hooks;
/* There is a nasty timing issue in the IOC3. When the rx_timer
* expires or the rx_high condition arises, we take an interrupt.

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