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:
Коммит
3498d13b80
|
@ -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
|
||||
|
||||
|
|
|
@ -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>;
|
||||
};
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -142,4 +142,6 @@ source "drivers/staging/ced1401/Kconfig"
|
|||
|
||||
source "drivers/staging/imx-drm/Kconfig"
|
||||
|
||||
source "drivers/staging/dgrp/Kconfig"
|
||||
|
||||
endif # STAGING
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
The user space code to work with this driver is located at
|
||||
https://github.com/wfp5p/dgrp-utils
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче