S: 1098 VA Amsterdam
S: The Netherlands
+N: Jiri Kosina
+E: jikos@jikos.cz
+E: jkosina@suse.cz
+D: Generic HID layer - original code split, fixes
+D: Various ACPI fixes, keeping correct battery state through suspend
+D: various lockdep annotations, autofs and other random bugfixes
+S: Prague, Czech Republic
+
N: Gene Kozin
E: 74604.152@compuserve.com
W: http://www.sangoma.com
--- /dev/null
+What: /debug/pktcdvd/pktcdvd[0-7]
+Date: Oct. 2006
+KernelVersion: 2.6.19
+Contact: Thomas Maier <balagi@justmail.de>
+Description:
+
+debugfs interface
+-----------------
+
+The pktcdvd module (packet writing driver) creates
+these files in debugfs:
+
+/debug/pktcdvd/pktcdvd[0-7]/
+ info (0444) Lots of human readable driver
+ statistics and infos. Multiple lines!
+
+Example:
+-------
+
+cat /debug/pktcdvd/pktcdvd0/info
--- /dev/null
+What: /sys/class/pktcdvd/
+Date: Oct. 2006
+KernelVersion: 2.6.19
+Contact: Thomas Maier <balagi@justmail.de>
+Description:
+
+sysfs interface
+---------------
+
+The pktcdvd module (packet writing driver) creates
+these files in the sysfs:
+(<devid> is in format major:minor )
+
+/sys/class/pktcdvd/
+ add (0200) Write a block device id (major:minor)
+ to create a new pktcdvd device and map
+ it to the block device.
+
+ remove (0200) Write the pktcdvd device id (major:minor)
+ to it to remove the pktcdvd device.
+
+ device_map (0444) Shows the device mapping in format:
+ pktcdvd[0-7] <pktdevid> <blkdevid>
+
+/sys/class/pktcdvd/pktcdvd[0-7]/
+ dev (0444) Device id
+ uevent (0200) To send an uevent.
+
+/sys/class/pktcdvd/pktcdvd[0-7]/stat/
+ packets_started (0444) Number of started packets.
+ packets_finished (0444) Number of finished packets.
+
+ kb_written (0444) kBytes written.
+ kb_read (0444) kBytes read.
+ kb_read_gather (0444) kBytes read to fill write packets.
+
+ reset (0200) Write any value to it to reset
+ pktcdvd device statistic values, like
+ bytes read/written.
+
+/sys/class/pktcdvd/pktcdvd[0-7]/write_queue/
+ size (0444) Contains the size of the bio write
+ queue.
+
+ congestion_off (0644) If bio write queue size is below
+ this mark, accept new bio requests
+ from the block layer.
+
+ congestion_on (0644) If bio write queue size is higher
+ as this mark, do no longer accept
+ bio write requests from the block
+ layer and wait till the pktcdvd
+ device has processed enough bio's
+ so that bio write queue size is
+ below congestion off mark.
+ A value of <= 0 disables congestion
+ control.
+
+
+Example:
+--------
+To use the pktcdvd sysfs interface directly, you can do:
+
+# create a new pktcdvd device mapped to /dev/hdc
+echo "22:0" >/sys/class/pktcdvd/add
+cat /sys/class/pktcdvd/device_map
+# assuming device pktcdvd0 was created, look at stat's
+cat /sys/class/pktcdvd/pktcdvd0/stat/kb_written
+# print the device id of the mapped block device
+fgrep pktcdvd0 /sys/class/pktcdvd/device_map
+# remove device, using pktcdvd0 device id 253:0
+echo "253:0" >/sys/class/pktcdvd/remove
-->
</sect1>
</chapter>
+
+ <chapter id="input_subsystem">
+ <title>Input Subsystem</title>
+!Iinclude/linux/input.h
+!Edrivers/input/input.c
+!Edrivers/input/ff-core.c
+!Edrivers/input/ff-memless.c
+ </chapter>
</book>
to create an ext2 filesystem on the disc.
+Using the pktcdvd sysfs interface
+---------------------------------
+
+Since Linux 2.6.19, the pktcdvd module has a sysfs interface
+and can be controlled by it. For example the "pktcdvd" tool uses
+this interface. (see http://people.freenet.de/BalaGi#pktcdvd )
+
+"pktcdvd" works similar to "pktsetup", e.g.:
+
+ # pktcdvd -a dev_name /dev/hdc
+ # mkudffs /dev/pktcdvd/dev_name
+ # mount -t udf -o rw,noatime /dev/pktcdvd/dev_name /dvdram
+ # cp files /dvdram
+ # umount /dvdram
+ # pktcdvd -r dev_name
+
+
+For a description of the sysfs interface look into the file:
+
+ Documentation/ABI/testing/sysfs-block-pktcdvd
+
+
+Using the pktcdvd debugfs interface
+-----------------------------------
+
+To read pktcdvd device infos in human readable form, do:
+
+ # cat /debug/pktcdvd/pktcdvd[0-7]/info
+
+For a description of the debugfs interface look into the file:
+
+ Documentation/ABI/testing/debugfs-pktcdvd
+
+
+
Links
-----
--- /dev/null
+#!/bin/bash
+
+echo 1 > /proc/self/make-it-fail
+exec $*
--- /dev/null
+#!/bin/bash
+#
+# Usage: failmodule <failname> <modulename> [stacktrace-depth]
+#
+# <failname>: "failslab", "fail_alloc_page", or "fail_make_request"
+#
+# <modulename>: module name that you want to inject faults.
+#
+# [stacktrace-depth]: the maximum number of stacktrace walking allowed
+#
+
+STACKTRACE_DEPTH=5
+if [ $# -gt 2 ]; then
+ STACKTRACE_DEPTH=$3
+fi
+
+if [ ! -d /debug/$1 ]; then
+ echo "Fault-injection $1 does not exist" >&2
+ exit 1
+fi
+if [ ! -d /sys/module/$2 ]; then
+ echo "Module $2 does not exist" >&2
+ exit 1
+fi
+
+# Disable any fault injection
+echo 0 > /debug/$1/stacktrace-depth
+
+echo `cat /sys/module/$2/sections/.text` > /debug/$1/require-start
+echo `cat /sys/module/$2/sections/.exit.text` > /debug/$1/require-end
+echo $STACKTRACE_DEPTH > /debug/$1/stacktrace-depth
--- /dev/null
+Fault injection capabilities infrastructure
+===========================================
+
+See also drivers/md/faulty.c and "every_nth" module option for scsi_debug.
+
+
+Available fault injection capabilities
+--------------------------------------
+
+o failslab
+
+ injects slab allocation failures. (kmalloc(), kmem_cache_alloc(), ...)
+
+o fail_page_alloc
+
+ injects page allocation failures. (alloc_pages(), get_free_pages(), ...)
+
+o fail_make_request
+
+ injects disk IO errors on devices permitted by setting
+ /sys/block/<device>/make-it-fail or
+ /sys/block/<device>/<partition>/make-it-fail. (generic_make_request())
+
+Configure fault-injection capabilities behavior
+-----------------------------------------------
+
+o debugfs entries
+
+fault-inject-debugfs kernel module provides some debugfs entries for runtime
+configuration of fault-injection capabilities.
+
+- /debug/fail*/probability:
+
+ likelihood of failure injection, in percent.
+ Format: <percent>
+
+ Note that one-failure-per-hundred is a very high error rate
+ for some testcases. Consider setting probability=100 and configure
+ /debug/fail*/interval for such testcases.
+
+- /debug/fail*/interval:
+
+ specifies the interval between failures, for calls to
+ should_fail() that pass all the other tests.
+
+ Note that if you enable this, by setting interval>1, you will
+ probably want to set probability=100.
+
+- /debug/fail*/times:
+
+ specifies how many times failures may happen at most.
+ A value of -1 means "no limit".
+
+- /debug/fail*/space:
+
+ specifies an initial resource "budget", decremented by "size"
+ on each call to should_fail(,size). Failure injection is
+ suppressed until "space" reaches zero.
+
+- /debug/fail*/verbose
+
+ Format: { 0 | 1 | 2 }
+ specifies the verbosity of the messages when failure is
+ injected. '0' means no messages; '1' will print only a single
+ log line per failure; '2' will print a call trace too -- useful
+ to debug the problems revealed by fault injection.
+
+- /debug/fail*/task-filter:
+
+ Format: { 'Y' | 'N' }
+ A value of 'N' disables filtering by process (default).
+ Any positive value limits failures to only processes indicated by
+ /proc/<pid>/make-it-fail==1.
+
+- /debug/fail*/require-start:
+- /debug/fail*/require-end:
+- /debug/fail*/reject-start:
+- /debug/fail*/reject-end:
+
+ specifies the range of virtual addresses tested during
+ stacktrace walking. Failure is injected only if some caller
+ in the walked stacktrace lies within the required range, and
+ none lies within the rejected range.
+ Default required range is [0,ULONG_MAX) (whole of virtual address space).
+ Default rejected range is [0,0).
+
+- /debug/fail*/stacktrace-depth:
+
+ specifies the maximum stacktrace depth walked during search
+ for a caller within [require-start,require-end) OR
+ [reject-start,reject-end).
+
+- /debug/fail_page_alloc/ignore-gfp-highmem:
+
+ Format: { 'Y' | 'N' }
+ default is 'N', setting it to 'Y' won't inject failures into
+ highmem/user allocations.
+
+- /debug/failslab/ignore-gfp-wait:
+- /debug/fail_page_alloc/ignore-gfp-wait:
+
+ Format: { 'Y' | 'N' }
+ default is 'N', setting it to 'Y' will inject failures
+ only into non-sleep allocations (GFP_ATOMIC allocations).
+
+o Boot option
+
+In order to inject faults while debugfs is not available (early boot time),
+use the boot option:
+
+ failslab=
+ fail_page_alloc=
+ fail_make_request=<interval>,<probability>,<space>,<times>
+
+How to add new fault injection capability
+-----------------------------------------
+
+o #include <linux/fault-inject.h>
+
+o define the fault attributes
+
+ DECLARE_FAULT_INJECTION(name);
+
+ Please see the definition of struct fault_attr in fault-inject.h
+ for details.
+
+o provide a way to configure fault attributes
+
+- boot option
+
+ If you need to enable the fault injection capability from boot time, you can
+ provide boot option to configure it. There is a helper function for it:
+
+ setup_fault_attr(attr, str);
+
+- debugfs entries
+
+ failslab, fail_page_alloc, and fail_make_request use this way.
+ Helper functions:
+
+ init_fault_attr_entries(entries, attr, name);
+ void cleanup_fault_attr_entries(entries);
+
+- module parameters
+
+ If the scope of the fault injection capability is limited to a
+ single kernel module, it is better to provide module parameters to
+ configure the fault attributes.
+
+o add a hook to insert failures
+
+ Upon should_fail() returning true, client code should inject a failure.
+
+ should_fail(attr, size);
+
+Application Examples
+--------------------
+
+o inject slab allocation failures into module init/cleanup code
+
+------------------------------------------------------------------------------
+#!/bin/bash
+
+FAILCMD=Documentation/fault-injection/failcmd.sh
+BLACKLIST="root_plug evbug"
+
+FAILNAME=failslab
+echo Y > /debug/$FAILNAME/task-filter
+echo 10 > /debug/$FAILNAME/probability
+echo 100 > /debug/$FAILNAME/interval
+echo -1 > /debug/$FAILNAME/times
+echo 2 > /debug/$FAILNAME/verbose
+echo 1 > /debug/$FAILNAME/ignore-gfp-wait
+
+blacklist()
+{
+ echo $BLACKLIST | grep $1 > /dev/null 2>&1
+}
+
+oops()
+{
+ dmesg | grep BUG > /dev/null 2>&1
+}
+
+find /lib/modules/`uname -r` -name '*.ko' -exec basename {} .ko \; |
+ while read i
+ do
+ oops && exit 1
+
+ if ! blacklist $i
+ then
+ echo inserting $i...
+ bash $FAILCMD modprobe $i
+ fi
+ done
+
+lsmod | awk '{ if ($3 == 0) { print $1 } }' |
+ while read i
+ do
+ oops && exit 1
+
+ if ! blacklist $i
+ then
+ echo removing $i...
+ bash $FAILCMD modprobe -r $i
+ fi
+ done
+
+------------------------------------------------------------------------------
+
+o inject slab allocation failures only for a specific module
+
+------------------------------------------------------------------------------
+#!/bin/bash
+
+FAILMOD=Documentation/fault-injection/failmodule.sh
+
+echo injecting errors into the module $1...
+
+modprobe $1
+bash $FAILMOD failslab $1 10
+echo 25 > /debug/failslab/probability
+
+------------------------------------------------------------------------------
+
<mailto:aherrman@de.ibm.com>
0xF3 00-3F video/sisfb.h sisfb (in development)
<mailto:thomas@winischhofer.net>
+0xF4 00-1F video/mbxfb.h mbxfb
+ <mailto:raph@8d.com>
eurwdt= [HW,WDT] Eurotech CPU-1220/1410 onboard watchdog.
Format: <io>[,<irq>]
+ failslab=
+ fail_page_alloc=
+ fail_make_request=[KNL]
+ General fault injection mechanism.
+ Format: <interval>,<probability>,<space>,<times>
+ See also /Documentation/fault-injection/.
+
fd_mcs= [HW,SCSI]
See header of drivers/scsi/fd_mcs.c.
- 0.0.0002/
- 0.1.0000/0.1.1234/
...
+ - defunct/
In this example, device 0815 is accessed via subchannel 0 in subchannel set 0,
device 4711 via subchannel 1 in subchannel set 0, and subchannel 2 is a non-I/O
subchannel. Device 1234 is accessed via subchannel 0 in subchannel set 1.
+The subchannel named 'defunct' does not represent any real subchannel on the
+system; it is a pseudo subchannel where disconnnected ccw devices are moved to
+if they are displaced by another ccw device becoming operational on their
+former subchannel. The ccw devices will be moved again to a proper subchannel
+if they become operational again on that subchannel.
+
You should address a ccw device via its bus id (e.g. 0.0.4711); the device can
be found under bus/ccw/devices/.
CIRRUS LOGIC GENERIC FBDEV DRIVER
P: Jeff Garzik
M: jgarzik@pobox.com
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Odd Fixes
CIRRUS LOGIC CS4280/CS461x SOUNDDRIVER
CYBLAFB FRAMEBUFFER DRIVER
P: Knut Petersen
M: Knut_Petersen@t-online.de
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
CYCLADES 2X SYNC CARD DRIVER
FRAMEBUFFER LAYER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
W: http://linux-fbdev.sourceforge.net/
S: Maintained
IMS TWINTURBO FRAMEBUFFER DRIVER
P: Paul Mundt
M: lethal@chaoticdreams.org
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
INFINIBAND SUBSYSTEM
INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
P: Sylvain Meyer
M: sylvain.meyer@worldonline.fr
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
INTEL 810/815 FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
MATROX FRAMEBUFFER DRIVER
P: Petr Vandrovec
M: vandrove@vc.cvut.cz
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
MEGARAID SCSI DRIVERS
L: linux-kernel@vger.kernel.org
S: Maintained
+MOXA SMARTIO/INDUSTIO SERIAL CARD (MXSER 2.0)
+P: Jiri Slaby
+M: jirislaby@gmail.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
MSI LAPTOP SUPPORT
P: Lennart Poettering
M: mzxreary@0pointer.de
M: andrewtv@usa.net
S: Maintained
+MULTITECH MULTIPORT CARD (ISICOM)
+P: Jiri Slaby
+M: jirislaby@gmail.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
NATSEMI ETHERNET DRIVER (DP8381x)
P: Tim Hockin
M: thockin@hockin.org
NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
OPENCORES I2C BUS DRIVER
RADEON FRAMEBUFFER DISPLAY DRIVER
P: Benjamin Herrenschmidt
M: benh@kernel.crashing.org
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
RAGE128 FRAMEBUFFER DISPLAY DRIVER
P: Paul Mackerras
M: paulus@samba.org
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
S3 SAVAGE FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@pol.net
-L: linux-fbdev-devel@lists.sourceforge.net
+L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
S390
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
retval = -EBADF;
file = fget(fd);
if (file) {
- retval = do_osf_statfs(file->f_dentry, buffer, bufsiz);
+ retval = do_osf_statfs(file->f_path.dentry, buffer, bufsiz);
fput(file);
}
return retval;
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_BUST_SPINLOCK
bool
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
unsigned int mask = 0;
sync_port* port;
DEBUGPOLL( static unsigned int prev_mask = 0; );
unsigned int cmd, unsigned long arg)
{
int return_val = 0;
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
sync_port* port;
reg_sser_rw_tr_cfg tr_cfg;
reg_sser_rw_rec_cfg rec_cfg;
static ssize_t sync_serial_write(struct file * file, const char * buf,
size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
DECLARE_WAITQUEUE(wait, current);
sync_port *port;
unsigned long c, c1;
static ssize_t sync_serial_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
int avail;
sync_port *port;
unsigned char* start;
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default y
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default y
+
mainmenu "Fujitsu FR-V Kernel Configuration"
source "init/Kconfig"
#if 0
printk("[area] l=%lx (ENOMEM) f='%s'\n",
- len, filp ? filp->f_dentry->d_name.name : "");
+ len, filp ? filp->f_path.dentry->d_name.name : "");
#endif
return -ENOMEM;
success:
#if 0
printk("[area] l=%lx ad=%lx f='%s'\n",
- len, addr, filp ? filp->f_dentry->d_name.name : "");
+ len, addr, filp ? filp->f_path.dentry->d_name.name : "");
#endif
return addr;
} /* end arch_get_unmapped_area() */
bool
default n
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
config GENERIC_HWEIGHT
bool
default y
depends on !M386
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_CALIBRATE_DELAY
bool
default y
char __user *tmp = buf;
u32 data[4];
u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
+ int cpu = iminor(file->f_path.dentry->d_inode);
if (count % 16)
return -EINVAL; /* Invalid chunk size */
static int cpuid_open(struct inode *inode, struct file *file)
{
- unsigned int cpu = iminor(file->f_dentry->d_inode);
+ unsigned int cpu = iminor(file->f_path.dentry->d_inode);
struct cpuinfo_x86 *c = &(cpu_data)[cpu];
if (cpu >= NR_CPUS || !cpu_online(cpu))
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/bug.h>
#if 0
#define DEBUGP printk
apply_paravirt(pseg, pseg + para->sh_size);
}
- return 0;
+ return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
alternatives_smp_module_del(mod);
+ module_bug_cleanup(mod);
}
u32 __user *tmp = (u32 __user *) buf;
u32 data[2];
u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
+ int cpu = iminor(file->f_path.dentry->d_inode);
int err;
if (count % 8)
const u32 __user *tmp = (const u32 __user *)buf;
u32 data[2];
u32 reg = *ppos;
- int cpu = iminor(file->f_dentry->d_inode);
+ int cpu = iminor(file->f_path.dentry->d_inode);
int err;
if (count % 8)
static int msr_open(struct inode *inode, struct file *file)
{
- unsigned int cpu = iminor(file->f_dentry->d_inode);
+ unsigned int cpu = iminor(file->f_path.dentry->d_inode);
struct cpuinfo_x86 *c = &(cpu_data)[cpu];
if (cpu >= NR_CPUS || !cpu_online(cpu))
/* init low mem mapping */
clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
- KERNEL_PGD_PTRS);
+ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
flush_tlb_all();
schedule_work(&info.task);
wait_for_completion(&done);
#include <linux/unwind.h>
#include <linux/uaccess.h>
#include <linux/nmi.h>
+#include <linux/bug.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
printk("\n");
}
-static void handle_BUG(struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long eip)
{
- unsigned long eip = regs->eip;
unsigned short ud2;
if (eip < PAGE_OFFSET)
- return;
+ return 0;
if (probe_kernel_address((unsigned short *)eip, ud2))
- return;
- if (ud2 != 0x0b0f)
- return;
-
- printk(KERN_EMERG "------------[ cut here ]------------\n");
-
-#ifdef CONFIG_DEBUG_BUGVERBOSE
- do {
- unsigned short line;
- char *file;
- char c;
-
- if (probe_kernel_address((unsigned short *)(eip + 2), line))
- break;
- if (probe_kernel_address((char **)(eip + 4), file) ||
- (unsigned long)file < PAGE_OFFSET ||
- probe_kernel_address(file, c))
- file = "<bad filename>";
+ return 0;
- printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
- return;
- } while (0);
-#endif
- printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n");
+ return ud2 == 0x0b0f;
}
-/* This is gone through when something in the kernel
- * has done something bad and is about to be terminated.
-*/
+/*
+ * This is gone through when something in the kernel has done something bad and
+ * is about to be terminated.
+ */
void die(const char * str, struct pt_regs * regs, long err)
{
static struct {
unsigned long esp;
unsigned short ss;
- handle_BUG(regs);
+ report_bug(regs->eip);
+
printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
#ifdef CONFIG_PREEMPT
printk(KERN_EMERG "PREEMPT ");
RODATA
+ BUG_TABLE
+
. = ALIGN(4);
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
__tracedata_start = .;
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <asm/fixmap.h>
#include <asm/arch_hooks.h>
unsigned long sgivwfb_mem_phys;
unsigned long sgivwfb_mem_size;
+EXPORT_SYMBOL(sgivwfb_mem_phys);
+EXPORT_SYMBOL(sgivwfb_mem_size);
long long mem_size __initdata = 0;
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
if (!(flags & MAP_ANONYMOUS)) {
/* read the file contents */
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!inode->i_fop || !file->f_op->read
|| ((*file->f_op->read)(file, (char __user *) start, end - start, &off) < 0))
{
if (!is_congruent) {
/* read the file contents */
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!inode->i_fop || !file->f_op->read
|| ((*file->f_op->read)(file, (char __user *) pstart, pend - pstart, &poff)
< 0))
/*
* allocate a new dcache entry
*/
- file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
- if (!file->f_dentry) goto out;
+ file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
+ if (!file->f_path.dentry) goto out;
- file->f_dentry->d_op = &pfmfs_dentry_operations;
+ file->f_path.dentry->d_op = &pfmfs_dentry_operations;
- d_add(file->f_dentry, inode);
- file->f_vfsmnt = mntget(pfmfs_mnt);
+ d_add(file->f_path.dentry, inode);
+ file->f_path.mnt = mntget(pfmfs_mnt);
file->f_mapping = inode->i_mapping;
file->f_op = &pfm_file_ops;
static ssize_t
salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *entry = PDE(inode);
struct salinfo_data *data = entry->data;
char cmd[32];
static ssize_t
salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *entry = PDE(inode);
struct salinfo_data *data = entry->data;
u8 *buf;
static ssize_t
salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *entry = PDE(inode);
struct salinfo_data *data = entry->data;
char cmd[32];
bool
default n
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
* arch/m32r/boot/compressed/m32r_sio.c
*
* 2003-02-12: Takeo Takahashi
+ * 2006-11-30: OPSPUT support by Kazuhiro Inaoka
*
*/
return 0;
}
-#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT)
+#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
#include <asm/m32r.h>
#include <asm/io.h>
#define BOOT_SIO0TXB (volatile unsigned short *)(0x02c00000 + 0x2000c)
#else
#undef PLD_BASE
+#if defined(CONFIG_PLAT_OPSPUT)
+#define PLD_BASE 0x1cc00000
+#else
#define PLD_BASE 0xa4c00000
+#endif
#define BOOT_SIO0STS PLD_ESIO0STS
#define BOOT_SIO0TXB PLD_ESIO0TXB
#endif
* updated in fork.c:copy_thread, signal.c:do_signal,
* ptrace.c and ptrace.h
*
- * M32Rx/M32R2 M32R
- * @(sp) - r4 ditto
- * @(0x04,sp) - r5 ditto
- * @(0x08,sp) - r6 ditto
- * @(0x0c,sp) - *pt_regs ditto
- * @(0x10,sp) - r0 ditto
- * @(0x14,sp) - r1 ditto
- * @(0x18,sp) - r2 ditto
- * @(0x1c,sp) - r3 ditto
- * @(0x20,sp) - r7 ditto
- * @(0x24,sp) - r8 ditto
- * @(0x28,sp) - r9 ditto
- * @(0x2c,sp) - r10 ditto
- * @(0x30,sp) - r11 ditto
- * @(0x34,sp) - r12 ditto
- * @(0x38,sp) - syscall_nr ditto
- * @(0x3c,sp) - acc0h @(0x3c,sp) - acch
- * @(0x40,sp) - acc0l @(0x40,sp) - accl
- * @(0x44,sp) - acc1h @(0x44,sp) - dummy_acc1h
- * @(0x48,sp) - acc1l @(0x48,sp) - dummy_acc1l
- * @(0x4c,sp) - psw ditto
- * @(0x50,sp) - bpc ditto
- * @(0x54,sp) - bbpsw ditto
- * @(0x58,sp) - bbpc ditto
- * @(0x5c,sp) - spu (cr3) ditto
- * @(0x60,sp) - fp (r13) ditto
- * @(0x64,sp) - lr (r14) ditto
- * @(0x68,sp) - spi (cr2) ditto
- * @(0x6c,sp) - orig_r0 ditto
+ * M32R/M32Rx/M32R2
+ * @(sp) - r4
+ * @(0x04,sp) - r5
+ * @(0x08,sp) - r6
+ * @(0x0c,sp) - *pt_regs
+ * @(0x10,sp) - r0
+ * @(0x14,sp) - r1
+ * @(0x18,sp) - r2
+ * @(0x1c,sp) - r3
+ * @(0x20,sp) - r7
+ * @(0x24,sp) - r8
+ * @(0x28,sp) - r9
+ * @(0x2c,sp) - r10
+ * @(0x30,sp) - r11
+ * @(0x34,sp) - r12
+ * @(0x38,sp) - syscall_nr
+ * @(0x3c,sp) - acc0h
+ * @(0x40,sp) - acc0l
+ * @(0x44,sp) - acc1h ; ISA_DSP_LEVEL2 only
+ * @(0x48,sp) - acc1l ; ISA_DSP_LEVEL2 only
+ * @(0x4c,sp) - psw
+ * @(0x50,sp) - bpc
+ * @(0x54,sp) - bbpsw
+ * @(0x58,sp) - bbpc
+ * @(0x5c,sp) - spu (cr3)
+ * @(0x60,sp) - fp (r13)
+ * @(0x64,sp) - lr (r14)
+ * @(0x68,sp) - spi (cr2)
+ * @(0x6c,sp) - orig_r0
*/
#include <linux/linkage.h>
#define R11(reg) @(0x30,reg)
#define R12(reg) @(0x34,reg)
#define SYSCALL_NR(reg) @(0x38,reg)
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
#define ACC0H(reg) @(0x3C,reg)
#define ACC0L(reg) @(0x40,reg)
#define ACC1H(reg) @(0x44,reg)
#define ACC1L(reg) @(0x48,reg)
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
-#define ACCH(reg) @(0x3C,reg)
-#define ACCL(reg) @(0x40,reg)
-#else
-#error unknown isa configuration
-#endif
#define PSW(reg) @(0x4C,reg)
#define BPC(reg) @(0x50,reg)
#define BBPSW(reg) @(0x54,reg)
beqz r1, inst
oprand:
ld r2, @(low(MDEVA_offset),r2) ; set address
- srli r2, #12
- slli r2, #12
srli r1, #1
bra 1f
inst:
extern void pcc_iowrite_word(int, unsigned long, void *, size_t, size_t, int);
#endif /* CONFIG_PCMCIA && CONFIG_M32R_CFC */
-#define PORT2ADDR(port) _port2addr(port)
-#define PORT2ADDR_USB(port) _port2addr_usb(port)
+#define PORT2ADDR(port) _port2addr(port)
+#define PORT2ADDR_USB(port) _port2addr_usb(port)
static inline void *_port2addr(unsigned long port)
{
return (void *)(port | NONCACHE_OFFSET);
}
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+static inline void *__port2addr_ata(unsigned long port)
+{
+ static int dummy_reg;
+
+ switch (port) {
+ case 0x1f0: return (void *)(0x0c002000 | NONCACHE_OFFSET);
+ case 0x1f1: return (void *)(0x0c012800 | NONCACHE_OFFSET);
+ case 0x1f2: return (void *)(0x0c012002 | NONCACHE_OFFSET);
+ case 0x1f3: return (void *)(0x0c012802 | NONCACHE_OFFSET);
+ case 0x1f4: return (void *)(0x0c012004 | NONCACHE_OFFSET);
+ case 0x1f5: return (void *)(0x0c012804 | NONCACHE_OFFSET);
+ case 0x1f6: return (void *)(0x0c012006 | NONCACHE_OFFSET);
+ case 0x1f7: return (void *)(0x0c012806 | NONCACHE_OFFSET);
+ case 0x3f6: return (void *)(0x0c01200e | NONCACHE_OFFSET);
+ default: return (void *)&dummy_reg;
+ }
+}
+#endif
+
/*
* OPSPUT-LAN is located in the extended bus space
* from 0x10000000 to 0x13ffffff on physical address.
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
return _ne_inb(PORT2ADDR_NE(port));
+
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ return *(volatile unsigned char *)__port2addr_ata(port);
+ }
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
unsigned char b;
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
return _ne_inw(PORT2ADDR_NE(port));
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ return *(volatile unsigned short *)__port2addr_ata(port);
+ }
+#endif
#if defined(CONFIG_USB)
else if(port >= 0x340 && port < 0x3a0)
return *(volatile unsigned short *)PORT2ADDR_USB(port);
if (port >= LAN_IOSTART && port < LAN_IOEND)
_ne_outb(b, PORT2ADDR_NE(port));
else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ *(volatile unsigned char *)__port2addr_ata(port) = b;
+ } else
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_byte(0, port, &b, sizeof(b), 1, 0);
if (port >= LAN_IOSTART && port < LAN_IOEND)
_ne_outw(w, PORT2ADDR_NE(port));
else
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ *(volatile unsigned short *)__port2addr_ata(port) = w;
+ } else
+#endif
#if defined(CONFIG_USB)
if(port >= 0x340 && port < 0x3a0)
*(volatile unsigned short *)PORT2ADDR_USB(port) = w;
{
if (port >= LAN_IOSTART && port < LAN_IOEND)
_ne_insb(PORT2ADDR_NE(port), addr, count);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ unsigned char *buf = addr;
+ unsigned char *portp = __port2addr_ata(port);
+ while (count--)
+ *buf++ = *(volatile unsigned char *)portp;
+ }
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_ioread_byte(0, port, (void *)addr, sizeof(unsigned char),
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_ioread_word(9, port, (void *)addr, sizeof(unsigned short),
count, 1);
+#endif
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *buf++ = *(volatile unsigned short *)portp;
#endif
} else {
portp = PORT2ADDR(port);
portp = PORT2ADDR_NE(port);
while (count--)
_ne_outb(*buf++, portp);
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *(volatile unsigned char *)portp = *buf++;
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_byte(0, port, (void *)addr, sizeof(unsigned char),
portp = PORT2ADDR_NE(port);
while (count--)
*(volatile unsigned short *)portp = *buf++;
+#if defined(CONFIG_IDE) && !defined(CONFIG_M32R_CFC)
+ } else if ((port >= 0x1f0 && port <=0x1f7) || port == 0x3f6) {
+ portp = __port2addr_ata(port);
+ while (count--)
+ *(volatile unsigned short *)portp = *buf++;
+#endif
#if defined(CONFIG_PCMCIA) && defined(CONFIG_M32R_CFC)
} else if (port >= M32R_PCC_IOSTART0 && port <= M32R_PCC_IOEND0) {
pcc_iowrite_word(9, port, (void *)addr, sizeof(unsigned short),
static struct hw_interrupt_type opsput_lanpld_irq_type =
{
- "OPSPUT-PLD-LAN-IRQ",
- startup_opsput_lanpld_irq,
- shutdown_opsput_lanpld_irq,
- enable_opsput_lanpld_irq,
- disable_opsput_lanpld_irq,
- mask_and_ack_opsput_lanpld,
- end_opsput_lanpld_irq
+ .typename = "OPSPUT-PLD-LAN-IRQ",
+ .startup = startup_opsput_lanpld_irq,
+ .shutdown = shutdown_opsput_lanpld_irq,
+ .enable = enable_opsput_lanpld_irq,
+ .disable = disable_opsput_lanpld_irq,
+ .ack = mask_and_ack_opsput_lanpld,
+ .end = end_opsput_lanpld_irq
};
/*
disable_opsput_pld_irq(PLD_IRQ_SIO0_SND);
#endif /* CONFIG_SERIAL_M32R_PLDSIO */
-#if defined(CONFIG_M32R_CFC)
/* INT#1: CFC IREQ on PLD */
irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
irq_desc[PLD_IRQ_CFIREQ].chip = &opsput_pld_irq_type;
irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */
disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT);
-#endif /* CONFIG_M32R_CFC */
-
/*
* INT0# is used for LAN, DIO
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
-#if 0
+
if (error_code & ACE_USERMODE) {
/*
* accessing the stack below "spu" is always a bug.
if (address + 4 < regs->spu)
goto bad_area;
}
-#endif
+
if (expand_stack(vma, address))
goto bad_area;
/*
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
bool
default n
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
psinfo.pr_pid = prstatus.pr_pid = current->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid;
psinfo.pr_pgrp = prstatus.pr_pgrp = process_group(current);
- psinfo.pr_sid = prstatus.pr_sid = current->signal->session;
+ psinfo.pr_sid = prstatus.pr_sid = process_session(current);
if (current->pid == current->tgid) {
/*
* This is the record for the group leader. Add in the
int minor;
unsigned int mask = 0;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
poll_wait(file, &channel_wqs[minor].rt_queue, wait);
poll_wait(file, &channel_wqs[minor].lx_queue, wait);
static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
loff_t * ppos)
{
- int minor = iminor(file->f_dentry->d_inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
/* data available? */
if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
struct rtlx_channel *rt;
DECLARE_WAITQUEUE(wait, current);
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
rt = &rtlx->channel[minor];
/* any space left... */
goto out;
}
- error = vfs_statfs(file->f_dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, &kbuf);
if (error)
goto out_f;
unsigned long old_pos;
long max_size = offset + len;
- if (max_size > file->f_dentry->d_inode->i_size) {
+ if (max_size > file->f_path.dentry->d_inode->i_size) {
old_pos = sys_lseek (fd, max_size - 1, 0);
sys_write (fd, (void __user *) "", 1);
sys_lseek (fd, old_pos, 0);
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, &kbuf);
if (error)
goto out_f;
unsigned long old_pos;
long max_size = off2 + len;
- if (max_size > file->f_dentry->d_inode->i_size) {
+ if (max_size > file->f_path.dentry->d_inode->i_size) {
old_pos = sys_lseek (fd, max_size - 1, 0);
sys_write (fd, (void __user *) "", 1);
sys_lseek (fd, old_pos, 0);
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, &kbuf);
if (error)
goto out_f;
size_t ret = count;
struct vpe *v;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
if ((v = get_vpe(minor)) == NULL)
return -ENODEV;
mutex_unlock(&lasat_info_mutex);
return r;
}
- if (filp && filp->f_dentry)
+ if (filp && filp->f_path.dentry)
{
- if (!strcmp(filp->f_dentry->d_name.name, "prid"))
+ if (!strcmp(filp->f_path.dentry->d_name.name, "prid"))
lasat_board_info.li_eeprom_info.prid = lasat_board_info.li_prid;
- if (!strcmp(filp->f_dentry->d_name.name, "debugaccess"))
+ if (!strcmp(filp->f_path.dentry->d_name.name, "debugaccess"))
lasat_board_info.li_eeprom_info.debugaccess = lasat_board_info.li_debugaccess;
}
lasat_write_eeprom_info();
* (C) Copyright 1995 1996 Linus Torvalds
* (C) Copyright 2001, 2002 Ralf Baechle
*/
+#include <linux/mm.h>
#include <linux/module.h>
#include <asm/addrspace.h>
#include <asm/byteorder.h>
#include <linux/vmalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
-#include <asm/tlbflush.h>
-
-static inline void remap_area_pte(pte_t * pte, unsigned long address,
- phys_t size, phys_t phys_addr, unsigned long flags)
-{
- phys_t end;
- unsigned long pfn;
- pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
- | __WRITEABLE | flags);
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, pfn_pte(pfn, pgprot));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address,
- phys_t size, phys_t phys_addr, unsigned long flags)
-{
- phys_t end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static int remap_area_pages(unsigned long address, phys_t phys_addr,
- phys_t size, unsigned long flags)
-{
- int error;
- pgd_t * dir;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset(&init_mm, address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pud_t *pud;
- pmd_t *pmd;
-
- error = -ENOMEM;
- pud = pud_alloc(&init_mm, dir, address);
- if (!pud)
- break;
- pmd = pmd_alloc(&init_mm, pud, address);
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
+#include <linux/io.h>
/*
* Generic mapping function (not visible outside):
unsigned long offset;
phys_t last_addr;
void * addr;
+ pgprot_t pgprot;
phys_addr = fixup_bigphys_addr(phys_addr, size);
return NULL;
}
+ pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE
+ | __WRITEABLE | flags);
+
/*
* Mappings have to be page-aligned
*/
if (!area)
return NULL;
addr = area->addr;
- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
vunmap(addr);
return NULL;
}
config RWSEM_XCHGADD_ALGORITHM
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_FIND_NEXT_BIT
bool
default y
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_hpux(file->f_dentry, &tmp);
+ error = vfs_statfs_hpux(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
#include <linux/vmalloc.h>
#include <linux/errno.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-
-static inline void
-remap_area_pte(pte_t *pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end, pfn;
- pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY |
- _PAGE_ACCESSED | flags);
-
- address &= ~PMD_MASK;
-
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
-
- BUG_ON(address >= end);
-
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- BUG_ON(!pte_none(*pte));
-
- set_pte(pte, pfn_pte(pfn, pgprot));
-
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int
-remap_area_pmd(pmd_t *pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
-
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
-
- BUG_ON(address >= end);
-
- phys_addr -= address;
- do {
- pte_t *pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
-
- remap_area_pte(pte, address, end - address,
- address + phys_addr, flags);
-
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
-
- return 0;
-}
-
-static int
-remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- pgd_t *dir;
- int error = 0;
- unsigned long end = address + size;
-
- BUG_ON(address >= end);
-
- phys_addr -= address;
- dir = pgd_offset_k(address);
-
- flush_cache_all();
-
- do {
- pud_t *pud;
- pmd_t *pmd;
-
- error = -ENOMEM;
- pud = pud_alloc(&init_mm, dir, address);
- if (!pud)
- break;
-
- pmd = pmd_alloc(&init_mm, pud, address);
- if (!pmd)
- break;
-
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags))
- break;
-
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
-
- flush_tlb_all();
-
- return error;
-}
/*
* Generic mapping function (not visible outside):
void *addr;
struct vm_struct *area;
unsigned long offset, last_addr;
+ pgprot_t pgprot;
#ifdef CONFIG_EISA
unsigned long end = phys_addr + size - 1;
}
}
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY |
+ _PAGE_ACCESSED | flags);
+
/*
* Mappings have to be page-aligned
*/
return NULL;
addr = area->addr;
- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
vfree(addr);
return NULL;
}
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default y
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default y if 64BIT
+
config GENERIC_HWEIGHT
bool
default y
static loff_t page_map_seek( struct file *file, loff_t off, int whence)
{
loff_t new;
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
switch(whence) {
case 0:
static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size);
}
static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
if ((vma->vm_end - vma->vm_start) > dp->size)
return -EINVAL;
static int rtas_flash_release(struct inode *inode, struct file *file)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
uf = (struct rtas_update_flash_t *) dp->data;
static ssize_t rtas_flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
char msg[RTAS_MSG_MAXLEN];
int msglen;
static ssize_t rtas_flash_write(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
char *p;
int next_free;
static ssize_t manage_flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_manage_flash_t *args_buf;
char msg[RTAS_MSG_MAXLEN];
int msglen;
static ssize_t manage_flash_write(struct file *file, const char __user *buf,
size_t count, loff_t *off)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_manage_flash_t *args_buf;
const char reject_str[] = "0";
const char commit_str[] = "1";
static ssize_t validate_flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_validate_flash_t *args_buf;
char msg[RTAS_MSG_MAXLEN];
int msglen;
static ssize_t validate_flash_write(struct file *file, const char __user *buf,
size_t count, loff_t *off)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_validate_flash_t *args_buf;
int rc;
static int validate_flash_release(struct inode *inode, struct file *file)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_validate_flash_t *args_buf;
args_buf = (struct rtas_validate_flash_t *) dp->data;
struct dentry *dir;
int ret;
- dir = file->f_dentry;
+ dir = file->f_path.dentry;
parent = dir->d_parent->d_inode;
ctx = SPUFS_I(dir->d_inode)->i_ctx;
struct dentry *dir;
int ret;
- dir = file->f_dentry;
+ dir = file->f_path.dentry;
parent = dir->d_parent->d_inode;
ret = spufs_rmgang(parent, dir);
if (filp->f_op != &spufs_context_fops)
goto out;
- i = SPUFS_I(filp->f_dentry->d_inode);
+ i = SPUFS_I(filp->f_path.dentry->d_inode);
ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
if (put_user(npc, unpc))
const char __user *buf,
size_t count, loff_t *ppos)
{
- struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
ssize_t rc;
dma_addr_t dma_addr;
char *page;
rc = seq_open(file, &hcall_inst_seq_ops);
seq = file->private_data;
- seq->private = file->f_dentry->d_inode->i_private;
+ seq->private = file->f_path.dentry->d_inode->i_private;
return rc;
}
static ssize_t scanlog_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp;
unsigned int *data;
int status;
int rc = 0;
if (sq.busy)
- rc = sq_fsync(file, file->f_dentry);
+ rc = sq_fsync(file, file->f_path.dentry);
sound.soft = sound.dsp;
sound.hard = sound.dsp;
sound_silence();
return 0;
case SNDCTL_DSP_POST:
case SNDCTL_DSP_SYNC:
- return sq_fsync(file, file->f_dentry);
+ return sq_fsync(file, file->f_path.dentry);
/* ++TeSche: before changing any of these it's
* probably wise to wait until sound playing has
* settled down. */
case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_speed(data));
case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_stereo(data));
case SOUND_PCM_WRITE_CHANNELS:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_dentry);
+ sq_fsync(file, file->f_path.dentry);
IOCTL_IN(arg, data);
return IOCTL_OUT(arg, sound_set_format(data));
case SNDCTL_DSP_GETFMTS:
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default y
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
source "init/Kconfig"
menu "Processor"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/prctl.h>
+#include <linux/bug.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
}
}
-/*
- * Look through the list of trap instructions that are used for BUG(),
- * BUG_ON() and WARN_ON() and see if we hit one. At this point we know
- * that the exception was caused by a trap instruction of some kind.
- * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
- * otherwise.
- */
-extern struct bug_entry __start___bug_table[], __stop___bug_table[];
-
-#ifndef CONFIG_MODULES
-#define module_find_bug(x) NULL
-#endif
-
-struct bug_entry *find_bug(unsigned long bugaddr)
-{
- struct bug_entry *bug;
-
- for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
- if (bugaddr == bug->bug_addr)
- return bug;
- return module_find_bug(bugaddr);
-}
-
-int check_bug_trap(struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long addr)
{
- struct bug_entry *bug;
- unsigned long addr;
-
- if (regs->msr & MSR_PR)
- return 0; /* not in kernel */
- addr = regs->nip; /* address of trap instruction */
- if (addr < PAGE_OFFSET)
- return 0;
- bug = find_bug(regs->nip);
- if (bug == NULL)
- return 0;
- if (bug->line & BUG_WARNING_TRAP) {
- /* this is a WARN_ON rather than BUG/BUG_ON */
-#ifdef CONFIG_XMON
- xmon_printf(KERN_ERR "Badness in %s at %s:%ld\n",
- bug->function, bug->file,
- bug->line & ~BUG_WARNING_TRAP);
-#endif /* CONFIG_XMON */
- printk(KERN_ERR "Badness in %s at %s:%ld\n",
- bug->function, bug->file,
- bug->line & ~BUG_WARNING_TRAP);
- dump_stack();
- return 1;
- }
-#ifdef CONFIG_XMON
- xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
- bug->function, bug->file, bug->line);
- xmon(regs);
-#endif /* CONFIG_XMON */
- printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
- bug->function, bug->file, bug->line);
-
- return 0;
+ return addr >= PAGE_OFFSET;
}
void program_check_exception(struct pt_regs *regs)
/* trap exception */
if (debugger_bpt(regs))
return;
- if (check_bug_trap(regs)) {
+
+ if (!(regs->msr & MSR_PR) && /* not user-mode */
+ report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
}
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config GENERIC_HWEIGHT
bool
default y
This allows you to specify the maximum frame size a function may
have without the compiler complaining about it.
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
source "mm/Kconfig"
+config HOLES_IN_ZONE
+ def_bool y
+
comment "I/O subsystem configuration"
config MACHCHK_WARNING
If unsure, say Y.
-config QDIO_PERF_STATS
- bool "Performance statistics in /proc"
- depends on QDIO
- help
- Say Y here to get performance statistics in /proc/qdio_perf
-
- If unsure, say N.
-
config QDIO_DEBUG
bool "Extended debugging information"
depends on QDIO
#
CONFIG_MACHCHK_WARNING=y
CONFIG_QDIO=y
-# CONFIG_QDIO_PERF_STATS is not set
# CONFIG_QDIO_DEBUG is not set
#
static int hypfs_open(struct inode *inode, struct file *filp)
{
- char *data = filp->f_dentry->d_inode->i_private;
+ char *data = filp->f_path.dentry->d_inode->i_private;
struct hypfs_sb_info *fs_info;
if (filp->f_mode & FMODE_WRITE) {
struct hypfs_sb_info *fs_info;
size_t count = iov_length(iov, nr_segs);
- sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
+ sb = iocb->ki_filp->f_path.dentry->d_inode->i_sb;
fs_info = sb->s_fs_info;
/*
* Currently we only allow one update per second for two reasons:
debug_info_t *debug_info, *debug_info_snapshot;
down(&debug_lock);
- debug_info = file->f_dentry->d_inode->i_private;
+ debug_info = file->f_path.dentry->d_inode->i_private;
/* find debug view */
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
if (!debug_info->views[i])
continue;
else if (debug_info->debugfs_entries[i] ==
- file->f_dentry) {
+ file->f_path.dentry) {
goto found; /* found view ! */
}
}
unsigned int console_irq = -1;
unsigned long machine_flags = 0;
-struct mem_chunk memory_chunk[MEMORY_CHUNKS];
+struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
-unsigned long __initdata zholes_size[MAX_NR_ZONES];
static unsigned long __initdata memory_end;
/*
*/
void (*pm_power_off)(void) = machine_power_off;
-static void __init
-add_memory_hole(unsigned long start, unsigned long end)
-{
- unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
-
- if (end <= dma_pfn)
- zholes_size[ZONE_DMA] += end - start + 1;
- else if (start > dma_pfn)
- zholes_size[ZONE_NORMAL] += end - start + 1;
- else {
- zholes_size[ZONE_DMA] += dma_pfn - start + 1;
- zholes_size[ZONE_NORMAL] += end - dma_pfn;
- }
-}
-
static int __init early_parse_mem(char *p)
{
memory_end = memparse(p, &p);
{
unsigned long bootmap_size;
unsigned long start_pfn, end_pfn, init_pfn;
- unsigned long last_rw_end;
int i;
/*
/*
* Register RAM areas with the bootmem allocator.
*/
- last_rw_end = start_pfn;
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
- unsigned long start_chunk, end_chunk;
+ unsigned long start_chunk, end_chunk, pfn;
if (memory_chunk[i].type != CHUNK_READ_WRITE)
continue;
- start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1);
- start_chunk >>= PAGE_SHIFT;
- end_chunk = (memory_chunk[i].addr + memory_chunk[i].size);
- end_chunk >>= PAGE_SHIFT;
- if (start_chunk < start_pfn)
- start_chunk = start_pfn;
- if (end_chunk > end_pfn)
- end_chunk = end_pfn;
- if (start_chunk < end_chunk) {
- /* Initialize storage key for RAM pages */
- for (init_pfn = start_chunk ; init_pfn < end_chunk;
- init_pfn++)
- page_set_storage_key(init_pfn << PAGE_SHIFT,
- PAGE_DEFAULT_KEY);
- free_bootmem(start_chunk << PAGE_SHIFT,
- (end_chunk - start_chunk) << PAGE_SHIFT);
- if (last_rw_end < start_chunk)
- add_memory_hole(last_rw_end, start_chunk - 1);
- last_rw_end = end_chunk;
- }
+ start_chunk = PFN_DOWN(memory_chunk[i].addr);
+ end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1;
+ end_chunk = min(end_chunk, end_pfn);
+ if (start_chunk >= end_chunk)
+ continue;
+ add_active_range(0, start_chunk, end_chunk);
+ pfn = max(start_chunk, start_pfn);
+ for (; pfn <= end_chunk; pfn++)
+ page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
}
psw_set_key(PAGE_DEFAULT_KEY);
- if (last_rw_end < end_pfn - 1)
- add_memory_hole(last_rw_end, end_pfn - 1);
+ free_bootmem_with_active_regions(0, max_pfn);
+ reserve_bootmem(0, PFN_PHYS(start_pfn));
/*
* Reserve the bootmem bitmap itself as well. We do this in two
*/
#include <linux/errno.h>
-#include <asm/uaccess.h>
#include <linux/mm.h>
+#include <asm/uaccess.h>
#include <asm/futex.h>
static inline int __handle_fault(struct mm_struct *mm, unsigned long address,
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
+ down_read(&mm->mmap_sem);
goto survive;
}
printk("VM: killing process %s\n", current->comm);
# Makefile for the linux s390-specific parts of the memory manager.
#
-obj-y := init.o fault.o ioremap.o extmem.o mmap.o
+obj-y := init.o fault.o ioremap.o extmem.o mmap.o vmem.o
obj-$(CONFIG_CMM) += cmm.o
#include <linux/bootmem.h>
#include <linux/ctype.h>
#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/ebcdic.h>
#include <asm/errno.h>
#include <asm/extmem.h>
return rc;
}
-/*
- * check if the given segment collides with guest storage.
- * returns 1 if this is the case, 0 if no collision was found
- */
-static int
-segment_overlaps_storage(struct dcss_segment *seg)
-{
- int i;
-
- for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
- if (memory_chunk[i].type != CHUNK_READ_WRITE)
- continue;
- if ((memory_chunk[i].addr >> 20) > (seg->end >> 20))
- continue;
- if (((memory_chunk[i].addr + memory_chunk[i].size - 1) >> 20)
- < (seg->start_addr >> 20))
- continue;
- return 1;
- }
- return 0;
-}
-
-/*
- * check if segment collides with other segments that are currently loaded
- * returns 1 if this is the case, 0 if no collision was found
- */
-static int
-segment_overlaps_others (struct dcss_segment *seg)
-{
- struct list_head *l;
- struct dcss_segment *tmp;
-
- BUG_ON(!mutex_is_locked(&dcss_lock));
- list_for_each(l, &dcss_list) {
- tmp = list_entry(l, struct dcss_segment, list);
- if ((tmp->start_addr >> 20) > (seg->end >> 20))
- continue;
- if ((tmp->end >> 20) < (seg->start_addr >> 20))
- continue;
- if (seg == tmp)
- continue;
- return 1;
- }
- return 0;
-}
-
-/*
- * check if segment exceeds the kernel mapping range (detected or set via mem=)
- * returns 1 if this is the case, 0 if segment fits into the range
- */
-static inline int
-segment_exceeds_range (struct dcss_segment *seg)
-{
- int seg_last_pfn = (seg->end) >> PAGE_SHIFT;
- if (seg_last_pfn > max_pfn)
- return 1;
- return 0;
-}
-
/*
* get info about a segment
* possible return values:
rc = query_segment_type (seg);
if (rc < 0)
goto out_free;
- if (segment_exceeds_range(seg)) {
- PRINT_WARN ("segment_load: not loading segment %s - exceeds"
- " kernel mapping range\n",name);
- rc = -ERANGE;
+
+ rc = add_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+
+ switch (rc) {
+ case 0:
+ break;
+ case -ENOSPC:
+ PRINT_WARN("segment_load: not loading segment %s - overlaps "
+ "storage/segment\n", name);
goto out_free;
- }
- if (segment_overlaps_storage(seg)) {
- PRINT_WARN ("segment_load: not loading segment %s - overlaps"
- " storage\n",name);
- rc = -ENOSPC;
+ case -ERANGE:
+ PRINT_WARN("segment_load: not loading segment %s - exceeds "
+ "kernel mapping range\n", name);
goto out_free;
- }
- if (segment_overlaps_others(seg)) {
- PRINT_WARN ("segment_load: not loading segment %s - overlaps"
- " other segments\n",name);
- rc = -EBUSY;
+ default:
+ PRINT_WARN("segment_load: not loading segment %s (rc: %d)\n",
+ name, rc);
goto out_free;
}
+
if (do_nonshared)
dcss_command = DCSS_LOADNSR;
else
rc = dcss_diag_translate_rc (seg->end);
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
&seg->start_addr, &seg->end);
- goto out_free;
+ goto out_shared;
}
seg->do_nonshared = do_nonshared;
atomic_set(&seg->ref_count, 1);
(void*)seg->start_addr, (void*)seg->end,
segtype_string[seg->vm_segtype]);
goto out;
+ out_shared:
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
out_free:
kfree(seg);
out:
"please report to linux390@de.ibm.com\n",name);
goto out_unlock;
}
- if (atomic_dec_return(&seg->ref_count) == 0) {
- list_del(&seg->list);
- dcss_diag(DCSS_PURGESEG, seg->dcss_name,
- &dummy, &dummy);
- kfree(seg);
- }
+ if (atomic_dec_return(&seg->ref_count) != 0)
+ goto out_unlock;
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ list_del(&seg->list);
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ kfree(seg);
out_unlock:
mutex_unlock(&dcss_lock);
}
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/pfn.h>
+#include <linux/poison.h>
#include <asm/processor.h>
#include <asm/system.h>
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
while (i-- > 0) {
+ if (!pfn_valid(i))
+ continue;
page = pfn_to_page(i);
total++;
if (PageReserved(page))
printk("%d pages swap cached\n",cached);
}
-extern unsigned long __initdata zholes_size[];
-/*
- * paging_init() sets up the page tables
- */
-
-#ifndef CONFIG_64BIT
-void __init paging_init(void)
+static void __init setup_ro_region(void)
{
- pgd_t * pg_dir;
- pte_t * pg_table;
- pte_t pte;
- int i;
- unsigned long tmp;
- unsigned long pfn = 0;
- unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
- static const int ssm_mask = 0x04000000L;
- unsigned long ro_start_pfn, ro_end_pfn;
- unsigned long zones_size[MAX_NR_ZONES];
-
- ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata);
- ro_end_pfn = PFN_UP((unsigned long)&__end_rodata);
-
- memset(zones_size, 0, sizeof(zones_size));
- zones_size[ZONE_DMA] = max_low_pfn;
- free_area_init_node(0, &contig_page_data, zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT,
- zholes_size);
-
- /* unmap whole virtual address space */
-
- pg_dir = swapper_pg_dir;
-
- for (i = 0; i < PTRS_PER_PGD; i++)
- pmd_clear((pmd_t *) pg_dir++);
-
- /*
- * map whole physical memory to virtual memory (identity mapping)
- */
-
- pg_dir = swapper_pg_dir;
-
- while (pfn < max_low_pfn) {
- /*
- * pg_table is physical at this point
- */
- pg_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
-
- pmd_populate_kernel(&init_mm, (pmd_t *) pg_dir, pg_table);
- pg_dir++;
-
- for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
- if (pfn >= ro_start_pfn && pfn < ro_end_pfn)
- pte = pfn_pte(pfn, __pgprot(_PAGE_RO));
- else
- pte = pfn_pte(pfn, PAGE_KERNEL);
- if (pfn >= max_low_pfn)
- pte_val(pte) = _PAGE_TYPE_EMPTY;
- set_pte(pg_table, pte);
- pfn++;
- }
- }
-
- S390_lowcore.kernel_asce = pgdir_k;
-
- /* enable virtual mapping in kernel mode */
- __ctl_load(pgdir_k, 1, 1);
- __ctl_load(pgdir_k, 7, 7);
- __ctl_load(pgdir_k, 13, 13);
- __raw_local_irq_ssm(ssm_mask);
-
- local_flush_tlb();
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t new_pte;
+ unsigned long address, end;
+
+ address = ((unsigned long)&__start_rodata) & PAGE_MASK;
+ end = PFN_ALIGN((unsigned long)&__end_rodata);
+
+ for (; address < end; address += PAGE_SIZE) {
+ pgd = pgd_offset_k(address);
+ pmd = pmd_offset(pgd, address);
+ pte = pte_offset_kernel(pmd, address);
+ new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
+ set_pte(pte, new_pte);
+ }
}
-#else /* CONFIG_64BIT */
+extern void vmem_map_init(void);
+/*
+ * paging_init() sets up the page tables
+ */
void __init paging_init(void)
{
- pgd_t * pg_dir;
- pmd_t * pm_dir;
- pte_t * pt_dir;
- pte_t pte;
- int i,j,k;
- unsigned long pfn = 0;
- unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
- _KERN_REGION_TABLE;
+ pgd_t *pg_dir;
+ int i;
+ unsigned long pgdir_k;
static const int ssm_mask = 0x04000000L;
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long dma_pfn, high_pfn;
- unsigned long ro_start_pfn, ro_end_pfn;
-
- memset(zones_size, 0, sizeof(zones_size));
- dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
- high_pfn = max_low_pfn;
- ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata);
- ro_end_pfn = PFN_UP((unsigned long)&__end_rodata);
-
- if (dma_pfn > high_pfn)
- zones_size[ZONE_DMA] = high_pfn;
- else {
- zones_size[ZONE_DMA] = dma_pfn;
- zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
- }
-
- /* Initialize mem_map[]. */
- free_area_init_node(0, &contig_page_data, zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
- /*
- * map whole physical memory to virtual memory (identity mapping)
- */
-
- pg_dir = swapper_pg_dir;
-
- for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
+ pg_dir = swapper_pg_dir;
- if (pfn >= max_low_pfn) {
- pgd_clear(pg_dir);
- continue;
- }
-
- pm_dir = (pmd_t *) alloc_bootmem_pages(PAGE_SIZE * 4);
- pgd_populate(&init_mm, pg_dir, pm_dir);
-
- for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
- if (pfn >= max_low_pfn) {
- pmd_clear(pm_dir);
- continue;
- }
-
- pt_dir = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
- pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
-
- for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
- if (pfn >= ro_start_pfn && pfn < ro_end_pfn)
- pte = pfn_pte(pfn, __pgprot(_PAGE_RO));
- else
- pte = pfn_pte(pfn, PAGE_KERNEL);
- if (pfn >= max_low_pfn)
- pte_val(pte) = _PAGE_TYPE_EMPTY;
- set_pte(pt_dir, pte);
- pfn++;
- }
- }
- }
+#ifdef CONFIG_64BIT
+ pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
+ for (i = 0; i < PTRS_PER_PGD; i++)
+ pgd_clear(pg_dir + i);
+#else
+ pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
+ for (i = 0; i < PTRS_PER_PGD; i++)
+ pmd_clear((pmd_t *)(pg_dir + i));
+#endif
+ vmem_map_init();
+ setup_ro_region();
S390_lowcore.kernel_asce = pgdir_k;
__ctl_load(pgdir_k, 13, 13);
__raw_local_irq_ssm(ssm_mask);
- local_flush_tlb();
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ free_area_init_nodes(max_zone_pfns);
}
-#endif /* CONFIG_64BIT */
void __init mem_init(void)
{
printk("Write protected kernel read-only data: %#lx - %#lx\n",
(unsigned long)&__start_rodata,
PFN_ALIGN((unsigned long)&__end_rodata) - 1);
+ printk("Virtual memmap size: %ldk\n",
+ (max_pfn * sizeof(struct page)) >> 10);
}
void free_initmem(void)
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
free_page(addr);
totalram_pages++;
}
#include <linux/vmalloc.h>
#include <linux/mm.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
- unsigned long pfn;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, pfn_pte(pfn, __pgprot(flags)));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- int error;
- pgd_t * dir;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset(&init_mm, address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pmd_t *pmd;
- pmd = pmd_alloc(&init_mm, dir, address);
- error = -ENOMEM;
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return 0;
-}
/*
* Generic mapping function (not visible outside):
if (!area)
return NULL;
addr = area->addr;
- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, __pgprot(flags))) {
vfree(addr);
return NULL;
}
--- /dev/null
+/*
+ * arch/s390/mm/vmem.c
+ *
+ * Copyright IBM Corp. 2006
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/bootmem.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/tlbflush.h>
+
+unsigned long vmalloc_end;
+EXPORT_SYMBOL(vmalloc_end);
+
+static struct page *vmem_map;
+static DEFINE_MUTEX(vmem_mutex);
+
+struct memory_segment {
+ struct list_head list;
+ unsigned long start;
+ unsigned long size;
+};
+
+static LIST_HEAD(mem_segs);
+
+void memmap_init(unsigned long size, int nid, unsigned long zone,
+ unsigned long start_pfn)
+{
+ struct page *start, *end;
+ struct page *map_start, *map_end;
+ int i;
+
+ start = pfn_to_page(start_pfn);
+ end = start + size;
+
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ unsigned long cstart, cend;
+
+ cstart = PFN_DOWN(memory_chunk[i].addr);
+ cend = cstart + PFN_DOWN(memory_chunk[i].size);
+
+ map_start = mem_map + cstart;
+ map_end = mem_map + cend;
+
+ if (map_start < start)
+ map_start = start;
+ if (map_end > end)
+ map_end = end;
+
+ map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1))
+ / sizeof(struct page);
+ map_end += ((PFN_ALIGN((unsigned long) map_end)
+ - (unsigned long) map_end)
+ / sizeof(struct page));
+
+ if (map_start < map_end)
+ memmap_init_zone((unsigned long)(map_end - map_start),
+ nid, zone, page_to_pfn(map_start));
+ }
+}
+
+static inline void *vmem_alloc_pages(unsigned int order)
+{
+ if (slab_is_available())
+ return (void *)__get_free_pages(GFP_KERNEL, order);
+ return alloc_bootmem_pages((1 << order) * PAGE_SIZE);
+}
+
+static inline pmd_t *vmem_pmd_alloc(void)
+{
+ pmd_t *pmd;
+ int i;
+
+ pmd = vmem_alloc_pages(PMD_ALLOC_ORDER);
+ if (!pmd)
+ return NULL;
+ for (i = 0; i < PTRS_PER_PMD; i++)
+ pmd_clear(pmd + i);
+ return pmd;
+}
+
+static inline pte_t *vmem_pte_alloc(void)
+{
+ pte_t *pte;
+ pte_t empty_pte;
+ int i;
+
+ pte = vmem_alloc_pages(PTE_ALLOC_ORDER);
+ if (!pte)
+ return NULL;
+ pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
+ for (i = 0; i < PTRS_PER_PTE; i++)
+ set_pte(pte + i, empty_pte);
+ return pte;
+}
+
+/*
+ * Add a physical memory range to the 1:1 mapping.
+ */
+static int vmem_add_range(unsigned long start, unsigned long size)
+{
+ unsigned long address;
+ pgd_t *pg_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+ int ret = -ENOMEM;
+
+ for (address = start; address < start + size; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ pm_dir = vmem_pmd_alloc();
+ if (!pm_dir)
+ goto out;
+ pgd_populate(&init_mm, pg_dir, pm_dir);
+ }
+
+ pm_dir = pmd_offset(pg_dir, address);
+ if (pmd_none(*pm_dir)) {
+ pt_dir = vmem_pte_alloc();
+ if (!pt_dir)
+ goto out;
+ pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ }
+
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
+ set_pte(pt_dir, pte);
+ }
+ ret = 0;
+out:
+ flush_tlb_kernel_range(start, start + size);
+ return ret;
+}
+
+/*
+ * Remove a physical memory range from the 1:1 mapping.
+ * Currently only invalidates page table entries.
+ */
+static void vmem_remove_range(unsigned long start, unsigned long size)
+{
+ unsigned long address;
+ pgd_t *pg_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+
+ pte_val(pte) = _PAGE_TYPE_EMPTY;
+ for (address = start; address < start + size; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir))
+ continue;
+ pm_dir = pmd_offset(pg_dir, address);
+ if (pmd_none(*pm_dir))
+ continue;
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ set_pte(pt_dir, pte);
+ }
+ flush_tlb_kernel_range(start, start + size);
+}
+
+/*
+ * Add a backed mem_map array to the virtual mem_map array.
+ */
+static int vmem_add_mem_map(unsigned long start, unsigned long size)
+{
+ unsigned long address, start_addr, end_addr;
+ struct page *map_start, *map_end;
+ pgd_t *pg_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+ int ret = -ENOMEM;
+
+ map_start = vmem_map + PFN_DOWN(start);
+ map_end = vmem_map + PFN_DOWN(start + size);
+
+ start_addr = (unsigned long) map_start & PAGE_MASK;
+ end_addr = PFN_ALIGN((unsigned long) map_end);
+
+ for (address = start_addr; address < end_addr; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ pm_dir = vmem_pmd_alloc();
+ if (!pm_dir)
+ goto out;
+ pgd_populate(&init_mm, pg_dir, pm_dir);
+ }
+
+ pm_dir = pmd_offset(pg_dir, address);
+ if (pmd_none(*pm_dir)) {
+ pt_dir = vmem_pte_alloc();
+ if (!pt_dir)
+ goto out;
+ pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ }
+
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ if (pte_none(*pt_dir)) {
+ unsigned long new_page;
+
+ new_page =__pa(vmem_alloc_pages(0));
+ if (!new_page)
+ goto out;
+ pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
+ set_pte(pt_dir, pte);
+ }
+ }
+ ret = 0;
+out:
+ flush_tlb_kernel_range(start_addr, end_addr);
+ return ret;
+}
+
+static int vmem_add_mem(unsigned long start, unsigned long size)
+{
+ int ret;
+
+ ret = vmem_add_range(start, size);
+ if (ret)
+ return ret;
+ return vmem_add_mem_map(start, size);
+}
+
+/*
+ * Add memory segment to the segment list if it doesn't overlap with
+ * an already present segment.
+ */
+static int insert_memory_segment(struct memory_segment *seg)
+{
+ struct memory_segment *tmp;
+
+ if (PFN_DOWN(seg->start + seg->size) > max_pfn ||
+ seg->start + seg->size < seg->start)
+ return -ERANGE;
+
+ list_for_each_entry(tmp, &mem_segs, list) {
+ if (seg->start >= tmp->start + tmp->size)
+ continue;
+ if (seg->start + seg->size <= tmp->start)
+ continue;
+ return -ENOSPC;
+ }
+ list_add(&seg->list, &mem_segs);
+ return 0;
+}
+
+/*
+ * Remove memory segment from the segment list.
+ */
+static void remove_memory_segment(struct memory_segment *seg)
+{
+ list_del(&seg->list);
+}
+
+static void __remove_shared_memory(struct memory_segment *seg)
+{
+ remove_memory_segment(seg);
+ vmem_remove_range(seg->start, seg->size);
+}
+
+int remove_shared_memory(unsigned long start, unsigned long size)
+{
+ struct memory_segment *seg;
+ int ret;
+
+ mutex_lock(&vmem_mutex);
+
+ ret = -ENOENT;
+ list_for_each_entry(seg, &mem_segs, list) {
+ if (seg->start == start && seg->size == size)
+ break;
+ }
+
+ if (seg->start != start || seg->size != size)
+ goto out;
+
+ ret = 0;
+ __remove_shared_memory(seg);
+ kfree(seg);
+out:
+ mutex_unlock(&vmem_mutex);
+ return ret;
+}
+
+int add_shared_memory(unsigned long start, unsigned long size)
+{
+ struct memory_segment *seg;
+ struct page *page;
+ unsigned long pfn, num_pfn, end_pfn;
+ int ret;
+
+ mutex_lock(&vmem_mutex);
+ ret = -ENOMEM;
+ seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+ if (!seg)
+ goto out;
+ seg->start = start;
+ seg->size = size;
+
+ ret = insert_memory_segment(seg);
+ if (ret)
+ goto out_free;
+
+ ret = vmem_add_mem(start, size);
+ if (ret)
+ goto out_remove;
+
+ pfn = PFN_DOWN(start);
+ num_pfn = PFN_DOWN(size);
+ end_pfn = pfn + num_pfn;
+
+ page = pfn_to_page(pfn);
+ memset(page, 0, num_pfn * sizeof(struct page));
+
+ for (; pfn < end_pfn; pfn++) {
+ page = pfn_to_page(pfn);
+ init_page_count(page);
+ reset_page_mapcount(page);
+ SetPageReserved(page);
+ INIT_LIST_HEAD(&page->lru);
+ }
+ goto out;
+
+out_remove:
+ __remove_shared_memory(seg);
+out_free:
+ kfree(seg);
+out:
+ mutex_unlock(&vmem_mutex);
+ return ret;
+}
+
+/*
+ * map whole physical memory to virtual memory (identity mapping)
+ */
+void __init vmem_map_init(void)
+{
+ unsigned long map_size;
+ int i;
+
+ map_size = ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page);
+ vmalloc_end = PFN_ALIGN(VMALLOC_END_INIT) - PFN_ALIGN(map_size);
+ vmem_map = (struct page *) vmalloc_end;
+ NODE_DATA(0)->node_mem_map = vmem_map;
+
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
+ vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
+}
+
+/*
+ * Convert memory chunk array to a memory segment list so there is a single
+ * list that contains both r/w memory and shared memory segments.
+ */
+static int __init vmem_convert_memory_chunk(void)
+{
+ struct memory_segment *seg;
+ int i;
+
+ mutex_lock(&vmem_mutex);
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ if (!memory_chunk[i].size)
+ continue;
+ seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+ if (!seg)
+ panic("Out of memory...\n");
+ seg->start = memory_chunk[i].addr;
+ seg->size = memory_chunk[i].size;
+ insert_memory_segment(seg);
+ }
+ mutex_unlock(&vmem_mutex);
+ return 0;
+}
+
+core_initcall(vmem_convert_memory_chunk);
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source "init/Kconfig"
menu "System type"
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/addrspace.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
-static inline void remap_area_pte(pte_t * pte, unsigned long address,
- unsigned long size, unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
- unsigned long pfn;
- pgprot_t pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, pfn_pte(pfn, pgprot));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address,
- unsigned long size, unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-int remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- int error;
- pgd_t * dir;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset_k(address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pud_t *pud;
- pmd_t *pmd;
-
- error = -ENOMEM;
-
- pud = pud_alloc(&init_mm, dir, address);
- if (!pud)
- break;
- pmd = pmd_alloc(&init_mm, pud, address);
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
-
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
{
struct vm_struct * area;
unsigned long offset, last_addr, addr, orig_addr;
+ pgprot_t pgprot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
}
#endif
+ pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags);
if (likely(size))
- if (remap_area_pages(addr, phys_addr, size, flags)) {
+ if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) {
vunmap((void *)orig_addr);
return NULL;
}
*/
static inline int to_counter(struct file *file)
{
- const unsigned char *name = file->f_dentry->d_parent->d_name.name;
+ const unsigned char *name = file->f_path.dentry->d_parent->d_name.name;
return (int)simple_strtol(name, NULL, 10);
}
config GENERIC_ISA_DMA
bool
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source init/Kconfig
menu "System type"
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/string.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <linux/ioport.h>
static void shmedia_mapioaddr(unsigned long, unsigned long);
static unsigned long shmedia_ioremap(struct resource *, u32, int);
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
- unsigned long pfn;
- pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ |
- _PAGE_WRITE | _PAGE_DIRTY |
- _PAGE_ACCESSED | _PAGE_SHARED | flags);
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
-
- pfn = phys_addr >> PAGE_SHIFT;
-
- pr_debug(" %s: pte %p address %lx size %lx phys_addr %lx\n",
- __FUNCTION__,pte,address,size,phys_addr);
-
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
-
- set_pte(pte, pfn_pte(pfn, pgprot));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
-
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
-
- phys_addr -= address;
-
- if (address >= end)
- BUG();
-
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- int error;
- pgd_t * dir;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset_k(address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
- error = -ENOMEM;
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags)) {
- break;
- }
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return 0;
-}
-
/*
* Generic mapping function (not visible outside):
*/
void * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
+ pgprot_t pgprot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ |
+ _PAGE_WRITE | _PAGE_DIRTY |
+ _PAGE_ACCESSED | _PAGE_SHARED | flags);
+
/*
* Mappings have to be page-aligned
*/
return NULL;
area->phys_addr = phys_addr;
addr = area->addr;
- if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
vunmap(addr);
return NULL;
}
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config SUN_PM
bool
default y
* SunOS is so stupid some times... hmph!
*/
if (file) {
- if (imajor(file->f_dentry->d_inode) == MEM_MAJOR &&
- iminor(file->f_dentry->d_inode) == 5) {
+ if (imajor(file->f_path.dentry->d_inode) == MEM_MAJOR &&
+ iminor(file->f_path.dentry->d_inode) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
file = NULL;
if (!file)
goto out;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
socket = SOCKET_I(inode);
local.sin_family = AF_INET;
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
config AUDIT_ARCH
bool
default y
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ bprm->file->f_path.dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
file = fget(fd);
if (!file)
goto out;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (imajor(inode) == MEM_MAJOR && iminor(inode) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
if (!file)
return 0;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
socket = SOCKET_I(inode);
local.sin_family = AF_INET;
error = -EBADF;
file = fget(fd);
if (file) {
- error = report_statvfs(file->f_vfsmnt, file->f_dentry->d_inode, buf);
+ error = report_statvfs(file->f_path.mnt, file->f_path.dentry->d_inode, buf);
fput(file);
}
file = fget(fd);
if (file) {
lock_kernel();
- error = report_statvfs64(file->f_vfsmnt, file->f_dentry->d_inode, buf);
+ error = report_statvfs64(file->f_path.mnt, file->f_path.dentry->d_inode, buf);
unlock_kernel();
fput(file);
}
rcu_read_lock();
fdt = files_fdtable(current->files);
if (! fdt->fd[fd] ||
- ! fdt->fd[fd]->f_dentry ||
- ! (ino = fdt->fd[fd]->f_dentry->d_inode) ||
+ ! fdt->fd[fd]->f_path.dentry ||
+ ! (ino = fdt->fd[fd]->f_path.dentry->d_inode) ||
! S_ISSOCK(ino->i_mode)) {
rcu_read_unlock();
return TBADF;
struct sol_socket_struct *sock;
struct module_info *mi;
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
if (!S_ISSOCK(ino->i_mode))
return -EBADF;
sock = filp->private_data;
if (!file)
goto out;
else {
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
if(imajor(inode) == MEM_MAJOR &&
iminor(inode) == 5) {
flags |= MAP_ANONYMOUS;
Solaris setpgrp and setsid? */
ret = sys_setpgid(0, 0);
if (ret) return ret;
- mutex_lock(&tty_mutex);
- current->signal->tty = NULL;
- mutex_unlock(&tty_mutex);
+ proc_clear_tty(current);
return process_group(current);
}
case 2: /* getsid */
* No shit. WTF is it supposed to do, anyway?
*
* Try instead:
- * d_delete(filp->f_dentry), then d_instantiate with sock inode
+ * d_delete(filp->f_path.dentry), then d_instantiate with sock inode
*/
- dentry = filp->f_dentry;
- filp->f_dentry = dget(fcheck(fd)->f_dentry);
- filp->f_dentry->d_inode->i_rdev = inode->i_rdev;
- filp->f_dentry->d_inode->i_flock = inode->i_flock;
- SOCKET_I(filp->f_dentry->d_inode)->file = filp;
+ dentry = filp->f_path.dentry;
+ filp->f_path.dentry = dget(fcheck(fd)->f_path.dentry);
+ filp->f_path.dentry->d_inode->i_rdev = inode->i_rdev;
+ filp->f_path.dentry->d_inode->i_flock = inode->i_flock;
+ SOCKET_I(filp->f_path.dentry->d_inode)->file = filp;
filp->f_op = &socksys_file_ops;
sock = (struct sol_socket_struct*)
mykmalloc(sizeof(struct sol_socket_struct), GFP_KERNEL);
struct inode *ino;
unsigned int mask = 0;
- ino=filp->f_dentry->d_inode;
+ ino=filp->f_path.dentry->d_inode;
if (ino && S_ISSOCK(ino->i_mode)) {
struct sol_socket_struct *sock;
sock = (struct sol_socket_struct*)filp->private_data;
SOLD("wakeing socket");
fdt = files_fdtable(current->files);
- sock = SOCKET_I(fdt->fd[fd]->f_dentry->d_inode);
+ sock = SOCKET_I(fdt->fd[fd]->f_path.dentry->d_inode);
wake_up_interruptible(&sock->wait);
read_lock(&sock->sk->sk_callback_lock);
if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
fdt = files_fdtable(current->files);
filp = fdt->fd[fd];
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
sock = (struct sol_socket_struct *)filp->private_data;
SOLD("entry");
if (get_user(ret, (int __user *)A(ctl_buf)))
SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
fdt = files_fdtable(current->files);
filp = fdt->fd[fd];
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
sock = (struct sol_socket_struct *)filp->private_data;
SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
if ( ctl_maxlen > 0 && !sock->pfirst && SOCKET_I(ino)->type == SOCK_STREAM
filp = fdt->fd[fd];
if(!filp) goto out;
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
if (!ino || !S_ISSOCK(ino->i_mode))
goto out;
filp = fdt->fd[fd];
if(!filp) goto out;
- ino = filp->f_dentry->d_inode;
+ ino = filp->f_path.dentry->d_inode;
if (!ino) goto out;
if (!S_ISSOCK(ino->i_mode) &&
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
# Used in kernel/irq/manage.c and include/linux/irq.h
config IRQ_RELEASE_METHOD
bool
return ret;
}
-void line_set_termios(struct tty_struct *tty, struct termios * old)
+void line_set_termios(struct tty_struct *tty, struct ktermios * old)
{
/* nothing */
}
extern int line_write(struct tty_struct *tty, const unsigned char *buf,
int len);
extern void line_put_char(struct tty_struct *tty, unsigned char ch);
-extern void line_set_termios(struct tty_struct *tty, struct termios * old);
+extern void line_set_termios(struct tty_struct *tty, struct ktermios * old);
extern int line_chars_in_buffer(struct tty_struct *tty);
extern void line_flush_buffer(struct tty_struct *tty);
extern void line_flush_chars(struct tty_struct *tty);
char __user *__user *env)
{
long error;
+ struct tty_struct *tty;
#ifdef CONFIG_TTY_LOG
mutex_lock(&tty_mutex);
- task_lock(current); /* FIXME: is this needed ? */
- log_exec(argv, current->signal->tty);
- task_unlock(current);
+ tty = get_current_tty();
+ if (tty)
+ log_exec(argv, tty);
mutex_unlock(&tty_mutex);
#endif
error = do_execve(file, argv, env, ¤t->thread.regs);
-obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \
sys_call_table.o tls.o
--- /dev/null
+/*
+ * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL V2
+ */
+
+#include <linux/uaccess.h>
+
+/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
+ * that's not relevent in skas mode.
+ */
+
+int is_valid_bugaddr(unsigned long eip)
+{
+ unsigned short ud2;
+
+ if (probe_kernel_address((unsigned short __user *)eip, ud2))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
# Licensed under the GPL
#
-obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
+obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
setjmp.o sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o \
ksyms.o tls.o
--- /dev/null
+/*
+ * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL V2
+ */
+
+#include <linux/uaccess.h>
+
+/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
+ * that's not relevent in skas mode.
+ */
+
+int is_valid_bugaddr(unsigned long eip)
+{
+ unsigned short ud2;
+
+ if (probe_kernel_address((unsigned short __user *)eip, ud2))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
# Turn off some random 386 crap that can affect device config
config ISA
bool
bool
default y
+config GENERIC_BUG
+ bool
+ default y
+ depends on BUG
+
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source "init/Kconfig"
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ i_size_read(bprm->file->f_path.dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
- bprm->file->f_dentry->d_name.name);
+ bprm->file->f_path.dentry->d_name.name);
error_time = jiffies;
}
#endif
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
{
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert library: %s\n",
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
error_time = jiffies;
}
#endif
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/bug.h>
#include <asm/system.h>
#include <asm/page.h>
lseg, lseg + locks->sh_size,
tseg, tseg + text->sh_size);
}
- return 0;
+
+ return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
alternatives_smp_module_del(mod);
+ module_bug_cleanup(mod);
}
#include <linux/kexec.h>
#include <linux/unwind.h>
#include <linux/uaccess.h>
+#include <linux/bug.h>
#include <asm/system.h>
#include <asm/io.h>
printk("\n");
}
-void handle_BUG(struct pt_regs *regs)
-{
- struct bug_frame f;
- long len;
- const char *prefix = "";
+int is_valid_bugaddr(unsigned long rip)
+{
+ unsigned short ud2;
- if (user_mode(regs))
- return;
- if (__copy_from_user(&f, (const void __user *) regs->rip,
- sizeof(struct bug_frame)))
- return;
- if (f.filename >= 0 ||
- f.ud2[0] != 0x0f || f.ud2[1] != 0x0b)
- return;
- len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1;
- if (len < 0 || len >= PATH_MAX)
- f.filename = (int)(long)"unmapped filename";
- else if (len > 50) {
- f.filename += len - 50;
- prefix = "...";
- }
- printk("----------- [cut here ] --------- [please bite here ] ---------\n");
- printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line);
-}
+ if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2)))
+ return 0;
+
+ return ud2 == 0x0b0f;
+}
#ifdef CONFIG_BUG
void out_of_line_bug(void)
{
unsigned long flags = oops_begin();
- handle_BUG(regs);
+ if (!user_mode(regs))
+ report_bug(regs->rip);
+
__die(str, regs, err);
oops_end(flags);
do_exit(SIGSEGV);
RODATA
+ BUG_TABLE
+
. = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */
/* Data */
.data : AT(ADDR(.data) - LOAD_OFFSET) {
bool
default y
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
source "init/Kconfig"
menu "Processor type and features"
.show = disk_stats_read
};
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static ssize_t disk_fail_store(struct gendisk * disk,
+ const char *buf, size_t count)
+{
+ int i;
+
+ if (count > 0 && sscanf(buf, "%d", &i) > 0) {
+ if (i == 0)
+ disk->flags &= ~GENHD_FL_FAIL;
+ else
+ disk->flags |= GENHD_FL_FAIL;
+ }
+
+ return count;
+}
+static ssize_t disk_fail_read(struct gendisk * disk, char *page)
+{
+ return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0);
+}
+static struct disk_attribute disk_attr_fail = {
+ .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
+ .store = disk_fail_store,
+ .show = disk_fail_read
+};
+
+#endif
+
static struct attribute * default_attrs[] = {
&disk_attr_uevent.attr,
&disk_attr_dev.attr,
&disk_attr_removable.attr,
&disk_attr_size.attr,
&disk_attr_stat.attr,
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+ &disk_attr_fail.attr,
+#endif
NULL,
};
bdevp = bdget_disk(disk, part);
if (!bdevp)
return -ENOMEM;
- mutex_lock_nested(&bdevp->bd_mutex, BD_MUTEX_PARTITION);
+ mutex_lock(&bdevp->bd_mutex);
if (bdevp->bd_openers) {
mutex_unlock(&bdevp->bd_mutex);
bdput(bdevp);
fsync_bdev(bdevp);
invalidate_bdev(bdevp, 0);
- mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_WHOLE);
+ mutex_lock(&bdev->bd_mutex);
delete_partition(disk, part);
mutex_unlock(&bdev->bd_mutex);
mutex_unlock(&bdevp->bd_mutex);
ENOIOCTLCMD for unknown ioctls. */
long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+ struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
int ret = -ENOIOCTLCMD;
if (disk->fops->compat_ioctl) {
#include <linux/interrupt.h>
#include <linux/cpu.h>
#include <linux/blktrace_api.h>
+#include <linux/fault-inject.h>
/*
* for max sense size
set_bit(BIO_EOF, &bio->bi_flags);
}
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static DECLARE_FAULT_ATTR(fail_make_request);
+
+static int __init setup_fail_make_request(char *str)
+{
+ return setup_fault_attr(&fail_make_request, str);
+}
+__setup("fail_make_request=", setup_fail_make_request);
+
+static int should_fail_request(struct bio *bio)
+{
+ if ((bio->bi_bdev->bd_disk->flags & GENHD_FL_FAIL) ||
+ (bio->bi_bdev->bd_part && bio->bi_bdev->bd_part->make_it_fail))
+ return should_fail(&fail_make_request, bio->bi_size);
+
+ return 0;
+}
+
+static int __init fail_make_request_debugfs(void)
+{
+ return init_fault_attr_dentries(&fail_make_request,
+ "fail_make_request");
+}
+
+late_initcall(fail_make_request_debugfs);
+
+#else /* CONFIG_FAIL_MAKE_REQUEST */
+
+static inline int should_fail_request(struct bio *bio)
+{
+ return 0;
+}
+
+#endif /* CONFIG_FAIL_MAKE_REQUEST */
+
/**
* generic_make_request: hand a buffer to its device driver for I/O
* @bio: The bio describing the location in memory and on the device.
if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
goto end_io;
+ if (should_fail_request(bio))
+ goto end_io;
+
/*
* If this device has partitions, remap block n
* of partition p to block n+start(p) of the disk.
source "sound/Kconfig"
+source "drivers/hid/Kconfig"
+
source "drivers/usb/Kconfig"
source "drivers/mmc/Kconfig"
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
+obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
config ATM_AMBASSADOR
tristate "Madge Ambassador (Collage PCI 155 Server)"
depends on PCI && ATM
+ select BITREVERSE
help
This is a driver for ATMizer based ATM card produced by Madge
Networks Ltd. Say Y (or M to compile as a module named ambassador)
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/poison.h>
+#include <linux/bitrev.h>
#include <asm/atomic.h>
#include <asm/io.h>
PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor);
}
-// swap bits within byte to get Ethernet ordering
-static u8 bit_swap (u8 byte)
-{
- const u8 swap[] = {
- 0x0, 0x8, 0x4, 0xc,
- 0x2, 0xa, 0x6, 0xe,
- 0x1, 0x9, 0x5, 0xd,
- 0x3, 0xb, 0x7, 0xf
- };
- return ((swap[byte & 0xf]<<4) | swap[byte>>4]);
-}
-
// get end station address
static void __devinit amb_esi (amb_dev * dev, u8 * esi) {
u32 lower4;
PRINTDB (DBG_INIT, "ESI:");
for (i = 0; i < ESI_LEN; ++i) {
if (i < 4)
- esi[i] = bit_swap (lower4>>(8*i));
+ esi[i] = bitrev8(lower4>>(8*i));
else
- esi[i] = bit_swap (upper2>>(8*(i-4)));
+ esi[i] = bitrev8(upper2>>(8*(i-4)));
PRINTDM (DBG_INIT, " %02x", esi[i]);
}
tristate "Packet writing on CD/DVD media"
depends on !UML
help
- If you have a CDROM drive that supports packet writing, say Y to
- include preliminary support. It should work with any MMC/Mt Fuji
- compliant ATAPI or SCSI drive, which is just about any newer CD
- writer.
+ If you have a CDROM/DVD drive that supports packet writing, say
+ Y to include support. It should work with any MMC/Mt Fuji
+ compliant ATAPI or SCSI drive, which is just about any newer
+ DVD/CD writer.
- Currently only writing to CD-RW, DVD-RW and DVD+RW discs is possible.
+ Currently only writing to CD-RW, DVD-RW, DVD+RW and DVDRAM discs
+ is possible.
DVD-RW disks must be in restricted overwrite mode.
+ See the file <file:Documentation/cdrom/packet-writing.txt>
+ for further information on the use of this driver.
+
To compile this driver as a module, choose M here: the
module will be called pktcdvd.
loff_t *ppos )
{
- struct inode *node = file->f_dentry->d_inode;
+ struct inode *node = file->f_path.dentry->d_inode;
unsigned long page;
int length;
int end;
loff_t *ppos )
{
- struct inode *node = file->f_dentry->d_inode;
+ struct inode *node = file->f_path.dentry->d_inode;
int device = iminor(node);
int n, filled, w, h;
{
int ret;
lock_kernel();
- ret = cciss_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+ ret = cciss_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
unlock_kernel();
return ret;
}
if (lo->lo_state != Lo_bound)
return -ENXIO;
- error = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
+ error = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat);
if (error)
return error;
memset(info, 0, sizeof(*info));
static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
int err;
error = -EINVAL;
file = fget(arg);
if (file) {
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
lo->file = file;
lo->sock = SOCKET_I(inode);
/*
* Copyright (C) 2000 Jens Axboe <axboe@suse.de>
* Copyright (C) 2001-2004 Peter Osterlund <petero2@telia.com>
+ * Copyright (C) 2006 Thomas Maier <balagi@justmail.de>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
static struct proc_dir_entry *pkt_proc;
static int pktdev_major;
+static int write_congestion_on = PKT_WRITE_CONGESTION_ON;
+static int write_congestion_off = PKT_WRITE_CONGESTION_OFF;
static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
+static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */
+static struct dentry *pkt_debugfs_root = NULL; /* /debug/pktcdvd */
+
+/* forward declaration */
+static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
+static int pkt_remove_dev(dev_t pkt_dev);
+static int pkt_seq_show(struct seq_file *m, void *p);
+
+
+
+/*
+ * create and register a pktcdvd kernel object.
+ */
+static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
+ const char* name,
+ struct kobject* parent,
+ struct kobj_type* ktype)
+{
+ struct pktcdvd_kobj *p;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return NULL;
+ kobject_set_name(&p->kobj, "%s", name);
+ p->kobj.parent = parent;
+ p->kobj.ktype = ktype;
+ p->pd = pd;
+ if (kobject_register(&p->kobj) != 0)
+ return NULL;
+ return p;
+}
+/*
+ * remove a pktcdvd kernel object.
+ */
+static void pkt_kobj_remove(struct pktcdvd_kobj *p)
+{
+ if (p)
+ kobject_unregister(&p->kobj);
+}
+/*
+ * default release function for pktcdvd kernel objects.
+ */
+static void pkt_kobj_release(struct kobject *kobj)
+{
+ kfree(to_pktcdvdkobj(kobj));
+}
+
+
+/**********************************************************
+ *
+ * sysfs interface for pktcdvd
+ * by (C) 2006 Thomas Maier <balagi@justmail.de>
+ *
+ **********************************************************/
+
+#define DEF_ATTR(_obj,_name,_mode) \
+ static struct attribute _obj = { \
+ .name = _name, .owner = THIS_MODULE, .mode = _mode }
+
+/**********************************************************
+ /sys/class/pktcdvd/pktcdvd[0-7]/
+ stat/reset
+ stat/packets_started
+ stat/packets_finished
+ stat/kb_written
+ stat/kb_read
+ stat/kb_read_gather
+ write_queue/size
+ write_queue/congestion_off
+ write_queue/congestion_on
+ **********************************************************/
+
+DEF_ATTR(kobj_pkt_attr_st1, "reset", 0200);
+DEF_ATTR(kobj_pkt_attr_st2, "packets_started", 0444);
+DEF_ATTR(kobj_pkt_attr_st3, "packets_finished", 0444);
+DEF_ATTR(kobj_pkt_attr_st4, "kb_written", 0444);
+DEF_ATTR(kobj_pkt_attr_st5, "kb_read", 0444);
+DEF_ATTR(kobj_pkt_attr_st6, "kb_read_gather", 0444);
+
+static struct attribute *kobj_pkt_attrs_stat[] = {
+ &kobj_pkt_attr_st1,
+ &kobj_pkt_attr_st2,
+ &kobj_pkt_attr_st3,
+ &kobj_pkt_attr_st4,
+ &kobj_pkt_attr_st5,
+ &kobj_pkt_attr_st6,
+ NULL
+};
+
+DEF_ATTR(kobj_pkt_attr_wq1, "size", 0444);
+DEF_ATTR(kobj_pkt_attr_wq2, "congestion_off", 0644);
+DEF_ATTR(kobj_pkt_attr_wq3, "congestion_on", 0644);
+
+static struct attribute *kobj_pkt_attrs_wqueue[] = {
+ &kobj_pkt_attr_wq1,
+ &kobj_pkt_attr_wq2,
+ &kobj_pkt_attr_wq3,
+ NULL
+};
+
+/* declares a char buffer[64] _dbuf, copies data from
+ * _b with length _l into it and ensures that _dbuf ends
+ * with a \0 character.
+ */
+#define DECLARE_BUF_AS_STRING(_dbuf, _b, _l) \
+ char _dbuf[64]; int dlen = (_l) < 0 ? 0 : (_l); \
+ if (dlen >= sizeof(_dbuf)) dlen = sizeof(_dbuf)-1; \
+ memcpy(_dbuf, _b, dlen); _dbuf[dlen] = 0
+
+static ssize_t kobj_pkt_show(struct kobject *kobj,
+ struct attribute *attr, char *data)
+{
+ struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
+ int n = 0;
+ int v;
+ if (strcmp(attr->name, "packets_started") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.pkt_started);
+
+ } else if (strcmp(attr->name, "packets_finished") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.pkt_ended);
+
+ } else if (strcmp(attr->name, "kb_written") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.secs_w >> 1);
+
+ } else if (strcmp(attr->name, "kb_read") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.secs_r >> 1);
+
+ } else if (strcmp(attr->name, "kb_read_gather") == 0) {
+ n = sprintf(data, "%lu\n", pd->stats.secs_rg >> 1);
+
+ } else if (strcmp(attr->name, "size") == 0) {
+ spin_lock(&pd->lock);
+ v = pd->bio_queue_size;
+ spin_unlock(&pd->lock);
+ n = sprintf(data, "%d\n", v);
+
+ } else if (strcmp(attr->name, "congestion_off") == 0) {
+ spin_lock(&pd->lock);
+ v = pd->write_congestion_off;
+ spin_unlock(&pd->lock);
+ n = sprintf(data, "%d\n", v);
+
+ } else if (strcmp(attr->name, "congestion_on") == 0) {
+ spin_lock(&pd->lock);
+ v = pd->write_congestion_on;
+ spin_unlock(&pd->lock);
+ n = sprintf(data, "%d\n", v);
+ }
+ return n;
+}
+
+static void init_write_congestion_marks(int* lo, int* hi)
+{
+ if (*hi > 0) {
+ *hi = max(*hi, 500);
+ *hi = min(*hi, 1000000);
+ if (*lo <= 0)
+ *lo = *hi - 100;
+ else {
+ *lo = min(*lo, *hi - 100);
+ *lo = max(*lo, 100);
+ }
+ } else {
+ *hi = -1;
+ *lo = -1;
+ }
+}
+
+static ssize_t kobj_pkt_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *data, size_t len)
+{
+ struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
+ int val;
+ DECLARE_BUF_AS_STRING(dbuf, data, len); /* ensure sscanf scans a string */
+
+ if (strcmp(attr->name, "reset") == 0 && dlen > 0) {
+ pd->stats.pkt_started = 0;
+ pd->stats.pkt_ended = 0;
+ pd->stats.secs_w = 0;
+ pd->stats.secs_rg = 0;
+ pd->stats.secs_r = 0;
+
+ } else if (strcmp(attr->name, "congestion_off") == 0
+ && sscanf(dbuf, "%d", &val) == 1) {
+ spin_lock(&pd->lock);
+ pd->write_congestion_off = val;
+ init_write_congestion_marks(&pd->write_congestion_off,
+ &pd->write_congestion_on);
+ spin_unlock(&pd->lock);
+
+ } else if (strcmp(attr->name, "congestion_on") == 0
+ && sscanf(dbuf, "%d", &val) == 1) {
+ spin_lock(&pd->lock);
+ pd->write_congestion_on = val;
+ init_write_congestion_marks(&pd->write_congestion_off,
+ &pd->write_congestion_on);
+ spin_unlock(&pd->lock);
+ }
+ return len;
+}
+
+static struct sysfs_ops kobj_pkt_ops = {
+ .show = kobj_pkt_show,
+ .store = kobj_pkt_store
+};
+static struct kobj_type kobj_pkt_type_stat = {
+ .release = pkt_kobj_release,
+ .sysfs_ops = &kobj_pkt_ops,
+ .default_attrs = kobj_pkt_attrs_stat
+};
+static struct kobj_type kobj_pkt_type_wqueue = {
+ .release = pkt_kobj_release,
+ .sysfs_ops = &kobj_pkt_ops,
+ .default_attrs = kobj_pkt_attrs_wqueue
+};
+
+static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
+{
+ if (class_pktcdvd) {
+ pd->clsdev = class_device_create(class_pktcdvd,
+ NULL, pd->pkt_dev,
+ NULL, "%s", pd->name);
+ if (IS_ERR(pd->clsdev))
+ pd->clsdev = NULL;
+ }
+ if (pd->clsdev) {
+ pd->kobj_stat = pkt_kobj_create(pd, "stat",
+ &pd->clsdev->kobj,
+ &kobj_pkt_type_stat);
+ pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
+ &pd->clsdev->kobj,
+ &kobj_pkt_type_wqueue);
+ }
+}
+
+static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
+{
+ pkt_kobj_remove(pd->kobj_stat);
+ pkt_kobj_remove(pd->kobj_wqueue);
+ if (class_pktcdvd)
+ class_device_destroy(class_pktcdvd, pd->pkt_dev);
+}
+
+
+/********************************************************************
+ /sys/class/pktcdvd/
+ add map block device
+ remove unmap packet dev
+ device_map show mappings
+ *******************************************************************/
+
+static void class_pktcdvd_release(struct class *cls)
+{
+ kfree(cls);
+}
+static ssize_t class_pktcdvd_show_map(struct class *c, char *data)
+{
+ int n = 0;
+ int idx;
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+ for (idx = 0; idx < MAX_WRITERS; idx++) {
+ struct pktcdvd_device *pd = pkt_devs[idx];
+ if (!pd)
+ continue;
+ n += sprintf(data+n, "%s %u:%u %u:%u\n",
+ pd->name,
+ MAJOR(pd->pkt_dev), MINOR(pd->pkt_dev),
+ MAJOR(pd->bdev->bd_dev),
+ MINOR(pd->bdev->bd_dev));
+ }
+ mutex_unlock(&ctl_mutex);
+ return n;
+}
+
+static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
+ size_t count)
+{
+ unsigned int major, minor;
+ DECLARE_BUF_AS_STRING(dbuf, buf, count);
+ if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) {
+ pkt_setup_dev(MKDEV(major, minor), NULL);
+ return count;
+ }
+ return -EINVAL;
+}
+
+static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf,
+ size_t count)
+{
+ unsigned int major, minor;
+ DECLARE_BUF_AS_STRING(dbuf, buf, count);
+ if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) {
+ pkt_remove_dev(MKDEV(major, minor));
+ return count;
+ }
+ return -EINVAL;
+}
+
+static struct class_attribute class_pktcdvd_attrs[] = {
+ __ATTR(add, 0200, NULL, class_pktcdvd_store_add),
+ __ATTR(remove, 0200, NULL, class_pktcdvd_store_remove),
+ __ATTR(device_map, 0444, class_pktcdvd_show_map, NULL),
+ __ATTR_NULL
+};
+
+
+static int pkt_sysfs_init(void)
+{
+ int ret = 0;
+
+ /*
+ * create control files in sysfs
+ * /sys/class/pktcdvd/...
+ */
+ class_pktcdvd = kzalloc(sizeof(*class_pktcdvd), GFP_KERNEL);
+ if (!class_pktcdvd)
+ return -ENOMEM;
+ class_pktcdvd->name = DRIVER_NAME;
+ class_pktcdvd->owner = THIS_MODULE;
+ class_pktcdvd->class_release = class_pktcdvd_release;
+ class_pktcdvd->class_attrs = class_pktcdvd_attrs;
+ ret = class_register(class_pktcdvd);
+ if (ret) {
+ kfree(class_pktcdvd);
+ class_pktcdvd = NULL;
+ printk(DRIVER_NAME": failed to create class pktcdvd\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void pkt_sysfs_cleanup(void)
+{
+ if (class_pktcdvd)
+ class_destroy(class_pktcdvd);
+ class_pktcdvd = NULL;
+}
+
+/********************************************************************
+ entries in debugfs
+
+ /debugfs/pktcdvd[0-7]/
+ info
+
+ *******************************************************************/
+
+static int pkt_debugfs_seq_show(struct seq_file *m, void *p)
+{
+ return pkt_seq_show(m, p);
+}
+
+static int pkt_debugfs_fops_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pkt_debugfs_seq_show, inode->i_private);
+}
+
+static struct file_operations debug_fops = {
+ .open = pkt_debugfs_fops_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static void pkt_debugfs_dev_new(struct pktcdvd_device *pd)
+{
+ if (!pkt_debugfs_root)
+ return;
+ pd->dfs_f_info = NULL;
+ pd->dfs_d_root = debugfs_create_dir(pd->name, pkt_debugfs_root);
+ if (IS_ERR(pd->dfs_d_root)) {
+ pd->dfs_d_root = NULL;
+ return;
+ }
+ pd->dfs_f_info = debugfs_create_file("info", S_IRUGO,
+ pd->dfs_d_root, pd, &debug_fops);
+ if (IS_ERR(pd->dfs_f_info)) {
+ pd->dfs_f_info = NULL;
+ return;
+ }
+}
+
+static void pkt_debugfs_dev_remove(struct pktcdvd_device *pd)
+{
+ if (!pkt_debugfs_root)
+ return;
+ if (pd->dfs_f_info)
+ debugfs_remove(pd->dfs_f_info);
+ pd->dfs_f_info = NULL;
+ if (pd->dfs_d_root)
+ debugfs_remove(pd->dfs_d_root);
+ pd->dfs_d_root = NULL;
+}
+
+static void pkt_debugfs_init(void)
+{
+ pkt_debugfs_root = debugfs_create_dir(DRIVER_NAME, NULL);
+ if (IS_ERR(pkt_debugfs_root)) {
+ pkt_debugfs_root = NULL;
+ return;
+ }
+}
+
+static void pkt_debugfs_cleanup(void)
+{
+ if (!pkt_debugfs_root)
+ return;
+ debugfs_remove(pkt_debugfs_root);
+ pkt_debugfs_root = NULL;
+}
+
+/* ----------------------------------------------------------*/
+
static void pkt_bio_finished(struct pktcdvd_device *pd)
{
sector_t zone = 0; /* Suppress gcc warning */
struct pkt_rb_node *node, *first_node;
struct rb_node *n;
+ int wakeup;
VPRINTK("handle_queue\n");
pkt->write_size += bio->bi_size / CD_FRAMESIZE;
spin_unlock(&pkt->lock);
}
+ /* check write congestion marks, and if bio_queue_size is
+ below, wake up any waiters */
+ wakeup = (pd->write_congestion_on > 0
+ && pd->bio_queue_size <= pd->write_congestion_off);
spin_unlock(&pd->lock);
+ if (wakeup)
+ blk_clear_queue_congested(pd->disk->queue, WRITE);
pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
pkt_set_state(pkt, PACKET_WAITING_STATE);
}
spin_unlock(&pd->cdrw.active_list_lock);
+ /*
+ * Test if there is enough room left in the bio work queue
+ * (queue size >= congestion on mark).
+ * If not, wait till the work queue size is below the congestion off mark.
+ */
+ spin_lock(&pd->lock);
+ if (pd->write_congestion_on > 0
+ && pd->bio_queue_size >= pd->write_congestion_on) {
+ blk_set_queue_congested(q, WRITE);
+ do {
+ spin_unlock(&pd->lock);
+ congestion_wait(WRITE, HZ);
+ spin_lock(&pd->lock);
+ } while(pd->bio_queue_size > pd->write_congestion_off);
+ }
+ spin_unlock(&pd->lock);
+
/*
* No matching packet found. Store the bio in the work queue.
*/
seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
states[0], states[1], states[2], states[3], states[4], states[5]);
+ seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n",
+ pd->write_congestion_off,
+ pd->write_congestion_on);
return 0;
}
/*
* Set up mapping from pktcdvd device to CD-ROM device.
*/
-static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
+static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
{
int idx;
int ret = -ENOMEM;
struct pktcdvd_device *pd;
struct gendisk *disk;
- dev_t dev = new_decode_dev(ctrl_cmd->dev);
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
for (idx = 0; idx < MAX_WRITERS; idx++)
if (!pkt_devs[idx])
break;
if (idx == MAX_WRITERS) {
printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_mutex;
}
pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
if (!pd)
- return ret;
+ goto out_mutex;
pd->rb_pool = mempool_create_kmalloc_pool(PKT_RB_POOL_SIZE,
sizeof(struct pkt_rb_node));
if (!pd->rb_pool)
goto out_mem;
- disk = alloc_disk(1);
- if (!disk)
- goto out_mem;
- pd->disk = disk;
-
INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
spin_lock_init(&pd->cdrw.active_list_lock);
init_waitqueue_head(&pd->wqueue);
pd->bio_queue = RB_ROOT;
+ pd->write_congestion_on = write_congestion_on;
+ pd->write_congestion_off = write_congestion_off;
+
+ disk = alloc_disk(1);
+ if (!disk)
+ goto out_mem;
+ pd->disk = disk;
disk->major = pktdev_major;
disk->first_minor = idx;
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
+ strcpy(disk->disk_name, pd->name);
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
goto out_new_dev;
add_disk(disk);
+
+ pkt_sysfs_dev_new(pd);
+ pkt_debugfs_dev_new(pd);
+
pkt_devs[idx] = pd;
- ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
+ if (pkt_dev)
+ *pkt_dev = pd->pkt_dev;
+
+ mutex_unlock(&ctl_mutex);
return 0;
out_new_dev:
if (pd->rb_pool)
mempool_destroy(pd->rb_pool);
kfree(pd);
+out_mutex:
+ mutex_unlock(&ctl_mutex);
+ printk(DRIVER_NAME": setup of pktcdvd device failed\n");
return ret;
}
/*
* Tear down mapping from pktcdvd device to CD-ROM device.
*/
-static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
+static int pkt_remove_dev(dev_t pkt_dev)
{
struct pktcdvd_device *pd;
int idx;
- dev_t pkt_dev = new_decode_dev(ctrl_cmd->pkt_dev);
+ int ret = 0;
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
for (idx = 0; idx < MAX_WRITERS; idx++) {
pd = pkt_devs[idx];
}
if (idx == MAX_WRITERS) {
DPRINTK(DRIVER_NAME": dev not setup\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto out;
}
- if (pd->refcnt > 0)
- return -EBUSY;
-
+ if (pd->refcnt > 0) {
+ ret = -EBUSY;
+ goto out;
+ }
if (!IS_ERR(pd->cdrw.thread))
kthread_stop(pd->cdrw.thread);
+ pkt_devs[idx] = NULL;
+
+ pkt_debugfs_dev_remove(pd);
+ pkt_sysfs_dev_remove(pd);
+
blkdev_put(pd->bdev);
remove_proc_entry(pd->name, pkt_proc);
blk_cleanup_queue(pd->disk->queue);
put_disk(pd->disk);
- pkt_devs[idx] = NULL;
mempool_destroy(pd->rb_pool);
kfree(pd);
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
- return 0;
+
+out:
+ mutex_unlock(&ctl_mutex);
+ return ret;
}
static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd)
{
- struct pktcdvd_device *pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
+ struct pktcdvd_device *pd;
+
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+ pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index);
if (pd) {
ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev);
ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev);
ctrl_cmd->pkt_dev = 0;
}
ctrl_cmd->num_devices = MAX_WRITERS;
+
+ mutex_unlock(&ctl_mutex);
}
static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
void __user *argp = (void __user *)arg;
struct pkt_ctrl_command ctrl_cmd;
int ret = 0;
+ dev_t pkt_dev = 0;
if (cmd != PACKET_CTRL_CMD)
return -ENOTTY;
case PKT_CTRL_CMD_SETUP:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- ret = pkt_setup_dev(&ctrl_cmd);
- mutex_unlock(&ctl_mutex);
+ ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev);
+ ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev);
break;
case PKT_CTRL_CMD_TEARDOWN:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- ret = pkt_remove_dev(&ctrl_cmd);
- mutex_unlock(&ctl_mutex);
+ ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev));
break;
case PKT_CTRL_CMD_STATUS:
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
pkt_get_status(&ctrl_cmd);
- mutex_unlock(&ctl_mutex);
break;
default:
return -ENOTTY;
{
int ret;
+ mutex_init(&ctl_mutex);
+
psd_pool = mempool_create_kmalloc_pool(PSD_POOL_SIZE,
sizeof(struct packet_stacked_data));
if (!psd_pool)
if (!pktdev_major)
pktdev_major = ret;
+ ret = pkt_sysfs_init();
+ if (ret)
+ goto out;
+
+ pkt_debugfs_init();
+
ret = misc_register(&pkt_misc);
if (ret) {
printk(DRIVER_NAME": Unable to register misc device\n");
- goto out;
+ goto out_misc;
}
- mutex_init(&ctl_mutex);
-
pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
return 0;
+out_misc:
+ pkt_debugfs_cleanup();
+ pkt_sysfs_cleanup();
out:
unregister_blkdev(pktdev_major, DRIVER_NAME);
out2:
{
remove_proc_entry(DRIVER_NAME, proc_root_driver);
misc_deregister(&pkt_misc);
+
+ pkt_debugfs_cleanup();
+ pkt_sysfs_cleanup();
+
unregister_blkdev(pktdev_major, DRIVER_NAME);
mempool_destroy(psd_pool);
}
The module will be called mxser. If you want to do that, say M
here.
+config MOXA_SMARTIO_NEW
+ tristate "Moxa SmartIO support v. 2.0 (EXPERIMENTAL)"
+ depends on SERIAL_NONSTANDARD
+ help
+ Say Y here if you have a Moxa SmartIO multiport serial card and/or
+ want to help develop a new version of this driver.
+
+ This is upgraded (1.9.1) driver from original Moxa drivers with
+ changes finally resulting in PCI probing.
+
+ Use at your own risk.
+
+ This driver can also be built as a module. The module will be called
+ mxser_new. If you want to do that, say M here.
+
config ISI
tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
depends on SERIAL_NONSTANDARD
obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
+obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o
obj-$(CONFIG_COMPUTONE) += ip2/
obj-$(CONFIG_RISCOM8) += riscom8.o
obj-$(CONFIG_ISI) += isicom.o
static unsigned char current_ctl_bits;
-static void change_speed(struct async_struct *info, struct termios *old);
+static void change_speed(struct async_struct *info, struct ktermios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
* the specified baud rate for a serial port.
*/
static void change_speed(struct async_struct *info,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int quot = 0, baud_base, baud;
unsigned cflag, cval = 0;
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
static ssize_t cs5535_gpio_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
- u32 m = iminor(file->f_dentry->d_inode);
+ u32 m = iminor(file->f_path.dentry->d_inode);
int i, j;
u32 base = gpio_base + cs5535_lowhigh_base(m);
u32 m0, m1;
static ssize_t cs5535_gpio_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
- u32 m = iminor(file->f_dentry->d_inode);
+ u32 m = iminor(file->f_path.dentry->d_inode);
u32 base = gpio_base + cs5535_lowhigh_base(m);
int rd_bit = 1 << (m & 0x0f);
int i;
#undef BLOCKMOVE
#define Z_WAKE
#undef Z_EXT_CHARS_IN_BUFFER
-static char rcsid[] =
-"$Revision: 2.3.2.20 $$Date: 2004/02/25 18:14:16 $";
/*
* linux/drivers/char/cyclades.c
*
*/
+#define CY_VERSION "2.4"
+
/* If you need to install more boards than NR_CARDS, change the constant
in the definition below. No other change is necessary to support up to
eight boards. Beyond that you'll have to extend cy_isa_addresses. */
-#define NR_CARDS 4
+#define NR_CARDS 4
/*
If the total number of ports is larger than NR_PORTS, change this
constant in the definition below. No other change is necessary to
support more boards/ports. */
-#define NR_PORTS 256
+#define NR_PORTS 256
#define ZE_V1_NPORTS 64
#define ZO_V1 0
#undef CY_PCI_DEBUG
#if 0
-#define PAUSE __asm__("nop");
+#define PAUSE __asm__("nop")
#else
-#define PAUSE ;
+#define PAUSE do {} while (0)
#endif
/*
do { \
spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
} while (0)
-
+
#define CY_UNLOCK(info,flags) \
do { \
spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
#include <linux/stat.h>
#include <linux/proc_fs.h>
-static void cy_throttle (struct tty_struct *tty);
-static void cy_send_xchar (struct tty_struct *tty, char ch);
+static void cy_throttle(struct tty_struct *tty);
+static void cy_send_xchar(struct tty_struct *tty, char ch);
#define IS_CYC_Z(card) ((card).num_chips == -1)
#define Z_FPGA_CHECK(card) \
- ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
- ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
+ ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
+ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
#define STD_COM_FLAGS (0)
-#define JIFFIES_DIFF(n, j) ((j) - (n))
-
static struct tty_driver *cy_serial_driver;
#ifdef CONFIG_ISA
*/
static unsigned int cy_isa_addresses[] = {
- 0xD0000,
- 0xD2000,
- 0xD4000,
- 0xD6000,
- 0xD8000,
- 0xDA000,
- 0xDC000,
- 0xDE000,
- 0,0,0,0,0,0,0,0
+ 0xD0000,
+ 0xD2000,
+ 0xD4000,
+ 0xD6000,
+ 0xD8000,
+ 0xDA000,
+ 0xDC000,
+ 0xDE000,
+ 0, 0, 0, 0, 0, 0, 0, 0
};
+
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
#ifdef MODULE
static long maddr[NR_CARDS] = { 0, };
-static int irq[NR_CARDS] = { 0, };
+static int irq[NR_CARDS] = { 0, };
module_param_array(maddr, long, NULL, 0);
module_param_array(irq, int, NULL, 0);
#endif
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_ISA */
/* This is the per-card data structure containing address, irq, number of
channels, etc. This driver supports a maximum of NR_CARDS cards.
*/
static struct cyclades_port cy_port[NR_PORTS];
-static int cy_next_channel; /* next minor available */
+static int cy_next_channel; /* next minor available */
/*
* This is used to look up the divisor speeds and the timeouts
* 20
*/
static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
- 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
- 230400, 0};
-
-static char baud_co_25[] = { /* 25 MHz clock option table */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
- 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
- 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
-
-static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
- 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00};
-
-static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
- 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
- 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
- 0x21};
-
-static char baud_cor3[] = { /* receive threshold */
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
- 0x07};
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+ 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
+ 230400, 0
+};
+
+static char baud_co_25[] = { /* 25 MHz clock option table */
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
+ 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
+ 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
+};
+
+static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
+ 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+};
+
+static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
+ 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
+ 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
+ 0x21
+};
+
+static char baud_cor3[] = { /* receive threshold */
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
+ 0x07
+};
/*
* The Cyclades driver implements HW flow control as any serial driver.
* cables.
*/
-static char rflow_thr[] = { /* rflow threshold */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a};
+static char rflow_thr[] = { /* rflow threshold */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a
+};
/* The Cyclom-Ye has placed the sequential chips in non-sequential
* address order. This look-up table overcomes that problem.
*/
-static int cy_chip_offset [] =
- { 0x0000,
- 0x0400,
- 0x0800,
- 0x0C00,
- 0x0200,
- 0x0600,
- 0x0A00,
- 0x0E00
- };
+static int cy_chip_offset[] = { 0x0000,
+ 0x0400,
+ 0x0800,
+ 0x0C00,
+ 0x0200,
+ 0x0600,
+ 0x0A00,
+ 0x0E00
+};
/* PCI related definitions */
-static unsigned short cy_pci_nboard;
-static unsigned short cy_isa_nboard;
-static unsigned short cy_nboard;
+static unsigned short cy_pci_nboard;
+static unsigned short cy_isa_nboard;
+static unsigned short cy_nboard;
#ifdef CONFIG_PCI
-static unsigned short cy_pci_dev_id[] = {
- PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
- 0 /* end of table */
- };
+static unsigned short cy_pci_dev_id[] = {
+ PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
+ PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */
+ PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */
+ PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
+ 0 /* end of table */
+};
#endif
static void cy_start(struct tty_struct *);
static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_ISA */
-static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *);
+static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *);
#ifndef CONFIG_CYZ_INTR
static void cyz_poll(unsigned long);
static int cyz_timeron = 0;
static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
-#else /* CONFIG_CYZ_INTR */
+#else /* CONFIG_CYZ_INTR */
static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
-#endif /* CONFIG_CYZ_INTR */
+#endif /* CONFIG_CYZ_INTR */
-static inline int
-serial_paranoia_check(struct cyclades_port *info,
- char *name, const char *routine)
+static inline int serial_paranoia_check(struct cyclades_port *info,
+ char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "cyc Warning: bad magic number for serial struct (%s) in %s\n";
- static const char *badinfo =
- "cyc Warning: null cyclades_port for (%s) in %s\n";
- static const char *badrange =
- "cyc Warning: cyclades_port out of range for (%s) in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
-
- if( (long)info < (long)(&cy_port[0])
- || (long)(&cy_port[NR_PORTS]) < (long)info ){
- printk(badrange, name, routine);
- return 1;
- }
-
- if (info->magic != CYCLADES_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
+ if (!info) {
+ printk("cyc Warning: null cyclades_port for (%s) in %s\n",
+ name, routine);
+ return 1;
+ }
+
+ if ((long)info < (long)(&cy_port[0]) ||
+ (long)(&cy_port[NR_PORTS]) < (long)info) {
+ printk("cyc Warning: cyclades_port out of range for (%s) in "
+ "%s\n", name, routine);
+ return 1;
+ }
+
+ if (info->magic != CYCLADES_MAGIC) {
+ printk("cyc Warning: bad magic number for serial struct (%s) "
+ "in %s\n", name, routine);
+ return 1;
+ }
#endif
- return 0;
-} /* serial_paranoia_check */
+ return 0;
+} /* serial_paranoia_check */
/*
* This routine is used by the interrupt handler to schedule
* (also known as the "bottom half"). This can be called any
* number of times for any channel without harm.
*/
-static inline void
-cy_sched_event(struct cyclades_port *info, int event)
+static inline void cy_sched_event(struct cyclades_port *info, int event)
{
- info->event |= 1 << event; /* remember what kind of event and who */
- schedule_work(&info->tqueue);
-} /* cy_sched_event */
-
+ info->event |= 1 << event; /* remember what kind of event and who */
+ schedule_work(&info->tqueue);
+} /* cy_sched_event */
/*
* This routine is used to handle the "bottom half" processing for the
{
struct cyclades_port *info =
container_of(work, struct cyclades_port, tqueue);
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- }
- if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->open_wait);
- }
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ }
+ if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
+ wake_up_interruptible(&info->open_wait);
#ifdef CONFIG_CYZ_INTR
- if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
- if (cyz_rx_full_timer[info->line].function == NULL) {
- cyz_rx_full_timer[info->line].expires = jiffies + 1;
- cyz_rx_full_timer[info->line].function = cyz_rx_restart;
- cyz_rx_full_timer[info->line].data = (unsigned long)info;
- add_timer(&cyz_rx_full_timer[info->line]);
+ if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
+ if (cyz_rx_full_timer[info->line].function == NULL) {
+ cyz_rx_full_timer[info->line].expires = jiffies + 1;
+ cyz_rx_full_timer[info->line].function = cyz_rx_restart;
+ cyz_rx_full_timer[info->line].data =
+ (unsigned long)info;
+ add_timer(&cyz_rx_full_timer[info->line]);
+ }
}
- }
#endif
- if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->delta_msr_wait);
- }
- if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
- tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
+ if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
+ wake_up_interruptible(&info->delta_msr_wait);
+ tty_wakeup(tty);
#ifdef Z_WAKE
- if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->shutdown_wait);
- }
+ if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
+ wake_up_interruptible(&info->shutdown_wait);
#endif
} /* do_softint */
This function is only called from inside spinlock-protected code.
*/
-static int
-cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
+static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
{
- volatile int i;
+ volatile int i;
- /* Check to see that the previous command has completed */
- for(i = 0 ; i < 100 ; i++){
- if (cy_readb(base_addr+(CyCCR<<index)) == 0){
- break;
+ /* Check to see that the previous command has completed */
+ for (i = 0; i < 100; i++) {
+ if (cy_readb(base_addr + (CyCCR << index)) == 0) {
+ break;
+ }
+ udelay(10L);
}
- udelay(10L);
- }
- /* if the CCR never cleared, the previous command
- didn't finish within the "reasonable time" */
- if (i == 100) return (-1);
+ /* if the CCR never cleared, the previous command
+ didn't finish within the "reasonable time" */
+ if (i == 100)
+ return -1;
- /* Issue the new command */
- cy_writeb(base_addr+(CyCCR<<index), cmd);
+ /* Issue the new command */
+ cy_writeb(base_addr + (CyCCR << index), cmd);
- return(0);
-} /* cyy_issue_cmd */
+ return 0;
+} /* cyy_issue_cmd */
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
-static unsigned
-detect_isa_irq(void __iomem *address)
+static unsigned detect_isa_irq(void __iomem * address)
{
- int irq;
- unsigned long irqs, flags;
- int save_xir, save_car;
- int index = 0; /* IRQ probing is only for ISA */
-
- /* forget possible initially masked and pending IRQ */
- irq = probe_irq_off(probe_irq_on());
-
- /* Clear interrupts on the board first */
- cy_writeb(address + (Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
-
- irqs = probe_irq_on();
- /* Wait ... */
- udelay(5000L);
-
- /* Enable the Tx interrupts on the CD1400 */
- local_irq_save(flags);
- cy_writeb(address + (CyCAR<<index), 0);
- cyy_issue_cmd(address, CyCHAN_CTL|CyENB_XMTR, index);
-
- cy_writeb(address + (CyCAR<<index), 0);
- cy_writeb(address + (CySRER<<index),
- cy_readb(address + (CySRER<<index)) | CyTxRdy);
- local_irq_restore(flags);
-
- /* Wait ... */
- udelay(5000L);
-
- /* Check which interrupt is in use */
- irq = probe_irq_off(irqs);
-
- /* Clean up */
- save_xir = (u_char) cy_readb(address + (CyTIR<<index));
- save_car = cy_readb(address + (CyCAR<<index));
- cy_writeb(address + (CyCAR<<index), (save_xir & 0x3));
- cy_writeb(address + (CySRER<<index),
- cy_readb(address + (CySRER<<index)) & ~CyTxRdy);
- cy_writeb(address + (CyTIR<<index), (save_xir & 0x3f));
- cy_writeb(address + (CyCAR<<index), (save_car));
- cy_writeb(address + (Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
-
- return (irq > 0)? irq : 0;
+ int irq;
+ unsigned long irqs, flags;
+ int save_xir, save_car;
+ int index = 0; /* IRQ probing is only for ISA */
+
+ /* forget possible initially masked and pending IRQ */
+ irq = probe_irq_off(probe_irq_on());
+
+ /* Clear interrupts on the board first */
+ cy_writeb(address + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+
+ irqs = probe_irq_on();
+ /* Wait ... */
+ udelay(5000L);
+
+ /* Enable the Tx interrupts on the CD1400 */
+ local_irq_save(flags);
+ cy_writeb(address + (CyCAR << index), 0);
+ cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
+
+ cy_writeb(address + (CyCAR << index), 0);
+ cy_writeb(address + (CySRER << index),
+ cy_readb(address + (CySRER << index)) | CyTxRdy);
+ local_irq_restore(flags);
+
+ /* Wait ... */
+ udelay(5000L);
+
+ /* Check which interrupt is in use */
+ irq = probe_irq_off(irqs);
+
+ /* Clean up */
+ save_xir = (u_char) cy_readb(address + (CyTIR << index));
+ save_car = cy_readb(address + (CyCAR << index));
+ cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
+ cy_writeb(address + (CySRER << index),
+ cy_readb(address + (CySRER << index)) & ~CyTxRdy);
+ cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
+ cy_writeb(address + (CyCAR << index), (save_car));
+ cy_writeb(address + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+
+ return (irq > 0) ? irq : 0;
}
-#endif /* CONFIG_ISA */
+#endif /* CONFIG_ISA */
-/* The real interrupt service routine is called
- whenever the card wants its hand held--chars
- received, out buffer empty, modem change, etc.
- */
-static irqreturn_t
-cyy_interrupt(int irq, void *dev_id)
+static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
+ void __iomem * base_addr, int status, int index)
{
- struct tty_struct *tty;
- int status;
- struct cyclades_card *cinfo;
- struct cyclades_port *info;
- void __iomem *base_addr, *card_base_addr;
- int chip;
- int save_xir, channel, save_car;
- char data;
- volatile int char_count;
- int outch;
- int i,j,index;
- int too_many;
- int had_work;
- int mdm_change;
- int mdm_status;
- int len;
- if((cinfo = (struct cyclades_card *)dev_id) == 0){
-#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
-#endif
- return IRQ_NONE; /* spurious interrupt */
- }
-
- card_base_addr = cinfo->base_addr;
- index = cinfo->bus_index;
-
-
- /* This loop checks all chips in the card. Make a note whenever
- _any_ chip had some work to do, as this is considered an
- indication that there will be more to do. Only when no chip
- has any work does this outermost loop exit.
- */
- do{
- had_work = 0;
- for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) {
- base_addr = cinfo->base_addr + (cy_chip_offset[chip]<<index);
- too_many = 0;
- while ( (status = cy_readb(base_addr+(CySVRR<<index))) != 0x00) {
- had_work++;
- /* The purpose of the following test is to ensure that
- no chip can monopolize the driver. This forces the
- chips to be checked in a round-robin fashion (after
- draining each of a bunch (1000) of characters).
- */
- if(1000<too_many++){
- break;
- }
- if (status & CySRReceive) { /* reception interrupt */
+ struct cyclades_port *info;
+ struct tty_struct *tty;
+ volatile int char_count;
+ int i, j, len, mdm_change, mdm_status, outch;
+ int save_xir, channel, save_car;
+ char data;
+
+ if (status & CySRReceive) { /* reception interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
+ printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
#endif
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
- channel = (u_short ) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- info = &cy_port[i];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr+(CyCAR<<index));
- cy_writeb(base_addr+(CyCAR<<index), save_xir);
-
- /* if there is nowhere to put the data, discard it */
- if(info->tty == 0){
- j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
- if ( j == CyIVRRxEx ) { /* exception */
- data = cy_readb(base_addr+(CyRDSR<<index));
- } else { /* normal character reception */
- char_count = cy_readb(base_addr+(CyRDCR<<index));
- while(char_count--){
- data = cy_readb(base_addr+(CyRDSR<<index));
- }
- }
- }else{ /* there is an open port for this data */
- tty = info->tty;
- j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
- if ( j == CyIVRRxEx ) { /* exception */
- data = cy_readb(base_addr+(CyRDSR<<index));
-
- /* For statistics only */
- if (data & CyBREAK)
- info->icount.brk++;
- else if(data & CyFRAME)
- info->icount.frame++;
- else if(data & CyPARITY)
- info->icount.parity++;
- else if(data & CyOVERRUN)
- info->icount.overrun++;
-
- if(data & info->ignore_status_mask){
- info->icount.rx++;
- continue;
- }
- if (tty_buffer_request_room(tty, 1)) {
- if (data & info->read_status_mask){
- if(data & CyBREAK){
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK);
- info->icount.rx++;
- if (info->flags & ASYNC_SAK){
- do_SAK(tty);
- }
- }else if(data & CyFRAME){
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME);
- info->icount.rx++;
- info->idle_stats.frame_errs++;
- }else if(data & CyPARITY){
- /* Pieces of seven... */
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY);
- info->icount.rx++;
- info->idle_stats.parity_errs++;
- }else if(data & CyOVERRUN){
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ /* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
+ save_xir = (u_char) cy_readb(base_addr + (CyRIR << index));
+ channel = (u_short) (save_xir & CyIRChannel);
+ i = channel + chip * 4 + cinfo->first_line;
+ info = &cy_port[i];
+ info->last_active = jiffies;
+ save_car = cy_readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ /* if there is nowhere to put the data, discard it */
+ if (info->tty == 0) {
+ j = (cy_readb(base_addr + (CyRIVR << index)) &
+ CyIVRMask);
+ if (j == CyIVRRxEx) { /* exception */
+ data = cy_readb(base_addr + (CyRDSR << index));
+ } else { /* normal character reception */
+ char_count = cy_readb(base_addr +
+ (CyRDCR << index));
+ while (char_count--) {
+ data = cy_readb(base_addr +
+ (CyRDSR << index));
+ }
+ }
+ } else { /* there is an open port for this data */
+ tty = info->tty;
+ j = (cy_readb(base_addr + (CyRIVR << index)) &
+ CyIVRMask);
+ if (j == CyIVRRxEx) { /* exception */
+ data = cy_readb(base_addr + (CyRDSR << index));
+
+ /* For statistics only */
+ if (data & CyBREAK)
+ info->icount.brk++;
+ else if (data & CyFRAME)
+ info->icount.frame++;
+ else if (data & CyPARITY)
+ info->icount.parity++;
+ else if (data & CyOVERRUN)
+ info->icount.overrun++;
+
+ if (data & info->ignore_status_mask) {
info->icount.rx++;
- /* If the flip buffer itself is
- overflowing, we still lose
- the next incoming character.
- */
- tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME);
- info->icount.rx++;
+ return;
+ }
+ if (tty_buffer_request_room(tty, 1)) {
+ if (data & info->read_status_mask) {
+ if (data & CyBREAK) {
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_BREAK);
+ info->icount.rx++;
+ if (info->flags &
+ ASYNC_SAK) {
+ do_SAK(tty);
+ }
+ } else if (data & CyFRAME) {
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_FRAME);
+ info->icount.rx++;
+ info->idle_stats.
+ frame_errs++;
+ } else if (data & CyPARITY) {
+ /* Pieces of seven... */
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_PARITY);
+ info->icount.rx++;
+ info->idle_stats.
+ parity_errs++;
+ } else if (data & CyOVERRUN) {
+ tty_insert_flip_char(
+ tty, 0,
+ TTY_OVERRUN);
+ info->icount.rx++;
+ /* If the flip buffer itself is
+ overflowing, we still lose
+ the next incoming character.
+ */
+ tty_insert_flip_char(
+ tty,
+ cy_readb(
+ base_addr +
+ (CyRDSR <<
+ index)),
+ TTY_FRAME);
+ info->icount.rx++;
+ info->idle_stats.
+ overruns++;
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* }else if(data & CyTIMEOUT){ */
+ /* }else if(data & CySPECHAR){ */
+ } else {
+ tty_insert_flip_char(
+ tty, 0,
+ TTY_NORMAL);
+ info->icount.rx++;
+ }
+ } else {
+ tty_insert_flip_char(tty, 0,
+ TTY_NORMAL);
+ info->icount.rx++;
+ }
+ } else {
+ /* there was a software buffer
+ overrun and nothing could be
+ done about it!!! */
+ info->icount.buf_overrun++;
info->idle_stats.overruns++;
- /* These two conditions may imply */
- /* a normal read should be done. */
- /* }else if(data & CyTIMEOUT){ */
- /* }else if(data & CySPECHAR){ */
- }else {
- tty_insert_flip_char(tty, 0, TTY_NORMAL);
- info->icount.rx++;
- }
- }else{
- tty_insert_flip_char(tty, 0, TTY_NORMAL);
- info->icount.rx++;
- }
- }else{
- /* there was a software buffer
- overrun and nothing could be
- done about it!!! */
- info->icount.buf_overrun++;
- info->idle_stats.overruns++;
- }
- } else { /* normal character reception */
- /* load # chars available from the chip */
- char_count = cy_readb(base_addr+(CyRDCR<<index));
+ }
+ } else { /* normal character reception */
+ /* load # chars available from the chip */
+ char_count = cy_readb(base_addr +
+ (CyRDCR << index));
#ifdef CY_ENABLE_MONITORING
- ++info->mon.int_count;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ ++info->mon.int_count;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
- len = tty_buffer_request_room(tty, char_count);
- while(len--){
- data = cy_readb(base_addr+(CyRDSR<<index));
- tty_insert_flip_char(tty, data, TTY_NORMAL);
- info->idle_stats.recv_bytes++;
- info->icount.rx++;
+ len = tty_buffer_request_room(tty, char_count);
+ while (len--) {
+ data = cy_readb(base_addr +
+ (CyRDSR << index));
+ tty_insert_flip_char(tty, data,
+ TTY_NORMAL);
+ info->idle_stats.recv_bytes++;
+ info->icount.rx++;
#ifdef CY_16Y_HACK
- udelay(10L);
+ udelay(10L);
#endif
- }
- info->idle_stats.recv_idle = jiffies;
- }
+ }
+ info->idle_stats.recv_idle = jiffies;
+ }
tty_schedule_flip(tty);
- }
- /* end of service */
- cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f));
- cy_writeb(base_addr+(CyCAR<<index), (save_car));
- spin_unlock(&cinfo->card_lock);
- }
-
-
- if (status & CySRTransmit) { /* transmission interrupt */
- /* Since we only get here when the transmit buffer
- is empty, we know we can always stuff a dozen
- characters. */
+ }
+ /* end of service */
+ cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f));
+ cy_writeb(base_addr + (CyCAR << index), (save_car));
+ spin_unlock(&cinfo->card_lock);
+ }
+
+ if (status & CySRTransmit) { /* transmission interrupt */
+ /* Since we only get here when the transmit buffer
+ is empty, we know we can always stuff a dozen
+ characters. */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
+ printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
#endif
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index));
- channel = (u_short ) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- save_car = cy_readb(base_addr+(CyCAR<<index));
- cy_writeb(base_addr+(CyCAR<<index), save_xir);
-
- /* validate the port# (as configured and open) */
- if( (i < 0) || (NR_PORTS <= i) ){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy);
- goto txend;
- }
- info = &cy_port[i];
- info->last_active = jiffies;
- if(info->tty == 0){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy);
- goto txdone;
- }
-
- /* load the on-chip space for outbound data */
- char_count = info->xmit_fifo_size;
-
- if(info->x_char) { /* send special char */
- outch = info->x_char;
- cy_writeb(base_addr+(CyTDR<<index), outch);
- char_count--;
+ /* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
+ save_xir = (u_char) cy_readb(base_addr + (CyTIR << index));
+ channel = (u_short) (save_xir & CyIRChannel);
+ i = channel + chip * 4 + cinfo->first_line;
+ save_car = cy_readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ /* validate the port# (as configured and open) */
+ if ((i < 0) || (NR_PORTS <= i)) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) &
+ ~CyTxRdy);
+ goto txend;
+ }
+ info = &cy_port[i];
+ info->last_active = jiffies;
+ if (info->tty == 0) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) &
+ ~CyTxRdy);
+ goto txdone;
+ }
+
+ /* load the on-chip space for outbound data */
+ char_count = info->xmit_fifo_size;
+
+ if (info->x_char) { /* send special char */
+ outch = info->x_char;
+ cy_writeb(base_addr + (CyTDR << index), outch);
+ char_count--;
info->icount.tx++;
- info->x_char = 0;
- }
+ info->x_char = 0;
+ }
- if (info->breakon || info->breakoff) {
+ if (info->breakon || info->breakoff) {
if (info->breakon) {
- cy_writeb(base_addr + (CyTDR<<index), 0);
- cy_writeb(base_addr + (CyTDR<<index), 0x81);
- info->breakon = 0;
- char_count -= 2;
+ cy_writeb(base_addr + (CyTDR << index), 0);
+ cy_writeb(base_addr + (CyTDR << index), 0x81);
+ info->breakon = 0;
+ char_count -= 2;
}
if (info->breakoff) {
- cy_writeb(base_addr + (CyTDR<<index), 0);
- cy_writeb(base_addr + (CyTDR<<index), 0x83);
- info->breakoff = 0;
- char_count -= 2;
+ cy_writeb(base_addr + (CyTDR << index), 0);
+ cy_writeb(base_addr + (CyTDR << index), 0x83);
+ info->breakoff = 0;
+ char_count -= 2;
}
- }
-
- while (char_count-- > 0){
- if (!info->xmit_cnt){
- if (cy_readb(base_addr+(CySRER<<index))&CyTxMpty) {
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
- ~CyTxMpty);
- } else {
- cy_writeb(base_addr+(CySRER<<index),
- ((cy_readb(base_addr+(CySRER<<index))
- & ~CyTxRdy)
- | CyTxMpty));
- }
- goto txdone;
+ }
+
+ while (char_count-- > 0) {
+ if (!info->xmit_cnt) {
+ if (cy_readb(base_addr + (CySRER << index)) &
+ CyTxMpty) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER << index)) &
+ ~CyTxMpty);
+ } else {
+ cy_writeb(base_addr + (CySRER << index),
+ (cy_readb(base_addr +
+ (CySRER << index)) &
+ ~CyTxRdy) | CyTxMpty);
+ }
+ goto txdone;
}
- if (info->xmit_buf == 0){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
+ if (info->xmit_buf == 0) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index))&
~CyTxRdy);
- goto txdone;
+ goto txdone;
}
- if (info->tty->stopped || info->tty->hw_stopped){
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
+ if (info->tty->stopped || info->tty->hw_stopped) {
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index))&
~CyTxRdy);
- goto txdone;
+ goto txdone;
}
- /* Because the Embedded Transmit Commands have
- been enabled, we must check to see if the
+ /* Because the Embedded Transmit Commands have
+ been enabled, we must check to see if the
escape character, NULL, is being sent. If it
is, we must ensure that there is room for it
to be doubled in the output stream. Therefore
after the check for a NULL output character.
This is necessary because there may not be
room for the two chars needed to send a NULL.)
- */
- outch = info->xmit_buf[info->xmit_tail];
- if( outch ){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr+(CyTDR<<index), outch);
- info->icount.tx++;
- }else{
- if(char_count > 1){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr+(CyTDR<<index),
- outch);
- cy_writeb(base_addr+(CyTDR<<index), 0);
+ */
+ outch = info->xmit_buf[info->xmit_tail];
+ if (outch) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) &
+ (SERIAL_XMIT_SIZE - 1);
+ cy_writeb(base_addr + (CyTDR << index), outch);
info->icount.tx++;
- char_count--;
- }else{
- }
- }
- }
-
- txdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
- txend:
- /* end of service */
- cy_writeb(base_addr+(CyTIR<<index),
- (save_xir & 0x3f));
- cy_writeb(base_addr+(CyCAR<<index), (save_car));
- spin_unlock(&cinfo->card_lock);
- }
-
- if (status & CySRModem) { /* modem interrupt */
-
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index));
- channel = (u_short ) (save_xir & CyIRChannel);
- info = &cy_port[channel + chip * 4
- + cinfo->first_line];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr+(CyCAR<<index));
- cy_writeb(base_addr+(CyCAR<<index), save_xir);
-
- mdm_change = cy_readb(base_addr+(CyMISR<<index));
- mdm_status = cy_readb(base_addr+(CyMSVR1<<index));
-
- if(info->tty == 0){/* no place for data, ignore it*/
- ;
- }else{
+ } else {
+ if (char_count > 1) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)&
+ (SERIAL_XMIT_SIZE - 1);
+ cy_writeb(base_addr + (CyTDR << index),
+ outch);
+ cy_writeb(base_addr + (CyTDR << index),
+ 0);
+ info->icount.tx++;
+ char_count--;
+ } else {
+ }
+ }
+ }
+
+txdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+txend:
+ /* end of service */
+ cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
+ cy_writeb(base_addr + (CyCAR << index), (save_car));
+ spin_unlock(&cinfo->card_lock);
+ }
+
+ if (status & CySRModem) { /* modem interrupt */
+
+ /* determine the channel & change to that context */
+ spin_lock(&cinfo->card_lock);
+ save_xir = (u_char) cy_readb(base_addr + (CyMIR << index));
+ channel = (u_short) (save_xir & CyIRChannel);
+ info = &cy_port[channel + chip * 4 + cinfo->first_line];
+ info->last_active = jiffies;
+ save_car = cy_readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ mdm_change = cy_readb(base_addr + (CyMISR << index));
+ mdm_status = cy_readb(base_addr + (CyMSVR1 << index));
+
+ if (info->tty == 0) { /* no place for data, ignore it */
+ ;
+ } else {
if (mdm_change & CyANY_DELTA) {
- /* For statistics only */
- if (mdm_change & CyDCD) info->icount.dcd++;
- if (mdm_change & CyCTS) info->icount.cts++;
- if (mdm_change & CyDSR) info->icount.dsr++;
- if (mdm_change & CyRI) info->icount.rng++;
+ /* For statistics only */
+ if (mdm_change & CyDCD)
+ info->icount.dcd++;
+ if (mdm_change & CyCTS)
+ info->icount.cts++;
+ if (mdm_change & CyDSR)
+ info->icount.dsr++;
+ if (mdm_change & CyRI)
+ info->icount.rng++;
+
+ cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ }
+
+ if ((mdm_change & CyDCD) &&
+ (info->flags & ASYNC_CHECK_CD)) {
+ if (mdm_status & CyDCD) {
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ } else {
+ cy_sched_event(info, Cy_EVENT_HANGUP);
+ }
+ }
+ if ((mdm_change & CyCTS) &&
+ (info->flags & ASYNC_CTS_FLOW)) {
+ if (info->tty->hw_stopped) {
+ if (mdm_status & CyCTS) {
+ /* cy_start isn't used
+ because... !!! */
+ info->tty->hw_stopped = 0;
+ cy_writeb(base_addr +
+ (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER <<
+ index))|
+ CyTxRdy);
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
+ }
+ } else {
+ if (!(mdm_status & CyCTS)) {
+ /* cy_stop isn't used
+ because ... !!! */
+ info->tty->hw_stopped = 1;
+ cy_writeb(base_addr +
+ (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER <<
+ index)) &
+ ~CyTxRdy);
+ }
+ }
+ }
+ if (mdm_change & CyDSR) {
+ }
+ if (mdm_change & CyRI) {
+ }
+ }
+ /* end of service */
+ cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
+ cy_writeb(base_addr + (CyCAR << index), save_car);
+ spin_unlock(&cinfo->card_lock);
+ }
+}
- cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+/* The real interrupt service routine is called
+ whenever the card wants its hand held--chars
+ received, out buffer empty, modem change, etc.
+ */
+static irqreturn_t cyy_interrupt(int irq, void *dev_id)
+{
+ int status;
+ struct cyclades_card *cinfo;
+ void __iomem *base_addr, *card_base_addr;
+ int chip;
+ int index;
+ int too_many;
+ int had_work;
+
+ if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+#ifdef CY_DEBUG_INTERRUPTS
+ printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
+#endif
+ return IRQ_NONE; /* spurious interrupt */
+ }
+
+ card_base_addr = cinfo->base_addr;
+ index = cinfo->bus_index;
+
+ /* This loop checks all chips in the card. Make a note whenever
+ _any_ chip had some work to do, as this is considered an
+ indication that there will be more to do. Only when no chip
+ has any work does this outermost loop exit.
+ */
+ do {
+ had_work = 0;
+ for (chip = 0; chip < cinfo->num_chips; chip++) {
+ base_addr = cinfo->base_addr +
+ (cy_chip_offset[chip] << index);
+ too_many = 0;
+ while ((status = cy_readb(base_addr +
+ (CySVRR << index))) != 0x00) {
+ had_work++;
+ /* The purpose of the following test is to ensure that
+ no chip can monopolize the driver. This forces the
+ chips to be checked in a round-robin fashion (after
+ draining each of a bunch (1000) of characters).
+ */
+ if (1000 < too_many++) {
+ break;
+ }
+ cyy_intr_chip(cinfo, chip, base_addr, status,
+ index);
}
+ }
+ } while (had_work);
- if((mdm_change & CyDCD)
- && (info->flags & ASYNC_CHECK_CD)){
- if(mdm_status & CyDCD){
- cy_sched_event(info,
- Cy_EVENT_OPEN_WAKEUP);
- }else{
- cy_sched_event(info,
- Cy_EVENT_HANGUP);
- }
- }
- if((mdm_change & CyCTS)
- && (info->flags & ASYNC_CTS_FLOW)){
- if(info->tty->hw_stopped){
- if(mdm_status & CyCTS){
- /* cy_start isn't used
- because... !!! */
- info->tty->hw_stopped = 0;
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) |
- CyTxRdy);
- cy_sched_event(info,
- Cy_EVENT_WRITE_WAKEUP);
- }
- }else{
- if(!(mdm_status & CyCTS)){
- /* cy_stop isn't used
- because ... !!! */
- info->tty->hw_stopped = 1;
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) &
- ~CyTxRdy);
- }
- }
- }
- if(mdm_change & CyDSR){
- }
- if(mdm_change & CyRI){
- }
- }
- /* end of service */
- cy_writeb(base_addr+(CyMIR<<index),
- (save_xir & 0x3f));
- cy_writeb(base_addr+(CyCAR<<index), save_car);
- spin_unlock(&cinfo->card_lock);
- }
- } /* end while status != 0 */
- } /* end loop for chips... */
- } while(had_work);
-
- /* clear interrupts */
- spin_lock(&cinfo->card_lock);
- cy_writeb(card_base_addr + (Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
- spin_unlock(&cinfo->card_lock);
- return IRQ_HANDLED;
-} /* cyy_interrupt */
+ /* clear interrupts */
+ spin_lock(&cinfo->card_lock);
+ cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+ spin_unlock(&cinfo->card_lock);
+ return IRQ_HANDLED;
+} /* cyy_interrupt */
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
/***********************************************************/
static int
-cyz_fetch_msg( struct cyclades_card *cinfo,
- uclong *channel, ucchar *cmd, uclong *param)
+cyz_fetch_msg(struct cyclades_card *cinfo,
+ uclong * channel, ucchar * cmd, uclong * param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- unsigned long loc_doorbell;
-
- firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)){
- return (-1);
- }
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
- loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
- (cinfo->ctl_addr))->loc_doorbell);
- if (loc_doorbell){
- *cmd = (char)(0xff & loc_doorbell);
- *channel = cy_readl(&board_ctrl->fwcmd_channel);
- *param = (uclong)cy_readl(&board_ctrl->fwcmd_param);
- cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->loc_doorbell,
- 0xffffffff);
- return 1;
- }
- return 0;
-} /* cyz_fetch_msg */
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ unsigned long loc_doorbell;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*cinfo)) {
+ return -1;
+ }
+ zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
+ (cinfo->ctl_addr))->loc_doorbell);
+ if (loc_doorbell) {
+ *cmd = (char)(0xff & loc_doorbell);
+ *channel = cy_readl(&board_ctrl->fwcmd_channel);
+ *param = (uclong) cy_readl(&board_ctrl->fwcmd_param);
+ cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+ loc_doorbell, 0xffffffff);
+ return 1;
+ }
+ return 0;
+} /* cyz_fetch_msg */
static int
-cyz_issue_cmd( struct cyclades_card *cinfo,
- uclong channel, ucchar cmd, uclong param)
+cyz_issue_cmd(struct cyclades_card *cinfo,
+ uclong channel, ucchar cmd, uclong param)
{
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- unsigned long __iomem *pci_doorbell;
- int index;
-
- firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)){
- return (-1);
- }
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
-
- index = 0;
- pci_doorbell = &((struct RUNTIME_9060 __iomem *) (cinfo->ctl_addr))->pci_doorbell;
- while( (cy_readl(pci_doorbell) & 0xff) != 0){
- if (index++ == 1000){
- return((int)(cy_readl(pci_doorbell) & 0xff));
- }
- udelay(50L);
- }
- cy_writel(&board_ctrl->hcmd_channel, channel);
- cy_writel(&board_ctrl->hcmd_param , param);
- cy_writel(pci_doorbell, (long)cmd);
-
- return(0);
-} /* cyz_issue_cmd */
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ unsigned long __iomem *pci_doorbell;
+ int index;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*cinfo)) {
+ return -1;
+ }
+ zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ index = 0;
+ pci_doorbell =
+ &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
+ while ((cy_readl(pci_doorbell) & 0xff) != 0) {
+ if (index++ == 1000) {
+ return (int)(cy_readl(pci_doorbell) & 0xff);
+ }
+ udelay(50L);
+ }
+ cy_writel(&board_ctrl->hcmd_channel, channel);
+ cy_writel(&board_ctrl->hcmd_param, param);
+ cy_writel(pci_doorbell, (long)cmd);
+
+ return 0;
+} /* cyz_issue_cmd */
static void
cyz_handle_rx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem *ch_ctrl,
- volatile struct BUF_CTRL __iomem *buf_ctrl)
+ volatile struct CH_CTRL __iomem * ch_ctrl,
+ volatile struct BUF_CTRL __iomem * buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
- struct tty_struct *tty = info->tty;
- volatile int char_count;
- int len;
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct tty_struct *tty = info->tty;
+ volatile int char_count;
+ int len;
#ifdef BLOCKMOVE
- int small_count;
+ int small_count;
#else
- char data;
+ char data;
#endif
- volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
+ volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
- rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
- rx_put = cy_readl(&buf_ctrl->rx_put);
- rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
- rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
- if (rx_put >= rx_get)
- char_count = rx_put - rx_get;
- else
- char_count = rx_put - rx_get + rx_bufsize;
+ rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
+ rx_put = cy_readl(&buf_ctrl->rx_put);
+ rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
+ rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
+ if (rx_put >= rx_get)
+ char_count = rx_put - rx_get;
+ else
+ char_count = rx_put - rx_get + rx_bufsize;
- if ( char_count ) {
- info->last_active = jiffies;
- info->jiffies[1] = jiffies;
+ if (char_count) {
+ info->last_active = jiffies;
+ info->jiffies[1] = jiffies;
#ifdef CY_ENABLE_MONITORING
- info->mon.int_count++;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ info->mon.int_count++;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
- if(tty == 0){
- /* flush received characters */
- new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1);
- info->rflush_count++;
- }else{
+ if (tty == 0) {
+ /* flush received characters */
+ new_rx_get = (new_rx_get + char_count) &
+ (rx_bufsize - 1);
+ info->rflush_count++;
+ } else {
#ifdef BLOCKMOVE
- /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
- for performance, but because of buffer boundaries, there
- may be several steps to the operation */
- while(0 < (small_count =
- min_t(unsigned int, (rx_bufsize - new_rx_get),
- min_t(unsigned int, (TTY_FLIPBUF_SIZE - tty->flip.count), char_count))
- )) {
- memcpy_fromio(tty->flip.char_buf_ptr,
- (char *)(cinfo->base_addr
- + rx_bufaddr + new_rx_get),
- small_count);
-
- tty->flip.char_buf_ptr += small_count;
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL, small_count);
- tty->flip.flag_buf_ptr += small_count;
- new_rx_get = (new_rx_get + small_count) & (rx_bufsize - 1);
- char_count -= small_count;
- info->icount.rx += small_count;
- info->idle_stats.recv_bytes += small_count;
- tty->flip.count += small_count;
- }
+ /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+ for performance, but because of buffer boundaries, there
+ may be several steps to the operation */
+ while (0 < (small_count = min_t(unsigned int,
+ rx_bufsize - new_rx_get,
+ min_t(unsigned int, TTY_FLIPBUF_SIZE -
+ tty->flip.count, char_count)))){
+ memcpy_fromio(tty->flip.char_buf_ptr,
+ (char *)(cinfo->base_addr + rx_bufaddr +
+ new_rx_get),
+ small_count);
+
+ tty->flip.char_buf_ptr += small_count;
+ memset(tty->flip.flag_buf_ptr, TTY_NORMAL,
+ small_count);
+ tty->flip.flag_buf_ptr += small_count;
+ new_rx_get = (new_rx_get + small_count) &
+ (rx_bufsize - 1);
+ char_count -= small_count;
+ info->icount.rx += small_count;
+ info->idle_stats.recv_bytes += small_count;
+ tty->flip.count += small_count;
+ }
#else
- len = tty_buffer_request_room(tty, char_count);
- while(len--){
- data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get);
- new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1);
- tty_insert_flip_char(tty, data, TTY_NORMAL);
- info->idle_stats.recv_bytes++;
- info->icount.rx++;
- }
+ len = tty_buffer_request_room(tty, char_count);
+ while (len--) {
+ data = cy_readb(cinfo->base_addr + rx_bufaddr +
+ new_rx_get);
+ new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ info->idle_stats.recv_bytes++;
+ info->icount.rx++;
+ }
#endif
#ifdef CONFIG_CYZ_INTR
- /* Recalculate the number of chars in the RX buffer and issue
- a cmd in case it's higher than the RX high water mark */
- rx_put = cy_readl(&buf_ctrl->rx_put);
- if (rx_put >= rx_get)
- char_count = rx_put - rx_get;
- else
- char_count = rx_put - rx_get + rx_bufsize;
- if(char_count >= cy_readl(&buf_ctrl->rx_threshold)) {
- cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
- }
+ /* Recalculate the number of chars in the RX buffer and issue
+ a cmd in case it's higher than the RX high water mark */
+ rx_put = cy_readl(&buf_ctrl->rx_put);
+ if (rx_put >= rx_get)
+ char_count = rx_put - rx_get;
+ else
+ char_count = rx_put - rx_get + rx_bufsize;
+ if (char_count >= (int)cy_readl(&buf_ctrl->
+ rx_threshold)) {
+ cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
+ }
#endif
- info->idle_stats.recv_idle = jiffies;
- tty_schedule_flip(tty);
+ info->idle_stats.recv_idle = jiffies;
+ tty_schedule_flip(tty);
+ }
+ /* Update rx_get */
+ cy_writel(&buf_ctrl->rx_get, new_rx_get);
}
- /* Update rx_get */
- cy_writel(&buf_ctrl->rx_get, new_rx_get);
- }
}
static void
cyz_handle_tx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem *ch_ctrl,
- volatile struct BUF_CTRL __iomem *buf_ctrl)
+ volatile struct CH_CTRL __iomem * ch_ctrl,
+ volatile struct BUF_CTRL __iomem * buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
- struct tty_struct *tty = info->tty;
- char data;
- volatile int char_count;
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct tty_struct *tty = info->tty;
+ char data;
+ volatile int char_count;
#ifdef BLOCKMOVE
- int small_count;
+ int small_count;
#endif
- volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
+ volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
- if (info->xmit_cnt <= 0) /* Nothing to transmit */
- return;
+ if (info->xmit_cnt <= 0) /* Nothing to transmit */
+ return;
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
- if (tx_put >= tx_get)
- char_count = tx_get - tx_put - 1 + tx_bufsize;
- else
- char_count = tx_get - tx_put - 1;
+ tx_get = cy_readl(&buf_ctrl->tx_get);
+ tx_put = cy_readl(&buf_ctrl->tx_put);
+ tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
+ if (tx_put >= tx_get)
+ char_count = tx_get - tx_put - 1 + tx_bufsize;
+ else
+ char_count = tx_get - tx_put - 1;
- if ( char_count ) {
+ if (char_count) {
- if( tty == 0 ){
- goto ztxdone;
- }
+ if (tty == 0) {
+ goto ztxdone;
+ }
- if(info->x_char) { /* send special char */
- data = info->x_char;
+ if (info->x_char) { /* send special char */
+ data = info->x_char;
- cy_writeb((cinfo->base_addr + tx_bufaddr + tx_put), data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- info->x_char = 0;
- char_count--;
- info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
+ cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
+ tx_put = (tx_put + 1) & (tx_bufsize - 1);
+ info->x_char = 0;
+ char_count--;
+ info->icount.tx++;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#ifdef BLOCKMOVE
- while(0 < (small_count =
- min_t(unsigned int, (tx_bufsize - tx_put),
- min_t(unsigned int, (SERIAL_XMIT_SIZE - info->xmit_tail),
- min_t(unsigned int, info->xmit_cnt, char_count))))) {
-
- memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
- &info->xmit_buf[info->xmit_tail],
- small_count);
-
- tx_put = (tx_put + small_count) & (tx_bufsize - 1);
- char_count -= small_count;
- info->icount.tx += small_count;
- info->xmit_cnt -= small_count;
- info->xmit_tail =
- (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
+ while (0 < (small_count = min_t(unsigned int,
+ tx_bufsize - tx_put, min_t(unsigned int,
+ (SERIAL_XMIT_SIZE - info->xmit_tail),
+ min_t(unsigned int, info->xmit_cnt,
+ char_count))))) {
+
+ memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
+ tx_put),
+ &info->xmit_buf[info->xmit_tail],
+ small_count);
+
+ tx_put = (tx_put + small_count) & (tx_bufsize - 1);
+ char_count -= small_count;
+ info->icount.tx += small_count;
+ info->xmit_cnt -= small_count;
+ info->xmit_tail = (info->xmit_tail + small_count) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#else
- while (info->xmit_cnt && char_count){
- data = info->xmit_buf[info->xmit_tail];
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
-
- cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
- tx_put = (tx_put + 1) & (tx_bufsize - 1);
- char_count--;
- info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
- }
+ while (info->xmit_cnt && char_count) {
+ data = info->xmit_buf[info->xmit_tail];
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) &
+ (SERIAL_XMIT_SIZE - 1);
+
+ cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
+ tx_put = (tx_put + 1) & (tx_bufsize - 1);
+ char_count--;
+ info->icount.tx++;
+ info->last_active = jiffies;
+ info->jiffies[2] = jiffies;
+ }
#endif
- ztxdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ztxdone:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+ /* Update tx_put */
+ cy_writel(&buf_ctrl->tx_put, tx_put);
}
- /* Update tx_put */
- cy_writel(&buf_ctrl->tx_put, tx_put);
- }
}
-static void
-cyz_handle_cmd(struct cyclades_card *cinfo)
+static void cyz_handle_cmd(struct cyclades_card *cinfo)
{
- struct tty_struct *tty;
- struct cyclades_port *info;
- static volatile struct FIRM_ID __iomem *firm_id;
- static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
- static volatile struct BOARD_CTRL __iomem *board_ctrl;
- static volatile struct CH_CTRL __iomem *ch_ctrl;
- static volatile struct BUF_CTRL __iomem *buf_ctrl;
- uclong channel;
- ucchar cmd;
- uclong param;
- uclong hw_ver, fw_ver;
- int special_count;
- int delta_count;
-
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- fw_ver = cy_readl(&board_ctrl->fw_version);
- hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->mail_box_0);
-
-
- while(cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) {
- special_count = 0;
- delta_count = 0;
- info = &cy_port[channel + cinfo->first_line];
- if((tty = info->tty) == 0) {
- continue;
- }
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
- switch(cmd) {
- case C_CM_PR_ERROR:
- tty_insert_flip_char(tty, 0, TTY_PARITY);
- info->icount.rx++;
- special_count++;
- break;
- case C_CM_FR_ERROR:
- tty_insert_flip_char(tty, 0, TTY_FRAME);
- info->icount.rx++;
- special_count++;
- break;
- case C_CM_RXBRK:
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- info->icount.rx++;
- special_count++;
- break;
- case C_CM_MDCD:
- info->icount.dcd++;
- delta_count++;
- if (info->flags & ASYNC_CHECK_CD){
- if ((fw_ver > 241 ?
- ((u_long)param) :
- cy_readl(&ch_ctrl->rs_status)) & C_RS_DCD) {
- cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
- }else{
- cy_sched_event(info, Cy_EVENT_HANGUP);
- }
+ struct tty_struct *tty;
+ struct cyclades_port *info;
+ static volatile struct FIRM_ID __iomem *firm_id;
+ static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
+ static volatile struct BOARD_CTRL __iomem *board_ctrl;
+ static volatile struct CH_CTRL __iomem *ch_ctrl;
+ static volatile struct BUF_CTRL __iomem *buf_ctrl;
+ uclong channel;
+ ucchar cmd;
+ uclong param;
+ uclong hw_ver, fw_ver;
+ int special_count;
+ int delta_count;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ fw_ver = cy_readl(&board_ctrl->fw_version);
+ hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+ mail_box_0);
+
+ while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) {
+ special_count = 0;
+ delta_count = 0;
+ info = &cy_port[channel + cinfo->first_line];
+ if ((tty = info->tty) == 0) {
+ continue;
}
- break;
- case C_CM_MCTS:
- info->icount.cts++;
- delta_count++;
- break;
- case C_CM_MRI:
- info->icount.rng++;
- delta_count++;
- break;
- case C_CM_MDSR:
- info->icount.dsr++;
- delta_count++;
- break;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+ switch (cmd) {
+ case C_CM_PR_ERROR:
+ tty_insert_flip_char(tty, 0, TTY_PARITY);
+ info->icount.rx++;
+ special_count++;
+ break;
+ case C_CM_FR_ERROR:
+ tty_insert_flip_char(tty, 0, TTY_FRAME);
+ info->icount.rx++;
+ special_count++;
+ break;
+ case C_CM_RXBRK:
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ info->icount.rx++;
+ special_count++;
+ break;
+ case C_CM_MDCD:
+ info->icount.dcd++;
+ delta_count++;
+ if (info->flags & ASYNC_CHECK_CD) {
+ if ((fw_ver > 241 ? ((u_long) param) :
+ cy_readl(&ch_ctrl->rs_status)) &
+ C_RS_DCD) {
+ cy_sched_event(info,
+ Cy_EVENT_OPEN_WAKEUP);
+ } else {
+ cy_sched_event(info, Cy_EVENT_HANGUP);
+ }
+ }
+ break;
+ case C_CM_MCTS:
+ info->icount.cts++;
+ delta_count++;
+ break;
+ case C_CM_MRI:
+ info->icount.rng++;
+ delta_count++;
+ break;
+ case C_CM_MDSR:
+ info->icount.dsr++;
+ delta_count++;
+ break;
#ifdef Z_WAKE
- case C_CM_IOCTLW:
- cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
- break;
+ case C_CM_IOCTLW:
+ cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+ break;
#endif
#ifdef CONFIG_CYZ_INTR
- case C_CM_RXHIWM:
- case C_CM_RXNNDT:
- case C_CM_INTBACK2:
- /* Reception Interrupt */
+ case C_CM_RXHIWM:
+ case C_CM_RXNNDT:
+ case C_CM_INTBACK2:
+ /* Reception Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: rcvd intr, card %d, port %ld\n\r",
- info->card, channel);
+ printk("cyz_interrupt: rcvd intr, card %d, "
+ "port %ld\n\r", info->card, channel);
#endif
- cyz_handle_rx(info, ch_ctrl, buf_ctrl);
- break;
- case C_CM_TXBEMPTY:
- case C_CM_TXLOWWM:
- case C_CM_INTBACK:
- /* Transmission Interrupt */
+ cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+ break;
+ case C_CM_TXBEMPTY:
+ case C_CM_TXLOWWM:
+ case C_CM_INTBACK:
+ /* Transmission Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: xmit intr, card %d, port %ld\n\r",
- info->card, channel);
+ printk("cyz_interrupt: xmit intr, card %d, "
+ "port %ld\n\r", info->card, channel);
#endif
- cyz_handle_tx(info, ch_ctrl, buf_ctrl);
- break;
-#endif /* CONFIG_CYZ_INTR */
- case C_CM_FATAL:
- /* should do something with this !!! */
- break;
- default:
- break;
+ cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ break;
+#endif /* CONFIG_CYZ_INTR */
+ case C_CM_FATAL:
+ /* should do something with this !!! */
+ break;
+ default:
+ break;
+ }
+ if (delta_count)
+ cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ if (special_count)
+ tty_schedule_flip(tty);
}
- if(delta_count)
- cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
- if(special_count)
- tty_schedule_flip(tty);
- }
}
#ifdef CONFIG_CYZ_INTR
-static irqreturn_t
-cyz_interrupt(int irq, void *dev_id)
+static irqreturn_t cyz_interrupt(int irq, void *dev_id)
{
- struct cyclades_card *cinfo;
+ struct cyclades_card *cinfo;
- if((cinfo = (struct cyclades_card *)dev_id) == 0){
+ if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+ printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
#endif
- return IRQ_NONE; /* spurious interrupt */
- }
+ return IRQ_NONE; /* spurious interrupt */
+ }
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
+ printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
#endif
- return IRQ_NONE;
- }
+ return IRQ_NONE;
+ }
- /* Handle the interrupts */
- cyz_handle_cmd(cinfo);
+ /* Handle the interrupts */
+ cyz_handle_cmd(cinfo);
- return IRQ_HANDLED;
-} /* cyz_interrupt */
+ return IRQ_HANDLED;
+} /* cyz_interrupt */
-static void
-cyz_rx_restart(unsigned long arg)
+static void cyz_rx_restart(unsigned long arg)
{
- struct cyclades_port *info = (struct cyclades_port *)arg;
- int retval;
- int card = info->card;
- uclong channel = (info->line) - (cy_card[card].first_line);
- unsigned long flags;
-
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
- if (retval != 0){
- printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
- info->line, retval);
- }
- cyz_rx_full_timer[info->line].function = NULL;
- CY_UNLOCK(info, flags);
+ struct cyclades_port *info = (struct cyclades_port *)arg;
+ int retval;
+ int card = info->card;
+ uclong channel = (info->line) - (cy_card[card].first_line);
+ unsigned long flags;
+
+ CY_LOCK(info, flags);
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
+ if (retval != 0) {
+ printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ cyz_rx_full_timer[info->line].function = NULL;
+ CY_UNLOCK(info, flags);
}
-#else /* CONFIG_CYZ_INTR */
+#else /* CONFIG_CYZ_INTR */
-static void
-cyz_poll(unsigned long arg)
+static void cyz_poll(unsigned long arg)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info;
- struct tty_struct *tty;
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct BOARD_CTRL *board_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
- int card, port;
-
- cyz_timerlist.expires = jiffies + (HZ);
- for (card = 0 ; card < NR_CARDS ; card++){
- cinfo = &cy_card[card];
-
- if (!IS_CYC_Z(*cinfo)) continue;
- if (!ISZLOADED(*cinfo)) continue;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info;
+ struct tty_struct *tty;
+ static volatile struct FIRM_ID *firm_id;
+ static volatile struct ZFW_CTRL *zfw_ctrl;
+ static volatile struct BOARD_CTRL *board_ctrl;
+ static volatile struct CH_CTRL *ch_ctrl;
+ static volatile struct BUF_CTRL *buf_ctrl;
+ int card, port;
- firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &(zfw_ctrl->board_ctrl);
+ cyz_timerlist.expires = jiffies + (HZ);
+ for (card = 0; card < NR_CARDS; card++) {
+ cinfo = &cy_card[card];
+
+ if (!IS_CYC_Z(*cinfo))
+ continue;
+ if (!ISZLOADED(*cinfo))
+ continue;
+
+ firm_id = cinfo->base_addr + ID_ADDRESS;
+ zfw_ctrl = cinfo->base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &(zfw_ctrl->board_ctrl);
/* Skip first polling cycle to avoid racing conditions with the FW */
- if (!cinfo->intr_enabled) {
- cinfo->nports = (int) cy_readl(&board_ctrl->n_channel);
- cinfo->intr_enabled = 1;
- continue;
- }
+ if (!cinfo->intr_enabled) {
+ cinfo->nports = (int)cy_readl(&board_ctrl->n_channel);
+ cinfo->intr_enabled = 1;
+ continue;
+ }
- cyz_handle_cmd(cinfo);
+ cyz_handle_cmd(cinfo);
- for (port = 0 ; port < cinfo->nports ; port++) {
- info = &cy_port[ port + cinfo->first_line ];
- tty = info->tty;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
+ for (port = 0; port < cinfo->nports; port++) {
+ info = &cy_port[port + cinfo->first_line];
+ tty = info->tty;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
- if (!info->throttle)
- cyz_handle_rx(info, ch_ctrl, buf_ctrl);
- cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ if (!info->throttle)
+ cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+ cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ }
+ /* poll every 'cyz_polling_cycle' period */
+ cyz_timerlist.expires = jiffies + cyz_polling_cycle;
}
- /* poll every 'cyz_polling_cycle' period */
- cyz_timerlist.expires = jiffies + cyz_polling_cycle;
- }
- add_timer(&cyz_timerlist);
-
- return;
-} /* cyz_poll */
+ add_timer(&cyz_timerlist);
+} /* cyz_poll */
-#endif /* CONFIG_CYZ_INTR */
+#endif /* CONFIG_CYZ_INTR */
/********** End of block of Cyclades-Z specific code *********/
/***********************************************************/
-
/* This is called whenever a port becomes active;
interrupts are enabled and DTR & RTS are turned on.
*/
-static int
-startup(struct cyclades_port * info)
+static int startup(struct cyclades_port *info)
{
- unsigned long flags;
- int retval = 0;
- void __iomem *base_addr;
- int card,chip,channel,index;
- unsigned long page;
+ unsigned long flags;
+ int retval = 0;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+ unsigned long page;
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
- CY_LOCK(info, flags);
+ CY_LOCK(info, flags);
- if (info->flags & ASYNC_INITIALIZED){
- free_page(page);
- goto errout;
- }
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
- if (!info->type){
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- free_page(page);
- goto errout;
- }
+ if (!info->type) {
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ free_page(page);
+ goto errout;
+ }
- if (info->xmit_buf)
- free_page(page);
- else
- info->xmit_buf = (unsigned char *) page;
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *)page;
- CY_UNLOCK(info, flags);
+ CY_UNLOCK(info, flags);
- set_line_char(info);
+ set_line_char(info);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
- card, chip, channel, (long)base_addr);/**/
+ printk("cyc startup card %d, chip %d, channel %d, "
+ "base_addr %lx\n",
+ card, chip, channel, (long)base_addr);
+ /**/
#endif
+ CY_LOCK(info, flags);
- CY_LOCK(info, flags);
-
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- cy_writeb(base_addr+(CyRTPR<<index), (info->default_timeout
- ? info->default_timeout : 0x02)); /* 10ms rx timeout */
+ cy_writeb(base_addr + (CyRTPR << index),
+ (info->default_timeout ? info->default_timeout : 0x02));
+ /* 10ms rx timeout */
- cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+ cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
+ index);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
+ cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:startup raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyRxData);
- info->flags |= ASYNC_INITIALIZED;
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) | CyRxData);
+ info->flags |= ASYNC_INITIALIZED;
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->breakon = info->breakoff = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ CY_UNLOCK(info, flags);
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
+ } else {
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
- base_addr = cy_card[card].base_addr;
+ base_addr = cy_card[card].base_addr;
- firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])){
- return -ENODEV;
- }
+ firm_id = base_addr + ID_ADDRESS;
+ if (!ISZLOADED(cy_card[card])) {
+ return -ENODEV;
+ }
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
#ifdef CY_DEBUG_OPEN
- printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);/**/
+ printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);
+ /**/
#endif
+ CY_LOCK(info, flags);
- CY_LOCK(info, flags);
-
- cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
+ cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
- C_IN_IOCTLW|
- C_IN_MDCD);
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
+ C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_IOCTLW|
- C_IN_MDCD);
-#endif /* CONFIG_CYZ_INTR */
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_IOCTLW | C_IN_MDCD);
+#endif /* CONFIG_CYZ_INTR */
#else
#ifdef CONFIG_CYZ_INTR
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_TXBEMPTY|C_IN_TXLOWWM|C_IN_RXHIWM|C_IN_RXNNDT|
- C_IN_MDCD);
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
+ C_IN_RXNNDT | C_IN_MDCD);
#else
- cy_writel(&ch_ctrl[channel].intr_enable,
- C_IN_MDCD);
-#endif /* CONFIG_CYZ_INTR */
-#endif /* Z_WAKE */
-
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
- if (retval != 0){
- printk("cyc:startup(1) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);
+#endif /* CONFIG_CYZ_INTR */
+#endif /* Z_WAKE */
+
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ if (retval != 0) {
+ printk("cyc:startup(1) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
- /* Flush RX buffers before raising DTR and RTS */
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX, 0L);
- if (retval != 0){
- printk("cyc:startup(2) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ /* Flush RX buffers before raising DTR and RTS */
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX,
+ 0L);
+ if (retval != 0) {
+ printk("cyc:startup(2) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
- /* set timeout !!! */
- /* set RTS and DTR !!! */
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR) ;
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:startup(3) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ /* set timeout !!! */
+ /* set RTS and DTR !!! */
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
+ C_RS_DTR);
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:startup(3) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising Z DTR\n");
+ printk("cyc:startup raising Z DTR\n");
#endif
- /* enable send, recv, modem !!! */
+ /* enable send, recv, modem !!! */
- info->flags |= ASYNC_INITIALIZED;
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- info->breakon = info->breakoff = 0;
- memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
- info->idle_stats.in_use =
- info->idle_stats.recv_idle =
- info->idle_stats.xmit_idle = jiffies;
+ info->flags |= ASYNC_INITIALIZED;
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->breakon = info->breakoff = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
- }
+ CY_UNLOCK(info, flags);
+ }
#ifdef CY_DEBUG_OPEN
printk(" cyc startup done\n");
errout:
CY_UNLOCK(info, flags);
return retval;
-} /* startup */
-
+} /* startup */
-static void
-start_xmit( struct cyclades_port *info )
+static void start_xmit(struct cyclades_port *info)
{
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), channel);
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
-#ifdef CONFIG_CYZ_INTR
- int retval;
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L);
- if (retval != 0){
- printk("cyc:start_xmit retval on ttyC%d was %x\n",
- info->line, retval);
- }
- CY_UNLOCK(info, flags);
-#else /* CONFIG_CYZ_INTR */
- /* Don't have to do anything at this time */
-#endif /* CONFIG_CYZ_INTR */
- }
-} /* start_xmit */
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), channel);
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
+ CY_UNLOCK(info, flags);
+ } else {
+#ifdef CONFIG_CYZ_INTR
+ int retval;
+
+ CY_LOCK(info, flags);
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK,
+ 0L);
+ if (retval != 0) {
+ printk("cyc:start_xmit retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
+#else /* CONFIG_CYZ_INTR */
+ /* Don't have to do anything at this time */
+#endif /* CONFIG_CYZ_INTR */
+ }
+} /* start_xmit */
/*
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
*/
-static void
-shutdown(struct cyclades_port * info)
+static void shutdown(struct cyclades_port *info)
{
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
-
- if (!(info->flags & ASYNC_INITIALIZED)){
- return;
- }
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+
+ if (!(info->flags & ASYNC_INITIALIZED)) {
+ return;
+ }
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
- card, chip, channel, (long)base_addr);
+ printk("cyc shutdown Y card %d, chip %d, channel %d, "
+ "base_addr %lx\n",
+ card, chip, channel, (long)base_addr);
#endif
- CY_LOCK(info, flags);
+ CY_LOCK(info, flags);
+
+ /* Clear delta_msr_wait queue to avoid mem leaks. */
+ wake_up_interruptible(&info->delta_msr_wait);
- /* Clear delta_msr_wait queue to avoid mem leaks. */
- wake_up_interruptible(&info->delta_msr_wait);
-
- if (info->xmit_buf){
- unsigned char * temp;
- temp = info->xmit_buf;
- info->xmit_buf = NULL;
- free_page((unsigned long) temp);
- }
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
+ if (info->xmit_buf) {
+ unsigned char *temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = NULL;
+ free_page((unsigned long)temp);
+ }
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
+ cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc shutdown dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc shutdown dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- }
- cyy_issue_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
- /* it may be appropriate to clear _XMIT at
- some later date (after testing)!!! */
-
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->flags &= ~ASYNC_INITIALIZED;
- CY_UNLOCK(info, flags);
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- base_addr = cy_card[card].base_addr;
+ }
+ cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
+ /* it may be appropriate to clear _XMIT at
+ some later date (after testing)!!! */
+
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+ CY_UNLOCK(info, flags);
+ } else {
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
+
+ base_addr = cy_card[card].base_addr;
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);
+ printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
+ card, channel, (long)base_addr);
#endif
- firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
- return;
- }
+ firm_id = base_addr + ID_ADDRESS;
+ if (!ISZLOADED(cy_card[card])) {
+ return;
+ }
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
- CY_LOCK(info, flags);
+ CY_LOCK(info, flags);
- if (info->xmit_buf){
- unsigned char * temp;
- temp = info->xmit_buf;
- info->xmit_buf = NULL;
- free_page((unsigned long) temp);
- }
-
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- cy_writel(&ch_ctrl[channel].rs_control,
- (uclong)(cy_readl(&ch_ctrl[channel].rs_control) &
- ~(C_RS_RTS | C_RS_DTR)));
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:shutdown retval on ttyC%d was %x\n",
- info->line, retval);
+ if (info->xmit_buf) {
+ unsigned char *temp;
+ temp = info->xmit_buf;
+ info->xmit_buf = NULL;
+ free_page((unsigned long)temp);
}
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ cy_writel(&ch_ctrl[channel].rs_control,
+ (uclong)(cy_readl(&ch_ctrl[channel].rs_control)&
+ ~(C_RS_RTS | C_RS_DTR)));
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:shutdown retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:shutdown dropping Z DTR\n");
+ printk("cyc:shutdown dropping Z DTR\n");
#endif
- }
-
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- info->flags &= ~ASYNC_INITIALIZED;
+ }
- CY_UNLOCK(info, flags);
- }
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ CY_UNLOCK(info, flags);
+ }
#ifdef CY_DEBUG_OPEN
- printk(" cyc shutdown done\n");
+ printk(" cyc shutdown done\n");
#endif
- return;
-} /* shutdown */
-
+} /* shutdown */
/*
* ------------------------------------------------------------
*/
static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
- struct cyclades_port *info)
+block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct cyclades_port *info)
{
- DECLARE_WAITQUEUE(wait, current);
- struct cyclades_card *cinfo;
- unsigned long flags;
- int chip, channel,index;
- int retval;
- void __iomem *base_addr;
-
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
+ DECLARE_WAITQUEUE(wait, current);
+ struct cyclades_card *cinfo;
+ unsigned long flags;
+ int chip, channel, index;
+ int retval;
+ void __iomem *base_addr;
+
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ }
+ return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
- return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
- }
-
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
+
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * cy_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- CY_LOCK(info, flags);
- if (!tty_hung_up_p(filp))
- info->count--;
- CY_UNLOCK(info, flags);
+ CY_LOCK(info, flags);
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ CY_UNLOCK(info, flags);
#ifdef CY_DEBUG_COUNT
- printk("cyc block_til_ready: (%d): decrementing count to %d\n",
- current->pid, info->count);
+ printk("cyc block_til_ready: (%d): decrementing count to %d\n",
+ current->pid, info->count);
#endif
- info->blocked_open++;
-
- if (!IS_CYC_Z(*cinfo)) {
- chip = channel>>2;
- channel &= 0x03;
- index = cinfo->bus_index;
- base_addr = cinfo->base_addr + (cy_chip_offset[chip]<<index);
-
- while (1) {
- CY_LOCK(info, flags);
- if ((tty->termios->c_cflag & CBAUD)){
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
+ info->blocked_open++;
+
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cinfo->bus_index;
+ base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
+
+ while (1) {
+ CY_LOCK(info, flags);
+ if ((tty->termios->c_cflag & CBAUD)) {
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:block_til_ready raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr +
+ (CyMSVR1 << index)),
+ cy_readb(base_addr +
+ (CyMSVR2 << index)));
#endif
- }
- CY_UNLOCK(info, flags);
+ }
+ CY_UNLOCK(info, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+ break;
+ }
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (!(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
+ (cy_readb(base_addr +
+ (CyMSVR1 << index)) & CyDCD))) {
+ CY_UNLOCK(info, flags);
+ break;
+ }
CY_UNLOCK(info, flags);
- break;
- }
- CY_UNLOCK(info, flags);
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc block_til_ready blocking: ttyC%d, "
+ "count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- schedule();
- }
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- base_addr = cinfo->base_addr;
- firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)){
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- return -EINVAL;
- }
-
- zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- while (1) {
- if ((tty->termios->c_cflag & CBAUD)){
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) |
- (C_RS_RTS | C_RS_DTR));
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:block_til_ready retval on ttyC%d was %x\n",
- info->line, retval);
+ schedule();
+ }
+ } else {
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
+
+ base_addr = cinfo->base_addr;
+ firm_id = base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*cinfo)) {
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ return -EINVAL;
}
+
+ zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ while (1) {
+ if ((tty->termios->c_cflag & CBAUD)) {
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) | (C_RS_RTS |
+ C_RS_DTR));
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:block_til_ready retval on "
+ "ttyC%d was %x\n",
+ info->line, retval);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising Z DTR\n");
+ printk("cyc:block_til_ready raising Z DTR\n");
#endif
- }
+ }
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
- break;
- }
- if (!(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+ break;
+ }
+ if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
+ (cy_readl(&ch_ctrl[channel].rs_status) &
+ C_RS_DCD))) {
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc block_til_ready blocking: ttyC%d, "
+ "count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- schedule();
+ schedule();
+ }
}
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp)){
- info->count++;
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp)) {
+ info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:block_til_ready (%d): incrementing count to %d\n",
- current->pid, info->count);
+ printk("cyc:block_til_ready (%d): incrementing count to %d\n",
+ current->pid, info->count);
#endif
- }
- info->blocked_open--;
+ }
+ info->blocked_open--;
#ifdef CY_DEBUG_OPEN
- printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
+ info->line, info->count);
+ /**/
#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
-
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+} /* block_til_ready */
/*
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
*/
-static int
-cy_open(struct tty_struct *tty, struct file * filp)
+static int cy_open(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (NR_PORTS <= line)){
- return -ENODEV;
- }
- info = &cy_port[line];
- if (info->line < 0){
- return -ENODEV;
- }
-
- /* If the card's firmware hasn't been loaded,
- treat it as absent from the system. This
- will make the user pay attention.
- */
- if (IS_CYC_Z(cy_card[info->card])) {
- struct cyclades_card *cinfo = &cy_card[info->card];
- struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
-
- if (!ISZLOADED(*cinfo)) {
- if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 __iomem *)
- (cinfo->ctl_addr))->mail_box_0)) &&
- Z_FPGA_CHECK (*cinfo)) &&
- (ZFIRM_HLT == cy_readl (&firm_id->signature)))
- {
- printk ("cyc:Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
- } else {
- printk("cyc:Cyclades-Z firmware not yet loaded\n");
- }
- return -ENODEV;
- }
-#ifdef CONFIG_CYZ_INTR
- else {
- /* In case this Z board is operating in interrupt mode, its
- interrupts should be enabled as soon as the first open happens
- to one of its ports. */
- if (!cinfo->intr_enabled) {
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
-
- zfw_ctrl = cinfo->base_addr + (cy_readl (&firm_id->zfwctrl_addr) & 0xfffff);
+ struct cyclades_port *info;
+ int retval, line;
- board_ctrl = &zfw_ctrl->board_ctrl;
+ line = tty->index;
+ if ((line < 0) || (NR_PORTS <= line)) {
+ return -ENODEV;
+ }
+ info = &cy_port[line];
+ if (info->line < 0) {
+ return -ENODEV;
+ }
- /* Enable interrupts on the PLX chip */
- cy_writew(cinfo->ctl_addr+0x68,
- cy_readw(cinfo->ctl_addr+0x68)|0x0900);
- /* Enable interrupts on the FW */
- retval = cyz_issue_cmd(cinfo,
- 0, C_CM_IRQ_ENBL, 0L);
- if (retval != 0){
- printk("cyc:IRQ enable retval was %x\n", retval);
+ /* If the card's firmware hasn't been loaded,
+ treat it as absent from the system. This
+ will make the user pay attention.
+ */
+ if (IS_CYC_Z(cy_card[info->card])) {
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
+
+ if (!ISZLOADED(*cinfo)) {
+ if (((ZE_V1 == cy_readl(
+ &((struct RUNTIME_9060 __iomem *)
+ (cinfo->ctl_addr))->mail_box_0)) &&
+ Z_FPGA_CHECK(*cinfo)) &&
+ (ZFIRM_HLT == cy_readl(
+ &firm_id->signature))) {
+ printk("cyc:Cyclades-Z Error: you need an "
+ "external power supply for this number "
+ "of ports.\n\rFirmware halted.\r\n");
+ } else {
+ printk("cyc:Cyclades-Z firmware not yet "
+ "loaded\n");
+ }
+ return -ENODEV;
}
- cinfo->nports = (int) cy_readl (&board_ctrl->n_channel);
- cinfo->intr_enabled = 1;
- }
+#ifdef CONFIG_CYZ_INTR
+ else {
+ /* In case this Z board is operating in interrupt mode, its
+ interrupts should be enabled as soon as the first open
+ happens to one of its ports. */
+ if (!cinfo->intr_enabled) {
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+
+ zfw_ctrl = cinfo->base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
+
+ board_ctrl = &zfw_ctrl->board_ctrl;
+
+ /* Enable interrupts on the PLX chip */
+ cy_writew(cinfo->ctl_addr + 0x68,
+ cy_readw(cinfo->ctl_addr +
+ 0x68) | 0x0900);
+ /* Enable interrupts on the FW */
+ retval = cyz_issue_cmd(cinfo, 0,
+ C_CM_IRQ_ENBL, 0L);
+ if (retval != 0) {
+ printk("cyc:IRQ enable retval was %x\n",
+ retval);
+ }
+ cinfo->nports =
+ (int)cy_readl(&board_ctrl->n_channel);
+ cinfo->intr_enabled = 1;
+ }
+ }
+#endif /* CONFIG_CYZ_INTR */
+ /* Make sure this Z port really exists in hardware */
+ if (info->line > (cinfo->first_line + cinfo->nports - 1))
+ return -ENODEV;
}
-#endif /* CONFIG_CYZ_INTR */
- /* Make sure this Z port really exists in hardware */
- if (info->line > (cinfo->first_line + cinfo->nports - 1))
- return -ENODEV;
- }
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_open ttyC%d\n", info->line); /* */
+ printk("cyc:cy_open ttyC%d\n", info->line); /* */
#endif
- tty->driver_data = info;
- info->tty = tty;
- if (serial_paranoia_check(info, tty->name, "cy_open")){
- return -ENODEV;
- }
+ tty->driver_data = info;
+ info->tty = tty;
+ if (serial_paranoia_check(info, tty->name, "cy_open")) {
+ return -ENODEV;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open ttyC%d, count = %d\n",
- info->line, info->count);/**/
+ printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);
+ /**/
#endif
- info->count++;
+ info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_open (%d): incrementing count to %d\n",
- current->pid, info->count);
+ printk("cyc:cy_open (%d): incrementing count to %d\n",
+ current->pid, info->count);
#endif
- /*
- * If the port is the middle of closing, bail out now
- */
- if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
- return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
- }
-
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval){
- return retval;
- }
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
+ }
- info->throttle = 0;
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval) {
+ return retval;
+ }
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
#ifdef CY_DEBUG_OPEN
- printk(" cyc:cy_open done\n");/**/
+ printk("cyc:cy_open returning after block_til_ready with %d\n",
+ retval);
#endif
+ return retval;
+ }
- return 0;
-} /* cy_open */
+ info->throttle = 0;
+#ifdef CY_DEBUG_OPEN
+ printk(" cyc:cy_open done\n");
+ /**/
+#endif
+ return 0;
+} /* cy_open */
/*
* cy_wait_until_sent() --- wait until the transmitter is empty
*/
-static void
-cy_wait_until_sent(struct tty_struct *tty, int timeout)
+static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- void __iomem *base_addr;
- int card,chip,channel,index;
- unsigned long orig_jiffies;
- int char_time;
-
- if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
- return;
-
- if (info->xmit_fifo_size == 0)
- return; /* Just in case.... */
-
-
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- *
- * Note: we have to use pretty tight timings here to satisfy
- * the NIST-PCTS.
- */
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time <= 0)
- char_time = 1;
- if (timeout < 0)
- timeout = 0;
- if (timeout)
- char_time = min(char_time, timeout);
- /*
- * If the transmitter hasn't cleared in twice the approximate
- * amount of time to send the entire FIFO, it probably won't
- * ever clear. This assumes the UART isn't doing flow
- * control, which is currently the case. Hence, if it ever
- * takes longer than info->timeout, this is probably due to a
- * UART bug of some kind. So, we clamp the timeout parameter at
- * 2*info->timeout.
- */
- if (!timeout || timeout > 2*info->timeout)
- timeout = 2*info->timeout;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+ unsigned long orig_jiffies;
+ int char_time;
+
+ if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
+ return;
+
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time <= 0)
+ char_time = 1;
+ if (timeout < 0)
+ timeout = 0;
+ if (timeout)
+ char_time = min(char_time, timeout);
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2 * info->timeout)
+ timeout = 2 * info->timeout;
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
+ printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
#endif
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
- while (cy_readb(base_addr+(CySRER<<index)) & CyTxRdy) {
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Not clean (jiff=%lu)...", jiffies);
+ printk("Not clean (jiff=%lu)...", jiffies);
#endif
- if (msleep_interruptible(jiffies_to_msecs(char_time)))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
+ if (msleep_interruptible(jiffies_to_msecs(char_time)))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies +
+ timeout))
+ break;
+ }
+ } else {
+ /* Nothing to do! */
}
- } else {
- // Nothing to do!
- }
- /* Run one more char cycle */
- msleep_interruptible(jiffies_to_msecs(char_time * 5));
+ /* Run one more char cycle */
+ msleep_interruptible(jiffies_to_msecs(char_time * 5));
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Clean (jiff=%lu)...done\n", jiffies);
+ printk("Clean (jiff=%lu)...done\n", jiffies);
#endif
}
/*
* This routine is called when a particular tty device is closed.
*/
-static void
-cy_close(struct tty_struct *tty, struct file *filp)
+static void cy_close(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_close ttyC%d\n", info->line);
+ printk("cyc:cy_close ttyC%d\n", info->line);
#endif
- if (!info || serial_paranoia_check(info, tty->name, "cy_close")){
- return;
- }
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
+ return;
+ }
- CY_LOCK(info, flags);
- /* If the TTY is being hung up, nothing to do */
- if (tty_hung_up_p(filp)) {
- CY_UNLOCK(info, flags);
- return;
- }
-
+ CY_LOCK(info, flags);
+ /* If the TTY is being hung up, nothing to do */
+ if (tty_hung_up_p(filp)) {
+ CY_UNLOCK(info, flags);
+ return;
+ }
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+ printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
#endif
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("cyc:cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("cyc:cy_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_close at (%d): decrementing count to %d\n",
- current->pid, info->count - 1);
+ printk("cyc:cy_close at (%d): decrementing count to %d\n",
+ current->pid, info->count - 1);
#endif
- if (--info->count < 0) {
+ if (--info->count < 0) {
#ifdef CY_DEBUG_COUNT
- printk("cyc:cyc_close setting count to 0\n");
+ printk("cyc:cyc_close setting count to 0\n");
#endif
- info->count = 0;
- }
- if (info->count) {
- CY_UNLOCK(info, flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
-
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- CY_UNLOCK(info, flags);
- if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
- tty_wait_until_sent(tty, info->closing_wait);
- }
- CY_LOCK(info, flags);
-
- if (!IS_CYC_Z(cy_card[info->card])) {
- int channel = info->line - cy_card[info->card].first_line;
- int index = cy_card[info->card].bus_index;
- void __iomem *base_addr = cy_card[info->card].base_addr + (cy_chip_offset[channel>>2] << index);
- /* Stop accepting input */
- channel &= 0x03;
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyRxData);
- if (info->flags & ASYNC_INITIALIZED) {
- /* Waiting for on-board buffers to be empty before closing
- the port */
- CY_UNLOCK(info, flags);
- cy_wait_until_sent(tty, info->timeout);
- CY_LOCK(info, flags);
+ info->count = 0;
}
- } else {
-#ifdef Z_WAKE
- /* Waiting for on-board buffers to be empty before closing the port */
- void __iomem *base_addr = cy_card[info->card].base_addr;
- struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
- struct ZFW_CTRL __iomem *zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
- int channel = info->line - cy_card[info->card].first_line;
- int retval;
+ if (info->count) {
+ CY_UNLOCK(info, flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
- if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
- C_CM_IOCTLW, 0L);
- if (retval != 0){
- printk("cyc:cy_close retval on ttyC%d was %x\n",
- info->line, retval);
- }
- CY_UNLOCK(info, flags);
- interruptible_sleep_on(&info->shutdown_wait);
- CY_LOCK(info, flags);
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ CY_UNLOCK(info, flags);
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ tty_wait_until_sent(tty, info->closing_wait);
}
+ CY_LOCK(info, flags);
+
+ if (!IS_CYC_Z(cy_card[info->card])) {
+ int channel = info->line - cy_card[info->card].first_line;
+ int index = cy_card[info->card].bus_index;
+ void __iomem *base_addr = cy_card[info->card].base_addr +
+ (cy_chip_offset[channel >> 2] << index);
+ /* Stop accepting input */
+ channel &= 0x03;
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) & ~CyRxData);
+ if (info->flags & ASYNC_INITIALIZED) {
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
+ CY_UNLOCK(info, flags);
+ cy_wait_until_sent(tty, info->timeout);
+ CY_LOCK(info, flags);
+ }
+ } else {
+#ifdef Z_WAKE
+ /* Waiting for on-board buffers to be empty before closing the port */
+ void __iomem *base_addr = cy_card[info->card].base_addr;
+ struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
+ struct ZFW_CTRL __iomem *zfw_ctrl =
+ base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
+ int channel = info->line - cy_card[info->card].first_line;
+ int retval;
+
+ if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLW, 0L);
+ if (retval != 0) {
+ printk("cyc:cy_close retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
+ interruptible_sleep_on(&info->shutdown_wait);
+ CY_LOCK(info, flags);
+ }
#endif
- }
-
- CY_UNLOCK(info, flags);
- shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- CY_LOCK(info, flags);
-
- tty->closing = 0;
- info->event = 0;
- info->tty = NULL;
- if (info->blocked_open) {
+ }
+
CY_UNLOCK(info, flags);
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
+ shutdown(info);
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ tty_ldisc_flush(tty);
CY_LOCK(info, flags);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
+
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ CY_UNLOCK(info, flags);
+ if (info->close_delay) {
+ msleep_interruptible(jiffies_to_msecs
+ (info->close_delay));
+ }
+ wake_up_interruptible(&info->open_wait);
+ CY_LOCK(info, flags);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_close done\n");
+ printk(" cyc:cy_close done\n");
#endif
- CY_UNLOCK(info, flags);
- return;
-} /* cy_close */
-
+ CY_UNLOCK(info, flags);
+} /* cy_close */
/* This routine gets called when tty_write has put something into
* the write_queue. The characters may come from user space or
* If the port is already active, there is no need to kick it.
*
*/
-static int
-cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- int c, ret = 0;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ int c, ret = 0;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write")){
- return 0;
- }
-
- if (!info->xmit_buf)
- return 0;
+ if (serial_paranoia_check(info, tty->name, "cy_write")) {
+ return 0;
+ }
+
+ if (!info->xmit_buf)
+ return 0;
+
+ CY_LOCK(info, flags);
+ while (1) {
+ c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
+ (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
+
+ if (c <= 0)
+ break;
+
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ CY_UNLOCK(info, flags);
- CY_LOCK(info, flags);
- while (1) {
- c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
- (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
-
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- buf += c;
- count -= c;
- ret += c;
- }
- CY_UNLOCK(info, flags);
-
- info->idle_stats.xmit_bytes += ret;
- info->idle_stats.xmit_idle = jiffies;
-
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
- start_xmit(info);
- }
- return ret;
-} /* cy_write */
+ info->idle_stats.xmit_bytes += ret;
+ info->idle_stats.xmit_idle = jiffies;
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ start_xmit(info);
+ }
+ return ret;
+} /* cy_write */
/*
* This routine is called by the kernel to write a single
* done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored.
*/
-static void
-cy_put_char(struct tty_struct *tty, unsigned char ch)
+static void cy_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_put_char ttyC%d\n", info->line);
+ printk("cyc:cy_put_char ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_put_char"))
+ return;
- if (!info->xmit_buf)
- return;
+ if (!info->xmit_buf)
+ return;
- CY_LOCK(info, flags);
- if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- CY_UNLOCK(info, flags);
- return;
- }
+ CY_LOCK(info, flags);
+ if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
+ CY_UNLOCK(info, flags);
+ return;
+ }
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= SERIAL_XMIT_SIZE - 1;
- info->xmit_cnt++;
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ info->xmit_cnt++;
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
-} /* cy_put_char */
-
+ CY_UNLOCK(info, flags);
+} /* cy_put_char */
/*
* This routine is called by the kernel after it has written a
* series of characters to the tty device using put_char().
*/
-static void
-cy_flush_chars(struct tty_struct *tty)
+static void cy_flush_chars(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+ printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
- return;
-
- if (info->xmit_cnt <= 0 || tty->stopped
- || tty->hw_stopped || !info->xmit_buf)
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
+ return;
- start_xmit(info);
-} /* cy_flush_chars */
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
+ start_xmit(info);
+} /* cy_flush_chars */
/*
* This routine returns the numbers of characters the tty driver
* to change as output buffers get emptied, or if the output flow
* control is activated.
*/
-static int
-cy_write_room(struct tty_struct *tty)
+static int cy_write_room(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int ret;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int ret;
+
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
+ printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-} /* cy_write_room */
+ if (serial_paranoia_check(info, tty->name, "cy_write_room"))
+ return 0;
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+} /* cy_write_room */
-
-static int
-cy_chars_in_buffer(struct tty_struct *tty)
+static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel;
-
- if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
- return 0;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, channel;
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
+ return 0;
+
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
#ifdef Z_EXT_CHARS_IN_BUFFER
- if (!IS_CYC_Z(cy_card[card])) {
-#endif /* Z_EXT_CHARS_IN_BUFFER */
+ if (!IS_CYC_Z(cy_card[card])) {
+#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
- info->line, info->xmit_cnt); /* */
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
#endif
- return info->xmit_cnt;
+ return info->xmit_cnt;
#ifdef Z_EXT_CHARS_IN_BUFFER
- } else {
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
- int char_count;
- volatile uclong tx_put, tx_get, tx_bufsize;
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
-
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- if (tx_put >= tx_get)
- char_count = tx_put - tx_get;
- else
- char_count = tx_put - tx_get + tx_bufsize;
+ } else {
+ static volatile struct FIRM_ID *firm_id;
+ static volatile struct ZFW_CTRL *zfw_ctrl;
+ static volatile struct CH_CTRL *ch_ctrl;
+ static volatile struct BUF_CTRL *buf_ctrl;
+ int char_count;
+ volatile uclong tx_put, tx_get, tx_bufsize;
+
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+ tx_get = cy_readl(&buf_ctrl->tx_get);
+ tx_put = cy_readl(&buf_ctrl->tx_put);
+ tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ if (tx_put >= tx_get)
+ char_count = tx_put - tx_get;
+ else
+ char_count = tx_put - tx_get + tx_bufsize;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
- info->line, info->xmit_cnt + char_count); /* */
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */
#endif
- return (info->xmit_cnt + char_count);
- }
-#endif /* Z_EXT_CHARS_IN_BUFFER */
-} /* cy_chars_in_buffer */
-
+ return info->xmit_cnt + char_count;
+ }
+#endif /* Z_EXT_CHARS_IN_BUFFER */
+} /* cy_chars_in_buffer */
/*
* ------------------------------------------------------------
* ------------------------------------------------------------
*/
-static void
-cyy_baud_calc(struct cyclades_port *info, uclong baud)
+static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
{
- int co, co_val, bpr;
- uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : 25000000);
-
- if (baud == 0) {
- info->tbpr = info->tco = info->rbpr = info->rco = 0;
- return;
- }
-
- /* determine which prescaler to use */
- for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
- if (cy_clock / co_val / baud > 63)
- break;
- }
-
- bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
- if (bpr > 255)
- bpr = 255;
-
- info->tbpr = info->rbpr = bpr;
- info->tco = info->rco = co;
+ int co, co_val, bpr;
+ uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
+ 25000000);
+
+ if (baud == 0) {
+ info->tbpr = info->tco = info->rbpr = info->rco = 0;
+ return;
+ }
+
+ /* determine which prescaler to use */
+ for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
+ if (cy_clock / co_val / baud > 63)
+ break;
+ }
+
+ bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
+ if (bpr > 255)
+ bpr = 255;
+
+ info->tbpr = info->rbpr = bpr;
+ info->tco = info->rco = co;
}
/*
* This routine finds or computes the various line characteristics.
* It used to be called config_setup
*/
-static void
-set_line_char(struct cyclades_port * info)
+static void set_line_char(struct cyclades_port *info)
{
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
- unsigned cflag, iflag;
- unsigned short chip_number;
- int baud, baud_rate = 0;
- int i;
-
-
- if (!info->tty || !info->tty->termios){
- return;
- }
- if (info->line == -1){
- return;
- }
- cflag = info->tty->termios->c_cflag;
- iflag = info->tty->termios->c_iflag;
-
- /*
- * Set up the tty->alt_speed kludge
- */
- if (info->tty) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->tty->alt_speed = 115200;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->tty->alt_speed = 230400;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
- }
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- chip_number = channel / 4;
-
- if (!IS_CYC_Z(cy_card[card])) {
-
- index = cy_card[card].bus_index;
-
- /* baud rate */
- baud = tty_get_baud_rate(info->tty);
- if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- if (info->custom_divisor)
- baud_rate = info->baud / info->custom_divisor;
- else
- baud_rate = info->baud;
- } else if (baud > CD1400_MAX_SPEED) {
- baud = CD1400_MAX_SPEED;
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
+ unsigned cflag, iflag;
+ unsigned short chip_number;
+ int baud, baud_rate = 0;
+ int i;
+
+ if (!info->tty || !info->tty->termios) {
+ return;
}
- /* find the baud index */
- for (i = 0; i < 20; i++) {
- if (baud == baud_table[i]) {
- break;
- }
+ if (info->line == -1) {
+ return;
}
- if (i == 20) {
- i = 19; /* CD1400_MAX_SPEED */
- }
+ cflag = info->tty->termios->c_cflag;
+ iflag = info->tty->termios->c_iflag;
- if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- cyy_baud_calc(info, baud_rate);
- } else {
- if(info->chip_rev >= CD1400_REV_J) {
- /* It is a CD1400 rev. J or later */
- info->tbpr = baud_bpr_60[i]; /* Tx BPR */
- info->tco = baud_co_60[i]; /* Tx CO */
- info->rbpr = baud_bpr_60[i]; /* Rx BPR */
- info->rco = baud_co_60[i]; /* Rx CO */
- } else {
- info->tbpr = baud_bpr_25[i]; /* Tx BPR */
- info->tco = baud_co_25[i]; /* Tx CO */
- info->rbpr = baud_bpr_25[i]; /* Rx BPR */
- info->rco = baud_co_25[i]; /* Rx CO */
- }
- }
- if (baud_table[i] == 134) {
- /* get it right for 134.5 baud */
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- } else if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2;
- } else if (baud_table[i]) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
- /* this needs to be propagated into the card info */
- } else {
- info->timeout = 0;
- }
- /* By tradition (is it a standard?) a baud rate of zero
- implies the line should be/has been closed. A bit
- later in this routine such a test is performed. */
-
- /* byte size and parity */
- info->cor5 = 0;
- info->cor4 = 0;
- info->cor3 = (info->default_threshold
- ? info->default_threshold
- : baud_cor3[i]); /* receive threshold */
- info->cor2 = CyETC;
- switch(cflag & CSIZE){
- case CS5:
- info->cor1 = Cy_5_BITS;
- break;
- case CS6:
- info->cor1 = Cy_6_BITS;
- break;
- case CS7:
- info->cor1 = Cy_7_BITS;
- break;
- case CS8:
- info->cor1 = Cy_8_BITS;
- break;
- }
- if(cflag & CSTOPB){
- info->cor1 |= Cy_2_STOP;
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- info->cor1 |= CyPARITY_O;
- }else{
- info->cor1 |= CyPARITY_E;
- }
- }else{
- info->cor1 |= CyPARITY_NONE;
- }
-
- /* CTS flow control flag */
- if (cflag & CRTSCTS){
- info->flags |= ASYNC_CTS_FLOW;
- info->cor2 |= CyCtsAE;
- }else{
- info->flags &= ~ASYNC_CTS_FLOW;
- info->cor2 &= ~CyCtsAE;
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
}
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
+
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ chip_number = channel / 4;
+
+ if (!IS_CYC_Z(cy_card[card])) {
+
+ index = cy_card[card].bus_index;
+
+ /* baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ if (info->custom_divisor)
+ baud_rate = info->baud / info->custom_divisor;
+ else
+ baud_rate = info->baud;
+ } else if (baud > CD1400_MAX_SPEED) {
+ baud = CD1400_MAX_SPEED;
+ }
+ /* find the baud index */
+ for (i = 0; i < 20; i++) {
+ if (baud == baud_table[i]) {
+ break;
+ }
+ }
+ if (i == 20) {
+ i = 19; /* CD1400_MAX_SPEED */
+ }
+
+ if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ cyy_baud_calc(info, baud_rate);
+ } else {
+ if (info->chip_rev >= CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ info->tbpr = baud_bpr_60[i]; /* Tx BPR */
+ info->tco = baud_co_60[i]; /* Tx CO */
+ info->rbpr = baud_bpr_60[i]; /* Rx BPR */
+ info->rco = baud_co_60[i]; /* Rx CO */
+ } else {
+ info->tbpr = baud_bpr_25[i]; /* Tx BPR */
+ info->tco = baud_co_25[i]; /* Tx CO */
+ info->rbpr = baud_bpr_25[i]; /* Rx BPR */
+ info->rco = baud_co_25[i]; /* Rx CO */
+ }
+ }
+ if (baud_table[i] == 134) {
+ /* get it right for 134.5 baud */
+ info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
+ 2;
+ } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud_rate) + 2;
+ } else if (baud_table[i]) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud_table[i]) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
+ /* By tradition (is it a standard?) a baud rate of zero
+ implies the line should be/has been closed. A bit
+ later in this routine such a test is performed. */
+
+ /* byte size and parity */
+ info->cor5 = 0;
+ info->cor4 = 0;
+ /* receive threshold */
+ info->cor3 = (info->default_threshold ?
+ info->default_threshold : baud_cor3[i]);
+ info->cor2 = CyETC;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->cor1 = Cy_5_BITS;
+ break;
+ case CS6:
+ info->cor1 = Cy_6_BITS;
+ break;
+ case CS7:
+ info->cor1 = Cy_7_BITS;
+ break;
+ case CS8:
+ info->cor1 = Cy_8_BITS;
+ break;
+ }
+ if (cflag & CSTOPB) {
+ info->cor1 |= Cy_2_STOP;
+ }
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ info->cor1 |= CyPARITY_O;
+ } else {
+ info->cor1 |= CyPARITY_E;
+ }
+ } else {
+ info->cor1 |= CyPARITY_NONE;
+ }
+
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->cor2 |= CyCtsAE;
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ info->cor2 &= ~CyCtsAE;
+ }
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
/***********************************************
The hardware option, CyRtsAO, presents RTS when
cable. Contact Marcio Saito for details.
***********************************************/
- chip = channel>>2;
- channel &= 0x03;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ chip = channel >> 2;
+ channel &= 0x03;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
-
- /* tx and rx baud rate */
-
- cy_writeb(base_addr+(CyTCOR<<index), info->tco);
- cy_writeb(base_addr+(CyTBPR<<index), info->tbpr);
- cy_writeb(base_addr+(CyRCOR<<index), info->rco);
- cy_writeb(base_addr+(CyRBPR<<index), info->rbpr);
-
- /* set line characteristics according configuration */
-
- cy_writeb(base_addr+(CySCHR1<<index),
- START_CHAR(info->tty));
- cy_writeb(base_addr+(CySCHR2<<index),
- STOP_CHAR(info->tty));
- cy_writeb(base_addr+(CyCOR1<<index), info->cor1);
- cy_writeb(base_addr+(CyCOR2<<index), info->cor2);
- cy_writeb(base_addr+(CyCOR3<<index), info->cor3);
- cy_writeb(base_addr+(CyCOR4<<index), info->cor4);
- cy_writeb(base_addr+(CyCOR5<<index), info->cor5);
-
- cyy_issue_cmd(base_addr,
- CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
-
- cy_writeb(base_addr+(CyCAR<<index),
- (u_char)channel); /* !!! Is this needed? */
- cy_writeb(base_addr+(CyRTPR<<index), (info->default_timeout
- ? info->default_timeout
- : 0x02)); /* 10ms rx timeout */
-
- if (C_CLOCAL(info->tty)) {
- /* without modem intr */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr+(CyMCOR1<<index),
- (CyCTS|rflow_thr[i]));
- } else {
- cy_writeb(base_addr+(CyMCOR1<<index), CyCTS);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr+(CyMCOR2<<index), CyCTS);
- } else {
- /* without modem intr */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyMdmCh);
- /* act on 1->0 modem transitions */
- if ((cflag & CRTSCTS) && info->rflow) {
- cy_writeb(base_addr+(CyMCOR1<<index),
- (CyDSR|CyCTS|CyRI|CyDCD|rflow_thr[i]));
- } else {
- cy_writeb(base_addr+(CyMCOR1<<index),
- CyDSR|CyCTS|CyRI|CyDCD);
- }
- /* act on 0->1 modem transitions */
- cy_writeb(base_addr+(CyMCOR2<<index),
- CyDSR|CyCTS|CyRI|CyDCD);
- }
-
- if(i == 0){ /* baud rate is zero, turn off line */
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+
+ /* tx and rx baud rate */
+
+ cy_writeb(base_addr + (CyTCOR << index), info->tco);
+ cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
+ cy_writeb(base_addr + (CyRCOR << index), info->rco);
+ cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
+
+ /* set line characteristics according configuration */
+
+ cy_writeb(base_addr + (CySCHR1 << index),
+ START_CHAR(info->tty));
+ cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->tty));
+ cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
+ cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
+ cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
+ cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
+ cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
+
+ cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
+ CyCOR3ch, index);
+
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
+ cy_writeb(base_addr + (CyRTPR << index),
+ (info->default_timeout ? info->default_timeout : 0x02));
+ /* 10ms rx timeout */
+
+ if (C_CLOCAL(info->tty)) {
+ /* without modem intr */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER << index)) | CyMdmCh);
+ /* act on 1->0 modem transitions */
+ if ((cflag & CRTSCTS) && info->rflow) {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ (CyCTS | rflow_thr[i]));
+ } else {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ CyCTS);
+ }
+ /* act on 0->1 modem transitions */
+ cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
} else {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
+ /* without modem intr */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr +
+ (CySRER << index)) | CyMdmCh);
+ /* act on 1->0 modem transitions */
+ if ((cflag & CRTSCTS) && info->rflow) {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ (CyDSR | CyCTS | CyRI | CyDCD |
+ rflow_thr[i]));
+ } else {
+ cy_writeb(base_addr + (CyMCOR1 << index),
+ CyDSR | CyCTS | CyRI | CyDCD);
+ }
+ /* act on 0->1 modem transitions */
+ cy_writeb(base_addr + (CyMCOR2 << index),
+ CyDSR | CyCTS | CyRI | CyDCD);
}
+
+ if (i == 0) { /* baud rate is zero, turn off line */
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_line_char dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- }else{
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- } else {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- }
+ } else {
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_line_char raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- }
-
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
- CY_UNLOCK(info, flags);
+ }
- } else {
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- struct BUF_CTRL __iomem *buf_ctrl;
- uclong sw_flow;
- int retval;
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
- return;
- }
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ CY_UNLOCK(info, flags);
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
- buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
-
- /* baud rate */
- baud = tty_get_baud_rate(info->tty);
- if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- if (info->custom_divisor)
- baud_rate = info->baud / info->custom_divisor;
- else
- baud_rate = info->baud;
- } else if (baud > CYZ_MAX_SPEED) {
- baud = CYZ_MAX_SPEED;
- }
- cy_writel(&ch_ctrl->comm_baud , baud);
-
- if (baud == 134) {
- /* get it right for 134.5 baud */
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- } else if ((baud == 38400) &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2;
- } else if (baud) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2;
- /* this needs to be propagated into the card info */
} else {
- info->timeout = 0;
- }
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ struct BUF_CTRL __iomem *buf_ctrl;
+ uclong sw_flow;
+ int retval;
+
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ if (!ISZLOADED(cy_card[card])) {
+ return;
+ }
- /* byte size and parity */
- switch(cflag & CSIZE){
- case CS5: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS5); break;
- case CS6: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS6); break;
- case CS7: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS7); break;
- case CS8: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS8); break;
- }
- if(cflag & CSTOPB){
- cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
- }else{
- cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- cy_writel(&ch_ctrl->comm_parity , C_PR_ODD);
- }else{
- cy_writel(&ch_ctrl->comm_parity , C_PR_EVEN);
- }
- }else{
- cy_writel(&ch_ctrl->comm_parity , C_PR_NONE);
- }
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
+
+ /* baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ if (info->custom_divisor)
+ baud_rate = info->baud / info->custom_divisor;
+ else
+ baud_rate = info->baud;
+ } else if (baud > CYZ_MAX_SPEED) {
+ baud = CYZ_MAX_SPEED;
+ }
+ cy_writel(&ch_ctrl->comm_baud, baud);
+
+ if (baud == 134) {
+ /* get it right for 134.5 baud */
+ info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
+ 2;
+ } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
+ ASYNC_SPD_CUST) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud_rate) + 2;
+ } else if (baud) {
+ info->timeout = (info->xmit_fifo_size * HZ * 15 /
+ baud) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
- /* CTS flow control flag */
- if (cflag & CRTSCTS){
- cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
- }else{
- cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
- }
- /* As the HW flow control is done in firmware, the driver doesn't
- need to care about it */
- info->flags &= ~ASYNC_CTS_FLOW;
-
- /* XON/XOFF/XANY flow control flags */
- sw_flow = 0;
- if (iflag & IXON){
- sw_flow |= C_FL_OXX;
- if (iflag & IXANY)
- sw_flow |= C_FL_OIXANY;
- }
- cy_writel(&ch_ctrl->sw_flow, sw_flow);
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
+ break;
+ case CS6:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
+ break;
+ case CS7:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
+ break;
+ case CS8:
+ cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
+ break;
+ }
+ if (cflag & CSTOPB) {
+ cy_writel(&ch_ctrl->comm_data_l,
+ cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
+ } else {
+ cy_writel(&ch_ctrl->comm_data_l,
+ cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
+ }
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
+ } else {
+ cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
+ }
+ } else {
+ cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
+ }
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
- if (retval != 0){
- printk("cyc:set_line_char retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ /* CTS flow control flag */
+ if (cflag & CRTSCTS) {
+ cy_writel(&ch_ctrl->hw_flow,
+ cy_readl(&ch_ctrl->
+ hw_flow) | C_RS_CTS | C_RS_RTS);
+ } else {
+ cy_writel(&ch_ctrl->hw_flow,
+ cy_readl(&ch_ctrl->
+ hw_flow) & ~(C_RS_CTS | C_RS_RTS));
+ }
+ /* As the HW flow control is done in firmware, the driver
+ doesn't need to care about it */
+ info->flags &= ~ASYNC_CTS_FLOW;
+
+ /* XON/XOFF/XANY flow control flags */
+ sw_flow = 0;
+ if (iflag & IXON) {
+ sw_flow |= C_FL_OXX;
+ if (iflag & IXANY)
+ sw_flow |= C_FL_OIXANY;
+ }
+ cy_writel(&ch_ctrl->sw_flow, sw_flow);
- /* CD sensitivity */
- if (cflag & CLOCAL){
- info->flags &= ~ASYNC_CHECK_CD;
- }else{
- info->flags |= ASYNC_CHECK_CD;
- }
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ if (retval != 0) {
+ printk("cyc:set_line_char retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+
+ /* CD sensitivity */
+ if (cflag & CLOCAL) {
+ info->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ info->flags |= ASYNC_CHECK_CD;
+ }
- if(baud == 0){ /* baud rate is zero, turn off line */
- cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
+ if (baud == 0) { /* baud rate is zero, turn off line */
+ cy_writel(&ch_ctrl->rs_control,
+ cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping Z DTR\n");
+ printk("cyc:set_line_char dropping Z DTR\n");
#endif
- }else{
- cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
+ } else {
+ cy_writel(&ch_ctrl->rs_control,
+ cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising Z DTR\n");
+ printk("cyc:set_line_char raising Z DTR\n");
#endif
- }
+ }
- retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
- if (retval != 0){
- printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L);
+ if (retval != 0) {
+ printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
}
- }
-} /* set_line_char */
-
+} /* set_line_char */
static int
-get_serial_info(struct cyclades_port * info,
- struct serial_struct __user * retinfo)
+get_serial_info(struct cyclades_port *info,
+ struct serial_struct __user * retinfo)
{
- struct serial_struct tmp;
- struct cyclades_card *cinfo = &cy_card[info->card];
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
- tmp.irq = cinfo->irq;
- tmp.flags = info->flags;
- tmp.close_delay = info->close_delay;
- tmp.baud_base = info->baud;
- tmp.custom_divisor = info->custom_divisor;
- tmp.hub6 = 0; /*!!!*/
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo))?-EFAULT:0;
-} /* get_serial_info */
+ struct serial_struct tmp;
+ struct cyclades_card *cinfo = &cy_card[info->card];
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
+ tmp.irq = cinfo->irq;
+ tmp.flags = info->flags;
+ tmp.close_delay = info->close_delay;
+ tmp.baud_base = info->baud;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0; /*!!! */
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+} /* get_serial_info */
static int
-set_serial_info(struct cyclades_port * info,
- struct serial_struct __user * new_info)
+set_serial_info(struct cyclades_port *info,
+ struct serial_struct __user * new_info)
{
- struct serial_struct new_serial;
- struct cyclades_port old_info;
-
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.close_delay != info->close_delay) ||
- (new_serial.baud_base != info->baud) ||
- ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
- (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud = new_serial.baud_base;
- info->custom_divisor = new_serial.custom_divisor;
- info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->close_delay = new_serial.close_delay * HZ/100;
- info->closing_wait = new_serial.closing_wait * HZ/100;
+ struct serial_struct new_serial;
+ struct cyclades_port old_info;
+
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+ old_info = *info;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if (new_serial.close_delay != info->close_delay ||
+ new_serial.baud_base != info->baud ||
+ (new_serial.flags & ASYNC_FLAGS &
+ ~ASYNC_USR_MASK) !=
+ (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
+ return -EPERM;
+ info->flags = (info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK);
+ info->baud = new_serial.baud_base;
+ info->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->baud = new_serial.baud_base;
+ info->custom_divisor = new_serial.custom_divisor;
+ info->flags = (info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS);
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
check_and_exit:
- if (info->flags & ASYNC_INITIALIZED){
- set_line_char(info);
- return 0;
- }else{
- return startup(info);
- }
-} /* set_serial_info */
+ if (info->flags & ASYNC_INITIALIZED) {
+ set_line_char(info);
+ return 0;
+ } else {
+ return startup(info);
+ }
+} /* set_serial_info */
/*
* get_lsr_info - get line status register info
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
+static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
{
- int card, chip, channel, index;
- unsigned char status;
- unsigned int result;
- unsigned long flags;
- void __iomem *base_addr;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ int card, chip, channel, index;
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+ void __iomem *base_addr;
- CY_LOCK(info, flags);
- status = cy_readb(base_addr+(CySRER<<index)) & (CyTxRdy|CyTxMpty);
- CY_UNLOCK(info, flags);
- result = (status ? 0 : TIOCSER_TEMT);
- } else {
- /* Not supported yet */
- return -EINVAL;
- }
- return put_user(result, (unsigned long __user *) value);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ status = cy_readb(base_addr + (CySRER << index)) &
+ (CyTxRdy | CyTxMpty);
+ CY_UNLOCK(info, flags);
+ result = (status ? 0 : TIOCSER_TEMT);
+ } else {
+ /* Not supported yet */
+ return -EINVAL;
+ }
+ return put_user(result, (unsigned long __user *)value);
}
-static int
-cy_tiocmget(struct tty_struct *tty, struct file *file)
+static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int card,chip,channel,index;
- void __iomem *base_addr;
- unsigned long flags;
- unsigned char status;
- unsigned long lstatus;
- unsigned int result;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, chip, channel, index;
+ void __iomem *base_addr;
+ unsigned long flags;
+ unsigned char status;
+ unsigned long lstatus;
+ unsigned int result;
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+
+ if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ return -ENODEV;
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- status = cy_readb(base_addr+(CyMSVR1<<index));
- status |= cy_readb(base_addr+(CyMSVR2<<index));
- CY_UNLOCK(info, flags);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
- if (info->rtsdtr_inv) {
- result = ((status & CyRTS) ? TIOCM_DTR : 0)
- | ((status & CyDTR) ? TIOCM_RTS : 0);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
+ status = cy_readb(base_addr + (CyMSVR1 << index));
+ status |= cy_readb(base_addr + (CyMSVR2 << index));
+ CY_UNLOCK(info, flags);
+
+ if (info->rtsdtr_inv) {
+ result = ((status & CyRTS) ? TIOCM_DTR : 0) |
+ ((status & CyDTR) ? TIOCM_RTS : 0);
+ } else {
+ result = ((status & CyRTS) ? TIOCM_RTS : 0) |
+ ((status & CyDTR) ? TIOCM_DTR : 0);
+ }
+ result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
+ ((status & CyRI) ? TIOCM_RNG : 0) |
+ ((status & CyDSR) ? TIOCM_DSR : 0) |
+ ((status & CyCTS) ? TIOCM_CTS : 0);
} else {
- result = ((status & CyRTS) ? TIOCM_RTS : 0)
- | ((status & CyDTR) ? TIOCM_DTR : 0);
- }
- result |= ((status & CyDCD) ? TIOCM_CAR : 0)
- | ((status & CyRI) ? TIOCM_RNG : 0)
- | ((status & CyDSR) ? TIOCM_DSR : 0)
- | ((status & CyCTS) ? TIOCM_CTS : 0);
- } else {
- base_addr = cy_card[card].base_addr;
-
- if (cy_card[card].num_chips != -1){
- return -EINVAL;
- }
+ base_addr = cy_card[card].base_addr;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
- lstatus = cy_readl(&ch_ctrl[channel].rs_status);
- result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0)
- | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0)
- | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0)
- | ((lstatus & C_RS_RI) ? TIOCM_RNG : 0)
- | ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0)
- | ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
- }else{
- result = 0;
- return -ENODEV;
- }
+ if (cy_card[card].num_chips != -1) {
+ return -EINVAL;
+ }
- }
- return result;
-} /* cy_tiomget */
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ if (ISZLOADED(cy_card[card])) {
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+ lstatus = cy_readl(&ch_ctrl[channel].rs_status);
+ result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
+ ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
+ ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
+ ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
+ ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
+ ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
+ } else {
+ result = 0;
+ return -ENODEV;
+ }
+ }
+ return result;
+} /* cy_tiomget */
static int
cy_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int card,chip,channel,index;
- void __iomem *base_addr;
- unsigned long flags;
- struct FIRM_ID __iomem *firm_id;
- struct ZFW_CTRL __iomem *zfw_ctrl;
- struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
- int retval;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- if (set & TIOCM_RTS){
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- }
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- }
- CY_UNLOCK(info, flags);
- }
- if (set & TIOCM_DTR){
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- } else {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- }
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, chip, channel, index;
+ void __iomem *base_addr;
+ unsigned long flags;
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ int retval;
+
+ if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ return -ENODEV;
+
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ if (set & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ }
+ if (set & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_modem_info raising DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- } else {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
- }
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ } else {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ }
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr+(CyMSVR1<<index)),
- cy_readb(base_addr+(CyMSVR2<<index)));
+ printk("cyc:set_modem_info dropping DTR\n");
+ printk(" status: 0x%x, 0x%x\n",
+ cy_readb(base_addr + (CyMSVR1 << index)),
+ cy_readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
- }
- } else {
- base_addr = cy_card[card].base_addr;
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
- board_ctrl = &zfw_ctrl->board_ctrl;
- ch_ctrl = zfw_ctrl->ch_ctrl;
-
- if (set & TIOCM_RTS){
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
- CY_UNLOCK(info, flags);
- }
- if (set & TIOCM_DTR){
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
+ CY_UNLOCK(info, flags);
+ }
+ } else {
+ base_addr = cy_card[card].base_addr;
+
+ firm_id = cy_card[card].base_addr + ID_ADDRESS;
+ if (ISZLOADED(cy_card[card])) {
+ zfw_ctrl = cy_card[card].base_addr +
+ (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ board_ctrl = &zfw_ctrl->board_ctrl;
+ ch_ctrl = zfw_ctrl->ch_ctrl;
+
+ if (set & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) | C_RS_RTS);
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_RTS) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) & ~C_RS_RTS);
+ CY_UNLOCK(info, flags);
+ }
+ if (set & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising Z DTR\n");
+ printk("cyc:set_modem_info raising Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
- }
- if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
- cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
+ CY_UNLOCK(info, flags);
+ }
+ if (clear & TIOCM_DTR) {
+ CY_LOCK(info, flags);
+ cy_writel(&ch_ctrl[channel].rs_control,
+ cy_readl(&ch_ctrl[channel].
+ rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info clearing Z DTR\n");
+ printk("cyc:set_modem_info clearing Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
- }
- }else{
- return -ENODEV;
- }
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM,0L);
- if (retval != 0){
- printk("cyc:set_modem_info retval on ttyC%d was %x\n",
- info->line, retval);
+ CY_UNLOCK(info, flags);
+ }
+ } else {
+ return -ENODEV;
+ }
+ CY_LOCK(info, flags);
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ channel, C_CM_IOCTLM, 0L);
+ if (retval != 0) {
+ printk("cyc:set_modem_info retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
}
- CY_UNLOCK(info, flags);
- }
- return 0;
-} /* cy_tiocmset */
+ return 0;
+} /* cy_tiocmset */
/*
* cy_break() --- routine which turns the break handling on or off
*/
-static void
-cy_break(struct tty_struct *tty, int break_state)
+static void cy_break(struct tty_struct *tty, int break_state)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "cy_break"))
- return;
-
- CY_LOCK(info, flags);
- if (!IS_CYC_Z(cy_card[info->card])) {
- /* Let the transmit ISR take care of this (since it
- requires stuffing characters into the output stream).
- */
- if (break_state == -1) {
- if (!info->breakon) {
- info->breakon = 1;
- if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
- start_xmit(info);
- CY_LOCK(info, flags);
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->name, "cy_break"))
+ return;
+
+ CY_LOCK(info, flags);
+ if (!IS_CYC_Z(cy_card[info->card])) {
+ /* Let the transmit ISR take care of this (since it
+ requires stuffing characters into the output stream).
+ */
+ if (break_state == -1) {
+ if (!info->breakon) {
+ info->breakon = 1;
+ if (!info->xmit_cnt) {
+ CY_UNLOCK(info, flags);
+ start_xmit(info);
+ CY_LOCK(info, flags);
+ }
+ }
+ } else {
+ if (!info->breakoff) {
+ info->breakoff = 1;
+ if (!info->xmit_cnt) {
+ CY_UNLOCK(info, flags);
+ start_xmit(info);
+ CY_LOCK(info, flags);
+ }
+ }
}
- }
} else {
- if (!info->breakoff) {
- info->breakoff = 1;
- if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
- start_xmit(info);
- CY_LOCK(info, flags);
+ int retval;
+
+ if (break_state == -1) {
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ info->line - cy_card[info->card].first_line,
+ C_CM_SET_BREAK, 0L);
+ if (retval != 0) {
+ printk("cyc:cy_break (set) retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
+ } else {
+ retval = cyz_issue_cmd(&cy_card[info->card],
+ info->line - cy_card[info->card].first_line,
+ C_CM_CLR_BREAK, 0L);
+ if (retval != 0) {
+ printk("cyc:cy_break (clr) retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
}
- }
}
- } else {
- int retval;
-
- if (break_state == -1) {
- retval = cyz_issue_cmd(&cy_card[info->card],
- (info->line) - (cy_card[info->card].first_line),
- C_CM_SET_BREAK, 0L);
- if (retval != 0) {
- printk("cyc:cy_break (set) retval on ttyC%d was %x\n",
- info->line, retval);
- }
- } else {
- retval = cyz_issue_cmd(&cy_card[info->card],
- (info->line) - (cy_card[info->card].first_line),
- C_CM_CLR_BREAK, 0L);
- if (retval != 0) {
- printk("cyc:cy_break (clr) retval on ttyC%d was %x\n",
- info->line, retval);
- }
- }
- }
- CY_UNLOCK(info, flags);
-} /* cy_break */
+ CY_UNLOCK(info, flags);
+} /* cy_break */
static int
-get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon)
+get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
{
- if(copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
- return -EFAULT;
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
-}/* get_mon_info */
-
+ if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
+ return -EFAULT;
+ info->mon.int_count = 0;
+ info->mon.char_count = 0;
+ info->mon.char_max = 0;
+ info->mon.char_last = 0;
+ return 0;
+} /* get_mon_info */
-static int
-set_threshold(struct cyclades_port * info, unsigned long value)
+static int set_threshold(struct cyclades_port *info, unsigned long value)
{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long flags;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- info->cor3 &= ~CyREC_FIFO;
- info->cor3 |= value & CyREC_FIFO;
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long flags;
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCOR3<<index), info->cor3);
- cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
- return 0;
-}/* set_threshold */
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ info->cor3 &= ~CyREC_FIFO;
+ info->cor3 |= value & CyREC_FIFO;
-static int
-get_threshold(struct cyclades_port * info, unsigned long __user *value)
-{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- tmp = cy_readb(base_addr+(CyCOR3<<index)) & CyREC_FIFO;
- return put_user(tmp,value);
- } else {
- // Nothing to do!
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
+ cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
return 0;
- }
-}/* get_threshold */
-
+} /* set_threshold */
static int
-set_default_threshold(struct cyclades_port * info, unsigned long value)
+get_threshold(struct cyclades_port *info, unsigned long __user * value)
{
- info->default_threshold = value & 0x0f;
- return 0;
-}/* set_default_threshold */
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long tmp;
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+ return put_user(tmp, value);
+ } else {
+ /* Nothing to do! */
+ return 0;
+ }
+} /* get_threshold */
static int
-get_default_threshold(struct cyclades_port * info, unsigned long __user *value)
+set_default_threshold(struct cyclades_port *info, unsigned long value)
{
- return put_user(info->default_threshold,value);
-}/* get_default_threshold */
-
+ info->default_threshold = value & 0x0f;
+ return 0;
+} /* set_default_threshold */
static int
-set_timeout(struct cyclades_port * info, unsigned long value)
+get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long flags;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
+ return put_user(info->default_threshold, value);
+} /* get_default_threshold */
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyRTPR<<index), value & 0xff);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
- return 0;
-}/* set_timeout */
+static int set_timeout(struct cyclades_port *info, unsigned long value)
+{
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long flags;
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
-static int
-get_timeout(struct cyclades_port * info, unsigned long __user *value)
-{
- void __iomem *base_addr;
- int card,channel,chip,index;
- unsigned long tmp;
-
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- tmp = cy_readb(base_addr+(CyRTPR<<index));
- return put_user(tmp,value);
- } else {
- // Nothing to do!
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
return 0;
- }
-}/* get_timeout */
+} /* set_timeout */
-
-static int
-set_default_timeout(struct cyclades_port * info, unsigned long value)
+static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
{
- info->default_timeout = value & 0xff;
- return 0;
-}/* set_default_timeout */
+ void __iomem *base_addr;
+ int card, channel, chip, index;
+ unsigned long tmp;
+
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr =
+ cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+
+ tmp = cy_readb(base_addr + (CyRTPR << index));
+ return put_user(tmp, value);
+ } else {
+ /* Nothing to do! */
+ return 0;
+ }
+} /* get_timeout */
+static int set_default_timeout(struct cyclades_port *info, unsigned long value)
+{
+ info->default_timeout = value & 0xff;
+ return 0;
+} /* set_default_timeout */
static int
-get_default_timeout(struct cyclades_port * info, unsigned long __user *value)
+get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
{
- return put_user(info->default_timeout,value);
-}/* get_default_timeout */
+ return put_user(info->default_timeout, value);
+} /* get_default_timeout */
/*
* This routine allows the tty driver to implement device-
* not recognized by the driver, it should return ENOIOCTLCMD.
*/
static int
-cy_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+cy_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- struct cyclades_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct __user *p_cuser; /* user space */
- int ret_val = 0;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
-
- if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
- return -ENODEV;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser; /* user space */
+ int ret_val = 0;
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
+
+ if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
+ return -ENODEV;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
- info->line, cmd, arg); /* */
+ printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
#endif
- switch (cmd) {
- case CYGETMON:
- ret_val = get_mon_info(info, argp);
- break;
- case CYGETTHRESH:
- ret_val = get_threshold(info, argp);
- break;
- case CYSETTHRESH:
- ret_val = set_threshold(info, arg);
- break;
- case CYGETDEFTHRESH:
- ret_val = get_default_threshold(info, argp);
- break;
- case CYSETDEFTHRESH:
- ret_val = set_default_threshold(info, arg);
- break;
- case CYGETTIMEOUT:
- ret_val = get_timeout(info, argp);
- break;
- case CYSETTIMEOUT:
- ret_val = set_timeout(info, arg);
- break;
- case CYGETDEFTIMEOUT:
- ret_val = get_default_timeout(info, argp);
- break;
- case CYSETDEFTIMEOUT:
- ret_val = set_default_timeout(info, arg);
- break;
+ switch (cmd) {
+ case CYGETMON:
+ ret_val = get_mon_info(info, argp);
+ break;
+ case CYGETTHRESH:
+ ret_val = get_threshold(info, argp);
+ break;
+ case CYSETTHRESH:
+ ret_val = set_threshold(info, arg);
+ break;
+ case CYGETDEFTHRESH:
+ ret_val = get_default_threshold(info, argp);
+ break;
+ case CYSETDEFTHRESH:
+ ret_val = set_default_threshold(info, arg);
+ break;
+ case CYGETTIMEOUT:
+ ret_val = get_timeout(info, argp);
+ break;
+ case CYSETTIMEOUT:
+ ret_val = set_timeout(info, arg);
+ break;
+ case CYGETDEFTIMEOUT:
+ ret_val = get_default_timeout(info, argp);
+ break;
+ case CYSETDEFTIMEOUT:
+ ret_val = set_default_timeout(info, arg);
+ break;
case CYSETRFLOW:
- info->rflow = (int)arg;
- ret_val = 0;
- break;
+ info->rflow = (int)arg;
+ ret_val = 0;
+ break;
case CYGETRFLOW:
- ret_val = info->rflow;
- break;
+ ret_val = info->rflow;
+ break;
case CYSETRTSDTR_INV:
- info->rtsdtr_inv = (int)arg;
- ret_val = 0;
- break;
+ info->rtsdtr_inv = (int)arg;
+ ret_val = 0;
+ break;
case CYGETRTSDTR_INV:
- ret_val = info->rtsdtr_inv;
- break;
+ ret_val = info->rtsdtr_inv;
+ break;
case CYGETCARDINFO:
- if (copy_to_user(argp, &cy_card[info->card],
- sizeof (struct cyclades_card))) {
- ret_val = -EFAULT;
+ if (copy_to_user(argp, &cy_card[info->card],
+ sizeof(struct cyclades_card))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ ret_val = 0;
break;
- }
- ret_val = 0;
- break;
case CYGETCD1400VER:
- ret_val = info->chip_rev;
- break;
+ ret_val = info->chip_rev;
+ break;
#ifndef CONFIG_CYZ_INTR
case CYZSETPOLLCYCLE:
- cyz_polling_cycle = (arg * HZ) / 1000;
- ret_val = 0;
- break;
+ cyz_polling_cycle = (arg * HZ) / 1000;
+ ret_val = 0;
+ break;
case CYZGETPOLLCYCLE:
- ret_val = (cyz_polling_cycle * 1000) / HZ;
- break;
-#endif /* CONFIG_CYZ_INTR */
+ ret_val = (cyz_polling_cycle * 1000) / HZ;
+ break;
+#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
- info->closing_wait = (unsigned short)arg * HZ/100;
- ret_val = 0;
- break;
+ info->closing_wait = (unsigned short)arg *HZ / 100;
+ ret_val = 0;
+ break;
case CYGETWAIT:
- ret_val = info->closing_wait / (HZ/100);
- break;
- case TIOCGSERIAL:
- ret_val = get_serial_info(info, argp);
- break;
- case TIOCSSERIAL:
- ret_val = set_serial_info(info, argp);
- break;
- case TIOCSERGETLSR: /* Get line status register */
- ret_val = get_lsr_info(info, argp);
- break;
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
+ ret_val = info->closing_wait / (HZ / 100);
+ break;
+ case TIOCGSERIAL:
+ ret_val = get_serial_info(info, argp);
+ break;
+ case TIOCSSERIAL:
+ ret_val = set_serial_info(info, argp);
+ break;
+ case TIOCSERGETLSR: /* Get line status register */
+ ret_val = get_lsr_info(info, argp);
+ break;
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
case TIOCMIWAIT:
- CY_LOCK(info, flags);
- /* note the counters on entry */
- cprev = info->icount;
- CY_UNLOCK(info, flags);
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
-
CY_LOCK(info, flags);
- cnow = info->icount; /* atomic copy */
+ /* note the counters on entry */
+ cprev = info->icount;
CY_UNLOCK(info, flags);
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+ }
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
- return -EIO; /* no change => error */
- }
- if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
+ CY_LOCK(info, flags);
+ cnow = info->icount; /* atomic copy */
+ CY_UNLOCK(info, flags);
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+ return -EIO; /* no change => error */
+ }
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
case TIOCGICOUNT:
- CY_LOCK(info, flags);
- cnow = info->icount;
- CY_UNLOCK(info, flags);
- p_cuser = argp;
- ret_val = put_user(cnow.cts, &p_cuser->cts);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.dsr, &p_cuser->dsr);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.rng, &p_cuser->rng);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.dcd, &p_cuser->dcd);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.rx, &p_cuser->rx);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.tx, &p_cuser->tx);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.frame, &p_cuser->frame);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.overrun, &p_cuser->overrun);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.parity, &p_cuser->parity);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.brk, &p_cuser->brk);
- if (ret_val) return ret_val;
- ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
- if (ret_val) return ret_val;
- ret_val = 0;
- break;
- default:
- ret_val = -ENOIOCTLCMD;
- }
+ CY_LOCK(info, flags);
+ cnow = info->icount;
+ CY_UNLOCK(info, flags);
+ p_cuser = argp;
+ ret_val = put_user(cnow.cts, &p_cuser->cts);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.dsr, &p_cuser->dsr);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.rng, &p_cuser->rng);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.dcd, &p_cuser->dcd);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.rx, &p_cuser->rx);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.tx, &p_cuser->tx);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.frame, &p_cuser->frame);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.overrun, &p_cuser->overrun);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.parity, &p_cuser->parity);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.brk, &p_cuser->brk);
+ if (ret_val)
+ return ret_val;
+ ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+ if (ret_val)
+ return ret_val;
+ ret_val = 0;
+ break;
+ default:
+ ret_val = -ENOIOCTLCMD;
+ }
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_ioctl done\n");
+ printk(" cyc:cy_ioctl done\n");
#endif
- return ret_val;
-} /* cy_ioctl */
-
+ return ret_val;
+} /* cy_ioctl */
/*
* This routine allows the tty driver to be notified when
* well-designed tty driver should be prepared to accept the case
* where old == NULL, and try to do something rational.
*/
-static void
-cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
+static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_set_termios ttyC%d\n", info->line);
+ printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
- if ((tty->termios->c_cflag == old_termios->c_cflag) &&
- ((tty->termios->c_iflag & (IXON|IXANY)) ==
- (old_termios->c_iflag & (IXON|IXANY))))
- return;
- set_line_char(info);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- cy_start(tty);
- }
+ if (tty->termios->c_cflag == old_termios->c_cflag &&
+ (tty->termios->c_iflag & (IXON | IXANY)) ==
+ (old_termios->c_iflag & (IXON | IXANY)))
+ return;
+ set_line_char(info);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ cy_start(tty);
+ }
#if 0
- /*
- * No need to wake up processes in open wait, since they
- * sample the CLOCAL flag once, and don't recheck it.
- * XXX It's not clear whether the current behavior is correct
- * or not. Hence, this may change.....
- */
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
+ /*
+ * No need to wake up processes in open wait, since they
+ * sample the CLOCAL flag once, and don't recheck it.
+ * XXX It's not clear whether the current behavior is correct
+ * or not. Hence, this may change.....
+ */
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
#endif
-
- return;
-} /* cy_set_termios */
+} /* cy_set_termios */
/* This function is used to send a high-priority XON/XOFF character to
the device.
*/
-static void
-cy_send_xchar (struct tty_struct *tty, char ch)
+static void cy_send_xchar(struct tty_struct *tty, char ch)
{
- struct cyclades_port *info = (struct cyclades_port *) tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
int card, channel;
- if (serial_paranoia_check (info, tty->name, "cy_send_xchar"))
+ if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
return;
- info->x_char = ch;
+ info->x_char = ch;
if (ch)
- cy_start (tty);
+ cy_start(tty);
card = info->card;
channel = info->line - cy_card[card].first_line;
- if (IS_CYC_Z (cy_card[card])) {
- if (ch == STOP_CHAR (tty))
- cyz_issue_cmd (&cy_card[card], channel, C_CM_SENDXOFF, 0L);
- else if (ch == START_CHAR (tty))
- cyz_issue_cmd (&cy_card[card], channel, C_CM_SENDXON, 0L);
+ if (IS_CYC_Z(cy_card[card])) {
+ if (ch == STOP_CHAR(tty))
+ cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF,
+ 0L);
+ else if (ch == START_CHAR(tty))
+ cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON,
+ 0L);
}
}
that incoming characters should be throttled because the input
buffers are close to full.
*/
-static void
-cy_throttle(struct tty_struct * tty)
+static void cy_throttle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
- char buf[64];
+ char buf[64];
- printk("cyc:throttle %s: %d....ttyC%d\n",
- tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty), info->line);
+ printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_throttle")){
- return;
- }
-
- card = info->card;
-
- if (I_IXOFF(tty)) {
- if (!IS_CYC_Z (cy_card[card]))
- cy_send_xchar (tty, STOP_CHAR (tty));
- else
- info->throttle = 1;
- }
-
- if (tty->termios->c_cflag & CRTSCTS) {
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), ~CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), ~CyRTS);
- }
- CY_UNLOCK(info, flags);
- } else {
- info->throttle = 1;
- }
- }
+ if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
+ return;
+ }
+
+ card = info->card;
- return;
-} /* cy_throttle */
+ if (I_IXOFF(tty)) {
+ if (!IS_CYC_Z(cy_card[card]))
+ cy_send_xchar(tty, STOP_CHAR(tty));
+ else
+ info->throttle = 1;
+ }
+ if (tty->termios->c_cflag & CRTSCTS) {
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ ~CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ ~CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ } else {
+ info->throttle = 1;
+ }
+ }
+} /* cy_throttle */
/*
* This routine notifies the tty driver that it should signal
* that characters can now be sent to the tty without fear of
* overrunning the input buffers of the line disciplines.
*/
-static void
-cy_unthrottle(struct tty_struct * tty)
+static void cy_unthrottle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- void __iomem *base_addr;
- int card,chip,channel,index;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ void __iomem *base_addr;
+ int card, chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
- char buf[64];
-
- printk("cyc:unthrottle %s: %d....ttyC%d\n",
- tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty), info->line);
-#endif
+ char buf[64];
- if (serial_paranoia_check(info, tty->name, "cy_unthrottle")){
- return;
- }
+ printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty), info->line);
+#endif
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- cy_send_xchar (tty, START_CHAR (tty));
- }
-
- if (tty->termios->c_cflag & CRTSCTS) {
- card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
- chip = channel>>2;
- channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index), (u_char)channel);
- if (info->rtsdtr_inv) {
- cy_writeb(base_addr+(CyMSVR2<<index), CyDTR);
- } else {
- cy_writeb(base_addr+(CyMSVR1<<index), CyRTS);
- }
- CY_UNLOCK(info, flags);
- } else {
- info->throttle = 0;
+ if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
+ return;
}
- }
- return;
-} /* cy_unthrottle */
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ cy_send_xchar(tty, START_CHAR(tty));
+ }
+ if (tty->termios->c_cflag & CRTSCTS) {
+ card = info->card;
+ channel = info->line - cy_card[card].first_line;
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = cy_card[card].base_addr +
+ (cy_chip_offset[chip] << index);
+
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) channel);
+ if (info->rtsdtr_inv) {
+ cy_writeb(base_addr + (CyMSVR2 << index),
+ CyDTR);
+ } else {
+ cy_writeb(base_addr + (CyMSVR1 << index),
+ CyRTS);
+ }
+ CY_UNLOCK(info, flags);
+ } else {
+ info->throttle = 0;
+ }
+ }
+} /* cy_unthrottle */
/* cy_start and cy_stop provide software output flow control as a
function of XON/XOFF, software CTS, and other such stuff.
*/
-static void
-cy_stop(struct tty_struct *tty)
+static void cy_stop(struct tty_struct *tty)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- void __iomem *base_addr;
- int chip,channel,index;
- unsigned long flags;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ void __iomem *base_addr;
+ int chip, channel, index;
+ unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+ printk("cyc:cy_stop ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_stop"))
- return;
-
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
- if (!IS_CYC_Z(*cinfo)) {
- index = cinfo->bus_index;
- chip = channel>>2;
- channel &= 0x03;
- base_addr = cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index),
- (u_char)(channel & 0x0003)); /* index channel */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
+ if (serial_paranoia_check(info, tty->name, "cy_stop"))
+ return;
- return;
-} /* cy_stop */
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ if (!IS_CYC_Z(*cinfo)) {
+ index = cinfo->bus_index;
+ chip = channel >> 2;
+ channel &= 0x03;
+ base_addr = cy_card[info->card].base_addr +
+ (cy_chip_offset[chip] << index);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char)(channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
+} /* cy_stop */
-static void
-cy_start(struct tty_struct *tty)
+static void cy_start(struct tty_struct *tty)
{
- struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- void __iomem *base_addr;
- int chip,channel,index;
- unsigned long flags;
+ struct cyclades_card *cinfo;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ void __iomem *base_addr;
+ int chip, channel, index;
+ unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_start ttyC%d\n", info->line); /* */
+ printk("cyc:cy_start ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_start"))
- return;
-
- cinfo = &cy_card[info->card];
- channel = info->line - cinfo->first_line;
- index = cinfo->bus_index;
- if (!IS_CYC_Z(*cinfo)) {
- chip = channel>>2;
- channel &= 0x03;
- base_addr = cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index);
-
- CY_LOCK(info, flags);
- cy_writeb(base_addr+(CyCAR<<index),
- (u_char)(channel & 0x0003)); /* index channel */
- cy_writeb(base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- // Nothing to do!
- }
+ if (serial_paranoia_check(info, tty->name, "cy_start"))
+ return;
- return;
-} /* cy_start */
+ cinfo = &cy_card[info->card];
+ channel = info->line - cinfo->first_line;
+ index = cinfo->bus_index;
+ if (!IS_CYC_Z(*cinfo)) {
+ chip = channel >> 2;
+ channel &= 0x03;
+ base_addr = cy_card[info->card].base_addr +
+ (cy_chip_offset[chip] << index);
+ CY_LOCK(info, flags);
+ cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CySRER << index),
+ cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
+ CY_UNLOCK(info, flags);
+ } else {
+ /* Nothing to do! */
+ }
+} /* cy_start */
-static void
-cy_flush_buffer(struct tty_struct *tty)
+static void cy_flush_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel, retval;
- unsigned long flags;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, channel, retval;
+ unsigned long flags;
+
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+ printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
- return;
-
- card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
+ return;
- CY_LOCK(info, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- CY_UNLOCK(info, flags);
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
- if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
- buffers as well */
CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
- if (retval != 0) {
- printk("cyc: flush_buffer retval on ttyC%d was %x\n",
- info->line, retval);
- }
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
CY_UNLOCK(info, flags);
- }
- tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
-} /* cy_flush_buffer */
+ if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
+ buffers as well */
+ CY_LOCK(info, flags);
+ retval =
+ cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
+ if (retval != 0) {
+ printk("cyc: flush_buffer retval on ttyC%d was %x\n",
+ info->line, retval);
+ }
+ CY_UNLOCK(info, flags);
+ }
+ tty_wakeup(tty);
+ wake_up_interruptible(&tty->write_wait);
+} /* cy_flush_buffer */
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-static void
-cy_hangup(struct tty_struct *tty)
+static void cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
+ printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_hangup"))
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_hangup"))
+ return;
- cy_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
+ cy_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
+ printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
#endif
- info->tty = NULL;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
-
+ info->tty = NULL;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
/*
* ---------------------------------------------------------------------
/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
static unsigned short __init
-cyy_init_card(void __iomem *true_base_addr,int index)
+cyy_init_card(void __iomem * true_base_addr, int index)
{
- unsigned int chip_number;
- void __iomem *base_addr;
-
- cy_writeb(true_base_addr+(Cy_HwReset<<index), 0);
- /* Cy_HwReset is 0x1400 */
- cy_writeb(true_base_addr+(Cy_ClrIntr<<index), 0);
- /* Cy_ClrIntr is 0x1800 */
- udelay(500L);
-
- for(chip_number=0; chip_number<CyMAX_CHIPS_PER_CARD; chip_number++){
- base_addr = true_base_addr + (cy_chip_offset[chip_number]<<index);
- mdelay(1);
- if(cy_readb(base_addr+(CyCCR<<index)) != 0x00){
- /*************
- printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
- chip_number, (unsigned long)base_addr);
- *************/
- return chip_number;
- }
-
- cy_writeb(base_addr+(CyGFRCR<<index), 0);
- udelay(10L);
-
- /* The Cyclom-16Y does not decode address bit 9 and therefore
- cannot distinguish between references to chip 0 and a non-
- existent chip 4. If the preceding clearing of the supposed
- chip 4 GFRCR register appears at chip 0, there is no chip 4
- and this must be a Cyclom-16Y, not a Cyclom-32Ye.
- */
- if (chip_number == 4
- && cy_readb(true_base_addr
- + (cy_chip_offset[0]<<index)
- + (CyGFRCR<<index)) == 0){
- return chip_number;
- }
-
- cy_writeb(base_addr+(CyCCR<<index), CyCHIP_RESET);
- mdelay(1);
-
- if(cy_readb(base_addr+(CyGFRCR<<index)) == 0x00){
- /*
- printk(" chip #%d at %#6lx is not responding ",
- chip_number, (unsigned long)base_addr);
- printk("(GFRCR stayed 0)\n",
- */
- return chip_number;
- }
- if((0xf0 & (cy_readb(base_addr+(CyGFRCR<<index)))) != 0x40){
- /*
- printk(" chip #%d at %#6lx is not valid (GFRCR == %#2x)\n",
- chip_number, (unsigned long)base_addr,
- base_addr[CyGFRCR<<index]);
- */
- return chip_number;
- }
- cy_writeb(base_addr+(CyGCR<<index), CyCH0_SERIAL);
- if (cy_readb(base_addr+(CyGFRCR<<index)) >= CD1400_REV_J){
- /* It is a CD1400 rev. J or later */
- /* Impossible to reach 5ms with this chip.
- Changed to 2ms instead (f = 500 Hz). */
- cy_writeb(base_addr+(CyPPR<<index), CyCLOCK_60_2MS);
- } else {
- /* f = 200 Hz */
- cy_writeb(base_addr+(CyPPR<<index), CyCLOCK_25_5MS);
- }
+ unsigned int chip_number;
+ void __iomem *base_addr;
+
+ cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
+ /* Cy_HwReset is 0x1400 */
+ cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
+ /* Cy_ClrIntr is 0x1800 */
+ udelay(500L);
+
+ for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
+ base_addr =
+ true_base_addr + (cy_chip_offset[chip_number] << index);
+ mdelay(1);
+ if (cy_readb(base_addr + (CyCCR << index)) != 0x00) {
+ /*************
+ printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
+ chip_number, (unsigned long)base_addr);
+ *************/
+ return chip_number;
+ }
+
+ cy_writeb(base_addr + (CyGFRCR << index), 0);
+ udelay(10L);
+
+ /* The Cyclom-16Y does not decode address bit 9 and therefore
+ cannot distinguish between references to chip 0 and a non-
+ existent chip 4. If the preceding clearing of the supposed
+ chip 4 GFRCR register appears at chip 0, there is no chip 4
+ and this must be a Cyclom-16Y, not a Cyclom-32Ye.
+ */
+ if (chip_number == 4 && cy_readb(true_base_addr +
+ (cy_chip_offset[0] << index) +
+ (CyGFRCR << index)) == 0) {
+ return chip_number;
+ }
+
+ cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
+ mdelay(1);
+
+ if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) {
+ /*
+ printk(" chip #%d at %#6lx is not responding ",
+ chip_number, (unsigned long)base_addr);
+ printk("(GFRCR stayed 0)\n",
+ */
+ return chip_number;
+ }
+ if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) !=
+ 0x40) {
+ /*
+ printk(" chip #%d at %#6lx is not valid (GFRCR == "
+ "%#2x)\n",
+ chip_number, (unsigned long)base_addr,
+ base_addr[CyGFRCR<<index]);
+ */
+ return chip_number;
+ }
+ cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
+ if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ /* Impossible to reach 5ms with this chip.
+ Changed to 2ms instead (f = 500 Hz). */
+ cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
+ } else {
+ /* f = 200 Hz */
+ cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
+ }
- /*
- printk(" chip #%d at %#6lx is rev 0x%2x\n",
- chip_number, (unsigned long)base_addr,
- cy_readb(base_addr+(CyGFRCR<<index)));
- */
- }
- return chip_number;
-} /* cyy_init_card */
+ /*
+ printk(" chip #%d at %#6lx is rev 0x%2x\n",
+ chip_number, (unsigned long)base_addr,
+ cy_readb(base_addr+(CyGFRCR<<index)));
+ */
+ }
+ return chip_number;
+} /* cyy_init_card */
/*
* ---------------------------------------------------------------------
* sets global variables and return the number of ISA boards found.
* ---------------------------------------------------------------------
*/
-static int __init
-cy_detect_isa(void)
+static int __init cy_detect_isa(void)
{
#ifdef CONFIG_ISA
- unsigned short cy_isa_irq,nboard;
- void __iomem *cy_isa_address;
- unsigned short i,j,cy_isa_nchan;
+ unsigned short cy_isa_irq, nboard;
+ void __iomem *cy_isa_address;
+ unsigned short i, j, cy_isa_nchan;
#ifdef MODULE
- int isparam = 0;
+ int isparam = 0;
#endif
- nboard = 0;
+ nboard = 0;
#ifdef MODULE
/* Check for module parameters */
- for(i = 0 ; i < NR_CARDS; i++) {
- if (maddr[i] || i) {
- isparam = 1;
- cy_isa_addresses[i] = maddr[i];
- }
- if (!maddr[i])
- break;
+ for (i = 0; i < NR_CARDS; i++) {
+ if (maddr[i] || i) {
+ isparam = 1;
+ cy_isa_addresses[i] = maddr[i];
+ }
+ if (!maddr[i])
+ break;
}
#endif
- /* scan the address table probing for Cyclom-Y/ISA boards */
- for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
- unsigned int isa_address = cy_isa_addresses[i];
- if (isa_address == 0x0000) {
- return(nboard);
- }
+ /* scan the address table probing for Cyclom-Y/ISA boards */
+ for (i = 0; i < NR_ISA_ADDRS; i++) {
+ unsigned int isa_address = cy_isa_addresses[i];
+ if (isa_address == 0x0000) {
+ return nboard;
+ }
- /* probe for CD1400... */
+ /* probe for CD1400... */
cy_isa_address = ioremap(isa_address, CyISA_Ywin);
- cy_isa_nchan = CyPORTS_PER_CHIP *
- cyy_init_card(cy_isa_address,0);
- if (cy_isa_nchan == 0) {
- continue;
- }
-
+ cy_isa_nchan = CyPORTS_PER_CHIP *
+ cyy_init_card(cy_isa_address, 0);
+ if (cy_isa_nchan == 0) {
+ continue;
+ }
#ifdef MODULE
if (isparam && irq[i])
- cy_isa_irq = irq[i];
+ cy_isa_irq = irq[i];
else
#endif
- /* find out the board's irq by probing */
- cy_isa_irq = detect_isa_irq(cy_isa_address);
- if (cy_isa_irq == 0) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but the IRQ could not be detected.\n");
- continue;
- }
-
- if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but no more channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(nboard);
- }
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but no more cards can be used .\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(nboard);
- }
-
- /* allocate IRQ */
- if(request_irq(cy_isa_irq, cyy_interrupt,
- IRQF_DISABLED, "Cyclom-Y", &cy_card[j]))
- {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long) cy_isa_address);
- printk("but could not allocate IRQ#%d.\n",
- cy_isa_irq);
- return(nboard);
- }
-
- /* set cy_card */
- cy_card[j].base_addr = cy_isa_address;
- cy_card[j].ctl_addr = 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/4;
- nboard++;
-
- /* print message */
- printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1, (unsigned long) cy_isa_address,
- (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
- cy_isa_irq);
- printk("%d channels starting from port %d.\n",
- cy_isa_nchan, cy_next_channel);
- cy_next_channel += cy_isa_nchan;
- }
- return(nboard);
+ /* find out the board's irq by probing */
+ cy_isa_irq = detect_isa_irq(cy_isa_address);
+ if (cy_isa_irq == 0) {
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but the IRQ could not be detected.\n");
+ continue;
+ }
+
+ if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but no more channels are available.\n");
+ printk("Change NR_PORTS in cyclades.c and recompile "
+ "kernel.\n");
+ return nboard;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but no more cards can be used .\n");
+ printk("Change NR_CARDS in cyclades.c and recompile "
+ "kernel.\n");
+ return nboard;
+ }
+
+ /* allocate IRQ */
+ if (request_irq(cy_isa_irq, cyy_interrupt,
+ IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
+ printk("Cyclom-Y/ISA found at 0x%lx ",
+ (unsigned long)cy_isa_address);
+ printk("but could not allocate IRQ#%d.\n", cy_isa_irq);
+ return nboard;
+ }
+
+ /* set cy_card */
+ cy_card[j].base_addr = cy_isa_address;
+ cy_card[j].ctl_addr = 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 / 4;
+ nboard++;
+
+ /* print message */
+ printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
+ j + 1, (unsigned long)cy_isa_address,
+ (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
+ cy_isa_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_isa_nchan, cy_next_channel);
+ cy_next_channel += cy_isa_nchan;
+ }
+ return nboard;
#else
- return(0);
-#endif /* CONFIG_ISA */
-} /* cy_detect_isa */
+ return 0;
+#endif /* CONFIG_ISA */
+} /* cy_detect_isa */
-static void
-plx_init(void __iomem *addr, uclong initctl)
+static void plx_init(void __iomem * addr, uclong initctl)
{
- /* Reset PLX */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
- udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
-
- /* Reload Config. Registers from EEPROM */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
- udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+ /* Reset PLX */
+ cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+ udelay(100L);
+ cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+
+ /* Reload Config. Registers from EEPROM */
+ cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+ udelay(100L);
+ cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
}
/*
* sets global variables and return the number of PCI boards found.
* ---------------------------------------------------------------------
*/
-static int __init
-cy_detect_pci(void)
+static int __init cy_detect_pci(void)
{
#ifdef CONFIG_PCI
- struct pci_dev *pdev = NULL;
- unsigned char cyy_rev_id;
- unsigned char cy_pci_irq = 0;
- uclong cy_pci_phys0, cy_pci_phys2;
- void __iomem *cy_pci_addr0, *cy_pci_addr2;
- unsigned short i,j,cy_pci_nchan, plx_ver;
- unsigned short device_id,dev_index = 0;
- uclong mailbox;
- uclong ZeIndex = 0;
- void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
- uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
- unsigned char Ze_irq[NR_CARDS];
- struct pci_dev *Ze_pdev[NR_CARDS];
-
- for (i = 0; i < NR_CARDS; i++) {
- /* look for a Cyclades card by vendor and device id */
- while((device_id = cy_pci_dev_id[dev_index]) != 0) {
- if((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
- device_id, pdev)) == NULL) {
- dev_index++; /* try next device id */
- } else {
- break; /* found a board */
- }
- }
+ struct pci_dev *pdev = NULL;
+ unsigned char cyy_rev_id;
+ unsigned char cy_pci_irq = 0;
+ uclong cy_pci_phys0, cy_pci_phys2;
+ void __iomem *cy_pci_addr0, *cy_pci_addr2;
+ unsigned short i, j, cy_pci_nchan, plx_ver;
+ unsigned short device_id, dev_index = 0;
+ uclong mailbox;
+ uclong ZeIndex = 0;
+ void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
+ uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
+ unsigned char Ze_irq[NR_CARDS];
+ struct pci_dev *Ze_pdev[NR_CARDS];
+
+ for (i = 0; i < NR_CARDS; i++) {
+ /* look for a Cyclades card by vendor and device id */
+ while ((device_id = cy_pci_dev_id[dev_index]) != 0) {
+ if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
+ device_id, pdev)) == NULL) {
+ dev_index++; /* try next device id */
+ } else {
+ break; /* found a board */
+ }
+ }
if (device_id == 0)
- break;
+ break;
if (pci_enable_device(pdev))
- continue;
+ continue;
- /* read PCI configuration area */
+ /* read PCI configuration area */
cy_pci_irq = pdev->irq;
cy_pci_phys0 = pci_resource_start(pdev, 0);
cy_pci_phys2 = pci_resource_start(pdev, 2);
device_id &= ~PCI_DEVICE_ID_MASK;
- if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
- || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Y/PCI:found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
#endif
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly set. "
- "Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
-
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve PCI resources\n");
- continue;
- }
+ if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+ printk(" Warning: PCI I/O bit incorrectly "
+ "set. Ignoring it...\n");
+ pdev->resource[2].flags &= ~IORESOURCE_IO;
+ }
+ /* Although we don't use this I/O region, we should
+ request it from the kernel anyway, to avoid problems
+ with other drivers accessing it. */
+ if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
+ printk(KERN_ERR "cyclades: failed to reserve "
+ "PCI resources\n");
+ continue;
+ }
#if defined(__alpha__)
- if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
- printk("Cyclom-Y/PCI not supported for low addresses in "
- "Alpha systems.\n");
- i--;
- continue;
- }
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
+ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclom-Y/PCI:found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong)cy_pci_phys2,
+ (ulong)cy_pci_phys0);
+ printk("Cyclom-Y/PCI not supported for low "
+ "addresses in Alpha systems.\n");
+ i--;
+ continue;
+ }
#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
+ cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
+ cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
+ printk("Cyclom-Y/PCI: relocate winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
#endif
- cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
- cyy_init_card(cy_pci_addr2, 1));
- if(cy_pci_nchan == 0) {
- printk("Cyclom-Y PCI host card with ");
- printk("no Serial-Modules at 0x%lx.\n",
- (ulong) cy_pci_phys2);
- i--;
- continue;
- }
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(i);
- }
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(i);
- }
-
- /* allocate IRQ */
- if(request_irq(cy_pci_irq, cyy_interrupt,
- IRQF_SHARED, "Cyclom-Y", &cy_card[j]))
- {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return(i);
- }
-
- /* set cy_card */
- cy_card[j].base_phys = (ulong)cy_pci_phys2;
- cy_card[j].ctl_phys = (ulong)cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_pci_nchan/4;
- cy_card[j].pdev = pdev;
-
- /* enable interrupts in the PCI interface */
- plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
- switch (plx_ver) {
- case PLX_9050:
-
- cy_writeb(cy_pci_addr0+0x4c, 0x43);
- break;
-
- case PLX_9060:
- case PLX_9080:
- default: /* Old boards, use PLX_9060 */
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
-
- cy_writew(cy_pci_addr0+0x68,
- cy_readw(cy_pci_addr0+0x68)|0x0900);
- break;
- }
+ cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
+ cyy_init_card(cy_pci_addr2, 1));
+ if (cy_pci_nchan == 0) {
+ printk("Cyclom-Y PCI host card with ");
+ printk("no Serial-Modules at 0x%lx.\n",
+ (ulong) cy_pci_phys2);
+ i--;
+ continue;
+ }
+ if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclom-Y/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but no channels are available.\n");
+ printk("Change NR_PORTS in cyclades.c and "
+ "recompile kernel.\n");
+ return i;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclom-Y/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but no more cards can be used.\n");
+ printk("Change NR_CARDS in cyclades.c and "
+ "recompile kernel.\n");
+ return i;
+ }
- /* print message */
- printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1,
- (ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Ywin - 1),
- (int)cy_pci_irq);
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
-
- cy_next_channel += cy_pci_nchan;
- }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
- /* print message */
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
- printk("Cyclades-Z/PCI not supported for low addresses\n");
- break;
- }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
+ /* allocate IRQ */
+ if (request_irq(cy_pci_irq, cyy_interrupt,
+ IRQF_SHARED, "Cyclom-Y", &cy_card[j])) {
+ printk("Cyclom-Y/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but could not allocate IRQ%d.\n",
+ cy_pci_irq);
+ return i;
+ }
+
+ /* set cy_card */
+ cy_card[j].base_phys = (ulong) cy_pci_phys2;
+ cy_card[j].ctl_phys = (ulong) cy_pci_phys0;
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int)cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = cy_pci_nchan / 4;
+ cy_card[j].pdev = pdev;
+
+ /* enable interrupts in the PCI interface */
+ plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
+ switch (plx_ver) {
+ case PLX_9050:
+
+ cy_writeb(cy_pci_addr0 + 0x4c, 0x43);
+ break;
+
+ case PLX_9060:
+ case PLX_9080:
+ default: /* Old boards, use PLX_9060 */
+
+ plx_init(cy_pci_addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+ cy_pci_irq);
+
+ cy_writew(cy_pci_addr0 + 0x68,
+ cy_readw(cy_pci_addr0 +
+ 0x68) | 0x0900);
+ break;
+ }
+
+ /* print message */
+ printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+ j + 1, (ulong)cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1),
+ (int)cy_pci_irq);
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+
+ cy_next_channel += cy_pci_nchan;
+ } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
+ /* print message */
+ printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclades-Z/PCI: found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+ printk("Cyclades-Z/PCI not supported for low "
+ "addresses\n");
+ break;
+ } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+ printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+ pdev->bus->number, pdev->devfn);
+ printk("rev_id=%d) IRQ%d\n",
+ cyy_rev_id, (int)cy_pci_irq);
+ printk("Cyclades-Z/PCI: found winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong) cy_pci_phys2, (ulong) cy_pci_phys0);
#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
-
- /* Disable interrupts on the PLX before resetting it */
- cy_writew(cy_pci_addr0+0x68,
- cy_readw(cy_pci_addr0+0x68) & ~0x0900);
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
-
- mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
-
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly set. "
- "Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
+ cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
+
+ /* Disable interrupts on the PLX before resetting it */
+ cy_writew(cy_pci_addr0 + 0x68,
+ cy_readw(cy_pci_addr0 + 0x68) & ~0x0900);
+
+ plx_init(cy_pci_addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+ cy_pci_irq);
+
+ mailbox =
+ (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
+ cy_pci_addr0)->mail_box_0);
+
+ if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+ printk(" Warning: PCI I/O bit incorrectly "
+ "set. Ignoring it...\n");
+ pdev->resource[2].flags &= ~IORESOURCE_IO;
+ }
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve PCI resources\n");
- continue;
- }
-
- if (mailbox == ZE_V1) {
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ze_win);
- if (ZeIndex == NR_CARDS) {
- printk("Cyclades-Ze/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- } else {
- Ze_phys0[ZeIndex] = cy_pci_phys0;
- Ze_phys2[ZeIndex] = cy_pci_phys2;
- Ze_addr0[ZeIndex] = cy_pci_addr0;
- Ze_addr2[ZeIndex] = cy_pci_addr2;
- Ze_irq[ZeIndex] = cy_pci_irq;
- Ze_pdev[ZeIndex] = pdev;
- ZeIndex++;
- }
- i--;
- continue;
- } else {
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Zwin);
- }
+ /* Although we don't use this I/O region, we should
+ request it from the kernel anyway, to avoid problems
+ with other drivers accessing it. */
+ if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
+ printk(KERN_ERR "cyclades: failed to reserve "
+ "PCI resources\n");
+ continue;
+ }
+
+ if (mailbox == ZE_V1) {
+ cy_pci_addr2 = ioremap(cy_pci_phys2,
+ CyPCI_Ze_win);
+ if (ZeIndex == NR_CARDS) {
+ printk("Cyclades-Ze/PCI found at "
+ "0x%lx but no more cards can "
+ "be used.\nChange NR_CARDS in "
+ "cyclades.c and recompile "
+ "kernel.\n",
+ (ulong)cy_pci_phys2);
+ } else {
+ Ze_phys0[ZeIndex] = cy_pci_phys0;
+ Ze_phys2[ZeIndex] = cy_pci_phys2;
+ Ze_addr0[ZeIndex] = cy_pci_addr0;
+ Ze_addr2[ZeIndex] = cy_pci_addr2;
+ Ze_irq[ZeIndex] = cy_pci_irq;
+ Ze_pdev[ZeIndex] = pdev;
+ ZeIndex++;
+ }
+ i--;
+ continue;
+ } else {
+ cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin);
+ }
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
- if (mailbox == ZO_V1) {
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base, WIN_CREG);
- PAUSE
- printk("Cyclades-8Zo/PCI: FPGA id %lx, ver %lx\n",
- (ulong)(0xff & cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->fpga_id)),
- (ulong)(0xff & cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->fpga_version)));
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base, WIN_RAM);
- } else {
- printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n");
- }
+ printk("Cyclades-Z/PCI: relocate winaddr=0x%lx "
+ "ctladdr=0x%lx\n",
+ (ulong) cy_pci_addr2, (ulong) cy_pci_addr0);
+ if (mailbox == ZO_V1) {
+ cy_writel(&((struct RUNTIME_9060 *)
+ (cy_pci_addr0))->loc_addr_base,
+ WIN_CREG);
+ PAUSE;
+ printk("Cyclades-8Zo/PCI: FPGA id %lx, ver "
+ "%lx\n", (ulong) (0xff &
+ cy_readl(&((struct CUSTOM_REG *)
+ (cy_pci_addr2))->fpga_id)),
+ (ulong)(0xff &
+ cy_readl(&((struct CUSTOM_REG *)
+ (cy_pci_addr2))->
+ fpga_version)));
+ cy_writel(&((struct RUNTIME_9060 *)
+ (cy_pci_addr0))->loc_addr_base,
+ WIN_RAM);
+ } else {
+ printk("Cyclades-Z/PCI: New Cyclades-Z board. "
+ "FPGA not loaded\n");
+ }
#endif
- /* The following clears the firmware id word. This ensures
- that the driver will not attempt to talk to the board
- until it has been properly initialized.
- */
- PAUSE
- if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
- cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
-
- /* This must be a Cyclades-8Zo/PCI. The extendable
- version will have a different device_id and will
- be allocated its maximum number of ports. */
- cy_pci_nchan = 8;
-
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-8Zo/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(i);
- }
-
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-8Zo/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(i);
- }
+ /* The following clears the firmware id word. This
+ ensures that the driver will not attempt to talk to
+ the board until it has been properly initialized.
+ */
+ PAUSE;
+ if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
+ cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
+
+ /* This must be a Cyclades-8Zo/PCI. The extendable
+ version will have a different device_id and will
+ be allocated its maximum number of ports. */
+ cy_pci_nchan = 8;
+
+ if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclades-8Zo/PCI found at 0x%lx but"
+ "no channels are available.\nChange "
+ "NR_PORTS in cyclades.c and recompile "
+ "kernel.\n", (ulong)cy_pci_phys2);
+ return i;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclades-8Zo/PCI found at 0x%lx but"
+ "no more cards can be used.\nChange "
+ "NR_CARDS in cyclades.c and recompile "
+ "kernel.\n", (ulong)cy_pci_phys2);
+ return i;
+ }
+#ifdef CONFIG_CYZ_INTR
+ /* allocate IRQ only if board has an IRQ */
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
+ if (request_irq(cy_pci_irq, cyz_interrupt,
+ IRQF_SHARED, "Cyclades-Z",
+ &cy_card[j])) {
+ printk("Cyclom-8Zo/PCI found at 0x%lx "
+ "but could not allocate "
+ "IRQ%d.\n", (ulong)cy_pci_phys2,
+ cy_pci_irq);
+ return i;
+ }
+ }
+#endif /* CONFIG_CYZ_INTR */
+
+ /* set cy_card */
+ cy_card[j].base_phys = cy_pci_phys2;
+ cy_card[j].ctl_phys = cy_pci_phys0;
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int)cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = -1;
+ cy_card[j].pdev = pdev;
+
+ /* print message */
#ifdef CONFIG_CYZ_INTR
- /* allocate IRQ only if board has an IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
- if(request_irq(cy_pci_irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z", &cy_card[j]))
- {
- printk("Cyclom-8Zo/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return(i);
- }
+ /* don't report IRQ if board is no IRQ */
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
+ printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, "
+ "IRQ%d, ", j + 1, (ulong)cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1),
+ (int)cy_pci_irq);
+ else
+#endif /* CONFIG_CYZ_INTR */
+ printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
+ j + 1, (ulong)cy_pci_phys2,
+ (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
+
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+ cy_next_channel += cy_pci_nchan;
}
-#endif /* CONFIG_CYZ_INTR */
-
-
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
- cy_card[j].pdev = pdev;
+ }
- /* print message */
-#ifdef CONFIG_CYZ_INTR
- /* don't report IRQ if board is no IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1),
- (int)cy_pci_irq);
- else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
-
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan,cy_next_channel);
- cy_next_channel += cy_pci_nchan;
- }
- }
-
- for (; ZeIndex != 0 && i < NR_CARDS; i++) {
- cy_pci_phys0 = Ze_phys0[0];
- cy_pci_phys2 = Ze_phys2[0];
- cy_pci_addr0 = Ze_addr0[0];
- cy_pci_addr2 = Ze_addr2[0];
- cy_pci_irq = Ze_irq[0];
- pdev = Ze_pdev[0];
- for (j = 0 ; j < ZeIndex-1 ; j++) {
- Ze_phys0[j] = Ze_phys0[j+1];
- Ze_phys2[j] = Ze_phys2[j+1];
- Ze_addr0[j] = Ze_addr0[j+1];
- Ze_addr2[j] = Ze_addr2[j+1];
- Ze_irq[j] = Ze_irq[j+1];
- Ze_pdev[j] = Ze_pdev[j+1];
- }
- ZeIndex--;
- mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
+ for (; ZeIndex != 0 && i < NR_CARDS; i++) {
+ cy_pci_phys0 = Ze_phys0[0];
+ cy_pci_phys2 = Ze_phys2[0];
+ cy_pci_addr0 = Ze_addr0[0];
+ cy_pci_addr2 = Ze_addr2[0];
+ cy_pci_irq = Ze_irq[0];
+ pdev = Ze_pdev[0];
+ for (j = 0; j < ZeIndex - 1; j++) {
+ Ze_phys0[j] = Ze_phys0[j + 1];
+ Ze_phys2[j] = Ze_phys2[j + 1];
+ Ze_addr0[j] = Ze_addr0[j + 1];
+ Ze_addr2[j] = Ze_addr2[j + 1];
+ Ze_irq[j] = Ze_irq[j + 1];
+ Ze_pdev[j] = Ze_pdev[j + 1];
+ }
+ ZeIndex--;
+ mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
+ cy_pci_addr0)->mail_box_0);
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
- printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n");
+ printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
+ (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
+ printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not "
+ "loaded\n");
#endif
- PAUSE
- /* This must be the new Cyclades-Ze/PCI. */
- cy_pci_nchan = ZE_V1_NPORTS;
-
- if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-Ze/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
- return(i);
- }
-
- /* fill the next cy_card structure available */
- for (j = 0 ; j < NR_CARDS ; j++) {
- if (cy_card[j].base_addr == 0) break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-Ze/PCI found at 0x%lx ",
- (ulong)cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
- return(i);
- }
+ PAUSE;
+ /* This must be the new Cyclades-Ze/PCI. */
+ cy_pci_nchan = ZE_V1_NPORTS;
+
+ if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
+ printk("Cyclades-Ze/PCI found at 0x%lx but no channels "
+ "are available.\nChange NR_PORTS in cyclades.c "
+ "and recompile kernel.\n",
+ (ulong) cy_pci_phys2);
+ return i;
+ }
+ /* fill the next cy_card structure available */
+ for (j = 0; j < NR_CARDS; j++) {
+ if (cy_card[j].base_addr == 0)
+ break;
+ }
+ if (j == NR_CARDS) { /* no more cy_cards available */
+ printk("Cyclades-Ze/PCI found at 0x%lx but no more "
+ "cards can be used.\nChange NR_CARDS in "
+ "cyclades.c and recompile kernel.\n",
+ (ulong) cy_pci_phys2);
+ return i;
+ }
#ifdef CONFIG_CYZ_INTR
- /* allocate IRQ only if board has an IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
- if(request_irq(cy_pci_irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z", &cy_card[j]))
- {
- printk("Cyclom-Ze/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return(i);
- }
+ /* allocate IRQ only if board has an IRQ */
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
+ if (request_irq(cy_pci_irq, cyz_interrupt,
+ IRQF_SHARED, "Cyclades-Z",
+ &cy_card[j])) {
+ printk("Cyclom-Ze/PCI found at 0x%lx ",
+ (ulong) cy_pci_phys2);
+ printk("but could not allocate IRQ%d.\n",
+ cy_pci_irq);
+ return i;
+ }
}
-#endif /* CONFIG_CYZ_INTR */
-
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int) cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
+#endif /* CONFIG_CYZ_INTR */
+
+ /* set cy_card */
+ cy_card[j].base_phys = cy_pci_phys2;
+ cy_card[j].ctl_phys = cy_pci_phys0;
+ cy_card[j].base_addr = cy_pci_addr2;
+ cy_card[j].ctl_addr = cy_pci_addr0;
+ cy_card[j].irq = (int)cy_pci_irq;
+ cy_card[j].bus_index = 1;
+ cy_card[j].first_line = cy_next_channel;
+ cy_card[j].num_chips = -1;
cy_card[j].pdev = pdev;
- /* print message */
+ /* print message */
#ifdef CONFIG_CYZ_INTR
/* don't report IRQ if board is no IRQ */
- if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Ze_win - 1),
- (int)cy_pci_irq);
+ if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
+ printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+ j + 1, (ulong) cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1),
+ (int)cy_pci_irq);
else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
- j+1,(ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Ze_win - 1));
-
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan,cy_next_channel);
- cy_next_channel += cy_pci_nchan;
- }
+#endif /* CONFIG_CYZ_INTR */
+ printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
+ j + 1, (ulong) cy_pci_phys2,
+ (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1));
+
+ printk("%d channels starting from port %d.\n",
+ cy_pci_nchan, cy_next_channel);
+ cy_next_channel += cy_pci_nchan;
+ }
if (ZeIndex != 0) {
- printk("Cyclades-Ze/PCI found at 0x%x ",
- (unsigned int) Ze_phys2[0]);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+ printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be "
+ "used.\nChange NR_CARDS in cyclades.c and recompile "
+ "kernel.\n", (unsigned int)Ze_phys2[0]);
}
- return(i);
+ return i;
#else
- return(0);
-#endif /* ifdef CONFIG_PCI */
-} /* cy_detect_pci */
-
+ return 0;
+#endif /* ifdef CONFIG_PCI */
+} /* cy_detect_pci */
/*
* This routine prints out the appropriate serial driver version number
* and identifies which options were configured into this driver.
*/
-static inline void
-show_version(void)
+static inline void show_version(void)
{
- char *rcsvers, *rcsdate, *tmp;
- rcsvers = strchr(rcsid, ' '); rcsvers++;
- tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
- rcsdate = strchr(tmp, ' '); rcsdate++;
- tmp = strrchr(rcsdate, ' '); *tmp = '\0';
- printk("Cyclades driver %s %s\n",
- rcsvers, rcsdate);
- printk(" built %s %s\n",
- __DATE__, __TIME__);
-} /* show_version */
-
-static int
+ printk("Cyclades driver " CY_VERSION "\n");
+ printk(" built %s %s\n", __DATE__, __TIME__);
+} /* show_version */
+
+static int
cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
- int *eof, void *data)
+ int *eof, void *data)
{
- struct cyclades_port *info;
- int i;
- int len=0;
- off_t begin=0;
- off_t pos=0;
- int size;
- __u32 cur_jifs = jiffies;
-
- size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn IdleIn Overruns Ldisc\n");
-
- pos += size;
- len += size;
-
- /* Output one line for each known port */
- for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
- info = &cy_port[i];
-
- if (info->count)
- size = sprintf(buf+len,
- "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
- info->line,
- JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ,
- info->idle_stats.xmit_bytes,
- JIFFIES_DIFF(info->idle_stats.xmit_idle, cur_jifs) / HZ,
- info->idle_stats.recv_bytes,
- JIFFIES_DIFF(info->idle_stats.recv_idle, cur_jifs) / HZ,
- info->idle_stats.overruns,
- (long) info->tty->ldisc.num);
- else
- size = sprintf(buf+len,
- "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
- info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ struct cyclades_port *info;
+ int i;
+ int len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+ int size;
+ __u32 cur_jifs = jiffies;
+
+ size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn "
+ "IdleIn Overruns Ldisc\n");
+
+ pos += size;
len += size;
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
+ /* Output one line for each known port */
+ for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
+ info = &cy_port[i];
+
+ if (info->count)
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
+ "%8lu %9lu %6ld\n", info->line,
+ (cur_jifs - info->idle_stats.in_use) / HZ,
+ info->idle_stats.xmit_bytes,
+ (cur_jifs - info->idle_stats.xmit_idle) / HZ,
+ info->idle_stats.recv_bytes,
+ (cur_jifs - info->idle_stats.recv_idle) / HZ,
+ info->idle_stats.overruns,
+ (long)info->tty->ldisc.num);
+ else
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
+ "%8lu %9lu %6ld\n",
+ info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto done;
}
- if (pos > offset + length)
- goto done;
- }
- *eof = 1;
+ *eof = 1;
done:
- *start = buf + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- if (len < 0)
- len = 0;
- return len;
+ *start = buf + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ if (len < 0)
+ len = 0;
+ return len;
}
/* The serial driver boot-time initialization code!
*/
static const struct tty_operations cy_ops = {
- .open = cy_open,
- .close = cy_close,
- .write = cy_write,
- .put_char = cy_put_char,
- .flush_chars = cy_flush_chars,
- .write_room = cy_write_room,
- .chars_in_buffer = cy_chars_in_buffer,
- .flush_buffer = cy_flush_buffer,
- .ioctl = cy_ioctl,
- .throttle = cy_throttle,
- .unthrottle = cy_unthrottle,
- .set_termios = cy_set_termios,
- .stop = cy_stop,
- .start = cy_start,
- .hangup = cy_hangup,
- .break_ctl = cy_break,
- .wait_until_sent = cy_wait_until_sent,
- .read_proc = cyclades_get_proc_info,
- .tiocmget = cy_tiocmget,
- .tiocmset = cy_tiocmset,
+ .open = cy_open,
+ .close = cy_close,
+ .write = cy_write,
+ .put_char = cy_put_char,
+ .flush_chars = cy_flush_chars,
+ .write_room = cy_write_room,
+ .chars_in_buffer = cy_chars_in_buffer,
+ .flush_buffer = cy_flush_buffer,
+ .ioctl = cy_ioctl,
+ .throttle = cy_throttle,
+ .unthrottle = cy_unthrottle,
+ .set_termios = cy_set_termios,
+ .stop = cy_stop,
+ .start = cy_start,
+ .hangup = cy_hangup,
+ .break_ctl = cy_break,
+ .wait_until_sent = cy_wait_until_sent,
+ .read_proc = cyclades_get_proc_info,
+ .tiocmget = cy_tiocmget,
+ .tiocmset = cy_tiocmset,
};
-static int __init
-cy_init(void)
+static int __init cy_init(void)
{
- struct cyclades_port *info;
- struct cyclades_card *cinfo;
- int number_z_boards = 0;
- int board,port,i,index;
- unsigned long mailbox;
- unsigned short chip_number;
- int nports;
-
- cy_serial_driver = alloc_tty_driver(NR_PORTS);
- if (!cy_serial_driver)
- return -ENOMEM;
- show_version();
-
- /* Initialize the tty_driver structure */
-
- cy_serial_driver->owner = THIS_MODULE;
- cy_serial_driver->driver_name = "cyclades";
- cy_serial_driver->name = "ttyC";
- cy_serial_driver->major = CYCLADES_MAJOR;
- cy_serial_driver->minor_start = 0;
- cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
- cy_serial_driver->init_termios = tty_std_termios;
- cy_serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(cy_serial_driver, &cy_ops);
-
- if (tty_register_driver(cy_serial_driver))
- panic("Couldn't register Cyclades serial driver\n");
-
- for (i = 0; i < NR_CARDS; i++) {
- /* base_addr=0 indicates board not found */
- cy_card[i].base_addr = NULL;
- }
-
- /* the code below is responsible to find the boards. Each different
- type of board has its own detection routine. If a board is found,
- the next cy_card structure available is set by the detection
- routine. These functions are responsible for checking the
- availability of cy_card and cy_port data structures and updating
- the cy_next_channel. */
-
- /* look for isa boards */
- cy_isa_nboard = cy_detect_isa();
-
- /* look for pci boards */
- cy_pci_nboard = cy_detect_pci();
-
- cy_nboard = cy_isa_nboard + cy_pci_nboard;
-
- /* invalidate remaining cy_card structures */
- for (i = 0 ; i < NR_CARDS ; i++) {
- if (cy_card[i].base_addr == 0) {
- cy_card[i].first_line = -1;
- cy_card[i].ctl_addr = NULL;
- cy_card[i].irq = 0;
- cy_card[i].bus_index = 0;
- cy_card[i].first_line = 0;
- cy_card[i].num_chips = 0;
- }
- }
- /* invalidate remaining cy_port structures */
- for (i = cy_next_channel ; i < NR_PORTS ; i++) {
- cy_port[i].line = -1;
- cy_port[i].magic = -1;
- }
-
- /* initialize per-port data structures for each valid board found */
- for (board = 0 ; board < cy_nboard ; board++) {
- cinfo = &cy_card[board];
- if (cinfo->num_chips == -1) { /* Cyclades-Z */
- number_z_boards++;
- mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_card[board].ctl_addr)->mail_box_0);
- nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
- cinfo->intr_enabled = 0;
- cinfo->nports = 0; /* Will be correctly set later, after
- Z FW is loaded */
- spin_lock_init(&cinfo->card_lock);
- for (port = cinfo->first_line ;
- port < cinfo->first_line + nports;
- port++)
- {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_STARTECH;
- info->card = board;
- info->line = port;
- info->chip_rev = 0;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- if (mailbox == ZO_V1)
- info->xmit_fifo_size = CYZ_FIFO_SIZE;
- else
- info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
- info->cor1 = 0;
- info->cor2 = 0;
- info->cor3 = 0;
- info->cor4 = 0;
- info->cor5 = 0;
- info->tbpr = 0;
- info->tco = 0;
- info->rbpr = 0;
- info->rco = 0;
- info->custom_divisor = 0;
- info->close_delay = 5*HZ/10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask = 0;
- /* info->timeout */
- /* Bentson's vars */
- info->jiffies[0] = 0;
- info->jiffies[1] = 0;
- info->jiffies[2] = 0;
- info->rflush_count = 0;
+ struct cyclades_port *info;
+ struct cyclades_card *cinfo;
+ int number_z_boards = 0;
+ int board, port, i, index;
+ unsigned long mailbox;
+ unsigned short chip_number;
+ int nports;
+
+ cy_serial_driver = alloc_tty_driver(NR_PORTS);
+ if (!cy_serial_driver)
+ return -ENOMEM;
+ show_version();
+
+ /* Initialize the tty_driver structure */
+
+ cy_serial_driver->owner = THIS_MODULE;
+ cy_serial_driver->driver_name = "cyclades";
+ cy_serial_driver->name = "ttyC";
+ cy_serial_driver->major = CYCLADES_MAJOR;
+ cy_serial_driver->minor_start = 0;
+ cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ cy_serial_driver->init_termios = tty_std_termios;
+ cy_serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(cy_serial_driver, &cy_ops);
+
+ if (tty_register_driver(cy_serial_driver))
+ panic("Couldn't register Cyclades serial driver\n");
+
+ for (i = 0; i < NR_CARDS; i++) {
+ /* base_addr=0 indicates board not found */
+ cy_card[i].base_addr = NULL;
+ }
+
+ /* the code below is responsible to find the boards. Each different
+ type of board has its own detection routine. If a board is found,
+ the next cy_card structure available is set by the detection
+ routine. These functions are responsible for checking the
+ availability of cy_card and cy_port data structures and updating
+ the cy_next_channel. */
+
+ /* look for isa boards */
+ cy_isa_nboard = cy_detect_isa();
+
+ /* look for pci boards */
+ cy_pci_nboard = cy_detect_pci();
+
+ cy_nboard = cy_isa_nboard + cy_pci_nboard;
+
+ /* invalidate remaining cy_card structures */
+ for (i = 0; i < NR_CARDS; i++) {
+ if (cy_card[i].base_addr == 0) {
+ cy_card[i].first_line = -1;
+ cy_card[i].ctl_addr = NULL;
+ cy_card[i].irq = 0;
+ cy_card[i].bus_index = 0;
+ cy_card[i].first_line = 0;
+ cy_card[i].num_chips = 0;
+ }
+ }
+ /* invalidate remaining cy_port structures */
+ for (i = cy_next_channel; i < NR_PORTS; i++) {
+ cy_port[i].line = -1;
+ cy_port[i].magic = -1;
+ }
+
+ /* initialize per-port data structures for each valid board found */
+ for (board = 0; board < cy_nboard; board++) {
+ cinfo = &cy_card[board];
+ if (cinfo->num_chips == -1) { /* Cyclades-Z */
+ number_z_boards++;
+ mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
+ cy_card[board].ctl_addr)->
+ mail_box_0);
+ nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+ cinfo->intr_enabled = 0;
+ cinfo->nports = 0; /* Will be correctly set later, after
+ Z FW is loaded */
+ spin_lock_init(&cinfo->card_lock);
+ for (port = cinfo->first_line;
+ port < cinfo->first_line + nports; port++) {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_STARTECH;
+ info->card = board;
+ info->line = port;
+ info->chip_rev = 0;
+ info->flags = STD_COM_FLAGS;
+ info->tty = NULL;
+ if (mailbox == ZO_V1)
+ info->xmit_fifo_size = CYZ_FIFO_SIZE;
+ else
+ info->xmit_fifo_size =
+ 4 * CYZ_FIFO_SIZE;
+ info->cor1 = 0;
+ info->cor2 = 0;
+ info->cor3 = 0;
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->tbpr = 0;
+ info->tco = 0;
+ info->rbpr = 0;
+ info->rco = 0;
+ info->custom_divisor = 0;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask = 0;
+ /* info->timeout */
+ /* Bentson's vars */
+ info->jiffies[0] = 0;
+ info->jiffies[1] = 0;
+ info->jiffies[2] = 0;
+ info->rflush_count = 0;
#ifdef CONFIG_CYZ_INTR
- init_timer(&cyz_rx_full_timer[port]);
- cyz_rx_full_timer[port].function = NULL;
+ init_timer(&cyz_rx_full_timer[port]);
+ cyz_rx_full_timer[port].function = NULL;
#endif
- }
- continue;
- }else{ /* Cyclom-Y of some kind*/
- index = cinfo->bus_index;
- spin_lock_init(&cinfo->card_lock);
- cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
- for (port = cinfo->first_line ;
- port < cinfo->first_line + cinfo->nports ;
- port++)
- {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = board;
- info->line = port;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- info->xmit_fifo_size = CyMAX_CHAR_FIFO;
- info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = 0x08; /* _very_ small rcv threshold */
- info->cor4 = 0;
- info->cor5 = 0;
- info->custom_divisor = 0;
- info->close_delay = 5*HZ/10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev =
- cy_readb(cinfo->base_addr +
- (cy_chip_offset[chip_number]<<index) +
- (CyGFRCR<<index))) >= CD1400_REV_J) {
- /* It is a CD1400 rev. J or later */
- info->tbpr = baud_bpr_60[13]; /* Tx BPR */
- info->tco = baud_co_60[13]; /* Tx CO */
- info->rbpr = baud_bpr_60[13]; /* Rx BPR */
- info->rco = baud_co_60[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 1;
- } else {
- info->tbpr = baud_bpr_25[13]; /* Tx BPR */
- info->tco = baud_co_25[13]; /* Tx CO */
- info->rbpr = baud_bpr_25[13]; /* Rx BPR */
- info->rco = baud_co_25[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 0;
- }
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask =
- CyTIMEOUT| CySPECHAR| CyBREAK
- | CyPARITY| CyFRAME| CyOVERRUN;
- /* info->timeout */
- }
- }
- }
+ }
+ continue;
+ } else { /* Cyclom-Y of some kind */
+ index = cinfo->bus_index;
+ spin_lock_init(&cinfo->card_lock);
+ cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
+ for (port = cinfo->first_line;
+ port < cinfo->first_line + cinfo->nports; port++) {
+ info = &cy_port[port];
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_CIRRUS;
+ info->card = board;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->tty = NULL;
+ info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+ info->cor1 =
+ CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = 0x08; /* _very_ small rcv threshold */
+ info->cor4 = 0;
+ info->cor5 = 0;
+ info->custom_divisor = 0;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
+ chip_number = (port - cinfo->first_line) / 4;
+ if ((info->chip_rev =
+ cy_readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] <<
+ index) + (CyGFRCR << index))) >=
+ CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ info->tbpr = baud_bpr_60[13]; /* Tx BPR */
+ info->tco = baud_co_60[13]; /* Tx CO */
+ info->rbpr = baud_bpr_60[13]; /* Rx BPR */
+ info->rco = baud_co_60[13]; /* Rx CO */
+ info->rflow = 0;
+ info->rtsdtr_inv = 1;
+ } else {
+ info->tbpr = baud_bpr_25[13]; /* Tx BPR */
+ info->tco = baud_co_25[13]; /* Tx CO */
+ info->rbpr = baud_bpr_25[13]; /* Rx BPR */
+ info->rco = baud_co_25[13]; /* Rx CO */
+ info->rflow = 0;
+ info->rtsdtr_inv = 0;
+ }
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ /* info->session */
+ /* info->pgrp */
+ info->read_status_mask =
+ CyTIMEOUT | CySPECHAR | CyBREAK
+ | CyPARITY | CyFRAME | CyOVERRUN;
+ /* info->timeout */
+ }
+ }
+ }
#ifndef CONFIG_CYZ_INTR
- if (number_z_boards && !cyz_timeron){
- cyz_timeron++;
- cyz_timerlist.expires = jiffies + 1;
- add_timer(&cyz_timerlist);
+ if (number_z_boards && !cyz_timeron) {
+ cyz_timeron++;
+ cyz_timerlist.expires = jiffies + 1;
+ add_timer(&cyz_timerlist);
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z polling initialized\n");
+ printk("Cyclades-Z polling initialized\n");
#endif
- }
-#endif /* CONFIG_CYZ_INTR */
+ }
+#endif /* CONFIG_CYZ_INTR */
+
+ return 0;
- return 0;
-
-} /* cy_init */
+} /* cy_init */
-static void __exit
-cy_cleanup_module(void)
+static void __exit cy_cleanup_module(void)
{
- int i, e1;
+ int i, e1;
#ifndef CONFIG_CYZ_INTR
- if (cyz_timeron){
- cyz_timeron = 0;
- del_timer(&cyz_timerlist);
- }
+ if (cyz_timeron){
+ cyz_timeron = 0;
+ del_timer(&cyz_timerlist);
+ }
#endif /* CONFIG_CYZ_INTR */
- if ((e1 = tty_unregister_driver(cy_serial_driver)))
- printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
- e1);
+ if ((e1 = tty_unregister_driver(cy_serial_driver)))
+ printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
+ e1);
- put_tty_driver(cy_serial_driver);
+ put_tty_driver(cy_serial_driver);
- for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr) {
- iounmap(cy_card[i].base_addr);
- if (cy_card[i].ctl_addr)
- iounmap(cy_card[i].ctl_addr);
- if (cy_card[i].irq
+ for (i = 0; i < NR_CARDS; i++) {
+ if (cy_card[i].base_addr) {
+ iounmap(cy_card[i].base_addr);
+ if (cy_card[i].ctl_addr)
+ iounmap(cy_card[i].ctl_addr);
+ if (cy_card[i].irq
#ifndef CONFIG_CYZ_INTR
- && cy_card[i].num_chips != -1 /* not a Z card */
+ && cy_card[i].num_chips != -1 /* not a Z card */
#endif /* CONFIG_CYZ_INTR */
- )
- free_irq(cy_card[i].irq, &cy_card[i]);
+ )
+ free_irq(cy_card[i].irq, &cy_card[i]);
#ifdef CONFIG_PCI
- if (cy_card[i].pdev)
- pci_release_regions(cy_card[i].pdev);
+ if (cy_card[i].pdev)
+ pci_release_regions(cy_card[i].pdev);
#endif
- }
- }
+ }
+ }
} /* cy_cleanup_module */
module_init(cy_init);
&version->desc))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_VERSION, (unsigned long)version);
if (err)
return err;
&u->unique))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
if (err)
return err;
&u->unique))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
}
if (__put_user(idx, &map->offset))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_MAP, (unsigned long)map);
if (err)
return err;
|| __put_user(m32.flags, &map->flags))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_ADD_MAP, (unsigned long)map);
if (err)
return err;
if (__put_user((void *)(unsigned long)handle, &map->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RM_MAP, (unsigned long)map);
}
if (__put_user(idx, &client->idx))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_CLIENT, (unsigned long)client);
if (err)
return err;
if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_STATS, (unsigned long)stats);
if (err)
return err;
|| __put_user(agp_start, &buf->agp_start))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
if (err)
return err;
|| __put_user(b32.high_mark, &buf->high_mark))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
}
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_INFO_BUFS, (unsigned long)request);
if (err)
return err;
|| __put_user(list, &request->list))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MAP_BUFS, (unsigned long)request);
if (err)
return err;
&request->list))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_FREE_BUFS, (unsigned long)request);
}
&request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
}
if (__put_user(ctx_id, &request->ctx_id))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
if (err)
return err;
&res->contexts))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RES_CTX, (unsigned long)res);
if (err)
return err;
&d->request_sizes))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_DMA, (unsigned long)d);
if (err)
return err;
if (put_user(m32.mode, &mode->mode))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
}
if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_INFO, (unsigned long)info);
if (err)
return err;
|| __put_user(req32.type, &request->type))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
if (err)
return err;
if (__get_user(req32.handle, &request->handle)
|| __get_user(req32.physical, &request->physical)
|| copy_to_user(argp, &req32, sizeof(req32))) {
- drm_ioctl(file->f_dentry->d_inode, file,
+ drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_FREE, (unsigned long)request);
return -EFAULT;
}
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_FREE, (unsigned long)request);
}
|| __put_user(req32.offset, &request->offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_BIND, (unsigned long)request);
}
|| __put_user(handle, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
}
#endif /* __OS_HAS_AGP */
|| __put_user(x, &request->size))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SG_ALLOC, (unsigned long)request);
if (err)
return err;
|| __put_user(x << PAGE_SHIFT, &request->handle))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_SG_FREE, (unsigned long)request);
}
|| __put_user(req32.request.signal, &request->request.signal))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
if (err)
return err;
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
&batchbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_BATCHBUFFER,
(unsigned long)batchbuffer);
}
&cmdbuffer->cliprects))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_CMDBUFFER, (unsigned long)cmdbuffer);
}
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_IRQ_EMIT, (unsigned long)request);
}
typedef struct drm_i915_getparam32 {
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_GETPARAM, (unsigned long)request);
}
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_I915_ALLOC, (unsigned long)request);
}
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
if (err)
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_INIT, (unsigned long)init);
}
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
}
|| __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
return -EFAULT;
- err = drm_ioctl(file->f_dentry->d_inode, file,
+ err = drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_MGA_DMA_BOOTSTRAP,
(unsigned long)dma_bootstrap);
if (err)
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
&init->agp_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_INIT, (unsigned long)init);
}
&depth->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
}
&stipple->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
}
&getparam->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
}
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
&init->gart_textures_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
}
&clr->depth_boxes))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
}
&request->mask))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
}
&image->data))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
}
&request->prim))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
}
&request->boxes))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
}
&request->value))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
}
&request->region_offset))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
}
&request->irq_seq))
return -EFAULT;
- return drm_ioctl(file->f_dentry->d_inode, file,
+ return drm_ioctl(file->f_path.dentry->d_inode, file,
DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
}
if (fn != NULL)
ret = (*fn) (filp, cmd, arg);
else
- ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int dev = iminor(inode) & 0x0f;
switch(dev)
static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int dev = iminor(inode) & 0x0f;
switch(dev)
#if 0
static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
{
- int dev = iminor(file->f_dentry->d_inode) & 0x0f;
+ int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
switch(dev)
{
static ssize_t dtlk_read(struct file *file, char __user *buf,
size_t count, loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
char ch;
int i = 0, retries;
}
#endif
- if (iminor(file->f_dentry->d_inode) != DTLK_MINOR)
+ if (iminor(file->f_path.dentry->d_inode) != DTLK_MINOR)
return -EINVAL;
while (1) {
unsigned int, unsigned long);
static int info_ioctl(struct tty_struct *, struct file *,
unsigned int, unsigned long);
-static void pc_set_termios(struct tty_struct *, struct termios *);
+static void pc_set_termios(struct tty_struct *, struct ktermios *);
static void do_softint(struct work_struct *work);
static void pc_stop(struct tty_struct *);
static void pc_start(struct tty_struct *);
pc_driver->init_termios.c_oflag = 0;
pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
pc_driver->init_termios.c_lflag = 0;
+ pc_driver->init_termios.c_ispeed = 9600;
+ pc_driver->init_termios.c_ospeed = 9600;
pc_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(pc_driver, &pc_ops);
pc_info->init_termios.c_oflag = 0;
pc_info->init_termios.c_lflag = 0;
pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ pc_info->init_termios.c_ispeed = 9600;
+ pc_info->init_termios.c_ospeed = 9600;
pc_info->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(pc_info, &info_ops);
{ /* Begin epcaparam */
unsigned int cmdHead;
- struct termios *ts;
+ struct ktermios *ts;
struct board_chan __iomem *bc;
unsigned mval, hflow, cflag, iflag;
{ /* Begin receive_data */
unchar *rptr;
- struct termios *ts = NULL;
+ struct ktermios *ts = NULL;
struct tty_struct *tty;
struct board_chan __iomem *bc;
int dataToRead, wrapgap, bytesAvailable;
switch (cmd)
{ /* Begin switch cmd */
+#if 0 /* Handled by calling layer properly */
case TCGETS:
- if (copy_to_user(argp, tty->termios, sizeof(struct termios)))
+ if (copy_to_user(argp, tty->termios, sizeof(struct ktermios)))
return -EFAULT;
return 0;
case TCGETA:
return get_termio(tty, argp);
+#endif
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
/* --------------------- Begin pc_set_termios ----------------------- */
-static void pc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{ /* Begin pc_set_termios */
struct channel *ch;
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
void gs_set_termios (struct tty_struct * tty,
- struct termios * old_termios)
+ struct ktermios * old_termios)
{
struct gs_port *port;
int baudrate, tmp, rv;
- struct termios *tiosp;
+ struct ktermios *tiosp;
func_enter();
* that will cause echoing or we'll go into recursive loop echoing chars back
* and forth with the console drivers.
*/
-static struct termios hvcs_tty_termios = {
+static struct ktermios hvcs_tty_termios = {
.c_iflag = IGNBRK | IGNPAR,
.c_oflag = OPOST,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
- .c_cc = INIT_C_CC
+ .c_cc = INIT_C_CC,
+ .c_ispeed = 38400,
+ .c_ospeed = 38400
};
/*
hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
hvsi_driver->init_termios = tty_std_termios;
hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ hvsi_driver->init_termios.c_ispeed = 9600;
+ hvsi_driver->init_termios.c_ospeed = 9600;
hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(hvsi_driver, &hvsi_ops);
static int ip2_chars_in_buf(PTTY);
static void ip2_flush_buffer(PTTY);
static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
-static void ip2_set_termios(PTTY, struct termios *);
+static void ip2_set_termios(PTTY, struct ktermios *);
static void ip2_set_line_discipline(PTTY);
static void ip2_throttle(PTTY);
static void ip2_unthrottle(PTTY);
static void ip2_wait_until_sent(PTTY,int);
-static void set_params (i2ChanStrPtr, struct termios *);
+static void set_params (i2ChanStrPtr, struct ktermios *);
static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
/* */
/******************************************************************************/
static void
-ip2_set_termios( PTTY tty, struct termios *old_termios )
+ip2_set_termios( PTTY tty, struct ktermios *old_termios )
{
i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
/* change. */
/******************************************************************************/
static void
-set_params( i2ChanStrPtr pCh, struct termios *o_tios )
+set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
{
tcflag_t cflag, iflag, lflag;
char stop_char, start_char;
- struct termios dummy;
+ struct ktermios dummy;
lflag = pCh->pTTY->termios->c_lflag;
cflag = pCh->pTTY->termios->c_cflag;
ssize_t
ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
{
- unsigned int minor = iminor(pFile->f_dentry->d_inode);
+ unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
int rc = 0;
#ifdef IP2DEBUG_IPL
if (copy_to_user(precv64, &recv64, sizeof(recv64)))
return -EFAULT;
- rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
+ rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
? IPMICTL_RECEIVE_MSG
: IPMICTL_RECEIVE_MSG_TRUNC),
return rc;
}
default:
- return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
+ return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
}
}
#endif
static int prev_card = 3; /* start servicing isi_card[0] */
static struct tty_driver *isicom_normal;
-static struct timer_list tx;
+static DECLARE_COMPLETION(isi_timerdone);
static char re_schedule = 1;
static void isicom_tx(unsigned long _data);
static void isicom_start(struct tty_struct *tty);
+static DEFINE_TIMER(tx, isicom_tx, 0, 0);
+
/* baud index mappings from linux defns to isi */
static signed char linuxb_to_isib[] = {
unsigned short shift_count;
struct isi_port * ports;
signed char count;
- unsigned char isa;
spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
unsigned long flags;
+ unsigned int index;
};
struct isi_port {
/* schedule another tx for hopefully in about 10ms */
sched_again:
if (!re_schedule) {
- re_schedule = 2;
+ complete(&isi_timerdone);
return;
}
- init_timer(&tx);
- tx.expires = jiffies + HZ/100;
- tx.data = 0;
- tx.function = isicom_tx;
- add_timer(&tx);
-
- return;
+ mod_timer(&tx, jiffies + msecs_to_jiffies(10));
}
/* Interrupt handlers */
base = card->base;
spin_lock(&card->card_lock);
- if (card->isa == NO) {
- /*
- * disable any interrupts from the PCI card and lower the
- * interrupt line
- */
- outw(0x8000, base+0x04);
- ClearInterrupt(base);
- }
+ /*
+ * disable any interrupts from the PCI card and lower the
+ * interrupt line
+ */
+ outw(0x8000, base+0x04);
+ ClearInterrupt(base);
inw(base); /* get the dummy word out */
header = inw(base);
if (channel + 1 > card->port_count) {
printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
"%d(channel) > port_count.\n", base, channel+1);
- if (card->isa)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
port = card->ports + channel;
if (!(port->flags & ASYNC_INITIALIZED)) {
- if (card->isa)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
return IRQ_HANDLED;
}
}
if (byte_count & 0x01)
inw(base);
- if (card->isa == YES)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
}
tty_flip_buffer_push(tty);
}
- if (card->isa == YES)
- ClearInterrupt(base);
- else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
return IRQ_HANDLED;
}
{
struct isi_port *port;
struct isi_board *card;
- unsigned int line, board;
- int error;
+ unsigned int board;
+ int error, line;
line = tty->index;
if (line < 0 || line > PORT_COUNT-1)
/* set_termios et all */
static void isicom_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct isi_port *port = tty->driver_data;
* Driver init and deinit functions
*/
-static int __devinit isicom_register_ioregion(struct pci_dev *pdev,
- const unsigned int index)
-{
- struct isi_board *board = pci_get_drvdata(pdev);
-
- if (!board->base)
- return -EINVAL;
-
- if (!request_region(board->base, 16, ISICOM_NAME)) {
- dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
- "will be disabled.\n", board->base, board->base + 15,
- index + 1);
- return -EBUSY;
- }
-
- return 0;
-}
-
-static void isicom_unregister_ioregion(struct pci_dev *pdev)
-{
- struct isi_board *board = pci_get_drvdata(pdev);
-
- if (!board->base)
- return;
-
- release_region(board->base, 16);
- dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx released.\n",
- board->base, board->base + 15);
- board->base = 0;
-}
-
static const struct tty_operations isicom_ops = {
.open = isicom_open,
.close = isicom_close,
.tiocmset = isicom_tiocmset,
};
-static int __devinit isicom_register_tty_driver(void)
-{
- int error = -ENOMEM;
-
- /* tty driver structure initialization */
- isicom_normal = alloc_tty_driver(PORT_COUNT);
- if (!isicom_normal)
- goto end;
-
- isicom_normal->owner = THIS_MODULE;
- isicom_normal->name = "ttyM";
- isicom_normal->major = ISICOM_NMAJOR;
- isicom_normal->minor_start = 0;
- isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
- isicom_normal->subtype = SERIAL_TYPE_NORMAL;
- isicom_normal->init_termios = tty_std_termios;
- isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
- CLOCAL;
- isicom_normal->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(isicom_normal, &isicom_ops);
-
- if ((error = tty_register_driver(isicom_normal))) {
- pr_dbg("Couldn't register the dialin driver, error=%d\n",
- error);
- put_tty_driver(isicom_normal);
- }
-end:
- return error;
-}
-
-static void isicom_unregister_tty_driver(void)
-{
- int error;
-
- if ((error = tty_unregister_driver(isicom_normal)))
- pr_dbg("couldn't unregister normal driver, error=%d.\n", error);
-
- put_tty_driver(isicom_normal);
-}
-
-static int __devinit isicom_register_isr(struct pci_dev *pdev,
- const unsigned int index)
-{
- struct isi_board *board = pci_get_drvdata(pdev);
- unsigned long irqflags = IRQF_DISABLED;
- int retval = -EINVAL;
-
- if (!board->base)
- goto end;
-
- if (board->isa == NO)
- irqflags |= IRQF_SHARED;
-
- retval = request_irq(board->irq, isicom_interrupt, irqflags,
- ISICOM_NAME, board);
- if (retval < 0)
- dev_warn(&pdev->dev, "Could not install handler at Irq %d. "
- "Card%d will be disabled.\n", board->irq, index + 1);
- else
- retval = 0;
-end:
- return retval;
-}
-
static int __devinit reset_card(struct pci_dev *pdev,
const unsigned int card, unsigned int *signature)
{
*signature = inw(base + 0x4) & 0xff;
- if (board->isa == YES) {
- if (!(inw(base + 0xe) & 0x1) || (inw(base + 0x2))) {
- dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
- inw(base + 0x2), inw(base + 0xe));
- dev_err(&pdev->dev, "ISILoad:ISA Card%d reset failure "
- "(Possible bad I/O Port Address 0x%lx).\n",
- card + 1, base);
- retval = -EIO;
- goto end;
- }
- } else {
- portcount = inw(base + 0x2);
- if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) &&
- (portcount != 4) && (portcount != 8))) {
- dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
- inw(base + 0x2), inw(base + 0xe));
- dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure "
- "(Possible bad I/O Port Address 0x%lx).\n",
- card + 1, base);
- retval = -EIO;
- goto end;
- }
+ portcount = inw(base + 0x2);
+ if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) &&
+ (portcount != 4) && (portcount != 8))) {
+ dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
+ inw(base + 0x2), inw(base + 0xe));
+ dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure "
+ "(Possible bad I/O Port Address 0x%lx).\n",
+ card + 1, base);
+ retval = -EIO;
+ goto end;
}
switch (*signature) {
case 0xa5:
case 0xbb:
case 0xdd:
- board->port_count = (board->isa == NO && portcount == 4) ? 4 :
- 8;
+ board->port_count = (portcount == 4) ? 4 : 8;
board->shift_count = 12;
break;
case 0xcc:
}
data = kmalloc(word_count * 2, GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(&pdev->dev, "Card%d, firmware upload "
+ "failed, not enough memory\n", index + 1);
+ goto errrelfw;
+ }
inw(base);
insw(base, data, word_count);
InterruptTheCard(base);
/*
* Insmod can set static symbols so keep these static
*/
-static int io[4];
-static int irq[4];
static int card;
static int __devinit isicom_probe(struct pci_dev *pdev,
break;
}
+ board->index = index;
board->base = ioaddr;
board->irq = pciirq;
- board->isa = NO;
card++;
pci_set_drvdata(pdev, board);
- retval = isicom_register_ioregion(pdev, index);
- if (retval < 0)
+ retval = pci_request_region(pdev, 3, ISICOM_NAME);
+ if (retval) {
+ dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
+ "will be disabled.\n", board->base, board->base + 15,
+ index + 1);
+ retval = -EBUSY;
goto err;
+ }
- retval = isicom_register_isr(pdev, index);
- if (retval < 0)
+ retval = request_irq(board->irq, isicom_interrupt,
+ IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "Could not install handler at Irq %d. "
+ "Card%d will be disabled.\n", board->irq, index + 1);
goto errunrr;
+ }
retval = reset_card(pdev, index, &signature);
if (retval < 0)
if (retval < 0)
goto errunri;
+ for (index = 0; index < board->port_count; index++)
+ tty_register_device(isicom_normal, board->index * 16 + index,
+ &pdev->dev);
+
return 0;
errunri:
free_irq(board->irq, board);
errunrr:
- isicom_unregister_ioregion(pdev);
+ pci_release_region(pdev, 3);
err:
board->base = 0;
return retval;
static void __devexit isicom_remove(struct pci_dev *pdev)
{
struct isi_board *board = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < board->port_count; i++)
+ tty_unregister_device(isicom_normal, board->index * 16 + i);
free_irq(board->irq, board);
- isicom_unregister_ioregion(pdev);
+ pci_release_region(pdev, 3);
}
-static int __devinit isicom_setup(void)
+static int __init isicom_init(void)
{
int retval, idx, channel;
struct isi_port *port;
card = 0;
- memset(isi_ports, 0, sizeof(isi_ports));
for(idx = 0; idx < BOARD_COUNT; idx++) {
port = &isi_ports[idx * 16];
}
isi_card[idx].base = 0;
isi_card[idx].irq = 0;
-
- if (!io[idx])
- continue;
-
- if (irq[idx] == 2 || irq[idx] == 3 || irq[idx] == 4 ||
- irq[idx] == 5 || irq[idx] == 7 ||
- irq[idx] == 10 || irq[idx] == 11 ||
- irq[idx] == 12 || irq[idx] == 15) {
- printk(KERN_ERR "ISICOM: ISA not supported yet.\n");
- retval = -EINVAL;
- goto error;
- } else
- printk(KERN_ERR "ISICOM: Irq %d unsupported. "
- "Disabling Card%d...\n", irq[idx], idx + 1);
}
- retval = isicom_register_tty_driver();
- if (retval < 0)
+ /* tty driver structure initialization */
+ isicom_normal = alloc_tty_driver(PORT_COUNT);
+ if (!isicom_normal) {
+ retval = -ENOMEM;
goto error;
+ }
+
+ isicom_normal->owner = THIS_MODULE;
+ isicom_normal->name = "ttyM";
+ isicom_normal->major = ISICOM_NMAJOR;
+ isicom_normal->minor_start = 0;
+ isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
+ isicom_normal->subtype = SERIAL_TYPE_NORMAL;
+ isicom_normal->init_termios = tty_std_termios;
+ isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ CLOCAL;
+ isicom_normal->flags = TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(isicom_normal, &isicom_ops);
+
+ retval = tty_register_driver(isicom_normal);
+ if (retval) {
+ pr_dbg("Couldn't register the dialin driver\n");
+ goto err_puttty;
+ }
retval = pci_register_driver(&isicom_driver);
if (retval < 0) {
printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
- goto errtty;
+ goto err_unrtty;
}
- init_timer(&tx);
- tx.expires = jiffies + 1;
- tx.data = 0;
- tx.function = isicom_tx;
- re_schedule = 1;
- add_timer(&tx);
+ mod_timer(&tx, jiffies + 1);
return 0;
-errtty:
- isicom_unregister_tty_driver();
+err_unrtty:
+ tty_unregister_driver(isicom_normal);
+err_puttty:
+ put_tty_driver(isicom_normal);
error:
return retval;
}
static void __exit isicom_exit(void)
{
- unsigned int index = 0;
-
re_schedule = 0;
- while (re_schedule != 2 && index++ < 100)
- msleep(10);
+ wait_for_completion_timeout(&isi_timerdone, HZ);
pci_unregister_driver(&isicom_driver);
- isicom_unregister_tty_driver();
+ tty_unregister_driver(isicom_normal);
+ put_tty_driver(isicom_normal);
}
-module_init(isicom_setup);
+module_init(isicom_init);
module_exit(isicom_exit);
MODULE_AUTHOR("MultiTech");
MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
MODULE_LICENSE("GPL");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O ports for the cards");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "Interrupts for the cards");
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; 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.
*/
/*****************************************************************************/
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/eisa.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#define BRD_BRUMBY4 2
#define BRD_ONBOARD2 3
#define BRD_ONBOARD 4
-#define BRD_BRUMBY8 5
-#define BRD_BRUMBY16 6
#define BRD_ONBOARDE 7
-#define BRD_ONBOARD32 9
-#define BRD_ONBOARD2_32 10
-#define BRD_ONBOARDRS 11
-#define BRD_EASYIO 20
-#define BRD_ECH 21
-#define BRD_ECHMC 22
#define BRD_ECP 23
#define BRD_ECPE 24
#define BRD_ECPMC 25
-#define BRD_ECHPCI 26
-#define BRD_ECH64PCI 27
-#define BRD_EASYIOPCI 28
#define BRD_ECPPCI 29
#define BRD_BRUMBY BRD_BRUMBY4
* interrupt is required.
*/
-typedef struct {
+struct stlconf {
int brdtype;
int ioaddr1;
int ioaddr2;
unsigned long memaddr;
int irq;
int irqtype;
-} stlconf_t;
-
-static stlconf_t stli_brdconf[] = {
- /*{ BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },*/
};
-static int stli_nrbrds = ARRAY_SIZE(stli_brdconf);
+static unsigned int stli_nrbrds;
/* stli_lock must NOT be taken holding brd_lock */
static spinlock_t stli_lock; /* TTY logic lock */
* with this termios initially. Basically all it defines is a raw port
* at 9600 baud, 8 data bits, no parity, 1 stop bit.
*/
-static struct termios stli_deftermios = {
+static struct ktermios stli_deftermios = {
.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
.c_cc = INIT_C_CC,
+ .c_ispeed = 9600,
+ .c_ospeed = 9600,
};
/*
*/
static comstats_t stli_comstats;
static combrd_t stli_brdstats;
-static asystats_t stli_cdkstats;
-static stlibrd_t stli_dummybrd;
-static stliport_t stli_dummyport;
+static struct asystats stli_cdkstats;
/*****************************************************************************/
-static stlibrd_t *stli_brds[STL_MAXBRDS];
+static DEFINE_MUTEX(stli_brdslock);
+static struct stlibrd *stli_brds[STL_MAXBRDS];
static int stli_shared;
*/
#define BST_FOUND 0x1
#define BST_STARTED 0x2
+#define BST_PROBED 0x4
/*
* Define the set of port state flags. These are marked for internal
"Brumby",
"Brumby",
"ONboard-EI",
- (char *) NULL,
+ NULL,
"ONboard",
"ONboard-MC",
"ONboard-MC",
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
"EasyIO",
"EC8/32-AT",
"EC8/32-MC",
* parse any module arguments.
*/
-typedef struct stlibrdtype {
+static struct stlibrdtype {
char *name;
int type;
-} stlibrdtype_t;
-
-static stlibrdtype_t stli_brdstr[] = {
+} stli_brdstr[] = {
{ "stallion", BRD_STALLION },
{ "1", BRD_STALLION },
{ "brumby", BRD_BRUMBY },
module_param_array(board3, charp, NULL, 0);
MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]");
+#if STLI_EISAPROBE != 0
/*
* Set up a default memory address table for EISA board probing.
* The default addresses are all bellow 1Mbyte, which has to be the
};
static int stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
+#endif
/*
* Define the Stallion PCI vendor and device IDs.
*/
-#ifdef CONFIG_PCI
-#ifndef PCI_VENDOR_ID_STALLION
-#define PCI_VENDOR_ID_STALLION 0x124d
-#endif
#ifndef PCI_DEVICE_ID_ECRA
#define PCI_DEVICE_ID_ECRA 0x0004
#endif
};
MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
-#endif /* CONFIG_PCI */
+static struct pci_driver stli_pcidriver;
/*****************************************************************************/
/*****************************************************************************/
-/*
- * Define some handy local macros...
- */
-#undef MIN
-#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
-
-#undef TOLOWER
-#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
-
-/*****************************************************************************/
-
/*
* Prototype all functions in this driver!
*/
-static int stli_parsebrd(stlconf_t *confp, char **argp);
-static int stli_init(void);
+static int stli_parsebrd(struct stlconf *confp, char **argp);
static int stli_open(struct tty_struct *tty, struct file *filp);
static void stli_close(struct tty_struct *tty, struct file *filp);
static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count);
static int stli_writeroom(struct tty_struct *tty);
static int stli_charsinbuffer(struct tty_struct *tty);
static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void stli_settermios(struct tty_struct *tty, struct termios *old);
+static void stli_settermios(struct tty_struct *tty, struct ktermios *old);
static void stli_throttle(struct tty_struct *tty);
static void stli_unthrottle(struct tty_struct *tty);
static void stli_stop(struct tty_struct *tty);
static void stli_waituntilsent(struct tty_struct *tty, int timeout);
static void stli_sendxchar(struct tty_struct *tty, char ch);
static void stli_hangup(struct tty_struct *tty);
-static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos);
+static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos);
-static int stli_brdinit(stlibrd_t *brdp);
-static int stli_startbrd(stlibrd_t *brdp);
+static int stli_brdinit(struct stlibrd *brdp);
+static int stli_startbrd(struct stlibrd *brdp);
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp);
+static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);
static void stli_poll(unsigned long arg);
-static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp);
-static int stli_initopen(stlibrd_t *brdp, stliport_t *portp);
-static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait);
-static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait);
-static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp);
+static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);
+static int stli_initopen(struct stlibrd *brdp, struct stliport *portp);
+static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
+static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
+static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
static void stli_dohangup(struct work_struct *);
-static int stli_setport(stliport_t *portp);
-static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp);
-static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp);
+static int stli_setport(struct stliport *portp);
+static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);
+static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);
static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
static long stli_mktiocm(unsigned long sigvalue);
-static void stli_read(stlibrd_t *brdp, stliport_t *portp);
-static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp);
-static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp);
+static void stli_read(struct stlibrd *brdp, struct stliport *portp);
+static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp);
+static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp);
static int stli_getbrdstats(combrd_t __user *bp);
-static int stli_getportstats(stliport_t *portp, comstats_t __user *cp);
-static int stli_portcmdstats(stliport_t *portp);
-static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp);
-static int stli_getportstruct(stliport_t __user *arg);
-static int stli_getbrdstruct(stlibrd_t __user *arg);
-static stlibrd_t *stli_allocbrd(void);
-
-static void stli_ecpinit(stlibrd_t *brdp);
-static void stli_ecpenable(stlibrd_t *brdp);
-static void stli_ecpdisable(stlibrd_t *brdp);
-static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_ecpreset(stlibrd_t *brdp);
-static void stli_ecpintr(stlibrd_t *brdp);
-static void stli_ecpeiinit(stlibrd_t *brdp);
-static void stli_ecpeienable(stlibrd_t *brdp);
-static void stli_ecpeidisable(stlibrd_t *brdp);
-static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_ecpeireset(stlibrd_t *brdp);
-static void stli_ecpmcenable(stlibrd_t *brdp);
-static void stli_ecpmcdisable(stlibrd_t *brdp);
-static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_ecpmcreset(stlibrd_t *brdp);
-static void stli_ecppciinit(stlibrd_t *brdp);
-static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_ecppcireset(stlibrd_t *brdp);
-
-static void stli_onbinit(stlibrd_t *brdp);
-static void stli_onbenable(stlibrd_t *brdp);
-static void stli_onbdisable(stlibrd_t *brdp);
-static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_onbreset(stlibrd_t *brdp);
-static void stli_onbeinit(stlibrd_t *brdp);
-static void stli_onbeenable(stlibrd_t *brdp);
-static void stli_onbedisable(stlibrd_t *brdp);
-static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_onbereset(stlibrd_t *brdp);
-static void stli_bbyinit(stlibrd_t *brdp);
-static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_bbyreset(stlibrd_t *brdp);
-static void stli_stalinit(stlibrd_t *brdp);
-static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
-static void stli_stalreset(stlibrd_t *brdp);
-
-static stliport_t *stli_getport(int brdnr, int panelnr, int portnr);
-
-static int stli_initecp(stlibrd_t *brdp);
-static int stli_initonb(stlibrd_t *brdp);
-static int stli_eisamemprobe(stlibrd_t *brdp);
-static int stli_initports(stlibrd_t *brdp);
-
-#ifdef CONFIG_PCI
-static int stli_initpcibrd(int brdtype, struct pci_dev *devp);
+static int stli_getportstats(struct stliport *portp, comstats_t __user *cp);
+static int stli_portcmdstats(struct stliport *portp);
+static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp);
+static int stli_getportstruct(struct stliport __user *arg);
+static int stli_getbrdstruct(struct stlibrd __user *arg);
+static struct stlibrd *stli_allocbrd(void);
+
+static void stli_ecpinit(struct stlibrd *brdp);
+static void stli_ecpenable(struct stlibrd *brdp);
+static void stli_ecpdisable(struct stlibrd *brdp);
+static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecpreset(struct stlibrd *brdp);
+static void stli_ecpintr(struct stlibrd *brdp);
+static void stli_ecpeiinit(struct stlibrd *brdp);
+static void stli_ecpeienable(struct stlibrd *brdp);
+static void stli_ecpeidisable(struct stlibrd *brdp);
+static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecpeireset(struct stlibrd *brdp);
+static void stli_ecpmcenable(struct stlibrd *brdp);
+static void stli_ecpmcdisable(struct stlibrd *brdp);
+static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecpmcreset(struct stlibrd *brdp);
+static void stli_ecppciinit(struct stlibrd *brdp);
+static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_ecppcireset(struct stlibrd *brdp);
+
+static void stli_onbinit(struct stlibrd *brdp);
+static void stli_onbenable(struct stlibrd *brdp);
+static void stli_onbdisable(struct stlibrd *brdp);
+static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_onbreset(struct stlibrd *brdp);
+static void stli_onbeinit(struct stlibrd *brdp);
+static void stli_onbeenable(struct stlibrd *brdp);
+static void stli_onbedisable(struct stlibrd *brdp);
+static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_onbereset(struct stlibrd *brdp);
+static void stli_bbyinit(struct stlibrd *brdp);
+static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_bbyreset(struct stlibrd *brdp);
+static void stli_stalinit(struct stlibrd *brdp);
+static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
+static void stli_stalreset(struct stlibrd *brdp);
+
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, unsigned int portnr);
+
+static int stli_initecp(struct stlibrd *brdp);
+static int stli_initonb(struct stlibrd *brdp);
+#if STLI_EISAPROBE != 0
+static int stli_eisamemprobe(struct stlibrd *brdp);
#endif
+static int stli_initports(struct stlibrd *brdp);
/*****************************************************************************/
static struct class *istallion_class;
-/*
- * Loadable module initialization stuff.
- */
-
-static int __init istallion_module_init(void)
-{
- stli_init();
- return 0;
-}
-
-/*****************************************************************************/
-
-static void __exit istallion_module_exit(void)
-{
- stlibrd_t *brdp;
- stliport_t *portp;
- int i, j;
-
- printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
- stli_drvversion);
-
- /*
- * Free up all allocated resources used by the ports. This includes
- * memory and interrupts.
- */
- if (stli_timeron) {
- stli_timeron = 0;
- del_timer_sync(&stli_timerlist);
- }
-
- i = tty_unregister_driver(stli_serial);
- if (i) {
- printk("STALLION: failed to un-register tty driver, "
- "errno=%d\n", -i);
- return;
- }
- put_tty_driver(stli_serial);
- for (i = 0; i < 4; i++)
- class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- class_destroy(istallion_class);
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -i);
-
- kfree(stli_txcookbuf);
-
- for (i = 0; (i < stli_nrbrds); i++) {
- if ((brdp = stli_brds[i]) == NULL)
- continue;
- for (j = 0; (j < STL_MAXPORTS); j++) {
- portp = brdp->ports[j];
- if (portp != NULL) {
- if (portp->tty != NULL)
- tty_hangup(portp->tty);
- kfree(portp);
- }
- }
-
- iounmap(brdp->membase);
- if (brdp->iosize > 0)
- release_region(brdp->iobase, brdp->iosize);
- kfree(brdp);
- stli_brds[i] = NULL;
- }
-}
-
-module_init(istallion_module_init);
-module_exit(istallion_module_exit);
-
-/*****************************************************************************/
-
-/*
- * Check for any arguments passed in on the module load command line.
- */
-
-static void stli_argbrds(void)
+static void stli_cleanup_ports(struct stlibrd *brdp)
{
- stlconf_t conf;
- stlibrd_t *brdp;
- int i;
-
- for (i = stli_nrbrds; i < ARRAY_SIZE(stli_brdsp); i++) {
- memset(&conf, 0, sizeof(conf));
- if (stli_parsebrd(&conf, stli_brdsp[i]) == 0)
- continue;
- if ((brdp = stli_allocbrd()) == NULL)
- continue;
- stli_nrbrds = i + 1;
- brdp->brdnr = i;
- brdp->brdtype = conf.brdtype;
- brdp->iobase = conf.ioaddr1;
- brdp->memaddr = conf.memaddr;
- stli_brdinit(brdp);
- }
-}
-
-/*****************************************************************************/
-
-/*
- * Convert an ascii string number into an unsigned long.
- */
-
-static unsigned long stli_atol(char *str)
-{
- unsigned long val;
- int base, c;
- char *sp;
-
- val = 0;
- sp = str;
- if ((*sp == '0') && (*(sp+1) == 'x')) {
- base = 16;
- sp += 2;
- } else if (*sp == '0') {
- base = 8;
- sp++;
- } else {
- base = 10;
- }
-
- for (; (*sp != 0); sp++) {
- c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
- if ((c < 0) || (c >= base)) {
- printk("STALLION: invalid argument %s\n", str);
- val = 0;
- break;
+ struct stliport *portp;
+ unsigned int j;
+
+ for (j = 0; j < STL_MAXPORTS; j++) {
+ portp = brdp->ports[j];
+ if (portp != NULL) {
+ if (portp->tty != NULL)
+ tty_hangup(portp->tty);
+ kfree(portp);
}
- val = (val * base) + c;
}
- return(val);
}
/*****************************************************************************/
* Parse the supplied argument string, into the board conf struct.
*/
-static int stli_parsebrd(stlconf_t *confp, char **argp)
+static int stli_parsebrd(struct stlconf *confp, char **argp)
{
+ unsigned int i;
char *sp;
- int i;
if (argp[0] == NULL || *argp[0] == 0)
return 0;
for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
- *sp = TOLOWER(*sp);
+ *sp = tolower(*sp);
for (i = 0; i < ARRAY_SIZE(stli_brdstr); i++) {
if (strcmp(stli_brdstr[i].name, argp[0]) == 0)
confp->brdtype = stli_brdstr[i].type;
if (argp[1] != NULL && *argp[1] != 0)
- confp->ioaddr1 = stli_atol(argp[1]);
+ confp->ioaddr1 = simple_strtoul(argp[1], NULL, 0);
if (argp[2] != NULL && *argp[2] != 0)
- confp->memaddr = stli_atol(argp[2]);
+ confp->memaddr = simple_strtoul(argp[2], NULL, 0);
return(1);
}
static int stli_open(struct tty_struct *tty, struct file *filp)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- unsigned int minordev;
- int brdnr, portnr, rc;
+ struct stlibrd *brdp;
+ struct stliport *portp;
+ unsigned int minordev, brdnr, portnr;
+ int rc;
minordev = tty->index;
brdnr = MINOR2BRD(minordev);
if ((brdp->state & BST_STARTED) == 0)
return -ENODEV;
portnr = MINOR2PORT(minordev);
- if ((portnr < 0) || (portnr > brdp->nrports))
+ if (portnr > brdp->nrports)
return -ENODEV;
portp = brdp->ports[portnr];
static void stli_close(struct tty_struct *tty, struct file *filp)
{
- stlibrd_t *brdp;
- stliport_t *portp;
+ struct stlibrd *brdp;
+ struct stliport *portp;
unsigned long flags;
portp = tty->driver_data;
* this still all happens pretty quickly.
*/
-static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
+static int stli_initopen(struct stlibrd *brdp, struct stliport *portp)
{
struct tty_struct *tty;
asynotify_t nt;
* to overlap.
*/
-static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
+static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait)
{
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
* wait is true then must have user context (to sleep).
*/
-static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
+static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait)
{
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
* to complete (as opposed to initiating the command then returning).
*/
-static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CMDING, &portp->state));
* waiting for the command to complete - so must have user context.
*/
-static int stli_setport(stliport_t *portp)
+static int stli_setport(struct stliport *portp)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
asyport_t aport;
if (portp == NULL)
return -ENODEV;
if (portp->tty == NULL)
return -ENODEV;
- if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return -ENODEV;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
* maybe because if we are clocal then we don't need to wait...
*/
-static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp)
+static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp)
{
unsigned long flags;
int rc, doclocal;
unsigned char __iomem *bits;
unsigned char __iomem *shbuf;
unsigned char *chbuf;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int len, stlen, head, tail, size;
unsigned long flags;
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
stlen = len;
}
- len = MIN(len, count);
+ len = min(len, (unsigned int)count);
count = 0;
shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->txoffset);
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy_toio(shbuf + head, chbuf, stlen);
chbuf += stlen;
len -= stlen;
unsigned char __iomem *bits;
cdkasy_t __iomem *ap;
struct tty_struct *cooktty;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int len, stlen, head, tail, size, count, cooksize;
unsigned char *buf;
unsigned char __iomem *shbuf;
portp = tty->driver_data;
if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
stlen = len;
}
- len = MIN(len, cooksize);
+ len = min(len, cooksize);
count = 0;
shbuf = EBRDGETMEMPTR(brdp, portp->txoffset);
buf = stli_txcookbuf;
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy_toio(shbuf + head, buf, stlen);
buf += stlen;
len -= stlen;
static int stli_writeroom(struct tty_struct *tty)
{
cdkasyrq_t __iomem *rp;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int head, tail, len;
unsigned long flags;
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static int stli_charsinbuffer(struct tty_struct *tty)
{
cdkasyrq_t __iomem *rp;
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int head, tail, len;
unsigned long flags;
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
* Generate the serial struct info.
*/
-static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
+static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
memset(&sio, 0, sizeof(struct serial_struct));
sio.type = PORT_UNKNOWN;
* just quietly ignore any requests to change irq, etc.
*/
-static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
+static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
int rc;
static int stli_tiocmget(struct tty_struct *tty, struct file *file)
{
- stliport_t *portp = tty->driver_data;
- stlibrd_t *brdp;
+ struct stliport *portp = tty->driver_data;
+ struct stlibrd *brdp;
int rc;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static int stli_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- stliport_t *portp = tty->driver_data;
- stlibrd_t *brdp;
+ struct stliport *portp = tty->driver_data;
+ struct stlibrd *brdp;
int rts = -1, dtr = -1;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned int ival;
int rc;
void __user *argp = (void __user *)arg;
portp = tty->driver_data;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
* Looks like it is true for the current ttys implementation..!!
*/
-static void stli_settermios(struct tty_struct *tty, struct termios *old)
+static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- struct termios *tiosp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
+ struct ktermios *tiosp;
asyport_t aport;
if (tty == NULL)
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static void stli_throttle(struct tty_struct *tty)
{
- stliport_t *portp = tty->driver_data;
+ struct stliport *portp = tty->driver_data;
if (portp == NULL)
return;
set_bit(ST_RXSTOP, &portp->state);
static void stli_unthrottle(struct tty_struct *tty)
{
- stliport_t *portp = tty->driver_data;
+ struct stliport *portp = tty->driver_data;
if (portp == NULL)
return;
clear_bit(ST_RXSTOP, &portp->state);
static void stli_dohangup(struct work_struct *ugly_api)
{
- stliport_t *portp = container_of(ugly_api, stliport_t, tqhangup);
+ struct stliport *portp = container_of(ugly_api, struct stliport, tqhangup);
if (portp->tty != NULL) {
tty_hangup(portp->tty);
}
static void stli_hangup(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned long flags;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static void stli_flushbuffer(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
+ struct stliport *portp;
+ struct stlibrd *brdp;
unsigned long ftype, flags;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static void stli_breakctl(struct tty_struct *tty, int state)
{
- stlibrd_t *brdp;
- stliport_t *portp;
+ struct stlibrd *brdp;
+ struct stliport *portp;
long arg;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
static void stli_waituntilsent(struct tty_struct *tty, int timeout)
{
- stliport_t *portp;
+ struct stliport *portp;
unsigned long tend;
if (tty == NULL)
static void stli_sendxchar(struct tty_struct *tty, char ch)
{
- stlibrd_t *brdp;
- stliport_t *portp;
+ struct stlibrd *brdp;
+ struct stliport *portp;
asyctrl_t actrl;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
* short then padded with spaces).
*/
-static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos)
+static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos)
{
char *sp, *uart;
int rc, cnt;
static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- int brdnr, portnr, totalport;
+ struct stlibrd *brdp;
+ struct stliport *portp;
+ unsigned int brdnr, portnr, totalport;
int curoff, maxoff;
char *pos;
* entry point)
*/
-static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
spin_unlock_irqrestore(&brd_lock, flags);
}
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{
unsigned long flags;
* more chars to unload.
*/
-static void stli_read(stlibrd_t *brdp, stliport_t *portp)
+static void stli_read(struct stlibrd *brdp, struct stliport *portp)
{
cdkasyrq_t __iomem *rp;
char __iomem *shbuf;
while (len > 0) {
unsigned char *cptr;
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
tty_prepare_flip_string(tty, &cptr, stlen);
memcpy_fromio(cptr, shbuf + tail, stlen);
len -= stlen;
* difficult to deal with them here.
*/
-static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp)
+static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp)
{
int cmd;
* then port is still busy, otherwise no longer busy.
*/
-static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
+static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
{
cdkasy_t __iomem *ap;
cdkctrl_t __iomem *cp;
* at the cdk header structure.
*/
-static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp)
+static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp)
{
- stliport_t *portp;
+ struct stliport *portp;
unsigned char hostbits[(STL_MAXCHANS / 8) + 1];
unsigned char slavebits[(STL_MAXCHANS / 8) + 1];
unsigned char __iomem *slavep;
static void stli_poll(unsigned long arg)
{
cdkhdr_t __iomem *hdrp;
- stlibrd_t *brdp;
- int brdnr;
+ struct stlibrd *brdp;
+ unsigned int brdnr;
- stli_timerlist.expires = STLI_TIMEOUT;
- add_timer(&stli_timerlist);
+ mod_timer(&stli_timerlist, STLI_TIMEOUT);
/*
* Check each board and do any servicing required.
* the slave.
*/
-static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp)
+static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp)
{
memset(pp, 0, sizeof(asyport_t));
* we need to do here is set up the appropriate per port data structures.
*/
-static int stli_initports(stlibrd_t *brdp)
+static int stli_initports(struct stlibrd *brdp)
{
- stliport_t *portp;
- int i, panelnr, panelport;
+ struct stliport *portp;
+ unsigned int i, panelnr, panelport;
for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
- portp = kzalloc(sizeof(stliport_t), GFP_KERNEL);
+ portp = kzalloc(sizeof(struct stliport), GFP_KERNEL);
if (!portp) {
printk("STALLION: failed to allocate port structure\n");
continue;
* All the following routines are board specific hardware operations.
*/
-static void stli_ecpinit(stlibrd_t *brdp)
+static void stli_ecpinit(struct stlibrd *brdp)
{
unsigned long memconf;
/*****************************************************************************/
-static void stli_ecpenable(stlibrd_t *brdp)
+static void stli_ecpenable(struct stlibrd *brdp)
{
outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR));
}
/*****************************************************************************/
-static void stli_ecpdisable(stlibrd_t *brdp)
+static void stli_ecpdisable(struct stlibrd *brdp)
{
outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
}
/*****************************************************************************/
-static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
/*****************************************************************************/
-static void stli_ecpreset(stlibrd_t *brdp)
+static void stli_ecpreset(struct stlibrd *brdp)
{
outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
udelay(10);
/*****************************************************************************/
-static void stli_ecpintr(stlibrd_t *brdp)
+static void stli_ecpintr(struct stlibrd *brdp)
{
outb(0x1, brdp->iobase);
}
* The following set of functions act on ECP EISA boards.
*/
-static void stli_ecpeiinit(stlibrd_t *brdp)
+static void stli_ecpeiinit(struct stlibrd *brdp)
{
unsigned long memconf;
/*****************************************************************************/
-static void stli_ecpeienable(stlibrd_t *brdp)
+static void stli_ecpeienable(struct stlibrd *brdp)
{
outb(ECP_EIENABLE, (brdp->iobase + ECP_EICONFR));
}
/*****************************************************************************/
-static void stli_ecpeidisable(stlibrd_t *brdp)
+static void stli_ecpeidisable(struct stlibrd *brdp)
{
outb(ECP_EIDISABLE, (brdp->iobase + ECP_EICONFR));
}
/*****************************************************************************/
-static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
/*****************************************************************************/
-static void stli_ecpeireset(stlibrd_t *brdp)
+static void stli_ecpeireset(struct stlibrd *brdp)
{
outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
udelay(10);
* The following set of functions act on ECP MCA boards.
*/
-static void stli_ecpmcenable(stlibrd_t *brdp)
+static void stli_ecpmcenable(struct stlibrd *brdp)
{
outb(ECP_MCENABLE, (brdp->iobase + ECP_MCCONFR));
}
/*****************************************************************************/
-static void stli_ecpmcdisable(stlibrd_t *brdp)
+static void stli_ecpmcdisable(struct stlibrd *brdp)
{
outb(ECP_MCDISABLE, (brdp->iobase + ECP_MCCONFR));
}
/*****************************************************************************/
-static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
/*****************************************************************************/
-static void stli_ecpmcreset(stlibrd_t *brdp)
+static void stli_ecpmcreset(struct stlibrd *brdp)
{
outb(ECP_MCSTOP, (brdp->iobase + ECP_MCCONFR));
udelay(10);
* The following set of functions act on ECP PCI boards.
*/
-static void stli_ecppciinit(stlibrd_t *brdp)
+static void stli_ecppciinit(struct stlibrd *brdp)
{
outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
udelay(10);
/*****************************************************************************/
-static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
/*****************************************************************************/
-static void stli_ecppcireset(stlibrd_t *brdp)
+static void stli_ecppcireset(struct stlibrd *brdp)
{
outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
udelay(10);
* The following routines act on ONboards.
*/
-static void stli_onbinit(stlibrd_t *brdp)
+static void stli_onbinit(struct stlibrd *brdp)
{
unsigned long memconf;
/*****************************************************************************/
-static void stli_onbenable(stlibrd_t *brdp)
+static void stli_onbenable(struct stlibrd *brdp)
{
outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR));
}
/*****************************************************************************/
-static void stli_onbdisable(stlibrd_t *brdp)
+static void stli_onbdisable(struct stlibrd *brdp)
{
outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR));
}
/*****************************************************************************/
-static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
/*****************************************************************************/
-static void stli_onbreset(stlibrd_t *brdp)
+static void stli_onbreset(struct stlibrd *brdp)
{
outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
udelay(10);
* The following routines act on ONboard EISA.
*/
-static void stli_onbeinit(stlibrd_t *brdp)
+static void stli_onbeinit(struct stlibrd *brdp)
{
unsigned long memconf;
/*****************************************************************************/
-static void stli_onbeenable(stlibrd_t *brdp)
+static void stli_onbeenable(struct stlibrd *brdp)
{
outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR));
}
/*****************************************************************************/
-static void stli_onbedisable(stlibrd_t *brdp)
+static void stli_onbedisable(struct stlibrd *brdp)
{
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
}
/*****************************************************************************/
-static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
/*****************************************************************************/
-static void stli_onbereset(stlibrd_t *brdp)
+static void stli_onbereset(struct stlibrd *brdp)
{
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
* The following routines act on Brumby boards.
*/
-static void stli_bbyinit(stlibrd_t *brdp)
+static void stli_bbyinit(struct stlibrd *brdp)
{
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
/*****************************************************************************/
-static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
void __iomem *ptr;
unsigned char val;
/*****************************************************************************/
-static void stli_bbyreset(stlibrd_t *brdp)
+static void stli_bbyreset(struct stlibrd *brdp)
{
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
* The following routines act on original old Stallion boards.
*/
-static void stli_stalinit(stlibrd_t *brdp)
+static void stli_stalinit(struct stlibrd *brdp)
{
outb(0x1, brdp->iobase);
mdelay(1000);
/*****************************************************************************/
-static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line)
{
BUG_ON(offset > brdp->memsize);
return brdp->membase + (offset % STAL_PAGESIZE);
/*****************************************************************************/
-static void stli_stalreset(stlibrd_t *brdp)
+static void stli_stalreset(struct stlibrd *brdp)
{
u32 __iomem *vecp;
* board types.
*/
-static int stli_initecp(stlibrd_t *brdp)
+static int stli_initecp(struct stlibrd *brdp)
{
cdkecpsig_t sig;
cdkecpsig_t __iomem *sigsp;
unsigned int status, nxtid;
char *name;
- int panelnr, nrports;
+ int retval, panelnr, nrports;
- if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
- return -EIO;
-
- if ((brdp->iobase == 0) || (brdp->memaddr == 0))
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENODEV;
+ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) {
+ retval = -ENODEV;
+ goto err;
+ }
+
+ if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+ retval = -EIO;
+ goto err;
}
brdp->iosize = ECP_IOSIZE;
*/
switch (brdp->brdtype) {
case BRD_ECP:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_MEMSIZE;
brdp->pagesize = ECP_ATPAGESIZE;
brdp->init = stli_ecpinit;
break;
case BRD_ECPE:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_MEMSIZE;
brdp->pagesize = ECP_EIPAGESIZE;
brdp->init = stli_ecpeiinit;
break;
case BRD_ECPMC:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_MEMSIZE;
brdp->pagesize = ECP_MCPAGESIZE;
brdp->init = NULL;
break;
case BRD_ECPPCI:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ECP_PCIMEMSIZE;
brdp->pagesize = ECP_PCIPAGESIZE;
brdp->init = stli_ecppciinit;
break;
default:
- release_region(brdp->iobase, brdp->iosize);
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_reg;
}
/*
EBRDINIT(brdp);
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == NULL)
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENOMEM;
+ if (brdp->membase == NULL) {
+ retval = -ENOMEM;
+ goto err_reg;
}
/*
memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t));
EBRDDISABLE(brdp);
- if (sig.magic != cpu_to_le32(ECP_MAGIC))
- {
- release_region(brdp->iobase, brdp->iosize);
- iounmap(brdp->membase);
- brdp->membase = NULL;
- return -ENODEV;
+ if (sig.magic != cpu_to_le32(ECP_MAGIC)) {
+ retval = -ENODEV;
+ goto err_unmap;
}
/*
brdp->state |= BST_FOUND;
return 0;
+err_unmap:
+ iounmap(brdp->membase);
+ brdp->membase = NULL;
+err_reg:
+ release_region(brdp->iobase, brdp->iosize);
+err:
+ return retval;
}
/*****************************************************************************/
* This handles only these board types.
*/
-static int stli_initonb(stlibrd_t *brdp)
+static int stli_initonb(struct stlibrd *brdp)
{
cdkonbsig_t sig;
cdkonbsig_t __iomem *sigsp;
char *name;
- int i;
+ int i, retval;
/*
* Do a basic sanity check on the IO and memory addresses.
*/
- if (brdp->iobase == 0 || brdp->memaddr == 0)
- return -ENODEV;
+ if (brdp->iobase == 0 || brdp->memaddr == 0) {
+ retval = -ENODEV;
+ goto err;
+ }
brdp->iosize = ONB_IOSIZE;
- if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
- return -EIO;
+ if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+ retval = -EIO;
+ goto err;
+ }
/*
* Based on the specific board type setup the common vars to access
*/
switch (brdp->brdtype) {
case BRD_ONBOARD:
- case BRD_ONBOARD32:
case BRD_ONBOARD2:
- case BRD_ONBOARD2_32:
- case BRD_ONBOARDRS:
brdp->memsize = ONB_MEMSIZE;
brdp->pagesize = ONB_ATPAGESIZE;
brdp->init = stli_onbinit;
break;
case BRD_BRUMBY4:
- case BRD_BRUMBY8:
- case BRD_BRUMBY16:
brdp->memsize = BBY_MEMSIZE;
brdp->pagesize = BBY_PAGESIZE;
brdp->init = stli_bbyinit;
break;
default:
- release_region(brdp->iobase, brdp->iosize);
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_reg;
}
/*
EBRDINIT(brdp);
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == NULL)
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENOMEM;
+ if (brdp->membase == NULL) {
+ retval = -ENOMEM;
+ goto err_reg;
}
/*
if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
- sig.magic3 != cpu_to_le16(ONB_MAGIC3))
- {
- release_region(brdp->iobase, brdp->iosize);
- iounmap(brdp->membase);
- brdp->membase = NULL;
- return -ENODEV;
+ sig.magic3 != cpu_to_le16(ONB_MAGIC3)) {
+ retval = -ENODEV;
+ goto err_unmap;
}
/*
brdp->state |= BST_FOUND;
return 0;
+err_unmap:
+ iounmap(brdp->membase);
+ brdp->membase = NULL;
+err_reg:
+ release_region(brdp->iobase, brdp->iosize);
+err:
+ return retval;
}
/*****************************************************************************/
* read in the memory map, and get the show on the road...
*/
-static int stli_startbrd(stlibrd_t *brdp)
+static int stli_startbrd(struct stlibrd *brdp)
{
cdkhdr_t __iomem *hdrp;
cdkmem_t __iomem *memp;
cdkasy_t __iomem *ap;
unsigned long flags;
- stliport_t *portp;
- int portnr, nrdevs, i, rc = 0;
+ unsigned int portnr, nrdevs, i;
+ struct stliport *portp;
+ int rc = 0;
u32 memoff;
spin_lock_irqsave(&brd_lock, flags);
if (! stli_timeron) {
stli_timeron++;
- stli_timerlist.expires = STLI_TIMEOUT;
- add_timer(&stli_timerlist);
+ mod_timer(&stli_timerlist, STLI_TIMEOUT);
}
return rc;
* Probe and initialize the specified board.
*/
-static int __init stli_brdinit(stlibrd_t *brdp)
+static int __devinit stli_brdinit(struct stlibrd *brdp)
{
- stli_brds[brdp->brdnr] = brdp;
+ int retval;
switch (brdp->brdtype) {
case BRD_ECP:
case BRD_ECPE:
case BRD_ECPMC:
case BRD_ECPPCI:
- stli_initecp(brdp);
+ retval = stli_initecp(brdp);
break;
case BRD_ONBOARD:
case BRD_ONBOARDE:
case BRD_ONBOARD2:
- case BRD_ONBOARD32:
- case BRD_ONBOARD2_32:
- case BRD_ONBOARDRS:
case BRD_BRUMBY4:
- case BRD_BRUMBY8:
- case BRD_BRUMBY16:
case BRD_STALLION:
- stli_initonb(brdp);
+ retval = stli_initonb(brdp);
break;
- case BRD_EASYIO:
- case BRD_ECH:
- case BRD_ECHMC:
- case BRD_ECHPCI:
- printk(KERN_ERR "STALLION: %s board type not supported in "
- "this driver\n", stli_brdnames[brdp->brdtype]);
- return -ENODEV;
default:
printk(KERN_ERR "STALLION: board=%d is unknown board "
"type=%d\n", brdp->brdnr, brdp->brdtype);
- return -ENODEV;
+ retval = -ENODEV;
}
- if ((brdp->state & BST_FOUND) == 0) {
- printk(KERN_ERR "STALLION: %s board not found, board=%d "
- "io=%x mem=%x\n",
- stli_brdnames[brdp->brdtype], brdp->brdnr,
- brdp->iobase, (int) brdp->memaddr);
- return -ENODEV;
- }
+ if (retval)
+ return retval;
stli_initports(brdp);
printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x "
return 0;
}
+#if STLI_EISAPROBE != 0
/*****************************************************************************/
/*
* might be. This is a bit if hack, but it is the best we can do.
*/
-static int stli_eisamemprobe(stlibrd_t *brdp)
+static int stli_eisamemprobe(struct stlibrd *brdp)
{
cdkecpsig_t ecpsig, __iomem *ecpsigp;
cdkonbsig_t onbsig, __iomem *onbsigp;
}
return 0;
}
+#endif
static int stli_getbrdnr(void)
{
- int i;
+ unsigned int i;
for (i = 0; i < STL_MAXBRDS; i++) {
if (!stli_brds[i]) {
return -1;
}
+#if STLI_EISAPROBE != 0
/*****************************************************************************/
/*
static int stli_findeisabrds(void)
{
- stlibrd_t *brdp;
- unsigned int iobase, eid;
- int i;
+ struct stlibrd *brdp;
+ unsigned int iobase, eid, i;
+ int brdnr, found = 0;
/*
* Firstly check if this is an EISA system. If this is not an EISA system then
* Allocate a board structure and initialize it.
*/
if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- if ((brdp->brdnr = stli_getbrdnr()) < 0)
- return -ENOMEM;
+ return found ? : -ENOMEM;
+ brdnr = stli_getbrdnr();
+ if (brdnr < 0)
+ return found ? : -ENOMEM;
+ brdp->brdnr = (unsigned int)brdnr;
eid = inb(iobase + 0xc82);
if (eid == ECP_EISAID)
brdp->brdtype = BRD_ECPE;
outb(0x1, (iobase + 0xc84));
if (stli_eisamemprobe(brdp))
outb(0, (iobase + 0xc84));
- stli_brdinit(brdp);
+ if (stli_brdinit(brdp) < 0) {
+ kfree(brdp);
+ continue;
+ }
+
+ stli_brds[brdp->brdnr] = brdp;
+ found++;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial,
+ brdp->brdnr * STL_MAXPORTS + i, NULL);
}
- return 0;
+ return found;
}
+#else
+static inline int stli_findeisabrds(void) { return 0; }
+#endif
/*****************************************************************************/
/*****************************************************************************/
-#ifdef CONFIG_PCI
-
/*
* We have a Stallion board. Allocate a board structure and
* initialize it. Read its IO and MEMORY resources from PCI
* configuration space.
*/
-static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
+static int __devinit stli_pciprobe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- stlibrd_t *brdp;
-
- if (pci_enable_device(devp))
- return -EIO;
- if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- if ((brdp->brdnr = stli_getbrdnr()) < 0) {
+ struct stlibrd *brdp;
+ unsigned int i;
+ int brdnr, retval = -EIO;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+ brdp = stli_allocbrd();
+ if (brdp == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ mutex_lock(&stli_brdslock);
+ brdnr = stli_getbrdnr();
+ if (brdnr < 0) {
printk(KERN_INFO "STALLION: too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
- return 0;
+ mutex_unlock(&stli_brdslock);
+ retval = -EIO;
+ goto err_fr;
}
- brdp->brdtype = brdtype;
+ brdp->brdnr = (unsigned int)brdnr;
+ stli_brds[brdp->brdnr] = brdp;
+ mutex_unlock(&stli_brdslock);
+ brdp->brdtype = BRD_ECPPCI;
/*
* We have all resources from the board, so lets setup the actual
* board structure now.
*/
- brdp->iobase = pci_resource_start(devp, 3);
- brdp->memaddr = pci_resource_start(devp, 2);
- stli_brdinit(brdp);
+ brdp->iobase = pci_resource_start(pdev, 3);
+ brdp->memaddr = pci_resource_start(pdev, 2);
+ retval = stli_brdinit(brdp);
+ if (retval)
+ goto err_null;
+
+ brdp->state |= BST_PROBED;
+ pci_set_drvdata(pdev, brdp);
+
+ EBRDENABLE(brdp);
+ brdp->enable = NULL;
+ brdp->disable = NULL;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial, brdp->brdnr * STL_MAXPORTS + i,
+ &pdev->dev);
return 0;
+err_null:
+ stli_brds[brdp->brdnr] = NULL;
+err_fr:
+ kfree(brdp);
+err:
+ return retval;
}
-/*****************************************************************************/
+static void stli_pciremove(struct pci_dev *pdev)
+{
+ struct stlibrd *brdp = pci_get_drvdata(pdev);
-/*
- * Find all Stallion PCI boards that might be installed. Initialize each
- * one as it is found.
- */
+ stli_cleanup_ports(brdp);
-static int stli_findpcibrds(void)
-{
- struct pci_dev *dev = NULL;
+ iounmap(brdp->membase);
+ if (brdp->iosize > 0)
+ release_region(brdp->iobase, brdp->iosize);
- while ((dev = pci_get_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, dev))) {
- stli_initpcibrd(BRD_ECPPCI, dev);
- }
- return 0;
+ stli_brds[brdp->brdnr] = NULL;
+ kfree(brdp);
}
-#endif
-
+static struct pci_driver stli_pcidriver = {
+ .name = "istallion",
+ .id_table = istallion_pci_tbl,
+ .probe = stli_pciprobe,
+ .remove = __devexit_p(stli_pciremove)
+};
/*****************************************************************************/
/*
* Allocate a new board structure. Fill out the basic info in it.
*/
-static stlibrd_t *stli_allocbrd(void)
+static struct stlibrd *stli_allocbrd(void)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
- brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL);
+ brdp = kzalloc(sizeof(struct stlibrd), GFP_KERNEL);
if (!brdp) {
printk(KERN_ERR "STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlibrd_t));
+ "(size=%Zd)\n", sizeof(struct stlibrd));
return NULL;
}
brdp->magic = STLI_BOARDMAGIC;
static int stli_initbrds(void)
{
- stlibrd_t *brdp, *nxtbrdp;
- stlconf_t *confp;
- int i, j;
-
- if (stli_nrbrds > STL_MAXBRDS) {
- printk(KERN_INFO "STALLION: too many boards in configuration "
- "table, truncating to %d\n", STL_MAXBRDS);
- stli_nrbrds = STL_MAXBRDS;
- }
+ struct stlibrd *brdp, *nxtbrdp;
+ struct stlconf conf;
+ unsigned int i, j, found = 0;
+ int retval;
-/*
- * Firstly scan the list of static boards configured. Allocate
- * resources and initialize the boards as found. If this is a
- * module then let the module args override static configuration.
- */
- for (i = 0; (i < stli_nrbrds); i++) {
- confp = &stli_brdconf[i];
- stli_parsebrd(confp, stli_brdsp[i]);
+ for (stli_nrbrds = 0; stli_nrbrds < ARRAY_SIZE(stli_brdsp);
+ stli_nrbrds++) {
+ memset(&conf, 0, sizeof(conf));
+ if (stli_parsebrd(&conf, stli_brdsp[stli_nrbrds]) == 0)
+ continue;
if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- brdp->brdnr = i;
- brdp->brdtype = confp->brdtype;
- brdp->iobase = confp->ioaddr1;
- brdp->memaddr = confp->memaddr;
- stli_brdinit(brdp);
+ continue;
+ brdp->brdnr = stli_nrbrds;
+ brdp->brdtype = conf.brdtype;
+ brdp->iobase = conf.ioaddr1;
+ brdp->memaddr = conf.memaddr;
+ if (stli_brdinit(brdp) < 0) {
+ kfree(brdp);
+ continue;
+ }
+ stli_brds[brdp->brdnr] = brdp;
+ found++;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial,
+ brdp->brdnr * STL_MAXPORTS + i, NULL);
}
-/*
- * Static configuration table done, so now use dynamic methods to
- * see if any more boards should be configured.
- */
- stli_argbrds();
- if (STLI_EISAPROBE)
- stli_findeisabrds();
-#ifdef CONFIG_PCI
- stli_findpcibrds();
-#endif
+ retval = stli_findeisabrds();
+ if (retval > 0)
+ found += retval;
/*
* All found boards are initialized. Now for a little optimization, if
}
}
+ retval = pci_register_driver(&stli_pcidriver);
+ if (retval && found == 0) {
+ printk(KERN_ERR "Neither isa nor eisa cards found nor pci "
+ "driver can be registered!\n");
+ goto err;
+ }
+
return 0;
+err:
+ return retval;
}
/*****************************************************************************/
{
unsigned long flags;
void __iomem *memptr;
- stlibrd_t *brdp;
- int brdnr, size, n;
+ struct stlibrd *brdp;
+ unsigned int brdnr;
+ int size, n;
void *p;
loff_t off = *offp;
- brdnr = iminor(fp->f_dentry->d_inode);
+ brdnr = iminor(fp->f_path.dentry->d_inode);
if (brdnr >= stli_nrbrds)
return -ENODEV;
brdp = stli_brds[brdnr];
if (off >= brdp->memsize || off + count < off)
return 0;
- size = MIN(count, (brdp->memsize - off));
+ size = min(count, (size_t)(brdp->memsize - off));
/*
* Copy the data a page at a time
spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
memptr = EBRDGETMEMPTR(brdp, off);
- n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
- n = MIN(n, PAGE_SIZE);
+ n = min(size, (int)(brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = min(n, (int)PAGE_SIZE);
memcpy_fromio(p, memptr, n);
EBRDDISABLE(brdp);
spin_unlock_irqrestore(&brd_lock, flags);
{
unsigned long flags;
void __iomem *memptr;
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
char __user *chbuf;
- int brdnr, size, n;
+ unsigned int brdnr;
+ int size, n;
void *p;
loff_t off = *offp;
- brdnr = iminor(fp->f_dentry->d_inode);
+ brdnr = iminor(fp->f_path.dentry->d_inode);
if (brdnr >= stli_nrbrds)
return -ENODEV;
return 0;
chbuf = (char __user *) buf;
- size = MIN(count, (brdp->memsize - off));
+ size = min(count, (size_t)(brdp->memsize - off));
/*
* Copy the data a page at a time
return -ENOMEM;
while (size > 0) {
- n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
- n = MIN(n, PAGE_SIZE);
+ n = min(size, (int)(brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = min(n, (int)PAGE_SIZE);
if (copy_from_user(p, chbuf, n)) {
if (count == 0)
count = -EFAULT;
static int stli_getbrdstats(combrd_t __user *bp)
{
- stlibrd_t *brdp;
- int i;
+ struct stlibrd *brdp;
+ unsigned int i;
if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
return -EFAULT;
* Resolve the referenced port number into a port struct pointer.
*/
-static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
+ unsigned int portnr)
{
- stlibrd_t *brdp;
- int i;
+ struct stlibrd *brdp;
+ unsigned int i;
- if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+ if (brdnr >= STL_MAXBRDS)
return NULL;
brdp = stli_brds[brdnr];
if (brdp == NULL)
return NULL;
for (i = 0; (i < panelnr); i++)
portnr += brdp->panels[i];
- if ((portnr < 0) || (portnr >= brdp->nrports))
+ if (portnr >= brdp->nrports)
return NULL;
return brdp->ports[portnr];
}
* what port to get stats for (used through board control device).
*/
-static int stli_portcmdstats(stliport_t *portp)
+static int stli_portcmdstats(struct stliport *portp)
{
unsigned long flags;
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int rc;
memset(&stli_comstats, 0, sizeof(comstats_t));
* what port to get stats for (used through board control device).
*/
-static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
+static int stli_getportstats(struct stliport *portp, comstats_t __user *cp)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int rc;
if (!portp) {
* Clear the port stats structure. We also return it zeroed out...
*/
-static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
+static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int rc;
if (!portp) {
* Return the entire driver ports structure to a user app.
*/
-static int stli_getportstruct(stliport_t __user *arg)
+static int stli_getportstruct(struct stliport __user *arg)
{
- stliport_t *portp;
+ struct stliport stli_dummyport;
+ struct stliport *portp;
- if (copy_from_user(&stli_dummyport, arg, sizeof(stliport_t)))
+ if (copy_from_user(&stli_dummyport, arg, sizeof(struct stliport)))
return -EFAULT;
portp = stli_getport(stli_dummyport.brdnr, stli_dummyport.panelnr,
stli_dummyport.portnr);
if (!portp)
return -ENODEV;
- if (copy_to_user(arg, portp, sizeof(stliport_t)))
+ if (copy_to_user(arg, portp, sizeof(struct stliport)))
return -EFAULT;
return 0;
}
* Return the entire driver board structure to a user app.
*/
-static int stli_getbrdstruct(stlibrd_t __user *arg)
+static int stli_getbrdstruct(struct stlibrd __user *arg)
{
- stlibrd_t *brdp;
+ struct stlibrd stli_dummybrd;
+ struct stlibrd *brdp;
- if (copy_from_user(&stli_dummybrd, arg, sizeof(stlibrd_t)))
+ if (copy_from_user(&stli_dummybrd, arg, sizeof(struct stlibrd)))
return -EFAULT;
- if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS))
+ if (stli_dummybrd.brdnr >= STL_MAXBRDS)
return -ENODEV;
brdp = stli_brds[stli_dummybrd.brdnr];
if (!brdp)
return -ENODEV;
- if (copy_to_user(arg, brdp, sizeof(stlibrd_t)))
+ if (copy_to_user(arg, brdp, sizeof(struct stlibrd)))
return -EFAULT;
return 0;
}
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
{
- stlibrd_t *brdp;
+ struct stlibrd *brdp;
int brdnr, rc, done;
void __user *argp = (void __user *)arg;
};
/*****************************************************************************/
+/*
+ * Loadable module initialization stuff.
+ */
+
+static void istallion_cleanup_isa(void)
+{
+ struct stlibrd *brdp;
+ unsigned int j;
+
+ for (j = 0; (j < stli_nrbrds); j++) {
+ if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED))
+ continue;
+
+ stli_cleanup_ports(brdp);
-static int __init stli_init(void)
+ iounmap(brdp->membase);
+ if (brdp->iosize > 0)
+ release_region(brdp->iobase, brdp->iosize);
+ kfree(brdp);
+ stli_brds[j] = NULL;
+ }
+}
+
+static int __init istallion_module_init(void)
{
- int i;
+ unsigned int i;
+ int retval;
+
printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
spin_lock_init(&stli_lock);
spin_lock_init(&brd_lock);
- stli_initbrds();
-
- stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
- if (!stli_serial)
- return -ENOMEM;
-
-/*
- * Allocate a temporary write buffer.
- */
stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
- if (!stli_txcookbuf)
+ if (!stli_txcookbuf) {
printk(KERN_ERR "STALLION: failed to allocate memory "
"(size=%d)\n", STLI_TXBUFSIZE);
+ retval = -ENOMEM;
+ goto err;
+ }
-/*
- * Set up a character driver for the shared memory region. We need this
- * to down load the slave code image. Also it is a useful debugging tool.
- */
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
- printk(KERN_ERR "STALLION: failed to register serial memory "
- "device\n");
-
- istallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++)
- class_device_create(istallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i),
- NULL, "staliomem%d", i);
+ stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+ if (!stli_serial) {
+ retval = -ENOMEM;
+ goto err_free;
+ }
-/*
- * Set up the tty driver structure and register us as a driver.
- */
stli_serial->owner = THIS_MODULE;
stli_serial->driver_name = stli_drvname;
stli_serial->name = stli_serialname;
stli_serial->type = TTY_DRIVER_TYPE_SERIAL;
stli_serial->subtype = SERIAL_TYPE_NORMAL;
stli_serial->init_termios = stli_deftermios;
- stli_serial->flags = TTY_DRIVER_REAL_RAW;
+ stli_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(stli_serial, &stli_ops);
- if (tty_register_driver(stli_serial)) {
- put_tty_driver(stli_serial);
+ retval = tty_register_driver(stli_serial);
+ if (retval) {
printk(KERN_ERR "STALLION: failed to register serial driver\n");
- return -EBUSY;
+ goto err_ttyput;
}
+
+ retval = stli_initbrds();
+ if (retval)
+ goto err_ttyunr;
+
+/*
+ * Set up a character driver for the shared memory region. We need this
+ * to down load the slave code image. Also it is a useful debugging tool.
+ */
+ retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
+ if (retval) {
+ printk(KERN_ERR "STALLION: failed to register serial memory "
+ "device\n");
+ goto err_deinit;
+ }
+
+ istallion_class = class_create(THIS_MODULE, "staliomem");
+ for (i = 0; i < 4; i++)
+ class_device_create(istallion_class, NULL,
+ MKDEV(STL_SIOMEMMAJOR, i),
+ NULL, "staliomem%d", i);
+
return 0;
+err_deinit:
+ pci_unregister_driver(&stli_pcidriver);
+ istallion_cleanup_isa();
+err_ttyunr:
+ tty_unregister_driver(stli_serial);
+err_ttyput:
+ put_tty_driver(stli_serial);
+err_free:
+ kfree(stli_txcookbuf);
+err:
+ return retval;
}
/*****************************************************************************/
+
+static void __exit istallion_module_exit(void)
+{
+ unsigned int j;
+
+ printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
+ stli_drvversion);
+
+ if (stli_timeron) {
+ stli_timeron = 0;
+ del_timer_sync(&stli_timerlist);
+ }
+
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+
+ for (j = 0; j < 4; j++)
+ class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
+ j));
+ class_destroy(istallion_class);
+
+ pci_unregister_driver(&stli_pcidriver);
+ istallion_cleanup_isa();
+
+ tty_unregister_driver(stli_serial);
+ put_tty_driver(stli_serial);
+
+ kfree(stli_txcookbuf);
+}
+
+module_init(istallion_module_init);
+module_exit(istallion_module_exit);
static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
{
- static const char *cur_chars = "BDCA";
+ static const char cur_chars[] = "BDCA";
if (up_flag)
return;
static ssize_t lp_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct parport *port = lp_table[minor].dev->port;
char *kbuf = lp_table[minor].lp_buffer;
ssize_t retv = 0;
size_t count, loff_t *ppos)
{
DEFINE_WAIT(wait);
- unsigned int minor=iminor(file->f_dentry->d_inode);
+ unsigned int minor=iminor(file->f_path.dentry->d_inode);
struct parport *port = lp_table[minor].dev->port;
ssize_t retval = 0;
char *kbuf = lp_table[minor].lp_buffer;
{
loff_t ret;
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch (orig) {
case 0:
file->f_pos = offset;
default:
ret = -EINVAL;
}
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return ret;
}
static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
static void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
-static void moxa_set_termios(struct tty_struct *, struct termios *);
+static void moxa_set_termios(struct tty_struct *, struct ktermios *);
static void moxa_stop(struct tty_struct *);
static void moxa_start(struct tty_struct *);
static void moxa_hangup(struct tty_struct *);
static void MoxaPortDisable(int);
static long MoxaPortGetMaxBaud(int);
static long MoxaPortSetBaud(int, long);
-static int MoxaPortSetTermio(int, struct termios *, speed_t);
+static int MoxaPortSetTermio(int, struct ktermios *, speed_t);
static int MoxaPortGetLineOut(int, int *, int *);
static void MoxaPortLineCtrl(int, int, int);
static void MoxaPortFlowCtrl(int, int, int, int, int, int);
moxaDriver->init_termios.c_oflag = 0;
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
moxaDriver->init_termios.c_lflag = 0;
+ moxaDriver->init_termios.c_ispeed = 9600;
+ moxaDriver->init_termios.c_ospeed = 9600;
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
}
static void moxa_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
static void set_tty_param(struct tty_struct *tty)
{
- register struct termios *ts;
+ register struct ktermios *ts;
struct moxa_str *ch;
int rts, cts, txflow, rxflow, xany;
static void receive_data(struct moxa_str *ch)
{
struct tty_struct *tp;
- struct termios *ts;
+ struct ktermios *ts;
unsigned long flags;
ts = NULL;
*
* Function 12: Configure the port.
* Syntax:
- * int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud);
+ * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
* int port : port number (0 - 127)
- * struct termios * termio : termio structure pointer
+ * struct ktermios * termio : termio structure pointer
* speed_t baud : baud rate
*
* return: -1 : this port is invalid or termio == NULL
return (baud);
}
-int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud)
+int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
{
void __iomem *ofsAddr;
tcflag_t cflag;
int xmit_tail;
int xmit_cnt;
struct work_struct tqueue;
- struct termios normal_termios;
- struct termios callout_termios;
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
static struct tty_driver *mxvar_sdriver;
static struct mxser_struct mxvar_table[MXSER_PORTS];
static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
-static struct termios *mxvar_termios[MXSER_PORTS + 1];
-static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
+static struct ktermios *mxvar_termios[MXSER_PORTS + 1];
+static struct ktermios *mxvar_termios_locked[MXSER_PORTS + 1];
static struct mxser_log mxvar_log;
static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
static int mxser_ioctl_special(unsigned int, void __user *);
static void mxser_throttle(struct tty_struct *);
static void mxser_unthrottle(struct tty_struct *);
-static void mxser_set_termios(struct tty_struct *, struct termios *);
+static void mxser_set_termios(struct tty_struct *, struct ktermios *);
static void mxser_stop(struct tty_struct *);
static void mxser_start(struct tty_struct *);
static void mxser_hangup(struct tty_struct *);
static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
static int mxser_startup(struct mxser_struct *);
static void mxser_shutdown(struct mxser_struct *);
-static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
+static int mxser_change_speed(struct mxser_struct *, struct ktermios *old_termios);
static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
if (pdev != NULL) { /* PCI */
release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
+ pci_dev_put(pdev);
} else {
release_region(mxsercfg[i].ioaddr[0], 8 * mxsercfg[i].ports);
release_region(mxsercfg[i].vector, 1);
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
/*if (verbose) */ {
- printk(KERN_DEBUG " ttyM%d - ttyM%d ",
+ printk(KERN_DEBUG " ttyMI%d - ttyMI%d ",
n, n + hwconf->ports - 1);
printk(" max. baud rate = %d bps.\n",
hwconf->MaxCanSetBaudRate[0]);
/* Initialize the tty_driver structure */
memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
- mxvar_sdriver->name = "ttyM";
+ mxvar_sdriver->name = "ttyMI";
mxvar_sdriver->major = ttymajor;
mxvar_sdriver->minor_start = 0;
mxvar_sdriver->num = MXSER_PORTS + 1;
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios;
mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ mxvar_sdriver->init_termios.c_ispeed = 9600;
+ mxvar_sdriver->init_termios.c_ospeed = 9600;
mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(mxvar_sdriver, &mxser_ops);
mxvar_sdriver->ttys = mxvar_tty;
index = 0;
b = 0;
while (b < n) {
- pdev = pci_find_device(mxser_pcibrds[b].vendor,
+ pdev = pci_get_device(mxser_pcibrds[b].vendor,
mxser_pcibrds[b].device, pdev);
- if (pdev == NULL) {
+ if (pdev == NULL) {
b++;
continue;
}
if (mxser_initbrd(m, &hwconf) < 0)
continue;
m++;
+ /* Keep an extra reference if we succeeded. It will
+ be returned at unload time */
+ pci_dev_get(pdev);
}
}
#endif
mxser_change_speed(info, NULL);
}
- info->session = current->signal->session;
+ info->session = process_session(current);
info->pgrp = process_group(current);
/*
/* MX_UNLOCK(&info->slock); */
}
-static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mxser_struct *info = tty->driver_data;
unsigned long flags;
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static int mxser_change_speed(struct mxser_struct *info, struct termios *old_termios)
+static int mxser_change_speed(struct mxser_struct *info, struct ktermios *old_termios)
{
unsigned cflag, cval, fcr;
int ret = 0;
--- /dev/null
+/*
+ * mxser.c -- MOXA Smartio/Industio family multiport serial driver.
+ *
+ * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 2006 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * This code is loosely based on the 1.8 moxa driver which is based on
+ * Linux serial driver, written by Linus Torvalds, Theodore T'so and
+ * others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
+ * <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
+ * - Fixed x86_64 cleanness
+ * - Fixed sleep with spinlock held in mxser_send_break
+ */
+
+#include <linux/module.h>
+#include <linux/autoconf.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/gfp.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#include "mxser_new.h"
+
+#define MXSER_VERSION "2.0"
+#define MXSERMAJOR 174
+#define MXSERCUMAJOR 175
+
+#define MXSER_EVENT_TXLOW 1
+
+#define MXSER_BOARDS 4 /* Max. boards */
+#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
+#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
+#define MXSER_ISR_PASS_LIMIT 99999L
+
+#define MXSER_ERR_IOADDR -1
+#define MXSER_ERR_IRQ -2
+#define MXSER_ERR_IRQ_CONFLIT -3
+#define MXSER_ERR_VECTOR -4
+
+#define WAKEUP_CHARS 256
+
+#define UART_MCR_AFE 0x20
+#define UART_LSR_SPECIAL 0x1E
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
+ IXON|IXOFF))
+
+#define C168_ASIC_ID 1
+#define C104_ASIC_ID 2
+#define C102_ASIC_ID 0xB
+#define CI132_ASIC_ID 4
+#define CI134_ASIC_ID 3
+#define CI104J_ASIC_ID 5
+
+#define MXSER_HIGHBAUD 1
+#define MXSER_HAS2 2
+
+/* This is only for PCI */
+static const struct {
+ int type;
+ int tx_fifo;
+ int rx_fifo;
+ int xmit_fifo_size;
+ int rx_high_water;
+ int rx_trigger;
+ int rx_low_water;
+ long max_baud;
+} Gpci_uart_info[] = {
+ {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
+ {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
+ {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
+};
+#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
+
+struct mxser_cardinfo {
+ unsigned int nports;
+ char *name;
+ unsigned int flags;
+};
+
+static const struct mxser_cardinfo mxser_cards[] = {
+ { 8, "C168 series", }, /* C168-ISA */
+ { 4, "C104 series", }, /* C104-ISA */
+ { 4, "CI-104J series", }, /* CI104J */
+ { 8, "C168H/PCI series", }, /* C168-PCI */
+ { 4, "C104H/PCI series", }, /* C104-PCI */
+ { 4, "C102 series", MXSER_HAS2 }, /* C102-ISA */
+ { 4, "CI-132 series", MXSER_HAS2 }, /* CI132 */
+ { 4, "CI-134 series", }, /* CI134 */
+ { 2, "CP-132 series", }, /* CP132 */
+ { 4, "CP-114 series", }, /* CP114 */
+ { 4, "CT-114 series", }, /* CT114 */
+ { 2, "CP-102 series", MXSER_HIGHBAUD }, /* CP102 */
+ { 4, "CP-104U series", }, /* CP104U */
+ { 8, "CP-168U series", }, /* CP168U */
+ { 2, "CP-132U series", }, /* CP132U */
+ { 4, "CP-134U series", }, /* CP134U */
+ { 4, "CP-104JU series", }, /* CP104JU */
+ { 8, "Moxa UC7000 Serial", }, /* RC7000 */
+ { 8, "CP-118U series", }, /* CP118U */
+ { 2, "CP-102UL series", }, /* CP102UL */
+ { 2, "CP-102U series", }, /* CP102U */
+ { 8, "CP-118EL series", }, /* CP118EL */
+ { 8, "CP-168EL series", }, /* CP168EL */
+ { 4, "CP-104EL series", } /* CP104EL */
+};
+
+/* driver_data correspond to the lines in the structure above
+ see also ISA probe function before you change something */
+static struct pci_device_id mxser_pcibrds[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168),
+ .driver_data = 3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104),
+ .driver_data = 4 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132),
+ .driver_data = 8 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114),
+ .driver_data = 9 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114),
+ .driver_data = 10 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102),
+ .driver_data = 11 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U),
+ .driver_data = 12 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U),
+ .driver_data = 13 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U),
+ .driver_data = 14 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U),
+ .driver_data = 15 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU),
+ .driver_data = 16 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000),
+ .driver_data = 17 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U),
+ .driver_data = 18 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
+ .driver_data = 19 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U),
+ .driver_data = 20 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL),
+ .driver_data = 21 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL),
+ .driver_data = 22 },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL),
+ .driver_data = 23 },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+
+static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
+static int ttymajor = MXSERMAJOR;
+static int calloutmajor = MXSERCUMAJOR;
+
+/* Variables for insmod */
+
+MODULE_AUTHOR("Casper Yang");
+MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
+module_param_array(ioaddr, int, NULL, 0);
+module_param(ttymajor, int, 0);
+MODULE_LICENSE("GPL");
+
+struct mxser_log {
+ int tick;
+ unsigned long rxcnt[MXSER_PORTS];
+ unsigned long txcnt[MXSER_PORTS];
+};
+
+
+struct mxser_mon {
+ unsigned long rxcnt;
+ unsigned long txcnt;
+ unsigned long up_rxcnt;
+ unsigned long up_txcnt;
+ int modem_status;
+ unsigned char hold_reason;
+};
+
+struct mxser_mon_ext {
+ unsigned long rx_cnt[32];
+ unsigned long tx_cnt[32];
+ unsigned long up_rxcnt[32];
+ unsigned long up_txcnt[32];
+ int modem_status[32];
+
+ long baudrate[32];
+ int databits[32];
+ int stopbits[32];
+ int parity[32];
+ int flowctrl[32];
+ int fifo[32];
+ int iftype[32];
+};
+
+struct mxser_board;
+
+struct mxser_port {
+ struct mxser_board *board;
+ struct tty_struct *tty;
+
+ unsigned long ioaddr;
+ unsigned long opmode_ioaddr;
+ int max_baud;
+
+ int rx_high_water;
+ int rx_trigger; /* Rx fifo trigger level */
+ int rx_low_water;
+ int baud_base; /* max. speed */
+ long realbaud;
+ int type; /* UART type */
+ int flags; /* defined in tty.h */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+
+ int x_char; /* xon/xoff character */
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+
+ unsigned char stop_rx;
+ unsigned char ldisc_stop_rx;
+
+ int custom_divisor;
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned char err_shadow;
+ unsigned long event;
+
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ struct async_icount icount; /* kernel counters for 4 input interrupts */
+ int timeout;
+
+ int read_status_mask;
+ int ignore_status_mask;
+ int xmit_fifo_size;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
+
+ struct mxser_mon mon_data;
+
+ spinlock_t slock;
+ struct work_struct tqueue;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+ wait_queue_head_t delta_msr_wait;
+};
+
+struct mxser_board {
+ unsigned int idx;
+ int irq;
+ const struct mxser_cardinfo *info;
+ unsigned long vector;
+ unsigned long vector_mask;
+
+ int chip_flag;
+ int uart_type;
+
+ struct mxser_port ports[MXSER_PORTS_PER_BOARD];
+};
+
+struct mxser_mstatus {
+ tcflag_t cflag;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+};
+
+static struct mxser_mstatus GMStatus[MXSER_PORTS];
+
+static int mxserBoardCAP[MXSER_BOARDS] = {
+ 0, 0, 0, 0
+ /* 0x180, 0x280, 0x200, 0x320 */
+};
+
+static struct mxser_board mxser_boards[MXSER_BOARDS];
+static struct tty_driver *mxvar_sdriver;
+static struct mxser_log mxvar_log;
+static int mxvar_diagflag;
+static unsigned char mxser_msr[MXSER_PORTS + 1];
+static struct mxser_mon_ext mon_data_ext;
+static int mxser_set_baud_method[MXSER_PORTS + 1];
+static spinlock_t gm_lock;
+
+static int CheckIsMoxaMust(int io)
+{
+ u8 oldmcr, hwid;
+ int i;
+
+ outb(0, io + UART_LCR);
+ DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
+ oldmcr = inb(io + UART_MCR);
+ outb(0, io + UART_MCR);
+ SET_MOXA_MUST_XON1_VALUE(io, 0x11);
+ if ((hwid = inb(io + UART_MCR)) != 0) {
+ outb(oldmcr, io + UART_MCR);
+ return MOXA_OTHER_UART;
+ }
+
+ GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
+ for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+ if (hwid == Gpci_uart_info[i].type)
+ return (int)hwid;
+ }
+ return MOXA_OTHER_UART;
+}
+
+static void process_txrx_fifo(struct mxser_port *info)
+{
+ int i;
+
+ if ((info->type == PORT_16450) || (info->type == PORT_8250)) {
+ info->rx_trigger = 1;
+ info->rx_high_water = 1;
+ info->rx_low_water = 1;
+ info->xmit_fifo_size = 1;
+ } else
+ for (i = 0; i < UART_INFO_NUM; i++)
+ if (info->board->chip_flag == Gpci_uart_info[i].type) {
+ info->rx_trigger = Gpci_uart_info[i].rx_trigger;
+ info->rx_low_water = Gpci_uart_info[i].rx_low_water;
+ info->rx_high_water = Gpci_uart_info[i].rx_high_water;
+ info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size;
+ break;
+ }
+}
+
+static void mxser_do_softint(struct work_struct *work)
+{
+ struct mxser_port *info = container_of(work, struct mxser_port, tqueue);
+ struct tty_struct *tty = info->tty;
+
+ if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
+ tty_wakeup(tty);
+}
+
+static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
+{
+ unsigned char status = 0;
+
+ status = inb(baseaddr + UART_MSR);
+
+ mxser_msr[port] &= 0x0F;
+ mxser_msr[port] |= status;
+ status = mxser_msr[port];
+ if (mode)
+ mxser_msr[port] = 0;
+
+ return status;
+}
+
+static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct mxser_port *port)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+ unsigned long flags;
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ test_bit(TTY_IO_ERROR, &tty->flags)) {
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, port->count is dropped by one, so that
+ * mxser_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&port->open_wait, &wait);
+
+ spin_lock_irqsave(&port->slock, flags);
+ if (!tty_hung_up_p(filp))
+ port->count--;
+ spin_unlock_irqrestore(&port->slock, flags);
+ port->blocked_open++;
+ while (1) {
+ spin_lock_irqsave(&port->slock, flags);
+ outb(inb(port->ioaddr + UART_MCR) |
+ UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&port->slock, flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(port->flags & ASYNC_CLOSING) &&
+ (do_clocal ||
+ (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ if (retval)
+ return retval;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int mxser_set_baud(struct mxser_port *info, long newspd)
+{
+ int quot = 0;
+ unsigned char cval;
+ int ret = 0;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+
+ if (!(info->ioaddr))
+ return ret;
+
+ if (newspd > info->max_baud)
+ return 0;
+
+ info->realbaud = newspd;
+ if (newspd == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (newspd) {
+ quot = info->baud_base / newspd;
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
+
+ info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
+ info->timeout += HZ / 50; /* Add .02 seconds of slop */
+
+ if (quot) {
+ spin_lock_irqsave(&info->slock, flags);
+ info->MCR |= UART_MCR_DTR;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ } else {
+ spin_lock_irqsave(&info->slock, flags);
+ info->MCR &= ~UART_MCR_DTR;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ret;
+ }
+
+ cval = inb(info->ioaddr + UART_LCR);
+
+ outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */
+
+ outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */
+ outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
+ outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
+
+
+ return ret;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static int mxser_change_speed(struct mxser_port *info,
+ struct ktermios *old_termios)
+{
+ unsigned cflag, cval, fcr;
+ int ret = 0;
+ unsigned char status;
+ long baud;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return ret;
+ cflag = info->tty->termios->c_cflag;
+ if (!(info->ioaddr))
+ return ret;
+
+ if (mxser_set_baud_method[info->tty->index] == 0) {
+ baud = tty_get_baud_rate(info->tty);
+ mxser_set_baud(info, baud);
+ }
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5:
+ cval = 0x00;
+ break;
+ case CS6:
+ cval = 0x01;
+ break;
+ case CS7:
+ cval = 0x02;
+ break;
+ case CS8:
+ cval = 0x03;
+ break;
+ default:
+ cval = 0x00;
+ break; /* too keep GCC shut... */
+ }
+ if (cflag & CSTOPB)
+ cval |= 0x04;
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+ if (cflag & CMSPAR)
+ cval |= UART_LCR_SPAR;
+
+ if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
+ if (info->board->chip_flag) {
+ fcr = UART_FCR_ENABLE_FIFO;
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else
+ fcr = 0;
+ } else {
+ fcr = UART_FCR_ENABLE_FIFO;
+ if (info->board->chip_flag) {
+ fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
+ SET_MOXA_MUST_FIFO_VALUE(info);
+ } else {
+ switch (info->rx_trigger) {
+ case 1:
+ fcr |= UART_FCR_TRIGGER_1;
+ break;
+ case 4:
+ fcr |= UART_FCR_TRIGGER_4;
+ break;
+ case 8:
+ fcr |= UART_FCR_TRIGGER_8;
+ break;
+ default:
+ fcr |= UART_FCR_TRIGGER_14;
+ break;
+ }
+ }
+ }
+
+ /* CTS flow control flag and modem status interrupts */
+ info->IER &= ~UART_IER_MSI;
+ info->MCR &= ~UART_MCR_AFE;
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->IER |= UART_IER_MSI;
+ if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
+ info->MCR |= UART_MCR_AFE;
+ } else {
+ status = inb(info->ioaddr + UART_MSR);
+ if (info->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ info->tty->hw_stopped = 0;
+ if (info->type != PORT_16550A &&
+ !info->board->chip_flag) {
+ outb(info->IER & ~UART_IER_THRI,
+ info->ioaddr +
+ UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr +
+ UART_IER);
+ }
+ set_bit(MXSER_EVENT_TXLOW, &info->event);
+ schedule_work(&info->tqueue); }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ info->tty->hw_stopped = 1;
+ if ((info->type != PORT_16550A) &&
+ (!info->board->chip_flag)) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr +
+ UART_IER);
+ }
+ }
+ }
+ }
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ }
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ if (cflag & CLOCAL) {
+ info->flags &= ~ASYNC_CHECK_CD;
+ } else {
+ info->flags |= ASYNC_CHECK_CD;
+ info->IER |= UART_IER_MSI;
+ }
+ outb(info->IER, info->ioaddr + UART_IER);
+
+ /*
+ * Set up parity check flag
+ */
+ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
+
+ info->ignore_status_mask = 0;
+
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ info->read_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty)) {
+ info->ignore_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ info->read_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ }
+ }
+ if (info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
+ SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+ if (I_IXON(info->tty)) {
+ ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ } else {
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ }
+ if (I_IXOFF(info->tty)) {
+ ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ } else {
+ DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+
+
+ outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
+ outb(cval, info->ioaddr + UART_LCR);
+
+ return ret;
+}
+
+static void mxser_check_modem_status(struct mxser_port *port, int status)
+{
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ port->icount.cts++;
+ port->mon_data.modem_status = status;
+ wake_up_interruptible(&port->delta_msr_wait);
+
+ if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+ if (status & UART_MSR_DCD)
+ wake_up_interruptible(&port->open_wait);
+ schedule_work(&port->tqueue);
+ }
+
+ if (port->flags & ASYNC_CTS_FLOW) {
+ if (port->tty->hw_stopped) {
+ if (status & UART_MSR_CTS) {
+ port->tty->hw_stopped = 0;
+
+ if ((port->type != PORT_16550A) &&
+ (!port->board->chip_flag)) {
+ outb(port->IER & ~UART_IER_THRI,
+ port->ioaddr + UART_IER);
+ port->IER |= UART_IER_THRI;
+ outb(port->IER, port->ioaddr +
+ UART_IER);
+ }
+ set_bit(MXSER_EVENT_TXLOW, &port->event);
+ schedule_work(&port->tqueue);
+ }
+ } else {
+ if (!(status & UART_MSR_CTS)) {
+ port->tty->hw_stopped = 1;
+ if (port->type != PORT_16550A &&
+ !port->board->chip_flag) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr +
+ UART_IER);
+ }
+ }
+ }
+ }
+}
+
+static int mxser_startup(struct mxser_port *info)
+{
+ unsigned long page;
+ unsigned long flags;
+
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+
+ if (!info->ioaddr || !info->type) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ free_page(page);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+ }
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in mxser_change_speed())
+ */
+ if (info->board->chip_flag)
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
+ else
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+
+ /*
+ * At this point there's no way the LSR could still be 0xFF;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (inb(info->ioaddr + UART_LSR) == 0xff) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ return 0;
+ } else
+ return -ENODEV;
+ }
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) inb(info->ioaddr + UART_LSR);
+ (void) inb(info->ioaddr + UART_RX);
+ (void) inb(info->ioaddr + UART_IIR);
+ (void) inb(info->ioaddr + UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */
+ info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+
+ /*
+ * Finally, enable interrupts
+ */
+ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+
+ if (info->board->chip_flag)
+ info->IER |= MOXA_MUST_IER_EGDAI;
+ outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */
+
+ /*
+ * And clear the interrupt registers again for luck.
+ */
+ (void) inb(info->ioaddr + UART_LSR);
+ (void) inb(info->ioaddr + UART_RX);
+ (void) inb(info->ioaddr + UART_IIR);
+ (void) inb(info->ioaddr + UART_MSR);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ /*
+ * and set the speed of the serial port
+ */
+ spin_unlock_irqrestore(&info->slock, flags);
+ mxser_change_speed(info, NULL);
+
+ info->flags |= ASYNC_INITIALIZED;
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts maybe disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mxser_shutdown(struct mxser_port *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be waken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ, if necessary
+ */
+ if (info->xmit_buf) {
+ free_page((unsigned long) info->xmit_buf);
+ info->xmit_buf = NULL;
+ }
+
+ info->IER = 0;
+ outb(0x00, info->ioaddr + UART_IER);
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
+ outb(info->MCR, info->ioaddr + UART_MCR);
+
+ /* clear Rx/Tx FIFO's */
+ if (info->board->chip_flag)
+ outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE,
+ info->ioaddr + UART_FCR);
+ else
+ outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+ info->ioaddr + UART_FCR);
+
+ /* read data port to reset things */
+ (void) inb(info->ioaddr + UART_RX);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+
+ if (info->board->chip_flag)
+ SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int mxser_open(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info;
+ int retval, line;
+
+ /* initialize driver_data in case something fails */
+ tty->driver_data = NULL;
+
+ line = tty->index;
+ if (line == MXSER_PORTS)
+ return 0;
+ if (line < 0 || line > MXSER_PORTS)
+ return -ENODEV;
+ info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD];
+ if (!info->ioaddr)
+ return -ENODEV;
+
+ tty->driver_data = info;
+ info->tty = tty;
+ /*
+ * Start up serial port
+ */
+ info->count++;
+ retval = mxser_startup(info);
+ if (retval)
+ return retval;
+
+ retval = mxser_block_til_ready(tty, filp, info);
+ if (retval)
+ return retval;
+
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ mxser_change_speed(info, NULL);
+ }
+
+ info->session = process_session(current);
+ info->pgrp = process_group(current);
+
+ /* unmark here for very high baud rate (ex. 921600 bps) used */
+ tty->low_latency = 1;
+ return 0;
+}
+
+/*
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void mxser_close(struct tty_struct *tty, struct file *filp)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ unsigned long timeout;
+ unsigned long flags;
+
+ if (tty->index == MXSER_PORTS)
+ return;
+ if (!info)
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (tty_hung_up_p(filp)) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk(KERN_ERR "mxser_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk(KERN_ERR "mxser_close: bad serial port count for "
+ "ttys%d: %d\n", tty->index, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ spin_unlock_irqrestore(&info->slock, flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ spin_unlock_irqrestore(&info->slock, flags);
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ 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.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the receive line status interrupts, and tell the
+ * interrupt driver to stop checking the data ready bit in the
+ * line status register.
+ */
+ info->IER &= ~UART_IER_RLSI;
+ if (info->board->chip_flag)
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ outb(info->IER, info->ioaddr + UART_IER);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ timeout = jiffies + HZ;
+ while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
+ schedule_timeout_interruptible(5);
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ }
+ mxser_shutdown(info);
+
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+
+ tty_ldisc_flush(tty);
+
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->close_delay)
+ schedule_timeout_interruptible(info->close_delay);
+ wake_up_interruptible(&info->open_wait);
+ }
+
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+
+}
+
+static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!info->xmit_buf)
+ return 0;
+
+ while (1) {
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ buf += c;
+ count -= c;
+ total += c;
+ }
+
+ if (info->xmit_cnt && !tty->stopped) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ (info->board->chip_flag)) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr +
+ UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ }
+ return total;
+}
+
+static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!info->xmit_buf)
+ return;
+
+ if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_buf[info->xmit_head++] = ch;
+ info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+ info->xmit_cnt++;
+ spin_unlock_irqrestore(&info->slock, flags);
+ if (!tty->stopped) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+ }
+}
+
+
+static void mxser_flush_chars(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if (info->xmit_cnt <= 0 ||
+ tty->stopped ||
+ !info->xmit_buf ||
+ (tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->board->chip_flag)
+ ))
+ return;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static int mxser_write_room(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ int ret;
+
+ ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+}
+
+static int mxser_chars_in_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ return info->xmit_cnt;
+}
+
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ char fcr;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ fcr = inb(info->ioaddr + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+ outb(fcr, info->ioaddr + UART_FCR);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_wakeup(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * friends of mxser_ioctl()
+ * ------------------------------------------------------------
+ */
+static int mxser_get_serial_info(struct mxser_port *info,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->tty->index;
+ tmp.port = info->ioaddr;
+ tmp.irq = info->board->irq;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ tmp.custom_divisor = info->custom_divisor;
+ tmp.hub6 = 0;
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int mxser_set_serial_info(struct mxser_port *info,
+ struct serial_struct __user *new_info)
+{
+ struct serial_struct new_serial;
+ unsigned int flags;
+ int retval = 0;
+
+ if (!new_info || !info->ioaddr)
+ return -EFAULT;
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+
+ if ((new_serial.irq != info->board->irq) ||
+ (new_serial.port != info->ioaddr) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return -EPERM;
+
+ flags = info->flags & ASYNC_SPD_MASK;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ } else {
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->close_delay = new_serial.close_delay * HZ / 100;
+ info->closing_wait = new_serial.closing_wait * HZ / 100;
+ info->tty->low_latency =
+ (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency = 0;
+ }
+
+ info->type = new_serial.type;
+
+ process_txrx_fifo(info);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ if (flags != (info->flags & ASYNC_SPD_MASK))
+ mxser_change_speed(info, NULL);
+ } else
+ retval = mxser_startup(info);
+
+ return retval;
+}
+
+/*
+ * mxser_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int mxser_get_lsr_info(struct mxser_port *info,
+ unsigned int __user *value)
+{
+ unsigned char status;
+ unsigned int result;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->ioaddr + UART_LSR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+ return put_user(result, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void mxser_send_break(struct mxser_port *info, int duration)
+{
+ unsigned long flags;
+
+ if (!info->ioaddr)
+ return;
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ schedule_timeout(duration);
+ spin_lock_irqsave(&info->slock, flags);
+ outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned char control, status;
+ unsigned long flags;
+
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ control = info->MCR;
+
+ spin_lock_irqsave(&info->slock, flags);
+ status = inb(info->ioaddr + UART_MSR);
+ if (status & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, status);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+}
+
+static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+
+ if (tty->index == MXSER_PORTS)
+ return -ENOIOCTLCMD;
+ if (test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ spin_lock_irqsave(&info->slock, flags);
+
+ if (set & TIOCM_RTS)
+ info->MCR |= UART_MCR_RTS;
+ if (set & TIOCM_DTR)
+ info->MCR |= UART_MCR_DTR;
+
+ if (clear & TIOCM_RTS)
+ info->MCR &= ~UART_MCR_RTS;
+ if (clear & TIOCM_DTR)
+ info->MCR &= ~UART_MCR_DTR;
+
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+ return 0;
+}
+
+static int mxser_program_mode(int port)
+{
+ int id, i, j, n;
+
+ spin_lock(&gm_lock);
+ outb(0, port);
+ outb(0, port);
+ outb(0, port);
+ (void)inb(port);
+ (void)inb(port);
+ outb(0, port);
+ (void)inb(port);
+ spin_unlock(&gm_lock);
+
+ id = inb(port + 1) & 0x1F;
+ if ((id != C168_ASIC_ID) &&
+ (id != C104_ASIC_ID) &&
+ (id != C102_ASIC_ID) &&
+ (id != CI132_ASIC_ID) &&
+ (id != CI134_ASIC_ID) &&
+ (id != CI104J_ASIC_ID))
+ return -1;
+ for (i = 0, j = 0; i < 4; i++) {
+ n = inb(port + 2);
+ if (n == 'M') {
+ j = 1;
+ } else if ((j == 1) && (n == 1)) {
+ j = 2;
+ break;
+ } else
+ j = 0;
+ }
+ if (j != 2)
+ id = -2;
+ return id;
+}
+
+static void mxser_normal_mode(int port)
+{
+ int i, n;
+
+ outb(0xA5, port + 1);
+ outb(0x80, port + 3);
+ outb(12, port + 0); /* 9600 bps */
+ outb(0, port + 1);
+ outb(0x03, port + 3); /* 8 data bits */
+ outb(0x13, port + 4); /* loop back mode */
+ for (i = 0; i < 16; i++) {
+ n = inb(port + 5);
+ if ((n & 0x61) == 0x60)
+ break;
+ if ((n & 1) == 1)
+ (void)inb(port);
+ }
+ outb(0x00, port + 4);
+}
+
+#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
+#define CHIP_DO 0x02 /* Serial Data Output in Eprom */
+#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */
+#define CHIP_DI 0x08 /* Serial Data Input in Eprom */
+#define EN_CCMD 0x000 /* Chip's command register */
+#define EN0_RSARLO 0x008 /* Remote start address reg 0 */
+#define EN0_RSARHI 0x009 /* Remote start address reg 1 */
+#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */
+#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */
+#define EN0_DCFG 0x00E /* Data configuration reg WR */
+#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
+#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
+#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
+static int mxser_read_register(int port, unsigned short *regs)
+{
+ int i, k, value, id;
+ unsigned int j;
+
+ id = mxser_program_mode(port);
+ if (id < 0)
+ return id;
+ for (i = 0; i < 14; i++) {
+ k = (i & 0x3F) | 0x180;
+ for (j = 0x100; j > 0; j >>= 1) {
+ outb(CHIP_CS, port);
+ if (k & j) {
+ outb(CHIP_CS | CHIP_DO, port);
+ outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */
+ } else {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
+ }
+ }
+ (void)inb(port);
+ value = 0;
+ for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
+ outb(CHIP_CS, port);
+ outb(CHIP_CS | CHIP_SK, port);
+ if (inb(port) & CHIP_DI)
+ value |= j;
+ }
+ regs[i] = value;
+ outb(0, port);
+ }
+ mxser_normal_mode(port);
+ return id;
+}
+
+static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
+{
+ struct mxser_port *port;
+ int result, status;
+ unsigned int i, j;
+
+ switch (cmd) {
+ case MOXA_GET_CONF:
+/* if (copy_to_user(argp, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
+ return -EFAULT;
+ return 0;*/
+ return -ENXIO;
+ case MOXA_GET_MAJOR:
+ if (copy_to_user(argp, &ttymajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_GET_CUMAJOR:
+ if (copy_to_user(argp, &calloutmajor, sizeof(int)))
+ return -EFAULT;
+ return 0;
+
+ case MOXA_CHKPORTENABLE:
+ result = 0;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
+ if (mxser_boards[i].ports[j].ioaddr)
+ result |= (1 << i);
+
+ return put_user(result, (unsigned long __user *)argp);
+ case MOXA_GETDATACOUNT:
+ if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
+ return -EFAULT;
+ return 0;
+ case MOXA_GETMSTATUS:
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ port = &mxser_boards[i].ports[j];
+
+ GMStatus[i].ri = 0;
+ if (!port->ioaddr) {
+ GMStatus[i].dcd = 0;
+ GMStatus[i].dsr = 0;
+ GMStatus[i].cts = 0;
+ continue;
+ }
+
+ if (!port->tty || !port->tty->termios)
+ GMStatus[i].cflag =
+ port->normal_termios.c_cflag;
+ else
+ GMStatus[i].cflag =
+ port->tty->termios->c_cflag;
+
+ status = inb(port->ioaddr + UART_MSR);
+ if (status & 0x80 /*UART_MSR_DCD */ )
+ GMStatus[i].dcd = 1;
+ else
+ GMStatus[i].dcd = 0;
+
+ if (status & 0x20 /*UART_MSR_DSR */ )
+ GMStatus[i].dsr = 1;
+ else
+ GMStatus[i].dsr = 0;
+
+
+ if (status & 0x10 /*UART_MSR_CTS */ )
+ GMStatus[i].cts = 1;
+ else
+ GMStatus[i].cts = 0;
+ }
+ if (copy_to_user(argp, GMStatus,
+ sizeof(struct mxser_mstatus) * MXSER_PORTS))
+ return -EFAULT;
+ return 0;
+ case MOXA_ASPP_MON_EXT: {
+ int status, p, shiftbit;
+ unsigned long opmode;
+ unsigned cflag, iflag;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
+ port = &mxser_boards[i].ports[j];
+ if (!port->ioaddr)
+ continue;
+
+ status = mxser_get_msr(port->ioaddr, 0, i);
+
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ port->icount.cts++;
+
+ port->mon_data.modem_status = status;
+ mon_data_ext.rx_cnt[i] = port->mon_data.rxcnt;
+ mon_data_ext.tx_cnt[i] = port->mon_data.txcnt;
+ mon_data_ext.up_rxcnt[i] =
+ port->mon_data.up_rxcnt;
+ mon_data_ext.up_txcnt[i] =
+ port->mon_data.up_txcnt;
+ mon_data_ext.modem_status[i] =
+ port->mon_data.modem_status;
+ mon_data_ext.baudrate[i] = port->realbaud;
+
+ if (!port->tty || !port->tty->termios) {
+ cflag = port->normal_termios.c_cflag;
+ iflag = port->normal_termios.c_iflag;
+ } else {
+ cflag = port->tty->termios->c_cflag;
+ iflag = port->tty->termios->c_iflag;
+ }
+
+ mon_data_ext.databits[i] = cflag & CSIZE;
+
+ mon_data_ext.stopbits[i] = cflag & CSTOPB;
+
+ mon_data_ext.parity[i] =
+ cflag & (PARENB | PARODD | CMSPAR);
+
+ mon_data_ext.flowctrl[i] = 0x00;
+
+ if (cflag & CRTSCTS)
+ mon_data_ext.flowctrl[i] |= 0x03;
+
+ if (iflag & (IXON | IXOFF))
+ mon_data_ext.flowctrl[i] |= 0x0C;
+
+ if (port->type == PORT_16550A)
+ mon_data_ext.fifo[i] = 1;
+ else
+ mon_data_ext.fifo[i] = 0;
+
+ p = i % 4;
+ shiftbit = p * 2;
+ opmode = inb(port->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+
+ mon_data_ext.iftype[i] = opmode;
+
+ }
+ if (copy_to_user(argp, &mon_data_ext,
+ sizeof(mon_data_ext)))
+ return -EFAULT;
+
+ return 0;
+
+ } default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int mxser_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mxser_port *info = tty->driver_data;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser;
+ unsigned long templ;
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
+ int retval;
+
+ if (tty->index == MXSER_PORTS)
+ return mxser_ioctl_special(cmd, argp);
+
+ if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
+ int p;
+ unsigned long opmode;
+ static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
+ int shiftbit;
+ unsigned char val, mask;
+
+ p = tty->index % 4;
+ if (cmd == MOXA_SET_OP_MODE) {
+ if (get_user(opmode, (int __user *) argp))
+ return -EFAULT;
+ if (opmode != RS232_MODE &&
+ opmode != RS485_2WIRE_MODE &&
+ opmode != RS422_MODE &&
+ opmode != RS485_4WIRE_MODE)
+ return -EFAULT;
+ mask = ModeMask[p];
+ shiftbit = p * 2;
+ val = inb(info->opmode_ioaddr);
+ val &= mask;
+ val |= (opmode << shiftbit);
+ outb(val, info->opmode_ioaddr);
+ } else {
+ shiftbit = p * 2;
+ opmode = inb(info->opmode_ioaddr) >> shiftbit;
+ opmode &= OP_MODE_MASK;
+ if (copy_to_user(argp, &opmode, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+
+ if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
+ test_bit(TTY_IO_ERROR, &tty->flags))
+ return -EIO;
+
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ mxser_send_break(info, HZ / 4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
+ return 0;
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
+ case TIOCSSOFTCAR:
+ if (get_user(templ, (unsigned long __user *) argp))
+ return -EFAULT;
+ arg = templ;
+ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCGSERIAL:
+ return mxser_get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ return mxser_set_serial_info(info, argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return mxser_get_lsr_info(info, argp);
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT: {
+ DECLARE_WAITQUEUE(wait, current);
+ int ret;
+ spin_lock_irqsave(&info->slock, flags);
+ cprev = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ add_wait_queue(&info->delta_msr_wait, &wait);
+ while (1) {
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount; /* atomic copy */
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (((arg & TIOCM_RNG) &&
+ (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) &&
+ (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) &&
+ (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) &&
+ (cnow.cts != cprev.cts))) {
+ ret = 0;
+ break;
+ }
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ cprev = cnow;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->delta_msr_wait, &wait);
+ break;
+ }
+ /* NOTREACHED */
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->slock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->slock, flags);
+ p_cuser = argp;
+ if (put_user(cnow.frame, &p_cuser->frame))
+ return -EFAULT;
+ if (put_user(cnow.brk, &p_cuser->brk))
+ return -EFAULT;
+ if (put_user(cnow.overrun, &p_cuser->overrun))
+ return -EFAULT;
+ if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+ return -EFAULT;
+ if (put_user(cnow.parity, &p_cuser->parity))
+ return -EFAULT;
+ if (put_user(cnow.rx, &p_cuser->rx))
+ return -EFAULT;
+ if (put_user(cnow.tx, &p_cuser->tx))
+ return -EFAULT;
+ put_user(cnow.cts, &p_cuser->cts);
+ put_user(cnow.dsr, &p_cuser->dsr);
+ put_user(cnow.rng, &p_cuser->rng);
+ put_user(cnow.dcd, &p_cuser->dcd);
+ return 0;
+ case MOXA_HighSpeedOn:
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+ case MOXA_SDS_RSTICOUNTER:
+ info->mon_data.rxcnt = 0;
+ info->mon_data.txcnt = 0;
+ return 0;
+ case MOXA_ASPP_SETBAUD:{
+ long baud;
+ if (get_user(baud, (long __user *)argp))
+ return -EFAULT;
+ mxser_set_baud(info, baud);
+ return 0;
+ }
+ case MOXA_ASPP_GETBAUD:
+ if (copy_to_user(argp, &info->realbaud, sizeof(long)))
+ return -EFAULT;
+
+ return 0;
+
+ case MOXA_ASPP_OQUEUE:{
+ int len, lsr;
+
+ len = mxser_chars_in_buffer(tty);
+
+ lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
+
+ len += (lsr ? 0 : 1);
+
+ if (copy_to_user(argp, &len, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case MOXA_ASPP_MON: {
+ int mcr, status;
+
+ status = mxser_get_msr(info->ioaddr, 1, tty->index);
+ mxser_check_modem_status(info, status);
+
+ mcr = inb(info->ioaddr + UART_MCR);
+ if (mcr & MOXA_MUST_MCR_XON_FLAG)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD;
+
+ if (mcr & MOXA_MUST_MCR_TX_XON)
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT;
+ else
+ info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
+
+ if (info->tty->hw_stopped)
+ info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
+ else
+ info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
+
+ if (copy_to_user(argp, &info->mon_data,
+ sizeof(struct mxser_mon)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case MOXA_ASPP_LSTATUS: {
+ if (copy_to_user(argp, &info->err_shadow,
+ sizeof(unsigned char)))
+ return -EFAULT;
+
+ info->err_shadow = 0;
+ return 0;
+ }
+ case MOXA_SET_BAUD_METHOD: {
+ int method;
+
+ if (get_user(method, (int __user *)argp))
+ return -EFAULT;
+ mxser_set_baud_method[tty->index] = method;
+ if (copy_to_user(argp, &method, sizeof(int)))
+ return -EFAULT;
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void mxser_stoprx(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ info->ldisc_stop_rx = 1;
+ if (I_IXOFF(tty)) {
+ if (info->board->chip_flag) {
+ info->IER &= ~MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->ioaddr + UART_IER);
+ } else {
+ info->x_char = STOP_CHAR(tty);
+ outb(0, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ }
+
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR &= ~UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ }
+}
+
+/*
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ */
+static void mxser_throttle(struct tty_struct *tty)
+{
+ mxser_stoprx(tty);
+}
+
+static void mxser_unthrottle(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ /* startrx */
+ info->ldisc_stop_rx = 0;
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else {
+ if (info->board->chip_flag) {
+ info->IER |= MOXA_MUST_RECV_ISR;
+ outb(info->IER, info->ioaddr + UART_IER);
+ } else {
+ info->x_char = START_CHAR(tty);
+ outb(0, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ }
+ }
+
+ if (info->tty->termios->c_cflag & CRTSCTS) {
+ info->MCR |= UART_MCR_RTS;
+ outb(info->MCR, info->ioaddr + UART_MCR);
+ }
+}
+
+/*
+ * mxser_stop() and mxser_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ */
+static void mxser_stop(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (info->IER & UART_IER_THRI) {
+ info->IER &= ~UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_start(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (info->xmit_cnt && info->xmit_buf) {
+ outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
+ info->IER |= UART_IER_THRI;
+ outb(info->IER, info->ioaddr + UART_IER);
+ }
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+ (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+
+ mxser_change_speed(info, old_termios);
+
+ if ((old_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->stopped = 0;
+
+ if (info->board->chip_flag) {
+ spin_lock_irqsave(&info->slock, flags);
+ DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ spin_unlock_irqrestore(&info->slock, flags);
+ }
+
+ mxser_start(tty);
+ }
+}
+
+/*
+ * mxser_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+ int lsr;
+
+ if (info->type == PORT_UNKNOWN)
+ return;
+
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout && timeout < char_time)
+ char_time = timeout;
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2 * info->timeout)
+ timeout = 2 * info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+ timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+ while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+ schedule_timeout_interruptible(char_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+ printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * This routine is called by tty_hangup() when a hangup is signaled.
+ */
+void mxser_hangup(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+
+ mxser_flush_buffer(tty);
+ mxser_shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ info->tty = NULL;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * mxser_rs_break() --- routine which turns the break handling on or off
+ */
+static void mxser_rs_break(struct tty_struct *tty, int break_state)
+{
+ struct mxser_port *info = tty->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->slock, flags);
+ if (break_state == -1)
+ outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ else
+ outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC,
+ info->ioaddr + UART_LCR);
+ spin_unlock_irqrestore(&info->slock, flags);
+}
+
+static void mxser_receive_chars(struct mxser_port *port, int *status)
+{
+ struct tty_struct *tty = port->tty;
+ unsigned char ch, gdl;
+ int ignored = 0;
+ int cnt = 0;
+ int recv_room;
+ int max = 256;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->slock, flags);
+
+ recv_room = tty->receive_room;
+ if ((recv_room == 0) && (!port->ldisc_stop_rx))
+ mxser_stoprx(tty);
+
+ if (port->board->chip_flag != MOXA_OTHER_UART) {
+
+ if (*status & UART_LSR_SPECIAL)
+ goto intr_old;
+ if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
+ (*status & MOXA_MUST_LSR_RERR))
+ goto intr_old;
+ if (*status & MOXA_MUST_LSR_RERR)
+ goto intr_old;
+
+ gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
+
+ if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
+ gdl &= MOXA_MUST_GDL_MASK;
+ if (gdl >= recv_room) {
+ if (!port->ldisc_stop_rx)
+ mxser_stoprx(tty);
+ }
+ while (gdl--) {
+ ch = inb(port->ioaddr + UART_RX);
+ tty_insert_flip_char(tty, ch, 0);
+ cnt++;
+ }
+ goto end_intr;
+ }
+intr_old:
+
+ do {
+ if (max-- < 0)
+ break;
+
+ ch = inb(port->ioaddr + UART_RX);
+ if (port->board->chip_flag && (*status & UART_LSR_OE))
+ outb(0x23, port->ioaddr + UART_FCR);
+ *status &= port->read_status_mask;
+ if (*status & port->ignore_status_mask) {
+ if (++ignored > 100)
+ break;
+ } else {
+ char flag = 0;
+ if (*status & UART_LSR_SPECIAL) {
+ if (*status & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ port->icount.brk++;
+
+ if (port->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (*status & UART_LSR_PE) {
+ flag = TTY_PARITY;
+ port->icount.parity++;
+ } else if (*status & UART_LSR_FE) {
+ flag = TTY_FRAME;
+ port->icount.frame++;
+ } else if (*status & UART_LSR_OE) {
+ flag = TTY_OVERRUN;
+ port->icount.overrun++;
+ }
+ }
+ tty_insert_flip_char(tty, ch, flag);
+ cnt++;
+ if (cnt >= recv_room) {
+ if (!port->ldisc_stop_rx)
+ mxser_stoprx(tty);
+ break;
+ }
+
+ }
+
+ if (port->board->chip_flag)
+ break;
+
+ *status = inb(port->ioaddr + UART_LSR);
+ } while (*status & UART_LSR_DR);
+
+end_intr:
+ mxvar_log.rxcnt[port->tty->index] += cnt;
+ port->mon_data.rxcnt += cnt;
+ port->mon_data.up_rxcnt += cnt;
+ spin_unlock_irqrestore(&port->slock, flags);
+
+ tty_flip_buffer_push(tty);
+}
+
+static void mxser_transmit_chars(struct mxser_port *port)
+{
+ int count, cnt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->slock, flags);
+
+ if (port->x_char) {
+ outb(port->x_char, port->ioaddr + UART_TX);
+ port->x_char = 0;
+ mxvar_log.txcnt[port->tty->index]++;
+ port->mon_data.txcnt++;
+ port->mon_data.up_txcnt++;
+ port->icount.tx++;
+ goto unlock;
+ }
+
+ if (port->xmit_buf == 0)
+ goto unlock;
+
+ if ((port->xmit_cnt <= 0) || port->tty->stopped ||
+ (port->tty->hw_stopped &&
+ (port->type != PORT_16550A) &&
+ (!port->board->chip_flag))) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr + UART_IER);
+ goto unlock;
+ }
+
+ cnt = port->xmit_cnt;
+ count = port->xmit_fifo_size;
+ do {
+ outb(port->xmit_buf[port->xmit_tail++],
+ port->ioaddr + UART_TX);
+ port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ if (--port->xmit_cnt <= 0)
+ break;
+ } while (--count > 0);
+ mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
+
+ port->mon_data.txcnt += (cnt - port->xmit_cnt);
+ port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
+ port->icount.tx += (cnt - port->xmit_cnt);
+
+ if (port->xmit_cnt < WAKEUP_CHARS) {
+ set_bit(MXSER_EVENT_TXLOW, &port->event);
+ schedule_work(&port->tqueue);
+ }
+ if (port->xmit_cnt <= 0) {
+ port->IER &= ~UART_IER_THRI;
+ outb(port->IER, port->ioaddr + UART_IER);
+ }
+unlock:
+ spin_unlock_irqrestore(&port->slock, flags);
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
+{
+ int status, iir, i;
+ struct mxser_board *brd = NULL;
+ struct mxser_port *port;
+ int max, irqbits, bits, msr;
+ int pass_counter = 0;
+ unsigned int int_cnt;
+ int handled = IRQ_NONE;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (dev_id == &mxser_boards[i]) {
+ brd = dev_id;
+ break;
+ }
+
+ if (i == MXSER_BOARDS)
+ goto irq_stop;
+ if (brd == NULL)
+ goto irq_stop;
+ max = brd->info->nports;
+ while (1) {
+ irqbits = inb(brd->vector) & brd->vector_mask;
+ if (irqbits == brd->vector_mask)
+ break;
+
+ handled = IRQ_HANDLED;
+ for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+ if (irqbits == brd->vector_mask)
+ break;
+ if (bits & irqbits)
+ continue;
+ port = &brd->ports[i];
+
+ int_cnt = 0;
+ do {
+ iir = inb(port->ioaddr + UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ break;
+ iir &= MOXA_MUST_IIR_MASK;
+ if (!port->tty) {
+ status = inb(port->ioaddr + UART_LSR);
+ outb(0x27, port->ioaddr + UART_FCR);
+ inb(port->ioaddr + UART_MSR);
+ break;
+ }
+
+ status = inb(port->ioaddr + UART_LSR);
+
+ if (status & UART_LSR_PE)
+ port->err_shadow |= NPPI_NOTIFY_PARITY;
+ if (status & UART_LSR_FE)
+ port->err_shadow |= NPPI_NOTIFY_FRAMING;
+ if (status & UART_LSR_OE)
+ port->err_shadow |=
+ NPPI_NOTIFY_HW_OVERRUN;
+ if (status & UART_LSR_BI)
+ port->err_shadow |= NPPI_NOTIFY_BREAK;
+
+ if (port->board->chip_flag) {
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
+ mxser_receive_chars(port,
+ &status);
+
+ } else {
+ status &= port->read_status_mask;
+ if (status & UART_LSR_DR)
+ mxser_receive_chars(port,
+ &status);
+ }
+ msr = inb(port->ioaddr + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(port, msr);
+
+ if (port->board->chip_flag) {
+ if (iir == 0x02 && (status &
+ UART_LSR_THRE))
+ mxser_transmit_chars(port);
+ } else {
+ if (status & UART_LSR_THRE)
+ mxser_transmit_chars(port);
+ }
+ } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
+ }
+ if (pass_counter++ > MXSER_ISR_PASS_LIMIT)
+ break; /* Prevent infinite loops */
+ }
+
+irq_stop:
+ return handled;
+}
+
+static const struct tty_operations mxser_ops = {
+ .open = mxser_open,
+ .close = mxser_close,
+ .write = mxser_write,
+ .put_char = mxser_put_char,
+ .flush_chars = mxser_flush_chars,
+ .write_room = mxser_write_room,
+ .chars_in_buffer = mxser_chars_in_buffer,
+ .flush_buffer = mxser_flush_buffer,
+ .ioctl = mxser_ioctl,
+ .throttle = mxser_throttle,
+ .unthrottle = mxser_unthrottle,
+ .set_termios = mxser_set_termios,
+ .stop = mxser_stop,
+ .start = mxser_start,
+ .hangup = mxser_hangup,
+ .break_ctl = mxser_rs_break,
+ .wait_until_sent = mxser_wait_until_sent,
+ .tiocmget = mxser_tiocmget,
+ .tiocmset = mxser_tiocmset,
+};
+
+/*
+ * The MOXA Smartio/Industio serial driver boot-time initialization code!
+ */
+
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+ unsigned int irq)
+{
+ if (irq)
+ free_irq(brd->irq, brd);
+ if (pdev != NULL) { /* PCI */
+ pci_release_region(pdev, 2);
+ pci_release_region(pdev, 3);
+ pci_dev_put(pdev);
+ } else {
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+ release_region(brd->vector, 1);
+ }
+}
+
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+ struct pci_dev *pdev)
+{
+ struct mxser_port *info;
+ unsigned int i;
+ int retval;
+
+ printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
+
+ for (i = 0; i < brd->info->nports; i++) {
+ info = &brd->ports[i];
+ info->board = brd;
+ info->stop_rx = 0;
+ info->ldisc_stop_rx = 0;
+
+ /* Enhance mode enabled here */
+ if (brd->chip_flag != MOXA_OTHER_UART)
+ ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+
+ info->flags = ASYNC_SHARE_IRQ;
+ info->type = brd->uart_type;
+
+ process_txrx_fifo(info);
+
+ info->custom_divisor = info->baud_base * 16;
+ info->close_delay = 5 * HZ / 10;
+ info->closing_wait = 30 * HZ;
+ INIT_WORK(&info->tqueue, mxser_do_softint);
+ info->normal_termios = mxvar_sdriver->init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ memset(&info->mon_data, 0, sizeof(struct mxser_mon));
+ info->err_shadow = 0;
+ spin_lock_init(&info->slock);
+
+ /* before set INT ISR, disable all int */
+ outb(inb(info->ioaddr + UART_IER) & 0xf0,
+ info->ioaddr + UART_IER);
+ }
+ /*
+ * Allocate the IRQ if necessary
+ */
+
+ retval = request_irq(brd->irq, mxser_interrupt,
+ (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED :
+ IRQF_DISABLED, "mxser", brd);
+ if (retval) {
+ printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
+ "conflict with another device.\n",
+ brd->info->name, brd->irq);
+ /* We hold resources, we need to release them. */
+ mxser_release_res(brd, pdev, 0);
+ return retval;
+ }
+ return 0;
+}
+
+static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
+{
+ int id, i, bits;
+ unsigned short regs[16], irq;
+ unsigned char scratch, scratch2;
+
+ brd->chip_flag = MOXA_OTHER_UART;
+
+ id = mxser_read_register(cap, regs);
+ switch (id) {
+ case C168_ASIC_ID:
+ brd->info = &mxser_cards[0];
+ break;
+ case C104_ASIC_ID:
+ brd->info = &mxser_cards[1];
+ break;
+ case CI104J_ASIC_ID:
+ brd->info = &mxser_cards[2];
+ break;
+ case C102_ASIC_ID:
+ brd->info = &mxser_cards[5];
+ break;
+ case CI132_ASIC_ID:
+ brd->info = &mxser_cards[6];
+ break;
+ case CI134_ASIC_ID:
+ brd->info = &mxser_cards[7];
+ break;
+ default:
+ return 0;
+ }
+
+ irq = 0;
+ /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
+ Flag-hack checks if configuration should be read as 2-port here. */
+ if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ if (irq != (regs[9] & 0xFF00))
+ return MXSER_ERR_IRQ_CONFLIT;
+ } else if (brd->info->nports == 4) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ irq = irq | (irq >> 8);
+ if (irq != regs[9])
+ return MXSER_ERR_IRQ_CONFLIT;
+ } else if (brd->info->nports == 8) {
+ irq = regs[9] & 0xF000;
+ irq = irq | (irq >> 4);
+ irq = irq | (irq >> 8);
+ if ((irq != regs[9]) || (irq != regs[10]))
+ return MXSER_ERR_IRQ_CONFLIT;
+ }
+
+ if (!irq)
+ return MXSER_ERR_IRQ;
+ brd->irq = ((int)(irq & 0xF000) >> 12);
+ for (i = 0; i < 8; i++)
+ brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8;
+ if ((regs[12] & 0x80) == 0)
+ return MXSER_ERR_VECTOR;
+ brd->vector = (int)regs[11]; /* interrupt vector */
+ if (id == 1)
+ brd->vector_mask = 0x00FF;
+ else
+ brd->vector_mask = 0x000F;
+ for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
+ if (regs[12] & bits) {
+ brd->ports[i].baud_base = 921600;
+ brd->ports[i].max_baud = 921600;
+ } else {
+ brd->ports[i].baud_base = 115200;
+ brd->ports[i].max_baud = 115200;
+ }
+ }
+ scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
+ outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR);
+ outb(0, cap + UART_EFR); /* EFR is the same as FCR */
+ outb(scratch2, cap + UART_LCR);
+ outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR);
+ scratch = inb(cap + UART_IIR);
+
+ if (scratch & 0xC0)
+ brd->uart_type = PORT_16550A;
+ else
+ brd->uart_type = PORT_16450;
+ if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
+ "mxser(IO)"))
+ return MXSER_ERR_IOADDR;
+ if (!request_region(brd->vector, 1, "mxser(vector)")) {
+ release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+ return MXSER_ERR_VECTOR;
+ }
+ return brd->info->nports;
+}
+
+static int __devinit mxser_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mxser_board *brd;
+ unsigned int i, j;
+ unsigned long ioaddress;
+ int retval = -EINVAL;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info == NULL)
+ break;
+
+ if (i >= MXSER_BOARDS) {
+ printk(KERN_ERR "Too many Smartio/Industio family boards found "
+ "(maximum %d), board not configured\n", MXSER_BOARDS);
+ goto err;
+ }
+
+ brd = &mxser_boards[i];
+ brd->idx = i * MXSER_PORTS_PER_BOARD;
+ printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+ mxser_cards[ent->driver_data].name,
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ goto err;
+ }
+
+ /* io address */
+ ioaddress = pci_resource_start(pdev, 2);
+ retval = pci_request_region(pdev, 2, "mxser(IO)");
+ if (retval)
+ goto err;
+
+ brd->info = &mxser_cards[ent->driver_data];
+ for (i = 0; i < brd->info->nports; i++)
+ brd->ports[i].ioaddr = ioaddress + 8 * i;
+
+ /* vector */
+ ioaddress = pci_resource_start(pdev, 3);
+ retval = pci_request_region(pdev, 3, "mxser(vector)");
+ if (retval)
+ goto err_relio;
+ brd->vector = ioaddress;
+
+ /* irq */
+ brd->irq = pdev->irq;
+
+ brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr);
+ brd->uart_type = PORT_16550A;
+ brd->vector_mask = 0;
+
+ for (i = 0; i < brd->info->nports; i++) {
+ for (j = 0; j < UART_INFO_NUM; j++) {
+ if (Gpci_uart_info[j].type == brd->chip_flag) {
+ brd->ports[i].max_baud =
+ Gpci_uart_info[j].max_baud;
+
+ /* exception....CP-102 */
+ if (brd->info->flags & MXSER_HIGHBAUD)
+ brd->ports[i].max_baud = 921600;
+ break;
+ }
+ }
+ }
+
+ if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
+ for (i = 0; i < brd->info->nports; i++) {
+ if (i < 4)
+ brd->ports[i].opmode_ioaddr = ioaddress + 4;
+ else
+ brd->ports[i].opmode_ioaddr = ioaddress + 0x0c;
+ }
+ outb(0, ioaddress + 4); /* default set to RS232 mode */
+ outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
+ }
+
+ for (i = 0; i < brd->info->nports; i++) {
+ brd->vector_mask |= (1 << i);
+ brd->ports[i].baud_base = 921600;
+ }
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, pdev) < 0)
+ goto err_relvec;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+ pci_set_drvdata(pdev, brd);
+
+ return 0;
+err_relvec:
+ pci_release_region(pdev, 3);
+err_relio:
+ pci_release_region(pdev, 2);
+ brd->info = NULL;
+err:
+ return retval;
+}
+
+static void __devexit mxser_remove(struct pci_dev *pdev)
+{
+ struct mxser_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_unregister_device(mxvar_sdriver, brd->idx + i);
+
+ mxser_release_res(brd, pdev, 1);
+}
+
+static struct pci_driver mxser_driver = {
+ .name = "mxser",
+ .id_table = mxser_pcibrds,
+ .probe = mxser_probe,
+ .remove = __devexit_p(mxser_remove)
+};
+
+static int __init mxser_module_init(void)
+{
+ struct mxser_board *brd;
+ unsigned long cap;
+ unsigned int i, m, isaloop;
+ int retval, b;
+
+ pr_debug("Loading module mxser ...\n");
+
+ mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
+ if (!mxvar_sdriver)
+ return -ENOMEM;
+ spin_lock_init(&gm_lock);
+
+ printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+ MXSER_VERSION);
+
+ /* Initialize the tty_driver structure */
+ mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
+ mxvar_sdriver->name = "ttyMI";
+ mxvar_sdriver->major = ttymajor;
+ mxvar_sdriver->minor_start = 0;
+ mxvar_sdriver->num = MXSER_PORTS + 1;
+ mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
+ mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
+ mxvar_sdriver->init_termios = tty_std_termios;
+ mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
+ mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(mxvar_sdriver, &mxser_ops);
+
+ retval = tty_register_driver(mxvar_sdriver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
+ "tty driver !\n");
+ goto err_put;
+ }
+
+ mxvar_diagflag = 0;
+
+ m = 0;
+ /* Start finding ISA boards here */
+ for (isaloop = 0; isaloop < 2; isaloop++)
+ for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
+ if (!isaloop)
+ cap = mxserBoardCAP[b]; /* predefined */
+ else
+ cap = ioaddr[b]; /* module param */
+
+ if (!cap)
+ continue;
+
+ brd = &mxser_boards[m];
+ retval = mxser_get_ISA_conf(cap, brd);
+
+ if (retval != 0)
+ printk(KERN_INFO "Found MOXA %s board "
+ "(CAP=0x%x)\n",
+ brd->info->name, ioaddr[b]);
+
+ if (retval <= 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk(KERN_ERR "Invalid interrupt "
+ "number, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk(KERN_ERR "Invalid interrupt "
+ "number, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk(KERN_ERR "Invalid interrupt "
+ "vector, board not "
+ "configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
+
+ brd->info = NULL;
+ continue;
+ }
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
+ continue;
+ }
+
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i,
+ NULL);
+
+ m++;
+ }
+
+ retval = pci_register_driver(&mxser_driver);
+ if (retval) {
+ printk(KERN_ERR "Can't register pci driver\n");
+ if (!m) {
+ retval = -ENODEV;
+ goto err_unr;
+ } /* else: we have some ISA cards under control */
+ }
+
+ pr_debug("Done.\n");
+
+ return 0;
+err_unr:
+ tty_unregister_driver(mxvar_sdriver);
+err_put:
+ put_tty_driver(mxvar_sdriver);
+ return retval;
+}
+
+static void __exit mxser_module_exit(void)
+{
+ unsigned int i, j;
+
+ pr_debug("Unloading module mxser ...\n");
+
+ pci_unregister_driver(&mxser_driver);
+
+ for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+ if (mxser_boards[i].info != NULL)
+ for (j = 0; j < mxser_boards[i].info->nports; j++)
+ tty_unregister_device(mxvar_sdriver,
+ mxser_boards[i].idx + j);
+ tty_unregister_driver(mxvar_sdriver);
+ put_tty_driver(mxvar_sdriver);
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info != NULL)
+ mxser_release_res(&mxser_boards[i], NULL, 1);
+
+ pr_debug("Done.\n");
+}
+
+module_init(mxser_module_init);
+module_exit(mxser_module_exit);
--- /dev/null
+#ifndef _MXSER_H
+#define _MXSER_H
+
+/*
+ * Semi-public control interfaces
+ */
+
+/*
+ * MOXA ioctls
+ */
+
+#define MOXA 0x400
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_CONF (MOXA + 35)
+#define MOXA_DIAGNOSE (MOXA + 50)
+#define MOXA_CHKPORTENABLE (MOXA + 60)
+#define MOXA_HighSpeedOn (MOXA + 61)
+#define MOXA_GET_MAJOR (MOXA + 63)
+#define MOXA_GET_CUMAJOR (MOXA + 64)
+#define MOXA_GETMSTATUS (MOXA + 65)
+#define MOXA_SET_OP_MODE (MOXA + 66)
+#define MOXA_GET_OP_MODE (MOXA + 67)
+
+#define RS232_MODE 0
+#define RS485_2WIRE_MODE 1
+#define RS422_MODE 2
+#define RS485_4WIRE_MODE 3
+#define OP_MODE_MASK 3
+// above add by Victor Yu. 01-05-2004
+
+#define TTY_THRESHOLD_THROTTLE 128
+
+#define LO_WATER (TTY_FLIPBUF_SIZE)
+#define HI_WATER (TTY_FLIPBUF_SIZE*2*3/4)
+
+// added by James. 03-11-2004.
+#define MOXA_SDS_GETICOUNTER (MOXA + 68)
+#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
+// (above) added by James.
+
+#define MOXA_ASPP_OQUEUE (MOXA + 70)
+#define MOXA_ASPP_SETBAUD (MOXA + 71)
+#define MOXA_ASPP_GETBAUD (MOXA + 72)
+#define MOXA_ASPP_MON (MOXA + 73)
+#define MOXA_ASPP_LSTATUS (MOXA + 74)
+#define MOXA_ASPP_MON_EXT (MOXA + 75)
+#define MOXA_SET_BAUD_METHOD (MOXA + 76)
+
+
+/* --------------------------------------------------- */
+
+#define NPPI_NOTIFY_PARITY 0x01
+#define NPPI_NOTIFY_FRAMING 0x02
+#define NPPI_NOTIFY_HW_OVERRUN 0x04
+#define NPPI_NOTIFY_SW_OVERRUN 0x08
+#define NPPI_NOTIFY_BREAK 0x10
+
+#define NPPI_NOTIFY_CTSHOLD 0x01 // Tx hold by CTS low
+#define NPPI_NOTIFY_DSRHOLD 0x02 // Tx hold by DSR low
+#define NPPI_NOTIFY_XOFFHOLD 0x08 // Tx hold by Xoff received
+#define NPPI_NOTIFY_XOFFXENT 0x10 // Xoff Sent
+
+//CheckIsMoxaMust return value
+#define MOXA_OTHER_UART 0x00
+#define MOXA_MUST_MU150_HWID 0x01
+#define MOXA_MUST_MU860_HWID 0x02
+
+// follow just for Moxa Must chip define.
+//
+// when LCR register (offset 0x03) write following value,
+// the Must chip will enter enchance mode. And write value
+// on EFR (offset 0x02) bit 6,7 to change bank.
+#define MOXA_MUST_ENTER_ENCHANCE 0xBF
+
+// when enhance mode enable, access on general bank register
+#define MOXA_MUST_GDL_REGISTER 0x07
+#define MOXA_MUST_GDL_MASK 0x7F
+#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
+
+#define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO
+// enchance register bank select and enchance mode setting register
+// when LCR register equal to 0xBF
+#define MOXA_MUST_EFR_REGISTER 0x02
+// enchance mode enable
+#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
+// enchance reister bank set 0, 1, 2
+#define MOXA_MUST_EFR_BANK0 0x00
+#define MOXA_MUST_EFR_BANK1 0x40
+#define MOXA_MUST_EFR_BANK2 0x80
+#define MOXA_MUST_EFR_BANK3 0xC0
+#define MOXA_MUST_EFR_BANK_MASK 0xC0
+
+// set XON1 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XON1_REGISTER 0x04
+
+// set XON2 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XON2_REGISTER 0x05
+
+// set XOFF1 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XOFF1_REGISTER 0x06
+
+// set XOFF2 value register, when LCR=0xBF and change to bank0
+#define MOXA_MUST_XOFF2_REGISTER 0x07
+
+#define MOXA_MUST_RBRTL_REGISTER 0x04
+#define MOXA_MUST_RBRTH_REGISTER 0x05
+#define MOXA_MUST_RBRTI_REGISTER 0x06
+#define MOXA_MUST_THRTL_REGISTER 0x07
+#define MOXA_MUST_ENUM_REGISTER 0x04
+#define MOXA_MUST_HWID_REGISTER 0x05
+#define MOXA_MUST_ECR_REGISTER 0x06
+#define MOXA_MUST_CSR_REGISTER 0x07
+
+// good data mode enable
+#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
+// only good data put into RxFIFO
+#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
+
+// enable CTS interrupt
+#define MOXA_MUST_IER_ECTSI 0x80
+// enable RTS interrupt
+#define MOXA_MUST_IER_ERTSI 0x40
+// enable Xon/Xoff interrupt
+#define MOXA_MUST_IER_XINT 0x20
+// enable GDA interrupt
+#define MOXA_MUST_IER_EGDAI 0x10
+
+#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
+
+// GDA interrupt pending
+#define MOXA_MUST_IIR_GDA 0x1C
+#define MOXA_MUST_IIR_RDA 0x04
+#define MOXA_MUST_IIR_RTO 0x0C
+#define MOXA_MUST_IIR_LSR 0x06
+
+// recieved Xon/Xoff or specical interrupt pending
+#define MOXA_MUST_IIR_XSC 0x10
+
+// RTS/CTS change state interrupt pending
+#define MOXA_MUST_IIR_RTSCTS 0x20
+#define MOXA_MUST_IIR_MASK 0x3E
+
+#define MOXA_MUST_MCR_XON_FLAG 0x40
+#define MOXA_MUST_MCR_XON_ANY 0x80
+#define MOXA_MUST_MCR_TX_XON 0x08
+
+
+// software flow control on chip mask value
+#define MOXA_MUST_EFR_SF_MASK 0x0F
+// send Xon1/Xoff1
+#define MOXA_MUST_EFR_SF_TX1 0x08
+// send Xon2/Xoff2
+#define MOXA_MUST_EFR_SF_TX2 0x04
+// send Xon1,Xon2/Xoff1,Xoff2
+#define MOXA_MUST_EFR_SF_TX12 0x0C
+// don't send Xon/Xoff
+#define MOXA_MUST_EFR_SF_TX_NO 0x00
+// Tx software flow control mask
+#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
+// don't receive Xon/Xoff
+#define MOXA_MUST_EFR_SF_RX_NO 0x00
+// receive Xon1/Xoff1
+#define MOXA_MUST_EFR_SF_RX1 0x02
+// receive Xon2/Xoff2
+#define MOXA_MUST_EFR_SF_RX2 0x01
+// receive Xon1,Xon2/Xoff1,Xoff2
+#define MOXA_MUST_EFR_SF_RX12 0x03
+// Rx software flow control mask
+#define MOXA_MUST_EFR_SF_RX_MASK 0x03
+
+//#define MOXA_MUST_MIN_XOFFLIMIT 66
+//#define MOXA_MUST_MIN_XONLIMIT 20
+//#define ID1_RX_TRIG 120
+
+
+#define CHECK_MOXA_MUST_XOFFLIMIT(info) { \
+ if ( (info)->IsMoxaMustChipFlag && \
+ (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \
+ (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \
+ (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \
+ } \
+}
+
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+//#define MOXA_MUST_RBRL_VALUE 4
+#define SET_MOXA_MUST_FIFO_VALUE(info) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((info)->ioaddr+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR); \
+ __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
+ outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)((info)->rx_high_water), (info)->ioaddr+MOXA_MUST_RBRTH_REGISTER); \
+ outb((u8)((info)->rx_trigger), (info)->ioaddr+MOXA_MUST_RBRTI_REGISTER); \
+ outb((u8)((info)->rx_low_water), (info)->ioaddr+MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (info)->ioaddr+UART_LCR); \
+}
+
+
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+}
+
+#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
+ u8 __oldmcr; \
+ __oldmcr = inb((baseio)+UART_MCR); \
+ __oldmcr |= MOXA_MUST_MCR_XON_ANY; \
+ outb(__oldmcr, (baseio)+UART_MCR); \
+}
+
+#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
+ u8 __oldmcr; \
+ __oldmcr = inb((baseio)+UART_MCR); \
+ __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \
+ outb(__oldmcr, (baseio)+UART_MCR); \
+}
+
+#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)
+
+
+#ifndef INIT_WORK
+#define INIT_WORK(_work, _func, _data){ \
+ _data->tqueue.routine = _func;\
+ _data->tqueue.data = _data;\
+ }
+#endif
+
+#endif
const unsigned char * buf, size_t nr);
static int r3964_ioctl(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old);
static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
struct poll_table_struct *wait);
static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
}
-static void r3964_set_termios(struct tty_struct *tty, struct termios * old)
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old)
{
TRACE_L("set_termios");
}
* when the ldisc is closed.
*/
-static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
+static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
{
if (!tty)
return;
ssize_t nsc_gpio_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
- unsigned m = iminor(file->f_dentry->d_inode);
+ unsigned m = iminor(file->f_path.dentry->d_inode);
struct nsc_gpio_ops *amp = file->private_data;
struct device *dev = amp->dev;
size_t i;
ssize_t nsc_gpio_read(struct file *file, char __user * buf,
size_t len, loff_t * ppos)
{
- unsigned m = iminor(file->f_dentry->d_inode);
+ unsigned m = iminor(file->f_path.dentry->d_inode);
int value;
struct nsc_gpio_ops *amp = file->private_data;
* tty pointer to tty structure
* termios pointer to buffer to hold returned old termios
*/
-static void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_read = 0;
static ssize_t pp_write (struct file * file, const char __user * buf,
size_t count, loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_written = 0;
return retval;
}
-static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+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);
pty_driver->init_termios.c_oflag = 0;
pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
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, &pty_ops);
pty_slave_driver->subtype = PTY_TYPE_SLAVE;
pty_slave_driver->init_termios = tty_std_termios;
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;
ptm_driver->init_termios.c_oflag = 0;
ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
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;
pts_driver->subtype = PTY_TYPE_SLAVE;
pts_driver->init_termios = tty_std_termios;
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;
if (p == buffer) {
return (ssize_t)ret;
} else {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_mtime = current_fs_time(inode->i_sb);
mark_inode_dirty(inode);
return (ssize_t)(p - buffer);
filp->f_flags |= O_DIRECT;
filp->f_mapping = bdev->bd_inode->i_mapping;
if (++raw_devices[minor].inuse == 1)
- filp->f_dentry->d_inode->i_mapping =
+ filp->f_path.dentry->d_inode->i_mapping =
bdev->bd_inode->i_mapping;
filp->private_data = bdev;
mutex_unlock(&raw_mutex);
wake_up_interruptible(&port->open_wait);
}
-static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios)
+static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
riscom_driver->init_termios = tty_std_termios;
riscom_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ riscom_driver->init_termios.c_ispeed = 9600;
+ riscom_driver->init_termios.c_ospeed = 9600;
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
if ((error = tty_register_driver(riscom_driver))) {
* user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
*/
static void configure_r_port(struct r_port *info,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
unsigned cflag;
unsigned long flags;
/*
* Info->count is now 1; so it's safe to sleep now.
*/
- info->session = current->signal->session;
+ info->session = process_session(current);
info->pgrp = process_group(current);
if ((info->flags & ROCKET_INITIALIZED) == 0) {
}
static void rp_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct r_port *info = (struct r_port *) tty->driver_data;
CHANNEL_t *cp;
int count = 0;
/* Work through the PCI device list, pulling out ours */
- while ((dev = pci_find_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
+ while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
if (register_PCI(count + boards_found, dev))
count++;
}
rocket_driver->init_termios = tty_std_termios;
rocket_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ rocket_driver->init_termios.c_ispeed = 9600;
+ rocket_driver->init_termios.c_ospeed = 9600;
#ifdef ROCKET_SOFT_FLOW
rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
#endif
a2232_driver->init_termios = tty_std_termios;
a2232_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ a2232_driver->init_termios.c_ispeed = 9600;
+ a2232_driver->init_termios.c_ospeed = 9600;
a2232_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(a2232_driver, &a2232_ops);
if ((error = tty_register_driver(a2232_driver))) {
static void
-cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
+cy_set_termios(struct tty_struct *tty, struct ktermios * old_termios)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
}
if (ret > 0) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_atime = current_fs_time(inode->i_sb);
}
}
-static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios)
+static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
specialix_driver->init_termios = tty_std_termios;
specialix_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ specialix_driver->init_termios.c_ispeed = 9600;
+ specialix_driver->init_termios.c_ospeed = 9600;
specialix_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(specialix_driver, &sx_ops);
i++;
continue;
}
- pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+ pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_IO8,
pdev);
if (!pdev) break;
if (!sx_probe(&sx_board[i]))
found ++;
}
+ /* May exit pci_get sequence early with lots of boards */
+ if (pdev != NULL)
+ pci_dev_put(pdev);
}
#endif
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_PCI
#include <linux/pci.h>
-#endif
/*****************************************************************************/
#define BRD_ECH64PCI 27
#define BRD_EASYIOPCI 28
-/*
- * Define a configuration structure to hold the board configuration.
- * Need to set this up in the code (for now) with the boards that are
- * to be configured into the system. This is what needs to be modified
- * when adding/removing/modifying boards. Each line entry in the
- * stl_brdconf[] array is a board. Each line contains io/irq/memory
- * ranges for that board (as well as what type of board it is).
- * Some examples:
- * { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
- * This line would configure an EasyIO board (4 or 8, no difference),
- * at io address 2a0 and irq 10.
- * Another example:
- * { BRD_ECH, 0x2a8, 0x280, 0, 12, 0 },
- * This line will configure an EasyConnection 8/32 board at primary io
- * address 2a8, secondary io address 280 and irq 12.
- * Enter as many lines into this array as you want (only the first 4
- * will actually be used!). Any combination of EasyIO and EasyConnection
- * boards can be specified. EasyConnection 8/32 boards can share their
- * secondary io addresses between each other.
- *
- * NOTE: there is no need to put any entries in this table for PCI
- * boards. They will be found automatically by the driver - provided
- * PCI BIOS32 support is compiled into the kernel.
- */
-
-typedef struct {
- int brdtype;
+struct stlconf {
+ unsigned int brdtype;
int ioaddr1;
int ioaddr2;
unsigned long memaddr;
int irq;
int irqtype;
-} stlconf_t;
-
-static stlconf_t stl_brdconf[] = {
- /*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/
};
-static int stl_nrbrds = ARRAY_SIZE(stl_brdconf);
+static unsigned int stl_nrbrds;
/*****************************************************************************/
* with this termios initially. Basically all it defines is a raw port
* at 9600, 8 data bits, 1 stop bit.
*/
-static struct termios stl_deftermios = {
+static struct ktermios stl_deftermios = {
.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
.c_cc = INIT_C_CC,
+ .c_ispeed = 9600,
+ .c_ospeed = 9600,
};
-/*
- * Define global stats structures. Not used often, and can be
- * re-used for each stats call.
- */
-static comstats_t stl_comstats;
-static combrd_t stl_brdstats;
-static stlbrd_t stl_dummybrd;
-static stlport_t stl_dummyport;
-
/*
* Define global place to put buffer overflow characters.
*/
/*****************************************************************************/
-static stlbrd_t *stl_brds[STL_MAXBRDS];
+static DEFINE_MUTEX(stl_brdslock);
+static struct stlbrd *stl_brds[STL_MAXBRDS];
/*
* Per board state flags. Used with the state field of the board struct.
* Not really much here!
*/
#define BRD_FOUND 0x1
+#define STL_PROBED 0x2
+
/*
* Define the port structure istate flags. These set of flags are
* referencing boards when printing trace and stuff.
*/
static char *stl_brdnames[] = {
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
"EasyIO",
"EC8/32-AT",
"EC8/32-MC",
- (char *) NULL,
- (char *) NULL,
- (char *) NULL,
+ NULL,
+ NULL,
+ NULL,
"EC8/32-PCI",
"EC8/64-PCI",
"EasyIO-PCI",
* load line. These allow for easy board definitions, and easy
* modification of the io, memory and irq resoucres.
*/
-static int stl_nargs = 0;
+static unsigned int stl_nargs;
static char *board0[4];
static char *board1[4];
static char *board2[4];
* parse any module arguments.
*/
-typedef struct stlbrdtype {
+static struct {
char *name;
int type;
-} stlbrdtype_t;
-
-static stlbrdtype_t stl_brdstr[] = {
+} stl_brdstr[] = {
{ "easyio", BRD_EASYIO },
{ "eio", BRD_EASYIO },
{ "20", BRD_EASYIO },
/*
* Define the module agruments.
*/
-MODULE_AUTHOR("Greg Ungerer");
-MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
-MODULE_LICENSE("GPL");
module_param_array(board0, charp, &stl_nargs, 0);
MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");
/*****************************************************************************/
-#ifdef CONFIG_PCI
-
/*
* Define the Stallion PCI vendor and device IDs.
*/
/*
* Define structure to hold all Stallion PCI boards.
*/
-typedef struct stlpcibrd {
- unsigned short vendid;
- unsigned short devid;
- int brdtype;
-} stlpcibrd_t;
-
-static stlpcibrd_t stl_pcibrds[] = {
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI },
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI },
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI },
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI },
-};
-static int stl_nrpcibrds = ARRAY_SIZE(stl_pcibrds);
-
-#endif
+static struct pci_device_id stl_pcibrds[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864),
+ .driver_data = BRD_ECH64PCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI),
+ .driver_data = BRD_EASYIOPCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832),
+ .driver_data = BRD_ECHPCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410),
+ .driver_data = BRD_ECHPCI },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, stl_pcibrds);
/*****************************************************************************/
9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
};
-/*
- * Define some handy local macros...
- */
-#undef MIN
-#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
-
-#undef TOLOWER
-#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x))
-
/*****************************************************************************/
/*
* Declare all those functions in this driver!
*/
-static void stl_argbrds(void);
-static int stl_parsebrd(stlconf_t *confp, char **argp);
-
-static unsigned long stl_atol(char *str);
-
-static int stl_init(void);
-static int stl_open(struct tty_struct *tty, struct file *filp);
-static void stl_close(struct tty_struct *tty, struct file *filp);
-static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void stl_putchar(struct tty_struct *tty, unsigned char ch);
-static void stl_flushchars(struct tty_struct *tty);
-static int stl_writeroom(struct tty_struct *tty);
-static int stl_charsinbuffer(struct tty_struct *tty);
-static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void stl_settermios(struct tty_struct *tty, struct termios *old);
-static void stl_throttle(struct tty_struct *tty);
-static void stl_unthrottle(struct tty_struct *tty);
-static void stl_stop(struct tty_struct *tty);
-static void stl_start(struct tty_struct *tty);
-static void stl_flushbuffer(struct tty_struct *tty);
-static void stl_breakctl(struct tty_struct *tty, int state);
-static void stl_waituntilsent(struct tty_struct *tty, int timeout);
-static void stl_sendxchar(struct tty_struct *tty, char ch);
-static void stl_hangup(struct tty_struct *tty);
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static int stl_portinfo(stlport_t *portp, int portnr, char *pos);
-static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data);
-
-static int stl_brdinit(stlbrd_t *brdp);
-static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
-static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp);
-static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp);
-static int stl_getbrdstats(combrd_t __user *bp);
-static int stl_getportstats(stlport_t *portp, comstats_t __user *cp);
-static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp);
-static int stl_getportstruct(stlport_t __user *arg);
-static int stl_getbrdstruct(stlbrd_t __user *arg);
-static int stl_waitcarrier(stlport_t *portp, struct file *filp);
-static int stl_eiointr(stlbrd_t *brdp);
-static int stl_echatintr(stlbrd_t *brdp);
-static int stl_echmcaintr(stlbrd_t *brdp);
-static int stl_echpciintr(stlbrd_t *brdp);
-static int stl_echpci64intr(stlbrd_t *brdp);
-static void stl_offintr(struct work_struct *);
-static stlbrd_t *stl_allocbrd(void);
-static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
-
-static inline int stl_initbrds(void);
-static inline int stl_initeio(stlbrd_t *brdp);
-static inline int stl_initech(stlbrd_t *brdp);
-static inline int stl_getbrdnr(void);
-
-#ifdef CONFIG_PCI
-static inline int stl_findpcibrds(void);
-static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp);
-#endif
+static int stl_brdinit(struct stlbrd *brdp);
+static int stl_getportstats(struct stlport *portp, comstats_t __user *cp);
+static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp);
+static int stl_waitcarrier(struct stlport *portp, struct file *filp);
/*
* CD1400 uart specific handling functions.
*/
-static void stl_cd1400setreg(stlport_t *portp, int regnr, int value);
-static int stl_cd1400getreg(stlport_t *portp, int regnr);
-static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value);
-static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp);
-static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
-static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp);
-static int stl_cd1400getsignals(stlport_t *portp);
-static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts);
-static void stl_cd1400ccrwait(stlport_t *portp);
-static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx);
-static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx);
-static void stl_cd1400disableintrs(stlport_t *portp);
-static void stl_cd1400sendbreak(stlport_t *portp, int len);
-static void stl_cd1400flowctrl(stlport_t *portp, int state);
-static void stl_cd1400sendflow(stlport_t *portp, int state);
-static void stl_cd1400flush(stlport_t *portp);
-static int stl_cd1400datastate(stlport_t *portp);
-static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase);
-static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase);
-static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr);
-static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr);
-static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr);
-
-static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr);
+static void stl_cd1400setreg(struct stlport *portp, int regnr, int value);
+static int stl_cd1400getreg(struct stlport *portp, int regnr);
+static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value);
+static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp);
+static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);
+static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp);
+static int stl_cd1400getsignals(struct stlport *portp);
+static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts);
+static void stl_cd1400ccrwait(struct stlport *portp);
+static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx);
+static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx);
+static void stl_cd1400disableintrs(struct stlport *portp);
+static void stl_cd1400sendbreak(struct stlport *portp, int len);
+static void stl_cd1400flowctrl(struct stlport *portp, int state);
+static void stl_cd1400sendflow(struct stlport *portp, int state);
+static void stl_cd1400flush(struct stlport *portp);
+static int stl_cd1400datastate(struct stlport *portp);
+static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase);
+static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase);
+static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr);
+static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr);
+static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr);
+
+static inline int stl_cd1400breakisr(struct stlport *portp, int ioaddr);
/*
* SC26198 uart specific handling functions.
*/
-static void stl_sc26198setreg(stlport_t *portp, int regnr, int value);
-static int stl_sc26198getreg(stlport_t *portp, int regnr);
-static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value);
-static int stl_sc26198getglobreg(stlport_t *portp, int regnr);
-static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp);
-static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
-static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp);
-static int stl_sc26198getsignals(stlport_t *portp);
-static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts);
-static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx);
-static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx);
-static void stl_sc26198disableintrs(stlport_t *portp);
-static void stl_sc26198sendbreak(stlport_t *portp, int len);
-static void stl_sc26198flowctrl(stlport_t *portp, int state);
-static void stl_sc26198sendflow(stlport_t *portp, int state);
-static void stl_sc26198flush(stlport_t *portp);
-static int stl_sc26198datastate(stlport_t *portp);
-static void stl_sc26198wait(stlport_t *portp);
-static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty);
-static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase);
-static void stl_sc26198txisr(stlport_t *port);
-static void stl_sc26198rxisr(stlport_t *port, unsigned int iack);
-static void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch);
-static void stl_sc26198rxbadchars(stlport_t *portp);
-static void stl_sc26198otherisr(stlport_t *port, unsigned int iack);
+static void stl_sc26198setreg(struct stlport *portp, int regnr, int value);
+static int stl_sc26198getreg(struct stlport *portp, int regnr);
+static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value);
+static int stl_sc26198getglobreg(struct stlport *portp, int regnr);
+static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp);
+static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);
+static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp);
+static int stl_sc26198getsignals(struct stlport *portp);
+static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts);
+static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx);
+static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx);
+static void stl_sc26198disableintrs(struct stlport *portp);
+static void stl_sc26198sendbreak(struct stlport *portp, int len);
+static void stl_sc26198flowctrl(struct stlport *portp, int state);
+static void stl_sc26198sendflow(struct stlport *portp, int state);
+static void stl_sc26198flush(struct stlport *portp);
+static int stl_sc26198datastate(struct stlport *portp);
+static void stl_sc26198wait(struct stlport *portp);
+static void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty);
+static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase);
+static void stl_sc26198txisr(struct stlport *port);
+static void stl_sc26198rxisr(struct stlport *port, unsigned int iack);
+static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch);
+static void stl_sc26198rxbadchars(struct stlport *portp);
+static void stl_sc26198otherisr(struct stlport *port, unsigned int iack);
/*****************************************************************************/
* Generic UART support structure.
*/
typedef struct uart {
- int (*panelinit)(stlbrd_t *brdp, stlpanel_t *panelp);
- void (*portinit)(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp);
- void (*setport)(stlport_t *portp, struct termios *tiosp);
- int (*getsignals)(stlport_t *portp);
- void (*setsignals)(stlport_t *portp, int dtr, int rts);
- void (*enablerxtx)(stlport_t *portp, int rx, int tx);
- void (*startrxtx)(stlport_t *portp, int rx, int tx);
- void (*disableintrs)(stlport_t *portp);
- void (*sendbreak)(stlport_t *portp, int len);
- void (*flowctrl)(stlport_t *portp, int state);
- void (*sendflow)(stlport_t *portp, int state);
- void (*flush)(stlport_t *portp);
- int (*datastate)(stlport_t *portp);
- void (*intr)(stlpanel_t *panelp, unsigned int iobase);
+ int (*panelinit)(struct stlbrd *brdp, struct stlpanel *panelp);
+ void (*portinit)(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp);
+ void (*setport)(struct stlport *portp, struct ktermios *tiosp);
+ int (*getsignals)(struct stlport *portp);
+ void (*setsignals)(struct stlport *portp, int dtr, int rts);
+ void (*enablerxtx)(struct stlport *portp, int rx, int tx);
+ void (*startrxtx)(struct stlport *portp, int rx, int tx);
+ void (*disableintrs)(struct stlport *portp);
+ void (*sendbreak)(struct stlport *portp, int len);
+ void (*flowctrl)(struct stlport *portp, int state);
+ void (*sendflow)(struct stlport *portp, int state);
+ void (*flush)(struct stlport *portp);
+ int (*datastate)(struct stlport *portp);
+ void (*intr)(struct stlpanel *panelp, unsigned int iobase);
} uart_t;
/*
.ioctl = stl_memioctl,
};
-/*****************************************************************************/
-
static struct class *stallion_class;
-/*
- * Loadable module initialization stuff.
- */
-
-static int __init stallion_module_init(void)
-{
- stl_init();
- return 0;
-}
-
-/*****************************************************************************/
-
-static void __exit stallion_module_exit(void)
-{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
- stlport_t *portp;
- int i, j, k;
-
-#ifdef DEBUG
- printk("cleanup_module()\n");
-#endif
-
- printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
- stl_drvversion);
-
-/*
- * Free up all allocated resources used by the ports. This includes
- * memory and interrupts. As part of this process we will also do
- * a hangup on every open port - to try to flush out any processes
- * hanging onto ports.
- */
- i = tty_unregister_driver(stl_serial);
- put_tty_driver(stl_serial);
- if (i) {
- printk("STALLION: failed to un-register tty driver, "
- "errno=%d\n", -i);
- return;
- }
- for (i = 0; i < 4; i++)
- class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -i);
- class_destroy(stallion_class);
-
- for (i = 0; (i < stl_nrbrds); i++) {
- if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
- continue;
-
- free_irq(brdp->irq, brdp);
-
- for (j = 0; (j < STL_MAXPANELS); j++) {
- panelp = brdp->panels[j];
- if (panelp == (stlpanel_t *) NULL)
- continue;
- for (k = 0; (k < STL_PORTSPERPANEL); k++) {
- portp = panelp->ports[k];
- if (portp == (stlport_t *) NULL)
- continue;
- if (portp->tty != (struct tty_struct *) NULL)
- stl_hangup(portp->tty);
- kfree(portp->tx.buf);
- kfree(portp);
- }
- kfree(panelp);
- }
-
- release_region(brdp->ioaddr1, brdp->iosize1);
- if (brdp->iosize2 > 0)
- release_region(brdp->ioaddr2, brdp->iosize2);
-
- kfree(brdp);
- stl_brds[i] = (stlbrd_t *) NULL;
- }
-}
-
-module_init(stallion_module_init);
-module_exit(stallion_module_exit);
-
-/*****************************************************************************/
-
/*
* Check for any arguments passed in on the module load command line.
*/
-static void stl_argbrds(void)
-{
- stlconf_t conf;
- stlbrd_t *brdp;
- int i;
-
-#ifdef DEBUG
- printk("stl_argbrds()\n");
-#endif
-
- for (i = stl_nrbrds; (i < stl_nargs); i++) {
- memset(&conf, 0, sizeof(conf));
- if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
- continue;
- if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
- continue;
- stl_nrbrds = i + 1;
- brdp->brdnr = i;
- brdp->brdtype = conf.brdtype;
- brdp->ioaddr1 = conf.ioaddr1;
- brdp->ioaddr2 = conf.ioaddr2;
- brdp->irq = conf.irq;
- brdp->irqtype = conf.irqtype;
- stl_brdinit(brdp);
- }
-}
-
-/*****************************************************************************/
-
-/*
- * Convert an ascii string number into an unsigned long.
- */
-
-static unsigned long stl_atol(char *str)
-{
- unsigned long val;
- int base, c;
- char *sp;
-
- val = 0;
- sp = str;
- if ((*sp == '0') && (*(sp+1) == 'x')) {
- base = 16;
- sp += 2;
- } else if (*sp == '0') {
- base = 8;
- sp++;
- } else {
- base = 10;
- }
-
- for (; (*sp != 0); sp++) {
- c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0');
- if ((c < 0) || (c >= base)) {
- printk("STALLION: invalid argument %s\n", str);
- val = 0;
- break;
- }
- val = (val * base) + c;
- }
- return val;
-}
-
/*****************************************************************************/
/*
* Parse the supplied argument string, into the board conf struct.
*/
-static int stl_parsebrd(stlconf_t *confp, char **argp)
+static int __init stl_parsebrd(struct stlconf *confp, char **argp)
{
char *sp;
- int i;
+ unsigned int i;
-#ifdef DEBUG
- printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
-#endif
+ pr_debug("stl_parsebrd(confp=%p,argp=%p)\n", confp, argp);
- if ((argp[0] == (char *) NULL) || (*argp[0] == 0))
+ if ((argp[0] == NULL) || (*argp[0] == 0))
return 0;
- for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
- *sp = TOLOWER(*sp);
+ for (sp = argp[0], i = 0; (*sp != 0) && (i < 25); sp++, i++)
+ *sp = tolower(*sp);
- for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++) {
+ for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++)
if (strcmp(stl_brdstr[i].name, argp[0]) == 0)
break;
- }
+
if (i == ARRAY_SIZE(stl_brdstr)) {
printk("STALLION: unknown board name, %s?\n", argp[0]);
return 0;
confp->brdtype = stl_brdstr[i].type;
i = 1;
- if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
- confp->ioaddr1 = stl_atol(argp[i]);
+ if ((argp[i] != NULL) && (*argp[i] != 0))
+ confp->ioaddr1 = simple_strtoul(argp[i], NULL, 0);
i++;
if (confp->brdtype == BRD_ECH) {
- if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
- confp->ioaddr2 = stl_atol(argp[i]);
+ if ((argp[i] != NULL) && (*argp[i] != 0))
+ confp->ioaddr2 = simple_strtoul(argp[i], NULL, 0);
i++;
}
- if ((argp[i] != (char *) NULL) && (*argp[i] != 0))
- confp->irq = stl_atol(argp[i]);
+ if ((argp[i] != NULL) && (*argp[i] != 0))
+ confp->irq = simple_strtoul(argp[i], NULL, 0);
return 1;
}
* Allocate a new board structure. Fill out the basic info in it.
*/
-static stlbrd_t *stl_allocbrd(void)
+static struct stlbrd *stl_allocbrd(void)
{
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
- brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL);
+ brdp = kzalloc(sizeof(struct stlbrd), GFP_KERNEL);
if (!brdp) {
printk("STALLION: failed to allocate memory (size=%Zd)\n",
- sizeof(stlbrd_t));
+ sizeof(struct stlbrd));
return NULL;
}
static int stl_open(struct tty_struct *tty, struct file *filp)
{
- stlport_t *portp;
- stlbrd_t *brdp;
- unsigned int minordev;
- int brdnr, panelnr, portnr, rc;
-
-#ifdef DEBUG
- printk("stl_open(tty=%x,filp=%x): device=%s\n", (int) tty,
- (int) filp, tty->name);
-#endif
+ struct stlport *portp;
+ struct stlbrd *brdp;
+ unsigned int minordev, brdnr, panelnr;
+ int portnr, rc;
+
+ pr_debug("stl_open(tty=%p,filp=%p): device=%s\n", tty, filp, tty->name);
minordev = tty->index;
brdnr = MINOR2BRD(minordev);
if (brdnr >= stl_nrbrds)
return -ENODEV;
brdp = stl_brds[brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
return -ENODEV;
minordev = MINOR2PORT(minordev);
- for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) {
- if (brdp->panels[panelnr] == (stlpanel_t *) NULL)
+ for (portnr = -1, panelnr = 0; panelnr < STL_MAXPANELS; panelnr++) {
+ if (brdp->panels[panelnr] == NULL)
break;
if (minordev < brdp->panels[panelnr]->nrports) {
portnr = minordev;
return -ENODEV;
portp = brdp->panels[panelnr]->ports[portnr];
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
/*
* previous opens still in effect. If we are a normal serial device
* then also we might have to wait for carrier.
*/
- if (!(filp->f_flags & O_NONBLOCK)) {
+ if (!(filp->f_flags & O_NONBLOCK))
if ((rc = stl_waitcarrier(portp, filp)) != 0)
return rc;
- }
+
portp->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
* maybe because if we are clocal then we don't need to wait...
*/
-static int stl_waitcarrier(stlport_t *portp, struct file *filp)
+static int stl_waitcarrier(struct stlport *portp, struct file *filp)
{
unsigned long flags;
int rc, doclocal;
-#ifdef DEBUG
- printk("stl_waitcarrier(portp=%x,filp=%x)\n", (int) portp, (int) filp);
-#endif
+ pr_debug("stl_waitcarrier(portp=%p,filp=%p)\n", portp, filp);
rc = 0;
doclocal = 0;
break;
}
if (((portp->flags & ASYNC_CLOSING) == 0) &&
- (doclocal || (portp->sigs & TIOCM_CD))) {
+ (doclocal || (portp->sigs & TIOCM_CD)))
break;
- }
if (signal_pending(current)) {
rc = -ERESTARTSYS;
break;
/*****************************************************************************/
+static void stl_flushbuffer(struct tty_struct *tty)
+{
+ struct stlport *portp;
+
+ pr_debug("stl_flushbuffer(tty=%p)\n", tty);
+
+ if (tty == NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == NULL)
+ return;
+
+ stl_flush(portp);
+ tty_wakeup(tty);
+}
+
+/*****************************************************************************/
+
+static void stl_waituntilsent(struct tty_struct *tty, int timeout)
+{
+ struct stlport *portp;
+ unsigned long tend;
+
+ pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
+
+ if (tty == NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == NULL)
+ return;
+
+ if (timeout == 0)
+ timeout = HZ;
+ tend = jiffies + timeout;
+
+ while (stl_datastate(portp)) {
+ if (signal_pending(current))
+ break;
+ msleep_interruptible(20);
+ if (time_after_eq(jiffies, tend))
+ break;
+ }
+}
+
+/*****************************************************************************/
+
static void stl_close(struct tty_struct *tty, struct file *filp)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);
-#endif
+ pr_debug("stl_close(tty=%p,filp=%p)\n", tty, filp);
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
spin_lock_irqsave(&stallion_lock, flags);
stl_enablerxtx(portp, 0, 0);
stl_flushbuffer(tty);
portp->istate = 0;
- if (portp->tx.buf != (char *) NULL) {
+ if (portp->tx.buf != NULL) {
kfree(portp->tx.buf);
- portp->tx.buf = (char *) NULL;
- portp->tx.head = (char *) NULL;
- portp->tx.tail = (char *) NULL;
+ portp->tx.buf = NULL;
+ portp->tx.head = NULL;
+ portp->tx.tail = NULL;
}
set_bit(TTY_IO_ERROR, &tty->flags);
tty_ldisc_flush(tty);
tty->closing = 0;
- portp->tty = (struct tty_struct *) NULL;
+ portp->tty = NULL;
if (portp->openwaitcnt) {
if (portp->close_delay)
static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int len, stlen;
unsigned char *chbuf;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_write(tty=%x,buf=%x,count=%d)\n",
- (int) tty, (int) buf, count);
-#endif
+ pr_debug("stl_write(tty=%p,buf=%p,count=%d)\n", tty, buf, count);
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return 0;
/*
stlen = len;
}
- len = MIN(len, count);
+ len = min(len, (unsigned int)count);
count = 0;
while (len > 0) {
- stlen = MIN(len, stlen);
+ stlen = min(len, stlen);
memcpy(head, chbuf, stlen);
len -= stlen;
chbuf += stlen;
static void stl_putchar(struct tty_struct *tty, unsigned char ch)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int len;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);
-#endif
+ pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return;
head = portp->tx.head;
static void stl_flushchars(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_flushchars(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_flushchars(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return;
stl_startrxtx(portp, -1, 1);
static int stl_writeroom(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_writeroom(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_writeroom(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return 0;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return 0;
head = portp->tx.head;
tail = portp->tx.tail;
- return ((head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1));
+ return (head >= tail) ? (STL_TXBUFSIZE - (head - tail) - 1) : (tail - head - 1);
}
/*****************************************************************************/
static int stl_charsinbuffer(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int size;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_charsinbuffer(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return 0;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
- if (portp->tx.buf == (char *) NULL)
+ if (portp->tx.buf == NULL)
return 0;
head = portp->tx.head;
* Generate the serial struct info.
*/
-static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp)
+static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
-#ifdef DEBUG
- printk("stl_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+ pr_debug("stl_getserial(portp=%p,sp=%p)\n", portp, sp);
memset(&sio, 0, sizeof(struct serial_struct));
sio.line = portp->portnr;
}
brdp = stl_brds[portp->brdnr];
- if (brdp != (stlbrd_t *) NULL)
+ if (brdp != NULL)
sio.irq = brdp->irq;
return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ? -EFAULT : 0;
* just quietly ignore any requests to change irq, etc.
*/
-static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp)
+static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp)
{
struct serial_struct sio;
-#ifdef DEBUG
- printk("stl_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+ pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp);
if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
return -EFAULT;
static int stl_tiocmget(struct tty_struct *tty, struct file *file)
{
- stlport_t *portp;
+ struct stlport *portp;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return -ENODEV;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
static int stl_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- stlport_t *portp;
+ struct stlport *portp;
int rts = -1, dtr = -1;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return -ENODEV;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int ival;
int rc;
void __user *argp = (void __user *)arg;
-#ifdef DEBUG
- printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
- (int) tty, (int) file, cmd, (int) arg);
-#endif
+ pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
+ arg);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return -ENODEV;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return -ENODEV;
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
+ (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS))
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
- }
rc = 0;
/*****************************************************************************/
-static void stl_settermios(struct tty_struct *tty, struct termios *old)
+/*
+ * Start the transmitter again. Just turn TX interrupts back on.
+ */
+
+static void stl_start(struct tty_struct *tty)
{
- stlport_t *portp;
- struct termios *tiosp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);
-#endif
+ pr_debug("stl_start(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
+ return;
+ stl_startrxtx(portp, -1, 1);
+}
+
+/*****************************************************************************/
+
+static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
+{
+ struct stlport *portp;
+ struct ktermios *tiosp;
+
+ pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
+
+ if (tty == NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == NULL)
return;
tiosp = tty->termios;
static void stl_throttle(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_throttle(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_throttle(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_flowctrl(portp, 0);
}
static void stl_unthrottle(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_unthrottle(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_unthrottle(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_flowctrl(portp, 1);
}
static void stl_stop(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_stop(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_stop(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_startrxtx(portp, -1, 0);
}
/*****************************************************************************/
-/*
- * Start the transmitter again. Just turn TX interrupts back on.
- */
-
-static void stl_start(struct tty_struct *tty)
-{
- stlport_t *portp;
-
-#ifdef DEBUG
- printk("stl_start(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
- return;
- stl_startrxtx(portp, -1, 1);
-}
-
-/*****************************************************************************/
-
/*
* Hangup this port. This is pretty much like closing the port, only
* a little more brutal. No waiting for data to drain. Shutdown the
static void stl_hangup(struct tty_struct *tty)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_hangup(tty=%x)\n", (int) tty);
-#endif
+ pr_debug("stl_hangup(tty=%p)\n", tty);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
portp->flags &= ~ASYNC_INITIALIZED;
stl_flushbuffer(tty);
portp->istate = 0;
set_bit(TTY_IO_ERROR, &tty->flags);
- if (portp->tx.buf != (char *) NULL) {
+ if (portp->tx.buf != NULL) {
kfree(portp->tx.buf);
- portp->tx.buf = (char *) NULL;
- portp->tx.head = (char *) NULL;
- portp->tx.tail = (char *) NULL;
+ portp->tx.buf = NULL;
+ portp->tx.head = NULL;
+ portp->tx.tail = NULL;
}
- portp->tty = (struct tty_struct *) NULL;
+ portp->tty = NULL;
portp->flags &= ~ASYNC_NORMAL_ACTIVE;
portp->refcount = 0;
wake_up_interruptible(&portp->open_wait);
/*****************************************************************************/
-static void stl_flushbuffer(struct tty_struct *tty)
-{
- stlport_t *portp;
-
-#ifdef DEBUG
- printk("stl_flushbuffer(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
- return;
-
- stl_flush(portp);
- tty_wakeup(tty);
-}
-
-/*****************************************************************************/
-
static void stl_breakctl(struct tty_struct *tty, int state)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state);
-#endif
+ pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
stl_sendbreak(portp, ((state == -1) ? 1 : 2));
/*****************************************************************************/
-static void stl_waituntilsent(struct tty_struct *tty, int timeout)
-{
- stlport_t *portp;
- unsigned long tend;
-
-#ifdef DEBUG
- printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
- return;
-
- if (timeout == 0)
- timeout = HZ;
- tend = jiffies + timeout;
-
- while (stl_datastate(portp)) {
- if (signal_pending(current))
- break;
- msleep_interruptible(20);
- if (time_after_eq(jiffies, tend))
- break;
- }
-}
-
-/*****************************************************************************/
-
static void stl_sendxchar(struct tty_struct *tty, char ch)
{
- stlport_t *portp;
+ struct stlport *portp;
-#ifdef DEBUG
- printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch);
-#endif
+ pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
if (ch == STOP_CHAR(tty))
* short then padded with spaces).
*/
-static int stl_portinfo(stlport_t *portp, int portnr, char *pos)
+static int stl_portinfo(struct stlport *portp, int portnr, char *pos)
{
char *sp;
int sigs, cnt;
*sp = ' ';
sp += cnt;
- for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
+ for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++)
*sp++ = ' ';
if (cnt >= MAXLINE)
pos[(MAXLINE - 2)] = '+';
static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
- stlport_t *portp;
- int brdnr, panelnr, portnr, totalport;
- int curoff, maxoff;
+ struct stlbrd *brdp;
+ struct stlpanel *panelp;
+ struct stlport *portp;
+ unsigned int brdnr, panelnr, portnr;
+ int totalport, curoff, maxoff;
char *pos;
-#ifdef DEBUG
- printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x,"
- "data=%x\n", (int) page, (int) start, (int) off, count,
- (int) eof, (int) data);
-#endif
+ pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p,"
+ "data=%p\n", page, start, off, count, eof, data);
pos = page;
totalport = 0;
* We scan through for each board, panel and port. The offset is
* calculated on the fly, and irrelevant ports are skipped.
*/
- for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) {
+ for (brdnr = 0; brdnr < stl_nrbrds; brdnr++) {
brdp = stl_brds[brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
continue;
if (brdp->state == 0)
continue;
}
totalport = brdnr * STL_MAXPORTS;
- for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
+ for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) {
panelp = brdp->panels[panelnr];
- if (panelp == (stlpanel_t *) NULL)
+ if (panelp == NULL)
continue;
maxoff = curoff + (panelp->nrports * MAXLINE);
continue;
}
- for (portnr = 0; (portnr < panelp->nrports); portnr++,
+ for (portnr = 0; portnr < panelp->nrports; portnr++,
totalport++) {
portp = panelp->ports[portnr];
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
continue;
if (off >= (curoff += MAXLINE))
continue;
stl_readdone:
*start = page;
- return (pos - page);
+ return pos - page;
}
/*****************************************************************************/
static irqreturn_t stl_intr(int irq, void *dev_id)
{
- stlbrd_t *brdp = (stlbrd_t *) dev_id;
+ struct stlbrd *brdp = dev_id;
-#ifdef DEBUG
- printk("stl_intr(brdp=%x,irq=%d)\n", (int) brdp, irq);
-#endif
+ pr_debug("stl_intr(brdp=%p,irq=%d)\n", brdp, irq);
return IRQ_RETVAL((* brdp->isr)(brdp));
}
* Interrupt service routine for EasyIO board types.
*/
-static int stl_eiointr(stlbrd_t *brdp)
+static int stl_eiointr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
+ struct stlpanel *panelp;
unsigned int iobase;
int handled = 0;
* Interrupt service routine for ECH-AT board types.
*/
-static int stl_echatintr(stlbrd_t *brdp)
+static int stl_echatintr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr;
int handled = 0;
outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
while (inb(brdp->iostatus) & ECH_INTRPEND) {
handled = 1;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
panelp = brdp->bnk2panel[bnknr];
* Interrupt service routine for ECH-MCA board types.
*/
-static int stl_echmcaintr(stlbrd_t *brdp)
+static int stl_echmcaintr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr;
int handled = 0;
while (inb(brdp->iostatus) & ECH_INTRPEND) {
handled = 1;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
panelp = brdp->bnk2panel[bnknr];
* Interrupt service routine for ECH-PCI board types.
*/
-static int stl_echpciintr(stlbrd_t *brdp)
+static int stl_echpciintr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr, recheck;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr, recheck;
int handled = 0;
while (1) {
recheck = 0;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
outb(brdp->bnkpageaddr[bnknr], brdp->ioctrl);
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
* Interrupt service routine for ECH-8/64-PCI board types.
*/
-static int stl_echpci64intr(stlbrd_t *brdp)
+static int stl_echpci64intr(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int ioaddr;
- int bnknr;
+ struct stlpanel *panelp;
+ unsigned int ioaddr, bnknr;
int handled = 0;
while (inb(brdp->ioctrl) & 0x1) {
handled = 1;
- for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ for (bnknr = 0; bnknr < brdp->nrbnks; bnknr++) {
ioaddr = brdp->bnkstataddr[bnknr];
if (inb(ioaddr) & ECH_PNLINTRPEND) {
panelp = brdp->bnk2panel[bnknr];
*/
static void stl_offintr(struct work_struct *work)
{
- stlport_t *portp = container_of(work, stlport_t, tqueue);
+ struct stlport *portp = container_of(work, struct stlport, tqueue);
struct tty_struct *tty;
unsigned int oldsigs;
-#ifdef DEBUG
- printk("stl_offintr(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_offintr(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
lock_kernel();
- if (test_bit(ASYI_TXLOW, &portp->istate)) {
+ if (test_bit(ASYI_TXLOW, &portp->istate))
tty_wakeup(tty);
- }
+
if (test_bit(ASYI_DCDCHANGE, &portp->istate)) {
clear_bit(ASYI_DCDCHANGE, &portp->istate);
oldsigs = portp->sigs;
portp->sigs = stl_getsignals(portp);
if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
wake_up_interruptible(&portp->open_wait);
- if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
+ if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0))
if (portp->flags & ASYNC_CHECK_CD)
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
- }
}
unlock_kernel();
}
* Initialize all the ports on a panel.
*/
-static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
+static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp)
{
- stlport_t *portp;
- int chipmask, i;
+ struct stlport *portp;
+ unsigned int i;
+ int chipmask;
-#ifdef DEBUG
- printk("stl_initports(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
-#endif
+ pr_debug("stl_initports(brdp=%p,panelp=%p)\n", brdp, panelp);
chipmask = stl_panelinit(brdp, panelp);
* All UART's are initialized (if found!). Now go through and setup
* each ports data structures.
*/
- for (i = 0; (i < panelp->nrports); i++) {
- portp = kzalloc(sizeof(stlport_t), GFP_KERNEL);
+ for (i = 0; i < panelp->nrports; i++) {
+ portp = kzalloc(sizeof(struct stlport), GFP_KERNEL);
if (!portp) {
printk("STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlport_t));
+ "(size=%Zd)\n", sizeof(struct stlport));
break;
}
stl_portinit(brdp, panelp, portp);
}
- return(0);
+ return 0;
+}
+
+static void stl_cleanup_panels(struct stlbrd *brdp)
+{
+ struct stlpanel *panelp;
+ struct stlport *portp;
+ unsigned int j, k;
+
+ for (j = 0; j < STL_MAXPANELS; j++) {
+ panelp = brdp->panels[j];
+ if (panelp == NULL)
+ continue;
+ for (k = 0; k < STL_PORTSPERPANEL; k++) {
+ portp = panelp->ports[k];
+ if (portp == NULL)
+ continue;
+ if (portp->tty != NULL)
+ stl_hangup(portp->tty);
+ kfree(portp->tx.buf);
+ kfree(portp);
+ }
+ kfree(panelp);
+ }
}
/*****************************************************************************/
* Try to find and initialize an EasyIO board.
*/
-static inline int stl_initeio(stlbrd_t *brdp)
+static int __devinit stl_initeio(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
+ struct stlpanel *panelp;
unsigned int status;
char *name;
- int rc;
+ int retval;
-#ifdef DEBUG
- printk("stl_initeio(brdp=%x)\n", (int) brdp);
-#endif
+ pr_debug("stl_initeio(brdp=%p)\n", brdp);
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 2;
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n",
brdp->irq, brdp->brdnr);
- return(-EINVAL);
+ retval = -EINVAL;
+ goto err;
}
outb((stl_vecmap[brdp->irq] | EIO_0WS |
((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
brdp->ioctrl);
}
+ retval = -EBUSY;
if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
"%x conflicts with another device\n", brdp->brdnr,
brdp->ioaddr1);
- return(-EBUSY);
+ goto err;
}
if (brdp->iosize2 > 0)
printk(KERN_WARNING "STALLION: Warning, also "
"releasing board %d I/O address %x \n",
brdp->brdnr, brdp->ioaddr1);
- release_region(brdp->ioaddr1, brdp->iosize1);
- return(-EBUSY);
+ goto err_rel1;
}
/*
brdp->clk = CD1400_CLK;
brdp->isr = stl_eiointr;
+ retval = -ENODEV;
switch (status & EIO_IDBITMASK) {
case EIO_8PORTM:
brdp->clk = CD1400_CLK8M;
brdp->nrports = 16;
break;
default:
- return(-ENODEV);
+ goto err_rel2;
}
break;
default:
- return(-ENODEV);
+ goto err_rel2;
}
/*
* can complete the setup.
*/
- panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
+ panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
if (!panelp) {
printk(KERN_WARNING "STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlpanel_t));
- return -ENOMEM;
+ "(size=%Zd)\n", sizeof(struct stlpanel));
+ retval = -ENOMEM;
+ goto err_rel2;
}
panelp->magic = STL_PANELMAGIC;
panelp->iobase = brdp->ioaddr1;
panelp->hwid = status;
if ((status & EIO_IDBITMASK) == EIO_MK3) {
- panelp->uartp = (void *) &stl_sc26198uart;
+ panelp->uartp = &stl_sc26198uart;
panelp->isr = stl_sc26198intr;
} else {
- panelp->uartp = (void *) &stl_cd1400uart;
+ panelp->uartp = &stl_cd1400uart;
panelp->isr = stl_cd1400eiointr;
}
if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, brdp->irq);
- rc = -ENODEV;
- } else {
- rc = 0;
+ retval = -ENODEV;
+ goto err_fr;
}
- return rc;
+
+ return 0;
+err_fr:
+ stl_cleanup_panels(brdp);
+err_rel2:
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+err_rel1:
+ release_region(brdp->ioaddr1, brdp->iosize1);
+err:
+ return retval;
}
/*****************************************************************************/
* dealing with all types of ECH board.
*/
-static inline int stl_initech(stlbrd_t *brdp)
+static int __devinit stl_initech(struct stlbrd *brdp)
{
- stlpanel_t *panelp;
- unsigned int status, nxtid, ioaddr, conflict;
- int panelnr, banknr, i;
+ struct stlpanel *panelp;
+ unsigned int status, nxtid, ioaddr, conflict, panelnr, banknr, i;
+ int retval;
char *name;
-#ifdef DEBUG
- printk("stl_initech(brdp=%x)\n", (int) brdp);
-#endif
+ pr_debug("stl_initech(brdp=%p)\n", brdp);
status = 0;
conflict = 0;
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 1;
status = inb(brdp->iostatus);
- if ((status & ECH_IDBITMASK) != ECH_ID)
- return(-ENODEV);
+ if ((status & ECH_IDBITMASK) != ECH_ID) {
+ retval = -ENODEV;
+ goto err;
+ }
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n",
brdp->irq, brdp->brdnr);
- return(-EINVAL);
+ retval = -EINVAL;
+ goto err;
}
status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
status |= (stl_vecmap[brdp->irq] << 1);
outb((status | ECH_BRDRESET), brdp->ioaddr1);
brdp->ioctrlval = ECH_INTENABLE |
((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
- for (i = 0; (i < 10); i++)
+ for (i = 0; i < 10; i++)
outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
brdp->iosize1 = 2;
brdp->iosize2 = 32;
brdp->ioctrl = brdp->ioaddr1 + 0x20;
brdp->iostatus = brdp->ioctrl;
status = inb(brdp->iostatus);
- if ((status & ECH_IDBITMASK) != ECH_ID)
- return(-ENODEV);
+ if ((status & ECH_IDBITMASK) != ECH_ID) {
+ retval = -ENODEV;
+ goto err;
+ }
if ((brdp->irq < 0) || (brdp->irq > 15) ||
(stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
printk("STALLION: invalid irq=%d for brd=%d\n",
brdp->irq, brdp->brdnr);
- return(-EINVAL);
+ retval = -EINVAL;
+ goto err;
}
outb(ECHMC_BRDRESET, brdp->ioctrl);
outb(ECHMC_INTENABLE, brdp->ioctrl);
default:
printk("STALLION: unknown board type=%d\n", brdp->brdtype);
- return(-EINVAL);
- break;
+ retval = -EINVAL;
+ goto err;
}
/*
* Check boards for possible IO address conflicts and return fail status
* if an IO conflict found.
*/
+ retval = -EBUSY;
if (!request_region(brdp->ioaddr1, brdp->iosize1, name)) {
printk(KERN_WARNING "STALLION: Warning, board %d I/O address "
"%x conflicts with another device\n", brdp->brdnr,
brdp->ioaddr1);
- return(-EBUSY);
+ goto err;
}
if (brdp->iosize2 > 0)
printk(KERN_WARNING "STALLION: Warning, also "
"releasing board %d I/O address %x \n",
brdp->brdnr, brdp->ioaddr1);
- release_region(brdp->ioaddr1, brdp->iosize1);
- return(-EBUSY);
+ goto err_rel1;
}
/*
panelnr = 0;
nxtid = 0;
- for (i = 0; (i < STL_MAXPANELS); i++) {
+ for (i = 0; i < STL_MAXPANELS; i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb(nxtid, brdp->ioctrl);
ioaddr = brdp->ioaddr2;
}
status = inb(ioaddr + ECH_PNLSTATUS);
if ((status & ECH_PNLIDMASK) != nxtid)
- break;
- panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
+ goto err_fr;
+ panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL);
if (!panelp) {
printk("STALLION: failed to allocate memory "
- "(size=%Zd)\n", sizeof(stlpanel_t));
- break;
+ "(size=%Zd)\n", sizeof(struct stlpanel));
+ goto err_fr;
}
panelp->magic = STL_PANELMAGIC;
panelp->brdnr = brdp->brdnr;
brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS;
if (status & ECH_PNLXPID) {
- panelp->uartp = (void *) &stl_sc26198uart;
+ panelp->uartp = &stl_sc26198uart;
panelp->isr = stl_sc26198intr;
if (status & ECH_PNL16PORT) {
panelp->nrports = 16;
brdp->bnkpageaddr[banknr] = nxtid;
brdp->bnkstataddr[banknr++] = ioaddr + 4 +
ECH_PNLSTATUS;
- } else {
+ } else
panelp->nrports = 8;
- }
} else {
- panelp->uartp = (void *) &stl_cd1400uart;
+ panelp->uartp = &stl_cd1400uart;
panelp->isr = stl_cd1400echintr;
if (status & ECH_PNL16PORT) {
panelp->nrports = 16;
brdp->panels[panelnr++] = panelp;
if ((brdp->brdtype != BRD_ECHPCI) &&
(ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
- break;
+ goto err_fr;
}
brdp->nrpanels = panelnr;
if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, brdp->irq);
- i = -ENODEV;
- } else {
- i = 0;
+ retval = -ENODEV;
+ goto err_fr;
}
- return(i);
+ return 0;
+err_fr:
+ stl_cleanup_panels(brdp);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+err_rel1:
+ release_region(brdp->ioaddr1, brdp->iosize1);
+err:
+ return retval;
}
/*****************************************************************************/
* since the initial search and setup is very different.
*/
-static int __init stl_brdinit(stlbrd_t *brdp)
+static int __devinit stl_brdinit(struct stlbrd *brdp)
{
- int i;
+ int i, retval;
-#ifdef DEBUG
- printk("stl_brdinit(brdp=%x)\n", (int) brdp);
-#endif
+ pr_debug("stl_brdinit(brdp=%p)\n", brdp);
switch (brdp->brdtype) {
case BRD_EASYIO:
case BRD_EASYIOPCI:
- stl_initeio(brdp);
+ retval = stl_initeio(brdp);
+ if (retval)
+ goto err;
break;
case BRD_ECH:
case BRD_ECHMC:
case BRD_ECHPCI:
case BRD_ECH64PCI:
- stl_initech(brdp);
+ retval = stl_initech(brdp);
+ if (retval)
+ goto err;
break;
default:
printk("STALLION: board=%d is unknown board type=%d\n",
brdp->brdnr, brdp->brdtype);
- return(ENODEV);
+ retval = -ENODEV;
+ goto err;
}
- stl_brds[brdp->brdnr] = brdp;
if ((brdp->state & BRD_FOUND) == 0) {
printk("STALLION: %s board not found, board=%d io=%x irq=%d\n",
stl_brdnames[brdp->brdtype], brdp->brdnr,
brdp->ioaddr1, brdp->irq);
- return(ENODEV);
+ goto err_free;
}
- for (i = 0; (i < STL_MAXPANELS); i++)
- if (brdp->panels[i] != (stlpanel_t *) NULL)
+ for (i = 0; i < STL_MAXPANELS; i++)
+ if (brdp->panels[i] != NULL)
stl_initports(brdp, brdp->panels[i]);
printk("STALLION: %s found, board=%d io=%x irq=%d "
"nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
brdp->nrports);
- return(0);
+
+ return 0;
+err_free:
+ free_irq(brdp->irq, brdp);
+
+ stl_cleanup_panels(brdp);
+
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+err:
+ return retval;
}
/*****************************************************************************/
* Find the next available board number that is free.
*/
-static inline int stl_getbrdnr(void)
+static int __devinit stl_getbrdnr(void)
{
- int i;
+ unsigned int i;
- for (i = 0; (i < STL_MAXBRDS); i++) {
- if (stl_brds[i] == (stlbrd_t *) NULL) {
+ for (i = 0; i < STL_MAXBRDS; i++)
+ if (stl_brds[i] == NULL) {
if (i >= stl_nrbrds)
stl_nrbrds = i + 1;
- return(i);
+ return i;
}
- }
- return(-1);
+
+ return -1;
}
/*****************************************************************************/
-
-#ifdef CONFIG_PCI
-
/*
* We have a Stallion board. Allocate a board structure and
* initialize it. Read its IO and IRQ resources from PCI
* configuration space.
*/
-static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
+static int __devinit stl_pciprobe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- stlbrd_t *brdp;
-
-#ifdef DEBUG
- printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
- devp->bus->number, devp->devfn);
-#endif
-
- if (pci_enable_device(devp))
- return(-EIO);
- if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
- return(-ENOMEM);
- if ((brdp->brdnr = stl_getbrdnr()) < 0) {
- printk("STALLION: too many boards found, "
+ struct stlbrd *brdp;
+ unsigned int i, brdtype = ent->driver_data;
+ int brdnr, retval = -ENODEV;
+
+ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
+ goto err;
+
+ dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n",
+ pdev->vendor, pdev->device, pdev->class);
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+ brdp = stl_allocbrd();
+ if (brdp == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ mutex_lock(&stl_brdslock);
+ brdnr = stl_getbrdnr();
+ if (brdnr < 0) {
+ dev_err(&pdev->dev, "too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
- return(0);
+ mutex_unlock(&stl_brdslock);
+ goto err_fr;
}
- brdp->brdtype = brdtype;
+ brdp->brdnr = (unsigned int)brdnr;
+ stl_brds[brdp->brdnr] = brdp;
+ mutex_unlock(&stl_brdslock);
-/*
- * Different Stallion boards use the BAR registers in different ways,
- * so set up io addresses based on board type.
- */
-#ifdef DEBUG
- printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
- pci_resource_start(devp, 0), pci_resource_start(devp, 1),
- pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq);
-#endif
+ brdp->brdtype = brdtype;
+ brdp->state |= STL_PROBED;
/*
* We have all resources from the board, so let's setup the actual
*/
switch (brdtype) {
case BRD_ECHPCI:
- brdp->ioaddr2 = pci_resource_start(devp, 0);
- brdp->ioaddr1 = pci_resource_start(devp, 1);
+ brdp->ioaddr2 = pci_resource_start(pdev, 0);
+ brdp->ioaddr1 = pci_resource_start(pdev, 1);
break;
case BRD_ECH64PCI:
- brdp->ioaddr2 = pci_resource_start(devp, 2);
- brdp->ioaddr1 = pci_resource_start(devp, 1);
+ brdp->ioaddr2 = pci_resource_start(pdev, 2);
+ brdp->ioaddr1 = pci_resource_start(pdev, 1);
break;
case BRD_EASYIOPCI:
- brdp->ioaddr1 = pci_resource_start(devp, 2);
- brdp->ioaddr2 = pci_resource_start(devp, 1);
+ brdp->ioaddr1 = pci_resource_start(pdev, 2);
+ brdp->ioaddr2 = pci_resource_start(pdev, 1);
break;
- default:
- printk("STALLION: unknown PCI board type=%d\n", brdtype);
- break;
- }
-
- brdp->irq = devp->irq;
- stl_brdinit(brdp);
-
- return(0);
-}
-
-/*****************************************************************************/
-
-/*
- * Find all Stallion PCI boards that might be installed. Initialize each
- * one as it is found.
- */
-
-
-static inline int stl_findpcibrds(void)
-{
- struct pci_dev *dev = NULL;
- int i, rc;
-
-#ifdef DEBUG
- printk("stl_findpcibrds()\n");
-#endif
-
- for (i = 0; (i < stl_nrpcibrds); i++)
- while ((dev = pci_find_device(stl_pcibrds[i].vendid,
- stl_pcibrds[i].devid, dev))) {
-
-/*
- * Found a device on the PCI bus that has our vendor and
- * device ID. Need to check now that it is really us.
- */
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
- continue;
-
- rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev);
- if (rc)
- return(rc);
- }
+ default:
+ dev_err(&pdev->dev, "unknown PCI board type=%u\n", brdtype);
+ break;
+ }
- return(0);
-}
+ brdp->irq = pdev->irq;
+ retval = stl_brdinit(brdp);
+ if (retval)
+ goto err_null;
-#endif
+ pci_set_drvdata(pdev, brdp);
-/*****************************************************************************/
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + i, &pdev->dev);
-/*
- * Scan through all the boards in the configuration and see what we
- * can find. Handle EIO and the ECH boards a little differently here
- * since the initial search and setup is too different.
- */
+ return 0;
+err_null:
+ stl_brds[brdp->brdnr] = NULL;
+err_fr:
+ kfree(brdp);
+err:
+ return retval;
+}
-static inline int stl_initbrds(void)
+static void __devexit stl_pciremove(struct pci_dev *pdev)
{
- stlbrd_t *brdp;
- stlconf_t *confp;
- int i;
+ struct stlbrd *brdp = pci_get_drvdata(pdev);
+ unsigned int i;
-#ifdef DEBUG
- printk("stl_initbrds()\n");
-#endif
+ free_irq(brdp->irq, brdp);
- if (stl_nrbrds > STL_MAXBRDS) {
- printk("STALLION: too many boards in configuration table, "
- "truncating to %d\n", STL_MAXBRDS);
- stl_nrbrds = STL_MAXBRDS;
- }
+ stl_cleanup_panels(brdp);
-/*
- * Firstly scan the list of static boards configured. Allocate
- * resources and initialize the boards as found.
- */
- for (i = 0; (i < stl_nrbrds); i++) {
- confp = &stl_brdconf[i];
- stl_parsebrd(confp, stl_brdsp[i]);
- if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
- return(-ENOMEM);
- brdp->brdnr = i;
- brdp->brdtype = confp->brdtype;
- brdp->ioaddr1 = confp->ioaddr1;
- brdp->ioaddr2 = confp->ioaddr2;
- brdp->irq = confp->irq;
- brdp->irqtype = confp->irqtype;
- stl_brdinit(brdp);
- }
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
-/*
- * Find any dynamically supported boards. That is via module load
- * line options or auto-detected on the PCI bus.
- */
- stl_argbrds();
-#ifdef CONFIG_PCI
- stl_findpcibrds();
-#endif
+ for (i = 0; i < brdp->nrports; i++)
+ tty_unregister_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + i);
- return(0);
+ stl_brds[brdp->brdnr] = NULL;
+ kfree(brdp);
}
+static struct pci_driver stl_pcidriver = {
+ .name = "stallion",
+ .id_table = stl_pcibrds,
+ .probe = stl_pciprobe,
+ .remove = __devexit_p(stl_pciremove)
+};
+
/*****************************************************************************/
/*
static int stl_getbrdstats(combrd_t __user *bp)
{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
- int i;
+ combrd_t stl_brdstats;
+ struct stlbrd *brdp;
+ struct stlpanel *panelp;
+ unsigned int i;
if (copy_from_user(&stl_brdstats, bp, sizeof(combrd_t)))
return -EFAULT;
if (stl_brdstats.brd >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
brdp = stl_brds[stl_brdstats.brd];
- if (brdp == (stlbrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
memset(&stl_brdstats, 0, sizeof(combrd_t));
stl_brdstats.brd = brdp->brdnr;
stl_brdstats.irq = brdp->irq;
stl_brdstats.nrpanels = brdp->nrpanels;
stl_brdstats.nrports = brdp->nrports;
- for (i = 0; (i < brdp->nrpanels); i++) {
+ for (i = 0; i < brdp->nrpanels; i++) {
panelp = brdp->panels[i];
stl_brdstats.panels[i].panel = i;
stl_brdstats.panels[i].hwid = panelp->hwid;
* Resolve the referenced port number into a port struct pointer.
*/
-static stlport_t *stl_getport(int brdnr, int panelnr, int portnr)
+static struct stlport *stl_getport(int brdnr, int panelnr, int portnr)
{
- stlbrd_t *brdp;
- stlpanel_t *panelp;
+ struct stlbrd *brdp;
+ struct stlpanel *panelp;
- if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
- return((stlport_t *) NULL);
+ if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+ return NULL;
brdp = stl_brds[brdnr];
- if (brdp == (stlbrd_t *) NULL)
- return((stlport_t *) NULL);
- if ((panelnr < 0) || (panelnr >= brdp->nrpanels))
- return((stlport_t *) NULL);
+ if (brdp == NULL)
+ return NULL;
+ if (panelnr < 0 || (unsigned int)panelnr >= brdp->nrpanels)
+ return NULL;
panelp = brdp->panels[panelnr];
- if (panelp == (stlpanel_t *) NULL)
- return((stlport_t *) NULL);
- if ((portnr < 0) || (portnr >= panelp->nrports))
- return((stlport_t *) NULL);
- return(panelp->ports[portnr]);
+ if (panelp == NULL)
+ return NULL;
+ if (portnr < 0 || (unsigned int)portnr >= panelp->nrports)
+ return NULL;
+ return panelp->ports[portnr];
}
/*****************************************************************************/
* what port to get stats for (used through board control device).
*/
-static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
+static int stl_getportstats(struct stlport *portp, comstats_t __user *cp)
{
+ comstats_t stl_comstats;
unsigned char *head, *tail;
unsigned long flags;
return -EFAULT;
portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
stl_comstats.port);
- if (portp == (stlport_t *) NULL)
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
}
portp->stats.state = portp->istate;
portp->stats.rxbuffered = 0;
spin_lock_irqsave(&stallion_lock, flags);
- if (portp->tty != (struct tty_struct *) NULL) {
+ if (portp->tty != NULL)
if (portp->tty->driver_data == portp) {
portp->stats.ttystate = portp->tty->flags;
/* No longer available as a statistic */
portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */
- if (portp->tty->termios != (struct termios *) NULL) {
+ if (portp->tty->termios != NULL) {
portp->stats.cflags = portp->tty->termios->c_cflag;
portp->stats.iflags = portp->tty->termios->c_iflag;
portp->stats.oflags = portp->tty->termios->c_oflag;
portp->stats.lflags = portp->tty->termios->c_lflag;
}
}
- }
spin_unlock_irqrestore(&stallion_lock, flags);
head = portp->tx.head;
tail = portp->tx.tail;
- portp->stats.txbuffered = ((head >= tail) ? (head - tail) :
- (STL_TXBUFSIZE - (tail - head)));
+ portp->stats.txbuffered = (head >= tail) ? (head - tail) :
+ (STL_TXBUFSIZE - (tail - head));
portp->stats.signals = (unsigned long) stl_getsignals(portp);
* Clear the port stats structure. We also return it zeroed out...
*/
-static int stl_clrportstats(stlport_t *portp, comstats_t __user *cp)
+static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp)
{
+ comstats_t stl_comstats;
+
if (!portp) {
if (copy_from_user(&stl_comstats, cp, sizeof(comstats_t)))
return -EFAULT;
portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
stl_comstats.port);
- if (portp == (stlport_t *) NULL)
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
}
memset(&portp->stats, 0, sizeof(comstats_t));
* Return the entire driver ports structure to a user app.
*/
-static int stl_getportstruct(stlport_t __user *arg)
+static int stl_getportstruct(struct stlport __user *arg)
{
- stlport_t *portp;
+ struct stlport stl_dummyport;
+ struct stlport *portp;
- if (copy_from_user(&stl_dummyport, arg, sizeof(stlport_t)))
+ if (copy_from_user(&stl_dummyport, arg, sizeof(struct stlport)))
return -EFAULT;
portp = stl_getport(stl_dummyport.brdnr, stl_dummyport.panelnr,
stl_dummyport.portnr);
if (!portp)
return -ENODEV;
- return copy_to_user(arg, portp, sizeof(stlport_t)) ? -EFAULT : 0;
+ return copy_to_user(arg, portp, sizeof(struct stlport)) ? -EFAULT : 0;
}
/*****************************************************************************/
* Return the entire driver board structure to a user app.
*/
-static int stl_getbrdstruct(stlbrd_t __user *arg)
+static int stl_getbrdstruct(struct stlbrd __user *arg)
{
- stlbrd_t *brdp;
+ struct stlbrd stl_dummybrd;
+ struct stlbrd *brdp;
- if (copy_from_user(&stl_dummybrd, arg, sizeof(stlbrd_t)))
+ if (copy_from_user(&stl_dummybrd, arg, sizeof(struct stlbrd)))
return -EFAULT;
- if ((stl_dummybrd.brdnr < 0) || (stl_dummybrd.brdnr >= STL_MAXBRDS))
+ if (stl_dummybrd.brdnr >= STL_MAXBRDS)
return -ENODEV;
brdp = stl_brds[stl_dummybrd.brdnr];
if (!brdp)
- return(-ENODEV);
- return copy_to_user(arg, brdp, sizeof(stlbrd_t)) ? -EFAULT : 0;
+ return -ENODEV;
+ return copy_to_user(arg, brdp, sizeof(struct stlbrd)) ? -EFAULT : 0;
}
/*****************************************************************************/
int brdnr, rc;
void __user *argp = (void __user *)arg;
-#ifdef DEBUG
- printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip,
- (int) fp, cmd, (int) arg);
-#endif
+ pr_debug("stl_memioctl(ip=%p,fp=%p,cmd=%x,arg=%lx)\n", ip, fp, cmd,arg);
brdnr = iminor(ip);
if (brdnr >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
rc = 0;
switch (cmd) {
break;
}
- return(rc);
+ return rc;
}
static const struct tty_operations stl_ops = {
.tiocmset = stl_tiocmset,
};
-/*****************************************************************************/
-
-static int __init stl_init(void)
-{
- int i;
- printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
-
- spin_lock_init(&stallion_lock);
- spin_lock_init(&brd_lock);
-
- stl_initbrds();
-
- stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
- if (!stl_serial)
- return -1;
-
-/*
- * Set up a character driver for per board stuff. This is mainly used
- * to do stats ioctls on the ports.
- */
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
- printk("STALLION: failed to register serial board device\n");
-
- stallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++)
- class_device_create(stallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i), NULL,
- "staliomem%d", i);
-
- stl_serial->owner = THIS_MODULE;
- stl_serial->driver_name = stl_drvname;
- stl_serial->name = "ttyE";
- stl_serial->major = STL_SERIALMAJOR;
- stl_serial->minor_start = 0;
- stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
- stl_serial->subtype = SERIAL_TYPE_NORMAL;
- stl_serial->init_termios = stl_deftermios;
- stl_serial->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(stl_serial, &stl_ops);
-
- if (tty_register_driver(stl_serial)) {
- put_tty_driver(stl_serial);
- printk("STALLION: failed to register serial driver\n");
- return -1;
- }
-
- return 0;
-}
-
/*****************************************************************************/
/* CD1400 HARDWARE FUNCTIONS */
/*****************************************************************************/
* (Maybe should make this inline...)
*/
-static int stl_cd1400getreg(stlport_t *portp, int regnr)
+static int stl_cd1400getreg(struct stlport *portp, int regnr)
{
outb((regnr + portp->uartaddr), portp->ioaddr);
return inb(portp->ioaddr + EREG_DATA);
}
-static void stl_cd1400setreg(stlport_t *portp, int regnr, int value)
+static void stl_cd1400setreg(struct stlport *portp, int regnr, int value)
{
- outb((regnr + portp->uartaddr), portp->ioaddr);
+ outb(regnr + portp->uartaddr, portp->ioaddr);
outb(value, portp->ioaddr + EREG_DATA);
}
-static int stl_cd1400updatereg(stlport_t *portp, int regnr, int value)
+static int stl_cd1400updatereg(struct stlport *portp, int regnr, int value)
{
- outb((regnr + portp->uartaddr), portp->ioaddr);
+ outb(regnr + portp->uartaddr, portp->ioaddr);
if (inb(portp->ioaddr + EREG_DATA) != value) {
outb(value, portp->ioaddr + EREG_DATA);
return 1;
* identical when dealing with ports.
*/
-static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
+static int stl_cd1400panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
{
unsigned int gfrcr;
int chipmask, i, j;
int nrchips, uartaddr, ioaddr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
-#endif
+ pr_debug("stl_panelinit(brdp=%p,panelp=%p)\n", brdp, panelp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(panelp->brdnr, panelp->pagenr);
*/
chipmask = 0;
nrchips = panelp->nrports / CD1400_PORTS;
- for (i = 0; (i < nrchips); i++) {
+ for (i = 0; i < nrchips; i++) {
if (brdp->brdtype == BRD_ECHPCI) {
outb((panelp->pagenr + (i >> 1)), brdp->ioctrl);
ioaddr = panelp->iobase;
- } else {
+ } else
ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1));
- }
uartaddr = (i & 0x01) ? 0x080 : 0;
outb((GFRCR + uartaddr), ioaddr);
outb(0, (ioaddr + EREG_DATA));
outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
outb(CCR_RESETFULL, (ioaddr + EREG_DATA));
outb((GFRCR + uartaddr), ioaddr);
- for (j = 0; (j < CCR_MAXWAIT); j++) {
+ for (j = 0; j < CCR_MAXWAIT; j++)
if ((gfrcr = inb(ioaddr + EREG_DATA)) != 0)
break;
- }
+
if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
printk("STALLION: cd1400 not responding, "
"brd=%d panel=%d chip=%d\n",
* Initialize hardware specific port registers.
*/
-static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
+static void stl_cd1400portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n",
- (int) brdp, (int) panelp, (int) portp);
-#endif
+ pr_debug("stl_cd1400portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp,
+ panelp, portp);
- if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
- (portp == (stlport_t *) NULL))
+ if ((brdp == NULL) || (panelp == NULL) ||
+ (portp == NULL))
return;
spin_lock_irqsave(&brd_lock, flags);
* since it won't usually take too long to be ready.
*/
-static void stl_cd1400ccrwait(stlport_t *portp)
+static void stl_cd1400ccrwait(struct stlport *portp)
{
int i;
- for (i = 0; (i < CCR_MAXWAIT); i++) {
- if (stl_cd1400getreg(portp, CCR) == 0) {
+ for (i = 0; i < CCR_MAXWAIT; i++)
+ if (stl_cd1400getreg(portp, CCR) == 0)
return;
- }
- }
printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n",
portp->portnr, portp->panelnr, portp->brdnr);
* settings.
*/
-static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
+static void stl_cd1400setport(struct stlport *portp, struct ktermios *tiosp)
{
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
unsigned long flags;
unsigned int clkdiv, baudrate;
unsigned char cor1, cor2, cor3;
sreroff = 0;
brdp = stl_brds[portp->brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
return;
/*
baudrate = STL_CD1400MAXBAUD;
if (baudrate > 0) {
- for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
- clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / baudrate);
+ for (clk = 0; clk < CD1400_NUMCLKS; clk++) {
+ clkdiv = (portp->clk / stl_cd1400clkdivs[clk]) / baudrate;
if (clkdiv < 0x100)
break;
}
mcor2 |= MCOR2_DCD;
sreron |= SRER_MODEM;
portp->flags |= ASYNC_CHECK_CD;
- } else {
+ } else
portp->flags &= ~ASYNC_CHECK_CD;
- }
/*
* Setup cd1400 enhanced modes if we can. In particular we want to
* them all up.
*/
-#ifdef DEBUG
- printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+ pr_debug("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
portp->portnr, portp->panelnr, portp->brdnr);
- printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n",
+ pr_debug(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n",
cor1, cor2, cor3, cor4, cor5);
- printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n",
+ pr_debug(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n",
mcor1, mcor2, rtpr, sreron, sreroff);
- printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
- printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
+ pr_debug(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
+ pr_debug(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
-#endif
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
* Set the state of the DTR and RTS signals.
*/
-static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
+static void stl_cd1400setsignals(struct stlport *portp, int dtr, int rts)
{
unsigned char msvr1, msvr2;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n",
- (int) portp, dtr, rts);
-#endif
+ pr_debug("stl_cd1400setsignals(portp=%p,dtr=%d,rts=%d)\n",
+ portp, dtr, rts);
msvr1 = 0;
msvr2 = 0;
* Return the state of the signals.
*/
-static int stl_cd1400getsignals(stlport_t *portp)
+static int stl_cd1400getsignals(struct stlport *portp)
{
unsigned char msvr1, msvr2;
unsigned long flags;
int sigs;
-#ifdef DEBUG
- printk("stl_cd1400getsignals(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400getsignals(portp=%p)\n", portp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
* Enable/Disable the Transmitter and/or Receiver.
*/
-static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
+static void stl_cd1400enablerxtx(struct stlport *portp, int rx, int tx)
{
unsigned char ccr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_cd1400enablerxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx);
+
ccr = 0;
if (tx == 0)
* Start/stop the Transmitter and/or Receiver.
*/
-static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
+static void stl_cd1400startrxtx(struct stlport *portp, int rx, int tx)
{
unsigned char sreron, sreroff;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_cd1400startrxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx);
sreron = 0;
sreroff = 0;
* Disable all interrupts from this port.
*/
-static void stl_cd1400disableintrs(stlport_t *portp)
+static void stl_cd1400disableintrs(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400disableintrs(portp=%p)\n", portp);
+
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
/*****************************************************************************/
-static void stl_cd1400sendbreak(stlport_t *portp, int len)
+static void stl_cd1400sendbreak(struct stlport *portp, int len)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len);
-#endif
+ pr_debug("stl_cd1400sendbreak(portp=%p,len=%d)\n", portp, len);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
* Take flow control actions...
*/
-static void stl_cd1400flowctrl(stlport_t *portp, int state)
+static void stl_cd1400flowctrl(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400flowctrl(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_cd1400flowctrl(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
* Send a flow control character...
*/
-static void stl_cd1400sendflow(stlport_t *portp, int state)
+static void stl_cd1400sendflow(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_cd1400sendflow(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
/*****************************************************************************/
-static void stl_cd1400flush(stlport_t *portp)
+static void stl_cd1400flush(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_cd1400flush(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400flush(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
* maintains the busy port flag.
*/
-static int stl_cd1400datastate(stlport_t *portp)
+static int stl_cd1400datastate(struct stlport *portp)
{
-#ifdef DEBUG
- printk("stl_cd1400datastate(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_cd1400datastate(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
return test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0;
* Interrupt service routine for cd1400 EasyIO boards.
*/
-static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_cd1400eiointr(struct stlpanel *panelp, unsigned int iobase)
{
unsigned char svrtype;
-#ifdef DEBUG
- printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n",
- (int) panelp, iobase);
-#endif
+ pr_debug("stl_cd1400eiointr(panelp=%p,iobase=%x)\n", panelp, iobase);
spin_lock(&brd_lock);
outb(SVRR, iobase);
* Interrupt service routine for cd1400 panels.
*/
-static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_cd1400echintr(struct stlpanel *panelp, unsigned int iobase)
{
unsigned char svrtype;
-#ifdef DEBUG
- printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp,
- iobase);
-#endif
+ pr_debug("stl_cd1400echintr(panelp=%p,iobase=%x)\n", panelp, iobase);
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
* this is the only way to generate them on the cd1400.
*/
-static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr)
+static int stl_cd1400breakisr(struct stlport *portp, int ioaddr)
{
if (portp->brklen == 1) {
outb((COR2 + portp->uartaddr), ioaddr);
* be NULL if the buffer has been freed.
*/
-static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr)
+static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr)
{
- stlport_t *portp;
+ struct stlport *portp;
int len, stlen;
char *head, *tail;
unsigned char ioack, srer;
-#ifdef DEBUG
- printk("stl_cd1400txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
-#endif
+ pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
ioack = inb(ioaddr + EREG_TXACK);
if (((ioack & panelp->ackmask) != 0) ||
}
outb(srer, (ioaddr + EREG_DATA));
} else {
- len = MIN(len, CD1400_TXFIFOSIZE);
+ len = min(len, CD1400_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb((TDR + portp->uartaddr), ioaddr);
outsb((ioaddr + EREG_DATA), tail, stlen);
len -= stlen;
* shutdown a port not in user context. Need to handle this case.
*/
-static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
+static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr)
{
- stlport_t *portp;
+ struct stlport *portp;
struct tty_struct *tty;
unsigned int ioack, len, buflen;
unsigned char status;
char ch;
-#ifdef DEBUG
- printk("stl_cd1400rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr);
-#endif
+ pr_debug("stl_cd1400rxisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr);
ioack = inb(ioaddr + EREG_RXACK);
if ((ioack & panelp->ackmask) != 0) {
outb((RDCR + portp->uartaddr), ioaddr);
len = inb(ioaddr + EREG_DATA);
if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
- len = MIN(len, sizeof(stl_unwanted));
+ len = min(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
portp->stats.rxtotal += len;
} else {
- len = MIN(len, buflen);
+ len = min(len, buflen);
if (len > 0) {
unsigned char *ptr;
outb((RDSR + portp->uartaddr), ioaddr);
do_SAK(tty);
BRDENABLE(portp->brdnr, portp->pagenr);
}
- } else if (status & ST_PARITY) {
+ } else if (status & ST_PARITY)
status = TTY_PARITY;
- } else if (status & ST_FRAMING) {
+ else if (status & ST_FRAMING)
status = TTY_FRAME;
- } else if(status & ST_OVERRUN) {
+ else if(status & ST_OVERRUN)
status = TTY_OVERRUN;
- } else {
+ else
status = 0;
- }
- } else {
+ } else
status = 0;
- }
tty_insert_flip_char(tty, ch, status);
tty_schedule_flip(tty);
}
* processing routine.
*/
-static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr)
+static void stl_cd1400mdmisr(struct stlpanel *panelp, int ioaddr)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int ioack;
unsigned char misr;
-#ifdef DEBUG
- printk("stl_cd1400mdmisr(panelp=%x)\n", (int) panelp);
-#endif
+ pr_debug("stl_cd1400mdmisr(panelp=%p)\n", panelp);
ioack = inb(ioaddr + EREG_MDACK);
if (((ioack & panelp->ackmask) != 0) ||
* (Maybe should make this inline...)
*/
-static int stl_sc26198getreg(stlport_t *portp, int regnr)
+static int stl_sc26198getreg(struct stlport *portp, int regnr)
{
outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
return inb(portp->ioaddr + XP_DATA);
}
-static void stl_sc26198setreg(stlport_t *portp, int regnr, int value)
+static void stl_sc26198setreg(struct stlport *portp, int regnr, int value)
{
outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
outb(value, (portp->ioaddr + XP_DATA));
}
-static int stl_sc26198updatereg(stlport_t *portp, int regnr, int value)
+static int stl_sc26198updatereg(struct stlport *portp, int regnr, int value)
{
outb((regnr | portp->uartaddr), (portp->ioaddr + XP_ADDR));
if (inb(portp->ioaddr + XP_DATA) != value) {
* Functions to get and set the sc26198 global registers.
*/
-static int stl_sc26198getglobreg(stlport_t *portp, int regnr)
+static int stl_sc26198getglobreg(struct stlport *portp, int regnr)
{
outb(regnr, (portp->ioaddr + XP_ADDR));
return inb(portp->ioaddr + XP_DATA);
}
#if 0
-static void stl_sc26198setglobreg(stlport_t *portp, int regnr, int value)
+static void stl_sc26198setglobreg(struct stlport *portp, int regnr, int value)
{
outb(regnr, (portp->ioaddr + XP_ADDR));
outb(value, (portp->ioaddr + XP_DATA));
* identical when dealing with ports.
*/
-static int stl_sc26198panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
+static int stl_sc26198panelinit(struct stlbrd *brdp, struct stlpanel *panelp)
{
int chipmask, i;
int nrchips, ioaddr;
-#ifdef DEBUG
- printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n",
- (int) brdp, (int) panelp);
-#endif
+ pr_debug("stl_sc26198panelinit(brdp=%p,panelp=%p)\n", brdp, panelp);
BRDENABLE(panelp->brdnr, panelp->pagenr);
if (brdp->brdtype == BRD_ECHPCI)
outb(panelp->pagenr, brdp->ioctrl);
- for (i = 0; (i < nrchips); i++) {
+ for (i = 0; i < nrchips; i++) {
ioaddr = panelp->iobase + (i * 4);
outb(SCCR, (ioaddr + XP_ADDR));
outb(CR_RESETALL, (ioaddr + XP_DATA));
* Initialize hardware specific port registers.
*/
-static void stl_sc26198portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
+static void stl_sc26198portinit(struct stlbrd *brdp, struct stlpanel *panelp, struct stlport *portp)
{
-#ifdef DEBUG
- printk("stl_sc26198portinit(brdp=%x,panelp=%x,portp=%x)\n",
- (int) brdp, (int) panelp, (int) portp);
-#endif
+ pr_debug("stl_sc26198portinit(brdp=%p,panelp=%p,portp=%p)\n", brdp,
+ panelp, portp);
- if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
- (portp == (stlport_t *) NULL))
+ if ((brdp == NULL) || (panelp == NULL) ||
+ (portp == NULL))
return;
portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4);
* settings.
*/
-static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
+static void stl_sc26198setport(struct stlport *portp, struct ktermios *tiosp)
{
- stlbrd_t *brdp;
+ struct stlbrd *brdp;
unsigned long flags;
unsigned int baudrate;
unsigned char mr0, mr1, mr2, clk;
imroff = 0;
brdp = stl_brds[portp->brdnr];
- if (brdp == (stlbrd_t *) NULL)
+ if (brdp == NULL)
return;
/*
mr1 |= (MR1_PARENB | MR1_PARODD);
else
mr1 |= (MR1_PARENB | MR1_PAREVEN);
- } else {
+ } else
mr1 |= MR1_PARNONE;
- }
mr1 |= MR1_ERRBLOCK;
if (baudrate > STL_SC26198MAXBAUD)
baudrate = STL_SC26198MAXBAUD;
- if (baudrate > 0) {
- for (clk = 0; (clk < SC26198_NRBAUDS); clk++) {
+ if (baudrate > 0)
+ for (clk = 0; clk < SC26198_NRBAUDS; clk++)
if (baudrate <= sc26198_baudtable[clk])
break;
- }
- }
/*
* Check what form of modem signaling is required and set it up.
if (tiosp->c_iflag & IXON) {
mr0 |= MR0_SWFTX | MR0_SWFT;
imron |= IR_XONXOFF;
- } else {
+ } else
imroff |= IR_XONXOFF;
- }
+
if (tiosp->c_iflag & IXOFF)
mr0 |= MR0_SWFRX;
* them all up.
*/
-#ifdef DEBUG
- printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+ pr_debug("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
portp->portnr, portp->panelnr, portp->brdnr);
- printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk);
- printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff);
- printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
+ pr_debug(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk);
+ pr_debug(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff);
+ pr_debug(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
-#endif
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
* Set the state of the DTR and RTS signals.
*/
-static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
+static void stl_sc26198setsignals(struct stlport *portp, int dtr, int rts)
{
unsigned char iopioron, iopioroff;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n",
- (int) portp, dtr, rts);
-#endif
+ pr_debug("stl_sc26198setsignals(portp=%p,dtr=%d,rts=%d)\n", portp,
+ dtr, rts);
iopioron = 0;
iopioroff = 0;
* Return the state of the signals.
*/
-static int stl_sc26198getsignals(stlport_t *portp)
+static int stl_sc26198getsignals(struct stlport *portp)
{
unsigned char ipr;
unsigned long flags;
int sigs;
-#ifdef DEBUG
- printk("stl_sc26198getsignals(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198getsignals(portp=%p)\n", portp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
* Enable/Disable the Transmitter and/or Receiver.
*/
-static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
+static void stl_sc26198enablerxtx(struct stlport *portp, int rx, int tx)
{
unsigned char ccr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_sc26198enablerxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx,tx);
ccr = portp->crenable;
if (tx == 0)
* Start/stop the Transmitter and/or Receiver.
*/
-static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
+static void stl_sc26198startrxtx(struct stlport *portp, int rx, int tx)
{
unsigned char imr;
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n",
- (int) portp, rx, tx);
-#endif
+ pr_debug("stl_sc26198startrxtx(portp=%p,rx=%d,tx=%d)\n", portp, rx, tx);
imr = portp->imr;
if (tx == 0)
* Disable all interrupts from this port.
*/
-static void stl_sc26198disableintrs(stlport_t *portp)
+static void stl_sc26198disableintrs(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198disableintrs(portp=%p)\n", portp);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
/*****************************************************************************/
-static void stl_sc26198sendbreak(stlport_t *portp, int len)
+static void stl_sc26198sendbreak(struct stlport *portp, int len)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len);
-#endif
+ pr_debug("stl_sc26198sendbreak(portp=%p,len=%d)\n", portp, len);
spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
if (len == 1) {
stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
portp->stats.txbreaks++;
- } else {
+ } else
stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
- }
+
BRDDISABLE(portp->brdnr);
spin_unlock_irqrestore(&brd_lock, flags);
}
* Take flow control actions...
*/
-static void stl_sc26198flowctrl(stlport_t *portp, int state)
+static void stl_sc26198flowctrl(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
unsigned char mr0;
-#ifdef DEBUG
- printk("stl_sc26198flowctrl(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_sc26198flowctrl(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
* Send a flow control character.
*/
-static void stl_sc26198sendflow(stlport_t *portp, int state)
+static void stl_sc26198sendflow(struct stlport *portp, int state)
{
struct tty_struct *tty;
unsigned long flags;
unsigned char mr0;
-#ifdef DEBUG
- printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state);
-#endif
+ pr_debug("stl_sc26198sendflow(portp=%p,state=%x)\n", portp, state);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
/*****************************************************************************/
-static void stl_sc26198flush(stlport_t *portp)
+static void stl_sc26198flush(struct stlport *portp)
{
unsigned long flags;
-#ifdef DEBUG
- printk("stl_sc26198flush(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198flush(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
spin_lock_irqsave(&brd_lock, flags);
* check the port statusy register to be sure.
*/
-static int stl_sc26198datastate(stlport_t *portp)
+static int stl_sc26198datastate(struct stlport *portp)
{
unsigned long flags;
unsigned char sr;
-#ifdef DEBUG
- printk("stl_sc26198datastate(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198datastate(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return 0;
if (test_bit(ASYI_TXBUSY, &portp->istate))
return 1;
* to process a command...
*/
-static void stl_sc26198wait(stlport_t *portp)
+static void stl_sc26198wait(struct stlport *portp)
{
int i;
-#ifdef DEBUG
- printk("stl_sc26198wait(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198wait(portp=%p)\n", portp);
- if (portp == (stlport_t *) NULL)
+ if (portp == NULL)
return;
- for (i = 0; (i < 20); i++)
+ for (i = 0; i < 20; i++)
stl_sc26198getglobreg(portp, TSTR);
}
* automatic flow control modes of the sc26198.
*/
-static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty)
+static void stl_sc26198txunflow(struct stlport *portp, struct tty_struct *tty)
{
unsigned char mr0;
* Interrupt service routine for sc26198 panels.
*/
-static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
+static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase)
{
- stlport_t *portp;
+ struct stlport *portp;
unsigned int iack;
spin_lock(&brd_lock);
* be NULL if the buffer has been freed.
*/
-static void stl_sc26198txisr(stlport_t *portp)
+static void stl_sc26198txisr(struct stlport *portp)
{
unsigned int ioaddr;
unsigned char mr0;
int len, stlen;
char *head, *tail;
-#ifdef DEBUG
- printk("stl_sc26198txisr(portp=%x)\n", (int) portp);
-#endif
+ pr_debug("stl_sc26198txisr(portp=%p)\n", portp);
ioaddr = portp->ioaddr;
head = portp->tx.head;
outb(mr0, (ioaddr + XP_DATA));
}
} else {
- len = MIN(len, SC26198_TXFIFOSIZE);
+ len = min(len, SC26198_TXFIFOSIZE);
portp->stats.txtotal += len;
- stlen = MIN(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
+ stlen = min(len, ((portp->tx.buf + STL_TXBUFSIZE) - tail));
outb(GTXFIFO, (ioaddr + XP_ADDR));
outsb((ioaddr + XP_DATA), tail, stlen);
len -= stlen;
* shutdown a port not in user context. Need to handle this case.
*/
-static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
+static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack)
{
struct tty_struct *tty;
unsigned int len, buflen, ioaddr;
-#ifdef DEBUG
- printk("stl_sc26198rxisr(portp=%x,iack=%x)\n", (int) portp, iack);
-#endif
+ pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack);
tty = portp->tty;
ioaddr = portp->ioaddr;
if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
- len = MIN(len, sizeof(stl_unwanted));
+ len = min(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
portp->stats.rxtotal += len;
} else {
- len = MIN(len, buflen);
+ len = min(len, buflen);
if (len > 0) {
unsigned char *ptr;
outb(GRXFIFO, (ioaddr + XP_ADDR));
* flow control modes of the sc26198.
*/
if (test_bit(ASYI_TXFLOWED, &portp->istate)) {
- if ((tty != (struct tty_struct *) NULL) &&
- (tty->termios != (struct termios *) NULL) &&
+ if ((tty != NULL) &&
+ (tty->termios != NULL) &&
(tty->termios->c_iflag & IXANY)) {
stl_sc26198txunflow(portp, tty);
}
* Process an RX bad character.
*/
-static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, char ch)
+static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char ch)
{
struct tty_struct *tty;
unsigned int ioaddr;
if (status & SR_RXBREAK)
portp->stats.rxbreaks++;
- if ((tty != (struct tty_struct *) NULL) &&
+ if ((tty != NULL) &&
((portp->rxignoremsk & status) == 0)) {
if (portp->rxmarkmsk & status) {
if (status & SR_RXBREAK) {
do_SAK(tty);
BRDENABLE(portp->brdnr, portp->pagenr);
}
- } else if (status & SR_RXPARITY) {
+ } else if (status & SR_RXPARITY)
status = TTY_PARITY;
- } else if (status & SR_RXFRAMING) {
+ else if (status & SR_RXFRAMING)
status = TTY_FRAME;
- } else if(status & SR_RXOVERRUN) {
+ else if(status & SR_RXOVERRUN)
status = TTY_OVERRUN;
- } else {
+ else
status = 0;
- }
- } else {
+ } else
status = 0;
- }
tty_insert_flip_char(tty, ch, status);
tty_schedule_flip(tty);
* the FIFO).
*/
-static void stl_sc26198rxbadchars(stlport_t *portp)
+static void stl_sc26198rxbadchars(struct stlport *portp)
{
unsigned char status, mr1;
char ch;
* processing time.
*/
-static void stl_sc26198otherisr(stlport_t *portp, unsigned int iack)
+static void stl_sc26198otherisr(struct stlport *portp, unsigned int iack)
{
unsigned char cir, ipr, xisr;
-#ifdef DEBUG
- printk("stl_sc26198otherisr(portp=%x,iack=%x)\n", (int) portp, iack);
-#endif
+ pr_debug("stl_sc26198otherisr(portp=%p,iack=%x)\n", portp, iack);
cir = stl_sc26198getglobreg(portp, CIR);
}
}
-/*****************************************************************************/
+static void stl_free_isabrds(void)
+{
+ struct stlbrd *brdp;
+ unsigned int i;
+
+ for (i = 0; i < stl_nrbrds; i++) {
+ if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED))
+ continue;
+
+ free_irq(brdp->irq, brdp);
+
+ stl_cleanup_panels(brdp);
+
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
+
+ kfree(brdp);
+ stl_brds[i] = NULL;
+ }
+}
+
+/*
+ * Loadable module initialization stuff.
+ */
+static int __init stallion_module_init(void)
+{
+ struct stlbrd *brdp;
+ struct stlconf conf;
+ unsigned int i, j;
+ int retval;
+
+ printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
+
+ spin_lock_init(&stallion_lock);
+ spin_lock_init(&brd_lock);
+
+/*
+ * Find any dynamically supported boards. That is via module load
+ * line options.
+ */
+ for (i = stl_nrbrds; i < stl_nargs; i++) {
+ memset(&conf, 0, sizeof(conf));
+ if (stl_parsebrd(&conf, stl_brdsp[i]) == 0)
+ continue;
+ if ((brdp = stl_allocbrd()) == NULL)
+ continue;
+ brdp->brdnr = i;
+ brdp->brdtype = conf.brdtype;
+ brdp->ioaddr1 = conf.ioaddr1;
+ brdp->ioaddr2 = conf.ioaddr2;
+ brdp->irq = conf.irq;
+ brdp->irqtype = conf.irqtype;
+ if (stl_brdinit(brdp))
+ kfree(brdp);
+ else {
+ for (j = 0; j < brdp->nrports; j++)
+ tty_register_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + j, NULL);
+ stl_brds[brdp->brdnr] = brdp;
+ stl_nrbrds = i + 1;
+ }
+ }
+
+ /* this has to be _after_ isa finding because of locking */
+ retval = pci_register_driver(&stl_pcidriver);
+ if (retval && stl_nrbrds == 0)
+ goto err;
+
+ stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+ if (!stl_serial) {
+ retval = -ENOMEM;
+ goto err_pcidr;
+ }
+
+/*
+ * Set up a character driver for per board stuff. This is mainly used
+ * to do stats ioctls on the ports.
+ */
+ if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
+ printk("STALLION: failed to register serial board device\n");
+
+ stallion_class = class_create(THIS_MODULE, "staliomem");
+ if (IS_ERR(stallion_class)) {
+ retval = PTR_ERR(stallion_class);
+ goto err_reg;
+ }
+ for (i = 0; i < 4; i++)
+ class_device_create(stallion_class, NULL,
+ MKDEV(STL_SIOMEMMAJOR, i), NULL,
+ "staliomem%d", i);
+
+ stl_serial->owner = THIS_MODULE;
+ stl_serial->driver_name = stl_drvname;
+ stl_serial->name = "ttyE";
+ stl_serial->major = STL_SERIALMAJOR;
+ stl_serial->minor_start = 0;
+ stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
+ stl_serial->subtype = SERIAL_TYPE_NORMAL;
+ stl_serial->init_termios = stl_deftermios;
+ stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(stl_serial, &stl_ops);
+
+ retval = tty_register_driver(stl_serial);
+ if (retval) {
+ printk("STALLION: failed to register serial driver\n");
+ goto err_clsdev;
+ }
+
+ return 0;
+err_clsdev:
+ for (i = 0; i < 4; i++)
+ class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ class_destroy(stallion_class);
+err_reg:
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+ put_tty_driver(stl_serial);
+err_pcidr:
+ pci_unregister_driver(&stl_pcidriver);
+ stl_free_isabrds();
+err:
+ return retval;
+}
+
+static void __exit stallion_module_exit(void)
+{
+ struct stlbrd *brdp;
+ unsigned int i, j;
+ int retval;
+
+ pr_debug("cleanup_module()\n");
+
+ printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
+ stl_drvversion);
+
+/*
+ * Free up all allocated resources used by the ports. This includes
+ * memory and interrupts. As part of this process we will also do
+ * a hangup on every open port - to try to flush out any processes
+ * hanging onto ports.
+ */
+ for (i = 0; i < stl_nrbrds; i++) {
+ if ((brdp = stl_brds[i]) == NULL || (brdp->state & STL_PROBED))
+ continue;
+ for (j = 0; j < brdp->nrports; j++)
+ tty_unregister_device(stl_serial,
+ brdp->brdnr * STL_MAXPORTS + j);
+ }
+ tty_unregister_driver(stl_serial);
+ put_tty_driver(stl_serial);
+
+ for (i = 0; i < 4; i++)
+ class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
+ printk("STALLION: failed to un-register serial memory device, "
+ "errno=%d\n", -retval);
+ class_destroy(stallion_class);
+
+ pci_unregister_driver(&stl_pcidriver);
+
+ stl_free_isabrds();
+}
+
+module_init(stallion_module_init);
+module_exit(stallion_module_exit);
+
+MODULE_AUTHOR("Greg Ungerer");
+MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
+MODULE_LICENSE("GPL");
* USA.
*
* Revision history:
- * $Log: sx.c,v $
* Revision 1.33 2000/03/09 10:00:00 pvdl,wolff
* - Fixed module and port counting
* - Fixed signal handling
*
* */
-
-#define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $"
-#define RCS_REV "$Revision: 1.33 $"
+#define SX_VERSION 1.33
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
+#include <linux/eisa.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/generic_serial.h>
#include "sx.h"
-
/* I don't think that this driver can handle more than 256 ports on
one machine. You'll have to increase the number of boards in sx.h
if you want more than 4 boards. */
#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
#endif
-#ifdef CONFIG_PCI
-static struct pci_device_id sx_pci_tbl[] = {
- { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, PCI_ANY_ID, PCI_ANY_ID },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
-#endif /* CONFIG_PCI */
-
/* Configurable options:
(Don't be too sure that it'll work if you toggle them) */
/* Am I paranoid or not ? ;-) */
#undef SX_PARANOIA_CHECK
-
/* 20 -> 2000 per second. The card should rate-limit interrupts at 100
Hz, but it is user configurable. I don't recommend going above 1000
Hz. The interrupt ratelimit might trigger if the interrupt is
interrupt. Use polling. */
#undef IRQ_RATE_LIMIT
-
#if 0
/* Not implemented */
/*
*/
#define SX_REPORT_FIFO
#define SX_REPORT_OVERRUN
-#endif
-
+#endif
/* Function prototypes */
-static void sx_disable_tx_interrupts (void * ptr);
-static void sx_enable_tx_interrupts (void * ptr);
-static void sx_disable_rx_interrupts (void * ptr);
-static void sx_enable_rx_interrupts (void * ptr);
-static int sx_get_CD (void * ptr);
-static void sx_shutdown_port (void * ptr);
-static int sx_set_real_termios (void *ptr);
-static void sx_close (void *ptr);
-static int sx_chars_in_buffer (void * ptr);
-static int sx_init_board (struct sx_board *board);
-static int sx_init_portstructs (int nboards, int nports);
-static int sx_fw_ioctl (struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+static void sx_disable_tx_interrupts(void *ptr);
+static void sx_enable_tx_interrupts(void *ptr);
+static void sx_disable_rx_interrupts(void *ptr);
+static void sx_enable_rx_interrupts(void *ptr);
+static int sx_get_CD(void *ptr);
+static void sx_shutdown_port(void *ptr);
+static int sx_set_real_termios(void *ptr);
+static void sx_close(void *ptr);
+static int sx_chars_in_buffer(void *ptr);
+static int sx_init_board(struct sx_board *board);
+static int sx_init_portstructs(int nboards, int nports);
+static int sx_fw_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
static int sx_init_drivers(void);
-
static struct tty_driver *sx_driver;
+static DEFINE_MUTEX(sx_boards_lock);
static struct sx_board boards[SX_NBOARDS];
static struct sx_port *sx_ports;
static int sx_initialized;
static int sx_nports;
static int sx_debug;
-
/* You can have the driver poll your card.
- Set sx_poll to 1 to poll every timer tick (10ms on Intel).
This is used when the card cannot use an interrupt for some reason.
static int sx_maxints = 100;
+#ifdef CONFIG_ISA
+
/* These are the only open spaces in my computer. Yours may have more
or less.... -- REW
duh: Card at 0xa0000 is possible on HP Netserver?? -- pvdl
*/
-static int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
- 0xc8000, 0xd8000, 0xe8000};
-static int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
- 0xc8000, 0xd8000, 0xe8000, 0xa0000};
-static int si1_probe_addrs[]= { 0xd0000};
+static int sx_probe_addrs[] = {
+ 0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000
+};
+static int si_probe_addrs[] = {
+ 0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000, 0xa0000
+};
+static int si1_probe_addrs[] = {
+ 0xd0000
+};
#define NR_SX_ADDRS ARRAY_SIZE(sx_probe_addrs)
#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
+module_param_array(sx_probe_addrs, int, NULL, 0);
+module_param_array(si_probe_addrs, int, NULL, 0);
+#endif
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
Some architectures may need more. */
static int sx_irqmask = -1;
-module_param_array(sx_probe_addrs, int, NULL, 0);
-module_param_array(si_probe_addrs, int, NULL, 0);
module_param(sx_poll, int, 0);
module_param(sx_slowpoll, int, 0);
module_param(sx_maxints, int, 0);
sx_disable_rx_interrupts,
sx_enable_rx_interrupts,
sx_get_CD,
- sx_shutdown_port,
- sx_set_real_termios,
+ sx_shutdown_port,
+ sx_set_real_termios,
sx_chars_in_buffer,
sx_close,
};
-
/*
This driver can spew a whole lot of debugging output at you. If you
need maximum performance, you should disable the DEBUG define. To
*/
#define DEBUG
-
#ifdef DEBUG
-#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
+#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
#else
-#define sx_dprintk(f, str...) /* nothing */
+#define sx_dprintk(f, str...) /* nothing */
#endif
+#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
+#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__FUNCTION__)
-
-#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
-#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit %s\n", __FUNCTION__)
-
-#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
- __FUNCTION__, port->line)
-
-
-
+#define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
+ __FUNCTION__, port->line)
/*
* Firmware loader driver specific routines
*/
static const struct file_operations sx_fw_fops = {
- .owner = THIS_MODULE,
- .ioctl = sx_fw_ioctl,
+ .owner = THIS_MODULE,
+ .ioctl = sx_fw_ioctl,
};
static struct miscdevice sx_fw_device = {
SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
};
-
-
-
-
#ifdef SX_PARANOIA_CHECK
/* This doesn't work. Who's paranoid around here? Not me! */
-static inline int sx_paranoia_check(struct sx_port const * port,
+static inline int sx_paranoia_check(struct sx_port const *port,
char *name, const char *routine)
{
+ static const char *badmagic = KERN_ERR "sx: Warning: bad sx port magic "
+ "number for device %s in %s\n";
+ static const char *badinfo = KERN_ERR "sx: Warning: null sx port for "
+ "device %s in %s\n";
- static const char *badmagic =
- KERN_ERR "sx: Warning: bad sx port magic number for device %s in %s\n";
- static const char *badinfo =
- KERN_ERR "sx: Warning: null sx port for device %s in %s\n";
-
if (!port) {
printk(badinfo, name, routine);
return 1;
#define TIMEOUT_1 30
#define TIMEOUT_2 1000000
-
#ifdef DEBUG
static void my_hd_io(void __iomem *p, int len)
{
int i, j, ch;
unsigned char __iomem *addr = p;
- for (i=0;i<len;i+=16) {
- printk ("%p ", addr+i);
- for (j=0;j<16;j++) {
- printk ("%02x %s", readb(addr+j+i), (j==7)?" ":"");
+ for (i = 0; i < len; i += 16) {
+ printk("%p ", addr + i);
+ for (j = 0; j < 16; j++) {
+ printk("%02x %s", readb(addr + j + i),
+ (j == 7) ? " " : "");
}
- for (j=0;j<16;j++) {
- ch = readb(addr+j+i);
- printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ for (j = 0; j < 16; j++) {
+ ch = readb(addr + j + i);
+ printk("%c", (ch < 0x20) ? '.' :
+ ((ch > 0x7f) ? '.' : ch));
}
- printk ("\n");
+ printk("\n");
}
}
static void my_hd(void *p, int len)
int i, j, ch;
unsigned char *addr = p;
- for (i=0;i<len;i+=16) {
- printk ("%p ", addr+i);
- for (j=0;j<16;j++) {
- printk ("%02x %s", addr[j+i], (j==7)?" ":"");
+ for (i = 0; i < len; i += 16) {
+ printk("%p ", addr + i);
+ for (j = 0; j < 16; j++) {
+ printk("%02x %s", addr[j + i], (j == 7) ? " " : "");
}
- for (j=0;j<16;j++) {
- ch = addr[j+i];
- printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ for (j = 0; j < 16; j++) {
+ ch = addr[j + i];
+ printk("%c", (ch < 0x20) ? '.' :
+ ((ch > 0x7f) ? '.' : ch));
}
- printk ("\n");
+ printk("\n");
}
}
#endif
-
-
/* This needs redoing for Alpha -- REW -- Done. */
-static inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
+static inline void write_sx_byte(struct sx_board *board, int offset, u8 byte)
{
- writeb (byte, board->base+offset);
+ writeb(byte, board->base + offset);
}
-static inline u8 read_sx_byte (struct sx_board *board, int offset)
+static inline u8 read_sx_byte(struct sx_board *board, int offset)
{
- return readb (board->base+offset);
+ return readb(board->base + offset);
}
-
-static inline void write_sx_word (struct sx_board *board, int offset, u16 word)
+static inline void write_sx_word(struct sx_board *board, int offset, u16 word)
{
- writew (word, board->base+offset);
+ writew(word, board->base + offset);
}
-static inline u16 read_sx_word (struct sx_board *board, int offset)
+static inline u16 read_sx_word(struct sx_board *board, int offset)
{
- return readw (board->base + offset);
+ return readw(board->base + offset);
}
-
-static int sx_busy_wait_eq (struct sx_board *board,
- int offset, int mask, int correctval)
+static int sx_busy_wait_eq(struct sx_board *board,
+ int offset, int mask, int correctval)
{
int i;
- func_enter ();
+ func_enter();
- for (i=0; i < TIMEOUT_1 ;i++)
- if ((read_sx_byte (board, offset) & mask) == correctval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_1; i++)
+ if ((read_sx_byte(board, offset) & mask) == correctval) {
+ func_exit();
return 1;
}
- for (i=0; i < TIMEOUT_2 ;i++) {
- if ((read_sx_byte (board, offset) & mask) == correctval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_2; i++) {
+ if ((read_sx_byte(board, offset) & mask) == correctval) {
+ func_exit();
return 1;
}
- udelay (1);
+ udelay(1);
}
- func_exit ();
+ func_exit();
return 0;
}
-
-static int sx_busy_wait_neq (struct sx_board *board,
- int offset, int mask, int badval)
+static int sx_busy_wait_neq(struct sx_board *board,
+ int offset, int mask, int badval)
{
int i;
- func_enter ();
+ func_enter();
- for (i=0; i < TIMEOUT_1 ;i++)
- if ((read_sx_byte (board, offset) & mask) != badval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_1; i++)
+ if ((read_sx_byte(board, offset) & mask) != badval) {
+ func_exit();
return 1;
}
- for (i=0; i < TIMEOUT_2 ;i++) {
- if ((read_sx_byte (board, offset) & mask) != badval) {
- func_exit ();
+ for (i = 0; i < TIMEOUT_2; i++) {
+ if ((read_sx_byte(board, offset) & mask) != badval) {
+ func_exit();
return 1;
}
- udelay (1);
+ udelay(1);
}
- func_exit ();
+ func_exit();
return 0;
}
-
-
/* 5.6.4 of 6210028 r2.3 */
-static int sx_reset (struct sx_board *board)
+static int sx_reset(struct sx_board *board)
{
- func_enter ();
+ func_enter();
- if (IS_SX_BOARD (board)) {
+ if (IS_SX_BOARD(board)) {
- write_sx_byte (board, SX_CONFIG, 0);
- write_sx_byte (board, SX_RESET, 1); /* Value doesn't matter */
+ write_sx_byte(board, SX_CONFIG, 0);
+ write_sx_byte(board, SX_RESET, 1); /* Value doesn't matter */
- if (!sx_busy_wait_eq (board, SX_RESET_STATUS, 1, 0)) {
- printk (KERN_INFO "sx: Card doesn't respond to reset....\n");
+ if (!sx_busy_wait_eq(board, SX_RESET_STATUS, 1, 0)) {
+ printk(KERN_INFO "sx: Card doesn't respond to "
+ "reset...\n");
return 0;
}
} else if (IS_EISA_BOARD(board)) {
- outb(board->irq<<4, board->eisa_base+0xc02);
+ outb(board->irq << 4, board->eisa_base + 0xc02);
} else if (IS_SI1_BOARD(board)) {
- write_sx_byte (board, SI1_ISA_RESET, 0); // value does not matter
+ write_sx_byte(board, SI1_ISA_RESET, 0); /*value doesn't matter*/
} else {
/* Gory details of the SI/ISA board */
- write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
- write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
- write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
- write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
- write_sx_byte (board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
+ write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
+ write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
+ write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
+ write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
+ write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+ write_sx_byte(board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
}
- func_exit ();
+ func_exit();
return 1;
}
-
/* This doesn't work on machines where "NULL" isn't 0 */
/* If you have one of those, someone will need to write
the equivalent of this, which will amount to about 3 lines. I don't
want to complicate this right now. -- REW
(See, I do write comments every now and then :-) */
-#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
-
-
-#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
-#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem))
-#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem))
+#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
+#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
+#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem))
+#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem))
#define sx_write_channel_byte(port, elem, val) \
- write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
+ write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
#define sx_read_channel_byte(port, elem) \
- read_sx_byte (port->board, CHAN_OFFSET (port, elem))
+ read_sx_byte (port->board, CHAN_OFFSET (port, elem))
#define sx_write_channel_word(port, elem, val) \
- write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
+ write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
#define sx_read_channel_word(port, elem) \
- read_sx_word (port->board, CHAN_OFFSET (port, elem))
-
+ read_sx_word (port->board, CHAN_OFFSET (port, elem))
#define sx_write_module_byte(board, addr, elem, val) \
- write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
+ write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
#define sx_read_module_byte(board, addr, elem) \
- read_sx_byte (board, MODU_OFFSET (board, addr, elem))
+ read_sx_byte (board, MODU_OFFSET (board, addr, elem))
#define sx_write_module_word(board, addr, elem, val) \
- write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
+ write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
#define sx_read_module_word(board, addr, elem) \
- read_sx_word (board, MODU_OFFSET (board, addr, elem))
-
+ read_sx_word (board, MODU_OFFSET (board, addr, elem))
#define sx_write_board_byte(board, elem, val) \
- write_sx_byte (board, BRD_OFFSET (board, elem), val)
+ write_sx_byte (board, BRD_OFFSET (board, elem), val)
#define sx_read_board_byte(board, elem) \
- read_sx_byte (board, BRD_OFFSET (board, elem))
+ read_sx_byte (board, BRD_OFFSET (board, elem))
#define sx_write_board_word(board, elem, val) \
- write_sx_word (board, BRD_OFFSET (board, elem), val)
+ write_sx_word (board, BRD_OFFSET (board, elem), val)
#define sx_read_board_word(board, elem) \
- read_sx_word (board, BRD_OFFSET (board, elem))
-
+ read_sx_word (board, BRD_OFFSET (board, elem))
-static int sx_start_board (struct sx_board *board)
+static int sx_start_board(struct sx_board *board)
{
- if (IS_SX_BOARD (board)) {
- write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN);
+ if (IS_SX_BOARD(board)) {
+ write_sx_byte(board, SX_CONFIG, SX_CONF_BUSEN);
} else if (IS_EISA_BOARD(board)) {
write_sx_byte(board, SI2_EISA_OFF, SI2_EISA_VAL);
- outb((board->irq<<4)|4, board->eisa_base+0xc02);
+ outb((board->irq << 4) | 4, board->eisa_base + 0xc02);
} else if (IS_SI1_BOARD(board)) {
- write_sx_byte (board, SI1_ISA_RESET_CLEAR, 0);
- write_sx_byte (board, SI1_ISA_INTCL, 0);
+ write_sx_byte(board, SI1_ISA_RESET_CLEAR, 0);
+ write_sx_byte(board, SI1_ISA_INTCL, 0);
} else {
/* Don't bug me about the clear_set.
I haven't the foggiest idea what it's about -- REW */
- write_sx_byte (board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
+ write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
}
return 1;
}
#define SX_IRQ_REG_VAL(board) \
- ((board->flags & SX_ISA_BOARD)?(board->irq << 4):0)
+ ((board->flags & SX_ISA_BOARD) ? (board->irq << 4) : 0)
/* Note. The SX register is write-only. Therefore, we have to enable the
bus too. This is a no-op, if you don't mess with this driver... */
-static int sx_start_interrupts (struct sx_board *board)
+static int sx_start_interrupts(struct sx_board *board)
{
/* Don't call this with board->irq == 0 */
if (IS_SX_BOARD(board)) {
- write_sx_byte (board, SX_CONFIG, SX_IRQ_REG_VAL (board) |
- SX_CONF_BUSEN |
- SX_CONF_HOSTIRQ);
+ write_sx_byte(board, SX_CONFIG, SX_IRQ_REG_VAL(board) |
+ SX_CONF_BUSEN | SX_CONF_HOSTIRQ);
} else if (IS_EISA_BOARD(board)) {
- inb(board->eisa_base+0xc03);
+ inb(board->eisa_base + 0xc03);
} else if (IS_SI1_BOARD(board)) {
- write_sx_byte (board, SI1_ISA_INTCL,0);
- write_sx_byte (board, SI1_ISA_INTCL_CLEAR,0);
+ write_sx_byte(board, SI1_ISA_INTCL, 0);
+ write_sx_byte(board, SI1_ISA_INTCL_CLEAR, 0);
} else {
switch (board->irq) {
- case 11:write_sx_byte (board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);break;
- case 12:write_sx_byte (board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);break;
- case 15:write_sx_byte (board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);break;
- default:printk (KERN_INFO "sx: SI/XIO card doesn't support interrupt %d.\n",
- board->irq);
- return 0;
+ case 11:
+ write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);
+ break;
+ case 12:
+ write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);
+ break;
+ case 15:
+ write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);
+ break;
+ default:
+ printk(KERN_INFO "sx: SI/XIO card doesn't support "
+ "interrupt %d.\n", board->irq);
+ return 0;
}
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
}
return 1;
}
-
-static int sx_send_command (struct sx_port *port,
- int command, int mask, int newstat)
+static int sx_send_command(struct sx_port *port,
+ int command, int mask, int newstat)
{
- func_enter2 ();
- write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command);
- func_exit ();
- return sx_busy_wait_eq (port->board, CHAN_OFFSET (port, hi_hstat), mask, newstat);
+ func_enter2();
+ write_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat), command);
+ func_exit();
+ return sx_busy_wait_eq(port->board, CHAN_OFFSET(port, hi_hstat), mask,
+ newstat);
}
-
-static char *mod_type_s (int module_type)
+static char *mod_type_s(int module_type)
{
switch (module_type) {
- case TA4: return "TA4";
- case TA8: return "TA8";
- case TA4_ASIC: return "TA4_ASIC";
- case TA8_ASIC: return "TA8_ASIC";
- case MTA_CD1400:return "MTA_CD1400";
- case SXDC: return "SXDC";
- default:return "Unknown/invalid";
+ case TA4:
+ return "TA4";
+ case TA8:
+ return "TA8";
+ case TA4_ASIC:
+ return "TA4_ASIC";
+ case TA8_ASIC:
+ return "TA8_ASIC";
+ case MTA_CD1400:
+ return "MTA_CD1400";
+ case SXDC:
+ return "SXDC";
+ default:
+ return "Unknown/invalid";
}
}
-
-static char *pan_type_s (int pan_type)
+static char *pan_type_s(int pan_type)
{
switch (pan_type) {
- case MOD_RS232DB25: return "MOD_RS232DB25";
- case MOD_RS232RJ45: return "MOD_RS232RJ45";
- case MOD_RS422DB25: return "MOD_RS422DB25";
- case MOD_PARALLEL: return "MOD_PARALLEL";
- case MOD_2_RS232DB25: return "MOD_2_RS232DB25";
- case MOD_2_RS232RJ45: return "MOD_2_RS232RJ45";
- case MOD_2_RS422DB25: return "MOD_2_RS422DB25";
- case MOD_RS232DB25MALE: return "MOD_RS232DB25MALE";
- case MOD_2_PARALLEL: return "MOD_2_PARALLEL";
- case MOD_BLANK: return "empty";
- default:return "invalid";
+ case MOD_RS232DB25:
+ return "MOD_RS232DB25";
+ case MOD_RS232RJ45:
+ return "MOD_RS232RJ45";
+ case MOD_RS422DB25:
+ return "MOD_RS422DB25";
+ case MOD_PARALLEL:
+ return "MOD_PARALLEL";
+ case MOD_2_RS232DB25:
+ return "MOD_2_RS232DB25";
+ case MOD_2_RS232RJ45:
+ return "MOD_2_RS232RJ45";
+ case MOD_2_RS422DB25:
+ return "MOD_2_RS422DB25";
+ case MOD_RS232DB25MALE:
+ return "MOD_RS232DB25MALE";
+ case MOD_2_PARALLEL:
+ return "MOD_2_PARALLEL";
+ case MOD_BLANK:
+ return "empty";
+ default:
+ return "invalid";
}
}
-
-static int mod_compat_type (int module_type)
+static int mod_compat_type(int module_type)
{
return module_type >> 4;
}
static void sx_reconfigure_port(struct sx_port *port)
{
- if (sx_read_channel_byte (port, hi_hstat) == HS_IDLE_OPEN) {
- if (sx_send_command (port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
- printk (KERN_WARNING "sx: Sent reconfigure command, but card didn't react.\n");
+ if (sx_read_channel_byte(port, hi_hstat) == HS_IDLE_OPEN) {
+ if (sx_send_command(port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
+ printk(KERN_WARNING "sx: Sent reconfigure command, but "
+ "card didn't react.\n");
}
} else {
- sx_dprintk (SX_DEBUG_TERMIOS,
- "sx: Not sending reconfigure: port isn't open (%02x).\n",
- sx_read_channel_byte (port, hi_hstat));
- }
+ sx_dprintk(SX_DEBUG_TERMIOS, "sx: Not sending reconfigure: "
+ "port isn't open (%02x).\n",
+ sx_read_channel_byte(port, hi_hstat));
+ }
}
-static void sx_setsignals (struct sx_port *port, int dtr, int rts)
+static void sx_setsignals(struct sx_port *port, int dtr, int rts)
{
int t;
- func_enter2 ();
+ func_enter2();
- t = sx_read_channel_byte (port, hi_op);
- if (dtr >= 0) t = dtr? (t | OP_DTR): (t & ~OP_DTR);
- if (rts >= 0) t = rts? (t | OP_RTS): (t & ~OP_RTS);
- sx_write_channel_byte (port, hi_op, t);
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
+ t = sx_read_channel_byte(port, hi_op);
+ if (dtr >= 0)
+ t = dtr ? (t | OP_DTR) : (t & ~OP_DTR);
+ if (rts >= 0)
+ t = rts ? (t | OP_RTS) : (t & ~OP_RTS);
+ sx_write_channel_byte(port, hi_op, t);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
- func_exit ();
+ func_exit();
}
-
-
-static int sx_getsignals (struct sx_port *port)
+static int sx_getsignals(struct sx_port *port)
{
- int i_stat,o_stat;
-
- o_stat = sx_read_channel_byte (port, hi_op);
- i_stat = sx_read_channel_byte (port, hi_ip);
-
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) %02x/%02x\n",
- (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
- port->c_dcd, sx_get_CD (port),
- sx_read_channel_byte (port, hi_ip),
- sx_read_channel_byte (port, hi_state));
-
- return (((o_stat & OP_DTR)?TIOCM_DTR:0) |
- ((o_stat & OP_RTS)?TIOCM_RTS:0) |
- ((i_stat & IP_CTS)?TIOCM_CTS:0) |
- ((i_stat & IP_DCD)?TIOCM_CAR:0) |
- ((i_stat & IP_DSR)?TIOCM_DSR:0) |
- ((i_stat & IP_RI)?TIOCM_RNG:0)
- );
+ int i_stat, o_stat;
+
+ o_stat = sx_read_channel_byte(port, hi_op);
+ i_stat = sx_read_channel_byte(port, hi_ip);
+
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) "
+ "%02x/%02x\n",
+ (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
+ port->c_dcd, sx_get_CD(port),
+ sx_read_channel_byte(port, hi_ip),
+ sx_read_channel_byte(port, hi_state));
+
+ return (((o_stat & OP_DTR) ? TIOCM_DTR : 0) |
+ ((o_stat & OP_RTS) ? TIOCM_RTS : 0) |
+ ((i_stat & IP_CTS) ? TIOCM_CTS : 0) |
+ ((i_stat & IP_DCD) ? TIOCM_CAR : 0) |
+ ((i_stat & IP_DSR) ? TIOCM_DSR : 0) |
+ ((i_stat & IP_RI) ? TIOCM_RNG : 0));
}
-
-static void sx_set_baud (struct sx_port *port)
+static void sx_set_baud(struct sx_port *port)
{
int t;
if (port->board->ta_type == MOD_SXDC) {
switch (port->gs.baud) {
- /* Save some typing work... */
-#define e(x) case x:t= BAUD_ ## x ; break
- e(50);e(75);e(110);e(150);e(200);e(300);e(600);
- e(1200);e(1800);e(2000);e(2400);e(4800);e(7200);
- e(9600);e(14400);e(19200);e(28800);e(38400);
- e(56000);e(57600);e(64000);e(76800);e(115200);
- e(128000);e(150000);e(230400);e(256000);e(460800);
- e(921600);
- case 134 :t = BAUD_134_5; break;
- case 0 :t = -1;
- break;
+ /* Save some typing work... */
+#define e(x) case x: t = BAUD_ ## x; break
+ e(50);
+ e(75);
+ e(110);
+ e(150);
+ e(200);
+ e(300);
+ e(600);
+ e(1200);
+ e(1800);
+ e(2000);
+ e(2400);
+ e(4800);
+ e(7200);
+ e(9600);
+ e(14400);
+ e(19200);
+ e(28800);
+ e(38400);
+ e(56000);
+ e(57600);
+ e(64000);
+ e(76800);
+ e(115200);
+ e(128000);
+ e(150000);
+ e(230400);
+ e(256000);
+ e(460800);
+ e(921600);
+ case 134:
+ t = BAUD_134_5;
+ break;
+ case 0:
+ t = -1;
+ break;
default:
/* Can I return "invalid"? */
t = BAUD_9600;
- printk (KERN_INFO "sx: unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: unsupported baud rate: %d.\n",
+ port->gs.baud);
break;
}
#undef e
if (t > 0) {
- /* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
- sx_setsignals (port, 1, -1);
+/* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
+ sx_setsignals(port, 1, -1);
/* XXX This is not TA & MTA compatible */
- sx_write_channel_byte (port, hi_csr, 0xff);
+ sx_write_channel_byte(port, hi_csr, 0xff);
- sx_write_channel_byte (port, hi_txbaud, t);
- sx_write_channel_byte (port, hi_rxbaud, t);
+ sx_write_channel_byte(port, hi_txbaud, t);
+ sx_write_channel_byte(port, hi_rxbaud, t);
} else {
- sx_setsignals (port, 0, -1);
+ sx_setsignals(port, 0, -1);
}
} else {
switch (port->gs.baud) {
-#define e(x) case x:t= CSR_ ## x ; break
- e(75);e(150);e(300);e(600);e(1200);e(2400);e(4800);
- e(1800);e(9600);
- e(19200);e(57600);e(38400);
- /* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
- case 110:
+#define e(x) case x: t = CSR_ ## x; break
+ e(75);
+ e(150);
+ e(300);
+ e(600);
+ e(1200);
+ e(2400);
+ e(4800);
+ e(1800);
+ e(9600);
+ e(19200);
+ e(57600);
+ e(38400);
+/* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
+ case 110:
if (port->board->ta_type == MOD_TA) {
t = CSR_110;
break;
} else {
t = CSR_9600;
- printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: Unsupported baud rate: "
+ "%d.\n", port->gs.baud);
break;
}
- case 115200:
+ case 115200:
if (port->board->ta_type == MOD_TA) {
t = CSR_9600;
- printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: Unsupported baud rate: "
+ "%d.\n", port->gs.baud);
break;
} else {
t = CSR_110;
break;
}
- case 0 :t = -1;
- break;
+ case 0:
+ t = -1;
+ break;
default:
t = CSR_9600;
- printk (KERN_INFO "sx: Unsupported baud rate: %d.\n", port->gs.baud);
+ printk(KERN_INFO "sx: Unsupported baud rate: %d.\n",
+ port->gs.baud);
break;
}
#undef e
if (t >= 0) {
- sx_setsignals (port, 1, -1);
- sx_write_channel_byte (port, hi_csr, t * 0x11);
+ sx_setsignals(port, 1, -1);
+ sx_write_channel_byte(port, hi_csr, t * 0x11);
} else {
- sx_setsignals (port, 0, -1);
+ sx_setsignals(port, 0, -1);
}
}
}
-
/* Simon Allen's version of this routine was 225 lines long. 85 is a lot
better. -- REW */
-static int sx_set_real_termios (void *ptr)
+static int sx_set_real_termios(void *ptr)
{
struct sx_port *port = ptr;
belongs (next to the drop dtr if baud == 0) -- REW */
/* sx_setsignals (port, 1, -1); */
- sx_set_baud (port);
+ sx_set_baud(port);
#define CFLAG port->gs.tty->termios->c_cflag
- sx_write_channel_byte (port, hi_mr1,
- (C_PARENB (port->gs.tty)? MR1_WITH:MR1_NONE) |
- (C_PARODD (port->gs.tty)? MR1_ODD:MR1_EVEN) |
- (C_CRTSCTS(port->gs.tty)? MR1_RTS_RXFLOW:0) |
- (((CFLAG & CSIZE)==CS8) ? MR1_8_BITS:0) |
- (((CFLAG & CSIZE)==CS7) ? MR1_7_BITS:0) |
- (((CFLAG & CSIZE)==CS6) ? MR1_6_BITS:0) |
- (((CFLAG & CSIZE)==CS5) ? MR1_5_BITS:0) );
-
- sx_write_channel_byte (port, hi_mr2,
- (C_CRTSCTS(port->gs.tty)?MR2_CTS_TXFLOW:0) |
- (C_CSTOPB (port->gs.tty)?MR2_2_STOP:MR2_1_STOP));
+ sx_write_channel_byte(port, hi_mr1,
+ (C_PARENB(port->gs.tty) ? MR1_WITH : MR1_NONE) |
+ (C_PARODD(port->gs.tty) ? MR1_ODD : MR1_EVEN) |
+ (C_CRTSCTS(port->gs.tty) ? MR1_RTS_RXFLOW : 0) |
+ (((CFLAG & CSIZE) == CS8) ? MR1_8_BITS : 0) |
+ (((CFLAG & CSIZE) == CS7) ? MR1_7_BITS : 0) |
+ (((CFLAG & CSIZE) == CS6) ? MR1_6_BITS : 0) |
+ (((CFLAG & CSIZE) == CS5) ? MR1_5_BITS : 0));
+
+ sx_write_channel_byte(port, hi_mr2,
+ (C_CRTSCTS(port->gs.tty) ? MR2_CTS_TXFLOW : 0) |
+ (C_CSTOPB(port->gs.tty) ? MR2_2_STOP :
+ MR2_1_STOP));
switch (CFLAG & CSIZE) {
- case CS8:sx_write_channel_byte (port, hi_mask, 0xff);break;
- case CS7:sx_write_channel_byte (port, hi_mask, 0x7f);break;
- case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
- case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
+ case CS8:
+ sx_write_channel_byte(port, hi_mask, 0xff);
+ break;
+ case CS7:
+ sx_write_channel_byte(port, hi_mask, 0x7f);
+ break;
+ case CS6:
+ sx_write_channel_byte(port, hi_mask, 0x3f);
+ break;
+ case CS5:
+ sx_write_channel_byte(port, hi_mask, 0x1f);
+ break;
default:
- printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
+ printk(KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
break;
}
- sx_write_channel_byte (port, hi_prtcl,
- (I_IXON (port->gs.tty)?SP_TXEN:0) |
- (I_IXOFF (port->gs.tty)?SP_RXEN:0) |
- (I_IXANY (port->gs.tty)?SP_TANY:0) |
- SP_DCEN);
+ sx_write_channel_byte(port, hi_prtcl,
+ (I_IXON(port->gs.tty) ? SP_TXEN : 0) |
+ (I_IXOFF(port->gs.tty) ? SP_RXEN : 0) |
+ (I_IXANY(port->gs.tty) ? SP_TANY : 0) | SP_DCEN);
- sx_write_channel_byte (port, hi_break,
- (I_IGNBRK(port->gs.tty)?BR_IGN:0 |
- I_BRKINT(port->gs.tty)?BR_INT:0));
+ sx_write_channel_byte(port, hi_break,
+ (I_IGNBRK(port->gs.tty) ? BR_IGN : 0 |
+ I_BRKINT(port->gs.tty) ? BR_INT : 0));
- sx_write_channel_byte (port, hi_txon, START_CHAR (port->gs.tty));
- sx_write_channel_byte (port, hi_rxon, START_CHAR (port->gs.tty));
- sx_write_channel_byte (port, hi_txoff, STOP_CHAR (port->gs.tty));
- sx_write_channel_byte (port, hi_rxoff, STOP_CHAR (port->gs.tty));
+ sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.tty));
+ sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.tty));
+ sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.tty));
+ sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.tty));
sx_reconfigure_port(port);
/* Tell line discipline whether we will do input cooking */
- if(I_OTHER(port->gs.tty)) {
+ if (I_OTHER(port->gs.tty)) {
clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
} else {
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
- port->gs.tty->termios->c_iflag,
- I_OTHER(port->gs.tty));
-
+ sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+ port->gs.tty->termios->c_iflag, I_OTHER(port->gs.tty));
/* Tell line discipline whether we will do output cooking.
* If OPOST is set and no other output flags are set then we can do output
* processing. Even if only *one* other flag in the O_OTHER group is set
* we do cooking in software.
*/
- if(O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
+ if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) {
set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
} else {
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
- port->gs.tty->termios->c_oflag,
- O_OTHER(port->gs.tty));
+ sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+ port->gs.tty->termios->c_oflag, O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
- func_exit ();
+ func_exit();
return 0;
}
-
-
/* ********************************************************************** *
* the interrupt related routines *
* ********************************************************************** */
know I'm dead against that, but I think it is required in this
case. */
-
-static void sx_transmit_chars (struct sx_port *port)
+static void sx_transmit_chars(struct sx_port *port)
{
int c;
int tx_ip;
int txroom;
- func_enter2 ();
- sx_dprintk (SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
- port, port->gs.xmit_cnt);
+ func_enter2();
+ sx_dprintk(SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
+ port, port->gs.xmit_cnt);
- if (test_and_set_bit (SX_PORT_TRANSMIT_LOCK, &port->locks)) {
+ if (test_and_set_bit(SX_PORT_TRANSMIT_LOCK, &port->locks)) {
return;
}
while (1) {
c = port->gs.xmit_cnt;
- sx_dprintk (SX_DEBUG_TRANSMIT, "Copying %d ", c);
- tx_ip = sx_read_channel_byte (port, hi_txipos);
+ sx_dprintk(SX_DEBUG_TRANSMIT, "Copying %d ", c);
+ tx_ip = sx_read_channel_byte(port, hi_txipos);
/* Took me 5 minutes to deduce this formula.
Luckily it is literally in the manual in section 6.5.4.3.5 */
- txroom = (sx_read_channel_byte (port, hi_txopos) - tx_ip - 1) & 0xff;
+ txroom = (sx_read_channel_byte(port, hi_txopos) - tx_ip - 1) &
+ 0xff;
/* Don't copy more bytes than there is room for in the buffer */
if (c > txroom)
c = txroom;
- sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom );
+ sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom);
/* Don't copy past the end of the hardware transmit buffer */
- if (c > 0x100 - tx_ip)
+ if (c > 0x100 - tx_ip)
c = 0x100 - tx_ip;
- sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100-tx_ip );
+ sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100 - tx_ip);
/* Don't copy pas the end of the source buffer */
- if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
+ if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
- sx_dprintk (SX_DEBUG_TRANSMIT, " %d(%ld) \n",
- c, SERIAL_XMIT_SIZE- port->gs.xmit_tail);
-
- /* If for one reason or another, we can't copy more data, we're done! */
- if (c == 0) break;
+ sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%ld) \n",
+ c, SERIAL_XMIT_SIZE - port->gs.xmit_tail);
+ /* If for one reason or another, we can't copy more data, we're
+ done! */
+ if (c == 0)
+ break;
- memcpy_toio (port->board->base + CHAN_OFFSET(port,hi_txbuf) + tx_ip,
- port->gs.xmit_buf + port->gs.xmit_tail, c);
+ memcpy_toio(port->board->base + CHAN_OFFSET(port, hi_txbuf) +
+ tx_ip, port->gs.xmit_buf + port->gs.xmit_tail, c);
/* Update the pointer in the card */
- sx_write_channel_byte (port, hi_txipos, (tx_ip+c) & 0xff);
+ sx_write_channel_byte(port, hi_txipos, (tx_ip + c) & 0xff);
/* Update the kernel buffer end */
- port->gs.xmit_tail = (port->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE-1);
+ port->gs.xmit_tail = (port->gs.xmit_tail + c) &
+ (SERIAL_XMIT_SIZE - 1);
/* This one last. (this is essential)
- It would allow others to start putting more data into the buffer! */
+ It would allow others to start putting more data into the
+ buffer! */
port->gs.xmit_cnt -= c;
}
if (port->gs.xmit_cnt == 0) {
- sx_disable_tx_interrupts (port);
+ sx_disable_tx_interrupts(port);
}
if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
tty_wakeup(port->gs.tty);
- sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
- port->gs.wakeup_chars);
+ sx_dprintk(SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
+ port->gs.wakeup_chars);
}
- clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks);
- func_exit ();
+ clear_bit(SX_PORT_TRANSMIT_LOCK, &port->locks);
+ func_exit();
}
-
/* Note the symmetry between receiving chars and transmitting them!
Note: The kernel should have implemented both a receive buffer and
a transmit buffer. */
/* Inlined: Called only once. Remove the inline when you add another call */
-static inline void sx_receive_chars (struct sx_port *port)
+static inline void sx_receive_chars(struct sx_port *port)
{
int c;
int rx_op;
struct tty_struct *tty;
- int copied=0;
+ int copied = 0;
unsigned char *rp;
- func_enter2 ();
+ func_enter2();
tty = port->gs.tty;
while (1) {
- rx_op = sx_read_channel_byte (port, hi_rxopos);
- c = (sx_read_channel_byte (port, hi_rxipos) - rx_op) & 0xff;
+ rx_op = sx_read_channel_byte(port, hi_rxopos);
+ c = (sx_read_channel_byte(port, hi_rxipos) - rx_op) & 0xff;
- sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
/* Don't copy past the end of the hardware receive buffer */
- if (rx_op + c > 0x100) c = 0x100 - rx_op;
+ if (rx_op + c > 0x100)
+ c = 0x100 - rx_op;
- sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
/* Don't copy more bytes than there is room for in the buffer */
c = tty_prepare_flip_string(tty, &rp, c);
- sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
/* If for one reason or another, we can't copy more data, we're done! */
- if (c == 0) break;
+ if (c == 0)
+ break;
- sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c,
- read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),
- CHAN_OFFSET(port, hi_rxbuf));
- memcpy_fromio (rp,
- port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);
+ sx_dprintk(SX_DEBUG_RECEIVE, "Copying over %d chars. First is "
+ "%d at %lx\n", c, read_sx_byte(port->board,
+ CHAN_OFFSET(port, hi_rxbuf) + rx_op),
+ CHAN_OFFSET(port, hi_rxbuf));
+ memcpy_fromio(rp, port->board->base +
+ CHAN_OFFSET(port, hi_rxbuf) + rx_op, c);
/* This one last. ( Not essential.)
- It allows the card to start putting more data into the buffer!
+ It allows the card to start putting more data into the
+ buffer!
Update the pointer in the card */
- sx_write_channel_byte (port, hi_rxopos, (rx_op + c) & 0xff);
+ sx_write_channel_byte(port, hi_rxopos, (rx_op + c) & 0xff);
copied += c;
}
if (copied) {
struct timeval tv;
- do_gettimeofday (&tv);
- sx_dprintk (SX_DEBUG_RECEIVE,
- "pushing flipq port %d (%3d chars): %d.%06d (%d/%d)\n",
- port->line, copied,
- (int) (tv.tv_sec % 60), (int)tv.tv_usec, tty->raw, tty->real_raw);
+ do_gettimeofday(&tv);
+ sx_dprintk(SX_DEBUG_RECEIVE, "pushing flipq port %d (%3d "
+ "chars): %d.%06d (%d/%d)\n", port->line,
+ copied, (int)(tv.tv_sec % 60), (int)tv.tv_usec,
+ tty->raw, tty->real_raw);
- /* Tell the rest of the system the news. Great news. New characters! */
- tty_flip_buffer_push (tty);
+ /* Tell the rest of the system the news. Great news. New
+ characters! */
+ tty_flip_buffer_push(tty);
/* tty_schedule_flip (tty); */
}
- func_exit ();
+ func_exit();
}
/* Inlined: it is called only once. Remove the inline if you add another
call */
-static inline void sx_check_modem_signals (struct sx_port *port)
+static inline void sx_check_modem_signals(struct sx_port *port)
{
int hi_state;
int c_dcd;
- hi_state = sx_read_channel_byte (port, hi_state);
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
- port->c_dcd, sx_get_CD (port));
+ hi_state = sx_read_channel_byte(port, hi_state);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
+ port->c_dcd, sx_get_CD(port));
if (hi_state & ST_BREAK) {
hi_state &= ~ST_BREAK;
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
- sx_write_channel_byte (port, hi_state, hi_state);
- gs_got_break (&port->gs);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a break.\n");
+ sx_write_channel_byte(port, hi_state, hi_state);
+ gs_got_break(&port->gs);
}
if (hi_state & ST_DCD) {
hi_state &= ~ST_DCD;
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
- sx_write_channel_byte (port, hi_state, hi_state);
- c_dcd = sx_get_CD (port);
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
+ sx_write_channel_byte(port, hi_state, hi_state);
+ c_dcd = sx_get_CD(port);
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
if (c_dcd != port->c_dcd) {
port->c_dcd = c_dcd;
- if (sx_get_CD (port)) {
+ if (sx_get_CD(port)) {
/* DCD went UP */
- if ((sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) &&
- !(port->gs.tty->termios->c_cflag & CLOCAL) ) {
- /* Are we blocking in open?*/
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n");
- wake_up_interruptible(&port->gs.open_wait);
+ if ((sx_read_channel_byte(port, hi_hstat) !=
+ HS_IDLE_CLOSED) &&
+ !(port->gs.tty->termios->
+ c_cflag & CLOCAL)) {
+ /* Are we blocking in open? */
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "active, unblocking open\n");
+ wake_up_interruptible(&port->gs.
+ open_wait);
} else {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD raised. Ignoring.\n");
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "raised. Ignoring.\n");
}
} else {
/* DCD went down! */
- if (!(port->gs.tty->termios->c_cflag & CLOCAL) ) {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n");
- tty_hangup (port->gs.tty);
+ if (!(port->gs.tty->termios->c_cflag & CLOCAL)){
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "dropped. hanging up....\n");
+ tty_hangup(port->gs.tty);
} else {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. ignoring.\n");
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+ "dropped. ignoring.\n");
}
}
} else {
- sx_dprintk (SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us DCD changed, but it didn't.\n");
+ sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us "
+ "DCD changed, but it didn't.\n");
}
}
}
-
/* This is what an interrupt routine should look like.
* Small, elegant, clear.
*/
-static irqreturn_t sx_interrupt (int irq, void *ptr)
+static irqreturn_t sx_interrupt(int irq, void *ptr)
{
struct sx_board *board = ptr;
struct sx_port *port;
int i;
- func_enter ();
- sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq);
+ func_enter();
+ sx_dprintk(SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq,
+ board->irq);
/* AAargh! The order in which to do these things is essential and
not trivial.
- Rate limit goes before "recursive". Otherwise a series of
- recursive calls will hang the machine in the interrupt routine.
+ recursive calls will hang the machine in the interrupt routine.
- hardware twiddling goes before "recursive". Otherwise when we
- poll the card, and a recursive interrupt happens, we won't
- ack the card, so it might keep on interrupting us. (especially
- level sensitive interrupt systems like PCI).
+ poll the card, and a recursive interrupt happens, we won't
+ ack the card, so it might keep on interrupting us. (especially
+ level sensitive interrupt systems like PCI).
- Rate limit goes before hardware twiddling. Otherwise we won't
- catch a card that has gone bonkers.
+ catch a card that has gone bonkers.
- The "initialized" test goes after the hardware twiddling. Otherwise
- the card will stick us in the interrupt routine again.
+ the card will stick us in the interrupt routine again.
- The initialized test goes before recursive.
- */
-
-
+ */
#ifdef IRQ_RATE_LIMIT
/* Aaargh! I'm ashamed. This costs more lines-of-code than the
- actual interrupt routine!. (Well, used to when I wrote that comment) */
+ actual interrupt routine!. (Well, used to when I wrote that
+ comment) */
{
static int lastjif;
- static int nintr=0;
+ static int nintr = 0;
if (lastjif == jiffies) {
if (++nintr > IRQ_RATE_LIMIT) {
- free_irq (board->irq, board);
- printk (KERN_ERR "sx: Too many interrupts. Turning off interrupt %d.\n",
- board->irq);
+ free_irq(board->irq, board);
+ printk(KERN_ERR "sx: Too many interrupts. "
+ "Turning off interrupt %d.\n",
+ board->irq);
}
} else {
lastjif = jiffies;
}
#endif
-
if (board->irq == irq) {
/* Tell the card we've noticed the interrupt. */
- sx_write_board_word (board, cc_int_pending, 0);
- if (IS_SX_BOARD (board)) {
- write_sx_byte (board, SX_RESET_IRQ, 1);
+ sx_write_board_word(board, cc_int_pending, 0);
+ if (IS_SX_BOARD(board)) {
+ write_sx_byte(board, SX_RESET_IRQ, 1);
} else if (IS_EISA_BOARD(board)) {
- inb(board->eisa_base+0xc03);
- write_sx_word(board, 8, 0);
+ inb(board->eisa_base + 0xc03);
+ write_sx_word(board, 8, 0);
} else {
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
- write_sx_byte (board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+ write_sx_byte(board, SI2_ISA_INTCLEAR,
+ SI2_ISA_INTCLEAR_CLEAR);
+ write_sx_byte(board, SI2_ISA_INTCLEAR,
+ SI2_ISA_INTCLEAR_SET);
}
}
if (!(board->flags & SX_BOARD_INITIALIZED))
return IRQ_HANDLED;
- if (test_and_set_bit (SX_BOARD_INTR_LOCK, &board->locks)) {
- printk (KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
+ if (test_and_set_bit(SX_BOARD_INTR_LOCK, &board->locks)) {
+ printk(KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
return IRQ_HANDLED;
}
- for (i=0;i<board->nports;i++) {
+ for (i = 0; i < board->nports; i++) {
port = &board->ports[i];
if (port->gs.flags & GS_ACTIVE) {
- if (sx_read_channel_byte (port, hi_state)) {
- sx_dprintk (SX_DEBUG_INTERRUPTS,
- "Port %d: modem signal change?... \n", i);
- sx_check_modem_signals (port);
+ if (sx_read_channel_byte(port, hi_state)) {
+ sx_dprintk(SX_DEBUG_INTERRUPTS, "Port %d: "
+ "modem signal change?... \n",i);
+ sx_check_modem_signals(port);
}
if (port->gs.xmit_cnt) {
- sx_transmit_chars (port);
+ sx_transmit_chars(port);
}
if (!(port->gs.flags & SX_RX_THROTTLE)) {
- sx_receive_chars (port);
+ sx_receive_chars(port);
}
}
}
- clear_bit (SX_BOARD_INTR_LOCK, &board->locks);
+ clear_bit(SX_BOARD_INTR_LOCK, &board->locks);
- sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq);
- func_exit ();
+ sx_dprintk(SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq,
+ board->irq);
+ func_exit();
return IRQ_HANDLED;
}
-
-static void sx_pollfunc (unsigned long data)
+static void sx_pollfunc(unsigned long data)
{
- struct sx_board *board = (struct sx_board *) data;
-
- func_enter ();
+ struct sx_board *board = (struct sx_board *)data;
- sx_interrupt (0, board);
+ func_enter();
- init_timer(&board->timer);
+ sx_interrupt(0, board);
- board->timer.expires = jiffies + sx_poll;
- add_timer (&board->timer);
- func_exit ();
+ mod_timer(&board->timer, jiffies + sx_poll);
+ func_exit();
}
-
-
/* ********************************************************************** *
* Here are the routines that actually *
* interface with the generic_serial driver *
/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */
/* Hmm. Ok I figured it out. You don't. */
-static void sx_disable_tx_interrupts (void * ptr)
+static void sx_disable_tx_interrupts(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
func_enter2();
port->gs.flags &= ~GS_TX_INTEN;
func_exit();
}
-
-static void sx_enable_tx_interrupts (void * ptr)
+static void sx_enable_tx_interrupts(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
int data_in_buffer;
func_enter2();
/* First transmit the characters that we're supposed to */
- sx_transmit_chars (port);
+ sx_transmit_chars(port);
/* The sx card will never interrupt us if we don't fill the buffer
past 25%. So we keep considering interrupts off if that's the case. */
- data_in_buffer = (sx_read_channel_byte (port, hi_txipos) -
- sx_read_channel_byte (port, hi_txopos)) & 0xff;
+ data_in_buffer = (sx_read_channel_byte(port, hi_txipos) -
+ sx_read_channel_byte(port, hi_txopos)) & 0xff;
/* XXX Must be "HIGH_WATER" for SI card according to doc. */
- if (data_in_buffer < LOW_WATER)
+ if (data_in_buffer < LOW_WATER)
port->gs.flags &= ~GS_TX_INTEN;
func_exit();
}
-
-static void sx_disable_rx_interrupts (void * ptr)
+static void sx_disable_rx_interrupts(void *ptr)
{
/* struct sx_port *port = ptr; */
func_enter();
func_exit();
}
-static void sx_enable_rx_interrupts (void * ptr)
+static void sx_enable_rx_interrupts(void *ptr)
{
/* struct sx_port *port = ptr; */
func_enter();
func_exit();
}
-
/* Jeez. Isn't this simple? */
-static int sx_get_CD (void * ptr)
+static int sx_get_CD(void *ptr)
{
struct sx_port *port = ptr;
func_enter2();
func_exit();
- return ((sx_read_channel_byte (port, hi_ip) & IP_DCD) != 0);
+ return ((sx_read_channel_byte(port, hi_ip) & IP_DCD) != 0);
}
-
/* Jeez. Isn't this simple? */
-static int sx_chars_in_buffer (void * ptr)
+static int sx_chars_in_buffer(void *ptr)
{
struct sx_port *port = ptr;
func_enter2();
func_exit();
- return ((sx_read_channel_byte (port, hi_txipos) -
- sx_read_channel_byte (port, hi_txopos)) & 0xff);
+ return ((sx_read_channel_byte(port, hi_txipos) -
+ sx_read_channel_byte(port, hi_txopos)) & 0xff);
}
-
-static void sx_shutdown_port (void * ptr)
+static void sx_shutdown_port(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
func_enter();
- port->gs.flags &= ~ GS_ACTIVE;
+ port->gs.flags &= ~GS_ACTIVE;
if (port->gs.tty && (port->gs.tty->termios->c_cflag & HUPCL)) {
- sx_setsignals (port, 0, 0);
+ sx_setsignals(port, 0, 0);
sx_reconfigure_port(port);
}
func_exit();
}
-
-
-
-
/* ********************************************************************** *
* Here are the routines that actually *
* interface with the rest of the system *
* ********************************************************************** */
-static int sx_open (struct tty_struct * tty, struct file * filp)
+static int sx_open(struct tty_struct *tty, struct file *filp)
{
struct sx_port *port;
int retval, line;
}
line = tty->index;
- sx_dprintk (SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, np=%d)\n",
- current->pid, line, tty, current->signal->tty, sx_nports);
+ sx_dprintk(SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, "
+ "np=%d)\n", current->pid, line, tty,
+ current->signal->tty, sx_nports);
if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
return -ENODEV;
- port = & sx_ports[line];
+ port = &sx_ports[line];
port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a
- 1 -> 0 transition. */
+ 1 -> 0 transition. */
-
- sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
+ sx_dprintk(SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
spin_lock_irqsave(&port->gs.driver_lock, flags);
port->gs.count++;
spin_unlock_irqrestore(&port->gs.driver_lock, flags);
- sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
+ sx_dprintk(SX_DEBUG_OPEN, "starting port\n");
/*
* Start up serial port
*/
retval = gs_init_port(&port->gs);
- sx_dprintk (SX_DEBUG_OPEN, "done gs_init\n");
+ sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n");
if (retval) {
port->gs.count--;
return retval;
port->gs.flags |= GS_ACTIVE;
if (port->gs.count <= 1)
- sx_setsignals (port, 1,1);
+ sx_setsignals(port, 1, 1);
#if 0
if (sx_debug & SX_DEBUG_OPEN)
- my_hd (port, sizeof (*port));
+ my_hd(port, sizeof(*port));
#else
if (sx_debug & SX_DEBUG_OPEN)
- my_hd_io (port->board->base + port->ch_base, sizeof (*port));
+ my_hd_io(port->board->base + port->ch_base, sizeof(*port));
#endif
if (port->gs.count <= 1) {
- if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
- printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
+ if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+ printk(KERN_ERR "sx: Card didn't respond to LOPEN "
+ "command.\n");
spin_lock_irqsave(&port->gs.driver_lock, flags);
port->gs.count--;
spin_unlock_irqrestore(&port->gs.driver_lock, flags);
}
retval = gs_block_til_ready(port, filp);
- sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
- retval, port->gs.count);
+ sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
+ retval, port->gs.count);
if (retval) {
- /*
- * Don't lower gs.count here because sx_close() will be called later
- */
+/*
+ * Don't lower gs.count here because sx_close() will be called later
+ */
return retval;
}
/* tty->low_latency = 1; */
- port->c_dcd = sx_get_CD (port);
- sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+ port->c_dcd = sx_get_CD(port);
+ sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
func_exit();
return 0;
}
-
-static void sx_close (void *ptr)
+static void sx_close(void *ptr)
{
- struct sx_port *port = ptr;
+ struct sx_port *port = ptr;
/* Give the port 5 seconds to close down. */
- int to = 5 * HZ;
+ int to = 5 * HZ;
- func_enter ();
+ func_enter();
- sx_setsignals (port, 0, 0);
- sx_reconfigure_port(port);
- sx_send_command (port, HS_CLOSE, 0, 0);
+ sx_setsignals(port, 0, 0);
+ sx_reconfigure_port(port);
+ sx_send_command(port, HS_CLOSE, 0, 0);
- while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED))
+ while (to-- && (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED))
if (msleep_interruptible(10))
break;
- if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
- if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
- printk (KERN_ERR
- "sx: sent the force_close command, but card didn't react\n");
+ if (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) {
+ if (sx_send_command(port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED)
+ != 1) {
+ printk(KERN_ERR "sx: sent the force_close command, but "
+ "card didn't react\n");
} else
- sx_dprintk (SX_DEBUG_CLOSE, "sent the force_close command.\n");
+ sx_dprintk(SX_DEBUG_CLOSE, "sent the force_close "
+ "command.\n");
}
- sx_dprintk (SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
- 5 * HZ - to - 1, port->gs.count);
+ sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
+ 5 * HZ - to - 1, port->gs.count);
- if(port->gs.count) {
- sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count);
- //printk ("%s SETTING port count to zero: %p count: %d\n", __FUNCTION__, port, port->gs.count);
- //port->gs.count = 0;
+ if (port->gs.count) {
+ sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
+ port->gs.count);
+ /*printk("%s SETTING port count to zero: %p count: %d\n",
+ __FUNCTION__, port, port->gs.count);
+ port->gs.count = 0;*/
}
- func_exit ();
+ func_exit();
}
-
-
/* This is relatively thorough. But then again it is only 20 lines. */
-#define MARCHUP for (i=min;i<max;i++)
-#define MARCHDOWN for (i=max-1;i>=min;i--)
-#define W0 write_sx_byte (board, i, 0x55)
-#define W1 write_sx_byte (board, i, 0xaa)
-#define R0 if (read_sx_byte (board, i) != 0x55) return 1
-#define R1 if (read_sx_byte (board, i) != 0xaa) return 1
+#define MARCHUP for (i = min; i < max; i++)
+#define MARCHDOWN for (i = max - 1; i >= min; i--)
+#define W0 write_sx_byte(board, i, 0x55)
+#define W1 write_sx_byte(board, i, 0xaa)
+#define R0 if (read_sx_byte(board, i) != 0x55) return 1
+#define R1 if (read_sx_byte(board, i) != 0xaa) return 1
/* This memtest takes a human-noticable time. You normally only do it
once a boot, so I guess that it is worth it. */
-static int do_memtest (struct sx_board *board, int min, int max)
+static int do_memtest(struct sx_board *board, int min, int max)
{
int i;
intermittent errors. -- REW
(For the theory behind memory testing see:
Testing Semiconductor Memories by A.J. van de Goor.) */
- MARCHUP {W0;}
- MARCHUP {R0;W1;R1;W0;R0;W1;}
- MARCHUP {R1;W0;W1;}
- MARCHDOWN {R1;W0;W1;W0;}
- MARCHDOWN {R0;W1;W0;}
+ MARCHUP {
+ W0;
+ }
+ MARCHUP {
+ R0;
+ W1;
+ R1;
+ W0;
+ R0;
+ W1;
+ }
+ MARCHUP {
+ R1;
+ W0;
+ W1;
+ }
+ MARCHDOWN {
+ R1;
+ W0;
+ W1;
+ W0;
+ }
+ MARCHDOWN {
+ R0;
+ W1;
+ W0;
+ }
return 0;
}
-
#undef MARCHUP
#undef MARCHDOWN
#undef W0
#undef R0
#undef R1
-#define MARCHUP for (i=min;i<max;i+=2)
-#define MARCHDOWN for (i=max-1;i>=min;i-=2)
-#define W0 write_sx_word (board, i, 0x55aa)
-#define W1 write_sx_word (board, i, 0xaa55)
-#define R0 if (read_sx_word (board, i) != 0x55aa) return 1
-#define R1 if (read_sx_word (board, i) != 0xaa55) return 1
+#define MARCHUP for (i = min; i < max; i += 2)
+#define MARCHDOWN for (i = max - 1; i >= min; i -= 2)
+#define W0 write_sx_word(board, i, 0x55aa)
+#define W1 write_sx_word(board, i, 0xaa55)
+#define R0 if (read_sx_word(board, i) != 0x55aa) return 1
+#define R1 if (read_sx_word(board, i) != 0xaa55) return 1
#if 0
/* This memtest takes a human-noticable time. You normally only do it
once a boot, so I guess that it is worth it. */
-static int do_memtest_w (struct sx_board *board, int min, int max)
+static int do_memtest_w(struct sx_board *board, int min, int max)
{
int i;
- MARCHUP {W0;}
- MARCHUP {R0;W1;R1;W0;R0;W1;}
- MARCHUP {R1;W0;W1;}
- MARCHDOWN {R1;W0;W1;W0;}
- MARCHDOWN {R0;W1;W0;}
+ MARCHUP {
+ W0;
+ }
+ MARCHUP {
+ R0;
+ W1;
+ R1;
+ W0;
+ R0;
+ W1;
+ }
+ MARCHUP {
+ R1;
+ W0;
+ W1;
+ }
+ MARCHDOWN {
+ R1;
+ W0;
+ W1;
+ W0;
+ }
+ MARCHDOWN {
+ R0;
+ W1;
+ W0;
+ }
return 0;
}
#endif
-
-static int sx_fw_ioctl (struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int sx_fw_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
int rc = 0;
int __user *descr = (int __user *)arg;
func_enter();
-#if 0
+#if 0
/* Removed superuser check: Sysops can use the permissions on the device
file to restrict access. Recommendation: Root only. (root.root 600) */
if (!capable(CAP_SYS_ADMIN)) {
}
#endif
- sx_dprintk (SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
- if (!board) board = &boards[0];
+ if (!board)
+ board = &boards[0];
if (board->flags & SX_BOARD_PRESENT) {
- sx_dprintk (SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
- board->flags);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
+ board->flags);
} else {
- sx_dprintk (SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
- board->flags);
- for (i=0;i< SX_NBOARDS;i++)
- sx_dprintk (SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
- sx_dprintk (SX_DEBUG_FIRMWARE, "\n");
+ sx_dprintk(SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
+ board->flags);
+ for (i = 0; i < SX_NBOARDS; i++)
+ sx_dprintk(SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "\n");
return -EIO;
}
switch (cmd) {
case SXIO_SET_BOARD:
- sx_dprintk (SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
- if (arg >= SX_NBOARDS) return -EIO;
- sx_dprintk (SX_DEBUG_FIRMWARE, "not out of range\n");
- if (!(boards[arg].flags & SX_BOARD_PRESENT)) return -EIO;
- sx_dprintk (SX_DEBUG_FIRMWARE, ".. and present!\n");
+ sx_dprintk(SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
+ if (arg >= SX_NBOARDS)
+ return -EIO;
+ sx_dprintk(SX_DEBUG_FIRMWARE, "not out of range\n");
+ if (!(boards[arg].flags & SX_BOARD_PRESENT))
+ return -EIO;
+ sx_dprintk(SX_DEBUG_FIRMWARE, ".. and present!\n");
board = &boards[arg];
break;
case SXIO_GET_TYPE:
- rc = -ENOENT; /* If we manage to miss one, return error. */
- if (IS_SX_BOARD (board)) rc = SX_TYPE_SX;
- if (IS_CF_BOARD (board)) rc = SX_TYPE_CF;
- if (IS_SI_BOARD (board)) rc = SX_TYPE_SI;
- if (IS_SI1_BOARD (board)) rc = SX_TYPE_SI;
- if (IS_EISA_BOARD (board)) rc = SX_TYPE_SI;
- sx_dprintk (SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
+ rc = -ENOENT; /* If we manage to miss one, return error. */
+ if (IS_SX_BOARD(board))
+ rc = SX_TYPE_SX;
+ if (IS_CF_BOARD(board))
+ rc = SX_TYPE_CF;
+ if (IS_SI_BOARD(board))
+ rc = SX_TYPE_SI;
+ if (IS_SI1_BOARD(board))
+ rc = SX_TYPE_SI;
+ if (IS_EISA_BOARD(board))
+ rc = SX_TYPE_SI;
+ sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);
break;
case SXIO_DO_RAMTEST:
- if (sx_initialized) /* Already initialized: better not ramtest the board. */
+ if (sx_initialized) /* Already initialized: better not ramtest the board. */
return -EPERM;
- if (IS_SX_BOARD (board)) {
- rc = do_memtest (board, 0, 0x7000);
- if (!rc) rc = do_memtest (board, 0, 0x7000);
- /*if (!rc) rc = do_memtest_w (board, 0, 0x7000);*/
+ if (IS_SX_BOARD(board)) {
+ rc = do_memtest(board, 0, 0x7000);
+ if (!rc)
+ rc = do_memtest(board, 0, 0x7000);
+ /*if (!rc) rc = do_memtest_w (board, 0, 0x7000); */
} else {
- rc = do_memtest (board, 0, 0x7ff8);
+ rc = do_memtest(board, 0, 0x7ff8);
/* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
}
- sx_dprintk (SX_DEBUG_FIRMWARE, "returning memtest result= %d\n", rc);
+ sx_dprintk(SX_DEBUG_FIRMWARE, "returning memtest result= %d\n",
+ rc);
break;
case SXIO_DOWNLOAD:
- if (sx_initialized) /* Already initialized */
+ if (sx_initialized) /* Already initialized */
return -EEXIST;
- if (!sx_reset (board))
+ if (!sx_reset(board))
return -EIO;
- sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
-
- tmp = kmalloc (SX_CHUNK_SIZE, GFP_USER);
- if (!tmp) return -ENOMEM;
- get_user (nbytes, descr++);
- get_user (offset, descr++);
- get_user (data, descr++);
+ sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
+
+ tmp = kmalloc(SX_CHUNK_SIZE, GFP_USER);
+ if (!tmp)
+ return -ENOMEM;
+ get_user(nbytes, descr++);
+ get_user(offset, descr++);
+ get_user(data, descr++);
while (nbytes && data) {
- for (i=0;i<nbytes;i += SX_CHUNK_SIZE) {
- if (copy_from_user(tmp, (char __user *)data+i,
- (i + SX_CHUNK_SIZE >
- nbytes) ? nbytes - i :
- SX_CHUNK_SIZE)) {
- kfree (tmp);
+ for (i = 0; i < nbytes; i += SX_CHUNK_SIZE) {
+ if (copy_from_user(tmp, (char __user *)data + i,
+ (i + SX_CHUNK_SIZE > nbytes) ?
+ nbytes - i : SX_CHUNK_SIZE)) {
+ kfree(tmp);
return -EFAULT;
}
- memcpy_toio(board->base2 + offset + i, tmp,
- (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
+ memcpy_toio(board->base2 + offset + i, tmp,
+ (i + SX_CHUNK_SIZE > nbytes) ?
+ nbytes - i : SX_CHUNK_SIZE);
}
- get_user (nbytes, descr++);
- get_user (offset, descr++);
- get_user (data, descr++);
+ get_user(nbytes, descr++);
+ get_user(offset, descr++);
+ get_user(data, descr++);
}
- kfree (tmp);
- sx_nports += sx_init_board (board);
+ kfree(tmp);
+ sx_nports += sx_init_board(board);
rc = sx_nports;
break;
case SXIO_INIT:
- if (sx_initialized) /* Already initialized */
+ if (sx_initialized) /* Already initialized */
return -EEXIST;
/* This is not allowed until all boards are initialized... */
- for (i=0;i<SX_NBOARDS;i++) {
- if ( (boards[i].flags & SX_BOARD_PRESENT) &&
- !(boards[i].flags & SX_BOARD_INITIALIZED))
+ for (i = 0; i < SX_NBOARDS; i++) {
+ if ((boards[i].flags & SX_BOARD_PRESENT) &&
+ !(boards[i].flags & SX_BOARD_INITIALIZED))
return -EIO;
}
- for (i=0;i<SX_NBOARDS;i++)
- if (!(boards[i].flags & SX_BOARD_PRESENT)) break;
-
- sx_dprintk (SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
- "%d channels, first board: %d ports\n",
- i, sx_nports, boards[0].nports);
- rc = sx_init_portstructs (i, sx_nports);
- sx_init_drivers ();
- if (rc >= 0)
+ for (i = 0; i < SX_NBOARDS; i++)
+ if (!(boards[i].flags & SX_BOARD_PRESENT))
+ break;
+
+ sx_dprintk(SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
+ "%d channels, first board: %d ports\n",
+ i, sx_nports, boards[0].nports);
+ rc = sx_init_portstructs(i, sx_nports);
+ sx_init_drivers();
+ if (rc >= 0)
sx_initialized++;
break;
case SXIO_SETDEBUG:
rc = sx_nports;
break;
default:
- printk (KERN_WARNING "Unknown ioctl on firmware device (%x).\n", cmd);
+ printk(KERN_WARNING "Unknown ioctl on firmware device (%x).\n",
+ cmd);
break;
}
- func_exit ();
+ func_exit();
return rc;
}
-
-static void sx_break (struct tty_struct * tty, int flag)
+static void sx_break(struct tty_struct *tty, int flag)
{
struct sx_port *port = tty->driver_data;
int rv;
- func_enter ();
+ func_enter();
- if (flag)
- rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
- else
- rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
- if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
- read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+ if (flag)
+ rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
+ else
+ rv = sx_send_command(port, HS_STOP, -1, HS_IDLE_OPEN);
+ if (rv != 1)
+ printk(KERN_ERR "sx: couldn't send break (%x).\n",
+ read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
- func_exit ();
+ func_exit();
}
-
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
struct sx_port *port = tty->driver_data;
}
static int sx_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
struct sx_port *port = tty->driver_data;
int rts = -1, dtr = -1;
return 0;
}
-static int sx_ioctl (struct tty_struct * tty, struct file * filp,
- unsigned int cmd, unsigned long arg)
+static int sx_ioctl(struct tty_struct *tty, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
int rc;
struct sx_port *port = tty->driver_data;
switch (cmd) {
case TIOCGSOFTCAR:
rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) argp);
+ (unsigned __user *)argp);
break;
case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *) argp)) == 0) {
+ if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) {
tty->termios->c_cflag =
(tty->termios->c_cflag & ~CLOCAL) |
(ival ? CLOCAL : 0);
return rc;
}
-
/* The throttle/unthrottle scheme for the Specialix card is different
* from other drivers and deserves some explanation.
* The Specialix hardware takes care of XON/XOFF
* flow control scheme is in use for that port. -- Simon Allen
*/
-static void sx_throttle (struct tty_struct * tty)
+static void sx_throttle(struct tty_struct *tty)
{
struct sx_port *port = (struct sx_port *)tty->driver_data;
/* If the port is using any type of input flow
* control then throttle the port.
*/
- if((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) {
+ if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
port->gs.flags |= SX_RX_THROTTLE;
}
func_exit();
}
-
-static void sx_unthrottle (struct tty_struct * tty)
+static void sx_unthrottle(struct tty_struct *tty)
{
struct sx_port *port = (struct sx_port *)tty->driver_data;
return;
}
-
/* ********************************************************************** *
* Here are the initialization routines. *
* ********************************************************************** */
-
-
-
-static int sx_init_board (struct sx_board *board)
+static int sx_init_board(struct sx_board *board)
{
int addr;
int chans;
board->flags |= SX_BOARD_INITIALIZED;
- if (read_sx_byte (board, 0))
+ if (read_sx_byte(board, 0))
/* CF boards may need this. */
- write_sx_byte(board,0, 0);
+ write_sx_byte(board, 0, 0);
/* This resets the processor again, to make sure it didn't do any
foolish things while we were downloading the image */
- if (!sx_reset (board))
+ if (!sx_reset(board))
return 0;
- sx_start_board (board);
- udelay (10);
- if (!sx_busy_wait_neq (board, 0, 0xff, 0)) {
- printk (KERN_ERR "sx: Ooops. Board won't initialize.\n");
+ sx_start_board(board);
+ udelay(10);
+ if (!sx_busy_wait_neq(board, 0, 0xff, 0)) {
+ printk(KERN_ERR "sx: Ooops. Board won't initialize.\n");
return 0;
}
/* Ok. So now the processor on the card is running. It gathered
some info for us... */
- sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n");
- if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base, 0x10);
- sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n");
- if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base + 0x80, 0x30);
-
- sx_dprintk (SX_DEBUG_INIT,
- "init_status: %x, %dk memory, firmware V%x.%02x,\n",
- read_sx_byte (board, 0), read_sx_byte(board, 1),
- read_sx_byte (board, 5), read_sx_byte(board, 4));
-
- if (read_sx_byte (board, 0) == 0xff) {
- printk (KERN_INFO "sx: No modules found. Sorry.\n");
+ sx_dprintk(SX_DEBUG_INIT, "The sxcard structure:\n");
+ if (sx_debug & SX_DEBUG_INIT)
+ my_hd_io(board->base, 0x10);
+ sx_dprintk(SX_DEBUG_INIT, "the first sx_module structure:\n");
+ if (sx_debug & SX_DEBUG_INIT)
+ my_hd_io(board->base + 0x80, 0x30);
+
+ sx_dprintk(SX_DEBUG_INIT, "init_status: %x, %dk memory, firmware "
+ "V%x.%02x,\n",
+ read_sx_byte(board, 0), read_sx_byte(board, 1),
+ read_sx_byte(board, 5), read_sx_byte(board, 4));
+
+ if (read_sx_byte(board, 0) == 0xff) {
+ printk(KERN_INFO "sx: No modules found. Sorry.\n");
board->nports = 0;
return 0;
}
chans = 0;
if (IS_SX_BOARD(board)) {
- sx_write_board_word (board, cc_int_count, sx_maxints);
+ sx_write_board_word(board, cc_int_count, sx_maxints);
} else {
if (sx_maxints)
- sx_write_board_word (board, cc_int_count, SI_PROCESSOR_CLOCK/8/sx_maxints);
+ sx_write_board_word(board, cc_int_count,
+ SI_PROCESSOR_CLOCK / 8 / sx_maxints);
}
/* grab the first module type... */
- /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
- board->ta_type = mod_compat_type (sx_read_module_byte (board, 0x80, mc_chip));
+ /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
+ board->ta_type = mod_compat_type(sx_read_module_byte(board, 0x80,
+ mc_chip));
/* XXX byteorder */
- for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
- type = sx_read_module_byte (board, addr, mc_chip);
- sx_dprintk (SX_DEBUG_INIT, "Module at %x: %d channels\n",
- addr, read_sx_byte (board, addr + 2));
-
- chans += sx_read_module_byte (board, addr, mc_type);
-
- sx_dprintk (SX_DEBUG_INIT, "module is an %s, which has %s/%s panels\n",
- mod_type_s (type),
- pan_type_s (sx_read_module_byte (board, addr, mc_mods) & 0xf),
- pan_type_s (sx_read_module_byte (board, addr, mc_mods) >> 4));
-
- sx_dprintk (SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC version: %x\n",
- sx_read_module_byte (board, addr, mc_rev1),
- sx_read_module_byte (board, addr, mc_rev2),
- sx_read_module_byte (board, addr, mc_mtaasic_rev));
+ for (addr = 0x80; addr != 0; addr = read_sx_word(board, addr) & 0x7fff){
+ type = sx_read_module_byte(board, addr, mc_chip);
+ sx_dprintk(SX_DEBUG_INIT, "Module at %x: %d channels\n",
+ addr, read_sx_byte(board, addr + 2));
+
+ chans += sx_read_module_byte(board, addr, mc_type);
+
+ sx_dprintk(SX_DEBUG_INIT, "module is an %s, which has %s/%s "
+ "panels\n",
+ mod_type_s(type),
+ pan_type_s(sx_read_module_byte(board, addr,
+ mc_mods) & 0xf),
+ pan_type_s(sx_read_module_byte(board, addr,
+ mc_mods) >> 4));
+
+ sx_dprintk(SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC "
+ "version: %x\n",
+ sx_read_module_byte(board, addr, mc_rev1),
+ sx_read_module_byte(board, addr, mc_rev2),
+ sx_read_module_byte(board, addr, mc_mtaasic_rev));
/* The following combinations are illegal: It should theoretically
work, but timing problems make the bus HANG. */
- if (mod_compat_type (type) != board->ta_type) {
- printk (KERN_ERR "sx: This is an invalid configuration.\n"
- "Don't mix TA/MTA/SXDC on the same hostadapter.\n");
- chans=0;
+ if (mod_compat_type(type) != board->ta_type) {
+ printk(KERN_ERR "sx: This is an invalid "
+ "configuration.\nDon't mix TA/MTA/SXDC on the "
+ "same hostadapter.\n");
+ chans = 0;
break;
}
- if ((IS_EISA_BOARD(board) ||
- IS_SI_BOARD(board)) && (mod_compat_type(type) == 4)) {
- printk (KERN_ERR "sx: This is an invalid configuration.\n"
- "Don't use SXDCs on an SI/XIO adapter.\n");
- chans=0;
+ if ((IS_EISA_BOARD(board) ||
+ IS_SI_BOARD(board)) &&
+ (mod_compat_type(type) == 4)) {
+ printk(KERN_ERR "sx: This is an invalid "
+ "configuration.\nDon't use SXDCs on an SI/XIO "
+ "adapter.\n");
+ chans = 0;
break;
}
-#if 0 /* Problem fixed: firmware 3.05 */
+#if 0 /* Problem fixed: firmware 3.05 */
if (IS_SX_BOARD(board) && (type == TA8)) {
/* There are some issues with the firmware and the DCD/RTS
lines. It might work if you tie them together or something.
- It might also work if you get a newer sx_firmware. Therefore
+ It might also work if you get a newer sx_firmware. Therefore
this is just a warning. */
- printk (KERN_WARNING "sx: The SX host doesn't work too well "
- "with the TA8 adapters.\nSpecialix is working on it.\n");
+ printk(KERN_WARNING
+ "sx: The SX host doesn't work too well "
+ "with the TA8 adapters.\nSpecialix is working on it.\n");
}
#endif
}
if (chans) {
- /* board->flags |= SX_BOARD_PRESENT; */
- if(board->irq > 0) {
+ if (board->irq > 0) {
/* fixed irq, probably PCI */
- if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
- if(request_irq(board->irq, sx_interrupt, IRQF_SHARED | IRQF_DISABLED, "sx", board)) {
- printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq);
+ if (sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
+ if (request_irq(board->irq, sx_interrupt,
+ IRQF_SHARED | IRQF_DISABLED,
+ "sx", board)) {
+ printk(KERN_ERR "sx: Cannot allocate "
+ "irq %d.\n", board->irq);
board->irq = 0;
}
} else
board->irq = 0;
- } else if(board->irq < 0 && sx_irqmask) {
+ } else if (board->irq < 0 && sx_irqmask) {
/* auto-allocate irq */
int irqnr;
- int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
- for(irqnr = 15; irqnr > 0; irqnr--)
- if(irqmask & (1 << irqnr))
- if(! request_irq(irqnr, sx_interrupt, IRQF_SHARED | IRQF_DISABLED, "sx", board))
+ int irqmask = sx_irqmask & (IS_SX_BOARD(board) ?
+ SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
+ for (irqnr = 15; irqnr > 0; irqnr--)
+ if (irqmask & (1 << irqnr))
+ if (!request_irq(irqnr, sx_interrupt,
+ IRQF_SHARED | IRQF_DISABLED,
+ "sx", board))
break;
- if(! irqnr)
+ if (!irqnr)
printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
board->irq = irqnr;
} else
if (board->irq) {
/* Found a valid interrupt, start up interrupts! */
- sx_dprintk (SX_DEBUG_INIT, "Using irq %d.\n", board->irq);
- sx_start_interrupts (board);
+ sx_dprintk(SX_DEBUG_INIT, "Using irq %d.\n",
+ board->irq);
+ sx_start_interrupts(board);
board->poll = sx_slowpoll;
board->flags |= SX_IRQ_ALLOCATED;
} else {
/* no irq: setup board for polled operation */
board->poll = sx_poll;
- sx_dprintk (SX_DEBUG_INIT, "Using poll-interval %d.\n", board->poll);
+ sx_dprintk(SX_DEBUG_INIT, "Using poll-interval %d.\n",
+ board->poll);
}
- /* The timer should be initialized anyway: That way we can safely
- del_timer it when the module is unloaded. */
- init_timer (&board->timer);
+ /* The timer should be initialized anyway: That way we can
+ safely del_timer it when the module is unloaded. */
+ setup_timer(&board->timer, sx_pollfunc, (unsigned long)board);
- if (board->poll) {
- board->timer.data = (unsigned long) board;
- board->timer.function = sx_pollfunc;
- board->timer.expires = jiffies + board->poll;
- add_timer (&board->timer);
- }
+ if (board->poll)
+ mod_timer(&board->timer, jiffies + board->poll);
} else {
board->irq = 0;
}
board->nports = chans;
- sx_dprintk (SX_DEBUG_INIT, "returning %d ports.", board->nports);
+ sx_dprintk(SX_DEBUG_INIT, "returning %d ports.", board->nports);
func_exit();
return chans;
}
-
-static void printheader(void)
+static void __devinit printheader(void)
{
static int header_printed;
if (!header_printed) {
- printk (KERN_INFO "Specialix SX driver "
- "(C) 1998/1999 R.E.Wolff@BitWizard.nl \n");
- printk (KERN_INFO "sx: version %s\n", RCS_ID);
+ printk(KERN_INFO "Specialix SX driver "
+ "(C) 1998/1999 R.E.Wolff@BitWizard.nl\n");
+ printk(KERN_INFO "sx: version " __stringify(SX_VERSION) "\n");
header_printed = 1;
}
}
-
-static int probe_sx (struct sx_board *board)
+static int __devinit probe_sx(struct sx_board *board)
{
struct vpd_prom vpdp;
char *p;
func_enter();
- if (!IS_CF_BOARD (board)) {
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
- board->base + SX_VPD_ROM);
+ if (!IS_CF_BOARD(board)) {
+ sx_dprintk(SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
+ board->base + SX_VPD_ROM);
if (sx_debug & SX_DEBUG_PROBE)
my_hd_io(board->base + SX_VPD_ROM, 0x40);
- p = (char *) &vpdp;
- for (i=0;i< sizeof (struct vpd_prom);i++)
- *p++ = read_sx_byte (board, SX_VPD_ROM + i*2);
+ p = (char *)&vpdp;
+ for (i = 0; i < sizeof(struct vpd_prom); i++)
+ *p++ = read_sx_byte(board, SX_VPD_ROM + i * 2);
if (sx_debug & SX_DEBUG_PROBE)
- my_hd (&vpdp, 0x20);
+ my_hd(&vpdp, 0x20);
- sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n");
+ sx_dprintk(SX_DEBUG_PROBE, "checking identifier...\n");
- if (strncmp (vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
- sx_dprintk (SX_DEBUG_PROBE, "Got non-SX identifier: '%s'\n",
- vpdp.identifier);
+ if (strncmp(vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
+ sx_dprintk(SX_DEBUG_PROBE, "Got non-SX identifier: "
+ "'%s'\n", vpdp.identifier);
return 0;
}
}
- printheader ();
-
- if (!IS_CF_BOARD (board)) {
- printk (KERN_DEBUG "sx: Found an SX board at %lx\n", board->hw_base);
- printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ",
- vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
- printk ( "Manufactured: %d/%d\n",
- 1970 + vpdp.myear, vpdp.mweek);
+ printheader();
+ if (!IS_CF_BOARD(board)) {
+ printk(KERN_DEBUG "sx: Found an SX board at %lx\n",
+ board->hw_base);
+ printk(KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, "
+ "uniq ID:%08x, ",
+ vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
+ printk("Manufactured: %d/%d\n", 1970 + vpdp.myear, vpdp.mweek);
- if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_PCI_UNIQUEID1) &&
- (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
- /* This might be a bit harsh. This was the primary reason the
- SX/ISA card didn't work at first... */
- printk (KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA card. Sorry: giving up.\n");
+ if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) !=
+ SX_PCI_UNIQUEID1) && (((vpdp.uniqid >> 24) &
+ SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
+ /* This might be a bit harsh. This was the primary
+ reason the SX/ISA card didn't work at first... */
+ printk(KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA "
+ "card. Sorry: giving up.\n");
return (0);
}
- if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
+ if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) ==
+ SX_ISA_UNIQUEID1) {
if (((unsigned long)board->hw_base) & 0x8000) {
- printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->hw_base);
- printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
+ printk(KERN_WARNING "sx: Warning: There may be "
+ "hardware problems with the card at "
+ "%lx.\n", board->hw_base);
+ printk(KERN_WARNING "sx: Read sx.txt for more "
+ "info.\n");
}
}
}
board->nports = -1;
/* This resets the processor, and keeps it off the bus. */
- if (!sx_reset (board))
+ if (!sx_reset(board))
return 0;
- sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
-
- board->flags |= SX_BOARD_PRESENT;
+ sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
func_exit();
return 1;
}
-
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
/* Specialix probes for this card at 32k increments from 640k to 16M.
I consider machines with less than 16M unlikely nowadays, so I'm
card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves
0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
-static int probe_si (struct sx_board *board)
+static int __devinit probe_si(struct sx_board *board)
{
int i;
func_enter();
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %p.\n", board->hw_base,
- board->base + SI2_ISA_ID_BASE);
+ sx_dprintk(SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at "
+ "%p.\n", board->hw_base, board->base + SI2_ISA_ID_BASE);
if (sx_debug & SX_DEBUG_PROBE)
my_hd_io(board->base + SI2_ISA_ID_BASE, 0x8);
if (!IS_EISA_BOARD(board)) {
- if( IS_SI1_BOARD(board) )
- {
- for (i=0;i<8;i++) {
- write_sx_byte (board, SI2_ISA_ID_BASE+7-i,i);
-
+ if (IS_SI1_BOARD(board)) {
+ for (i = 0; i < 8; i++) {
+ write_sx_byte(board, SI2_ISA_ID_BASE + 7 - i,i);
+ }
}
- }
- for (i=0;i<8;i++) {
- if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) {
- func_exit ();
+ for (i = 0; i < 8; i++) {
+ if ((read_sx_byte(board, SI2_ISA_ID_BASE + 7 - i) & 7)
+ != i) {
+ func_exit();
return 0;
}
}
but to prevent trouble, we'd better double check that we don't
have an SI1 board when we're probing for an SI2 board.... */
- write_sx_byte (board, SI2_ISA_ID_BASE,0x10);
- if ( IS_SI1_BOARD(board)) {
+ write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
+ if (IS_SI1_BOARD(board)) {
/* This should be an SI1 board, which has this
location writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) {
- func_exit ();
- return 0;
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
+ func_exit();
+ return 0;
}
} else {
/* This should be an SI2 board, which has the bottom
3 bits non-writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) {
- func_exit ();
- return 0;
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
+ func_exit();
+ return 0;
}
}
but to prevent trouble, we'd better double check that we don't
have an SI1 board when we're probing for an SI2 board.... */
- write_sx_byte (board, SI2_ISA_ID_BASE,0x10);
- if ( IS_SI1_BOARD(board)) {
+ write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
+ if (IS_SI1_BOARD(board)) {
/* This should be an SI1 board, which has this
location writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) {
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
func_exit();
- return 0;
+ return 0;
}
} else {
/* This should be an SI2 board, which has the bottom
3 bits non-writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) {
- func_exit ();
- return 0;
+ if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
+ func_exit();
+ return 0;
}
}
- printheader ();
+ printheader();
- printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
+ printk(KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
/* Compared to the SX boards, it is a complete guess as to what
- this card is up to... */
+ this card is up to... */
board->nports = -1;
/* This resets the processor, and keeps it off the bus. */
- if (!sx_reset (board))
+ if (!sx_reset(board))
return 0;
- sx_dprintk (SX_DEBUG_INIT, "reset the board...\n");
-
- board->flags |= SX_BOARD_PRESENT;
+ sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
func_exit();
return 1;
}
+#endif
static const struct tty_operations sx_ops = {
.break_ctl = sx_break,
- .open = sx_open,
+ .open = sx_open,
.close = gs_close,
.write = gs_write,
.put_char = gs_put_char,
sx_driver->type = TTY_DRIVER_TYPE_SERIAL;
sx_driver->subtype = SERIAL_TYPE_NORMAL;
sx_driver->init_termios = tty_std_termios;
- sx_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ sx_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ sx_driver->init_termios.c_ispeed = 9600;
+ sx_driver->init_termios.c_ospeed = 9600;
sx_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(sx_driver, &sx_ops);
if ((error = tty_register_driver(sx_driver))) {
put_tty_driver(sx_driver);
printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
- error);
+ error);
return 1;
}
func_exit();
return 0;
}
-
-static void * ckmalloc (int size)
-{
- void *p;
-
- p = kmalloc(size, GFP_KERNEL);
- if (p)
- memset(p, 0, size);
- return p;
-}
-
-
-static int sx_init_portstructs (int nboards, int nports)
+static int sx_init_portstructs(int nboards, int nports)
{
struct sx_board *board;
struct sx_port *port;
func_enter();
/* Many drivers statically allocate the maximum number of ports
- There is no reason not to allocate them dynamically. Is there? -- REW */
- sx_ports = ckmalloc(nports * sizeof (struct sx_port));
+ There is no reason not to allocate them dynamically.
+ Is there? -- REW */
+ sx_ports = kcalloc(nports, sizeof(struct sx_port), GFP_KERNEL);
if (!sx_ports)
return -ENOMEM;
for (i = 0; i < nboards; i++) {
board = &boards[i];
board->ports = port;
- for (j=0; j < boards[i].nports;j++) {
- sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j);
+ for (j = 0; j < boards[i].nports; j++) {
+ sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
port->gs.magic = SX_MAGIC;
- port->gs.close_delay = HZ/2;
+ port->gs.close_delay = HZ / 2;
port->gs.closing_wait = 30 * HZ;
port->board = board;
port->gs.rd = &sx_real_driver;
* Initializing wait queue
*/
init_waitqueue_head(&port->gs.open_wait);
- init_waitqueue_head(&port->gs.close_wait);
-
+ init_waitqueue_head(&port->gs.close_wait);
+
port++;
}
}
board = &boards[i];
board->port_base = portno;
/* Possibly the configuration was rejected. */
- sx_dprintk (SX_DEBUG_PROBE, "Board has %d channels\n", board->nports);
- if (board->nports <= 0) continue;
+ sx_dprintk(SX_DEBUG_PROBE, "Board has %d channels\n",
+ board->nports);
+ if (board->nports <= 0)
+ continue;
/* XXX byteorder ?? */
- for (addr = 0x80;addr != 0;addr = read_sx_word (board, addr) & 0x7fff) {
- chans = sx_read_module_byte (board, addr, mc_type);
- sx_dprintk (SX_DEBUG_PROBE, "Module at %x: %d channels\n", addr, chans);
- sx_dprintk (SX_DEBUG_PROBE, "Port at");
- for (j=0;j<chans;j++) {
- /* The "sx-way" is the way it SHOULD be done. That way in the
- future, the firmware may for example pack the structures a bit
- more efficient. Neil tells me it isn't going to happen anytime
- soon though. */
+ for (addr = 0x80; addr != 0;
+ addr = read_sx_word(board, addr) & 0x7fff) {
+ chans = sx_read_module_byte(board, addr, mc_type);
+ sx_dprintk(SX_DEBUG_PROBE, "Module at %x: %d "
+ "channels\n", addr, chans);
+ sx_dprintk(SX_DEBUG_PROBE, "Port at");
+ for (j = 0; j < chans; j++) {
+ /* The "sx-way" is the way it SHOULD be done.
+ That way in the future, the firmware may for
+ example pack the structures a bit more
+ efficient. Neil tells me it isn't going to
+ happen anytime soon though. */
if (IS_SX_BOARD(board))
- port->ch_base = sx_read_module_word (board, addr+j*2, mc_chan_pointer);
+ port->ch_base = sx_read_module_word(
+ board, addr + j * 2,
+ mc_chan_pointer);
else
- port->ch_base = addr + 0x100 + 0x300*j;
+ port->ch_base = addr + 0x100 + 0x300 *j;
- sx_dprintk (SX_DEBUG_PROBE, " %x", port->ch_base);
+ sx_dprintk(SX_DEBUG_PROBE, " %x",
+ port->ch_base);
port->line = portno++;
port++;
}
- sx_dprintk (SX_DEBUG_PROBE, "\n");
+ sx_dprintk(SX_DEBUG_PROBE, "\n");
}
/* This has to be done earlier. */
/* board->flags |= SX_BOARD_INITIALIZED; */
return 0;
}
+static unsigned int sx_find_free_board(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < SX_NBOARDS; i++)
+ if (!(boards[i].flags & SX_BOARD_PRESENT))
+ break;
+
+ return i;
+}
+
static void __exit sx_release_drivers(void)
{
func_enter();
func_exit();
}
-#ifdef CONFIG_PCI
+static void __devexit sx_remove_card(struct sx_board *board,
+ struct pci_dev *pdev)
+{
+ if (board->flags & SX_BOARD_INITIALIZED) {
+ /* The board should stop messing with us. (actually I mean the
+ interrupt) */
+ sx_reset(board);
+ if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
+ free_irq(board->irq, board);
+
+ /* It is safe/allowed to del_timer a non-active timer */
+ del_timer(&board->timer);
+ if (pdev) {
+ pci_iounmap(pdev, board->base);
+ pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
+ } else {
+ iounmap(board->base);
+ release_region(board->hw_base, board->hw_len);
+ }
+
+ board->flags &= ~(SX_BOARD_INITIALIZED | SX_BOARD_PRESENT);
+ }
+}
+
+#ifdef CONFIG_EISA
+
+static int __devinit sx_eisa_probe(struct device *dev)
+{
+ struct eisa_device *edev = to_eisa_device(dev);
+ struct sx_board *board;
+ unsigned long eisa_slot = edev->base_addr;
+ unsigned int i;
+ int retval = -EIO;
+
+ mutex_lock(&sx_boards_lock);
+ i = sx_find_free_board();
+ if (i == SX_NBOARDS) {
+ mutex_unlock(&sx_boards_lock);
+ goto err;
+ }
+ board = &boards[i];
+ board->flags |= SX_BOARD_PRESENT;
+ mutex_unlock(&sx_boards_lock);
+
+ dev_info(dev, "XIO : Signature found in EISA slot %lu, "
+ "Product %d Rev %d (REPORT THIS TO LKLM)\n",
+ eisa_slot >> 12,
+ inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 2),
+ inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 3));
+
+ board->eisa_base = eisa_slot;
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= SI_EISA_BOARD;
+
+ board->hw_base = ((inb(eisa_slot + 0xc01) << 8) +
+ inb(eisa_slot + 0xc00)) << 16;
+ board->hw_len = SI2_EISA_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx")) {
+ dev_err(dev, "can't request region\n");
+ goto err_flag;
+ }
+ board->base2 =
+ board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+ if (!board->base) {
+ dev_err(dev, "can't remap memory\n");
+ goto err_reg;
+ }
+
+ sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+ sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
+ board->irq = inb(eisa_slot + 0xc02) >> 4;
+ sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
+
+ if (!probe_si(board))
+ goto err_unmap;
+
+ dev_set_drvdata(dev, board);
+
+ return 0;
+err_unmap:
+ iounmap(board->base);
+err_reg:
+ release_region(board->hw_base, board->hw_len);
+err_flag:
+ board->flags &= ~SX_BOARD_PRESENT;
+err:
+ return retval;
+}
+
+static int __devexit sx_eisa_remove(struct device *dev)
+{
+ struct sx_board *board = dev_get_drvdata(dev);
+
+ sx_remove_card(board, NULL);
+
+ return 0;
+}
+
+static struct eisa_device_id sx_eisa_tbl[] = {
+ { "SLX" },
+ { "" }
+};
+
+MODULE_DEVICE_TABLE(eisa, sx_eisa_tbl);
+
+static struct eisa_driver sx_eisadriver = {
+ .id_table = sx_eisa_tbl,
+ .driver = {
+ .name = "sx",
+ .probe = sx_eisa_probe,
+ .remove = __devexit_p(sx_eisa_remove),
+ }
+};
+
+#endif
+
/********************************************************
* Setting bit 17 in the CNTRL register of the PLX 9050 *
* chip forces a retry on writes while a read is pending.*
EEprom. As the bit is read/write for the CPU, we can fix it here,
if we detect that it isn't set correctly. -- REW */
-static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
+static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
{
unsigned int hwbase;
void __iomem *rebase;
unsigned int t;
-#define CNTRL_REG_OFFSET 0x50
-#define CNTRL_REG_GOODVALUE 0x18260000
+#define CNTRL_REG_OFFSET 0x50
+#define CNTRL_REG_GOODVALUE 0x18260000
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
rebase = ioremap(hwbase, 0x80);
- t = readl (rebase + CNTRL_REG_OFFSET);
+ t = readl(rebase + CNTRL_REG_OFFSET);
if (t != CNTRL_REG_GOODVALUE) {
- printk (KERN_DEBUG "sx: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE);
- writel (CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
+ printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
+ "%08x\n", t, CNTRL_REG_GOODVALUE);
+ writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
}
iounmap(rebase);
}
-#endif
-
-static int __init sx_init(void)
+static int __devinit sx_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int i;
- int found = 0;
- int eisa_slot;
struct sx_board *board;
+ unsigned int i, reg;
+ int retval = -EIO;
-#ifdef CONFIG_PCI
- struct pci_dev *pdev = NULL;
- unsigned int tint;
- unsigned short tshort;
-#endif
+ mutex_lock(&sx_boards_lock);
+ i = sx_find_free_board();
+ if (i == SX_NBOARDS) {
+ mutex_unlock(&sx_boards_lock);
+ goto err;
+ }
+ board = &boards[i];
+ board->flags |= SX_BOARD_PRESENT;
+ mutex_unlock(&sx_boards_lock);
- func_enter();
- sx_dprintk (SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n", sx_debug);
- if (abs ((long) (&sx_debug) - sx_debug) < 0x10000) {
- printk (KERN_WARNING "sx: sx_debug is an address, instead of a value. "
- "Assuming -1.\n");
- printk ("(%p)\n", &sx_debug);
- sx_debug=-1;
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err_flag;
+
+ board->flags &= ~SX_BOARD_TYPE;
+ board->flags |= (pdev->subsystem_vendor == 0x200) ? SX_PCI_BOARD :
+ SX_CFPCI_BOARD;
+
+ /* CF boards use base address 3.... */
+ reg = IS_CF_BOARD(board) ? 3 : 2;
+ retval = pci_request_region(pdev, reg, "sx");
+ if (retval) {
+ dev_err(&pdev->dev, "can't request region\n");
+ goto err_flag;
+ }
+ board->hw_base = pci_resource_start(pdev, reg);
+ board->base2 =
+ board->base = pci_iomap(pdev, reg, WINDOW_LEN(board));
+ if (!board->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err_reg;
}
- if (misc_register(&sx_fw_device) < 0) {
- printk(KERN_ERR "SX: Unable to register firmware loader driver.\n");
- return -EIO;
+ /* Most of the stuff on the CF board is offset by 0x18000 .... */
+ if (IS_CF_BOARD(board))
+ board->base += 0x18000;
+
+ board->irq = pdev->irq;
+
+ dev_info(&pdev->dev, "Got a specialix card: %p(%d) %x.\n", board->base,
+ board->irq, board->flags);
+
+ if (!probe_sx(board)) {
+ retval = -EIO;
+ goto err_unmap;
}
-#ifdef CONFIG_PCI
- while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
- PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
- pdev))) {
- if (pci_enable_device(pdev))
- continue;
+ fix_sx_pci(pdev, board);
- /* Specialix has a whole bunch of cards with
- 0x2000 as the device ID. They say its because
- the standard requires it. Stupid standard. */
- /* It seems that reading a word doesn't work reliably on 2.0.
- Also, reading a non-aligned dword doesn't work. So we read the
- whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
- ourselves */
- /* I don't know why the define doesn't work, constant 0x2c does --REW */
- pci_read_config_dword (pdev, 0x2c, &tint);
- tshort = (tint >> 16) & 0xffff;
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
- /* sx_dprintk (SX_DEBUG_PROBE, "pdev = %d/%d (%x)\n", pdev, tint); */
- if ((tshort != 0x0200) && (tshort != 0x0300)) {
- sx_dprintk (SX_DEBUG_PROBE, "But it's not an SX card (%d)...\n",
- tshort);
- continue;
- }
- board = &boards[found];
+ pci_set_drvdata(pdev, board);
- board->flags &= ~SX_BOARD_TYPE;
- board->flags |= (tshort == 0x200)?SX_PCI_BOARD:
- SX_CFPCI_BOARD;
-
- /* CF boards use base address 3.... */
- if (IS_CF_BOARD (board))
- board->hw_base = pci_resource_start (pdev, 3);
- else
- board->hw_base = pci_resource_start (pdev, 2);
- board->base2 =
- board->base = ioremap(board->hw_base, WINDOW_LEN (board));
- if (!board->base) {
- printk(KERN_ERR "ioremap failed\n");
- /* XXX handle error */
- }
+ return 0;
+err_unmap:
+ pci_iounmap(pdev, board->base);
+err_reg:
+ pci_release_region(pdev, reg);
+err_flag:
+ board->flags &= ~SX_BOARD_PRESENT;
+err:
+ return retval;
+}
- /* Most of the stuff on the CF board is offset by
- 0x18000 .... */
- if (IS_CF_BOARD (board)) board->base += 0x18000;
+static void __devexit sx_pci_remove(struct pci_dev *pdev)
+{
+ struct sx_board *board = pci_get_drvdata(pdev);
- board->irq = pdev->irq;
+ sx_remove_card(board, pdev);
+}
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%p(%d) %x.\n",
- tint, boards[found].base, board->irq, board->flags);
+/* Specialix has a whole bunch of cards with 0x2000 as the device ID. They say
+ its because the standard requires it. So check for SUBVENDOR_ID. */
+static struct pci_device_id sx_pci_tbl[] = {
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ .subvendor = 0x0200,.subdevice = PCI_ANY_ID },
+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+ .subvendor = 0x0300,.subdevice = PCI_ANY_ID },
+ { 0 }
+};
- if (probe_sx (board)) {
- found++;
- fix_sx_pci (pdev, board);
- } else
- iounmap(board->base2);
- }
+MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
+
+static struct pci_driver sx_pcidriver = {
+ .name = "sx",
+ .id_table = sx_pci_tbl,
+ .probe = sx_pci_probe,
+ .remove = __devexit_p(sx_pci_remove)
+};
+
+static int __init sx_init(void)
+{
+#ifdef CONFIG_EISA
+ int retval1;
#endif
+#ifdef CONFIG_ISA
+ struct sx_board *board;
+ unsigned int i;
+#endif
+ unsigned int found = 0;
+ int retval;
+
+ func_enter();
+ sx_dprintk(SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n",
+ sx_debug);
+ if (abs((long)(&sx_debug) - sx_debug) < 0x10000) {
+ printk(KERN_WARNING "sx: sx_debug is an address, instead of a "
+ "value. Assuming -1.\n(%p)\n", &sx_debug);
+ sx_debug = -1;
+ }
- for (i=0;i<NR_SX_ADDRS;i++) {
+ if (misc_register(&sx_fw_device) < 0) {
+ printk(KERN_ERR "SX: Unable to register firmware loader "
+ "driver.\n");
+ return -EIO;
+ }
+#ifdef CONFIG_ISA
+ for (i = 0; i < NR_SX_ADDRS; i++) {
board = &boards[found];
board->hw_base = sx_probe_addrs[i];
+ board->hw_len = SX_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx"))
+ continue;
board->base2 =
- board->base = ioremap(board->hw_base, SX_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, board->hw_len);
+ if (!board->base)
+ goto err_sx_reg;
board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SX_ISA_BOARD;
- board->irq = sx_irqmask?-1:0;
+ board->flags |= SX_ISA_BOARD;
+ board->irq = sx_irqmask ? -1 : 0;
- if (probe_sx (board)) {
+ if (probe_sx(board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
iounmap(board->base);
+err_sx_reg:
+ release_region(board->hw_base, board->hw_len);
}
}
- for (i=0;i<NR_SI_ADDRS;i++) {
+ for (i = 0; i < NR_SI_ADDRS; i++) {
board = &boards[found];
board->hw_base = si_probe_addrs[i];
+ board->hw_len = SI2_ISA_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx"))
+ continue;
board->base2 =
- board->base = ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, board->hw_len);
+ if (!board->base)
+ goto err_si_reg;
board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI_ISA_BOARD;
- board->irq = sx_irqmask ?-1:0;
+ board->flags |= SI_ISA_BOARD;
+ board->irq = sx_irqmask ? -1 : 0;
- if (probe_si (board)) {
+ if (probe_si(board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
- iounmap (board->base);
+ iounmap(board->base);
+err_si_reg:
+ release_region(board->hw_base, board->hw_len);
}
}
- for (i=0;i<NR_SI1_ADDRS;i++) {
+ for (i = 0; i < NR_SI1_ADDRS; i++) {
board = &boards[found];
board->hw_base = si1_probe_addrs[i];
+ board->hw_len = SI1_ISA_WINDOW_LEN;
+ if (!request_region(board->hw_base, board->hw_len, "sx"))
+ continue;
board->base2 =
- board->base = ioremap(board->hw_base, SI1_ISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, board->hw_len);
+ if (!board->base)
+ goto err_si1_reg;
board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI1_ISA_BOARD;
- board->irq = sx_irqmask ?-1:0;
+ board->flags |= SI1_ISA_BOARD;
+ board->irq = sx_irqmask ? -1 : 0;
- if (probe_si (board)) {
+ if (probe_si(board)) {
+ board->flags |= SX_BOARD_PRESENT;
found++;
} else {
- iounmap (board->base);
+ iounmap(board->base);
+err_si1_reg:
+ release_region(board->hw_base, board->hw_len);
}
}
+#endif
+#ifdef CONFIG_EISA
+ retval1 = eisa_driver_register(&sx_eisadriver);
+#endif
+ retval = pci_register_driver(&sx_pcidriver);
- sx_dprintk(SX_DEBUG_PROBE, "Probing for EISA cards\n");
- for(eisa_slot=0x1000; eisa_slot<0x10000; eisa_slot+=0x1000)
- {
- if((inb(eisa_slot+0xc80)==0x4d) &&
- (inb(eisa_slot+0xc81)==0x98))
- {
- sx_dprintk(SX_DEBUG_PROBE, "%s : Signature found in EISA slot %d, Product %d Rev %d\n",
- "XIO", (eisa_slot>>12), inb(eisa_slot+0xc82), inb(eisa_slot+0xc83));
-
- board = &boards[found];
- board->eisa_base = eisa_slot;
- board->flags &= ~SX_BOARD_TYPE;
- board->flags |= SI_EISA_BOARD;
-
- board->hw_base = (((inb(0xc01+eisa_slot) << 8) + inb(0xc00+eisa_slot)) << 16);
- board->base2 =
- board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
-
- sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
- sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
- board->irq = inb(board->eisa_base+0xc02)>>4;
- sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
-
- probe_si(board);
-
- found++;
- }
- }
if (found) {
- printk (KERN_INFO "sx: total of %d boards detected.\n", found);
- } else {
- misc_deregister(&sx_fw_device);
+ printk(KERN_INFO "sx: total of %d boards detected.\n", found);
+ retval = 0;
+ } else if (retval) {
+#ifdef CONFIG_EISA
+ retval = retval1;
+ if (retval1)
+#endif
+ misc_deregister(&sx_fw_device);
}
func_exit();
- return found?0:-EIO;
+ return retval;
}
-
-static void __exit sx_exit (void)
+static void __exit sx_exit(void)
{
- int i;
- struct sx_board *board;
+ int i;
func_enter();
- for (i = 0; i < SX_NBOARDS; i++) {
- board = &boards[i];
- if (board->flags & SX_BOARD_INITIALIZED) {
- sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %p\n", board->base);
- /* The board should stop messing with us.
- (actually I mean the interrupt) */
- sx_reset (board);
- if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
- free_irq (board->irq, board);
-
- /* It is safe/allowed to del_timer a non-active timer */
- del_timer (& board->timer);
- iounmap(board->base);
- }
- }
+#ifdef CONFIG_EISA
+ eisa_driver_unregister(&sx_eisadriver);
+#endif
+ pci_unregister_driver(&sx_pcidriver);
+
+ for (i = 0; i < SX_NBOARDS; i++)
+ sx_remove_card(&boards[i], NULL);
+
if (misc_deregister(&sx_fw_device) < 0) {
- printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+ printk(KERN_INFO "sx: couldn't deregister firmware loader "
+ "device\n");
}
- sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
+ sx_dprintk(SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n",
+ sx_initialized);
if (sx_initialized)
- sx_release_drivers ();
+ sx_release_drivers();
- kfree (sx_ports);
+ kfree(sx_ports);
func_exit();
}
module_init(sx_init);
module_exit(sx_exit);
-
-
void __iomem *base;
void __iomem *base2;
unsigned long hw_base;
+ resource_size_t hw_len;
int eisa_base;
int port_base; /* Number of the first port */
struct sx_port *ports;
*
* Return Value: None
*/
-static void mgsl_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
unsigned long flags;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->init_termios.c_ispeed = 9600;
+ serial_driver->init_termios.c_ospeed = 9600;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &mgsl_ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
static int open(struct tty_struct *tty, struct file * filp);
static void close(struct tty_struct *tty, struct file * filp);
static void hangup(struct tty_struct *tty);
-static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
static void put_char(struct tty_struct *tty, unsigned char ch);
wake_up_interruptible(&info->open_wait);
}
-static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct slgt_info *info = tty->driver_data;
unsigned long flags;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->init_termios.c_ispeed = 9600;
+ serial_driver->init_termios.c_ospeed = 9600;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
static int open(struct tty_struct *tty, struct file * filp);
static void close(struct tty_struct *tty, struct file * filp);
static void hangup(struct tty_struct *tty);
-static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
static void put_char(struct tty_struct *tty, unsigned char ch);
/* Set new termios settings
*/
-static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
unsigned long flags;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->init_termios.c_ispeed = 9600;
+ serial_driver->init_termios.c_ospeed = 9600;
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
unsigned int minor;
char value;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
switch (minor) {
case 0:
value = get_led();
int retval = 0;
char c;
- minor = iminor(file->f_dentry->d_inode);
+ minor = iminor(file->f_path.dentry->d_inode);
switch (minor) {
case 0:
type = TYPE_LED;
tipar_write (struct file *file, const char __user *buf, size_t count,
loff_t * ppos)
{
- unsigned int minor = iminor(file->f_dentry->d_inode) - TIPAR_MINOR;
+ unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR;
ssize_t n;
parport_claim_or_block(table[minor].dev);
tipar_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
{
int b = 0;
- unsigned int minor = iminor(file->f_dentry->d_inode) - TIPAR_MINOR;
+ unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR;
ssize_t retval = 0;
ssize_t n = 0;
#define TTY_PARANOIA_CHECK 1
#define CHECK_TTY_COUNT 1
-struct termios tty_std_termios = { /* for the benefit of tty drivers */
+struct ktermios tty_std_termios = { /* for the benefit of tty drivers */
.c_iflag = ICRNL | IXON,
.c_oflag = OPOST | ONLCR,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN,
- .c_cc = INIT_C_CC
+ .c_cc = INIT_C_CC,
+ .c_ispeed = 38400,
+ .c_ospeed = 38400
};
EXPORT_SYMBOL(tty_std_termios);
LIST_HEAD(tty_drivers); /* linked list of tty drivers */
-/* Semaphore to protect creating and releasing a tty. This is shared with
+/* Mutex to protect creating and releasing a tty. This is shared with
vt.c for deeply disgusting hack reasons */
DEFINE_MUTEX(tty_mutex);
EXPORT_SYMBOL(tty_mutex);
"!= #fd's(%d) in %s\n",
tty->name, tty->count, count, routine);
return count;
- }
+ }
#endif
return 0;
}
* Tty buffer allocation management
*/
-
-/**
- * tty_buffer_free_all - free buffers used by a tty
- * @tty: tty to free from
- *
- * Remove all the buffers pending on a tty whether queued with data
- * or in the free ring. Must be called when the tty is no longer in use
- *
- * Locking: none
- */
-
-
/**
* tty_buffer_free_all - free buffers used by a tty
* @tty: tty to free from
* they are not on hot paths so a little discipline won't do
* any harm.
*
- * Locking: takes termios_sem
+ * Locking: takes termios_mutex
*/
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
* context.
*
* Locking: takes tty_ldisc_lock.
- * called functions take termios_sem
+ * called functions take termios_mutex
*/
static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
}
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
+/**
+ * tty_reset_termios - reset terminal state
+ * @tty: tty to reset
+ *
+ * Restore a terminal to the driver default state
+ */
+
+static void tty_reset_termios(struct tty_struct *tty)
+{
+ mutex_lock(&tty->termios_mutex);
+ *tty->termios = tty->driver->init_termios;
+ tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+ tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ mutex_unlock(&tty->termios_mutex);
+}
/**
* do_tty_hangup - actual handler for hangup events
*
* Locking:
* BKL
- * redirect lock for undoing redirection
- * file list lock for manipulating list of ttys
- * tty_ldisc_lock from called functions
- * termios_sem resetting termios data
- * tasklist_lock to walk task list for hangup event
- *
+ * redirect lock for undoing redirection
+ * file list lock for manipulating list of ttys
+ * tty_ldisc_lock from called functions
+ * termios_mutex resetting termios data
+ * tasklist_lock to walk task list for hangup event
+ * ->siglock to protect ->signal/->sighand
*/
static void do_tty_hangup(struct work_struct *work)
{
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
- {
- mutex_lock(&tty->termios_mutex);
- *tty->termios = tty->driver->init_termios;
- mutex_unlock(&tty->termios_mutex);
- }
+ tty_reset_termios(tty);
/* Defer ldisc switch */
/* tty_deferred_ldisc_switch(N_TTY);
read_lock(&tasklist_lock);
if (tty->session > 0) {
do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+ spin_lock_irq(&p->sighand->siglock);
if (p->signal->tty == tty)
p->signal->tty = NULL;
- if (!p->signal->leader)
+ if (!p->signal->leader) {
+ spin_unlock_irq(&p->sighand->siglock);
continue;
- group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
- group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+ }
+ __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+ __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
if (tty->pgrp > 0)
p->signal->tty_old_pgrp = tty->pgrp;
+ spin_unlock_irq(&p->sighand->siglock);
} while_each_task_pid(tty->session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
EXPORT_SYMBOL(tty_hung_up_p);
+static void session_clear_tty(pid_t session)
+{
+ struct task_struct *p;
+ do_each_task_pid(session, PIDTYPE_SID, p) {
+ proc_clear_tty(p);
+ } while_each_task_pid(session, PIDTYPE_SID, p);
+}
+
/**
* disassociate_ctty - disconnect controlling tty
* @on_exit: true if exiting so need to "hang up" the session
* The argument on_exit is set to 1 if called when a process is
* exiting; it is 0 if called by the ioctl TIOCNOTTY.
*
- * Locking: tty_mutex is taken to protect current->signal->tty
+ * Locking:
* BKL is taken for hysterical raisins
- * Tasklist lock is taken (under tty_mutex) to walk process
- * lists for the session.
+ * tty_mutex is taken to protect tty
+ * ->siglock is taken to protect ->signal/->sighand
+ * tasklist_lock is taken to walk process list for sessions
+ * ->siglock is taken to protect ->signal/->sighand
*/
void disassociate_ctty(int on_exit)
{
struct tty_struct *tty;
- struct task_struct *p;
int tty_pgrp = -1;
+ int session;
lock_kernel();
mutex_lock(&tty_mutex);
- tty = current->signal->tty;
+ tty = get_current_tty();
if (tty) {
tty_pgrp = tty->pgrp;
mutex_unlock(&tty_mutex);
+ /* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
} else {
- if (current->signal->tty_old_pgrp) {
- kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
- kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
+ pid_t old_pgrp = current->signal->tty_old_pgrp;
+ if (old_pgrp) {
+ kill_pg(old_pgrp, SIGHUP, on_exit);
+ kill_pg(old_pgrp, SIGCONT, on_exit);
}
mutex_unlock(&tty_mutex);
unlock_kernel();
kill_pg(tty_pgrp, SIGCONT, on_exit);
}
- /* Must lock changes to tty_old_pgrp */
- mutex_lock(&tty_mutex);
+ spin_lock_irq(¤t->sighand->siglock);
current->signal->tty_old_pgrp = 0;
- tty->session = 0;
- tty->pgrp = -1;
+ session = process_session(current);
+ spin_unlock_irq(¤t->sighand->siglock);
+
+ mutex_lock(&tty_mutex);
+ /* It is possible that do_tty_hangup has free'd this tty */
+ tty = get_current_tty();
+ if (tty) {
+ tty->session = 0;
+ tty->pgrp = 0;
+ } else {
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
+ " = NULL", tty);
+#endif
+ }
+ mutex_unlock(&tty_mutex);
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
- do_each_task_pid(current->signal->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
+ session_clear_tty(session);
read_unlock(&tasklist_lock);
- mutex_unlock(&tty_mutex);
unlock_kernel();
}
struct tty_ldisc *ld;
tty = (struct tty_struct *)file->private_data;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (tty_paranoia_check(tty, inode, "tty_read"))
return -EIO;
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
cond_resched();
}
if (written) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_mtime = current_fs_time(inode->i_sb);
ret = written;
}
loff_t *ppos)
{
struct tty_struct * tty;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t ret;
struct tty_ldisc *ld;
struct tty_struct **ret_tty)
{
struct tty_struct *tty, *o_tty;
- struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
- struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
+ struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
+ struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
int retval = 0;
/* check whether we're reopening an existing tty */
}
if (!*tp_loc) {
- tp = (struct termios *) kmalloc(sizeof(struct termios),
+ tp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
GFP_KERNEL);
if (!tp)
goto free_mem_out;
}
if (!*ltp_loc) {
- ltp = (struct termios *) kmalloc(sizeof(struct termios),
+ ltp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
GFP_KERNEL);
if (!ltp)
goto free_mem_out;
- memset(ltp, 0, sizeof(struct termios));
+ memset(ltp, 0, sizeof(struct ktermios));
}
if (driver->type == TTY_DRIVER_TYPE_PTY) {
}
if (!*o_tp_loc) {
- o_tp = (struct termios *)
- kmalloc(sizeof(struct termios), GFP_KERNEL);
+ o_tp = (struct ktermios *)
+ kmalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!o_tp)
goto free_mem_out;
*o_tp = driver->other->init_termios;
}
if (!*o_ltp_loc) {
- o_ltp = (struct termios *)
- kmalloc(sizeof(struct termios), GFP_KERNEL);
+ o_ltp = (struct ktermios *)
+ kmalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!o_ltp)
goto free_mem_out;
- memset(o_ltp, 0, sizeof(struct termios));
+ memset(o_ltp, 0, sizeof(struct ktermios));
}
/*
*ltp_loc = ltp;
tty->termios = *tp_loc;
tty->termios_locked = *ltp_loc;
+ /* Compatibility until drivers always set this */
+ tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+ tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
driver->refcount++;
tty->count++;
static void release_mem(struct tty_struct *tty, int idx)
{
struct tty_struct *o_tty;
- struct termios *tp;
+ struct ktermios *tp;
int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
if ((o_tty = tty->link) != NULL) {
unsigned long flags;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev"))
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "release_dev"))
return;
check_tty_count(tty, "release_dev");
* tty.
*/
if (tty_closing || o_tty_closing) {
- struct task_struct *p;
-
read_lock(&tasklist_lock);
- do_each_task_pid(tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(tty->session, PIDTYPE_SID, p);
+ session_clear_tty(tty->session);
if (o_tty)
- do_each_task_pid(o_tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(o_tty->session, PIDTYPE_SID, p);
+ session_clear_tty(o_tty->session);
read_unlock(&tasklist_lock);
}
* The termios state of a pty is reset on first open so that
* settings don't persist across reuse.
*
- * Locking: tty_mutex protects current->signal->tty, get_tty_driver and
- * init_dev work. tty->count should protect the rest.
- * task_lock is held to update task details for sessions
+ * Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
+ * tty->count should protect the rest.
+ * ->siglock protects ->signal/->sighand
*/
static int tty_open(struct inode * inode, struct file * filp)
mutex_lock(&tty_mutex);
if (device == MKDEV(TTYAUX_MAJOR,0)) {
- if (!current->signal->tty) {
+ tty = get_current_tty();
+ if (!tty) {
mutex_unlock(&tty_mutex);
return -ENXIO;
}
- driver = current->signal->tty->driver;
- index = current->signal->tty->index;
+ driver = tty->driver;
+ index = tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */
goto got_driver;
filp->f_op = &tty_fops;
goto retry_open;
}
+
+ mutex_lock(&tty_mutex);
+ spin_lock_irq(¤t->sighand->siglock);
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
- tty->session == 0) {
- task_lock(current);
- current->signal->tty = tty;
- task_unlock(current);
- current->signal->tty_old_pgrp = 0;
- tty->session = current->signal->session;
- tty->pgrp = process_group(current);
- }
+ tty->session == 0)
+ __proc_set_tty(current, tty);
+ spin_unlock_irq(¤t->sighand->siglock);
+ mutex_unlock(&tty_mutex);
return 0;
}
int ret = 0;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll"))
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
return 0;
ld = tty_ldisc_ref_wait(tty);
int retval;
tty = (struct tty_struct *)filp->private_data;
- if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_fasync"))
+ if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
return 0;
retval = fasync_helper(fd, filp, on, &tty->fasync);
*
* Copies the kernel idea of the window size into the user buffer.
*
- * Locking: tty->termios_sem is taken to ensure the winsize data
+ * Locking: tty->termios_mutex is taken to ensure the winsize data
* is consistent.
*/
* Locking:
* Called function use the console_sem is used to ensure we do
* not try and resize the console twice at once.
- * The tty->termios_sem is used to ensure we don't double
- * resize and get confused. Lock order - tty->termios.sem before
+ * The tty->termios_mutex is used to ensure we don't double
+ * resize and get confused. Lock order - tty->termios_mutex before
* console sem
*/
* leader to set this tty as the controlling tty for the session.
*
* Locking:
- * Takes tasklist lock internally to walk sessions
- * Takes task_lock() when updating signal->tty
* Takes tty_mutex() to protect tty instance
- *
+ * Takes tasklist_lock internally to walk sessions
+ * Takes ->siglock() when updating signal->tty
*/
static int tiocsctty(struct tty_struct *tty, int arg)
{
- struct task_struct *p;
-
+ int ret = 0;
if (current->signal->leader &&
- (current->signal->session == tty->session))
- return 0;
+ (process_session(current) == tty->session))
+ return ret;
+
+ mutex_lock(&tty_mutex);
/*
* The process must be a session leader and
* not have a controlling tty already.
*/
- if (!current->signal->leader || current->signal->tty)
- return -EPERM;
+ if (!current->signal->leader || current->signal->tty) {
+ ret = -EPERM;
+ goto unlock;
+ }
+
if (tty->session > 0) {
/*
* This tty is already the controlling
/*
* Steal it away
*/
-
read_lock(&tasklist_lock);
- do_each_task_pid(tty->session, PIDTYPE_SID, p) {
- p->signal->tty = NULL;
- } while_each_task_pid(tty->session, PIDTYPE_SID, p);
+ session_clear_tty(tty->session);
read_unlock(&tasklist_lock);
- } else
- return -EPERM;
+ } else {
+ ret = -EPERM;
+ goto unlock;
+ }
}
- mutex_lock(&tty_mutex);
- task_lock(current);
- current->signal->tty = tty;
- task_unlock(current);
+ proc_set_tty(current, tty);
+unlock:
mutex_unlock(&tty_mutex);
- current->signal->tty_old_pgrp = 0;
- tty->session = current->signal->session;
- tty->pgrp = process_group(current);
- return 0;
+ return ret;
}
/**
* Obtain the process group of the tty. If there is no process group
* return an error.
*
- * Locking: none. Reference to ->signal->tty is safe.
+ * Locking: none. Reference to current->signal->tty is safe.
*/
static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
return retval;
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
- (real_tty->session != current->signal->session))
+ (real_tty->session != process_session(current)))
return -ENOTTY;
if (get_user(pgrp, p))
return -EFAULT;
if (pgrp < 0)
return -EINVAL;
- if (session_of_pgrp(pgrp) != current->signal->session)
+ if (session_of_pgrp(pgrp) != process_session(current))
return -EPERM;
real_tty->pgrp = pgrp;
return 0;
* Obtain the session id of the tty. If there is no session
* return an error.
*
- * Locking: none. Reference to ->signal->tty is safe.
+ * Locking: none. Reference to current->signal->tty is safe.
*/
static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
clear_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
case TIOCNOTTY:
- /* FIXME: taks lock or tty_mutex ? */
if (current->signal->tty != tty)
return -ENOTTY;
if (current->signal->leader)
disassociate_ctty(0);
- task_lock(current);
- current->signal->tty = NULL;
- task_unlock(current);
+ proc_clear_tty(current);
return 0;
case TIOCSCTTY:
return tiocsctty(tty, arg);
if (!tty)
return;
- session = tty->session;
+ session = tty->session;
/* We don't want an ldisc switch during this */
disc = tty_ldisc_ref(tty);
/* Kill the entire session */
do_each_task_pid(session, PIDTYPE_SID, p) {
printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): p->signal->session==tty->session\n",
+ " (%s): process_session(p)==tty->session\n",
p->pid, p->comm);
send_sig(SIGKILL, p, 1);
} while_each_task_pid(session, PIDTYPE_SID, p);
do_each_thread(g, p) {
if (p->signal->tty == tty) {
printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): p->signal->session==tty->session\n",
+ " (%s): process_session(p)==tty->session\n",
p->pid, p->comm);
send_sig(SIGKILL, p, 1);
continue;
tty_ldisc_deref(disc);
}
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
- 76800, 153600, 307200, 614400, 921600
-#else
- 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
- 2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- * tty_termios_baud_rate
- * @termios: termios structure
- *
- * Convert termios baud rate data into a speed. This should be called
- * with the termios lock held if this termios is a terminal termios
- * structure. May change the termios data.
- *
- * Locking: none
- */
-
-int tty_termios_baud_rate(struct termios *termios)
-{
- unsigned int cbaud;
-
- cbaud = termios->c_cflag & CBAUD;
-
- if (cbaud & CBAUDEX) {
- cbaud &= ~CBAUDEX;
-
- if (cbaud < 1 || cbaud + 15 > n_baud_table)
- termios->c_cflag &= ~CBAUDEX;
- else
- cbaud += 15;
- }
- return baud_table[cbaud];
-}
-
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- * tty_get_baud_rate - get tty bit rates
- * @tty: tty to query
- *
- * Returns the baud rate as an integer for this terminal. The
- * termios lock must be held by the caller and the terminal bit
- * flags may be updated.
- *
- * Locking: none
- */
-
-int tty_get_baud_rate(struct tty_struct *tty)
-{
- int baud = tty_termios_baud_rate(tty->termios);
-
- if (baud == 38400 && tty->alt_speed) {
- if (!tty->warned) {
- printk(KERN_WARNING "Use of setserial/setrocket to "
- "set SPD_* flags is deprecated\n");
- tty->warned = 1;
- }
- baud = tty->alt_speed;
- }
-
- return baud;
-}
-
-EXPORT_SYMBOL(tty_get_baud_rate);
-
/**
* tty_flip_buffer_push - terminal
* @tty: tty to push
if (p) {
driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct termios **)(p + driver->num);
- driver->termios_locked = (struct termios **)(p + driver->num * 2);
+ driver->termios = (struct ktermios **)(p + driver->num);
+ driver->termios_locked = (struct ktermios **)(p + driver->num * 2);
} else {
driver->ttys = NULL;
driver->termios = NULL;
int tty_unregister_driver(struct tty_driver *driver)
{
int i;
- struct termios *tp;
+ struct ktermios *tp;
void *p;
if (driver->refcount)
cdev_del(&driver->cdev);
return 0;
}
-
EXPORT_SYMBOL(tty_unregister_driver);
+dev_t tty_devnum(struct tty_struct *tty)
+{
+ return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+}
+EXPORT_SYMBOL(tty_devnum);
+
+void proc_clear_tty(struct task_struct *p)
+{
+ spin_lock_irq(&p->sighand->siglock);
+ p->signal->tty = NULL;
+ spin_unlock_irq(&p->sighand->siglock);
+}
+EXPORT_SYMBOL(proc_clear_tty);
+
+void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+ if (tty) {
+ tty->session = process_session(tsk);
+ tty->pgrp = process_group(tsk);
+ }
+ tsk->signal->tty = tty;
+ tsk->signal->tty_old_pgrp = 0;
+}
+
+void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+ spin_lock_irq(&tsk->sighand->siglock);
+ __proc_set_tty(tsk, tty);
+ spin_unlock_irq(&tsk->sighand->siglock);
+}
+
+struct tty_struct *get_current_tty(void)
+{
+ struct tty_struct *tty;
+ WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
+ tty = current->signal->tty;
+ /*
+ * session->tty can be changed/cleared from under us, make sure we
+ * issue the load. The obtained pointer, when not NULL, is valid as
+ * long as we hold tty_mutex.
+ */
+ barrier();
+ return tty;
+}
/*
* Initialize the console device. This is called *early*, so
#define TERMIOS_FLUSH 1
#define TERMIOS_WAIT 2
#define TERMIOS_TERMIO 4
+#define TERMIOS_OLD 8
/**
EXPORT_SYMBOL(tty_wait_until_sent);
-static void unset_locked_termios(struct termios *termios,
- struct termios *old,
- struct termios *locked)
+static void unset_locked_termios(struct ktermios *termios,
+ struct ktermios *old,
+ struct ktermios *locked)
{
int i;
for (i=0; i < NCCS; i++)
termios->c_cc[i] = locked->c_cc[i] ?
old->c_cc[i] : termios->c_cc[i];
+ /* FIXME: What should we do for i/ospeed */
}
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static const speed_t baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+ 76800, 153600, 307200, 614400, 921600
+#else
+ 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+#ifndef __sparc__
+static const tcflag_t baud_bits[] = {
+ B0, B50, B75, B110, B134, B150, B200, B300, B600,
+ B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+ B57600, B115200, B230400, B460800, B500000, B576000,
+ B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
+ B3000000, B3500000, B4000000
+};
+#else
+static const tcflag_t baud_bits[] = {
+ B0, B50, B75, B110, B134, B150, B200, B300, B600,
+ B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+ B57600, B115200, B230400, B460800, B76800, B153600,
+ B307200, B614400, B921600
+};
+#endif
+
+static int n_baud_table = ARRAY_SIZE(baud_table);
+
+/**
+ * tty_termios_baud_rate
+ * @termios: termios structure
+ *
+ * Convert termios baud rate data into a speed. This should be called
+ * with the termios lock held if this termios is a terminal termios
+ * structure. May change the termios data. Device drivers can call this
+ * function but should use ->c_[io]speed directly as they are updated.
+ *
+ * Locking: none
+ */
+
+speed_t tty_termios_baud_rate(struct ktermios *termios)
+{
+ unsigned int cbaud;
+
+ cbaud = termios->c_cflag & CBAUD;
+
+#ifdef BOTHER
+ /* Magic token for arbitary speed via c_ispeed/c_ospeed */
+ if (cbaud == BOTHER)
+ return termios->c_ospeed;
+#endif
+ if (cbaud & CBAUDEX) {
+ cbaud &= ~CBAUDEX;
+
+ if (cbaud < 1 || cbaud + 15 > n_baud_table)
+ termios->c_cflag &= ~CBAUDEX;
+ else
+ cbaud += 15;
+ }
+ return baud_table[cbaud];
+}
+
+EXPORT_SYMBOL(tty_termios_baud_rate);
+
+/**
+ * tty_termios_input_baud_rate
+ * @termios: termios structure
+ *
+ * Convert termios baud rate data into a speed. This should be called
+ * with the termios lock held if this termios is a terminal termios
+ * structure. May change the termios data. Device drivers can call this
+ * function but should use ->c_[io]speed directly as they are updated.
+ *
+ * Locking: none
+ */
+
+speed_t tty_termios_input_baud_rate(struct ktermios *termios)
+{
+#ifdef IBSHIFT
+ unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
+
+ if (cbaud == B0)
+ return tty_termios_baud_rate(termios);
+
+ /* Magic token for arbitary speed via c_ispeed*/
+ if (cbaud == BOTHER)
+ return termios->c_ispeed;
+
+ if (cbaud & CBAUDEX) {
+ cbaud &= ~CBAUDEX;
+
+ if (cbaud < 1 || cbaud + 15 > n_baud_table)
+ termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
+ else
+ cbaud += 15;
+ }
+ return baud_table[cbaud];
+#else
+ return tty_termios_baud_rate(termios);
+#endif
+}
+
+EXPORT_SYMBOL(tty_termios_input_baud_rate);
+
+#ifdef BOTHER
+
+/**
+ * tty_termios_encode_baud_rate
+ * @termios: termios structure
+ * @ispeed: input speed
+ * @ospeed: output speed
+ *
+ * Encode the speeds set into the passed termios structure. This is
+ * used as a library helper for drivers os that they can report back
+ * the actual speed selected when it differs from the speed requested
+ *
+ * For now input and output speed must agree.
+ *
+ * Locking: Caller should hold termios lock. This is already held
+ * when calling this function from the driver termios handler.
+ */
+
+void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
+{
+ int i = 0;
+ int ifound = 0, ofound = 0;
+
+ termios->c_ispeed = ibaud;
+ termios->c_ospeed = obaud;
+
+ termios->c_cflag &= ~CBAUD;
+ /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/
+ if (termios->c_ispeed == termios->c_ospeed)
+ ifound = 1;
+
+ do {
+ if (obaud == baud_table[i]) {
+ termios->c_cflag |= baud_bits[i];
+ ofound = 1;
+ /* So that if ibaud == obaud we don't set it */
+ continue;
+ }
+ if (ibaud == baud_table[i]) {
+ termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+ ifound = 1;
+ }
+ }
+ while(++i < n_baud_table);
+ if (!ofound)
+ termios->c_cflag |= BOTHER;
+ if (!ifound)
+ termios->c_cflag |= (BOTHER << IBSHIFT);
+}
+
+EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+
+#endif
+
+/**
+ * tty_get_baud_rate - get tty bit rates
+ * @tty: tty to query
+ *
+ * Returns the baud rate as an integer for this terminal. The
+ * termios lock must be held by the caller and the terminal bit
+ * flags may be updated.
+ *
+ * Locking: none
+ */
+
+speed_t tty_get_baud_rate(struct tty_struct *tty)
+{
+ speed_t baud = tty_termios_baud_rate(tty->termios);
+
+ if (baud == 38400 && tty->alt_speed) {
+ if (!tty->warned) {
+ printk(KERN_WARNING "Use of setserial/setrocket to "
+ "set SPD_* flags is deprecated\n");
+ tty->warned = 1;
+ }
+ baud = tty->alt_speed;
+ }
+
+ return baud;
+}
+
+EXPORT_SYMBOL(tty_get_baud_rate);
+
/**
* change_termios - update termios values
* @tty: tty to update
* Locking: termios_sem
*/
-static void change_termios(struct tty_struct * tty, struct termios * new_termios)
+static void change_termios(struct tty_struct * tty, struct ktermios * new_termios)
{
int canon_change;
- struct termios old_termios = *tty->termios;
+ struct ktermios old_termios = *tty->termios;
struct tty_ldisc *ld;
/*
static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
{
- struct termios tmp_termios;
+ struct ktermios tmp_termios;
struct tty_ldisc *ld;
int retval = tty_check_change(tty);
if (retval)
return retval;
+ memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+
if (opt & TERMIOS_TERMIO) {
- memcpy(&tmp_termios, tty->termios, sizeof(struct termios));
if (user_termio_to_kernel_termios(&tmp_termios,
(struct termio __user *)arg))
return -EFAULT;
+#ifdef TCGETS2
+ } else if (opt & TERMIOS_OLD) {
+ if (user_termios_to_kernel_termios_1(&tmp_termios,
+ (struct termios __user *)arg))
+ return -EFAULT;
} else {
if (user_termios_to_kernel_termios(&tmp_termios,
- (struct termios __user *)arg))
+ (struct termios2 __user *)arg))
return -EFAULT;
}
+#else
+ } else if (user_termios_to_kernel_termios(&tmp_termios,
+ (struct termios __user *)arg))
+ return -EFAULT;
+#endif
+
+ /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed
+ so its unconditionally usable */
+ tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
+ tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
ld = tty_ldisc_ref(tty);
struct sgttyb tmp;
mutex_lock(&tty->termios_mutex);
- tmp.sg_ispeed = 0;
- tmp.sg_ospeed = 0;
+ tmp.sg_ispeed = tty->termios->c_ispeed;
+ tmp.sg_ospeed = tty->termios->c_ospeed;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
-static void set_sgflags(struct termios * termios, int flags)
+static void set_sgflags(struct ktermios * termios, int flags)
{
termios->c_iflag = ICRNL | IXON;
termios->c_oflag = 0;
{
int retval;
struct sgttyb tmp;
- struct termios termios;
+ struct ktermios termios;
retval = tty_check_change(tty);
if (retval)
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
+ /* Try and encode into Bfoo format */
+#ifdef BOTHER
+ tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed);
+#endif
mutex_unlock(&tty->termios_mutex);
change_termios(tty, &termios);
return 0;
case TIOCSLTC:
return set_ltchars(real_tty, p);
#endif
+ case TCSETSF:
+ return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+ case TCSETSW:
+ return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+ case TCSETS:
+ return set_termios(real_tty, p, TERMIOS_OLD);
+#ifndef TCGETS2
case TCGETS:
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
return -EFAULT;
return 0;
- case TCSETSF:
+#else
+ case TCGETS:
+ if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
+ return -EFAULT;
+ return 0;
+ case TCGETS2:
+ if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
+ return -EFAULT;
+ return 0;
+ case TCSETSF2:
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
- case TCSETSW:
+ case TCSETSW2:
return set_termios(real_tty, p, TERMIOS_WAIT);
- case TCSETS:
+ case TCSETS2:
return set_termios(real_tty, p, 0);
+#endif
case TCGETA:
return get_termio(real_tty, p);
case TCSETAF:
int size;
down(&con_buf_sem);
- size = vcs_size(file->f_dentry->d_inode);
+ size = vcs_size(file->f_path.dentry->d_inode);
switch (orig) {
default:
up(&con_buf_sem);
static ssize_t
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
static ssize_t
vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
unsigned int currcons = iminor(inode);
struct vc_data *vc;
long pos;
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
/*
* We need to make sure we can send a request. We use
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
/*
* We need to make sure we can send a request. We use
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
down(&reqSem);
if (op == NULL)
return -ENOMEM;
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
/* Note: We currently only support one mode! */
if ((devi.devno >= viotape_numdev) || (devi.mode)) {
return -ENOMEM;
init_completion(&op->com);
- get_dev_info(file->f_dentry->d_inode, &devi);
+ get_dev_info(file->f_path.dentry->d_inode, &devi);
if (devi.devno >= viotape_numdev) {
ret = -ENODEV;
scc_driver->init_termios = tty_std_termios;
scc_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ scc_driver->init_termios.c_ispeed = 9600;
+ scc_driver->init_termios.c_ospeed = 9600;
scc_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(scc_driver, &scc_ops);
unsigned int pin;
char value = '0';
- pin = iminor(file->f_dentry->d_inode);
+ pin = iminor(file->f_path.dentry->d_inode);
if (pin >= giu_nr_pins)
return -EBADF;
char c;
int retval = 0;
- pin = iminor(file->f_dentry->d_inode);
+ pin = iminor(file->f_path.dentry->d_inode);
if (pin >= giu_nr_pins)
return -EBADF;
acpi_pm_check_graylist);
#endif
+#ifndef CONFIG_X86_64
+#include "mach_timer.h"
+#define PMTMR_EXPECTED_RATE \
+ ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (CLOCK_TICK_RATE>>10))
+/*
+ * Some boards have the PMTMR running way too fast. We check
+ * the PMTMR rate against PIT channel 2 to catch these cases.
+ */
+static int verify_pmtmr_rate(void)
+{
+ u32 value1, value2;
+ unsigned long count, delta;
+
+ mach_prepare_counter();
+ value1 = read_pmtmr();
+ mach_countup(&count);
+ value2 = read_pmtmr();
+ delta = (value2 - value1) & ACPI_PM_MASK;
+
+ /* Check that the PMTMR delta is within 5% of what we expect */
+ if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
+ delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
+ printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% "
+ "of normal - aborting.\n",
+ 100UL * delta / PMTMR_EXPECTED_RATE);
+ return -1;
+ }
+
+ return 0;
+}
+#else
+#define verify_pmtmr_rate() (0)
+#endif
static int __init init_acpi_pm_clocksource(void)
{
return -ENODEV;
pm_good:
+ if (verify_pmtmr_rate() != 0)
+ return -ENODEV;
+
return clocksource_register(&clocksource_acpi_pm);
}
--- /dev/null
+#
+# HID driver configuration
+#
+menu "HID Devices"
+ depends on INPUT
+
+config HID
+ tristate "Generic HID support"
+ default y
+ ---help---
+ Say Y here if you want generic HID support to connect keyboards,
+ mice, joysticks, graphic tablets, or any other HID based devices
+ to your computer. You also need to select particular types of
+ HID devices you want to compile support for, in the particular
+ driver menu (USB, Bluetooth)
+
+endmenu
+
--- /dev/null
+#
+# Makefile for the HID driver
+#
+
+# Multipart objects.
+hid-objs := hid-core.o hid-input.o
+
+# Optional parts of multipart objects.
+
+obj-$(CONFIG_HID) += hid.o
+
+ifeq ($(CONFIG_INPUT_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
--- /dev/null
+/*
+ * HID support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/input.h>
+#include <linux/wait.h>
+
+#undef DEBUG
+#undef DEBUG_DATA
+
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+
+/*
+ * Version Information
+ */
+
+#define DRIVER_VERSION "v2.6"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_DESC "USB HID core driver"
+#define DRIVER_LICENSE "GPL"
+
+/*
+ * Module parameters.
+ */
+
+static unsigned int hid_mousepoll_interval;
+module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+
+/*
+ * Register a new report for a device.
+ */
+
+static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+{
+ struct hid_report_enum *report_enum = device->report_enum + type;
+ struct hid_report *report;
+
+ if (report_enum->report_id_hash[id])
+ return report_enum->report_id_hash[id];
+
+ if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+ return NULL;
+
+ if (id != 0)
+ report_enum->numbered = 1;
+
+ report->id = id;
+ report->type = type;
+ report->size = 0;
+ report->device = device;
+ report_enum->report_id_hash[id] = report;
+
+ list_add_tail(&report->list, &report_enum->report_list);
+
+ return report;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
+{
+ struct hid_field *field;
+
+ if (report->maxfield == HID_MAX_FIELDS) {
+ dbg("too many fields in report");
+ return NULL;
+ }
+
+ if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+ + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+
+ field->index = report->maxfield++;
+ report->field[field->index] = field;
+ field->usage = (struct hid_usage *)(field + 1);
+ field->value = (unsigned *)(field->usage + usages);
+ field->report = report;
+
+ return field;
+}
+
+/*
+ * Open a collection. The type/usage is pushed on the stack.
+ */
+
+static int open_collection(struct hid_parser *parser, unsigned type)
+{
+ struct hid_collection *collection;
+ unsigned usage;
+
+ usage = parser->local.usage[0];
+
+ if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
+ dbg("collection stack overflow");
+ return -1;
+ }
+
+ if (parser->device->maxcollection == parser->device->collection_size) {
+ collection = kmalloc(sizeof(struct hid_collection) *
+ parser->device->collection_size * 2, GFP_KERNEL);
+ if (collection == NULL) {
+ dbg("failed to reallocate collection array");
+ return -1;
+ }
+ memcpy(collection, parser->device->collection,
+ sizeof(struct hid_collection) *
+ parser->device->collection_size);
+ memset(collection + parser->device->collection_size, 0,
+ sizeof(struct hid_collection) *
+ parser->device->collection_size);
+ kfree(parser->device->collection);
+ parser->device->collection = collection;
+ parser->device->collection_size *= 2;
+ }
+
+ parser->collection_stack[parser->collection_stack_ptr++] =
+ parser->device->maxcollection;
+
+ collection = parser->device->collection +
+ parser->device->maxcollection++;
+ collection->type = type;
+ collection->usage = usage;
+ collection->level = parser->collection_stack_ptr - 1;
+
+ if (type == HID_COLLECTION_APPLICATION)
+ parser->device->maxapplication++;
+
+ return 0;
+}
+
+/*
+ * Close a collection.
+ */
+
+static int close_collection(struct hid_parser *parser)
+{
+ if (!parser->collection_stack_ptr) {
+ dbg("collection stack underflow");
+ return -1;
+ }
+ parser->collection_stack_ptr--;
+ return 0;
+}
+
+/*
+ * Climb up the stack, search for the specified collection type
+ * and return the usage.
+ */
+
+static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
+{
+ int n;
+ for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
+ if (parser->device->collection[parser->collection_stack[n]].type == type)
+ return parser->device->collection[parser->collection_stack[n]].usage;
+ return 0; /* we know nothing about this usage type */
+}
+
+/*
+ * Add a usage to the temporary parser table.
+ */
+
+static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+{
+ if (parser->local.usage_index >= HID_MAX_USAGES) {
+ dbg("usage index exceeded");
+ return -1;
+ }
+ parser->local.usage[parser->local.usage_index] = usage;
+ parser->local.collection_index[parser->local.usage_index] =
+ parser->collection_stack_ptr ?
+ parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
+ parser->local.usage_index++;
+ return 0;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
+{
+ struct hid_report *report;
+ struct hid_field *field;
+ int usages;
+ unsigned offset;
+ int i;
+
+ if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+ dbg("hid_register_report failed");
+ return -1;
+ }
+
+ if (parser->global.logical_maximum < parser->global.logical_minimum) {
+ dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+ return -1;
+ }
+
+ offset = report->size;
+ report->size += parser->global.report_size * parser->global.report_count;
+
+ if (!parser->local.usage_index) /* Ignore padding fields */
+ return 0;
+
+ usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+
+ if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+ return 0;
+
+ field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
+ field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
+ field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
+
+ for (i = 0; i < usages; i++) {
+ int j = i;
+ /* Duplicate the last usage we parsed if we have excess values */
+ if (i >= parser->local.usage_index)
+ j = parser->local.usage_index - 1;
+ field->usage[i].hid = parser->local.usage[j];
+ field->usage[i].collection_index =
+ parser->local.collection_index[j];
+ }
+
+ field->maxusage = usages;
+ field->flags = flags;
+ field->report_offset = offset;
+ field->report_type = report_type;
+ field->report_size = parser->global.report_size;
+ field->report_count = parser->global.report_count;
+ field->logical_minimum = parser->global.logical_minimum;
+ field->logical_maximum = parser->global.logical_maximum;
+ field->physical_minimum = parser->global.physical_minimum;
+ field->physical_maximum = parser->global.physical_maximum;
+ field->unit_exponent = parser->global.unit_exponent;
+ field->unit = parser->global.unit;
+
+ return 0;
+}
+
+/*
+ * Read data value from item.
+ */
+
+static u32 item_udata(struct hid_item *item)
+{
+ switch (item->size) {
+ case 1: return item->data.u8;
+ case 2: return item->data.u16;
+ case 4: return item->data.u32;
+ }
+ return 0;
+}
+
+static s32 item_sdata(struct hid_item *item)
+{
+ switch (item->size) {
+ case 1: return item->data.s8;
+ case 2: return item->data.s16;
+ case 4: return item->data.s32;
+ }
+ return 0;
+}
+
+/*
+ * Process a global item.
+ */
+
+static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
+{
+ switch (item->tag) {
+
+ case HID_GLOBAL_ITEM_TAG_PUSH:
+
+ if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+ dbg("global enviroment stack overflow");
+ return -1;
+ }
+
+ memcpy(parser->global_stack + parser->global_stack_ptr++,
+ &parser->global, sizeof(struct hid_global));
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_POP:
+
+ if (!parser->global_stack_ptr) {
+ dbg("global enviroment stack underflow");
+ return -1;
+ }
+
+ memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
+ sizeof(struct hid_global));
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+ parser->global.usage_page = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+ parser->global.logical_minimum = item_sdata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+ if (parser->global.logical_minimum < 0)
+ parser->global.logical_maximum = item_sdata(item);
+ else
+ parser->global.logical_maximum = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+ parser->global.physical_minimum = item_sdata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+ if (parser->global.physical_minimum < 0)
+ parser->global.physical_maximum = item_sdata(item);
+ else
+ parser->global.physical_maximum = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+ parser->global.unit_exponent = item_sdata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_UNIT:
+ parser->global.unit = item_udata(item);
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+ if ((parser->global.report_size = item_udata(item)) > 32) {
+ dbg("invalid report_size %d", parser->global.report_size);
+ return -1;
+ }
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+ if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
+ dbg("invalid report_count %d", parser->global.report_count);
+ return -1;
+ }
+ return 0;
+
+ case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+ if ((parser->global.report_id = item_udata(item)) == 0) {
+ dbg("report_id 0 is invalid");
+ return -1;
+ }
+ return 0;
+
+ default:
+ dbg("unknown global tag 0x%x", item->tag);
+ return -1;
+ }
+}
+
+/*
+ * Process a local item.
+ */
+
+static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
+{
+ __u32 data;
+ unsigned n;
+
+ if (item->size == 0) {
+ dbg("item data expected for local item");
+ return -1;
+ }
+
+ data = item_udata(item);
+
+ switch (item->tag) {
+
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+ if (data) {
+ /*
+ * We treat items before the first delimiter
+ * as global to all usage sets (branch 0).
+ * In the moment we process only these global
+ * items and the first delimiter set.
+ */
+ if (parser->local.delimiter_depth != 0) {
+ dbg("nested delimiters");
+ return -1;
+ }
+ parser->local.delimiter_depth++;
+ parser->local.delimiter_branch++;
+ } else {
+ if (parser->local.delimiter_depth < 1) {
+ dbg("bogus close delimiter");
+ return -1;
+ }
+ parser->local.delimiter_depth--;
+ }
+ return 1;
+
+ case HID_LOCAL_ITEM_TAG_USAGE:
+
+ if (parser->local.delimiter_branch > 1) {
+ dbg("alternative usage ignored");
+ return 0;
+ }
+
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
+
+ return hid_add_usage(parser, data);
+
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+
+ if (parser->local.delimiter_branch > 1) {
+ dbg("alternative usage ignored");
+ return 0;
+ }
+
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
+
+ parser->local.usage_minimum = data;
+ return 0;
+
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+
+ if (parser->local.delimiter_branch > 1) {
+ dbg("alternative usage ignored");
+ return 0;
+ }
+
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
+
+ for (n = parser->local.usage_minimum; n <= data; n++)
+ if (hid_add_usage(parser, n)) {
+ dbg("hid_add_usage failed\n");
+ return -1;
+ }
+ return 0;
+
+ default:
+
+ dbg("unknown local item tag 0x%x", item->tag);
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * Process a main item.
+ */
+
+static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
+{
+ __u32 data;
+ int ret;
+
+ data = item_udata(item);
+
+ switch (item->tag) {
+ case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+ ret = open_collection(parser, data & 0xff);
+ break;
+ case HID_MAIN_ITEM_TAG_END_COLLECTION:
+ ret = close_collection(parser);
+ break;
+ case HID_MAIN_ITEM_TAG_INPUT:
+ ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+ break;
+ case HID_MAIN_ITEM_TAG_OUTPUT:
+ ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+ break;
+ case HID_MAIN_ITEM_TAG_FEATURE:
+ ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+ break;
+ default:
+ dbg("unknown main item tag 0x%x", item->tag);
+ ret = 0;
+ }
+
+ memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */
+
+ return ret;
+}
+
+/*
+ * Process a reserved item.
+ */
+
+static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
+{
+ dbg("reserved item type, tag 0x%x", item->tag);
+ return 0;
+}
+
+/*
+ * Free a report and all registered fields. The field->usage and
+ * field->value table's are allocated behind the field, so we need
+ * only to free(field) itself.
+ */
+
+static void hid_free_report(struct hid_report *report)
+{
+ unsigned n;
+
+ for (n = 0; n < report->maxfield; n++)
+ kfree(report->field[n]);
+ kfree(report);
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+void hid_free_device(struct hid_device *device)
+{
+ unsigned i,j;
+
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ struct hid_report_enum *report_enum = device->report_enum + i;
+
+ for (j = 0; j < 256; j++) {
+ struct hid_report *report = report_enum->report_id_hash[j];
+ if (report)
+ hid_free_report(report);
+ }
+ }
+
+ kfree(device->rdesc);
+ kfree(device);
+}
+EXPORT_SYMBOL_GPL(hid_free_device);
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
+{
+ u8 b;
+
+ if ((end - start) <= 0)
+ return NULL;
+
+ b = *start++;
+
+ item->type = (b >> 2) & 3;
+ item->tag = (b >> 4) & 15;
+
+ if (item->tag == HID_ITEM_TAG_LONG) {
+
+ item->format = HID_ITEM_FORMAT_LONG;
+
+ if ((end - start) < 2)
+ return NULL;
+
+ item->size = *start++;
+ item->tag = *start++;
+
+ if ((end - start) < item->size)
+ return NULL;
+
+ item->data.longdata = start;
+ start += item->size;
+ return start;
+ }
+
+ item->format = HID_ITEM_FORMAT_SHORT;
+ item->size = b & 3;
+
+ switch (item->size) {
+
+ case 0:
+ return start;
+
+ case 1:
+ if ((end - start) < 1)
+ return NULL;
+ item->data.u8 = *start++;
+ return start;
+
+ case 2:
+ if ((end - start) < 2)
+ return NULL;
+ item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
+ start = (__u8 *)((__le16 *)start + 1);
+ return start;
+
+ case 3:
+ item->size++;
+ if ((end - start) < 4)
+ return NULL;
+ item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
+ start = (__u8 *)((__le32 *)start + 1);
+ return start;
+ }
+
+ return NULL;
+}
+
+/*
+ * Parse a report description into a hid_device structure. Reports are
+ * enumerated, fields are attached to these reports.
+ */
+
+struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+{
+ struct hid_device *device;
+ struct hid_parser *parser;
+ struct hid_item item;
+ __u8 *end;
+ unsigned i;
+ static int (*dispatch_type[])(struct hid_parser *parser,
+ struct hid_item *item) = {
+ hid_parser_main,
+ hid_parser_global,
+ hid_parser_local,
+ hid_parser_reserved
+ };
+
+ if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
+ return NULL;
+
+ if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
+ HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
+ kfree(device);
+ return NULL;
+ }
+ device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
+ for (i = 0; i < HID_REPORT_TYPES; i++)
+ INIT_LIST_HEAD(&device->report_enum[i].report_list);
+
+ if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
+ kfree(device->collection);
+ kfree(device);
+ return NULL;
+ }
+ memcpy(device->rdesc, start, size);
+ device->rsize = size;
+
+ if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+ kfree(device->rdesc);
+ kfree(device->collection);
+ kfree(device);
+ return NULL;
+ }
+ parser->device = device;
+
+ end = start + size;
+ while ((start = fetch_item(start, end, &item)) != NULL) {
+
+ if (item.format != HID_ITEM_FORMAT_SHORT) {
+ dbg("unexpected long global item");
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+
+ if (dispatch_type[item.type](parser, &item)) {
+ dbg("item %u %u %u %u parsing failed\n",
+ item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+
+ if (start == end) {
+ if (parser->collection_stack_ptr) {
+ dbg("unbalanced collection at end of report description");
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+ if (parser->local.delimiter_depth) {
+ dbg("unbalanced delimiter at end of report description");
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+ }
+ kfree(parser);
+ return device;
+ }
+ }
+
+ dbg("item fetching failed at offset %d\n", (int)(end - start));
+ kfree(device->collection);
+ hid_free_device(device);
+ kfree(parser);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(hid_parse_report);
+
+/*
+ * Convert a signed n-bit integer to signed 32-bit integer. Common
+ * cases are done through the compiler, the screwed things has to be
+ * done by hand.
+ */
+
+static s32 snto32(__u32 value, unsigned n)
+{
+ switch (n) {
+ case 8: return ((__s8)value);
+ case 16: return ((__s16)value);
+ case 32: return ((__s32)value);
+ }
+ return value & (1 << (n - 1)) ? value | (-1 << n) : value;
+}
+
+/*
+ * Convert a signed 32-bit integer to a signed n-bit integer.
+ */
+
+static u32 s32ton(__s32 value, unsigned n)
+{
+ s32 a = value >> (n - 1);
+ if (a && a != -1)
+ return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+ return value & ((1 << n) - 1);
+}
+
+/*
+ * Extract/implement a data field from/to a little endian report (bit array).
+ *
+ * Code sort-of follows HID spec:
+ * http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ *
+ * While the USB HID spec allows unlimited length bit fields in "report
+ * descriptors", most devices never use more than 16 bits.
+ * One model of UPS is claimed to report "LINEV" as a 32-bit field.
+ * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
+ */
+
+static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+{
+ u64 x;
+
+ WARN_ON(n > 32);
+
+ report += offset >> 3; /* adjust byte index */
+ offset &= 7; /* now only need bit offset into one byte */
+ x = get_unaligned((u64 *) report);
+ x = le64_to_cpu(x);
+ x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
+ return (u32) x;
+}
+
+/*
+ * "implement" : set bits in a little endian bit stream.
+ * Same concepts as "extract" (see comments above).
+ * The data mangled in the bit stream remains in little endian
+ * order the whole time. It make more sense to talk about
+ * endianness of register values by considering a register
+ * a "cached" copy of the little endiad bit stream.
+ */
+static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+{
+ u64 x;
+ u64 m = (1ULL << n) - 1;
+
+ WARN_ON(n > 32);
+
+ WARN_ON(value > m);
+ value &= m;
+
+ report += offset >> 3;
+ offset &= 7;
+
+ x = get_unaligned((u64 *)report);
+ x &= cpu_to_le64(~(m << offset));
+ x |= cpu_to_le64(((u64) value) << offset);
+ put_unaligned(x, (u64 *) report);
+}
+
+/*
+ * Search an array for a value.
+ */
+
+static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+{
+ while (n--) {
+ if (*array++ == value)
+ return 0;
+ }
+ return -1;
+}
+
+static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
+{
+ hid_dump_input(usage, value);
+ if (hid->claimed & HID_CLAIMED_INPUT)
+ hidinput_hid_event(hid, field, usage, value);
+ if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+}
+
+/*
+ * Analyse a received field, and fetch the data from it. The field
+ * content is stored for next report processing (we do differential
+ * reporting to the layer).
+ */
+
+void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
+{
+ unsigned n;
+ unsigned count = field->report_count;
+ unsigned offset = field->report_offset;
+ unsigned size = field->report_size;
+ __s32 min = field->logical_minimum;
+ __s32 max = field->logical_maximum;
+ __s32 *value;
+
+ if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
+ return;
+
+ for (n = 0; n < count; n++) {
+
+ value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
+ extract(data, offset + n * size, size);
+
+ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
+ && value[n] >= min && value[n] <= max
+ && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+ goto exit;
+ }
+
+ for (n = 0; n < count; n++) {
+
+ if (HID_MAIN_ITEM_VARIABLE & field->flags) {
+ hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
+ continue;
+ }
+
+ if (field->value[n] >= min && field->value[n] <= max
+ && field->usage[field->value[n] - min].hid
+ && search(value, field->value[n], count))
+ hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
+
+ if (value[n] >= min && value[n] <= max
+ && field->usage[value[n] - min].hid
+ && search(field->value, value[n], count))
+ hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
+ }
+
+ memcpy(field->value, value, count * sizeof(__s32));
+exit:
+ kfree(value);
+}
+EXPORT_SYMBOL_GPL(hid_input_field);
+
+/*
+ * Output the field into the report.
+ */
+
+static void hid_output_field(struct hid_field *field, __u8 *data)
+{
+ unsigned count = field->report_count;
+ unsigned offset = field->report_offset;
+ unsigned size = field->report_size;
+ unsigned n;
+
+ for (n = 0; n < count; n++) {
+ if (field->logical_minimum < 0) /* signed values */
+ implement(data, offset + n * size, size, s32ton(field->value[n], size));
+ else /* unsigned values */
+ implement(data, offset + n * size, size, field->value[n]);
+ }
+}
+
+/*
+ * Create a report.
+ */
+
+void hid_output_report(struct hid_report *report, __u8 *data)
+{
+ unsigned n;
+
+ if (report->id > 0)
+ *data++ = report->id;
+
+ for (n = 0; n < report->maxfield; n++)
+ hid_output_field(report->field[n], data);
+}
+EXPORT_SYMBOL_GPL(hid_output_report);
+
+/*
+ * Set a field value. The report this field belongs to has to be
+ * created and transferred to the device, to set this value in the
+ * device.
+ */
+
+int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+{
+ unsigned size = field->report_size;
+
+ hid_dump_input(field->usage + offset, value);
+
+ if (offset >= field->report_count) {
+ dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
+ hid_dump_field(field, 8);
+ return -1;
+ }
+ if (field->logical_minimum < 0) {
+ if (value != snto32(s32ton(value, size), size)) {
+ dbg("value %d is out of range", value);
+ return -1;
+ }
+ }
+ field->value[offset] = value;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_set_field);
+
+int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+{
+ struct hid_report_enum *report_enum = hid->report_enum + type;
+ struct hid_report *report;
+ int n, rsize;
+
+ if (!hid)
+ return -ENODEV;
+
+ if (!size) {
+ dbg("empty report");
+ return -1;
+ }
+
+#ifdef DEBUG_DATA
+ printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
+#endif
+
+ n = 0; /* Normally report number is 0 */
+ if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
+ n = *data++;
+ size--;
+ }
+
+#ifdef DEBUG_DATA
+ {
+ int i;
+ printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
+ for (i = 0; i < size; i++)
+ printk(" %02x", data[i]);
+ printk("\n");
+ }
+#endif
+
+ if (!(report = report_enum->report_id_hash[n])) {
+ dbg("undefined report_id %d received", n);
+ return -1;
+ }
+
+ rsize = ((report->size - 1) >> 3) + 1;
+
+ if (size < rsize) {
+ dbg("report %d is too short, (%d < %d)", report->id, size, rsize);
+ return -1;
+ }
+
+ if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
+ hid->hiddev_report_event(hid, report);
+
+ for (n = 0; n < report->maxfield; n++)
+ hid_input_field(hid, report->field[n], data, interrupt);
+
+ if (hid->claimed & HID_CLAIMED_INPUT)
+ hidinput_report_event(hid, report);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_input_report);
+
+MODULE_LICENSE(DRIVER_LICENSE);
+
* $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006 Jiri Kosina
*
- * USB HID to Linux Input mapping
+ * HID to Linux Input mapping
*/
/*
#undef DEBUG
-#include "hid.h"
+#include <linux/hid.h>
#define unk KEY_UNKNOWN
static struct hidinput_key_translation powerbook_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
- { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
- { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
- { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
- { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
- { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
- { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
- { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
- { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
- { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
- { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
- { KEY_UP, KEY_PAGEUP },
- { KEY_DOWN, KEY_PAGEDOWN },
- { KEY_LEFT, KEY_HOME },
- { KEY_RIGHT, KEY_END },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY },
+ { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY },
+ { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY },
+ { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY },
+ { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY },
+ { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY },
+ { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY },
+ { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
{ }
};
static struct hidinput_key_translation powerbook_numlock_keys[] = {
- { KEY_J, KEY_KP1 },
- { KEY_K, KEY_KP2 },
- { KEY_L, KEY_KP3 },
- { KEY_U, KEY_KP4 },
- { KEY_I, KEY_KP5 },
- { KEY_O, KEY_KP6 },
- { KEY_7, KEY_KP7 },
- { KEY_8, KEY_KP8 },
- { KEY_9, KEY_KP9 },
- { KEY_M, KEY_KP0 },
- { KEY_DOT, KEY_KPDOT },
- { KEY_SLASH, KEY_KPPLUS },
+ { KEY_J, KEY_KP1 },
+ { KEY_K, KEY_KP2 },
+ { KEY_L, KEY_KP3 },
+ { KEY_U, KEY_KP4 },
+ { KEY_I, KEY_KP5 },
+ { KEY_O, KEY_KP6 },
+ { KEY_7, KEY_KP7 },
+ { KEY_8, KEY_KP8 },
+ { KEY_9, KEY_KP9 },
+ { KEY_M, KEY_KP0 },
+ { KEY_DOT, KEY_KPDOT },
+ { KEY_SLASH, KEY_KPPLUS },
{ KEY_SEMICOLON, KEY_KPMINUS },
- { KEY_P, KEY_KPASTERISK },
- { KEY_MINUS, KEY_KPEQUAL },
- { KEY_0, KEY_KPSLASH },
- { KEY_F6, KEY_NUMLOCK },
- { KEY_KPENTER, KEY_KPENTER },
+ { KEY_P, KEY_KPASTERISK },
+ { KEY_MINUS, KEY_KPEQUAL },
+ { KEY_0, KEY_KPSLASH },
+ { KEY_F6, KEY_NUMLOCK },
+ { KEY_KPENTER, KEY_KPENTER },
{ KEY_BACKSPACE, KEY_BACKSPACE },
{ }
};
{ }
};
-static int usbhid_pb_fnmode = 1;
-module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
- "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
-
static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
{
struct hidinput_key_translation *trans;
}
static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
- struct hid_usage *usage, __s32 value)
+ struct hid_usage *usage, __s32 value)
{
struct hidinput_key_translation *trans;
return 1;
}
- if (usbhid_pb_fnmode) {
+ if (hid->pb_fnmode) {
int do_translate;
trans = find_translation(powerbook_fn_keys, usage->code);
do_translate = 1;
else if (trans->flags & POWERBOOK_FLAG_FKEY)
do_translate =
- (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
- (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+ (hid->pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+ (hid->pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
else
do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
}
if (test_bit(usage->code, hid->pb_pressed_numlock) ||
- test_bit(LED_NUML, input->led)) {
+ test_bit(LED_NUML, input->led)) {
trans = find_translation(powerbook_numlock_keys, usage->code);
if (trans) {
for (trans = powerbook_iso_keyboard; trans->from; trans++)
set_bit(trans->to, input->keybit);
+
}
#else
static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
- struct hid_usage *usage, __s32 value)
+ struct hid_usage *usage, __s32 value)
{
return 0;
}
|| ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
goto ignore;
+ if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
+ usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
+ field->flags &= ~HID_MAIN_ITEM_RELATIVE;
+
set_bit(usage->type, input->evbit);
while (usage->code <= max && test_and_set_bit(usage->code, bit))
list_for_each_entry(hidinput, &hid->inputs, list)
input_sync(hidinput->input);
}
+EXPORT_SYMBOL_GPL(hidinput_report_event);
-static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
{
struct hid_report *report;
int i, j;
}
return -1;
}
-
-static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct hid_device *hid = dev->private;
- struct hid_field *field;
- int offset;
-
- if (type == EV_FF)
- return input_ff_event(dev, type, code, value);
-
- if (type != EV_LED)
- return -1;
-
- if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
- warn("event field not found");
- return -1;
- }
-
- hid_set_field(field, offset, value);
- hid_submit_report(hid, field->report, USB_DIR_OUT);
-
- return 0;
-}
-
-static int hidinput_open(struct input_dev *dev)
-{
- struct hid_device *hid = dev->private;
- return hid_open(hid);
-}
-
-static void hidinput_close(struct input_dev *dev)
-{
- struct hid_device *hid = dev->private;
- hid_close(hid);
-}
+EXPORT_SYMBOL_GPL(hidinput_find_field);
/*
* Register the input device; print a message.
int hidinput_connect(struct hid_device *hid)
{
- struct usb_device *dev = hid->dev;
struct hid_report *report;
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
}
input_dev->private = hid;
- input_dev->event = hidinput_input_event;
- input_dev->open = hidinput_open;
- input_dev->close = hidinput_close;
+ input_dev->event = hid->hidinput_input_event;
+ input_dev->open = hid->hidinput_open;
+ input_dev->close = hid->hidinput_close;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
input_dev->uniq = hid->uniq;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &hid->intf->dev;
-
+ input_dev->id.bustype = hid->bus;
+ input_dev->id.vendor = hid->vendor;
+ input_dev->id.product = hid->product;
+ input_dev->id.version = hid->version;
+ input_dev->cdev.dev = hid->dev;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
}
}
- /* This only gets called when we are a single-input (most of the
- * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
- * only useful in this case, and not for multi-input quirks. */
- if (hidinput) {
- hid_ff_init(hid);
+ if (hidinput)
input_register_device(hidinput->input);
- }
return 0;
}
+EXPORT_SYMBOL_GPL(hidinput_connect);
void hidinput_disconnect(struct hid_device *hid)
{
kfree(hidinput);
}
}
+EXPORT_SYMBOL_GPL(hidinput_disconnect);
+
return -ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zd bytes.\n",
- iminor(file->f_dentry->d_inode), count);
+ iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_recv(client,tmp,count);
if (ret >= 0)
}
pr_debug("i2c-dev: i2c-%d writing %zd bytes.\n",
- iminor(file->f_dentry->d_inode), count);
+ iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_send(client,tmp,count);
kfree(tmp);
{
unsigned long flags;
u8 tmpbyte;
- struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+ struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0));
pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
- isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+ isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
if (!ali_proc) {
* clear bit 7
*/
pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
- local_irq_restore(flags);
- return 0;
+ goto out;
}
/*
* box without a device at 0:0.0. The ALi bridge will be at
* 0:0.0 so if we didn't find one we know what is cooking.
*/
- if (north && north->vendor != PCI_VENDOR_ID_AL) {
- local_irq_restore(flags);
- return 0;
- }
+ if (north && north->vendor != PCI_VENDOR_ID_AL)
+ goto out;
if (m5229_revision < 0xC5 && isa_dev)
{
pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
}
}
+out:
+ pci_dev_put(north);
+ pci_dev_put(isa_dev);
local_irq_restore(flags);
return 0;
}
* Split from:
* linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2005-2006 MontaVista Software, Inc.
* Portions Copyright (C) 1999 Promise Technology, Inc.
* Author: Frank Tiernan (frankt@promise.com)
* Released under terms of General Public License
*/
static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
{
- u8 speed;
-
- if (pio == 5) pio = 4;
- speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-
- (void)pdcnew_new_tune_chipset(drive, speed);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void)pdcnew_new_tune_chipset(drive, XFER_PIO_0 + pio);
}
static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
- if (!(speed)) {
- hwif->tuneproc(drive, 5);
+ if (!speed)
return 0;
- }
(void) hwif->speedproc(drive, speed);
return ide_dma_enable(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
- hwif->tuneproc(drive, 5);
+ hwif->tuneproc(drive, 255);
return hwif->ide_dma_off_quietly(drive);
}
/* IORDY not supported */
ide_pci_device_t *d)
{
struct pci_dev *findev = NULL;
+ int ret;
if ((dev->bus->self &&
dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
if (PCI_SLOT(dev->devfn) & 2)
return -ENODEV;
d->extra = 0;
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
+ while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
if ((findev->vendor == dev->vendor) &&
(findev->device == dev->device) &&
(PCI_SLOT(findev->devfn) & 2)) {
if (findev->irq != dev->irq) {
findev->irq = dev->irq;
}
- return ide_setup_pci_devices(dev, findev, d);
+ ret = ide_setup_pci_devices(dev, findev, d);
+ pci_dev_put(findev);
+ return ret;
}
}
}
if (trueid == 0x5517) { /* SiS 961/961B */
- lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */
+ lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */
pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
pci_read_config_byte(dev, 0x49, &prefctl);
+ pci_dev_put(lpc_bridge);
if (sbrev == 0x10 && (prefctl & 0x80)) {
printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n");
//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
- old = val = *((u32 *)&hwif->hwif_data);
+ old = val = (u32)pci_get_drvdata(dev);
if (drive->using_dma)
val &= ~mask;
else
val |= mask;
if (old != val) {
pci_write_config_dword(dev, 0x40, val);
- *((u32 *)&hwif->hwif_data) = val;
+ pci_set_drvdata(dev, (void *)val);
}
}
*/
static void sl82c105_resetproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
u32 val;
DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
pci_read_config_dword(dev, 0x40, &val);
- *((u32 *)&hwif->hwif_data) = val;
+ pci_set_drvdata(dev, (void *)val);
}
/*
pci_read_config_dword(dev, 0x40, &val);
val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
pci_write_config_dword(dev, 0x40, val);
+ pci_set_drvdata(dev, (void *)val);
return dev->irq;
}
static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
unsigned int rev;
u8 dma_state;
- u32 val;
-
+
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
hwif->tuneproc = tune_sl82c105;
hwif->selectproc = sl82c105_selectproc;
hwif->resetproc = sl82c105_resetproc;
-
- /* Default to PIO 0 for fallback unless tuned otherwise,
- * we always autotune PIO, this is done before DMA is
- * checked, so there is no risk of accidentally disabling
- * DMA
- */
+
+ /*
+ * Default to PIO 0 for fallback unless tuned otherwise.
+ * We always autotune PIO, this is done before DMA is checked,
+ * so there's no risk of accidentally disabling DMA
+ */
hwif->drives[0].pio_speed = XFER_PIO_0;
hwif->drives[0].autotune = 1;
- hwif->drives[1].pio_speed = XFER_PIO_1;
+ hwif->drives[1].pio_speed = XFER_PIO_0;
hwif->drives[1].autotune = 1;
- pci_read_config_dword(dev, 0x40, &val);
- *((u32 *)&hwif->hwif_data) = val;
-
hwif->atapi_dma = 0;
hwif->mwdma_mask = 0;
hwif->swdma_mask = 0;
/* return the index (within a minor number block) of a file */
static inline unsigned char ieee1394_file_to_instance(struct file *file)
{
- return file->f_dentry->d_inode->i_cindex;
+ return file->f_path.dentry->d_inode->i_cindex;
}
extern int hpsb_disable_irm;
* module reference.
*/
filp->f_op = fops_get(&uverbs_event_fops);
- filp->f_vfsmnt = mntget(uverbs_event_mnt);
- filp->f_dentry = dget(uverbs_event_mnt->mnt_root);
- filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_path.mnt = mntget(uverbs_event_mnt);
+ filp->f_path.dentry = dget(uverbs_event_mnt->mnt_root);
+ filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
filp->f_flags = O_RDONLY;
filp->f_mode = FMODE_READ;
filp->private_data = ev_file;
goto done;
}
- i_minor = iminor(fp->f_dentry->d_inode) - IPATH_USER_MINOR_BASE;
+ i_minor = iminor(fp->f_path.dentry->d_inode) - IPATH_USER_MINOR_BASE;
ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n",
- (long)fp->f_dentry->d_inode->i_rdev, i_minor);
+ (long)fp->f_path.dentry->d_inode->i_rdev, i_minor);
if (i_minor)
ret = find_free_port(i_minor - 1, fp, uinfo);
u16 i;
struct ipath_devdata *dd;
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
for (i = 0; i < NUM_COUNTERS; i++)
counters[i] = ipath_snap_cntr(dd, i);
struct ipath_devdata *dd;
u64 guid;
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
guid = be64_to_cpu(dd->ipath_guid);
u32 tmp, tmp2;
struct ipath_devdata *dd;
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
/* so we only initialize non-zero fields. */
memset(portinfo, 0, sizeof portinfo);
goto bail;
}
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
if (ipath_eeprom_read(dd, pos, tmp, count)) {
ipath_dev_err(dd, "failed to read from flash\n");
ret = -ENXIO;
goto bail_tmp;
}
- dd = file->f_dentry->d_inode->i_private;
+ dd = file->f_path.dentry->d_inode->i_private;
if (ipath_eeprom_write(dd, pos, tmp, count)) {
ret = -ENXIO;
ipath_dev_err(dd, "failed to write to flash\n");
props->max_map_per_fmr = 255;
else
props->max_map_per_fmr =
- (1 << (32 - long_log2(mdev->limits.num_mpts))) - 1;
+ (1 << (32 - ilog2(mdev->limits.num_mpts))) - 1;
err = 0;
out:
lkey = ucmd.lkey;
}
- ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, long_log2(entries), &status);
+ ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries), &status);
if (status)
ret = -EINVAL;
if (mthca_is_memfree(dev)) {
if (qp->rq.max)
- qp_context->rq_size_stride = long_log2(qp->rq.max) << 3;
+ qp_context->rq_size_stride = ilog2(qp->rq.max) << 3;
qp_context->rq_size_stride |= qp->rq.wqe_shift - 4;
if (qp->sq.max)
- qp_context->sq_size_stride = long_log2(qp->sq.max) << 3;
+ qp_context->sq_size_stride = ilog2(qp->sq.max) << 3;
qp_context->sq_size_stride |= qp->sq.wqe_shift - 4;
}
memset(context, 0, sizeof *context);
- logsize = long_log2(srq->max);
+ logsize = ilog2(srq->max);
context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn);
context->lkey = cpu_to_be32(srq->mr.ibmr.lkey);
context->db_index = cpu_to_be32(srq->db_index);
if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
return -EINVAL;
- srq->wqe_shift = long_log2(ds);
+ srq->wqe_shift = ilog2(ds);
srq->srqn = mthca_alloc(&dev->srq_table.alloc);
if (srq->srqn == -1)
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
mem = (void *)__get_free_pages(GFP_NOIO,
- long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+ ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else
mem = kmalloc(cmd_data_len, GFP_NOIO);
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
free_pages((unsigned long)mem_copy->copy_buf,
- long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+ ilog2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
else
kfree(mem_copy->copy_buf);
obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
+
}
/**
- * input_ff_erase - erase an effect from device
+ * input_ff_erase - erase a force-feedback effect from device
* @dev: input device to erase effect from
* @effect_id: id of the ffect to be erased
* @file: purported owner of the request
/**
* input_ff_free() - frees force feedback portion of input device
- * @dev: input device supporintg force feedback
+ * @dev: input device supporting force feedback
*
* This function is only needed in error path as input core will
* automatically free force feedback structures when device is
}
/**
- * input_ff_create_memless() - create memoryless FF device
+ * input_ff_create_memless() - create memoryless force-feedback device
* @dev: input device supporting force-feedback
* @data: driver-specific data to be passed into @play_effect
* @play_effect: driver-specific method for playing FF effect
return 0;
}
-static struct bus_type gameport_bus = {
- .name = "gameport",
- .probe = gameport_driver_probe,
- .remove = gameport_driver_remove,
-};
-
static void gameport_add_driver(struct gameport_driver *drv)
{
int error;
return !gameport_drv->ignore;
}
+static struct bus_type gameport_bus = {
+ .name = "gameport",
+ .dev_attrs = gameport_device_attrs,
+ .drv_attrs = gameport_driver_attrs,
+ .match = gameport_bus_match,
+ .probe = gameport_driver_probe,
+ .remove = gameport_driver_remove,
+};
+
static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)
{
mutex_lock(&gameport->drv_mutex);
int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)
{
-
if (gameport->open) {
if (gameport->open(gameport, mode)) {
return -1;
{
int error;
- gameport_bus.dev_attrs = gameport_device_attrs;
- gameport_bus.drv_attrs = gameport_driver_attrs;
- gameport_bus.match = gameport_bus_match;
error = bus_register(&gameport_bus);
if (error) {
printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
int i, cards = 0;
if (!request_region(L4_PORT, 1, "lightning"))
- return -1;
+ return -EBUSY;
for (i = 0; i < 2; i++)
if (l4_add_card(i) == 0)
if (!cards) {
release_region(L4_PORT, 1);
- return -1;
+ return -ENODEV;
}
return 0;
/**
* input_event() - report new input event
- * @handle: device that generated the event
+ * @dev: device that generated the event
* @type: type of the event
* @code: event code
* @value: value of the event
};
EXPORT_SYMBOL_GPL(input_class);
+/**
+ * input_allocate_device - allocate memory for new input device
+ *
+ * Returns prepared struct input_dev or NULL.
+ *
+ * NOTE: Use input_free_device() to free devices that have not been
+ * registered; input_unregister_device() should be used for already
+ * registered devices.
+ */
struct input_dev *input_allocate_device(void)
{
struct input_dev *dev;
}
EXPORT_SYMBOL(input_allocate_device);
+/**
+ * input_free_device - free memory occupied by input_dev structure
+ * @dev: input device to free
+ *
+ * This function should only be used if input_register_device()
+ * was not called yet or if it failed. Once device was registered
+ * use input_unregister_device() and memory will be freed once last
+ * refrence to the device is dropped.
+ *
+ * Device should be allocated by input_allocate_device().
+ *
+ * NOTE: If there are references to the input device then memory
+ * will not be freed until last reference is dropped.
+ */
void input_free_device(struct input_dev *dev)
{
if (dev) {
for (i = 0; i < 2; i++)
if (port->adi[i].length > 0) {
adi_init_center(port->adi + i);
- input_register_device(port->adi[i].dev);
+ err = input_register_device(port->adi[i].dev);
+ if (err)
+ goto fail3;
}
return 0;
+ fail3: while (--i >= 0) {
+ if (port->adi[i].length > 0) {
+ input_unregister_device(port->adi[i].dev);
+ port->adi[i].dev = NULL;
+ }
+ }
fail2: for (i = 0; i < 2; i++)
if (port->adi[i].dev)
input_free_device(port->adi[i].dev);
amijoy_dev[i]->absmax[ABS_X + j] = 1;
}
- input_register_device(amijoy_dev[i]);
+ err = input_register_device(amijoy_dev[i]);
+ if (err) {
+ input_free_device(amijoy_dev[i]);
+ goto fail;
+ }
}
return 0;
{
struct input_dev *input_dev;
int i, j, t, v, w, x, y, z;
+ int error;
analog_name(analog);
snprintf(analog->phys, sizeof(analog->phys),
analog_decode(analog, port->axes, port->initial, port->buttons);
- input_register_device(analog->dev);
+ error = input_register_device(analog->dev);
+ if (error) {
+ input_free_device(analog->dev);
+ return error;
+ }
return 0;
}
return 0;
fail3: while (--i >= 0)
- input_unregister_device(port->analog[i].dev);
+ if (port->analog[i].mask)
+ input_unregister_device(port->analog[i].dev);
fail2: gameport_close(gameport);
fail1: gameport_set_drvdata(gameport, NULL);
kfree(port);
for (j = 0; cobra_btn[j]; j++)
set_bit(cobra_btn[j], input_dev->keybit);
- input_register_device(cobra->dev[i]);
+ err = input_register_device(cobra->dev[i]);
+ if (err)
+ goto fail4;
}
return 0;
- fail3: for (i = 0; i < 2; i++)
+ fail4: input_free_device(cobra->dev[i]);
+ fail3: while (--i >= 0)
if (cobra->dev[i])
input_unregister_device(cobra->dev[i]);
fail2: gameport_close(gameport);
input_dev->absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
}
- input_register_device(gf2k->dev);
+ err = input_register_device(gf2k->dev);
+ if (err)
+ goto fail2;
return 0;
if (!port->registered) {
dbg("New Grip pad in multiport slot %d.\n", slot);
- register_slot(slot, grip);
+ if (register_slot(slot, grip)) {
+ port->mode = GRIP_MODE_RESET;
+ port->dirty = 0;
+ }
}
return flags;
}
struct grip_port *port = grip->port[slot];
struct input_dev *input_dev;
int j, t;
+ int err;
port->dev = input_dev = input_allocate_device();
if (!input_dev)
if (t > 0)
set_bit(t, input_dev->keybit);
- input_register_device(port->dev);
+ err = input_register_device(port->dev);
+ if (err) {
+ input_free_device(port->dev);
+ return err;
+ }
+
port->registered = 1;
if (port->dirty) /* report initial state, if any */
for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
set_bit(t, input_dev->keybit);
- input_register_device(guillemot->dev);
+ err = input_register_device(guillemot->dev);
+ if (err)
+ goto fail2;
return 0;
if (i == 20) { /* 5 seconds */
printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n");
- input_free_device(input_dev);
- return -ENODEV;
+ error = -ENODEV;
+ goto fail;
}
/*
set_bit(iforce->type->ff[i], input_dev->ffbit);
error = input_ff_create(input_dev, ff_effects);
- if (error) {
- input_free_device(input_dev);
- return error;
- }
+ if (error)
+ goto fail;
ff = input_dev->ff;
ff->upload = iforce_upload_effect;
* Register input device.
*/
- input_register_device(iforce->dev);
+ error = input_register_device(iforce->dev);
+ if (error)
+ goto fail;
printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open);
return 0;
+
+ fail: input_free_device(input_dev);
+ return error;
}
static int __init iforce_init(void)
{
+ int err = 0;
+
#ifdef CONFIG_JOYSTICK_IFORCE_USB
- usb_register(&iforce_usb_driver);
+ err = usb_register(&iforce_usb_driver);
+ if (err)
+ return err;
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
- serio_register_driver(&iforce_serio_drv);
+ err = serio_register_driver(&iforce_serio_drv);
+#ifdef CONFIG_JOYSTICK_IFORCE_USB
+ if (err)
+ usb_deregister(&iforce_usb_driver);
#endif
- return 0;
+#endif
+ return err;
}
static void __exit iforce_exit(void)
serio_set_drvdata(serio, iforce);
err = serio_open(serio, drv);
- if (err) {
- serio_set_drvdata(serio, NULL);
- kfree(iforce);
- return err;
- }
+ if (err)
+ goto fail1;
err = iforce_init_device(iforce);
- if (err) {
- serio_close(serio);
- serio_set_drvdata(serio, NULL);
- kfree(iforce);
- return -ENODEV;
- }
+ if (err)
+ goto fail2;
return 0;
+
+ fail2: serio_close(serio);
+ fail1: serio_set_drvdata(serio, NULL);
+ kfree(iforce);
+ return err;
}
static void iforce_serio_disconnect(struct serio *serio)
for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
set_bit(t, input_dev->keybit);
- input_register_device(interact->dev);
+ err = input_register_device(interact->dev);
+ if (err)
+ goto fail2;
return 0;
magellan = kzalloc(sizeof(struct magellan), GFP_KERNEL);
input_dev = input_allocate_device();
if (!magellan || !input_dev)
- goto fail;
+ goto fail1;
magellan->dev = input_dev;
snprintf(magellan->phys, sizeof(magellan->phys), "%s/input0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(magellan->dev);
+ if (err)
+ goto fail3;
- input_register_device(magellan->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(magellan);
return err;
}
static int __init magellan_init(void)
{
- serio_register_driver(&magellan_drv);
- return 0;
+ return serio_register_driver(&magellan_drv);
}
static void __exit magellan_exit(void)
spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL);
input_dev = input_allocate_device();
if (!spaceball || !input_dev)
- goto fail;
+ goto fail1;
spaceball->dev = input_dev;
snprintf(spaceball->phys, sizeof(spaceball->phys), "%s/input0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(spaceball->dev);
+ if (err)
+ goto fail3;
- input_register_device(spaceball->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(spaceball);
return err;
}
static int __init spaceball_init(void)
{
- serio_register_driver(&spaceball_drv);
- return 0;
+ return serio_register_driver(&spaceball_drv);
}
static void __exit spaceball_exit(void)
spaceorb = kzalloc(sizeof(struct spaceorb), GFP_KERNEL);
input_dev = input_allocate_device();
if (!spaceorb || !input_dev)
- goto fail;
+ goto fail1;
spaceorb->dev = input_dev;
snprintf(spaceorb->phys, sizeof(spaceorb->phys), "%s/input0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(spaceorb->dev);
+ if (err)
+ goto fail3;
- input_register_device(spaceorb->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(spaceorb);
return err;
}
static int __init spaceorb_init(void)
{
- serio_register_driver(&spaceorb_drv);
- return 0;
+ return serio_register_driver(&spaceorb_drv);
}
static void __exit spaceorb_exit(void)
stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL);
input_dev = input_allocate_device();
if (!stinger || !input_dev)
- goto fail;
+ goto fail1;
stinger->dev = input_dev;
snprintf(stinger->phys, sizeof(stinger->phys), "%s/serio0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(stinger->dev);
+ if (err)
+ goto fail3;
- input_register_device(stinger->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(stinger);
return err;
}
static int __init stinger_init(void)
{
- serio_register_driver(&stinger_drv);
- return 0;
+ return serio_register_driver(&stinger_drv);
}
static void __exit stinger_exit(void)
twidjoy = kzalloc(sizeof(struct twidjoy), GFP_KERNEL);
input_dev = input_allocate_device();
if (!twidjoy || !input_dev)
- goto fail;
+ goto fail1;
twidjoy->dev = input_dev;
snprintf(twidjoy->phys, sizeof(twidjoy->phys), "%s/input0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(twidjoy->dev);
+ if (err)
+ goto fail3;
- input_register_device(twidjoy->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(twidjoy);
return err;
}
static int __init twidjoy_init(void)
{
- serio_register_driver(&twidjoy_drv);
- return 0;
+ return serio_register_driver(&twidjoy_drv);
}
static void __exit twidjoy_exit(void)
warrior = kzalloc(sizeof(struct warrior), GFP_KERNEL);
input_dev = input_allocate_device();
if (!warrior || !input_dev)
- goto fail;
+ goto fail1;
warrior->dev = input_dev;
snprintf(warrior->phys, sizeof(warrior->phys), "%s/input0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(warrior->dev);
+ if (err)
+ goto fail3;
- input_register_device(warrior->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(warrior);
return err;
}
static int __init warrior_init(void)
{
- serio_register_driver(&warrior_drv);
- return 0;
+ return serio_register_driver(&warrior_drv);
}
static void __exit warrior_exit(void)
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
+config KEYBOARD_AAED2000
+ tristate "AAED-2000 keyboard"
+ depends on MACH_AAED2000
+ default y
+ help
+ Say Y here to enable the keyboard on the Agilent AAED-2000
+ development board.
+
+ To compile this driver as a module, choose M here: the
+ module will be called aaed2000_kbd.
+
endif
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
--- /dev/null
+/*
+ * Keyboard driver for the AAED-2000 dev board
+ *
+ * Copyright (c) 2006 Nicolas Bellido Y Ortega
+ *
+ * Based on corgikbd.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/aaed2000.h>
+
+#define KB_ROWS 12
+#define KB_COLS 8
+#define KB_ROWMASK(r) (1 << (r))
+#define SCANCODE(r,c) (((c) * KB_ROWS) + (r))
+#define NR_SCANCODES (KB_COLS * KB_ROWS)
+
+#define SCAN_INTERVAL (50) /* ms */
+#define KB_ACTIVATE_DELAY (20) /* us */
+
+static unsigned char aaedkbd_keycode[NR_SCANCODES] = {
+ KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, 0, KEY_SPACE, KEY_KP6, 0, KEY_KPDOT, 0, 0,
+ KEY_K, KEY_M, KEY_O, KEY_DOT, KEY_SLASH, 0, KEY_F, 0, 0, 0, KEY_LEFTSHIFT, 0,
+ KEY_I, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 0, 0, 0, 0, KEY_RIGHTSHIFT, 0,
+ KEY_8, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0,
+ KEY_J, KEY_H, KEY_B, KEY_KP8, KEY_KP4, 0, KEY_C, KEY_D, KEY_S, KEY_A, 0, KEY_CAPSLOCK,
+ KEY_Y, KEY_U, KEY_N, KEY_T, 0, 0, KEY_R, KEY_E, KEY_W, KEY_Q, 0, KEY_TAB,
+ KEY_7, KEY_6, KEY_G, 0, KEY_5, 0, KEY_4, KEY_3, KEY_2, KEY_1, 0, KEY_GRAVE,
+ 0, 0, KEY_COMMA, 0, KEY_KP2, 0, KEY_V, KEY_LEFTALT, KEY_X, KEY_Z, 0, KEY_LEFTCTRL
+};
+
+struct aaedkbd {
+ unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)];
+ struct input_dev *input;
+ struct work_struct workq;
+ int kbdscan_state[KB_COLS];
+ int kbdscan_count[KB_COLS];
+};
+
+#define KBDSCAN_STABLE_COUNT 2
+
+static void aaedkbd_report_col(struct aaedkbd *aaedkbd,
+ unsigned int col, unsigned int rowd)
+{
+ unsigned int scancode, pressed;
+ unsigned int row;
+
+ for (row = 0; row < KB_ROWS; row++) {
+ scancode = SCANCODE(row, col);
+ pressed = rowd & KB_ROWMASK(row);
+
+ input_report_key(aaedkbd->input, aaedkbd->keycode[scancode], pressed);
+ }
+}
+
+/* Scan the hardware keyboard and push any changes up through the input layer */
+static void aaedkbd_work(void *data)
+{
+ struct aaedkbd *aaedkbd = data;
+ unsigned int col, rowd;
+
+ col = 0;
+ do {
+ AAEC_GPIO_KSCAN = col + 8;
+ udelay(KB_ACTIVATE_DELAY);
+ rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN;
+
+ if (rowd != aaedkbd->kbdscan_state[col]) {
+ aaedkbd->kbdscan_count[col] = 0;
+ aaedkbd->kbdscan_state[col] = rowd;
+ } else if (++aaedkbd->kbdscan_count[col] >= KBDSCAN_STABLE_COUNT) {
+ aaedkbd_report_col(aaedkbd, col, rowd);
+ col++;
+ }
+ } while (col < KB_COLS);
+
+ AAEC_GPIO_KSCAN = 0x07;
+ input_sync(aaedkbd->input);
+
+ schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
+}
+
+static int aaedkbd_open(struct input_dev *indev)
+{
+ struct aaedkbd *aaedkbd = indev->private;
+
+ schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
+
+ return 0;
+}
+
+static void aaedkbd_close(struct input_dev *indev)
+{
+ struct aaedkbd *aaedkbd = indev->private;
+
+ cancel_delayed_work(&aaedkbd->workq);
+ flush_scheduled_work();
+}
+
+static int __devinit aaedkbd_probe(struct platform_device *pdev)
+{
+ struct aaedkbd *aaedkbd;
+ struct input_dev *input_dev;
+ int i;
+ int error;
+
+ aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!aaedkbd || !input_dev) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ platform_set_drvdata(pdev, aaedkbd);
+
+ aaedkbd->input = input_dev;
+
+ /* Init keyboard rescan workqueue */
+ INIT_WORK(&aaedkbd->workq, aaedkbd_work, aaedkbd);
+
+ memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode));
+
+ input_dev->name = "AAED-2000 Keyboard";
+ input_dev->phys = "aaedkbd/input0";
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->cdev.dev = &pdev->dev;
+ input_dev->private = aaedkbd;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->keycode = aaedkbd->keycode;
+ input_dev->keycodesize = sizeof(unsigned char);
+ input_dev->keycodemax = ARRAY_SIZE(aaedkbd_keycode);
+
+ for (i = 0; i < ARRAY_SIZE(aaedkbd_keycode); i++)
+ set_bit(aaedkbd->keycode[i], input_dev->keybit);
+ clear_bit(0, input_dev->keybit);
+
+ input_dev->open = aaedkbd_open;
+ input_dev->close = aaedkbd_close;
+
+ error = input_register_device(aaedkbd->input);
+ if (error)
+ goto fail;
+
+ return 0;
+
+ fail: kfree(aaedkbd);
+ input_free_device(input_dev);
+ return error;
+}
+
+static int __devexit aaedkbd_remove(struct platform_device *pdev)
+{
+ struct aaedkbd *aaedkbd = platform_get_drvdata(pdev);
+
+ input_unregister_device(aaedkbd->input);
+ kfree(aaedkbd);
+
+ return 0;
+}
+
+static struct platform_driver aaedkbd_driver = {
+ .probe = aaedkbd_probe,
+ .remove = __devexit_p(aaedkbd_remove),
+ .driver = {
+ .name = "aaed2000-keyboard",
+ },
+};
+
+static int __init aaedkbd_init(void)
+{
+ return platform_driver_register(&aaedkbd_driver);
+}
+
+static void __exit aaedkbd_exit(void)
+{
+ platform_driver_unregister(&aaedkbd_driver);
+}
+
+module_init(aaedkbd_init);
+module_exit(aaedkbd_exit);
+
+MODULE_AUTHOR("Nicolas Bellido Y Ortega");
+MODULE_DESCRIPTION("AAED-2000 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
int i, j;
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
- return -EIO;
+ return -ENODEV;
if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
return -EBUSY;
amikbd_dev = input_allocate_device();
if (!amikbd_dev) {
printk(KERN_ERR "amikbd: not enough memory for input device\n");
- release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto fail1;
}
amikbd_dev->name = "Amiga Keyboard";
memcpy(key_maps[i], temp_map, sizeof(temp_map));
}
ciaa.cra &= ~0x41; /* serial data in, turn off TA */
- request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt);
+ if (request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
+ amikbd_interrupt)) {
+ err = -EBUSY;
+ goto fail2;
+ }
+
+ err = input_register_device(amikbd_dev);
+ if (err)
+ goto fail3;
- input_register_device(amikbd_dev);
return 0;
+
+ fail3: free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
+ fail2: input_free_device(amikbd_dev);
+ fail1: release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
+ return err;
}
static void __exit amikbd_exit(void)
atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
dev = input_allocate_device();
if (!atkbd || !dev)
- goto fail;
+ goto fail1;
atkbd->dev = dev;
ps2_init(&atkbd->ps2dev, serio);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
if (atkbd->write) {
if (atkbd_probe(atkbd)) {
- serio_close(serio);
err = -ENODEV;
- goto fail;
+ goto fail3;
}
atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
+ err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
+ if (err)
+ goto fail3;
atkbd_enable(atkbd);
- input_register_device(atkbd->dev);
+ err = input_register_device(atkbd->dev);
+ if (err)
+ goto fail4;
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(dev);
+ fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(dev);
kfree(atkbd);
return err;
}
static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
{
- struct input_dev *new_dev;
+ struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
+ int err;
+ unsigned char old_extra, old_set;
if (!atkbd->write)
return -EIO;
if (atkbd->extra != value) {
/*
* Since device's properties will change we need to
- * unregister old device. But allocate new one first
- * to make sure we have it.
+ * unregister old device. But allocate and register
+ * new one first to make sure we have it.
*/
- if (!(new_dev = input_allocate_device()))
+ old_dev = atkbd->dev;
+ old_extra = atkbd->extra;
+ old_set = atkbd->set;
+
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
- input_unregister_device(atkbd->dev);
+
atkbd->dev = new_dev;
atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
atkbd_activate(atkbd);
+ atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(atkbd->dev);
+
+ err = input_register_device(atkbd->dev);
+ if (err) {
+ input_free_device(new_dev);
+
+ atkbd->dev = old_dev;
+ atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
+ atkbd_set_keycode_table(atkbd);
+ atkbd_set_device_attrs(atkbd);
+
+ return err;
+ }
+ input_unregister_device(old_dev);
+
}
return count;
}
static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
{
- struct input_dev *new_dev;
+ struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
+ int err;
+ unsigned char old_scroll;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
return -EINVAL;
if (atkbd->scroll != value) {
- if (!(new_dev = input_allocate_device()))
+ old_dev = atkbd->dev;
+ old_scroll = atkbd->scroll;
+
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
- input_unregister_device(atkbd->dev);
+
atkbd->dev = new_dev;
atkbd->scroll = value;
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(atkbd->dev);
+
+ err = input_register_device(atkbd->dev);
+ if (err) {
+ input_free_device(new_dev);
+
+ atkbd->scroll = old_scroll;
+ atkbd->dev = old_dev;
+ atkbd_set_keycode_table(atkbd);
+ atkbd_set_device_attrs(atkbd);
+
+ return err;
+ }
+ input_unregister_device(old_dev);
}
return count;
}
static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
{
- struct input_dev *new_dev;
+ struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
+ int err;
+ unsigned char old_set, old_extra;
if (!atkbd->write)
return -EIO;
return -EINVAL;
if (atkbd->set != value) {
- if (!(new_dev = input_allocate_device()))
+ old_dev = atkbd->dev;
+ old_extra = atkbd->extra;
+ old_set = atkbd->set;
+
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
- input_unregister_device(atkbd->dev);
+
atkbd->dev = new_dev;
atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
atkbd_activate(atkbd);
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- input_register_device(atkbd->dev);
+
+ err = input_register_device(atkbd->dev);
+ if (err) {
+ input_free_device(new_dev);
+
+ atkbd->dev = old_dev;
+ atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
+ atkbd_set_keycode_table(atkbd);
+ atkbd_set_device_attrs(atkbd);
+
+ return err;
+ }
+ input_unregister_device(old_dev);
}
return count;
}
static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
{
- struct input_dev *new_dev;
+ struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
+ int err;
+ unsigned char old_softrepeat, old_softraw;
if (!atkbd->write)
return -EIO;
return -EINVAL;
if (atkbd->softrepeat != value) {
- if (!(new_dev = input_allocate_device()))
+ old_dev = atkbd->dev;
+ old_softrepeat = atkbd->softrepeat;
+ old_softraw = atkbd->softraw;
+
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
- input_unregister_device(atkbd->dev);
+
atkbd->dev = new_dev;
atkbd->softrepeat = value;
if (atkbd->softrepeat)
atkbd->softraw = 1;
atkbd_set_device_attrs(atkbd);
- input_register_device(atkbd->dev);
+
+ err = input_register_device(atkbd->dev);
+ if (err) {
+ input_free_device(new_dev);
+
+ atkbd->dev = old_dev;
+ atkbd->softrepeat = old_softrepeat;
+ atkbd->softraw = old_softraw;
+ atkbd_set_device_attrs(atkbd);
+
+ return err;
+ }
+ input_unregister_device(old_dev);
}
return count;
}
static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
{
- struct input_dev *new_dev;
+ struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
+ int err;
+ unsigned char old_softraw;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
return -EINVAL;
if (atkbd->softraw != value) {
- if (!(new_dev = input_allocate_device()))
+ old_dev = atkbd->dev;
+ old_softraw = atkbd->softraw;
+
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
- input_unregister_device(atkbd->dev);
+
atkbd->dev = new_dev;
atkbd->softraw = value;
atkbd_set_device_attrs(atkbd);
- input_register_device(atkbd->dev);
+
+ err = input_register_device(atkbd->dev);
+ if (err) {
+ input_free_device(new_dev);
+
+ atkbd->dev = old_dev;
+ atkbd->softraw = old_softraw;
+ atkbd_set_device_attrs(atkbd);
+
+ return err;
+ }
+ input_unregister_device(old_dev);
}
return count;
}
static int __init atkbd_init(void)
{
- serio_register_driver(&atkbd_drv);
- return 0;
+ return serio_register_driver(&atkbd_drv);
}
static void __exit atkbd_exit(void)
{
struct corgikbd *corgikbd;
struct input_dev *input_dev;
- int i;
+ int i, err = -ENOMEM;
corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!corgikbd || !input_dev) {
- kfree(corgikbd);
- input_free_device(input_dev);
- return -ENOMEM;
- }
+ if (!corgikbd || !input_dev)
+ goto fail;
platform_set_drvdata(pdev, corgikbd);
set_bit(SW_TABLET_MODE, input_dev->swbit);
set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
- input_register_device(corgikbd->input);
+ err = input_register_device(corgikbd->input);
+ if (err)
+ goto fail;
mod_timer(&corgikbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
pxa_gpio_mode(CORGI_GPIO_AK_INT | GPIO_IN);
return 0;
+
+ fail: input_free_device(input_dev);
+ kfree(corgikbd);
+ return err;
}
static int corgikbd_remove(struct platform_device *pdev)
static int __init hil_kbd_init(void)
{
- serio_register_driver(&hil_kbd_serio_drv);
- return 0;
+ return serio_register_driver(&hil_kbd_serio_drv);
}
static void __exit hil_kbd_exit(void)
input_dev = input_allocate_device ();
if (!lk || !input_dev) {
err = -ENOMEM;
- goto fail;
+ goto fail1;
}
lk->serio = serio;
err = serio_open (serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device (lk->dev);
+ if (err)
+ goto fail3;
- input_register_device (lk->dev);
lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
return 0;
- fail: serio_set_drvdata (serio, NULL);
- input_free_device (input_dev);
+ fail3: serio_close (serio);
+ fail2: serio_set_drvdata (serio, NULL);
+ fail1: input_free_device (input_dev);
kfree (lk);
return err;
}
static int __init
lkkbd_init (void)
{
- serio_register_driver(&lkkbd_drv);
- return 0;
+ return serio_register_driver(&lkkbd_drv);
}
static void __exit
{
struct locomokbd *locomokbd;
struct input_dev *input_dev;
- int i, ret;
+ int i, err;
locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!locomokbd || !input_dev) {
- ret = -ENOMEM;
- goto free;
+ err = -ENOMEM;
+ goto err_free_mem;
}
/* try and claim memory region */
if (!request_mem_region((unsigned long) dev->mapbase,
dev->length,
LOCOMO_DRIVER_NAME(dev))) {
- ret = -EBUSY;
+ err = -EBUSY;
printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
- goto free;
+ goto err_free_mem;
}
locomokbd->ldev = dev;
clear_bit(0, input_dev->keybit);
/* attempt to get the interrupt */
- ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
- if (ret) {
+ err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
+ if (err) {
printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
- goto out;
+ goto err_release_region;
}
- input_register_device(locomokbd->input);
+ err = input_register_device(locomokbd->input);
+ if (err)
+ goto err_free_irq;
return 0;
-out:
+ err_free_irq:
+ free_irq(dev->irq[0], locomokbd);
+ err_release_region:
release_mem_region((unsigned long) dev->mapbase, dev->length);
locomo_set_drvdata(dev, NULL);
-free:
+ err_free_mem:
input_free_device(input_dev);
kfree(locomokbd);
- return ret;
+ return err;
}
static int locomokbd_remove(struct locomo_dev *dev)
+++ /dev/null
-/*
- * $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast keyboard driver
- * Based on drivers/usb/usbkbd.c
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/maple.h>
-
-MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
-MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
-MODULE_LICENSE("GPL");
-
-static unsigned char dc_kbd_keycode[256] = {
- 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
- 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
- 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
- 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
- 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
- 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
- 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
- 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
- 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
- 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
- 150,158,159,128,136,177,178,176,142,152,173,140
-};
-
-
-struct dc_kbd {
- struct input_dev *dev;
- unsigned char new[8];
- unsigned char old[8];
-};
-
-
-static void dc_scan_kbd(struct dc_kbd *kbd)
-{
- int i;
- struct input_dev *dev = kbd->dev;
-
- for (i = 0; i < 8; i++)
- input_report_key(dev, dc_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
-
- for (i = 2; i < 8; i++) {
-
- if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == NULL) {
- if (dc_kbd_keycode[kbd->old[i]])
- input_report_key(dev, dc_kbd_keycode[kbd->old[i]], 0);
- else
- printk("Unknown key (scancode %#x) released.",
- kbd->old[i]);
- }
-
- if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) != NULL) {
- if(dc_kbd_keycode[kbd->new[i]])
- input_report_key(dev, dc_kbd_keycode[kbd->new[i]], 1);
- else
- printk("Unknown key (scancode %#x) pressed.",
- kbd->new[i]);
- }
- }
-
- input_sync(dev);
-
- memcpy(kbd->old, kbd->new, 8);
-}
-
-
-static void dc_kbd_callback(struct mapleq *mq)
-{
- struct maple_device *mapledev = mq->dev;
- struct dc_kbd *kbd = mapledev->private_data;
- unsigned long *buf = mq->recvbuf;
-
- if (buf[1] == mapledev->function) {
- memcpy(kbd->new, buf + 2, 8);
- dc_scan_kbd(kbd);
- }
-}
-
-static int dc_kbd_connect(struct maple_device *dev)
-{
- struct dc_kbd *kbd;
- struct input_dev *input_dev;
- unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
- int i;
-
- dev->private_data = kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!kbd || !input_dev) {
- kfree(kbd);
- input_free_device(input_dev);
- return -ENOMEM;
- }
-
- kbd->dev = input_dev;
-
- input_dev->name = dev->product_name;
- input_dev->id.bustype = BUS_MAPLE;
- input_dev->private = kbd;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- for (i = 0; i < 255; i++)
- set_bit(dc_kbd_keycode[i], input_dev->keybit);
- clear_bit(0, input_dev->keybit);
-
- input_register_device(kbd->dev);
-
- maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
- return 0;
-}
-
-
-static void dc_kbd_disconnect(struct maple_device *dev)
-{
- struct dc_kbd *kbd = dev->private_data;
-
- input_unregister_device(kbd->dev);
- kfree(kbd);
-}
-
-
-static struct maple_driver dc_kbd_driver = {
- .function = MAPLE_FUNC_KEYBOARD,
- .name = "Dreamcast keyboard",
- .connect = dc_kbd_connect,
- .disconnect = dc_kbd_disconnect,
-};
-
-
-static int __init dc_kbd_init(void)
-{
- maple_register_driver(&dc_kbd_driver);
- return 0;
-}
-
-
-static void __exit dc_kbd_exit(void)
-{
- maple_unregister_driver(&dc_kbd_driver);
-}
-
-
-module_init(dc_kbd_init);
-module_exit(dc_kbd_exit);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!nkbd || !input_dev)
- goto fail;
+ goto fail1;
nkbd->serio = serio;
nkbd->dev = input_dev;
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(nkbd->dev);
+ if (err)
+ goto fail3;
- input_register_device(nkbd->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(nkbd);
return err;
}
static int __init nkbd_init(void)
{
- serio_register_driver(&nkbd_drv);
- return 0;
+ return serio_register_driver(&nkbd_drv);
}
static void __exit nkbd_exit(void)
{
struct spitzkbd *spitzkbd;
struct input_dev *input_dev;
- int i;
+ int i, err = -ENOMEM;
spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL);
- if (!spitzkbd)
- return -ENOMEM;
-
input_dev = input_allocate_device();
- if (!input_dev) {
- kfree(spitzkbd);
- return -ENOMEM;
- }
+ if (!spitzkbd || !input_dev)
+ goto fail;
platform_set_drvdata(dev, spitzkbd);
strcpy(spitzkbd->phys, "spitzkbd/input0");
set_bit(SW_TABLET_MODE, input_dev->swbit);
set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
- input_register_device(input_dev);
+ err = input_register_device(input_dev);
+ if (err)
+ goto fail;
mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd SWB", spitzkbd);
- request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
+ request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd HP", spitzkbd);
- printk(KERN_INFO "input: Spitz Keyboard Registered\n");
-
return 0;
+
+ fail: input_free_device(input_dev);
+ kfree(spitzkbd);
+ return err;
}
static int spitzkbd_remove(struct platform_device *dev)
.resume = spitzkbd_resume,
.driver = {
.name = "spitz-keyboard",
+ .owner = THIS_MODULE,
},
};
static int __init skbd_init(void)
{
- serio_register_driver(&skbd_drv);
- return 0;
+ return serio_register_driver(&skbd_drv);
}
static void __exit skbd_exit(void)
sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!sunkbd || !input_dev)
- goto fail;
+ goto fail1;
sunkbd->serio = serio;
sunkbd->dev = input_dev;
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
if (sunkbd_initialize(sunkbd) < 0) {
- serio_close(serio);
- goto fail;
+ err = -ENODEV;
+ goto fail3;
}
snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type);
clear_bit(0, input_dev->keybit);
sunkbd_enable(sunkbd, 1);
- input_register_device(sunkbd->dev);
+
+ err = input_register_device(sunkbd->dev);
+ if (err)
+ goto fail4;
+
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail4: sunkbd_enable(sunkbd, 0);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(sunkbd);
return err;
}
static int __init sunkbd_init(void)
{
- serio_register_driver(&sunkbd_drv);
- return 0;
+ return serio_register_driver(&sunkbd_drv);
}
static void __exit sunkbd_exit(void)
xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!xtkbd || !input_dev)
- goto fail;
+ goto fail1;
xtkbd->serio = serio;
xtkbd->dev = input_dev;
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(xtkbd->dev);
+ if (err)
+ goto fail3;
- input_register_device(xtkbd->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(xtkbd);
return err;
}
static int __init xtkbd_init(void)
{
- serio_register_driver(&xtkbd_drv);
- return 0;
+ return serio_register_driver(&xtkbd_drv);
}
static void __exit xtkbd_exit(void)
static int __init amimouse_init(void)
{
+ int err;
+
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
return -ENODEV;
- if (!(amimouse_dev = input_allocate_device()))
+ amimouse_dev = input_allocate_device();
+ if (!amimouse_dev)
return -ENOMEM;
amimouse_dev->name = "Amiga mouse";
amimouse_dev->open = amimouse_open;
amimouse_dev->close = amimouse_close;
- input_register_device(amimouse_dev);
+ err = input_register_device(amimouse_dev);
+ if (err) {
+ input_free_device(amimouse_dev);
+ return err;
+ }
return 0;
}
static int __init hil_ptr_init(void)
{
- serio_register_driver(&hil_ptr_serio_driver);
- return 0;
+ return serio_register_driver(&hil_ptr_serio_driver);
}
static void __exit hil_ptr_exit(void)
static int __init inport_init(void)
{
unsigned char a, b, c;
+ int err;
if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
b = inb(INPORT_SIGNATURE_PORT);
c = inb(INPORT_SIGNATURE_PORT);
if (a == b || a != c) {
- release_region(INPORT_BASE, INPORT_EXTENT);
printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
- return -ENODEV;
+ err = -ENODEV;
+ goto err_release_region;
}
- if (!(inport_dev = input_allocate_device())) {
+ inport_dev = input_allocate_device();
+ if (!inport_dev) {
printk(KERN_ERR "inport.c: Not enough memory for input device\n");
- release_region(INPORT_BASE, INPORT_EXTENT);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_release_region;
}
inport_dev->name = INPORT_NAME;
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
- input_register_device(inport_dev);
+ err = input_register_device(inport_dev);
+ if (err)
+ goto err_free_dev;
return 0;
+
+ err_free_dev:
+ input_free_device(inport_dev);
+ err_release_region:
+ release_region(INPORT_BASE, INPORT_EXTENT);
+
+ return err;
}
static void __exit inport_exit(void)
#include "lifebook.h"
static struct dmi_system_id lifebook_dmi_table[] = {
- {
- .ident = "LifeBook B",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
- },
- },
- {
- .ident = "Lifebook B",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
- },
- },
- {
- .ident = "Lifebook B213x/B2150",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
- },
- },
- {
- .ident = "Zephyr",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
- },
- },
- {
- .ident = "CF-18",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
- },
- },
- {
- .ident = "Lifebook B142",
- .matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
- },
-
- },
- { }
+ {
+ .ident = "FLORA-ie 55mi",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
+ },
+ },
+ {
+ .ident = "LifeBook B",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
+ },
+ },
+ {
+ .ident = "Lifebook B",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
+ },
+ },
+ {
+ .ident = "Lifebook B213x/B2150",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
+ },
+ },
+ {
+ .ident = "Zephyr",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
+ },
+ },
+ {
+ .ident = "CF-18",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
+ },
+ },
+ {
+ .ident = "Lifebook B142",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
+ },
+ },
+ { }
};
-
static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{
unsigned char *packet = psmouse->packet;
static int __init logibm_init(void)
{
+ int err;
+
if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) {
printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE);
return -EBUSY;
udelay(100);
if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
- release_region(LOGIBM_BASE, LOGIBM_EXTENT);
printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
- return -ENODEV;
+ err = -ENODEV;
+ goto err_release_region;
}
outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT);
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
- if (!(logibm_dev = input_allocate_device())) {
+ logibm_dev = input_allocate_device();
+ if (!logibm_dev) {
printk(KERN_ERR "logibm.c: Not enough memory for input device\n");
- release_region(LOGIBM_BASE, LOGIBM_EXTENT);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_release_region;
}
logibm_dev->name = "Logitech bus mouse";
logibm_dev->open = logibm_open;
logibm_dev->close = logibm_close;
- input_register_device(logibm_dev);
+ err = input_register_device(logibm_dev);
+ if (err)
+ goto err_free_dev;
return 0;
+
+ err_free_dev:
+ input_free_device(logibm_dev);
+ err_release_region:
+ release_region(LOGIBM_BASE, LOGIBM_EXTENT);
+
+ return err;
}
static void __exit logibm_exit(void)
unsigned char model, buttons;
const struct ps2pp_info *model_info;
int use_ps2pp = 0;
+ int error;
param[0] = 0;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse->set_resolution = ps2pp_set_resolution;
psmouse->disconnect = ps2pp_disconnect;
- device_create_file(&psmouse->ps2dev.serio->dev,
- &psmouse_attr_smartscroll.dattr);
+ error = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_smartscroll.dattr);
+ if (error) {
+ printk(KERN_ERR
+ "logips2pp.c: failed to create smartscroll "
+ "sysfs attribute, error: %d\n", error);
+ return -1;
+ }
}
}
static int __init pc110pad_init(void)
{
struct pci_dev *dev;
+ int err;
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev) {
outb(PC110PAD_OFF, pc110pad_io + 2);
if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) {
- release_region(pc110pad_io, 4);
printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
- return -EBUSY;
+ err = -EBUSY;
+ goto err_release_region;
}
- if (!(pc110pad_dev = input_allocate_device())) {
- free_irq(pc110pad_irq, NULL);
- release_region(pc110pad_io, 4);
+ pc110pad_dev = input_allocate_device();
+ if (!pc110pad_dev) {
printk(KERN_ERR "pc110pad: Not enough memory.\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_free_irq;
}
pc110pad_dev->name = "IBM PC110 TouchPad";
pc110pad_dev->open = pc110pad_open;
pc110pad_dev->close = pc110pad_close;
- input_register_device(pc110pad_dev);
+ err = input_register_device(pc110pad_dev);
+ if (err)
+ goto err_free_dev;
return 0;
+
+ err_free_dev:
+ input_free_device(pc110pad_dev);
+ err_free_irq:
+ free_irq(pc110pad_irq, NULL);
+ err_release_region:
+ release_region(pc110pad_io, 4);
+
+ return err;
}
static void __exit pc110pad_exit(void)
{
struct psmouse *psmouse, *parent = NULL;
struct input_dev *input_dev;
- int retval = -ENOMEM;
+ int retval = 0, error = -ENOMEM;
mutex_lock(&psmouse_mutex);
psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!psmouse || !input_dev)
- goto out;
+ goto err_free;
ps2_init(&psmouse->ps2dev, serio);
INIT_WORK(&psmouse->resync_work, psmouse_resync);
serio_set_drvdata(serio, psmouse);
- retval = serio_open(serio, drv);
- if (retval)
- goto out;
+ error = serio_open(serio, drv);
+ if (error)
+ goto err_clear_drvdata;
if (psmouse_probe(psmouse) < 0) {
- serio_close(serio);
- retval = -ENODEV;
- goto out;
+ error = -ENODEV;
+ goto err_close_serio;
}
psmouse->rate = psmouse_rate;
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
psmouse_initialize(psmouse);
- input_register_device(psmouse->dev);
+ error = input_register_device(psmouse->dev);
+ if (error)
+ goto err_protocol_disconnect;
if (parent && parent->pt_activate)
parent->pt_activate(parent);
- sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);
+ error = sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);
+ if (error)
+ goto err_pt_deactivate;
psmouse_activate(psmouse);
- retval = 0;
-
-out:
- if (retval) {
- serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
- kfree(psmouse);
- }
-
+ out:
/* If this is a pass-through port the parent needs to be re-activated */
if (parent)
psmouse_activate(parent);
mutex_unlock(&psmouse_mutex);
return retval;
+
+ err_pt_deactivate:
+ if (parent && parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+ err_protocol_disconnect:
+ if (psmouse->disconnect)
+ psmouse->disconnect(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ err_close_serio:
+ serio_close(serio);
+ err_clear_drvdata:
+ serio_set_drvdata(serio, NULL);
+ err_free:
+ input_free_device(input_dev);
+ kfree(psmouse);
+
+ retval = error;
+ goto out;
}
static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf)
{
- unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);
+ unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
- return sprintf(buf, "%lu\n", *field);
+ return sprintf(buf, "%u\n", *field);
}
static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count)
{
- unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);
+ unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
unsigned long value;
char *rest;
if (*rest)
return -EINVAL;
+ if ((unsigned int)value != value)
+ return -EINVAL;
+
*field = value;
return count;
{
struct serio *serio = psmouse->ps2dev.serio;
struct psmouse *parent = NULL;
- struct input_dev *new_dev;
- const struct psmouse_protocol *proto;
+ struct input_dev *old_dev, *new_dev;
+ const struct psmouse_protocol *proto, *old_proto;
+ int error;
int retry = 0;
- if (!(proto = psmouse_protocol_by_name(buf, count)))
+ proto = psmouse_protocol_by_name(buf, count);
+ if (!proto)
return -EINVAL;
if (psmouse->type == proto->type)
return count;
- if (!(new_dev = input_allocate_device()))
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
while (serio->child) {
parent->pt_deactivate(parent);
}
+ old_dev = psmouse->dev;
+ old_proto = psmouse_protocol_by_type(psmouse->type);
+
if (psmouse->disconnect)
psmouse->disconnect(psmouse);
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
- input_unregister_device(psmouse->dev);
psmouse->dev = new_dev;
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
psmouse_initialize(psmouse);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
- input_register_device(psmouse->dev);
+ error = input_register_device(psmouse->dev);
+ if (error) {
+ if (psmouse->disconnect)
+ psmouse->disconnect(psmouse);
+
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ input_free_device(new_dev);
+ psmouse->dev = old_dev;
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+ psmouse_switch_protocol(psmouse, old_proto);
+ psmouse_initialize(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+ return error;
+ }
+
+ input_unregister_device(old_dev);
if (parent && parent->pt_activate)
parent->pt_activate(parent);
static int __init psmouse_init(void)
{
+ int err;
+
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) {
printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
return -ENOMEM;
}
- serio_register_driver(&psmouse_drv);
+ err = serio_register_driver(&psmouse_drv);
+ if (err)
+ destroy_workqueue(kpsmoused_wq);
- return 0;
+ return err;
}
static void __exit psmouse_exit(void)
static int __init rpcmouse_init(void)
{
- if (!(rpcmouse_dev = input_allocate_device()))
+ int err;
+
+ rpcmouse_dev = input_allocate_device();
+ if (!rpcmouse_dev)
return -ENOMEM;
rpcmouse_dev->name = "Acorn RiscPC Mouse";
if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, IRQF_SHARED, "rpcmouse", rpcmouse_dev)) {
printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
- input_free_device(rpcmouse_dev);
- return -EBUSY;
+ err = -EBUSY;
+ goto err_free_dev;
}
- input_register_device(rpcmouse_dev);
+ err = input_register_device(rpcmouse_dev);
+ if (err)
+ goto err_free_irq;
return 0;
+
+ err_free_irq:
+ free_irq(IRQ_VSYNCPULSE, rpcmouse_dev);
+ err_free_dev:
+ input_free_device(rpcmouse_dev);
+
+ return err;
}
static void __exit rpcmouse_exit(void)
sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!sermouse || !input_dev)
- goto fail;
+ goto fail1;
sermouse->dev = input_dev;
snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys);
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
- input_register_device(sermouse->dev);
+ err = input_register_device(sermouse->dev);
+ if (err)
+ goto fail3;
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(sermouse);
return err;
}
static int __init sermouse_init(void)
{
- serio_register_driver(&sermouse_drv);
- return 0;
+ return serio_register_driver(&sermouse_drv);
}
static void __exit sermouse_exit(void)
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char firmware_id;
unsigned char button_info;
+ int error;
if (trackpoint_start_protocol(psmouse, &firmware_id))
return -1;
button_info = 0;
}
- psmouse->private = priv = kcalloc(1, sizeof(struct trackpoint_data), GFP_KERNEL);
+ psmouse->private = priv = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
if (!priv)
return -1;
trackpoint_defaults(priv);
trackpoint_sync(psmouse);
- sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
+ error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
+ if (error) {
+ printk(KERN_ERR
+ "trackpoint.c: failed to create sysfs attributes, error: %d\n",
+ error);
+ kfree(priv);
+ return -1;
+ }
printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n",
firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f);
mouse = kzalloc (sizeof (struct vsxxxaa), GFP_KERNEL);
input_dev = input_allocate_device ();
if (!mouse || !input_dev)
- goto fail;
+ goto fail1;
mouse->dev = input_dev;
mouse->serio = serio;
err = serio_open (serio, drv);
if (err)
- goto fail;
+ goto fail2;
/*
* Request selftest. Standard packet format and differential
*/
serio->write (serio, 'T'); /* Test */
- input_register_device (input_dev);
+ err = input_register_device (input_dev);
+ if (err)
+ goto fail3;
return 0;
- fail: serio_set_drvdata (serio, NULL);
- input_free_device (input_dev);
+ fail3: serio_close (serio);
+ fail2: serio_set_drvdata (serio, NULL);
+ fail1: input_free_device (input_dev);
kfree (mouse);
return err;
}
static int __init
vsxxxaa_init (void)
{
- serio_register_driver(&vsxxxaa_drv);
- return 0;
+ return serio_register_driver(&vsxxxaa_drv);
}
static void __exit
switch (code) {
case BTN_TOUCH:
case BTN_0:
- case BTN_FORWARD:
case BTN_LEFT: index = 0; break;
case BTN_STYLUS:
case BTN_1:
case BTN_RIGHT: index = 1; break;
case BTN_2:
+ case BTN_FORWARD:
case BTN_STYLUS2:
case BTN_MIDDLE: index = 2; break;
case BTN_3:
DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
},
},
+ {
+ .ident = "Fujitsu Lifebook P7010",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"),
+ },
+ },
{
.ident = "Fujitsu Lifebook P5020D",
.matches = {
static int i8042_aux_write(struct serio *serio, unsigned char c)
{
struct i8042_port *port = serio->port_data;
- int retval;
-
-/*
- * Send the byte out.
- */
-
- if (port->mux == -1)
- retval = i8042_command(&c, I8042_CMD_AUX_SEND);
- else
- retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux);
-
-/*
- * Make sure the interrupt happens and the character is received even
- * in the case the IRQ isn't wired, so that we can receive further
- * characters later.
- */
- i8042_interrupt(0, NULL);
- return retval;
+ return i8042_command(&c, port->mux == -1 ?
+ I8042_CMD_AUX_SEND :
+ I8042_CMD_MUX_SEND + port->mux);
}
/*
dfl = 0;
if (str & I8042_STR_MUXERR) {
dbg("MUX error, status is %02x, data is %02x", str, data);
- switch (data) {
- default:
/*
* When MUXERR condition is signalled the data register can only contain
* 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
- * it is not always the case. Some KBC just get confused which port the
- * data came from and signal error leaving the data intact. They _do not_
- * revert to legacy mode (actually I've never seen KBC reverting to legacy
- * mode yet, when we see one we'll add proper handling).
- * Anyway, we will assume that the data came from the same serio last byte
+ * it is not always the case. Some KBCs also report 0xfc when there is
+ * nothing connected to the port while others sometimes get confused which
+ * port the data came from and signal error leaving the data intact. They
+ * _do not_ revert to legacy mode (actually I've never seen KBC reverting
+ * to legacy mode yet, when we see one we'll add proper handling).
+ * Anyway, we process 0xfc, 0xfd, 0xfe and 0xff as timeouts, and for the
+ * rest assume that the data came from the same serio last byte
* was transmitted (if transmission happened not too long ago).
*/
+
+ switch (data) {
+ default:
if (time_before(jiffies, last_transmit + HZ/10)) {
str = last_str;
break;
}
/* fall through - report timeout */
+ case 0xfc:
case 0xfd:
case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
case 0xff: dfl = SERIO_PARITY; data = 0xfe; break;
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(__serio_unregister_port_delayed);
-EXPORT_SYMBOL(__serio_register_driver);
+EXPORT_SYMBOL(serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
static struct bus_type serio_bus;
-static void serio_add_driver(struct serio_driver *drv);
static void serio_add_port(struct serio *serio);
-static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
+static void serio_attach_driver(struct serio_driver *drv);
static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
{
*/
enum serio_event_type {
- SERIO_RESCAN,
- SERIO_RECONNECT,
+ SERIO_RESCAN_PORT,
+ SERIO_RECONNECT_PORT,
SERIO_REGISTER_PORT,
- SERIO_UNREGISTER_PORT,
- SERIO_REGISTER_DRIVER,
+ SERIO_ATTACH_DRIVER,
};
struct serio_event {
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static struct task_struct *serio_task;
-static void serio_queue_event(void *object, struct module *owner,
- enum serio_event_type event_type)
+static int serio_queue_event(void *object, struct module *owner,
+ enum serio_event_type event_type)
{
unsigned long flags;
struct serio_event *event;
+ int retval = 0;
spin_lock_irqsave(&serio_event_lock, flags);
}
}
- if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
- if (!try_module_get(owner)) {
- printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type);
- kfree(event);
- goto out;
- }
-
- event->type = event_type;
- event->object = object;
- event->owner = owner;
+ event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
+ if (!event) {
+ printk(KERN_ERR
+ "serio: Not enough memory to queue event %d\n",
+ event_type);
+ retval = -ENOMEM;
+ goto out;
+ }
- list_add_tail(&event->node, &serio_event_list);
- wake_up(&serio_wait);
- } else {
- printk(KERN_ERR "serio: Not enough memory to queue event %d\n", event_type);
+ if (!try_module_get(owner)) {
+ printk(KERN_WARNING
+ "serio: Can't get module reference, dropping event %d\n",
+ event_type);
+ kfree(event);
+ retval = -EINVAL;
+ goto out;
}
+
+ event->type = event_type;
+ event->object = object;
+ event->owner = owner;
+
+ list_add_tail(&event->node, &serio_event_list);
+ wake_up(&serio_wait);
+
out:
spin_unlock_irqrestore(&serio_event_lock, flags);
+ return retval;
}
static void serio_free_event(struct serio_event *event)
serio_add_port(event->object);
break;
- case SERIO_UNREGISTER_PORT:
- serio_disconnect_port(event->object);
- serio_destroy_port(event->object);
- break;
-
- case SERIO_RECONNECT:
+ case SERIO_RECONNECT_PORT:
serio_reconnect_port(event->object);
break;
- case SERIO_RESCAN:
+ case SERIO_RESCAN_PORT:
serio_disconnect_port(event->object);
serio_find_driver(event->object);
break;
- case SERIO_REGISTER_DRIVER:
- serio_add_driver(event->object);
+ case SERIO_ATTACH_DRIVER:
+ serio_attach_driver(event->object);
break;
default:
void serio_rescan(struct serio *serio)
{
- serio_queue_event(serio, NULL, SERIO_RESCAN);
+ serio_queue_event(serio, NULL, SERIO_RESCAN_PORT);
}
void serio_reconnect(struct serio *serio)
{
- serio_queue_event(serio, NULL, SERIO_RECONNECT);
+ serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
}
/*
mutex_unlock(&serio_mutex);
}
-/*
- * Submits register request to kseriod for subsequent execution.
- * Can be used when it is not obvious whether the serio_mutex is
- * taken or not and when delayed execution is feasible.
- */
-void __serio_unregister_port_delayed(struct serio *serio, struct module *owner)
-{
- serio_queue_event(serio, owner, SERIO_UNREGISTER_PORT);
-}
-
/*
* Serio driver operations
return 0;
}
-static struct bus_type serio_bus = {
- .name = "serio",
- .probe = serio_driver_probe,
- .remove = serio_driver_remove,
-};
-
-static void serio_add_driver(struct serio_driver *drv)
+static void serio_attach_driver(struct serio_driver *drv)
{
int error;
- error = driver_register(&drv->driver);
+ error = driver_attach(&drv->driver);
if (error)
- printk(KERN_ERR
- "serio: driver_register() failed for %s, error: %d\n",
+ printk(KERN_WARNING
+ "serio: driver_attach() failed for %s with error %d\n",
drv->driver.name, error);
}
-void __serio_register_driver(struct serio_driver *drv, struct module *owner)
+int serio_register_driver(struct serio_driver *drv)
{
+ int manual_bind = drv->manual_bind;
+ int error;
+
drv->driver.bus = &serio_bus;
- serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER);
+ /*
+ * Temporarily disable automatic binding because probing
+ * takes long time and we are better off doing it in kseriod
+ */
+ drv->manual_bind = 1;
+
+ error = driver_register(&drv->driver);
+ if (error) {
+ printk(KERN_ERR
+ "serio: driver_register() failed for %s, error: %d\n",
+ drv->driver.name, error);
+ return error;
+ }
+
+ /*
+ * Restore original bind mode and let kseriod bind the
+ * driver to free ports
+ */
+ if (!manual_bind) {
+ drv->manual_bind = 0;
+ error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER);
+ if (error) {
+ driver_unregister(&drv->driver);
+ return error;
+ }
+ }
+
+ return 0;
}
void serio_unregister_driver(struct serio_driver *drv)
return ret;
}
+static struct bus_type serio_bus = {
+ .name = "serio",
+ .dev_attrs = serio_device_attrs,
+ .drv_attrs = serio_driver_attrs,
+ .match = serio_bus_match,
+ .uevent = serio_uevent,
+ .probe = serio_driver_probe,
+ .remove = serio_driver_remove,
+ .resume = serio_resume,
+};
+
static int __init serio_init(void)
{
int error;
- serio_bus.dev_attrs = serio_device_attrs;
- serio_bus.drv_attrs = serio_driver_attrs;
- serio_bus.match = serio_bus_match;
- serio_bus.uevent = serio_uevent;
- serio_bus.resume = serio_resume;
error = bus_register(&serio_bus);
if (error) {
printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
static int __init serio_raw_init(void)
{
- serio_register_driver(&serio_raw_drv);
- return 0;
+ return serio_register_driver(&serio_raw_drv);
}
static void __exit serio_raw_exit(void)
To compile this driver as a module, choose M here: the
module will be called touchwin.
+config TOUCHSCREEN_UCB1400
+ tristate "Philips UCB1400 touchscreen"
+ select SND_AC97_BUS
+ help
+ This enables support for the Philips UCB1400 touchscreen interface.
+ The UCB1400 is an AC97 audio codec. The touchscreen interface
+ will be initialized only after the ALSA subsystem has been
+ brought up and the UCB1400 detected. You therefore have to
+ configure ALSA support as well (either built-in or modular,
+ independently of whether this driver is itself built-in or
+ modular) for this driver to work.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ucb1400_ts.
+
endif
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
char phys[32];
struct spi_device *spi;
+ struct attribute_group *attr_group;
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
+static struct attribute *ads7846_attributes[] = {
+ &dev_attr_temp0.attr,
+ &dev_attr_temp1.attr,
+ &dev_attr_vbatt.attr,
+ &dev_attr_vaux.attr,
+ &dev_attr_pen_down.attr,
+ &dev_attr_disable.attr,
+ NULL,
+};
+
+static struct attribute_group ads7846_attr_group = {
+ .attrs = ads7846_attributes,
+};
+
+/*
+ * ads7843/7845 don't have temperature sensors, and
+ * use the other sensors a bit differently too
+ */
+
+static struct attribute *ads7843_attributes[] = {
+ &dev_attr_vbatt.attr,
+ &dev_attr_vaux.attr,
+ &dev_attr_pen_down.attr,
+ &dev_attr_disable.attr,
+ NULL,
+};
+
+static struct attribute_group ads7843_attr_group = {
+ .attrs = ads7843_attributes,
+};
+
+static struct attribute *ads7845_attributes[] = {
+ &dev_attr_vaux.attr,
+ &dev_attr_pen_down.attr,
+ &dev_attr_disable.attr,
+ NULL,
+};
+
+static struct attribute_group ads7845_attr_group = {
+ .attrs = ads7845_attributes,
+};
+
/*--------------------------------------------------------------------------*/
/*
(void) ads7846_read12_ser(&spi->dev,
READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
- /* ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
- if (ts->model == 7846) {
- device_create_file(&spi->dev, &dev_attr_temp0);
- device_create_file(&spi->dev, &dev_attr_temp1);
+ switch (ts->model) {
+ case 7846:
+ ts->attr_group = &ads7846_attr_group;
+ break;
+ case 7845:
+ ts->attr_group = &ads7845_attr_group;
+ break;
+ default:
+ ts->attr_group = &ads7843_attr_group;
+ break;
}
- if (ts->model != 7845)
- device_create_file(&spi->dev, &dev_attr_vbatt);
- device_create_file(&spi->dev, &dev_attr_vaux);
-
- device_create_file(&spi->dev, &dev_attr_pen_down);
-
- device_create_file(&spi->dev, &dev_attr_disable);
+ err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+ if (err)
+ goto err_free_irq;
err = input_register_device(input_dev);
if (err)
- goto err_remove_attr;
+ goto err_remove_attr_group;
return 0;
- err_remove_attr:
- device_remove_file(&spi->dev, &dev_attr_disable);
- device_remove_file(&spi->dev, &dev_attr_pen_down);
- if (ts->model == 7846) {
- device_remove_file(&spi->dev, &dev_attr_temp1);
- device_remove_file(&spi->dev, &dev_attr_temp0);
- }
- if (ts->model != 7845)
- device_remove_file(&spi->dev, &dev_attr_vbatt);
- device_remove_file(&spi->dev, &dev_attr_vaux);
-
+ err_remove_attr_group:
+ sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ err_free_irq:
free_irq(spi->irq, ts);
err_free_mem:
input_free_device(input_dev);
ads7846_suspend(spi, PMSG_SUSPEND);
- device_remove_file(&spi->dev, &dev_attr_disable);
- device_remove_file(&spi->dev, &dev_attr_pen_down);
- if (ts->model == 7846) {
- device_remove_file(&spi->dev, &dev_attr_temp1);
- device_remove_file(&spi->dev, &dev_attr_temp0);
- }
- if (ts->model != 7845)
- device_remove_file(&spi->dev, &dev_attr_vbatt);
- device_remove_file(&spi->dev, &dev_attr_vaux);
+ sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
free_irq(ts->spi->irq, ts);
/* suspend left the IRQ disabled */
static void new_data(struct corgi_ts *corgi_ts)
{
+ struct input_dev *dev = corgi_ts->input;
+
if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
return;
if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
return;
- input_report_abs(corgi_ts->input, ABS_X, corgi_ts->tc.x);
- input_report_abs(corgi_ts->input, ABS_Y, corgi_ts->tc.y);
- input_report_abs(corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
- input_report_key(corgi_ts->input, BTN_TOUCH, (corgi_ts->pendown != 0));
- input_sync(corgi_ts->input);
+ input_report_abs(dev, ABS_X, corgi_ts->tc.x);
+ input_report_abs(dev, ABS_Y, corgi_ts->tc.y);
+ input_report_abs(dev, ABS_PRESSURE, corgi_ts->tc.pressure);
+ input_report_key(dev, BTN_TOUCH, corgi_ts->pendown);
+ input_sync(dev);
}
static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer)
static void corgi_ts_timer(unsigned long data)
{
struct corgi_ts *corgits_data = (struct corgi_ts *) data;
+
ts_interrupt_main(corgits_data, 1);
}
static irqreturn_t ts_interrupt(int irq, void *dev_id)
{
struct corgi_ts *corgits_data = dev_id;
+
ts_interrupt_main(corgits_data, 0);
return IRQ_HANDLED;
}
corgi_ts = kzalloc(sizeof(struct corgi_ts), GFP_KERNEL);
input_dev = input_allocate_device();
if (!corgi_ts || !input_dev)
- goto fail;
+ goto fail1;
platform_set_drvdata(pdev, corgi_ts);
if (corgi_ts->irq_gpio < 0) {
err = -ENODEV;
- goto fail;
+ goto fail1;
}
corgi_ts->input = input_dev;
if (request_irq(corgi_ts->irq_gpio, ts_interrupt, IRQF_DISABLED, "ts", corgi_ts)) {
err = -EBUSY;
- goto fail;
+ goto fail1;
}
- input_register_device(corgi_ts->input);
+ err = input_register_device(corgi_ts->input);
+ if (err)
+ goto fail2;
corgi_ts->power_mode = PWR_MODE_ACTIVE;
return 0;
- fail: input_free_device(input_dev);
+ fail2: free_irq(corgi_ts->irq_gpio, corgi_ts);
+ fail1: input_free_device(input_dev);
kfree(corgi_ts);
return err;
-
}
static int corgits_remove(struct platform_device *pdev)
{
struct corgi_ts *corgi_ts = platform_get_drvdata(pdev);
- free_irq(corgi_ts->irq_gpio, NULL);
+ free_irq(corgi_ts->irq_gpio, corgi_ts);
del_timer_sync(&corgi_ts->timer);
corgi_ts->machinfo->put_hsync();
input_unregister_device(corgi_ts->input);
static int __init elo_init(void)
{
- serio_register_driver(&elo_drv);
- return 0;
+ return serio_register_driver(&elo_drv);
}
static void __exit elo_exit(void)
input_dev = input_allocate_device();
if (!gunze || !input_dev) {
err = -ENOMEM;
- goto fail;
+ goto fail1;
}
gunze->serio = serio;
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
+
+ err = input_register_device(gunze->dev);
+ if (err)
+ goto fail3;
- input_register_device(gunze->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(gunze);
return err;
}
static int __init gunze_init(void)
{
- serio_register_driver(&gunze_drv);
- return 0;
+ return serio_register_driver(&gunze_drv);
}
static void __exit gunze_exit(void)
static int __init h3600ts_init(void)
{
- serio_register_driver(&h3600ts_drv);
- return 0;
+ return serio_register_driver(&h3600ts_drv);
}
static void __exit h3600ts_exit(void)
static int __init hp680_ts_init(void)
{
+ int err;
+
hp680_ts_dev = input_allocate_device();
if (!hp680_ts_dev)
return -ENOMEM;
hp680_ts_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
- hp680_ts_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
hp680_ts_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
- hp680_ts_dev->absmin[ABS_X] = HP680_TS_ABS_X_MIN;
- hp680_ts_dev->absmin[ABS_Y] = HP680_TS_ABS_Y_MIN;
- hp680_ts_dev->absmax[ABS_X] = HP680_TS_ABS_X_MAX;
- hp680_ts_dev->absmax[ABS_Y] = HP680_TS_ABS_Y_MAX;
+ input_set_abs_params(hp680_ts_dev, ABS_X,
+ HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
+ input_set_abs_params(hp680_ts_dev, ABS_Y,
+ HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
hp680_ts_dev->name = "HP Jornada touchscreen";
hp680_ts_dev->phys = "hp680_ts/input0";
- input_register_device(hp680_ts_dev);
-
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
IRQF_DISABLED, MODNAME, 0) < 0) {
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
HP680_TS_IRQ);
- input_unregister_device(hp680_ts_dev);
- return -EBUSY;
+ err = -EBUSY;
+ goto fail1;
}
+ err = input_register_device(hp680_ts_dev);
+ if (err)
+ goto fail2;
+
return 0;
+
+ fail2: free_irq(HP680_TS_IRQ, NULL);
+ cancel_delayed_work(&work);
+ flush_scheduled_work();
+ fail1: input_free_device(hp680_ts_dev);
+ return err;
}
static void __exit hp680_ts_exit(void)
{
- free_irq(HP680_TS_IRQ, 0);
+ free_irq(HP680_TS_IRQ, NULL);
cancel_delayed_work(&work);
flush_scheduled_work();
input_unregister_device(hp680_ts_dev);
goto end;
}
- if (~status & MK712_STATUS_TOUCH)
- {
+ if (~status & MK712_STATUS_TOUCH) {
debounce = 1;
input_report_key(mk712_dev, BTN_TOUCH, 0);
goto end;
}
- if (debounce)
- {
+ if (debounce) {
debounce = 0;
goto end;
}
input_report_abs(mk712_dev, ABS_X, last_x);
input_report_abs(mk712_dev, ABS_Y, last_y);
-end:
-
+ end:
last_x = inw(mk712_io + MK712_X) & 0x0fff;
last_y = inw(mk712_io + MK712_Y) & 0x0fff;
input_sync(mk712_dev);
(inw(mk712_io + MK712_STATUS) & 0xf333)) {
printk(KERN_WARNING "mk712: device not present\n");
err = -ENODEV;
- goto fail;
+ goto fail1;
}
- if (!(mk712_dev = input_allocate_device())) {
+ mk712_dev = input_allocate_device();
+ if (!mk712_dev) {
printk(KERN_ERR "mk712: not enough memory\n");
err = -ENOMEM;
- goto fail;
+ goto fail1;
}
mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
printk(KERN_WARNING "mk712: unable to get IRQ\n");
err = -EBUSY;
- goto fail;
+ goto fail1;
}
- input_register_device(mk712_dev);
+ err = input_register_device(mk712_dev);
+ if (err)
+ goto fail2;
+
return 0;
- fail: input_free_device(mk712_dev);
+ fail2: free_irq(mk712_irq, mk712_dev);
+ fail1: input_free_device(mk712_dev);
release_region(mk712_io, 8);
return err;
}
input_dev = input_allocate_device();
if (!mtouch || !input_dev) {
err = -ENOMEM;
- goto fail;
+ goto fail1;
}
mtouch->serio = serio;
err = serio_open(serio, drv);
if (err)
- goto fail;
+ goto fail2;
- input_register_device(mtouch->dev);
+ err = input_register_device(mtouch->dev);
+ if (err)
+ goto fail3;
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(mtouch);
return err;
}
static int __init mtouch_init(void)
{
- serio_register_driver(&mtouch_drv);
- return 0;
+ return serio_register_driver(&mtouch_drv);
}
static void __exit mtouch_exit(void)
static int __init pm_init(void)
{
- serio_register_driver(&pm_drv);
- return 0;
+ return serio_register_driver(&pm_drv);
}
static void __exit pm_exit(void)
static int __init tr_init(void)
{
- serio_register_driver(&tr_drv);
- return 0;
+ return serio_register_driver(&tr_drv);
}
static void __exit tr_exit(void)
static int __init tw_init(void)
{
- serio_register_driver(&tw_drv);
- return 0;
+ return serio_register_driver(&tw_drv);
}
static void __exit tw_exit(void)
--- /dev/null
+/*
+ * Philips UCB1400 touchscreen driver
+ *
+ * Author: Nicolas Pitre
+ * Created: September 25, 2006
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This code is heavily based on ucb1x00-*.c copyrighted by Russell King
+ * covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
+ * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/suspend.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+
+
+/*
+ * Interesting UCB1400 AC-link registers
+ */
+
+#define UCB_IE_RIS 0x5e
+#define UCB_IE_FAL 0x60
+#define UCB_IE_STATUS 0x62
+#define UCB_IE_CLEAR 0x62
+#define UCB_IE_ADC (1 << 11)
+#define UCB_IE_TSPX (1 << 12)
+
+#define UCB_TS_CR 0x64
+#define UCB_TS_CR_TSMX_POW (1 << 0)
+#define UCB_TS_CR_TSPX_POW (1 << 1)
+#define UCB_TS_CR_TSMY_POW (1 << 2)
+#define UCB_TS_CR_TSPY_POW (1 << 3)
+#define UCB_TS_CR_TSMX_GND (1 << 4)
+#define UCB_TS_CR_TSPX_GND (1 << 5)
+#define UCB_TS_CR_TSMY_GND (1 << 6)
+#define UCB_TS_CR_TSPY_GND (1 << 7)
+#define UCB_TS_CR_MODE_INT (0 << 8)
+#define UCB_TS_CR_MODE_PRES (1 << 8)
+#define UCB_TS_CR_MODE_POS (2 << 8)
+#define UCB_TS_CR_BIAS_ENA (1 << 11)
+#define UCB_TS_CR_TSPX_LOW (1 << 12)
+#define UCB_TS_CR_TSMX_LOW (1 << 13)
+
+#define UCB_ADC_CR 0x66
+#define UCB_ADC_SYNC_ENA (1 << 0)
+#define UCB_ADC_VREFBYP_CON (1 << 1)
+#define UCB_ADC_INP_TSPX (0 << 2)
+#define UCB_ADC_INP_TSMX (1 << 2)
+#define UCB_ADC_INP_TSPY (2 << 2)
+#define UCB_ADC_INP_TSMY (3 << 2)
+#define UCB_ADC_INP_AD0 (4 << 2)
+#define UCB_ADC_INP_AD1 (5 << 2)
+#define UCB_ADC_INP_AD2 (6 << 2)
+#define UCB_ADC_INP_AD3 (7 << 2)
+#define UCB_ADC_EXT_REF (1 << 5)
+#define UCB_ADC_START (1 << 7)
+#define UCB_ADC_ENA (1 << 15)
+
+#define UCB_ADC_DATA 0x68
+#define UCB_ADC_DAT_VALID (1 << 15)
+#define UCB_ADC_DAT_VALUE(x) ((x) & 0x3ff)
+
+#define UCB_ID 0x7e
+#define UCB_ID_1400 0x4304
+
+
+struct ucb1400 {
+ ac97_t *ac97;
+ struct input_dev *ts_idev;
+
+ int irq;
+
+ wait_queue_head_t ts_wait;
+ struct task_struct *ts_task;
+
+ unsigned int irq_pending; /* not bit field shared */
+ unsigned int ts_restart:1;
+ unsigned int adcsync:1;
+};
+
+static int adcsync;
+
+static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg)
+{
+ return ucb->ac97->bus->ops->read(ucb->ac97, reg);
+}
+
+static inline void ucb1400_reg_write(struct ucb1400 *ucb, u16 reg, u16 val)
+{
+ ucb->ac97->bus->ops->write(ucb->ac97, reg, val);
+}
+
+static inline void ucb1400_adc_enable(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
+}
+
+static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel)
+{
+ unsigned int val;
+
+ if (ucb->adcsync)
+ adc_channel |= UCB_ADC_SYNC_ENA;
+
+ ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel);
+ ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | UCB_ADC_START);
+
+ for (;;) {
+ val = ucb1400_reg_read(ucb, UCB_ADC_DATA);
+ if (val & UCB_ADC_DAT_VALID)
+ break;
+ /* yield to other processes */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ return UCB_ADC_DAT_VALUE(val);
+}
+
+static inline void ucb1400_adc_disable(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_ADC_CR, 0);
+}
+
+/* Switch to interrupt mode. */
+static inline void ucb1400_ts_mode_int(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+ UCB_TS_CR_MODE_INT);
+}
+
+/*
+ * Switch to pressure mode, and read pressure. We don't need to wait
+ * here, since both plates are being driven.
+ */
+static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
+}
+
+/*
+ * Switch to X position mode and measure Y plate. We switch the plate
+ * configuration in pressure mode, then switch to position mode. This
+ * gives a faster response time. Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+ udelay(55);
+
+ return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
+}
+
+/*
+ * Switch to Y position mode and measure X plate. We switch the plate
+ * configuration in pressure mode, then switch to position mode. This
+ * gives a faster response time. Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+ udelay(55);
+
+ return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX);
+}
+
+/*
+ * Switch to X plate resistance mode. Set MX to ground, PX to
+ * supply. Measure current.
+ */
+static inline unsigned int ucb1400_ts_read_xres(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ return ucb1400_adc_read(ucb, 0);
+}
+
+/*
+ * Switch to Y plate resistance mode. Set MY to ground, PY to
+ * supply. Measure current.
+ */
+static inline unsigned int ucb1400_ts_read_yres(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_TS_CR,
+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ return ucb1400_adc_read(ucb, 0);
+}
+
+static inline int ucb1400_ts_pen_down(struct ucb1400 *ucb)
+{
+ unsigned short val = ucb1400_reg_read(ucb, UCB_TS_CR);
+ return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
+}
+
+static inline void ucb1400_ts_irq_enable(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, UCB_IE_TSPX);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
+ ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_TSPX);
+}
+
+static inline void ucb1400_ts_irq_disable(struct ucb1400 *ucb)
+{
+ ucb1400_reg_write(ucb, UCB_IE_FAL, 0);
+}
+
+static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y)
+{
+ input_report_abs(idev, ABS_X, x);
+ input_report_abs(idev, ABS_Y, y);
+ input_report_abs(idev, ABS_PRESSURE, pressure);
+ input_sync(idev);
+}
+
+static void ucb1400_ts_event_release(struct input_dev *idev)
+{
+ input_report_abs(idev, ABS_PRESSURE, 0);
+ input_sync(idev);
+}
+
+static void ucb1400_handle_pending_irq(struct ucb1400 *ucb)
+{
+ unsigned int isr;
+
+ isr = ucb1400_reg_read(ucb, UCB_IE_STATUS);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, isr);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
+
+ if (isr & UCB_IE_TSPX)
+ ucb1400_ts_irq_disable(ucb);
+ else
+ printk(KERN_ERR "ucb1400: unexpected IE_STATUS = %#x\n", isr);
+
+ enable_irq(ucb->irq);
+}
+
+static int ucb1400_ts_thread(void *_ucb)
+{
+ struct ucb1400 *ucb = _ucb;
+ struct task_struct *tsk = current;
+ int valid = 0;
+
+ tsk->policy = SCHED_FIFO;
+ tsk->rt_priority = 1;
+
+ while (!kthread_should_stop()) {
+ unsigned int x, y, p;
+ long timeout;
+
+ ucb->ts_restart = 0;
+
+ if (ucb->irq_pending) {
+ ucb->irq_pending = 0;
+ ucb1400_handle_pending_irq(ucb);
+ }
+
+ ucb1400_adc_enable(ucb);
+ x = ucb1400_ts_read_xpos(ucb);
+ y = ucb1400_ts_read_ypos(ucb);
+ p = ucb1400_ts_read_pressure(ucb);
+ ucb1400_adc_disable(ucb);
+
+ /* Switch back to interrupt mode. */
+ ucb1400_ts_mode_int(ucb);
+
+ msleep(10);
+
+ if (ucb1400_ts_pen_down(ucb)) {
+ ucb1400_ts_irq_enable(ucb);
+
+ /*
+ * If we spat out a valid sample set last time,
+ * spit out a "pen off" sample here.
+ */
+ if (valid) {
+ ucb1400_ts_event_release(ucb->ts_idev);
+ valid = 0;
+ }
+
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ } else {
+ valid = 1;
+ ucb1400_ts_evt_add(ucb->ts_idev, p, x, y);
+ timeout = msecs_to_jiffies(10);
+ }
+
+ wait_event_interruptible_timeout(ucb->ts_wait,
+ ucb->irq_pending || ucb->ts_restart || kthread_should_stop(),
+ timeout);
+ try_to_freeze();
+ }
+
+ /* Send the "pen off" if we are stopping with the pen still active */
+ if (valid)
+ ucb1400_ts_event_release(ucb->ts_idev);
+
+ ucb->ts_task = NULL;
+ return 0;
+}
+
+/*
+ * A restriction with interrupts exists when using the ucb1400, as
+ * the codec read/write routines may sleep while waiting for codec
+ * access completion and uses semaphores for access control to the
+ * AC97 bus. A complete codec read cycle could take anywhere from
+ * 60 to 100uSec so we *definitely* don't want to spin inside the
+ * interrupt handler waiting for codec access. So, we handle the
+ * interrupt by scheduling a RT kernel thread to run in process
+ * context instead of interrupt context.
+ */
+static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid)
+{
+ struct ucb1400 *ucb = devid;
+
+ if (irqnr == ucb->irq) {
+ disable_irq(ucb->irq);
+ ucb->irq_pending = 1;
+ wake_up(&ucb->ts_wait);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int ucb1400_ts_open(struct input_dev *idev)
+{
+ struct ucb1400 *ucb = idev->private;
+ int ret = 0;
+
+ BUG_ON(ucb->ts_task);
+
+ ucb->ts_task = kthread_run(ucb1400_ts_thread, ucb, "UCB1400_ts");
+ if (IS_ERR(ucb->ts_task)) {
+ ret = PTR_ERR(ucb->ts_task);
+ ucb->ts_task = NULL;
+ }
+
+ return ret;
+}
+
+static void ucb1400_ts_close(struct input_dev *idev)
+{
+ struct ucb1400 *ucb = idev->private;
+
+ if (ucb->ts_task)
+ kthread_stop(ucb->ts_task);
+
+ ucb1400_ts_irq_disable(ucb);
+ ucb1400_reg_write(ucb, UCB_TS_CR, 0);
+}
+
+#ifdef CONFIG_PM
+static int ucb1400_ts_resume(struct device *dev)
+{
+ struct ucb1400 *ucb = dev_get_drvdata(dev);
+
+ if (ucb->ts_task) {
+ /*
+ * Restart the TS thread to ensure the
+ * TS interrupt mode is set up again
+ * after sleep.
+ */
+ ucb->ts_restart = 1;
+ wake_up(&ucb->ts_wait);
+ }
+ return 0;
+}
+#else
+#define ucb1400_ts_resume NULL
+#endif
+
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
+/*
+ * Try to probe our interrupt, rather than relying on lots of
+ * hard-coded machine dependencies.
+ */
+static int ucb1400_detect_irq(struct ucb1400 *ucb)
+{
+ unsigned long mask, timeout;
+
+ mask = probe_irq_on();
+ if (!mask) {
+ probe_irq_off(mask);
+ return -EBUSY;
+ }
+
+ /* Enable the ADC interrupt. */
+ ucb1400_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
+ ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
+
+ /* Cause an ADC interrupt. */
+ ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
+ ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
+
+ /* Wait for the conversion to complete. */
+ timeout = jiffies + HZ/2;
+ while (!(ucb1400_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VALID)) {
+ cpu_relax();
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "ucb1400: timed out in IRQ probe\n");
+ probe_irq_off(mask);
+ return -ENODEV;
+ }
+ }
+ ucb1400_reg_write(ucb, UCB_ADC_CR, 0);
+
+ /* Disable and clear interrupt. */
+ ucb1400_reg_write(ucb, UCB_IE_RIS, 0);
+ ucb1400_reg_write(ucb, UCB_IE_FAL, 0);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
+ ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0);
+
+ /* Read triggered interrupt. */
+ ucb->irq = probe_irq_off(mask);
+ if (ucb->irq < 0 || ucb->irq == NO_IRQ)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int ucb1400_ts_probe(struct device *dev)
+{
+ struct ucb1400 *ucb;
+ struct input_dev *idev;
+ int error, id, x_res, y_res;
+
+ ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL);
+ idev = input_allocate_device();
+ if (!ucb || !idev) {
+ error = -ENOMEM;
+ goto err_free_devs;
+ }
+
+ ucb->ts_idev = idev;
+ ucb->adcsync = adcsync;
+ ucb->ac97 = to_ac97_t(dev);
+ init_waitqueue_head(&ucb->ts_wait);
+
+ id = ucb1400_reg_read(ucb, UCB_ID);
+ if (id != UCB_ID_1400) {
+ error = -ENODEV;
+ goto err_free_devs;
+ }
+
+ error = ucb1400_detect_irq(ucb);
+ if (error) {
+ printk(KERN_ERR "UCB1400: IRQ probe failed\n");
+ goto err_free_devs;
+ }
+
+ error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING,
+ "UCB1400", ucb);
+ if (error) {
+ printk(KERN_ERR "ucb1400: unable to grab irq%d: %d\n",
+ ucb->irq, error);
+ goto err_free_devs;
+ }
+ printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
+
+ idev->private = ucb;
+ idev->cdev.dev = dev;
+ idev->name = "UCB1400 touchscreen interface";
+ idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
+ idev->id.product = id;
+ idev->open = ucb1400_ts_open;
+ idev->close = ucb1400_ts_close;
+ idev->evbit[0] = BIT(EV_ABS);
+
+ ucb1400_adc_enable(ucb);
+ x_res = ucb1400_ts_read_xres(ucb);
+ y_res = ucb1400_ts_read_yres(ucb);
+ ucb1400_adc_disable(ucb);
+ printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res);
+
+ input_set_abs_params(idev, ABS_X, 0, x_res, 0, 0);
+ input_set_abs_params(idev, ABS_Y, 0, y_res, 0, 0);
+ input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0);
+
+ error = input_register_device(idev);
+ if (error)
+ goto err_free_irq;
+
+ dev_set_drvdata(dev, ucb);
+ return 0;
+
+ err_free_irq:
+ free_irq(ucb->irq, ucb);
+ err_free_devs:
+ input_free_device(idev);
+ kfree(ucb);
+ return error;
+}
+
+static int ucb1400_ts_remove(struct device *dev)
+{
+ struct ucb1400 *ucb = dev_get_drvdata(dev);
+
+ free_irq(ucb->irq, ucb);
+ input_unregister_device(ucb->ts_idev);
+ dev_set_drvdata(dev, NULL);
+ kfree(ucb);
+ return 0;
+}
+
+static struct device_driver ucb1400_ts_driver = {
+ .owner = THIS_MODULE,
+ .bus = &ac97_bus_type,
+ .probe = ucb1400_ts_probe,
+ .remove = ucb1400_ts_remove,
+ .resume = ucb1400_ts_resume,
+};
+
+static int __init ucb1400_ts_init(void)
+{
+ return driver_register(&ucb1400_ts_driver);
+}
+
+static void __exit ucb1400_ts_exit(void)
+{
+ driver_unregister(&ucb1400_ts_driver);
+}
+
+module_param(adcsync, int, 0444);
+
+module_init(ucb1400_ts_init);
+module_exit(ucb1400_ts_exit);
+
+MODULE_DESCRIPTION("Philips UCB1400 touchscreen driver");
+MODULE_LICENSE("GPL");
{
int i;
act2000_card *card;
- if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(act2000_card), GFP_KERNEL))) {
printk(KERN_WARNING
"act2000: (%s) Could not allocate card-struct.\n", id);
return;
}
- memset((char *) card, 0, sizeof(act2000_card));
spin_lock_init(&card->lock);
spin_lock_init(&card->mnlock);
skb_queue_head_init(&card->sndq);
unsigned int minor = 0;
unsigned long flags;
- mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
+ mp = kzalloc(sizeof(*mp), GFP_ATOMIC);
if (!mp) {
printk(KERN_ERR "capi: can't alloc capiminor\n");
return NULL;
}
- memset(mp, 0, sizeof(struct capiminor));
mp->ap = ap;
mp->ncci = ncci;
mp->msgid = 0;
struct capiminor *mp = NULL;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- np = kmalloc(sizeof(*np), GFP_ATOMIC);
+ np = kzalloc(sizeof(*np), GFP_ATOMIC);
if (!np)
return NULL;
- memset(np, 0, sizeof(struct capincci));
np->ncci = ncci;
np->cdev = cdev;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct capidev *cdev;
unsigned long flags;
- cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return NULL;
- memset(cdev, 0, sizeof(struct capidev));
init_MUTEX(&cdev->ncci_list_sem);
skb_queue_head_init(&cdev->recvqueue);
{
struct capiminor *mp;
- if ((mp = capiminor_find(iminor(file->f_dentry->d_inode))) == 0)
+ if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
return -ENXIO;
if (mp->nccip == 0)
return -ENXIO;
return error;
}
-static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
{
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_set_termios\n");
{
capidrv_plci *plcip;
- plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
+ plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
if (plcip == 0)
return NULL;
- memset(plcip, 0, sizeof(capidrv_plci));
plcip->state = ST_PLCI_NONE;
plcip->plci = 0;
plcip->msgid = 0;
{
capidrv_ncci *nccip;
- nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
+ nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
if (nccip == 0)
return NULL;
- memset(nccip, 0, sizeof(capidrv_ncci));
nccip->ncci = ncci;
nccip->state = ST_NCCI_NONE;
nccip->plcip = plcip;
printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
return -1;
}
- if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
+ if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
printk(KERN_WARNING
"capidrv: (%s) Could not allocate contr-struct.\n", id);
return -1;
}
- memset(card, 0, sizeof(capidrv_contr));
card->owner = THIS_MODULE;
init_timer(&card->listentimer);
strcpy(card->name, id);
tristate "Siemens Gigaset support (isdn)"
depends on ISDN_I4L
select CRC_CCITT
+ select BITREVERSE
help
Say m here if you have a Gigaset or Sinus isdn device.
#include "gigaset.h"
#include <linux/crc-ccitt.h>
+#include <linux/bitrev.h>
//#define GIG_M10x_STUFF_VOICE_DATA
inputstate |= INS_skip_frame;
break;
}
- *__skb_put(skb, 1) = gigaset_invtab[c];
+ *__skb_put(skb, 1) = bitrev8(c);
}
if (unlikely(!numbytes))
cp = skb->data;
len = skb->len;
while (len--) {
- c = gigaset_invtab[*cp++];
+ c = bitrev8(*cp++);
if (c == DLE_FLAG)
*(skb_put(iraw_skb, 1)) = c;
*(skb_put(iraw_skb, 1)) = c;
#define VALID_ID 0x02
#define ASSIGNED 0x04
-/* bitwise byte inversion table */
-__u8 gigaset_invtab[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
-};
-EXPORT_SYMBOL_GPL(gigaset_invtab);
-
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf)
{
}
}
-
-/* bitwise byte inversion table */
-extern __u8 gigaset_invtab[]; /* in common.c */
-
/* append received bytes to inbuf */
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
unsigned numbytes);
static int if_chars_in_buffer(struct tty_struct *tty);
static void if_throttle(struct tty_struct *tty);
static void if_unthrottle(struct tty_struct *tty);
-static void if_set_termios(struct tty_struct *tty, struct termios *old);
+static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
static int if_tiocmget(struct tty_struct *tty, struct file *file);
static int if_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
mutex_unlock(&cs->mutex);
}
-static void if_set_termios(struct tty_struct *tty, struct termios *old)
+static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct cardstate *cs;
unsigned int iflag;
#include "gigaset.h"
#include <linux/crc-ccitt.h>
+#include <linux/bitrev.h>
/* access methods for isowbuf_t */
/* ============================ */
gig_dbg(DEBUG_STREAM, "put %d bytes", count);
write = atomic_read(&iwb->write);
do {
- c = gigaset_invtab[*in++];
+ c = bitrev8(*in++);
iwb->data[write++] = c;
write %= BAS_OUTBUFSIZE;
} while (--count > 0);
while (count > 0) {
dst = skb_put(skb, count < dobytes ? count : dobytes);
while (count > 0 && dobytes > 0) {
- *dst++ = gigaset_invtab[*src++];
+ *dst++ = bitrev8(*src++);
count--;
dobytes--;
}
p_dev->conf.Present = PRESENT_OPTION;
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
goto err;
- memset(local, 0, sizeof(local_info_t));
p_dev->priv = local;
return avmcs_config(p_dev);
avmctrl_info *cinfo;
int i;
- card = kmalloc(sizeof(*card), GFP_KERNEL);
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return NULL;
- memset(card, 0, sizeof(*card));
-
- cinfo = kmalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
+ cinfo = kzalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
if (!cinfo) {
kfree(card);
return NULL;
}
- memset(cinfo, 0, sizeof(*cinfo) * nr_controllers);
card->ctrlinfo = cinfo;
for (i = 0; i < nr_controllers; i++) {
avmcard_dmainfo *p;
void *buf;
- p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
+ p = kzalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
if (!p) {
printk(KERN_WARNING "%s: no memory.\n", name);
goto err;
}
- memset(p, 0, sizeof(avmcard_dmainfo));
p->recvbuf.size = rsize;
buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
{
int i;
+ unregister_capi_driver(&capi_driver_t1isa);
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
data_length -= 9;
- if ((to_copy = MIN(strlen(clients[id].drvName), data_length-1))) {
+ if ((to_copy = min(strlen(clients[id].drvName), (size_t)(data_length-1)))) {
memcpy (p, clients[id].drvName, to_copy);
p += to_copy;
data_length -= to_copy;
if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
*p++ = '(';
data_length -= 1;
- if ((to_copy = MIN(strlen(clients[id].hDbg->drvTag), data_length-2))) {
+ if ((to_copy = min(strlen(clients[id].hDbg->drvTag), (size_t)(data_length-2)))) {
memcpy (p, clients[id].hDbg->drvTag, to_copy);
p += to_copy;
data_length -= to_copy;
i = this->XCurrent;
X = PTR_X(a,this);
while(i<this->XNum && length<270) {
- clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+ clength = min((word)(270-length),(word)(X[i].PLength-this->XOffset));
a->ram_out_buffer(a,
&ReqOut->XBuffer.P[length],
PTR_P(a,this,&X[i].P[this->XOffset]),
sizeof(a->stream_buffer),
&final, NULL, NULL);
}
- IoAdapter->RBuffer.length = MIN(MLength, 270);
+ IoAdapter->RBuffer.length = min(MLength, (word)270);
if (IoAdapter->RBuffer.length != MLength) {
this->complete = 0;
} else {
this->RCurrent++;
}
if (cma) {
- clength = MIN(MLength, R[this->RCurrent].PLength-this->ROffset);
+ clength = min(MLength, (word)(R[this->RCurrent].PLength-this->ROffset));
} else {
- clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+ clength = min(a->ram_inw(a, &RBuffer->length)-offset,
R[this->RCurrent].PLength-this->ROffset);
}
if(R[this->RCurrent].P) {
unsigned char line[160];
va_start(args, format);
- vsprintf(line, format, args);
+ vsnprintf(line, sizeof(line), format, args);
va_end(args);
printk(KERN_INFO "%s: %s\n", DRIVERLNAME, line);
case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: {
diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info;
memset (&prms, 0x00, sizeof(prms));
- prms.structure_length = MIN(sizeof(prms), pI->structure_length);
+ prms.structure_length = min_t(size_t, sizeof(prms), pI->structure_length);
memset (pI, 0x00, pI->structure_length);
prms.flag_dynamic_l1_down = (IoAdapter->capi_cfg.cfg_1 & \
DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0;
return (-1); /* was not able to write */
break; /* only part of message was written */
}
- to_write = MIN(length, DIVA_DFIFO_DATA_SZ);
+ to_write = min(length, DIVA_DFIFO_DATA_SZ);
if (to_write) {
a->ram_out_buffer (a,
#ifdef PLATFORM_GT_32BIT
return (-1); /* was not able to read */
break;
}
- to_read = MIN(max_length, tmp[1]);
+ to_read = min(max_length, (int)tmp[1]);
if (to_read) {
a->ram_in_buffer(a,
#ifdef PLATFORM_GT_32BIT
#define NULL ((void *) 0)
#endif
-#ifndef MIN
-#define MIN(a,b) ((a)>(b) ? (b) : (a))
-#endif
-
-#ifndef MAX
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#endif
-
#ifndef far
#define far
#endif
This enables HiSax support for the Formula-n enter:now PCI
ISDN card.
-config HISAX_AMD7930
- bool "Am7930 (EXPERIMENTAL)"
- depends on EXPERIMENTAL && SPARC && BROKEN
- help
- This enables HiSax support for the AMD7930 chips on some SPARCs.
- This code is not finished yet.
-
endif
if ISDN_DRV_HISAX
tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
select CRC_CCITT
+ select BITREVERSE
help
This enables the driver for ST5481 based USB ISDN adapters,
e.g. the BeWan Gazel 128 USB
DEBUG(0, "avma1cs_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
p_dev->priv = local;
/* The io structure describes IO port mapping */
#define DEFAULT_CFG {5,0x2E0,0,0}
#endif
-
-#ifdef CONFIG_HISAX_AMD7930
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_AMD7930
-#define DEFAULT_CFG {12,0x3e0,0,0}
-#endif
-
#ifdef CONFIG_HISAX_NICCY
#undef DEFAULT_CARD
#undef DEFAULT_CFG
extern int setup_hfcsx(struct IsdnCard *card);
#endif
-#if CARD_AMD7930
-extern int setup_amd7930(struct IsdnCard *card);
-#endif
-
#if CARD_NICCY
extern int setup_niccy(struct IsdnCard *card);
#endif
struct IsdnCard *card = cards + cardnr;
struct IsdnCardState *cs;
- cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+ cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
if (!cs) {
printk(KERN_WARNING
"HiSax: No memory for IsdnCardState(card %d)\n",
cardnr + 1);
goto out;
}
- memset(cs, 0, sizeof(struct IsdnCardState));
card->cs = cs;
spin_lock_init(&cs->statlock);
spin_lock_init(&cs->lock);
ret = setup_niccy(card);
break;
#endif
-#if CARD_AMD7930
- case ISDN_CTYPE_AMD7930:
- ret = setup_amd7930(card);
- break;
-#endif
#if CARD_ISURF
case ISDN_CTYPE_ISURF:
ret = setup_isurf(card);
break;
case ISDN_CTYPE_ELSA_PCI:
case ISDN_CTYPE_NETJET_S:
- case ISDN_CTYPE_AMD7930:
case ISDN_CTYPE_TELESPCI:
case ISDN_CTYPE_W6692:
case ISDN_CTYPE_NETJET_U:
bytecnt = 32;
}
}
+
+#ifdef __ISAPNP__
ready:
+#endif
+
printk(KERN_INFO
"Diva: %s card configured at %#lx IRQ %d\n",
(cs->subtyp == DIVA_PCI) ? "PCI" :
DEBUG(0, "elsa_cs_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->p_dev = link;
link->priv = local;
int i;
fsm->jumpmatrix = (FSMFNPTR *)
- kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
+ kzalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
if (!fsm->jumpmatrix)
return -ENOMEM;
- memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
-
for (i = 0; i < fncount; i++)
if ((fnlist[i].state>=fsm->state_count) || (fnlist[i].event>=fsm->event_count)) {
printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data;
hfc4s8s_hw *hw;
- if (!(hw = kmalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
+ if (!(hw = kzalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) {
printk(KERN_ERR "No kmem for HFC-4S/8S card\n");
return (err);
}
- memset(hw, 0, sizeof(hfc4s8s_hw));
hw->pdev = pdev;
err = pci_enable_device(pdev);
break;
case (HW_TESTLOOP | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
- switch ((int) arg) {
+ switch ((long) arg) {
case (1):
Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* tx slot */
Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* rx slot */
default:
spin_unlock_irqrestore(&cs->lock, flags);
if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcpci_l1hw loop invalid %4x", (int) arg);
+ debugl1(cs, "hfcpci_l1hw loop invalid %4lx", (long) arg);
return;
}
cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
printk(KERN_INFO
- "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n",
- (u_int) cs->hw.hfcpci.pci_io,
- (u_int) cs->hw.hfcpci.fifos,
+ "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n",
+ cs->hw.hfcpci.pci_io,
+ cs->hw.hfcpci.fifos,
(u_int) virt_to_bus(cs->hw.hfcpci.fifos),
cs->irq, HZ);
spin_lock_irqsave(&cs->lock, flags);
iface = iface_used;
if (!
(context =
- kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
+ kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
return (-ENOMEM); /* got no mem */
- memset(context, 0, sizeof(hfcusb_data));
ep = iface->endpoint;
vcf = validconf[small_match];
#define CARD_HFC_SX 0
#endif
-#ifdef CONFIG_HISAX_AMD7930
-#define CARD_AMD7930 1
-#else
-#define CARD_AMD7930 0
-#endif
-
#ifdef CONFIG_HISAX_NICCY
#define CARD_NICCY 1
#ifndef ISDN_CHIP_ISAC
struct hisax_b_if *b_if[2];
int i;
- adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
+ adapter = kzalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
if (!adapter)
return NULL;
- memset(adapter, 0, sizeof(struct fritz_adapter));
-
adapter->isac.hisax_d_if.owner = THIS_MODULE;
adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
char buf[256];
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
DBG(DBG_L1M, "%s", buf);
va_end(args);
}
/*-------------------------------------------------------------------*/
-/* bit swap table.
- * Very handy for devices with different bit order,
- * and neccessary for each transparent B-channel access for all
- * devices which works with this HDLC decoder without bit reversal.
- */
-const unsigned char isdnhdlc_bit_rev_tab[256] = {
- 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
- 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
- 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
- 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
- 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
- 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
- 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
- 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
- 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
- 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
- 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
- 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
- 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
- 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
- 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
- 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
-};
-
enum {
HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
HDLC_GET_DATA,HDLC_FAST_FLAG
return len;
}
-EXPORT_SYMBOL(isdnhdlc_bit_rev_tab);
EXPORT_SYMBOL(isdnhdlc_rcv_init);
EXPORT_SYMBOL(isdnhdlc_decode);
EXPORT_SYMBOL(isdnhdlc_out_init);
#define HDLC_CRC_ERROR 2
#define HDLC_LENGTH_ERROR 3
-extern const unsigned char isdnhdlc_bit_rev_tab[256];
-
extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
return (0);
#endif /* CONFIG_PCI */
}
+
+#ifdef __ISAPNP__
ready:
+#endif
+
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
* here, it would fail.
DEBUG(0, "sedlbauer_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->cardnr = -1;
local->p_dev = link;
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/bitrev.h>
#include "st5481.h"
static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
register unsigned char *dest = urb->transfer_buffer+len;
register unsigned int count;
for (count = 0; count < bytes_sent; count++)
- *dest++ = isdnhdlc_bit_rev_tab[*src++];
+ *dest++ = bitrev8(*src++);
}
len += bytes_sent;
} else {
char buf[256];
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
DBG(8, "%s", buf);
va_end(args);
}
char buf[256];
va_start(args, fmt);
- vsprintf(buf, fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
DBG(0x2, "%s", buf);
va_end(args);
}
le16_to_cpu(dev->descriptor.idProduct),
number_of_leds);
- adapter = kmalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
+ adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
- memset(adapter, 0, sizeof(struct st5481_adapter));
-
adapter->number_of_leds = number_of_leds;
adapter->usb_dev = dev;
DEBUG(0, "teles_attach()\n");
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->cardnr = -1;
local->p_dev = link;
return 1;
}
if (!card->hyctrlinfo) {
- cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
+ cinfo = kzalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n");
return -ENOMEM;
}
- memset(cinfo, 0, sizeof(hycapictrl_info));
card->hyctrlinfo = cinfo;
cinfo->card = card;
spin_lock_init(&cinfo->lock);
return (-ERR_ALREADY_BOOT); /* boot already active */
}
/* error no mem available */
- if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
+ if (!(boot = kzalloc(sizeof(struct boot_data), GFP_KERNEL))) {
if (card->debug_flags & LOG_MEM_ERR)
hysdn_addlog(card, "POF open: unable to allocate mem");
return (-EFAULT);
}
card->boot = boot;
card->state = CARD_STATE_BOOTING;
- memset(boot, 0, sizeof(struct boot_data));
card->stopcard(card); /* first stop the card */
if (card->testram(card)) {
if (pci_enable_device(akt_pcidev))
continue;
- if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
return;
}
- memset(card, 0, sizeof(hysdn_card));
card->myid = cardmax; /* set own id */
card->bus = akt_pcidev->bus->number;
card->devfn = akt_pcidev->devfn; /* slot + function */
return (-ENOMEM);
}
hysdn_net_release(card); /* release an existing net device */
- if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
+ if ((dev = kzalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
return (-ENOMEM);
}
- memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
spin_lock_init(&((struct net_local *) dev)->lock);
{
struct log_data *inf;
int len;
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct procdata *pd = NULL;
hysdn_card *card;
hysdn_log_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
hysdn_card *card;
struct procdata *pd = NULL;
/* create a cardlog proc entry */
- if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
- memset(pd, 0, sizeof(struct procdata));
+ if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
pd->log->proc_fops = &log_fops;
* Allocate the main control structure for this instance.
*/
maxmaxcode = MAXCODE(bits);
- db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL);
+ db = kzalloc (sizeof (struct bsd_db),GFP_KERNEL);
if (!db)
return NULL;
- memset (db, 0, sizeof(struct bsd_db));
-
db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
decomp = db->xmit ? 0 : 1;
static ssize_t
isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
{
- uint minor = iminor(file->f_dentry->d_inode);
+ uint minor = iminor(file->f_path.dentry->d_inode);
int len = 0;
int drvidx;
int chidx;
static ssize_t
isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
{
- uint minor = iminor(file->f_dentry->d_inode);
+ uint minor = iminor(file->f_path.dentry->d_inode);
int drvidx;
int chidx;
int retval;
isdn_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- unsigned int minor = iminor(file->f_dentry->d_inode);
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
lock_kernel();
if ((adding) && (d->rcverr))
kfree(d->rcverr);
- if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
+ if (!(d->rcverr = kzalloc(sizeof(int) * m, GFP_ATOMIC))) {
printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
return -1;
}
- memset((char *) d->rcverr, 0, sizeof(int) * m);
if ((adding) && (d->rcvcount))
kfree(d->rcvcount);
- if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) {
+ if (!(d->rcvcount = kzalloc(sizeof(int) * m, GFP_ATOMIC))) {
printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
if (!adding)
kfree(d->rcverr);
return -1;
}
- memset((char *) d->rcvcount, 0, sizeof(int) * m);
if ((adding) && (d->rpqueue)) {
for (j = 0; j < d->channels; j++)
printk(KERN_WARNING "register_isdn: No write routine given.\n");
return 0;
}
- if (!(d = kmalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
+ if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) {
printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
return 0;
}
- memset((char *) d, 0, sizeof(isdn_driver_t));
d->maxbufsize = i->maxbufsize;
d->pktcount = 0;
printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
return NULL;
}
- if (!(netdev = (isdn_net_dev *) kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
+ if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return NULL;
}
- memset(netdev, 0, sizeof(isdn_net_dev));
- if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
+ if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
kfree(netdev);
return NULL;
}
- memset(netdev->local, 0, sizeof(isdn_net_local));
if (name == NULL)
strcpy(netdev->local->name, " ");
else
if (is->debug & 0x2)
printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- iminor(file->f_dentry->d_inode));
+ iminor(file->f_path.dentry->d_inode));
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
#endif /* CONFIG_ISDN_MPP */
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = (struct ippp_struct *)
- kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
+ if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
for (j = 0; j < i; j++)
kfree(ippp_table[j]);
return -1;
}
- memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
spin_lock_init(&ippp_table[i]->buflock);
ippp_table[i]->state = 0;
ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
{
int i;
int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
- if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz,
- GFP_KERNEL)) == NULL )
+ if( (isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL )
return -ENOMEM;
- memset(isdn_ppp_bundle_arr, 0, sz);
for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
return 0;
static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
{
struct ippp_ccp_reset *r;
- r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
+ r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
if(!r) {
printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
" structure - no mem\n");
return NULL;
}
- memset(r, 0, sizeof(struct ippp_ccp_reset));
printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
is->reset = r;
return r;
id);
return NULL;
} else {
- rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
+ rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
if(!rs)
return NULL;
- memset(rs, 0, sizeof(struct ippp_ccp_reset_state));
rs->state = CCPResetIdle;
rs->is = is;
rs->id = id;
rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
+ if (!skb_out) {
+ kfree_skb(skb);
+ printk(KERN_ERR "ippp: decomp memory allocation failure\n");
+ return NULL;
+ }
len = ipc->decompress(stat, skb, skb_out, &rsparm);
kfree_skb(skb);
if (len <= 0) {
}
static void
-isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
modem_info *info = (modem_info *) tty->driver_data;
int i;
isdn_v110_stream *v;
- if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
+ if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
return NULL;
- memset(v, 0, sizeof(isdn_v110_stream));
v->key = key;
v->nbits = 0;
for (i = 0; key & (1 << i); i++)
icn_card *card;
int i;
- if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(icn_card), GFP_KERNEL))) {
printk(KERN_WARNING
"icn: (%s) Could not allocate card-struct.\n", id);
return (icn_card *) 0;
}
- memset((char *) card, 0, sizeof(icn_card));
spin_lock_init(&card->lock);
card->port = port;
card->interface.owner = THIS_MODULE;
isdnloop_card *card;
int i;
- if (!(card = (isdnloop_card *) kmalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
+ if (!(card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
printk(KERN_WARNING
"isdnloop: (%s) Could not allocate card-struct.\n", id);
return (isdnloop_card *) 0;
}
- memset((char *) card, 0, sizeof(isdnloop_card));
card->interface.owner = THIS_MODULE;
card->interface.channels = ISDNLOOP_BCH;
card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/
struct pcbit_dev *dev;
isdn_if *dev_if;
- if ((dev=kmalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
+ if ((dev=kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
{
printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
return -ENOMEM;
}
dev_pcbit[board] = dev;
- memset(dev, 0, sizeof(struct pcbit_dev));
init_waitqueue_head(&dev->set_running_wq);
spin_lock_init(&dev->lock);
return -EACCES;
}
- dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+ dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b1) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
iounmap(dev->sh_mem);
return -ENOMEM;
}
- dev->b2 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+ dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b2) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
kfree(dev->b1);
return -ENOMEM;
}
- memset(dev->b1, 0, sizeof(struct pcbit_chan));
- memset(dev->b2, 0, sizeof(struct pcbit_chan));
dev->b2->id = 1;
INIT_WORK(&dev->qdelivery, pcbit_deliver);
kfree(dev->read_frame);
dev->read_frame = NULL;
}
- frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+ frame = kzalloc(sizeof(struct frame_buf), GFP_ATOMIC);
if (frame == NULL) {
printk(KERN_WARNING "kmalloc failed\n");
return;
}
- memset(frame, 0, sizeof(struct frame_buf));
cpu = pcbit_readb(dev);
proc = pcbit_readb(dev);
* Horray! We found a board, Make sure we can register
* it with ISDN4Linux
*/
- interface = kmalloc(sizeof(isdn_if), GFP_KERNEL);
+ interface = kzalloc(sizeof(isdn_if), GFP_KERNEL);
if (interface == NULL) {
/*
* Oops, can't malloc isdn_if
*/
continue;
}
- memset(interface, 0, sizeof(isdn_if));
interface->owner = THIS_MODULE;
interface->hl_hdrlen = 0;
/*
* Allocate the board structure
*/
- sc_adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
+ sc_adapter[cinst] = kzalloc(sizeof(board), GFP_KERNEL);
if (sc_adapter[cinst] == NULL) {
/*
* Oops, can't alloc memory for the board
kfree(interface);
continue;
}
- memset(sc_adapter[cinst], 0, sizeof(board));
spin_lock_init(&sc_adapter[cinst]->lock);
if(!register_isdn(interface)) {
/*
* Allocate channels status structures
*/
- sc_adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
+ sc_adapter[cinst]->channel = kzalloc(sizeof(bchan) * channels, GFP_KERNEL);
if (sc_adapter[cinst]->channel == NULL) {
/*
* Oops, can't alloc memory for the channels
kfree(sc_adapter[cinst]);
continue;
}
- memset(sc_adapter[cinst]->channel, 0, sizeof(bchan) * channels);
/*
* Lock down the hardware resources
config MAC_EMUMOUSEBTN
bool "Support for mouse button 2+3 emulation"
- depends on INPUT_ADBHID
help
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
if (!hid || !input_dev) {
err = -ENOMEM;
goto fail;
-
}
sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
input_dev->keycode = hid->keycode;
- input_register_device(input_dev);
+ err = input_register_device(input_dev);
+ if (err)
+ goto fail;
if (default_id == ADB_KEYBOARD) {
/* HACK WARNING!! This should go away as soon there is an utility
return 0;
fail: input_free_device(input_dev);
- kfree(hid);
+ if (hid) {
+ kfree(hid->keycode);
+ kfree(hid);
+ }
adbhid[id] = NULL;
return err;
}
static int emumousebtn_input_register(void)
{
+ int ret;
+
emumousebtn = input_allocate_device();
if (!emumousebtn)
return -ENOMEM;
emumousebtn->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
emumousebtn->relbit[0] = BIT(REL_X) | BIT(REL_Y);
- input_register_device(emumousebtn);
+ ret = input_register_device(emumousebtn);
+ if (ret)
+ input_free_device(emumousebtn);
- return 0;
+ return ret;
}
int __init mac_hid_init(void)
if (!buf)
return NULL;
- d = file->f_dentry;
- v = file->f_vfsmnt;
+ d = file->f_path.dentry;
+ v = file->f_path.mnt;
buf = d_path(d, v, buf, count);
unsigned long count)
{
struct page *page = NULL;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct buffer_head *bh;
sector_t block;
bitmap_file_unmap(bitmap);
if (file) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
invalidate_inode_pages(inode->i_mapping);
fput(file);
}
bl->tail = bl2->tail;
}
+static inline void bio_list_merge_head(struct bio_list *bl,
+ struct bio_list *bl2)
+{
+ if (!bl2->head)
+ return;
+
+ if (bl->head)
+ bl2->tail->bi_next = bl->head;
+ else
+ bl->tail = bl2->tail;
+
+ bl->head = bl2->head;
+}
+
static inline struct bio *bio_list_pop(struct bio_list *bl)
{
struct bio *bio = bl->head;
const char *opts)
{
unsigned int bs = crypto_blkcipher_blocksize(cc->tfm);
- int log = long_log2(bs);
+ int log = ilog2(bs);
/* we need to calculate how far we must shift the sector count
* to get the cipher block count, we use this shift in _gen */
atomic_set(&io->pending, 0);
kcryptd_queue_io(io);
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
static int crypt_status(struct dm_target *ti, status_type_t type,
static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
{
- struct path *path = bio->bi_private;
+ struct dm_path *path = bio->bi_private;
if (bio->bi_size)
return 1;
return 0;
}
-static struct bio *get_failover_bio(struct path *path, unsigned data_size)
+static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
{
struct bio *bio;
struct page *page;
}
static struct request *get_failover_req(struct emc_handler *h,
- struct bio *bio, struct path *path)
+ struct bio *bio, struct dm_path *path)
{
struct request *rq;
struct block_device *bdev = bio->bi_bdev;
}
static struct request *emc_trespass_get(struct emc_handler *h,
- struct path *path)
+ struct dm_path *path)
{
struct bio *bio;
struct request *rq;
}
static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed,
- struct path *path)
+ struct dm_path *path)
{
struct request *rq;
struct request_queue *q = bdev_get_queue(path->dev->bdev);
void (*destroy) (struct hw_handler *hwh);
void (*pg_init) (struct hw_handler *hwh, unsigned bypassed,
- struct path *path);
+ struct dm_path *path);
unsigned (*error) (struct hw_handler *hwh, struct bio *bio);
int (*status) (struct hw_handler *hwh, status_type_t type,
char *result, unsigned int maxlen);
*---------------------------------------------------------------*/
static inline void bio_set_region(struct bio *bio, unsigned region)
{
- bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len = region;
+ bio->bi_io_vec[bio->bi_max_vecs].bv_len = region;
}
static inline unsigned bio_get_region(struct bio *bio)
{
- return bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len;
+ return bio->bi_io_vec[bio->bi_max_vecs].bv_len;
}
/*-----------------------------------------------------------------
zero_fill_bio(bio);
dec_count(io, bio_get_region(bio), error);
+ bio->bi_max_vecs++;
bio_put(bio);
return 0;
while (remaining) {
/*
- * Allocate a suitably sized bio, we add an extra
- * bvec for bio_get/set_region().
+ * Allocate a suitably sized-bio: we add an extra
+ * bvec for bio_get/set_region() and decrement bi_max_vecs
+ * to hide it from bio_add_page().
*/
- num_bvecs = (remaining / (PAGE_SIZE >> 9)) + 2;
+ num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
bio->bi_private = io;
bio->bi_destructor = dm_bio_destructor;
+ bio->bi_max_vecs--;
bio_set_region(bio, region);
/*
}
/*
- * Drop the extra refence that we were holding to avoid
+ * Drop the extra reference that we were holding to avoid
* the io being completed too early.
*/
dec_count(io, 0, 0);
static int do_suspend(struct dm_ioctl *param)
{
int r = 0;
- int do_lockfs = 1;
+ unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
struct mapped_device *md;
md = find_device(param);
return -ENXIO;
if (param->flags & DM_SKIP_LOCKFS_FLAG)
- do_lockfs = 0;
+ suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+ if (param->flags & DM_NOFLUSH_FLAG)
+ suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
if (!dm_suspended(md))
- r = dm_suspend(md, do_lockfs);
+ r = dm_suspend(md, suspend_flags);
if (!r)
r = __dev_status(md, param);
static int do_resume(struct dm_ioctl *param)
{
int r = 0;
- int do_lockfs = 1;
+ unsigned suspend_flags = DM_SUSPEND_LOCKFS_FLAG;
struct hash_cell *hc;
struct mapped_device *md;
struct dm_table *new_map;
if (new_map) {
/* Suspend if it isn't already suspended */
if (param->flags & DM_SKIP_LOCKFS_FLAG)
- do_lockfs = 0;
+ suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+ if (param->flags & DM_NOFLUSH_FLAG)
+ suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
if (!dm_suspended(md))
- dm_suspend(md, do_lockfs);
+ dm_suspend(md, suspend_flags);
r = dm_swap_table(md, new_map);
if (r) {
bio->bi_bdev = lc->dev->bdev;
bio->bi_sector = lc->start + (bio->bi_sector - ti->begin);
- return 1;
+ return DM_MAPIO_REMAPPED;
}
static int linear_status(struct dm_target *ti, status_type_t type,
struct dentry fake_dentry = {};
fake_file.f_mode = lc->dev->mode;
- fake_file.f_dentry = &fake_dentry;
+ fake_file.f_path.dentry = &fake_dentry;
fake_dentry.d_inode = bdev->bd_inode;
return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg);
/* copy clean across to sync */
memcpy(lc->sync_bits, lc->clean_bits, size);
lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
+ lc->sync_search = 0;
/* set the correct number of regions in the header */
lc->header.nr_regions = lc->region_count;
return lc->region_size;
}
+static int core_resume(struct dirty_log *log)
+{
+ struct log_c *lc = (struct log_c *) log->context;
+ lc->sync_search = 0;
+ return 0;
+}
+
static int core_is_clean(struct dirty_log *log, region_t region)
{
struct log_c *lc = (struct log_c *) log->context;
return 1;
}
-static void core_complete_resync_work(struct dirty_log *log, region_t region,
- int success)
+static void core_set_region_sync(struct dirty_log *log, region_t region,
+ int in_sync)
{
struct log_c *lc = (struct log_c *) log->context;
log_clear_bit(lc, lc->recovering_bits, region);
- if (success) {
+ if (in_sync) {
log_set_bit(lc, lc->sync_bits, region);
lc->sync_count++;
- }
+ } else if (log_test_bit(lc->sync_bits, region)) {
+ lc->sync_count--;
+ log_clear_bit(lc, lc->sync_bits, region);
+ }
}
static region_t core_get_sync_count(struct dirty_log *log)
.module = THIS_MODULE,
.ctr = core_ctr,
.dtr = core_dtr,
+ .resume = core_resume,
.get_region_size = core_get_region_size,
.is_clean = core_is_clean,
.in_sync = core_in_sync,
.mark_region = core_mark_region,
.clear_region = core_clear_region,
.get_resync_work = core_get_resync_work,
- .complete_resync_work = core_complete_resync_work,
+ .set_region_sync = core_set_region_sync,
.get_sync_count = core_get_sync_count,
.status = core_status,
};
.mark_region = core_mark_region,
.clear_region = core_clear_region,
.get_resync_work = core_get_resync_work,
- .complete_resync_work = core_complete_resync_work,
+ .set_region_sync = core_set_region_sync,
.get_sync_count = core_get_sync_count,
.status = disk_status,
};
int (*get_resync_work)(struct dirty_log *log, region_t *region);
/*
- * This notifies the log that the resync of an area has
- * been completed. The log should then mark this region
- * as CLEAN.
+ * This notifies the log that the resync status of a region
+ * has changed. It also clears the region from the recovering
+ * list (if present).
*/
- void (*complete_resync_work)(struct dirty_log *log,
- region_t region, int success);
+ void (*set_region_sync)(struct dirty_log *log,
+ region_t region, int in_sync);
/*
* Returns the number of regions that are in sync.
struct priority_group *pg; /* Owning PG */
unsigned fail_count; /* Cumulative failure count */
- struct path path;
+ struct dm_path path;
};
#define path_to_pgpath(__pgp) container_of((__pgp), struct pgpath, path)
static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
{
- struct path *path;
+ struct dm_path *path;
path = pg->ps.type->select_path(&pg->ps, &m->repeat_count);
if (!path)
m->current_pg = NULL;
}
+/*
+ * Check whether bios must be queued in the device-mapper core rather
+ * than here in the target.
+ *
+ * m->lock must be held on entry.
+ *
+ * If m->queue_if_no_path and m->saved_queue_if_no_path hold the
+ * same value then we are not between multipath_presuspend()
+ * and multipath_resume() calls and we have no need to check
+ * for the DMF_NOFLUSH_SUSPENDING flag.
+ */
+static int __must_push_back(struct multipath *m)
+{
+ return (m->queue_if_no_path != m->saved_queue_if_no_path &&
+ dm_noflush_suspending(m->ti));
+}
+
static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
unsigned was_queued)
{
- int r = 1;
+ int r = DM_MAPIO_REMAPPED;
unsigned long flags;
struct pgpath *pgpath;
!m->queue_io)
queue_work(kmultipathd, &m->process_queued_ios);
pgpath = NULL;
- r = 0;
- } else if (!pgpath)
- r = -EIO; /* Failed */
- else
+ r = DM_MAPIO_SUBMITTED;
+ } else if (pgpath)
bio->bi_bdev = pgpath->path.dev->bdev;
+ else if (__must_push_back(m))
+ r = DM_MAPIO_REQUEUE;
+ else
+ r = -EIO; /* Failed */
mpio->pgpath = pgpath;
r = map_io(m, bio, mpio, 1);
if (r < 0)
bio_endio(bio, bio->bi_size, r);
- else if (r == 1)
+ else if (r == DM_MAPIO_REMAPPED)
generic_make_request(bio);
+ else if (r == DM_MAPIO_REQUEUE)
+ bio_endio(bio, bio->bi_size, -EIO);
bio = next;
}
map_context->ptr = mpio;
bio->bi_rw |= (1 << BIO_RW_FAILFAST);
r = map_io(m, bio, mpio, 0);
- if (r < 0)
+ if (r < 0 || r == DM_MAPIO_REQUEUE)
mempool_free(mpio, m->mpio_pool);
return r;
/*
* pg_init must call this when it has completed its initialisation
*/
-void dm_pg_init_complete(struct path *path, unsigned err_flags)
+void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
{
struct pgpath *pgpath = path_to_pgpath(path);
struct priority_group *pg = pgpath->pg;
spin_lock_irqsave(&m->lock, flags);
if (!m->nr_valid_paths) {
- if (!m->queue_if_no_path) {
+ if (__must_push_back(m)) {
+ spin_unlock_irqrestore(&m->lock, flags);
+ return DM_ENDIO_REQUEUE;
+ } else if (!m->queue_if_no_path) {
spin_unlock_irqrestore(&m->lock, flags);
return -EIO;
} else {
queue_work(kmultipathd, &m->process_queued_ios);
spin_unlock_irqrestore(&m->lock, flags);
- return 1; /* io not complete */
+ return DM_ENDIO_INCOMPLETE; /* io not complete */
}
static int multipath_end_io(struct dm_target *ti, struct bio *bio,
if (ps->type->end_io)
ps->type->end_io(ps, &pgpath->path);
}
- if (r <= 0)
+ if (r != DM_ENDIO_INCOMPLETE)
mempool_free(mpio, m->mpio_pool);
return r;
struct dentry fake_dentry = {};
int r = 0;
- fake_file.f_dentry = &fake_dentry;
+ fake_file.f_path.dentry = &fake_dentry;
spin_lock_irqsave(&m->lock, flags);
struct dm_dev;
-struct path {
+struct dm_path {
struct dm_dev *dev; /* Read-only */
unsigned is_active; /* Read-only */
};
/* Callback for hwh_pg_init_fn to use when complete */
-void dm_pg_init_complete(struct path *path, unsigned err_flags);
+void dm_pg_init_complete(struct dm_path *path, unsigned err_flags);
#endif
* Add an opaque path object, along with some selector specific
* path args (eg, path priority).
*/
- int (*add_path) (struct path_selector *ps, struct path *path,
+ int (*add_path) (struct path_selector *ps, struct dm_path *path,
int argc, char **argv, char **error);
/*
* calling the function again. 0 means don't call it again unless
* the path fails.
*/
- struct path *(*select_path) (struct path_selector *ps,
+ struct dm_path *(*select_path) (struct path_selector *ps,
unsigned *repeat_count);
/*
* Notify the selector that a path has failed.
*/
- void (*fail_path) (struct path_selector *ps, struct path *p);
+ void (*fail_path) (struct path_selector *ps, struct dm_path *p);
/*
* Ask selector to reinstate a path.
*/
- int (*reinstate_path) (struct path_selector *ps, struct path *p);
+ int (*reinstate_path) (struct path_selector *ps, struct dm_path *p);
/*
* Table content based on parameters added in ps_add_path_fn
* or path selector status
*/
- int (*status) (struct path_selector *ps, struct path *path,
+ int (*status) (struct path_selector *ps, struct dm_path *path,
status_type_t type, char *result, unsigned int maxlen);
- int (*end_io) (struct path_selector *ps, struct path *path);
+ int (*end_io) (struct path_selector *ps, struct dm_path *path);
};
/* Register a path selector */
}
}
+static void complete_resync_work(struct region *reg, int success)
+{
+ struct region_hash *rh = reg->rh;
+
+ rh->log->type->set_region_sync(rh->log, reg->key, success);
+ dispatch_bios(rh->ms, ®->delayed_bios);
+ if (atomic_dec_and_test(&rh->recovery_in_flight))
+ wake_up_all(&_kmirrord_recovery_stopped);
+ up(&rh->recovery_count);
+}
+
static void rh_update_states(struct region_hash *rh)
{
struct region *reg, *next;
*/
list_for_each_entry_safe (reg, next, &recovered, list) {
rh->log->type->clear_region(rh->log, reg->key);
- rh->log->type->complete_resync_work(rh->log, reg->key, 1);
- dispatch_bios(rh->ms, ®->delayed_bios);
- if (atomic_dec_and_test(&rh->recovery_in_flight))
- wake_up_all(&_kmirrord_recovery_stopped);
- up(&rh->recovery_count);
+ complete_resync_work(reg, 1);
mempool_free(reg, rh->region_pool);
}
if (rw == WRITE) {
queue_bio(ms, bio, rw);
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
r = ms->rh.log->type->in_sync(ms->rh.log,
return r;
if (r == -EWOULDBLOCK) /* FIXME: ugly */
- r = 0;
+ r = DM_MAPIO_SUBMITTED;
/*
* We don't want to fast track a recovery just for a read
if (!r) {
/* Pass this io over to the daemon */
queue_bio(ms, bio, rw);
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
m = choose_mirror(ms, bio->bi_sector);
return -EIO;
map_bio(ms, m, bio);
- return 1;
+ return DM_MAPIO_REMAPPED;
}
static int mirror_end_io(struct dm_target *ti, struct bio *bio,
*---------------------------------------------------------------*/
struct path_info {
struct list_head list;
- struct path *path;
+ struct dm_path *path;
unsigned repeat_count;
};
ps->context = NULL;
}
-static int rr_status(struct path_selector *ps, struct path *path,
+static int rr_status(struct path_selector *ps, struct dm_path *path,
status_type_t type, char *result, unsigned int maxlen)
{
struct path_info *pi;
* Called during initialisation to register each path with an
* optional repeat_count.
*/
-static int rr_add_path(struct path_selector *ps, struct path *path,
+static int rr_add_path(struct path_selector *ps, struct dm_path *path,
int argc, char **argv, char **error)
{
struct selector *s = (struct selector *) ps->context;
return 0;
}
-static void rr_fail_path(struct path_selector *ps, struct path *p)
+static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
{
struct selector *s = (struct selector *) ps->context;
struct path_info *pi = p->pscontext;
list_move(&pi->list, &s->invalid_paths);
}
-static int rr_reinstate_path(struct path_selector *ps, struct path *p)
+static int rr_reinstate_path(struct path_selector *ps, struct dm_path *p)
{
struct selector *s = (struct selector *) ps->context;
struct path_info *pi = p->pscontext;
return 0;
}
-static struct path *rr_select_path(struct path_selector *ps,
+static struct dm_path *rr_select_path(struct path_selector *ps,
unsigned *repeat_count)
{
struct selector *s = (struct selector *) ps->context;
*/
#define SNAPSHOT_PAGES 256
-struct workqueue_struct *ksnapd;
+static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);
struct pending_exception {
return r;
}
+static void __free_exceptions(struct dm_snapshot *s)
+{
+ kcopyd_client_destroy(s->kcopyd_client);
+ s->kcopyd_client = NULL;
+
+ exit_exception_table(&s->pending, pending_cache);
+ exit_exception_table(&s->complete, exception_cache);
+
+ s->store.destroy(&s->store);
+}
+
static void snapshot_dtr(struct dm_target *ti)
{
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
/* After this returns there can be no new kcopyd jobs. */
unregister_snapshot(s);
- kcopyd_client_destroy(s->kcopyd_client);
-
- exit_exception_table(&s->pending, pending_cache);
- exit_exception_table(&s->complete, exception_cache);
-
- /* Deallocate memory used */
- s->store.destroy(&s->store);
+ __free_exceptions(s);
dm_put_device(ti, s->origin);
dm_put_device(ti, s->cow);
{
struct exception *e;
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
- int r = 1;
+ int r = DM_MAPIO_REMAPPED;
chunk_t chunk;
struct pending_exception *pe = NULL;
remap_exception(s, &pe->e, bio);
bio_list_add(&pe->snapshot_bios, bio);
- r = 0;
+ r = DM_MAPIO_SUBMITTED;
if (!pe->started) {
/* this is protected by snap->lock */
*---------------------------------------------------------------*/
static int __origin_write(struct list_head *snapshots, struct bio *bio)
{
- int r = 1, first = 0;
+ int r = DM_MAPIO_REMAPPED, first = 0;
struct dm_snapshot *snap;
struct exception *e;
struct pending_exception *pe, *next_pe, *primary_pe = NULL;
bio_list_add(&primary_pe->origin_bios, bio);
- r = 0;
+ r = DM_MAPIO_SUBMITTED;
}
if (!pe->primary_pe) {
static int do_origin(struct dm_dev *origin, struct bio *bio)
{
struct origin *o;
- int r = 1;
+ int r = DM_MAPIO_REMAPPED;
down_read(&_origins_lock);
o = __lookup_origin(origin->bdev);
return -EOPNOTSUPP;
/* Only tell snapshots if this is a write */
- return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : 1;
+ return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED;
}
#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
bio->bi_bdev = sc->stripe[stripe].dev->bdev;
bio->bi_sector = sc->stripe[stripe].physical_start +
(chunk << sc->chunk_shift) + (offset & sc->chunk_mask);
- return 1;
+ return DM_MAPIO_REMAPPED;
}
static int stripe_status(struct dm_target *ti,
bio_endio(bio, bio->bi_size, 0);
/* accepted bio, don't make new request */
- return 0;
+ return DM_MAPIO_SUBMITTED;
}
static struct target_type zero_target = {
#define DMF_FROZEN 2
#define DMF_FREEING 3
#define DMF_DELETING 4
+#define DMF_NOFLUSH_SUSPENDING 5
struct mapped_device {
struct rw_semaphore io_lock;
struct semaphore suspend_lock;
+ spinlock_t pushback_lock;
rwlock_t map_lock;
atomic_t holders;
atomic_t open_count;
*/
atomic_t pending;
wait_queue_head_t wait;
- struct bio_list deferred;
+ struct bio_list deferred;
+ struct bio_list pushback;
/*
* The current mapping.
* you this clearly demarcated crap.
*---------------------------------------------------------------*/
+static int __noflush_suspending(struct mapped_device *md)
+{
+ return test_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+}
+
/*
* Decrements the number of outstanding ios that a bio has been
* cloned into, completing the original io if necc.
*/
static void dec_pending(struct dm_io *io, int error)
{
- if (error)
+ unsigned long flags;
+
+ /* Push-back supersedes any I/O errors */
+ if (error && !(io->error > 0 && __noflush_suspending(io->md)))
io->error = error;
if (atomic_dec_and_test(&io->io_count)) {
+ if (io->error == DM_ENDIO_REQUEUE) {
+ /*
+ * Target requested pushing back the I/O.
+ * This must be handled before the sleeper on
+ * suspend queue merges the pushback list.
+ */
+ spin_lock_irqsave(&io->md->pushback_lock, flags);
+ if (__noflush_suspending(io->md))
+ bio_list_add(&io->md->pushback, io->bio);
+ else
+ /* noflush suspend was interrupted. */
+ io->error = -EIO;
+ spin_unlock_irqrestore(&io->md->pushback_lock, flags);
+ }
+
if (end_io_acct(io))
/* nudge anyone waiting on suspend queue */
wake_up(&io->md->wait);
- blk_add_trace_bio(io->md->queue, io->bio, BLK_TA_COMPLETE);
+ if (io->error != DM_ENDIO_REQUEUE) {
+ blk_add_trace_bio(io->md->queue, io->bio,
+ BLK_TA_COMPLETE);
+
+ bio_endio(io->bio, io->bio->bi_size, io->error);
+ }
- bio_endio(io->bio, io->bio->bi_size, io->error);
free_io(io->md, io);
}
}
if (endio) {
r = endio(tio->ti, bio, error, &tio->info);
- if (r < 0)
+ if (r < 0 || r == DM_ENDIO_REQUEUE)
+ /*
+ * error and requeue request are handled
+ * in dec_pending().
+ */
error = r;
-
- else if (r > 0)
- /* the target wants another shot at the io */
+ else if (r == DM_ENDIO_INCOMPLETE)
+ /* The target will handle the io */
return 1;
+ else if (r) {
+ DMWARN("unimplemented target endio return value: %d", r);
+ BUG();
+ }
}
dec_pending(tio->io, error);
atomic_inc(&tio->io->io_count);
sector = clone->bi_sector;
r = ti->type->map(ti, clone, &tio->info);
- if (r > 0) {
+ if (r == DM_MAPIO_REMAPPED) {
/* the bio has been remapped so dispatch it */
blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
clone->bi_sector);
generic_make_request(clone);
- }
-
- else if (r < 0) {
- /* error the io and bail out */
+ } else if (r < 0 || r == DM_MAPIO_REQUEUE) {
+ /* error the io and bail out, or requeue it if needed */
md = tio->io->md;
dec_pending(tio->io, r);
/*
clone->bi_private = md->bs;
bio_put(clone);
free_tio(md, tio);
+ } else if (r) {
+ DMWARN("unimplemented target map return value: %d", r);
+ BUG();
}
}
memset(md, 0, sizeof(*md));
init_rwsem(&md->io_lock);
init_MUTEX(&md->suspend_lock);
+ spin_lock_init(&md->pushback_lock);
rwlock_init(&md->map_lock);
atomic_set(&md->holders, 1);
atomic_set(&md->open_count, 0);
md->queue->issue_flush_fn = dm_flush_all;
md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache);
- if (!md->io_pool)
- goto bad2;
+ if (!md->io_pool)
+ goto bad2;
md->tio_pool = mempool_create_slab_pool(MIN_IOS, _tio_cache);
if (!md->tio_pool)
* dm_bind_table, dm_suspend must be called to flush any in
* flight bios and ensure that any further io gets deferred.
*/
-int dm_suspend(struct mapped_device *md, int do_lockfs)
+int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
{
struct dm_table *map = NULL;
+ unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
struct bio *def;
int r = -EINVAL;
+ int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0;
+ int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0;
down(&md->suspend_lock);
map = dm_get_table(md);
+ /*
+ * DMF_NOFLUSH_SUSPENDING must be set before presuspend.
+ * This flag is cleared before dm_suspend returns.
+ */
+ if (noflush)
+ set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+
/* This does not get reverted if there's an error later. */
dm_table_presuspend_targets(map);
if (!md->suspended_bdev) {
DMWARN("bdget failed in dm_suspend");
r = -ENOMEM;
- goto out;
+ goto flush_and_out;
}
- /* Flush I/O to the device. */
- if (do_lockfs) {
+ /*
+ * Flush I/O to the device.
+ * noflush supersedes do_lockfs, because lock_fs() needs to flush I/Os.
+ */
+ if (do_lockfs && !noflush) {
r = lock_fs(md);
if (r)
goto out;
down_write(&md->io_lock);
remove_wait_queue(&md->wait, &wait);
+ if (noflush) {
+ spin_lock_irqsave(&md->pushback_lock, flags);
+ clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+ bio_list_merge_head(&md->deferred, &md->pushback);
+ bio_list_init(&md->pushback);
+ spin_unlock_irqrestore(&md->pushback_lock, flags);
+ }
+
/* were we interrupted ? */
r = -EINTR;
if (atomic_read(&md->pending)) {
__flush_deferred_io(md, def);
up_write(&md->io_lock);
unlock_fs(md);
- goto out;
+ goto out; /* pushback list is already flushed, so skip flush */
}
up_write(&md->io_lock);
r = 0;
+flush_and_out:
+ if (r && noflush) {
+ /*
+ * Because there may be already I/Os in the pushback list,
+ * flush them before return.
+ */
+ down_write(&md->io_lock);
+
+ spin_lock_irqsave(&md->pushback_lock, flags);
+ clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
+ bio_list_merge_head(&md->deferred, &md->pushback);
+ bio_list_init(&md->pushback);
+ spin_unlock_irqrestore(&md->pushback_lock, flags);
+
+ def = bio_list_get(&md->deferred);
+ __flush_deferred_io(md, def);
+ up_write(&md->io_lock);
+ }
+
out:
if (r && md->suspended_bdev) {
bdput(md->suspended_bdev);
return test_bit(DMF_SUSPENDED, &md->flags);
}
+int dm_noflush_suspending(struct dm_target *ti)
+{
+ struct mapped_device *md = dm_table_get_md(ti->table);
+ int r = __noflush_suspending(md);
+
+ dm_put(md);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_noflush_suspending);
+
static struct block_device_operations dm_blk_dops = {
.open = dm_blk_open,
.release = dm_blk_close,
#define SECTOR_SHIFT 9
+/*
+ * Definitions of return values from target end_io function.
+ */
+#define DM_ENDIO_INCOMPLETE 1
+#define DM_ENDIO_REQUEUE 2
+
+/*
+ * Definitions of return values from target map function.
+ */
+#define DM_MAPIO_SUBMITTED 0
+#define DM_MAPIO_REMAPPED 1
+#define DM_MAPIO_REQUEUE DM_ENDIO_REQUEUE
+
+/*
+ * Suspend feature flags
+ */
+#define DM_SUSPEND_LOCKFS_FLAG (1 << 0)
+#define DM_SUSPEND_NOFLUSH_FLAG (1 << 1)
+
/*
* List of devices that a metadevice uses and should open/close.
*/
struct block_device *bdev;
char b[BDEVNAME_SIZE];
- bdev = open_partition_by_devnum(dev, FMODE_READ|FMODE_WRITE);
+ bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
if (IS_ERR(bdev)) {
printk(KERN_ERR "md: could not open %s.\n",
__bdevname(dev, b));
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
- blkdev_put_partition(bdev);
+ blkdev_put(bdev);
return err;
}
rdev->bdev = bdev;
if (!bdev)
MD_BUG();
bd_release(bdev);
- blkdev_put_partition(bdev);
+ blkdev_put(bdev);
}
void md_autodetect_dev(dev_t dev);
mddev_t *mddev = inode->i_bdev->bd_disk->private_data;
int err;
- if ((err = mddev_lock(mddev)))
+ if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1)))
goto out;
err = 0;
chunk_kb ? "KB" : "B");
if (bitmap->file) {
seq_printf(seq, ", file: ");
- seq_path(seq, bitmap->file->f_vfsmnt,
- bitmap->file->f_dentry," \t\n");
+ seq_path(seq, bitmap->file->f_path.mnt,
+ bitmap->file->f_path.dentry," \t\n");
}
seq_printf(seq, "\n");
ret = file->f_op->unlocked_ioctl(file, cmd, arg);
else if (file->f_op->ioctl) {
lock_kernel();
- ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
unlock_kernel();
}
struct video_device* video_devdata(struct file *file)
{
- return video_device[iminor(file->f_dentry->d_inode)];
+ return video_device[iminor(file->f_path.dentry->d_inode)];
}
/*
static ssize_t zoran_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- struct zoran *zr = PDE(file->f_dentry->d_inode)->data;
+ struct zoran *zr = PDE(file->f_path.dentry->d_inode)->data;
char *string, *sp;
char *line, *ldelim, *varname, *svar, *tdelim;
}
string[count] = 0;
dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
- ZR_DEVNAME(zr), file->f_dentry->d_name.name, count, zr);
+ ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr);
ldelim = " \t\n";
tdelim = "=";
line = strpbrk(sp, ldelim);
host->rx_chan = rxchan;
}
-struct const mmc_host_ops au1xmmc_ops = {
+static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
};
struct pxamci_host *host = mmc_priv(mmc);
if (host->pdata && host->pdata->get_ro)
- return host->pdata->get_ro(mmc->dev);
+ return host->pdata->get_ro(mmc_dev(mmc));
/* Host doesn't support read only detection so assume writeable */
return 0;
}
host->power_mode = ios->power_mode;
if (host->pdata && host->pdata->setpower)
- host->pdata->setpower(mmc->dev, ios->vdd);
+ host->pdata->setpower(mmc_dev(mmc), ios->vdd);
if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMDAT_INIT;
writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(long_log2(cmd->data->blksz) - 2,
+ writel(ilog2(cmd->data->blksz) - 2,
sock->addr + SOCK_FIFO_PAGE_SIZE);
writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
{
struct sirtty_cb *priv = dev->priv;
struct tty_struct *tty;
- struct termios old_termios;
+ struct ktermios old_termios;
int cflag;
IRDA_ASSERT(priv != NULL, return -1;);
static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
{
- struct termios old_termios;
+ struct ktermios old_termios;
int cflag;
lock_kernel();
}
/* Finally, invert the result once to get the correct data */
crc = ~crc;
- return bitreverse(crc) >> 16;
+ return bitrev32(crc) >> 16;
}
/**
unsigned long flags;
int n;
- if ((n=iminor(file->f_dentry->d_inode)>>CARD_MINOR_BITS)
+ if ((n=iminor(file->f_path.dentry->d_inode)>>CARD_MINOR_BITS)
>= nr_cards)
return -ENODEV;
cosa = cosa_cards+n;
- if ((n=iminor(file->f_dentry->d_inode)
+ if ((n=iminor(file->f_path.dentry->d_inode)
& ((1<<CARD_MINOR_BITS)-1)) >= cosa->nchannels)
return -ENODEV;
chan = cosa->chan + n;
*/
static void set_baud(struct tty_struct *tty, unsigned int baudcode)
{
- struct termios old_termios = *(tty->termios);
+ struct ktermios old_termios = *(tty->termios);
tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */
tty->termios->c_cflag |= baudcode; /* Set the new baud setting */
tty->driver->set_termios(tty, &old_termios);
continue;
if (!(vma->vm_flags & VM_EXECUTABLE))
continue;
- cookie = fast_get_dcookie(vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
+ cookie = fast_get_dcookie(vma->vm_file->f_path.dentry,
+ vma->vm_file->f_path.mnt);
break;
}
continue;
if (vma->vm_file) {
- cookie = fast_get_dcookie(vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
+ cookie = fast_get_dcookie(vma->vm_file->f_path.dentry,
+ vma->vm_file->f_path.mnt);
*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr -
vma->vm_start;
} else {
proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
mutex_lock(&inode->i_mutex);
switch (whence) {
static ssize_t
proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_dentry->d_inode;
+ const struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
unsigned int pos = *ppos;
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_dentry->d_inode;
+ const struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
#ifdef HAVE_PCI_MMAP
static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data;
struct pci_filp_private *fpriv = file->private_data;
user_info_t *user;
int ret;
- ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
+ ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
if (count < 4)
return -EINVAL;
static ssize_t ds_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
+ ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
if (count != 4)
return -EINVAL;
struct pcmcia_socket *s;
user_info_t *user;
- ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
+ ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
user = file->private_data;
if (CHECK_USER(user))
static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct inode *ino = file->f_dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp = PDE(ino);
struct pnp_dev *dev = dp->data;
int pos = *ppos;
}
} else { /* error */
memcpy(&cqr->irb, irb, sizeof (struct irb));
-#ifdef ERP_DEBUG
- /* dump sense data */
- dasd_log_sense(cqr, irb);
-#endif
+ if (device->features & DASD_FEATURE_ERPLOG) {
+ /* dump sense data */
+ dasd_log_sense(cqr, irb);
+ }
switch (era) {
case dasd_era_fatal:
cqr->status = DASD_CQR_FAILED;
struct dasd_ccw_req *erp = NULL;
struct dasd_device *device = cqr->device;
__u32 cpa = cqr->irb.scsw.cpa;
+ struct dasd_ccw_req *temp_erp = NULL;
-#ifdef ERP_DEBUG
- /* print current erp_chain */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "ERP chain at BEGINNING of ERP-ACTION");
- {
- struct dasd_ccw_req *temp_erp = NULL;
-
+ if (device->features & DASD_FEATURE_ERPLOG) {
+ /* print current erp_chain */
+ DEV_MESSAGE(KERN_ERR, device, "%s",
+ "ERP chain at BEGINNING of ERP-ACTION");
for (temp_erp = cqr;
temp_erp != NULL; temp_erp = temp_erp->refers) {
temp_erp->refers);
}
}
-#endif /* ERP_DEBUG */
/* double-check if current erp/cqr was successfull */
if ((cqr->irb.scsw.cstat == 0x00) &&
erp = dasd_3990_erp_handle_match_erp(cqr, erp);
}
-#ifdef ERP_DEBUG
- /* print current erp_chain */
- DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at END of ERP-ACTION");
- {
- struct dasd_ccw_req *temp_erp = NULL;
+ if (device->features & DASD_FEATURE_ERPLOG) {
+ /* print current erp_chain */
+ DEV_MESSAGE(KERN_ERR, device, "%s",
+ "ERP chain at END of ERP-ACTION");
for (temp_erp = erp;
temp_erp != NULL; temp_erp = temp_erp->refers) {
temp_erp->refers);
}
}
-#endif /* ERP_DEBUG */
if (erp->status == DASD_CQR_FAILED)
dasd_log_ccw(erp, 1, cpa);
features |= DASD_FEATURE_READONLY;
else if (len == 4 && !strncmp(str, "diag", 4))
features |= DASD_FEATURE_USEDIAG;
+ else if (len == 6 && !strncmp(str, "erplog", 6))
+ features |= DASD_FEATURE_ERPLOG;
else {
MESSAGE(KERN_WARNING,
"unsupported feature: %*s, "
}
static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
+/*
+ * erplog controls the logging of ERP related data
+ * (e.g. failing channel programs).
+ */
+static ssize_t
+dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct dasd_devmap *devmap;
+ int erplog;
+
+ devmap = dasd_find_busid(dev->bus_id);
+ if (!IS_ERR(devmap))
+ erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0;
+ else
+ erplog = (DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG) != 0;
+ return snprintf(buf, PAGE_SIZE, erplog ? "1\n" : "0\n");
+}
+
+static ssize_t
+dasd_erplog_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dasd_devmap *devmap;
+ int val;
+ char *endp;
+
+ devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (((endp + 1) < (buf + count)) || (val > 1))
+ return -EINVAL;
+
+ spin_lock(&dasd_devmap_lock);
+ if (val)
+ devmap->features |= DASD_FEATURE_ERPLOG;
+ else
+ devmap->features &= ~DASD_FEATURE_ERPLOG;
+ if (devmap->device)
+ devmap->device->features = devmap->features;
+ spin_unlock(&dasd_devmap_lock);
+ return count;
+}
+
+static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store);
/*
* use_diag controls whether the driver should use diag rather than ssch
&dev_attr_uid.attr,
&dev_attr_use_diag.attr,
&dev_attr_eer_enabled.attr,
+ &dev_attr_erplog.attr,
NULL,
};
#ifdef __KERNEL__
-/* erp debugging in dasd.c and dasd_3990_erp.c */
-#define ERP_DEBUG
-
-
/* we keep old device allocation scheme; IOW, minors are still in 0..255 */
#define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS))
#define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
int rval;
lock_kernel();
- rval = dasd_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ rval = dasd_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return (rval == -EINVAL) ? -ENOIOCTLCMD : rval;
#ifdef CONFIG_MAGIC_SYSRQ
static int ctrlchar_sysrq_key;
+static struct tty_struct *sysrq_tty;
static void
-ctrlchar_handle_sysrq(void *tty)
+ctrlchar_handle_sysrq(struct work_struct *work)
{
- handle_sysrq(ctrlchar_sysrq_key, (struct tty_struct *) tty);
+ handle_sysrq(ctrlchar_sysrq_key, sysrq_tty);
}
-static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
+static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq);
#endif
/* racy */
if (len == 3 && buf[1] == '-') {
ctrlchar_sysrq_key = buf[2];
- ctrlchar_work.data = tty;
+ sysrq_tty = tty;
schedule_work(&ctrlchar_work);
return CTRLCHAR_SYSRQ;
}
struct idal_buffer *ib;
int minor, rc;
- if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR)
+ if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
return -ENODEV;
- minor = iminor(filp->f_dentry->d_inode);
+ minor = iminor(filp->f_path.dentry->d_inode);
/* Check for minor 0 multiplexer. */
if (minor == 0) {
- if (!current->signal->tty)
+ struct tty_struct *tty;
+ mutex_lock(&tty_mutex);
+ tty = get_current_tty();
+ if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
+ mutex_unlock(&tty_mutex);
return -ENODEV;
- if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR)
- return -ENODEV;
- minor = current->signal->tty->index + RAW3270_FIRSTMINOR;
+ }
+ minor = tty->index + RAW3270_FIRSTMINOR;
+ mutex_unlock(&tty_mutex);
}
/* Check if some other program is already using fullscreen mode. */
fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
struct tty_driver *sclp_tty_driver;
-extern struct termios tty_std_termios;
-
static struct sclp_ioctls sclp_ioctls;
static struct sclp_ioctls sclp_ioctls_init =
{
/* Block Frontend Data */
struct tape_blk_data
{
+ struct tape_device * device;
/* Block device request queue. */
request_queue_t * request_queue;
spinlock_t request_queue_lock;
#endif
/* Function to start or stop the next request later. */
- struct work_struct tape_dnr;
+ struct delayed_work tape_dnr;
};
/* Externals from tape_core.c */
return rc;
}
+struct tape_34xx_work {
+ struct tape_device *device;
+ enum tape_op op;
+ struct work_struct work;
+};
+
/*
* These functions are currently used only to schedule a medium_sense for
* later execution. This is because we get an interrupt whenever a medium
* interrupt handler.
*/
static void
-tape_34xx_work_handler(void *data)
+tape_34xx_work_handler(struct work_struct *work)
{
- struct {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
- } *p = data;
+ struct tape_34xx_work *p =
+ container_of(work, struct tape_34xx_work, work);
switch(p->op) {
case TO_MSEN:
static int
tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
{
- struct {
- struct tape_device *device;
- enum tape_op op;
- struct work_struct work;
- } *p;
+ struct tape_34xx_work *p;
if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
memset(p, 0, sizeof(*p));
- INIT_WORK(&p->work, tape_34xx_work_handler, p);
+ INIT_WORK(&p->work, tape_34xx_work_handler);
p->device = tape_get_device_reference(device);
p->op = op;
};
static void
-tape_3590_work_handler(void *data)
+tape_3590_work_handler(struct work_struct *work)
{
- struct work_handler_data *p = data;
+ struct work_handler_data *p =
+ container_of(work, struct work_handler_data, work);
switch (p->op) {
case TO_MSEN:
if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- INIT_WORK(&p->work, tape_3590_work_handler, p);
+ INIT_WORK(&p->work, tape_3590_work_handler);
p->device = tape_get_device_reference(device);
p->op = op;
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/buffer_head.h>
+#include <linux/kernel.h>
#include <asm/debug.h>
* queue.
*/
static void
-tapeblock_requeue(void *data) {
+tapeblock_requeue(struct work_struct *work) {
+ struct tape_blk_data * blkdat;
struct tape_device * device;
request_queue_t * queue;
int nr_queued;
struct list_head * l;
int rc;
- device = (struct tape_device *) data;
+ blkdat = container_of(work, struct tape_blk_data, requeue_task);
+ device = blkdat->device;
if (!device)
return;
int rc;
blkdat = &device->blk_data;
+ blkdat->device = device;
spin_lock_init(&blkdat->request_queue_lock);
atomic_set(&blkdat->requeue_scheduled, 0);
add_disk(disk);
- INIT_WORK(&blkdat->requeue_task, tapeblock_requeue,
- tape_get_device_reference(device));
+ tape_get_device_reference(device);
+ INIT_WORK(&blkdat->requeue_task, tapeblock_requeue);
return 0;
tapeblock_cleanup_device(struct tape_device *device)
{
flush_scheduled_work();
- device->blk_data.requeue_task.data = tape_put_device(device);
+ tape_put_device(device);
if (!device->blk_data.disk) {
PRINT_ERR("(%s): No gendisk to clean up!\n",
int minor, rc;
DBF_EVENT(6, "TCHAR:open: %i:%i\n",
- imajor(filp->f_dentry->d_inode),
- iminor(filp->f_dentry->d_inode));
+ imajor(filp->f_path.dentry->d_inode),
+ iminor(filp->f_path.dentry->d_inode));
- if (imajor(filp->f_dentry->d_inode) != tapechar_major)
+ if (imajor(filp->f_path.dentry->d_inode) != tapechar_major)
return -ENODEV;
- minor = iminor(filp->f_dentry->d_inode);
+ minor = iminor(filp->f_path.dentry->d_inode);
device = tape_get_device(minor / TAPE_MINORS_PER_DEV);
if (IS_ERR(device)) {
DBF_EVENT(3, "TCHAR:open: tape_get_device() failed\n");
#define PRINTK_HEADER "TAPE_CORE: "
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
-static void tape_delayed_next_request(void * data);
+static void tape_delayed_next_request(struct work_struct *);
/*
* One list to contain all tape devices of all disciplines, so
return 0;
case -EBUSY:
request->status = TAPE_REQUEST_CANCEL;
- schedule_work(&device->tape_dnr);
+ schedule_delayed_work(&device->tape_dnr, 0);
return 0;
case -ENODEV:
DBF_EXCEPTION(2, "device gone, retry\n");
*device->modeset_byte = 0;
device->first_minor = -1;
atomic_set(&device->ref_count, 1);
- INIT_WORK(&device->tape_dnr, tape_delayed_next_request, device);
+ INIT_DELAYED_WORK(&device->tape_dnr, tape_delayed_next_request);
return device;
}
} else if (rc == -EBUSY) {
/* The common I/O subsystem is currently busy. Retry later. */
request->status = TAPE_REQUEST_QUEUED;
- schedule_work(&device->tape_dnr);
+ schedule_delayed_work(&device->tape_dnr, 0);
rc = 0;
} else {
/* Start failed. Remove request and indicate failure. */
}
static void
-tape_delayed_next_request(void *data)
+tape_delayed_next_request(struct work_struct *work)
{
- struct tape_device * device;
+ struct tape_device *device =
+ container_of(work, struct tape_device, tape_dnr.work);
- device = (struct tape_device *) data;
DBF_LH(6, "tape_delayed_next_request(%p)\n", device);
spin_lock_irq(get_ccwdev_lock(device->cdev));
__tape_start_next_request(device);
* Check for visible/invisible input switches
*/
static void
-tty3270_set_termios(struct tty_struct *tty, struct termios *old)
+tty3270_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct tty3270 *tp;
int new;
page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!page)
return -ENOMEM;
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
ret = chsc_get_sch_desc_irq(sch, page);
if (ret) {
static int cio_chsc_err_msg;
cio_chsc_err_msg = 1;
}
}
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
free_page((unsigned long)page);
if (!ret) {
int j, chpid, mask;
if (j >= 8)
return 0;
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
stsch(sch->schid, &schib);
if (!schib.pmcw.dnv)
else if (sch->lpm == mask)
goto out_unreg;
out_unlock:
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
return 0;
out_unreg:
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
sch->lpm = 0;
if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
/* Check if a subchannel is newly available. */
return s390_process_res_acc_new_sch(schid);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
chp_mask = s390_process_res_acc_sch(res_data, sch);
if (chp_mask == 0) {
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
put_device(&sch->dev);
return 0;
}
else if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
put_device(&sch->dev);
return 0;
}
if (!sch)
/* Check if the subchannel is now available. */
return __chp_add_new_sch(schid);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
for (i=0; i<8; i++) {
mask = 0x80 >> i;
if ((sch->schib.pmcw.pim & mask) &&
(sch->schib.pmcw.chpid[i] == chp->id)) {
if (stsch(sch->schid, &sch->schib) != 0) {
/* Endgame. */
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
return -ENXIO;
}
break;
}
}
if (i==8) {
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
return 0;
}
sch->lpm = ((sch->schib.pmcw.pim &
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
put_device(&sch->dev);
return 0;
}
if (!sch->ssd_info.valid)
return;
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
old_lpm = sch->lpm;
for (chp = 0; chp < 8; chp++) {
if (sch->ssd_info.chpid[chp] != chpid)
sch->driver->verify(&sch->dev);
break;
}
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
}
static int
return 1;
local_bh_disable();
irq_enter ();
- spin_lock(&sch->lock);
+ spin_lock(sch->lock);
memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
if (sch->driver && sch->driver->irq)
sch->driver->irq(&sch->dev);
- spin_unlock(&sch->lock);
+ spin_unlock(sch->lock);
irq_exit ();
_local_bh_enable();
return 1;
CIO_TRACE_EVENT (2, "ensch");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ if (sch_is_pseudo_sch(sch))
+ return -EINVAL;
ccode = stsch (sch->schid, &sch->schib);
if (ccode)
return -ENODEV;
CIO_TRACE_EVENT (2, "dissch");
CIO_TRACE_EVENT (2, sch->dev.bus_id);
+ if (sch_is_pseudo_sch(sch))
+ return 0;
ccode = stsch (sch->schid, &sch->schib);
if (ccode == 3) /* Not operational. */
return -ENODEV;
return ret;
}
+int cio_create_sch_lock(struct subchannel *sch)
+{
+ sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+ if (!sch->lock)
+ return -ENOMEM;
+ spin_lock_init(sch->lock);
+ return 0;
+}
+
/*
* cio_validate_subchannel()
*
{
char dbf_txt[15];
int ccode;
+ int err;
sprintf (dbf_txt, "valsch%x", schid.sch_no);
CIO_TRACE_EVENT (4, dbf_txt);
/* Nuke all fields. */
memset(sch, 0, sizeof(struct subchannel));
- spin_lock_init(&sch->lock);
+ sch->schid = schid;
+ if (cio_is_console(schid)) {
+ sch->lock = cio_get_console_lock();
+ } else {
+ err = cio_create_sch_lock(sch);
+ if (err)
+ goto out;
+ }
mutex_init(&sch->reg_mutex);
-
/* Set a name for the subchannel */
snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
schid.sch_no);
* is not valid.
*/
ccode = stsch_err (schid, &sch->schib);
- if (ccode)
- return (ccode == 3) ? -ENXIO : ccode;
-
- sch->schid = schid;
+ if (ccode) {
+ err = (ccode == 3) ? -ENXIO : ccode;
+ goto out;
+ }
/* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st;
"non-I/O subchannel type %04X\n",
sch->schid.ssid, sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */
- return sch->st;
+ err = sch->st;
+ goto out;
}
/* Initialization for io subchannels. */
- if (!sch->schib.pmcw.dnv)
+ if (!sch->schib.pmcw.dnv) {
/* io subchannel but device number is invalid. */
- return -ENODEV;
-
+ err = -ENODEV;
+ goto out;
+ }
/* Devno is valid. */
if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
/*
CIO_MSG_EVENT(0, "Blacklisted device detected "
"at devno %04X, subchannel set %x\n",
sch->schib.pmcw.dev, sch->schid.ssid);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
sch->opm = 0xff;
if (!cio_is_console(sch->schid))
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1; /* multipath mode */
return 0;
+out:
+ if (!cio_is_console(schid))
+ kfree(sch->lock);
+ sch->lock = NULL;
+ return err;
}
/*
}
sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
if (sch)
- spin_lock(&sch->lock);
+ spin_lock(sch->lock);
/* Store interrupt response block to lowcore. */
if (tsch (tpi_info->schid, irb) == 0 && sch) {
/* Keep subchannel information word up to date. */
sch->driver->irq(&sch->dev);
}
if (sch)
- spin_unlock(&sch->lock);
+ spin_unlock(sch->lock);
/*
* Are more interrupts pending?
* If so, the tpi instruction will update the lowcore
__ctl_load (cr6, 6, 6);
do {
- spin_unlock(&console_subchannel.lock);
+ spin_unlock(console_subchannel.lock);
if (!cio_tpi())
cpu_relax();
- spin_lock(&console_subchannel.lock);
+ spin_lock(console_subchannel.lock);
} while (console_subchannel.schib.scsw.actl != 0);
/*
* restore previous isc value
/* subchannel data structure used by I/O subroutines */
struct subchannel {
struct subchannel_id schid;
- spinlock_t lock; /* subchannel lock */
+ spinlock_t *lock; /* subchannel lock */
struct mutex reg_mutex;
enum {
SUBCHANNEL_TYPE_IO = 0,
extern int cio_get_options (struct subchannel *);
extern int cio_modify (struct subchannel *);
+int cio_create_sch_lock(struct subchannel *);
+
/* Use with care. */
#ifdef CONFIG_CCW_CONSOLE
extern struct subchannel *cio_probe_console(void);
extern void cio_release_console(void);
extern int cio_is_console(struct subchannel_id);
extern struct subchannel *cio_get_console_subchannel(void);
+extern spinlock_t * cio_get_console_lock(void);
#else
#define cio_is_console(schid) 0
#define cio_get_console_subchannel() NULL
+#define cio_get_console_lock() NULL;
#endif
extern int cio_show_msg;
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
+ kfree(sch->lock);
kfree(sch);
}
-
}
static void
struct subchannel *sch;
sch = to_subchannel(dev);
- if (!cio_is_console(sch->schid))
+ if (!cio_is_console(sch->schid)) {
+ kfree(sch->lock);
kfree(sch);
+ }
}
extern int css_get_ssd_info(struct subchannel *sch);
sch->dev.parent = &css[0]->device;
sch->dev.bus = &css_bus_type;
sch->dev.release = &css_subchannel_release;
-
+ sch->dev.groups = subch_attr_groups;
+
/* make it known to the system */
ret = css_sch_device_register(sch);
- if (ret)
+ if (ret) {
printk (KERN_WARNING "%s: could not register %s\n",
__func__, sch->dev.bus_id);
- else
- css_get_ssd_info(sch);
+ return ret;
+ }
+ css_get_ssd_info(sch);
return ret;
}
unsigned long flags;
enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
disc = device_is_disconnected(sch);
if (disc && slow) {
/* Disconnected devices are evaluated directly only.*/
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
return 0;
}
/* No interrupt after machine check - kill pending timers. */
device_kill_pending_timer(sch);
if (!disc && !slow) {
/* Non-disconnected devices are evaluated on the slow path. */
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
return -EAGAIN;
}
event = css_get_subchannel_status(sch);
/* Ask driver what to do with device. */
action = UNREGISTER;
if (sch->driver && sch->driver->notify) {
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
ret = sch->driver->notify(&sch->dev, event);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
if (ret)
action = NONE;
}
case UNREGISTER:
case UNREGISTER_PROBE:
/* Unregister device (will use subchannel lock). */
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
css_sch_device_unregister(sch);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
default:
break;
}
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
/* Probe if necessary. */
if (action == UNREGISTER_PROBE)
ret = css_probe_device(sch->schid);
static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
-static inline void __init
-setup_css(int nr)
+static inline int __init setup_css(int nr)
{
u32 tod_high;
+ int ret;
memset(css[nr], 0, sizeof(struct channel_subsystem));
+ css[nr]->pseudo_subchannel =
+ kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
+ if (!css[nr]->pseudo_subchannel)
+ return -ENOMEM;
+ css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
+ css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+ if (ret) {
+ kfree(css[nr]->pseudo_subchannel);
+ return ret;
+ }
mutex_init(&css[nr]->mutex);
css[nr]->valid = 1;
css[nr]->cssid = nr;
css[nr]->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
css_generate_pgid(css[nr], tod_high);
+ return 0;
}
/*
ret = -ENOMEM;
goto out_unregister;
}
- setup_css(i);
- ret = device_register(&css[i]->device);
+ ret = setup_css(i);
if (ret)
goto out_free;
+ ret = device_register(&css[i]->device);
+ if (ret)
+ goto out_free_all;
if (css_characteristics_avail &&
css_chsc_characteristics.secm) {
ret = device_create_file(&css[i]->device,
if (ret)
goto out_device;
}
+ ret = device_register(&css[i]->pseudo_subchannel->dev);
+ if (ret)
+ goto out_file;
}
css_init_done = 1;
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_file:
+ device_remove_file(&css[i]->device, &dev_attr_cm_enable);
out_device:
device_unregister(&css[i]->device);
+out_free_all:
+ kfree(css[i]->pseudo_subchannel->lock);
+ kfree(css[i]->pseudo_subchannel);
out_free:
kfree(css[i]);
out_unregister:
while (i > 0) {
i--;
+ device_unregister(&css[i]->pseudo_subchannel->dev);
if (css_characteristics_avail && css_chsc_characteristics.secm)
device_remove_file(&css[i]->device,
&dev_attr_cm_enable);
return ret;
}
+int sch_is_pseudo_sch(struct subchannel *sch)
+{
+ return sch == to_css(sch->dev.parent)->pseudo_subchannel;
+}
+
/*
* find a driver for a subchannel. They identify by the subchannel
* type with the exception that the console subchannel driver has its own
} __attribute__ ((packed,aligned(4)));
struct ccw_device_private {
+ struct ccw_device *cdev;
+ struct subchannel *sch;
int state; /* device state */
atomic_t onoff;
unsigned long registered;
int cm_enabled;
void *cub_addr1;
void *cub_addr2;
+ /* for orphaned ccw devices */
+ struct subchannel *pseudo_subchannel;
};
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
int css_slow_subchannels_exist(void);
extern int need_rescan;
+int sch_is_pseudo_sch(struct subchannel *);
+
extern struct workqueue_struct *slow_path_wq;
extern struct work_struct slow_path_work;
+
+int subchannel_add_files (struct device *);
+extern struct attribute_group *subch_attr_groups[];
#endif
#include <asm/param.h> /* HZ */
#include "cio.h"
+#include "cio_debug.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
ssize_t ret = 0;
int chp;
- for (chp = 0; chp < 8; chp++)
- ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
-
+ if (ssd)
+ for (chp = 0; chp < 8; chp++)
+ ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
+ else
+ ret += sprintf (buf, "n/a");
ret += sprintf (buf+ret, "\n");
return min((ssize_t)PAGE_SIZE, ret);
}
return sprintf(buf, cdev->online ? "1\n" : "0\n");
}
+int ccw_device_is_orphan(struct ccw_device *cdev)
+{
+ return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent));
+}
+
+static void ccw_device_unregister(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
+ if (test_and_clear_bit(1, &cdev->private->registered))
+ device_unregister(&cdev->dev);
+ put_device(&cdev->dev);
+}
+
static void
ccw_device_remove_disconnected(struct ccw_device *cdev)
{
struct subchannel *sch;
+ unsigned long flags;
/*
* Forced offline in disconnected state means
* 'throw away device'.
*/
+ if (ccw_device_is_orphan(cdev)) {
+ /* Deregister ccw device. */
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ cdev->private->state = DEV_STATE_NOT_OPER;
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_unregister);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
+ return ;
+ }
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
struct ccw_device *cdev = to_ccwdev(dev);
struct subchannel *sch;
+ if (ccw_device_is_orphan(cdev))
+ return sprintf(buf, "no device\n");
switch (cdev->private->state) {
case DEV_STATE_BOXED:
return sprintf(buf, "boxed\n");
.attrs = subch_attrs,
};
-static inline int
-subchannel_add_files (struct device *dev)
-{
- return sysfs_create_group(&dev->kobj, &subch_attr_group);
-}
+struct attribute_group *subch_attr_groups[] = {
+ &subch_attr_group,
+ NULL,
+};
static struct attribute * ccwdev_attrs[] = {
&dev_attr_devtype.attr,
cdev = to_ccwdev(dev);
if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
+ !ccw_device_is_orphan(cdev) &&
ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
- (cdev != d->sibling)) {
- cdev->private->state = DEV_STATE_NOT_OPER;
+ (cdev != d->sibling))
return 1;
- }
return 0;
}
return dev ? to_ccwdev(dev) : NULL;
}
-static void
-ccw_device_add_changed(void *data)
+static int match_orphan(struct device *dev, void *data)
+{
+ struct ccw_dev_id *dev_id;
+ struct ccw_device *cdev;
+
+ dev_id = data;
+ cdev = to_ccwdev(dev);
+ return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
+}
+
+static struct ccw_device *
+get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
+ struct ccw_dev_id *dev_id)
{
+ struct device *dev;
+ dev = device_find_child(&css->pseudo_subchannel->dev, dev_id,
+ match_orphan);
+
+ return dev ? to_ccwdev(dev) : NULL;
+}
+
+static void
+ccw_device_add_changed(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
if (device_add(&cdev->dev)) {
put_device(&cdev->dev);
return;
}
}
-extern int css_get_ssd_info(struct subchannel *sch);
-
-void
-ccw_device_do_unreg_rereg(void *data)
+void ccw_device_do_unreg_rereg(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
- int need_rename;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
- if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
- /*
- * The device number has changed. This is usually only when
- * a device has been detached under VM and then re-appeared
- * on another subchannel because of a different attachment
- * order than before. Ideally, we should should just switch
- * subchannels, but unfortunately, this is not possible with
- * the current implementation.
- * Instead, we search for the old subchannel for this device
- * number and deregister so there are no collisions with the
- * newly registered ccw_device.
- * FIXME: Find another solution so the block layer doesn't
- * get possibly sick...
- */
- struct ccw_device *other_cdev;
- struct ccw_dev_id dev_id;
-
- need_rename = 1;
- dev_id.devno = sch->schib.pmcw.dev;
- dev_id.ssid = sch->schid.ssid;
- other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
- if (other_cdev) {
- struct subchannel *other_sch;
-
- other_sch = to_subchannel(other_cdev->dev.parent);
- if (get_device(&other_sch->dev)) {
- stsch(other_sch->schid, &other_sch->schib);
- if (other_sch->schib.pmcw.dnv) {
- other_sch->schib.pmcw.intparm = 0;
- cio_modify(other_sch);
- }
- css_sch_device_unregister(other_sch);
- }
- }
- /* Update ssd info here. */
- css_get_ssd_info(sch);
- cdev->private->dev_id.devno = sch->schib.pmcw.dev;
- } else
- need_rename = 0;
+
device_remove_files(&cdev->dev);
if (test_and_clear_bit(1, &cdev->private->registered))
device_del(&cdev->dev);
- if (need_rename)
- snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
- sch->schid.ssid, sch->schib.pmcw.dev);
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_add_changed, cdev);
+ ccw_device_add_changed);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
kfree(cdev);
}
+static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ if (cdev) {
+ cdev->private = kzalloc(sizeof(struct ccw_device_private),
+ GFP_KERNEL | GFP_DMA);
+ if (cdev->private)
+ return cdev;
+ }
+ kfree(cdev);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int io_subchannel_initialize_dev(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ cdev->private->cdev = cdev;
+ atomic_set(&cdev->private->onoff, 0);
+ cdev->dev.parent = &sch->dev;
+ cdev->dev.release = ccw_device_release;
+ INIT_LIST_HEAD(&cdev->private->kick_work.entry);
+ /* Do first half of device_register. */
+ device_initialize(&cdev->dev);
+ if (!get_device(&sch->dev)) {
+ if (cdev->dev.release)
+ cdev->dev.release(&cdev->dev);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+ int ret;
+
+ cdev = io_subchannel_allocate_dev(sch);
+ if (!IS_ERR(cdev)) {
+ ret = io_subchannel_initialize_dev(sch, cdev);
+ if (ret) {
+ kfree(cdev);
+ cdev = ERR_PTR(ret);
+ }
+ }
+ return cdev;
+}
+
+static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
+
+static void sch_attach_device(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ spin_lock_irq(sch->lock);
+ sch->dev.driver_data = cdev;
+ cdev->private->schid = sch->schid;
+ cdev->ccwlock = sch->lock;
+ device_trigger_reprobe(sch);
+ spin_unlock_irq(sch->lock);
+}
+
+static void sch_attach_disconnected_device(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ struct subchannel *other_sch;
+ int ret;
+
+ other_sch = to_subchannel(get_device(cdev->dev.parent));
+ ret = device_move(&cdev->dev, &sch->dev);
+ if (ret) {
+ CIO_MSG_EVENT(2, "Moving disconnected device 0.%x.%04x failed "
+ "(ret=%d)!\n", cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
+ put_device(&other_sch->dev);
+ return;
+ }
+ other_sch->dev.driver_data = NULL;
+ /* No need to keep a subchannel without ccw device around. */
+ css_sch_device_unregister(other_sch);
+ put_device(&other_sch->dev);
+ sch_attach_device(sch, cdev);
+}
+
+static void sch_attach_orphaned_device(struct subchannel *sch,
+ struct ccw_device *cdev)
+{
+ int ret;
+
+ /* Try to move the ccw device to its new subchannel. */
+ ret = device_move(&cdev->dev, &sch->dev);
+ if (ret) {
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
+ "failed (ret=%d)!\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
+ return;
+ }
+ sch_attach_device(sch, cdev);
+}
+
+static void sch_create_and_recog_new_device(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ /* Need to allocate a new ccw device. */
+ cdev = io_subchannel_create_ccwdev(sch);
+ if (IS_ERR(cdev)) {
+ /* OK, we did everything we could... */
+ css_sch_device_unregister(sch);
+ return;
+ }
+ spin_lock_irq(sch->lock);
+ sch->dev.driver_data = cdev;
+ spin_unlock_irq(sch->lock);
+ /* Start recognition for the new ccw device. */
+ if (io_subchannel_recog(cdev, sch)) {
+ spin_lock_irq(sch->lock);
+ sch->dev.driver_data = NULL;
+ spin_unlock_irq(sch->lock);
+ if (cdev->dev.release)
+ cdev->dev.release(&cdev->dev);
+ css_sch_device_unregister(sch);
+ }
+}
+
+
+void ccw_device_move_to_orphanage(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
+ struct ccw_device *replacing_cdev;
+ struct subchannel *sch;
+ int ret;
+ struct channel_subsystem *css;
+ struct ccw_dev_id dev_id;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
+ sch = to_subchannel(cdev->dev.parent);
+ css = to_css(sch->dev.parent);
+ dev_id.devno = sch->schib.pmcw.dev;
+ dev_id.ssid = sch->schid.ssid;
+
+ /*
+ * Move the orphaned ccw device to the orphanage so the replacing
+ * ccw device can take its place on the subchannel.
+ */
+ ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev);
+ if (ret) {
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
+ "(ret=%d)!\n", cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, ret);
+ return;
+ }
+ cdev->ccwlock = css->pseudo_subchannel->lock;
+ /*
+ * Search for the replacing ccw device
+ * - among the disconnected devices
+ * - in the orphanage
+ */
+ replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
+ if (replacing_cdev) {
+ sch_attach_disconnected_device(sch, replacing_cdev);
+ return;
+ }
+ replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
+ if (replacing_cdev) {
+ sch_attach_orphaned_device(sch, replacing_cdev);
+ return;
+ }
+ sch_create_and_recog_new_device(sch);
+}
+
/*
* Register recognized device.
*/
static void
-io_subchannel_register(void *data)
+io_subchannel_register(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
unsigned long flags;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
/*
printk (KERN_WARNING "%s: could not register %s\n",
__func__, cdev->dev.bus_id);
put_device(&cdev->dev);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
sch->dev.driver_data = NULL;
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
kfree (cdev->private);
kfree (cdev);
put_device(&sch->dev);
wake_up(&ccw_device_init_wq);
return;
}
-
- ret = subchannel_add_files(cdev->dev.parent);
- if (ret)
- printk(KERN_WARNING "%s: could not add attributes to %s\n",
- __func__, sch->dev.bus_id);
put_device(&cdev->dev);
out:
cdev->private->flags.recog_done = 1;
}
void
-ccw_device_call_sch_unregister(void *data)
+ccw_device_call_sch_unregister(struct work_struct *work)
{
- struct ccw_device *cdev = data;
+ struct ccw_device_private *priv;
+ struct ccw_device *cdev;
struct subchannel *sch;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
break;
sch = to_subchannel(cdev->dev.parent);
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister, cdev);
+ ccw_device_call_sch_unregister);
queue_work(slow_path_wq, &cdev->private->kick_work);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
if (!get_device(&cdev->dev))
break;
PREPARE_WORK(&cdev->private->kick_work,
- io_subchannel_register, cdev);
+ io_subchannel_register);
queue_work(slow_path_wq, &cdev->private->kick_work);
break;
}
sch->dev.driver_data = cdev;
sch->driver = &io_subchannel_driver;
- cdev->ccwlock = &sch->lock;
+ cdev->ccwlock = sch->lock;
/* Init private data. */
priv = cdev->private;
atomic_inc(&ccw_device_init_count);
/* Start async. device sensing. */
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
rc = ccw_device_recognition(cdev);
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
if (rc) {
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
return rc;
}
+static void ccw_device_move_to_sch(struct work_struct *work)
+{
+ struct ccw_device_private *priv;
+ int rc;
+ struct subchannel *sch;
+ struct ccw_device *cdev;
+ struct subchannel *former_parent;
+
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ sch = priv->sch;
+ cdev = priv->cdev;
+ former_parent = ccw_device_is_orphan(cdev) ?
+ NULL : to_subchannel(get_device(cdev->dev.parent));
+ mutex_lock(&sch->reg_mutex);
+ /* Try to move the ccw device to its new subchannel. */
+ rc = device_move(&cdev->dev, &sch->dev);
+ mutex_unlock(&sch->reg_mutex);
+ if (rc) {
+ CIO_MSG_EVENT(2, "Moving device 0.%x.%04x to subchannel "
+ "0.%x.%04x failed (ret=%d)!\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no, rc);
+ css_sch_device_unregister(sch);
+ goto out;
+ }
+ if (former_parent) {
+ spin_lock_irq(former_parent->lock);
+ former_parent->dev.driver_data = NULL;
+ spin_unlock_irq(former_parent->lock);
+ css_sch_device_unregister(former_parent);
+ /* Reset intparm to zeroes. */
+ former_parent->schib.pmcw.intparm = 0;
+ cio_modify(former_parent);
+ }
+ sch_attach_device(sch, cdev);
+out:
+ if (former_parent)
+ put_device(&former_parent->dev);
+ put_device(&cdev->dev);
+}
+
static int
io_subchannel_probe (struct subchannel *sch)
{
struct ccw_device *cdev;
int rc;
unsigned long flags;
+ struct ccw_dev_id dev_id;
if (sch->dev.driver_data) {
/*
cdev = sch->dev.driver_data;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
- subchannel_add_files(&sch->dev);
/*
* Check if the device is already online. If it is
* the reference count needs to be corrected
get_device(&cdev->dev);
return 0;
}
- cdev = kzalloc (sizeof(*cdev), GFP_KERNEL);
+ /*
+ * First check if a fitting device may be found amongst the
+ * disconnected devices or in the orphanage.
+ */
+ dev_id.devno = sch->schib.pmcw.dev;
+ dev_id.ssid = sch->schid.ssid;
+ cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
if (!cdev)
- return -ENOMEM;
- cdev->private = kzalloc(sizeof(struct ccw_device_private),
- GFP_KERNEL | GFP_DMA);
- if (!cdev->private) {
- kfree(cdev);
- return -ENOMEM;
- }
- atomic_set(&cdev->private->onoff, 0);
- cdev->dev.parent = &sch->dev;
- cdev->dev.release = ccw_device_release;
- INIT_LIST_HEAD(&cdev->private->kick_work.entry);
- /* Do first half of device_register. */
- device_initialize(&cdev->dev);
-
- if (!get_device(&sch->dev)) {
- if (cdev->dev.release)
- cdev->dev.release(&cdev->dev);
- return -ENODEV;
+ cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
+ &dev_id);
+ if (cdev) {
+ /*
+ * Schedule moving the device until when we have a registered
+ * subchannel to move to and succeed the probe. We can
+ * unregister later again, when the probe is through.
+ */
+ cdev->private->sch = sch;
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_move_to_sch);
+ queue_work(slow_path_wq, &cdev->private->kick_work);
+ return 0;
}
+ cdev = io_subchannel_create_ccwdev(sch);
+ if (IS_ERR(cdev))
+ return PTR_ERR(cdev);
rc = io_subchannel_recog(cdev, sch);
if (rc) {
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
sch->dev.driver_data = NULL;
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
if (cdev->dev.release)
cdev->dev.release(&cdev->dev);
}
return rc;
}
-static void
-ccw_device_unregister(void *data)
-{
- struct ccw_device *cdev;
-
- cdev = (struct ccw_device *)data;
- if (test_and_clear_bit(1, &cdev->private->registered))
- device_unregister(&cdev->dev);
- put_device(&cdev->dev);
-}
-
static int
io_subchannel_remove (struct subchannel *sch)
{
*/
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_unregister, cdev);
+ ccw_device_unregister);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
return 0;
static struct ccw_device_private console_private;
static int console_cdev_in_use;
+static DEFINE_SPINLOCK(ccw_console_lock);
+
+spinlock_t * cio_get_console_lock(void)
+{
+ return &ccw_console_lock;
+}
+
static int
ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
{
memset(&console_cdev, 0, sizeof(struct ccw_device));
memset(&console_private, 0, sizeof(struct ccw_device_private));
console_cdev.private = &console_private;
+ console_private.cdev = &console_cdev;
ret = ccw_device_console_enable(&console_cdev, sch);
if (ret) {
cio_release_console();
int ccw_device_cancel_halt_clear(struct ccw_device *);
-void ccw_device_do_unreg_rereg(void *);
-void ccw_device_call_sch_unregister(void *);
+void ccw_device_do_unreg_rereg(struct work_struct *);
+void ccw_device_call_sch_unregister(struct work_struct *);
+void ccw_device_move_to_orphanage(struct work_struct *);
+int ccw_device_is_orphan(struct ccw_device *);
int ccw_device_recognition(struct ccw_device *);
int ccw_device_online(struct ccw_device *);
/*
* Check if cu type and device type still match. If
* not, it is certainly another device and we have to
- * de- and re-register. Also check here for non-matching devno.
+ * de- and re-register.
*/
if (cdev->id.cu_type != cdev->private->senseid.cu_type ||
cdev->id.cu_model != cdev->private->senseid.cu_model ||
cdev->id.dev_type != cdev->private->senseid.dev_type ||
- cdev->id.dev_model != cdev->private->senseid.dev_model ||
- cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
+ cdev->id.dev_model != cdev->private->senseid.dev_model) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_do_unreg_rereg, cdev);
+ ccw_device_do_unreg_rereg);
queue_work(ccw_device_work, &cdev->private->kick_work);
return 0;
}
}
static void
-ccw_device_oper_notify(void *data)
+ccw_device_oper_notify(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
ret = (sch->driver && sch->driver->notify) ?
sch->driver->notify(&sch->dev, CIO_OPER) : 0;
if (!ret)
/* Driver doesn't want device back. */
- ccw_device_do_unreg_rereg(cdev);
+ ccw_device_do_unreg_rereg(work);
else {
/* Reenable channel measurements, if needed. */
cmf_reenable(cdev);
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
- PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify,
- cdev);
+ PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
static void
-ccw_device_nopath_notify(void *data)
+ccw_device_nopath_notify(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
- cdev = data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
sch = to_subchannel(cdev->dev.parent);
/* Extra sanity. */
if (sch->lpm)
cio_disable_subchannel(sch);
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister,
- cdev);
+ ccw_device_call_sch_unregister);
queue_work(ccw_device_work,
&cdev->private->kick_work);
} else
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
{
struct subchannel *sch;
+ if (ccw_device_is_orphan(cdev)) {
+ ccw_device_done(cdev, DEV_STATE_OFFLINE);
+ return 0;
+ }
sch = to_subchannel(cdev->dev.parent);
if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
return -ENODEV;
sch = to_subchannel(cdev->dev.parent);
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister, cdev);
+ ccw_device_call_sch_unregister);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
}
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister, cdev);
+ ccw_device_call_sch_unregister);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
sch = to_subchannel(cdev->dev.parent);
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
ERR_PTR(-EIO));
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
} else if (cdev->private->flags.doverify)
/* Start delayed path verification. */
sch = to_subchannel(cdev->dev.parent);
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
if (ret == -ENODEV) {
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
ERR_PTR(-EIO));
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, cdev);
+ ccw_device_nopath_notify);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
} else
/* Start delayed path verification. */
/* Update some values. */
if (stsch(sch->schid, &sch->schib))
return;
-
+ if (!sch->schib.pmcw.dnv)
+ return;
/*
* The pim, pam, pom values may not be accurate, but they are the best
* we have before performing device selection :/
sch->schib.pmcw.mp = 1;
sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
/* We should also udate ssd info, but this has to wait. */
- ccw_device_start_id(cdev, 0);
+ /* Check if this is another device which appeared on the same sch. */
+ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_move_to_orphanage);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ } else
+ ccw_device_start_id(cdev, 0);
}
static void
ccw_device_set_timeout(cdev, 0);
if (ret == -EBUSY) {
/* Try again later. */
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
msleep(10);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
continue;
}
if (ret != 0)
break;
/* Wait for end of request. */
cdev->private->intparm = magic;
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
wait_event(cdev->private->wait_q,
(cdev->private->intparm == -EIO) ||
(cdev->private->intparm == -EAGAIN) ||
(cdev->private->intparm == 0));
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
/* Check at least for channel end / device end */
if (cdev->private->intparm == -EIO) {
/* Non-retryable error. */
/* Success. */
break;
/* Try again later. */
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
msleep(10);
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
} while (1);
return ret;
return ret;
}
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
/* Save interrupt handler. */
handler = cdev->handler;
/* Temporarily install own handler. */
/* Restore interrupt handler. */
cdev->handler = handler;
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
clear_normalized_cda (rdc_ccw);
kfree(rdc_ccw);
rcd_ccw->count = ciw->count;
rcd_ccw->flags = CCW_FLAG_SLI;
- spin_lock_irq(&sch->lock);
+ spin_lock_irq(sch->lock);
/* Save interrupt handler. */
handler = cdev->handler;
/* Temporarily install own handler. */
/* Restore interrupt handler. */
cdev->handler = handler;
- spin_unlock_irq(&sch->lock);
+ spin_unlock_irq(sch->lock);
/*
* on success we update the user input parms
kfree(buf);
return -ENOMEM;
}
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
ret = cio_enable_subchannel(sch, 3);
if (ret)
goto out_unlock;
goto out_unlock;
}
cdev->private->irb.scsw.actl |= SCSW_ACTL_START_PEND;
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
wait_event(cdev->private->wait_q, cdev->private->irb.scsw.actl == 0);
- spin_lock_irqsave(&sch->lock, flags);
+ spin_lock_irqsave(sch->lock, flags);
cio_disable_subchannel(sch); //FIXME: return code?
if ((cdev->private->irb.scsw.dstat !=
(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
out_unlock:
kfree(buf);
kfree(buf2);
- spin_unlock_irqrestore(&sch->lock, flags);
+ spin_unlock_irqrestore(sch->lock, flags);
return ret;
}
#include <asm/timex.h>
#include <asm/debug.h>
+#include <asm/s390_rdev.h>
#include <asm/qdio.h>
#include "cio.h"
/******************** HERE WE GO ***********************************/
static const char version[] = "QDIO base support version 2";
+extern struct bus_type ccw_bus_type;
-#ifdef QDIO_PERFORMANCE_STATS
+static int qdio_performance_stats = 0;
static int proc_perf_file_registration;
static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
static struct qdio_perf_stats perf_stats;
-#endif /* QDIO_PERFORMANCE_STATS */
static int hydra_thinints;
static int is_passthrough = 0;
QDIO_DBF_TEXT4(0,trace,"sigasync");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_syncs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_syncs++;
cc = do_siga_sync(q->schid, gpr2, gpr3);
if (cc)
__u32 busy_bit;
__u64 start_time=0;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_outs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_outs++;
QDIO_DBF_TEXT4(0,trace,"sigaout");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
QDIO_DBF_TEXT4(0,trace,"sigain");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_ins++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_ins++;
cc = do_siga_input(q->schid, q->mask);
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- o_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ o_p_c++;
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
}
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- o_p_nc++;
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ o_p_nc++;
+ perf_stats.tl_runs++;
+ }
/* see comment in qdio_kick_outbound_q */
siga_attempts=atomic_read(&q->busy_siga_counter);
{
int i;
-#ifdef QDIO_PERFORMANCE_STATS
static int old_pcis=0;
static int old_thinints=0;
- if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))
- perf_stats.start_time_inbound=NOW;
- else
- old_pcis=perf_stats.pcis;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ if ((old_pcis==perf_stats.pcis)&&
+ (old_thinints==perf_stats.thinints))
+ perf_stats.start_time_inbound=NOW;
+ else
+ old_pcis=perf_stats.pcis;
+ }
i=qdio_get_inbound_buffer_frontier(q);
if ( (i!=GET_SAVED_FRONTIER(q)) ||
q->siga_error=0;
q->error_status_flags=0;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
- perf_stats.inbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
+ perf_stats.inbound_cnt++;
+ }
}
static inline void
*/
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_c++;
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
tiqdio_sched_tl();
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_nc++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_nc++;
if (unlikely(atomic_read(&q->is_in_shutdown))) {
qdio_unmark_q(q);
goto out;
irq_ptr = (struct qdio_irq*)q->irq_ptr;
for (i=0;i<irq_ptr->no_output_qs;i++) {
oq = irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
- if (!qdio_is_outbound_q_done(oq))
+ if (!qdio_is_outbound_q_done(oq)) {
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
__qdio_outbound_processing(oq);
+ }
}
}
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- i_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ i_p_c++;
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
}
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- i_p_nc++;
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ i_p_nc++;
+ perf_stats.tl_runs++;
+ }
again:
if (qdio_has_inbound_q_moved(q)) {
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_c++;
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
{
QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.tl_runs++;
tiqdio_inbound_checks();
}
{
QDIO_DBF_TEXT4(0,trace,"thin_int");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.thinints++;
- perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.thinints++;
+ perf_stats.start_time_inbound=NOW;
+ }
/* SVS only when needed:
* issue SVS to benefit from iqdio interrupt avoidance
int i;
struct qdio_q *q;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.pcis++;
- perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.pcis++;
+ perf_stats.start_time_inbound=NOW;
+ }
for (i=0;i<irq_ptr->no_input_qs;i++) {
q=irq_ptr->input_qs[i];
if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
qdio_mark_q(q);
else {
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
__qdio_inbound_processing(q);
}
}
return;
for (i=0;i<irq_ptr->no_output_qs;i++) {
q=irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
if (qdio_is_outbound_q_done(q))
continue;
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
if (!irq_ptr->sync_done_on_outb_pcis)
SYNC_MEMORY;
__qdio_outbound_processing(q);
}
static void
-qdio_call_shutdown(void *data)
+qdio_call_shutdown(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
- cdev = (struct ccw_device *)data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
put_device(&cdev->dev);
}
if (get_device(&cdev->dev)) {
/* Can't call shutdown from interrupt context. */
PREPARE_WORK(&cdev->private->kick_work,
- qdio_call_shutdown, (void *)cdev);
+ qdio_call_shutdown);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
break;
struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
/* This is the outbound handling of queues */
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.start_time_outbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.start_time_outbound=NOW;
qdio_do_qdio_fill_output(q,qidx,count,buffers);
used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
if (callflags&QDIO_FLAG_DONT_SIGA) {
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+ perf_stats.outbound_cnt++;
+ }
return;
}
if (q->is_iqdio_q) {
qdio_kick_outbound_q(q);
} else {
QDIO_DBF_TEXT3(0,trace, "fast-req");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.fast_reqs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.fast_reqs++;
}
}
/*
__qdio_outbound_processing(q);
}
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+ perf_stats.outbound_cnt++;
+ }
}
/* count must be 1 in iqdio */
return 0;
}
-#ifdef QDIO_PERFORMANCE_STATS
static int
qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
int buffer_length, int *eof, void *data)
_OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
_OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
_OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
- _OUTP_IT("Number of tasklet runs (total) : %u\n",
+ _OUTP_IT("Number of tasklet runs (total) : %lu\n",
perf_stats.tl_runs);
_OUTP_IT("\n");
- _OUTP_IT("Number of SIGA sync's issued : %u\n",
+ _OUTP_IT("Number of SIGA sync's issued : %lu\n",
perf_stats.siga_syncs);
- _OUTP_IT("Number of SIGA in's issued : %u\n",
+ _OUTP_IT("Number of SIGA in's issued : %lu\n",
perf_stats.siga_ins);
- _OUTP_IT("Number of SIGA out's issued : %u\n",
+ _OUTP_IT("Number of SIGA out's issued : %lu\n",
perf_stats.siga_outs);
- _OUTP_IT("Number of PCIs caught : %u\n",
+ _OUTP_IT("Number of PCIs caught : %lu\n",
perf_stats.pcis);
- _OUTP_IT("Number of adapter interrupts caught : %u\n",
+ _OUTP_IT("Number of adapter interrupts caught : %lu\n",
perf_stats.thinints);
- _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %u\n",
+ _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %lu\n",
perf_stats.fast_reqs);
_OUTP_IT("\n");
- _OUTP_IT("Total time of all inbound actions (us) incl. UL : %u\n",
+ _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n",
perf_stats.inbound_time);
- _OUTP_IT("Number of inbound transfers : %u\n",
+ _OUTP_IT("Number of inbound transfers : %lu\n",
perf_stats.inbound_cnt);
- _OUTP_IT("Total time of all outbound do_QDIOs (us) : %u\n",
+ _OUTP_IT("Total time of all outbound do_QDIOs (us) : %lu\n",
perf_stats.outbound_time);
- _OUTP_IT("Number of do_QDIOs outbound : %u\n",
+ _OUTP_IT("Number of do_QDIOs outbound : %lu\n",
perf_stats.outbound_cnt);
_OUTP_IT("\n");
}
static struct proc_dir_entry *qdio_perf_proc_file;
-#endif /* QDIO_PERFORMANCE_STATS */
static void
qdio_add_procfs_entry(void)
{
-#ifdef QDIO_PERFORMANCE_STATS
proc_perf_file_registration=0;
qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
S_IFREG|0444,&proc_root);
QDIO_PRINT_WARN("was not able to register perf. " \
"proc-file (%i).\n",
proc_perf_file_registration);
-#endif /* QDIO_PERFORMANCE_STATS */
}
static void
qdio_remove_procfs_entry(void)
{
-#ifdef QDIO_PERFORMANCE_STATS
perf_stats.tl_runs=0;
if (!proc_perf_file_registration) /* means if it went ok earlier */
remove_proc_entry(QDIO_PERF,&proc_root);
-#endif /* QDIO_PERFORMANCE_STATS */
}
+/**
+ * attributes in sysfs
+ *****************************************************************************/
+
+static ssize_t
+qdio_performance_stats_show(struct bus_type *bus, char *buf)
+{
+ return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
+}
+
+static ssize_t
+qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
+{
+ char *tmp;
+ int i;
+
+ i = simple_strtoul(buf, &tmp, 16);
+ if ((i == 0) || (i == 1)) {
+ if (i == qdio_performance_stats)
+ return count;
+ qdio_performance_stats = i;
+ if (i==0) {
+ /* reset perf. stat. info */
+ i_p_nc = 0;
+ i_p_c = 0;
+ ii_p_nc = 0;
+ ii_p_c = 0;
+ o_p_nc = 0;
+ o_p_c = 0;
+ memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
+ }
+ } else {
+ QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+ return -EINVAL;
+ }
+ return count;
+}
+
+static BUS_ATTR(qdio_performance_stats, 0644, qdio_performance_stats_show,
+ qdio_performance_stats_store);
+
static void
tiqdio_register_thinints(void)
{
kfree(indicators);
}
+
static void
qdio_unregister_dbf_views(void)
{
init_QDIO(void)
{
int res;
-#ifdef QDIO_PERFORMANCE_STATS
void *ptr;
-#endif /* QDIO_PERFORMANCE_STATS */
printk("qdio: loading %s\n",version);
return res;
QDIO_DBF_TEXT0(0,setup,"initQDIO");
+ res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
-#ifdef QDIO_PERFORMANCE_STATS
- memset((void*)&perf_stats,0,sizeof(perf_stats));
+ memset((void*)&perf_stats,0,sizeof(perf_stats));
QDIO_DBF_TEXT0(0,setup,"perfstat");
ptr=&perf_stats;
QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
-#endif /* QDIO_PERFORMANCE_STATS */
qdio_add_procfs_entry();
qdio_release_qdio_memory();
qdio_unregister_dbf_views();
mempool_destroy(qdio_mempool_scssc);
-
+ bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
printk("qdio: %s: module removed\n",version);
}
#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_USE_PROCESSING_STATE
-#ifdef CONFIG_QDIO_PERF_STATS
-#define QDIO_PERFORMANCE_STATS
-#endif /* CONFIG_QDIO_PERF_STATS */
-
#define QDIO_MINIMAL_BH_RELIEF_TIME 16
#define QDIO_TIMER_POLL_VALUE 1
#define IQDIO_TIMER_POLL_VALUE 1
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
-#ifdef QDIO_PERFORMANCE_STATS
struct qdio_perf_stats {
- unsigned int tl_runs;
+ unsigned long tl_runs;
- unsigned int siga_outs;
- unsigned int siga_ins;
- unsigned int siga_syncs;
- unsigned int pcis;
- unsigned int thinints;
- unsigned int fast_reqs;
+ unsigned long siga_outs;
+ unsigned long siga_ins;
+ unsigned long siga_syncs;
+ unsigned long pcis;
+ unsigned long thinints;
+ unsigned long fast_reqs;
__u64 start_time_outbound;
- unsigned int outbound_cnt;
- unsigned int outbound_time;
+ unsigned long outbound_cnt;
+ unsigned long outbound_time;
__u64 start_time_inbound;
- unsigned int inbound_cnt;
- unsigned int inbound_time;
+ unsigned long inbound_cnt;
+ unsigned long inbound_time;
};
-#endif /* QDIO_PERFORMANCE_STATS */
/* unlikely as the later the better */
#define SYNC_MEMORY if (unlikely(q->siga_sync)) qdio_siga_sync_q(q)
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <asm/s390_rdev.h>
+#include <asm/reset.h>
#include "ap_bus.h"
mutex_unlock(&ap_poll_thread_mutex);
}
+static void ap_reset(void)
+{
+ int i, j;
+
+ for (i = 0; i < AP_DOMAINS; i++)
+ for (j = 0; j < AP_DEVICES; j++)
+ ap_reset_queue(AP_MKQID(j, i));
+}
+
+static struct reset_call ap_reset_call = {
+ .fn = ap_reset,
+};
+
/**
* The module initialization code.
*/
printk(KERN_WARNING "AP instructions not installed.\n");
return -ENODEV;
}
+ register_reset_call(&ap_reset_call);
/* Create /sys/bus/ap. */
rc = bus_register(&ap_bus_type);
bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
bus_unregister(&ap_bus_type);
out:
+ unregister_reset_call(&ap_reset_call);
return rc;
}
for (i = 0; ap_bus_attrs[i]; i++)
bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
bus_unregister(&ap_bus_type);
+ unregister_reset_call(&ap_reset_call);
}
#ifndef CONFIG_ZCRYPT_MONOLITHIC
static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos)
{
long rc;
- unsigned minor = iminor(f->f_dentry->d_inode);
+ unsigned minor = iminor(f->f_path.dentry->d_inode);
if (minor >= BPP_NO) return -ENODEV;
if (!instances[minor].present) return -ENODEV;
static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos)
{
long errno = 0;
- unsigned minor = iminor(f->f_dentry->d_inode);
+ unsigned minor = iminor(f->f_path.dentry->d_inode);
if (minor >= BPP_NO) return -ENODEV;
if (!instances[minor].present) return -ENODEV;
case WIOCSTOP:
case WIOCGSTAT:
lock_kernel();
- rval = wd_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
unlock_kernel();
break;
/* everything else is handled by the generic compat layer */
__u8 ireg = 0;
int error = 0;
- if (D7S_MINOR != iminor(file->f_dentry->d_inode))
+ if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
return -ENODEV;
lock_kernel();
case OPROMSETCUR:
case OPROMPCI2NODE:
case OPROMPATH2NODE:
- rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ rval = openprom_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
break;
}
unsigned int map_size, ret, map_offset;
struct vfc_dev *dev;
- dev = vfc_get_dev_ptr(iminor(file->f_dentry->d_inode));
+ dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode));
if(dev == NULL)
return -ENODEV;
*/
static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+ struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
struct scsi_device *sdev = scsi_disk(disk)->device;
struct st_modedef *STm;
struct st_partstat *STps;
char *name = tape_name(STp);
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int mode = TAPE_MODE(inode);
STp->ready = ST_READY;
}
static void
-serial21285_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned long flags;
unsigned int baud, quot, h_lcr;
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
/* FIX UP modem control here someday......
*/
-static void rs_360_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
}
static void
-serial8250_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned char cval, fcr = 0;
}
static void
-pl010_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+pl010_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
}
static void
-pl011_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+pl011_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int lcr_h, old_cr;
unsigned long flags;
/*
* Change the port parameters
*/
-static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
+static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old)
{
unsigned long flags;
unsigned int mode, imr, quot, baud;
}
static void
-clps711xuart_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int ubrlcr, baud, quot;
unsigned long flags;
#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
-static struct termios *serial_termios[NR_PORTS];
-static struct termios *serial_termios_locked[NR_PORTS];
+static struct ktermios *serial_termios[NR_PORTS];
+static struct ktermios *serial_termios_locked[NR_PORTS];
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
static struct fast_timer fast_timers[NR_PORTS];
#endif
}
static void
-rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
driver->init_termios = tty_std_termios;
driver->init_termios.c_cflag =
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->termios = serial_termios;
driver->termios_locked = serial_termios_locked;
struct work_struct work;
struct async_icount icount; /* error-statistics etc.*/
- struct termios normal_termios;
- struct termios callout_termios;
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
#ifdef DECLARE_WAITQUEUE
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
spin_unlock_irqrestore(&uport->lock, flags);
}
-static void dz_set_termios(struct uart_port *uport, struct termios *termios,
- struct termios *old_termios)
+static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
+ struct ktermios *old_termios)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
}
static void icom_set_termios(struct uart_port *port,
- struct termios *termios,
- struct termios *old_termios)
+ struct ktermios *termios,
+ struct ktermios *old_termios)
{
int baud;
unsigned cflag, iflag;
}
static void
-imx_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+imx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
*/
static void
ioc3_change_speed(struct uart_port *the_port,
- struct termios *new_termios, struct termios *old_termios)
+ struct ktermios *new_termios, struct ktermios *old_termios)
{
struct ioc3_port *port = get_ioc3_port(the_port);
unsigned int cflag;
*/
static void
ic3_set_termios(struct uart_port *the_port,
- struct termios *termios, struct termios *old_termios)
+ struct ktermios *termios, struct ktermios *old_termios)
{
unsigned long port_flags;
*/
static void
ioc4_change_speed(struct uart_port *the_port,
- struct termios *new_termios, struct termios *old_termios)
+ struct ktermios *new_termios, struct ktermios *old_termios)
{
struct ioc4_port *port = get_ioc4_port(the_port, 0);
int baud, bits;
ioc4_set_proto(port, the_port->mapbase);
/* set the speed of the serial port */
- ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0);
+ ioc4_change_speed(the_port, info->tty->termios, (struct ktermios *)0);
return 0;
}
*/
static void
ic4_set_termios(struct uart_port *the_port,
- struct termios *termios, struct termios *old_termios)
+ struct ktermios *termios, struct ktermios *old_termios)
{
unsigned long port_flags;
/* The port lock is not held. */
static void
-ip22zilog_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
unsigned long flags;
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
- struct termios *termios;
+ struct ktermios *termios;
spin_lock_irqsave(&port->lock, lock_flags);
termios = port->info->tty->termios;
struct jsm_board *brd;
int rc = 0;
struct jsm_channel *channel = (struct jsm_channel *)port;
- struct termios *termios;
+ struct ktermios *termios;
/* Get board pointer from our array of majors we have allocated */
brd = channel->ch_bd;
static void jsm_tty_close(struct uart_port *port)
{
struct jsm_board *bd;
- struct termios *ts;
+ struct ktermios *ts;
struct jsm_channel *channel = (struct jsm_channel *)port;
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
}
static void jsm_tty_set_termios(struct uart_port *port,
- struct termios *termios,
- struct termios *old_termios)
+ struct ktermios *termios,
+ struct ktermios *old_termios)
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
}
static void m32r_sio_set_termios(struct uart_port *port,
- struct termios *termios, struct termios *old)
+ struct ktermios *termios, struct ktermios *old)
{
struct uart_sio_port *up = (struct uart_sio_port *)port;
unsigned char cval = 0;
return 0;
}
-static void mcfrs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
}
static void
-mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
- struct termios *old)
+mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
+ struct ktermios *old)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
}
static void
-mpsc_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
u32 baud;
* The Serial Mux does not support this function.
*/
static void
-mux_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+mux_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
}
}
static void
-netx_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+netx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud, quot;
unsigned char old_cr;
}
-static void __pmz_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned long baud;
if (ZS_IS_ASLEEP(uap))
return;
- memcpy(&uap->termios_cache, termios, sizeof(struct termios));
+ memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));
/* XXX Check which revs of machines actually allow 1 and 4Mb speeds
* on the IR dongle. Note that the IRTTY driver currently doesn't know
}
/* The port lock is not held. */
-static void pmz_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pmac_port *uap = to_pmz(port);
unsigned long flags;
volatile struct dbdma_regs __iomem *tx_dma_regs;
volatile struct dbdma_regs __iomem *rx_dma_regs;
- struct termios termios_cache;
+ struct ktermios termios_cache;
};
#define to_pmz(p) ((struct uart_pmac_port *)(p))
}
static void
-serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned char cval, fcr = 0;
}
static void s3c24xx_serial_set_termios(struct uart_port *port,
- struct termios *termios,
- struct termios *old)
+ struct ktermios *termios,
+ struct ktermios *old)
{
struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
struct s3c24xx_uart_port *ourport = to_ourport(port);
}
static void
-sa1100_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct sa1100_port *sport = (struct sa1100_port *)port;
unsigned long flags;
#define uart_console(port) (0)
#endif
-static void uart_change_speed(struct uart_state *state, struct termios *old_termios);
+static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios);
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
static void uart_change_pm(struct uart_state *state, int pm_state);
* we're actually going to be using.
*/
unsigned int
-uart_get_baud_rate(struct uart_port *port, struct termios *termios,
- struct termios *old, unsigned int min, unsigned int max)
+uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old, unsigned int min, unsigned int max)
{
unsigned int try, baud, altbaud = 38400;
upf_t flags = port->flags & UPF_SPD_MASK;
EXPORT_SYMBOL(uart_get_divisor);
static void
-uart_change_speed(struct uart_state *state, struct termios *old_termios)
+uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
struct tty_struct *tty = state->info->tty;
struct uart_port *port = state->port;
- struct termios *termios;
+ struct ktermios *termios;
/*
* If we have no tty, termios, or the port does not exist,
return ret;
}
-static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow)
{
- struct termios termios;
+ struct ktermios termios;
int i;
/*
spin_lock_init(&port->lock);
lockdep_set_class(&port->lock, &port_lock_key);
- memset(&termios, 0, sizeof(struct termios));
+ memset(&termios, 0, sizeof(struct ktermios));
termios.c_cflag = CREAD | HUPCL | CLOCAL;
* Re-enable the console device after suspending.
*/
if (uart_console(port)) {
- struct termios termios;
+ struct ktermios termios;
/*
* First try to use the console cflag setting.
*/
- memset(&termios, 0, sizeof(struct termios));
+ memset(&termios, 0, sizeof(struct ktermios));
termios.c_cflag = port->cons->cflag;
/*
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
}
static void lh7a40xuart_set_termios (struct uart_port* port,
- struct termios* termios,
- struct termios* old)
+ struct ktermios* termios,
+ struct ktermios* old)
{
unsigned int con;
unsigned int inten;
}
static void
-serial_txx9_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
unsigned int cval, fcr = 0;
s->disable(port);
}
-static void sci_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct sci_port *s = &sci_ports[port->line];
unsigned int status, baud, smr_val;
*
*/
static void
-snp_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+snp_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
}
}
/* port->lock is not held. */
-static void sunhv_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
unsigned int quot = uart_get_divisor(port, baud);
}
/* port->lock is not held. */
-static void sunsab_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags;
}
static void
-sunsu_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+sunsu_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int baud, quot;
/* The port lock is not held. */
static void
-sunzilog_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
unsigned long flags;
free_irq(port->irq, port);
}
-static void ulite_set_termios(struct uart_port *port, struct termios *termios,
- struct termios *old)
+static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned long flags;
unsigned int baud;
}
static void
-v850e_uart_set_termios (struct uart_port *port, struct termios *termios,
- struct termios *old)
+v850e_uart_set_termios (struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
{
unsigned cflags = termios->c_cflag;
free_irq(port->irq, port);
}
-static void siu_set_termios(struct uart_port *port, struct termios *new,
- struct termios *old)
+static void siu_set_termios(struct uart_port *port, struct ktermios *new,
+ struct ktermios *old)
{
tcflag_t c_cflag, c_iflag;
uint8_t lcr, fcr, ier;
return 0;
}
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct dec_serial *info = (struct dec_serial *)tty->driver_data;
int was_stopped;
static ssize_t ixj_read(struct file * file_p, char __user *buf, size_t length, loff_t * ppos)
{
unsigned long i = *ppos;
- IXJ * j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ * j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
DECLARE_WAITQUEUE(wait, current);
{
int pre_retval;
ssize_t read_retval = 0;
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
pre_retval = ixj_PreRead(j, 0L);
switch (pre_retval) {
int pre_retval;
ssize_t write_retval = 0;
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
pre_retval = ixj_PreWrite(j, 0L);
switch (pre_retval) {
{
unsigned int mask = 0;
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
poll_wait(file_p, &(j->poll_q), wait);
if (j->read_buffer_ready > 0)
static int ixj_fasync(int fd, struct file *file_p, int mode)
{
- IXJ *j = get_ixj(NUM(file_p->f_dentry->d_inode));
+ IXJ *j = get_ixj(NUM(file_p->f_path.dentry->d_inode));
return fasync_helper(fd, file_p, mode, &j->async_queue);
}
5, 6, 7, 8
};
-static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
+static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
{
struct acm *acm = tty->driver_data;
- struct termios *termios = tty->termios;
+ struct ktermios *termios = tty->termios;
struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
{
loff_t retval = -EINVAL;
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch(orig) {
case 0:
if (offset > 0) {
default:
break;
}
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return retval;
}
if (!filp->f_op->fsync)
return -EINVAL;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
mutex_lock(&inode->i_mutex);
rc = filemap_fdatawrite(inode->i_mapping);
- err = filp->f_op->fsync(filp, filp->f_dentry, 1);
+ err = filp->f_op->fsync(filp, filp->f_path.dentry, 1);
if (!rc)
rc = err;
err = filemap_fdatawait(inode->i_mapping);
static void invalidate_sub(struct lun *curlun)
{
struct file *filp = curlun->filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned long rc;
rc = invalidate_inode_pages(inode->i_mapping);
if (!(filp->f_mode & FMODE_WRITE))
ro = 1;
- if (filp->f_dentry)
- inode = filp->f_dentry->d_inode;
+ if (filp->f_path.dentry)
+ inode = filp->f_path.dentry->d_inode;
if (inode && S_ISBLK(inode->i_mode)) {
if (bdev_read_only(inode->i_bdev))
ro = 1;
down_read(&fsg->filesem);
if (backing_file_is_open(curlun)) { // Get the complete pathname
- p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt,
+ p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
buf, PAGE_SIZE - 1);
if (IS_ERR(p))
rc = PTR_ERR(p);
if (backing_file_is_open(curlun)) {
p = NULL;
if (pathbuf) {
- p = d_path(curlun->filp->f_dentry,
- curlun->filp->f_vfsmnt,
+ p = d_path(curlun->filp->f_path.dentry,
+ curlun->filp->f_path.mnt,
pathbuf, PATH_MAX);
if (IS_ERR(p))
p = NULL;
static void gs_break(struct tty_struct *tty, int break_state);
static int gs_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
-static void gs_set_termios(struct tty_struct *tty, struct termios *old);
+static void gs_set_termios(struct tty_struct *tty, struct ktermios *old);
static int gs_send(struct gs_dev *dev);
static int gs_send_packet(struct gs_dev *dev, char *packet,
/*
* gs_set_termios
*/
-static void gs_set_termios(struct tty_struct *tty, struct termios *old)
+static void gs_set_termios(struct tty_struct *tty, struct ktermios *old)
{
}
config USB_HID
tristate "USB Human Interface Device (full HID) support"
- depends on USB
+ default y
+ depends on USB && HID
---help---
- Say Y here if you want full HID support to connect keyboards,
+ Say Y here if you want full HID support to connect USB keyboards,
mice, joysticks, graphic tablets, or any other HID based devices
to your computer via USB. You also need to select HID Input layer
support (below) if you want to use keyboards, mice, joysticks and
comment "Input core support is needed for USB HID input layer or HIDBP support"
depends on USB_HID && INPUT=n
-config USB_HIDINPUT
- bool "HID input layer support"
- default y
- depends on INPUT && USB_HID
- help
- Say Y here if you want to use a USB keyboard, mouse or joystick,
- or any other HID input device.
-
- If unsure, say Y.
-
-config USB_HIDINPUT_POWERBOOK
+config USB_HID_POWERBOOK
bool "Enable support for iBook/PowerBook special keys"
default n
- depends on USB_HIDINPUT
+ depends on USB_HID
help
Say Y here if you want support for the special keys (Fn, Numlock) on
Apple iBooks and PowerBooks.
config HID_FF
bool "Force feedback support (EXPERIMENTAL)"
- depends on USB_HIDINPUT && EXPERIMENTAL
+ depends on USB_HID && EXPERIMENTAL
help
Say Y here is you want force feedback support for a few HID devices.
See below for a list of supported devices.
ifeq ($(CONFIG_USB_HIDDEV),y)
usbhid-objs += hiddev.o
endif
-ifeq ($(CONFIG_USB_HIDINPUT),y)
- usbhid-objs += hid-input.o
-endif
ifeq ($(CONFIG_HID_PID),y)
usbhid-objs += hid-pidff.o
endif
#define APPLE_VENDOR_ID 0x05AC
/* These names come from Info.plist in AppleUSBTrackpad.kext */
-#define GEYSER_ANSI_PRODUCT_ID 0x0214
-#define GEYSER_ISO_PRODUCT_ID 0x0215
-#define GEYSER_JIS_PRODUCT_ID 0x0216
+#define FOUNTAIN_ANSI_PRODUCT_ID 0x020E
+#define FOUNTAIN_ISO_PRODUCT_ID 0x020F
+
+#define FOUNTAIN_TP_ONLY_PRODUCT_ID 0x030A
+
+#define GEYSER1_TP_ONLY_PRODUCT_ID 0x030B
+
+#define GEYSER_ANSI_PRODUCT_ID 0x0214
+#define GEYSER_ISO_PRODUCT_ID 0x0215
+#define GEYSER_JIS_PRODUCT_ID 0x0216
/* MacBook devices */
-#define GEYSER3_ANSI_PRODUCT_ID 0x0217
-#define GEYSER3_ISO_PRODUCT_ID 0x0218
-#define GEYSER3_JIS_PRODUCT_ID 0x0219
+#define GEYSER3_ANSI_PRODUCT_ID 0x0217
+#define GEYSER3_ISO_PRODUCT_ID 0x0218
+#define GEYSER3_JIS_PRODUCT_ID 0x0219
+
+/*
+ * Geyser IV: same as Geyser III according to Info.plist in AppleUSBTrackpad.kext
+ * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables
+ */
+#define GEYSER4_ANSI_PRODUCT_ID 0x021A
+#define GEYSER4_ISO_PRODUCT_ID 0x021B
+#define GEYSER4_JIS_PRODUCT_ID 0x021C
#define ATP_DEVICE(prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
/* table of devices that work with this driver */
static struct usb_device_id atp_table [] = {
- { ATP_DEVICE(0x020E) },
- { ATP_DEVICE(0x020F) },
- { ATP_DEVICE(0x030A) },
- { ATP_DEVICE(0x030B) },
+ { ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) },
+ { ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) },
+ { ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) },
+ { ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) },
/* PowerBooks Oct 2005 */
{ ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) },
{ ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
{ ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
+ /* Core Duo MacBook & MacBook Pro */
{ ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) },
{ ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) },
{ ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) },
+ /* Core2 Duo MacBook & MacBook Pro */
+ { ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) },
+ { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) },
+ { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) },
+
/* Terminating entry */
{ }
};
*/
#define ATP_THRESHOLD 5
-/* MacBook Pro (Geyser 3) initialization constants */
+/* MacBook Pro (Geyser 3 & 4) initialization constants */
#define ATP_GEYSER3_MODE_READ_REQUEST_ID 1
#define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9
#define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300
MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
MODULE_LICENSE("GPL");
+/*
+ * Make the threshold a module parameter
+ */
+static int threshold = ATP_THRESHOLD;
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value");
+
static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activate debugging output");
return (productId == GEYSER3_ANSI_PRODUCT_ID) ||
(productId == GEYSER3_ISO_PRODUCT_ID) ||
- (productId == GEYSER3_JIS_PRODUCT_ID);
+ (productId == GEYSER3_JIS_PRODUCT_ID) ||
+ (productId == GEYSER4_ANSI_PRODUCT_ID) ||
+ (productId == GEYSER4_ISO_PRODUCT_ID) ||
+ (productId == GEYSER4_JIS_PRODUCT_ID);
}
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
int i;
/* values to calculate mean */
int pcum = 0, psum = 0;
+ int is_increasing = 0;
*fingers = 0;
for (i = 0; i < nb_sensors; i++) {
- if (xy_sensors[i] < ATP_THRESHOLD)
+ if (xy_sensors[i] < threshold) {
+ if (is_increasing)
+ is_increasing = 0;
+
continue;
- if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD))
+ }
+
+ /*
+ * Makes the finger detection more versatile. For example,
+ * two fingers with no gap will be detected. Also, my
+ * tests show it less likely to have intermittent loss
+ * of multiple finger readings while moving around (scrolling).
+ *
+ * Changes the multiple finger detection to counting humps on
+ * sensors (transitions from nonincreasing to increasing)
+ * instead of counting transitions from low sensors (no
+ * finger reading) to high sensors (finger above
+ * sensor)
+ *
+ * - Jason Parekh <jasonparekh@gmail.com>
+ */
+ if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
(*fingers)++;
- pcum += xy_sensors[i] * i;
- psum += xy_sensors[i];
+ is_increasing = 1;
+ } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) {
+ is_increasing = 0;
+ }
+
+ /*
+ * Subtracts threshold so a high sensor that just passes the threshold
+ * won't skew the calculated absolute coordinate. Fixes an issue
+ * where slowly moving the mouse would occassionaly jump a number of
+ * pixels (let me restate--slowly moving the mouse makes this issue
+ * most apparent).
+ */
+ pcum += (xy_sensors[i] - threshold) * i;
+ psum += (xy_sensors[i] - threshold);
}
if (psum > 0) {
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006 Jiri Kosina
*/
/*
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
#include <linux/hiddev.h>
+#include "usbhid.h"
/*
* Version Information
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
-/*
- * Register a new report for a device.
- */
-
-static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
-{
- struct hid_report_enum *report_enum = device->report_enum + type;
- struct hid_report *report;
-
- if (report_enum->report_id_hash[id])
- return report_enum->report_id_hash[id];
-
- if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
- return NULL;
-
- if (id != 0)
- report_enum->numbered = 1;
-
- report->id = id;
- report->type = type;
- report->size = 0;
- report->device = device;
- report_enum->report_id_hash[id] = report;
-
- list_add_tail(&report->list, &report_enum->report_list);
-
- return report;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
-{
- struct hid_field *field;
-
- if (report->maxfield == HID_MAX_FIELDS) {
- dbg("too many fields in report");
- return NULL;
- }
-
- if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
- + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
-
- field->index = report->maxfield++;
- report->field[field->index] = field;
- field->usage = (struct hid_usage *)(field + 1);
- field->value = (unsigned *)(field->usage + usages);
- field->report = report;
-
- return field;
-}
-
-/*
- * Open a collection. The type/usage is pushed on the stack.
- */
-
-static int open_collection(struct hid_parser *parser, unsigned type)
-{
- struct hid_collection *collection;
- unsigned usage;
-
- usage = parser->local.usage[0];
-
- if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
- dbg("collection stack overflow");
- return -1;
- }
-
- if (parser->device->maxcollection == parser->device->collection_size) {
- collection = kmalloc(sizeof(struct hid_collection) *
- parser->device->collection_size * 2, GFP_KERNEL);
- if (collection == NULL) {
- dbg("failed to reallocate collection array");
- return -1;
- }
- memcpy(collection, parser->device->collection,
- sizeof(struct hid_collection) *
- parser->device->collection_size);
- memset(collection + parser->device->collection_size, 0,
- sizeof(struct hid_collection) *
- parser->device->collection_size);
- kfree(parser->device->collection);
- parser->device->collection = collection;
- parser->device->collection_size *= 2;
- }
-
- parser->collection_stack[parser->collection_stack_ptr++] =
- parser->device->maxcollection;
-
- collection = parser->device->collection +
- parser->device->maxcollection++;
- collection->type = type;
- collection->usage = usage;
- collection->level = parser->collection_stack_ptr - 1;
-
- if (type == HID_COLLECTION_APPLICATION)
- parser->device->maxapplication++;
-
- return 0;
-}
-
-/*
- * Close a collection.
- */
-
-static int close_collection(struct hid_parser *parser)
-{
- if (!parser->collection_stack_ptr) {
- dbg("collection stack underflow");
- return -1;
- }
- parser->collection_stack_ptr--;
- return 0;
-}
-
-/*
- * Climb up the stack, search for the specified collection type
- * and return the usage.
- */
-
-static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
-{
- int n;
- for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
- if (parser->device->collection[parser->collection_stack[n]].type == type)
- return parser->device->collection[parser->collection_stack[n]].usage;
- return 0; /* we know nothing about this usage type */
-}
-
-/*
- * Add a usage to the temporary parser table.
- */
-
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
-{
- if (parser->local.usage_index >= HID_MAX_USAGES) {
- dbg("usage index exceeded");
- return -1;
- }
- parser->local.usage[parser->local.usage_index] = usage;
- parser->local.collection_index[parser->local.usage_index] =
- parser->collection_stack_ptr ?
- parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
- parser->local.usage_index++;
- return 0;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
-{
- struct hid_report *report;
- struct hid_field *field;
- int usages;
- unsigned offset;
- int i;
-
- if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
- dbg("hid_register_report failed");
- return -1;
- }
-
- if (parser->global.logical_maximum < parser->global.logical_minimum) {
- dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
- return -1;
- }
-
- offset = report->size;
- report->size += parser->global.report_size * parser->global.report_count;
-
- if (!parser->local.usage_index) /* Ignore padding fields */
- return 0;
-
- usages = max_t(int, parser->local.usage_index, parser->global.report_count);
-
- if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
- return 0;
-
- field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
- field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
- field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
-
- for (i = 0; i < usages; i++) {
- int j = i;
- /* Duplicate the last usage we parsed if we have excess values */
- if (i >= parser->local.usage_index)
- j = parser->local.usage_index - 1;
- field->usage[i].hid = parser->local.usage[j];
- field->usage[i].collection_index =
- parser->local.collection_index[j];
- }
-
- field->maxusage = usages;
- field->flags = flags;
- field->report_offset = offset;
- field->report_type = report_type;
- field->report_size = parser->global.report_size;
- field->report_count = parser->global.report_count;
- field->logical_minimum = parser->global.logical_minimum;
- field->logical_maximum = parser->global.logical_maximum;
- field->physical_minimum = parser->global.physical_minimum;
- field->physical_maximum = parser->global.physical_maximum;
- field->unit_exponent = parser->global.unit_exponent;
- field->unit = parser->global.unit;
-
- return 0;
-}
-
-/*
- * Read data value from item.
- */
-
-static u32 item_udata(struct hid_item *item)
-{
- switch (item->size) {
- case 1: return item->data.u8;
- case 2: return item->data.u16;
- case 4: return item->data.u32;
- }
- return 0;
-}
-
-static s32 item_sdata(struct hid_item *item)
-{
- switch (item->size) {
- case 1: return item->data.s8;
- case 2: return item->data.s16;
- case 4: return item->data.s32;
- }
- return 0;
-}
-
-/*
- * Process a global item.
- */
-
-static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
-{
- switch (item->tag) {
-
- case HID_GLOBAL_ITEM_TAG_PUSH:
-
- if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
- dbg("global enviroment stack overflow");
- return -1;
- }
-
- memcpy(parser->global_stack + parser->global_stack_ptr++,
- &parser->global, sizeof(struct hid_global));
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_POP:
-
- if (!parser->global_stack_ptr) {
- dbg("global enviroment stack underflow");
- return -1;
- }
-
- memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
- sizeof(struct hid_global));
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
- parser->global.usage_page = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
- parser->global.logical_minimum = item_sdata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
- if (parser->global.logical_minimum < 0)
- parser->global.logical_maximum = item_sdata(item);
- else
- parser->global.logical_maximum = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
- parser->global.physical_minimum = item_sdata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
- if (parser->global.physical_minimum < 0)
- parser->global.physical_maximum = item_sdata(item);
- else
- parser->global.physical_maximum = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
- parser->global.unit_exponent = item_sdata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_UNIT:
- parser->global.unit = item_udata(item);
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
- if ((parser->global.report_size = item_udata(item)) > 32) {
- dbg("invalid report_size %d", parser->global.report_size);
- return -1;
- }
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
- if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
- dbg("invalid report_count %d", parser->global.report_count);
- return -1;
- }
- return 0;
-
- case HID_GLOBAL_ITEM_TAG_REPORT_ID:
- if ((parser->global.report_id = item_udata(item)) == 0) {
- dbg("report_id 0 is invalid");
- return -1;
- }
- return 0;
-
- default:
- dbg("unknown global tag 0x%x", item->tag);
- return -1;
- }
-}
-
-/*
- * Process a local item.
- */
-
-static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
-{
- __u32 data;
- unsigned n;
-
- if (item->size == 0) {
- dbg("item data expected for local item");
- return -1;
- }
-
- data = item_udata(item);
-
- switch (item->tag) {
-
- case HID_LOCAL_ITEM_TAG_DELIMITER:
-
- if (data) {
- /*
- * We treat items before the first delimiter
- * as global to all usage sets (branch 0).
- * In the moment we process only these global
- * items and the first delimiter set.
- */
- if (parser->local.delimiter_depth != 0) {
- dbg("nested delimiters");
- return -1;
- }
- parser->local.delimiter_depth++;
- parser->local.delimiter_branch++;
- } else {
- if (parser->local.delimiter_depth < 1) {
- dbg("bogus close delimiter");
- return -1;
- }
- parser->local.delimiter_depth--;
- }
- return 1;
-
- case HID_LOCAL_ITEM_TAG_USAGE:
-
- if (parser->local.delimiter_branch > 1) {
- dbg("alternative usage ignored");
- return 0;
- }
-
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- return hid_add_usage(parser, data);
-
- case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-
- if (parser->local.delimiter_branch > 1) {
- dbg("alternative usage ignored");
- return 0;
- }
-
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- parser->local.usage_minimum = data;
- return 0;
-
- case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-
- if (parser->local.delimiter_branch > 1) {
- dbg("alternative usage ignored");
- return 0;
- }
-
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
-
- for (n = parser->local.usage_minimum; n <= data; n++)
- if (hid_add_usage(parser, n)) {
- dbg("hid_add_usage failed\n");
- return -1;
- }
- return 0;
-
- default:
-
- dbg("unknown local item tag 0x%x", item->tag);
- return 0;
- }
- return 0;
-}
-
-/*
- * Process a main item.
- */
-
-static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
-{
- __u32 data;
- int ret;
-
- data = item_udata(item);
-
- switch (item->tag) {
- case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
- ret = open_collection(parser, data & 0xff);
- break;
- case HID_MAIN_ITEM_TAG_END_COLLECTION:
- ret = close_collection(parser);
- break;
- case HID_MAIN_ITEM_TAG_INPUT:
- ret = hid_add_field(parser, HID_INPUT_REPORT, data);
- break;
- case HID_MAIN_ITEM_TAG_OUTPUT:
- ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
- break;
- case HID_MAIN_ITEM_TAG_FEATURE:
- ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
- break;
- default:
- dbg("unknown main item tag 0x%x", item->tag);
- ret = 0;
- }
-
- memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */
-
- return ret;
-}
-
-/*
- * Process a reserved item.
- */
-
-static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
-{
- dbg("reserved item type, tag 0x%x", item->tag);
- return 0;
-}
-
-/*
- * Free a report and all registered fields. The field->usage and
- * field->value table's are allocated behind the field, so we need
- * only to free(field) itself.
- */
-
-static void hid_free_report(struct hid_report *report)
-{
- unsigned n;
-
- for (n = 0; n < report->maxfield; n++)
- kfree(report->field[n]);
- kfree(report);
-}
-
-/*
- * Free a device structure, all reports, and all fields.
- */
-
-static void hid_free_device(struct hid_device *device)
-{
- unsigned i,j;
-
- for (i = 0; i < HID_REPORT_TYPES; i++) {
- struct hid_report_enum *report_enum = device->report_enum + i;
-
- for (j = 0; j < 256; j++) {
- struct hid_report *report = report_enum->report_id_hash[j];
- if (report)
- hid_free_report(report);
- }
- }
-
- kfree(device->rdesc);
- kfree(device);
-}
-
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
-
-static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
-{
- u8 b;
-
- if ((end - start) <= 0)
- return NULL;
-
- b = *start++;
-
- item->type = (b >> 2) & 3;
- item->tag = (b >> 4) & 15;
-
- if (item->tag == HID_ITEM_TAG_LONG) {
-
- item->format = HID_ITEM_FORMAT_LONG;
-
- if ((end - start) < 2)
- return NULL;
-
- item->size = *start++;
- item->tag = *start++;
-
- if ((end - start) < item->size)
- return NULL;
-
- item->data.longdata = start;
- start += item->size;
- return start;
- }
-
- item->format = HID_ITEM_FORMAT_SHORT;
- item->size = b & 3;
-
- switch (item->size) {
-
- case 0:
- return start;
-
- case 1:
- if ((end - start) < 1)
- return NULL;
- item->data.u8 = *start++;
- return start;
-
- case 2:
- if ((end - start) < 2)
- return NULL;
- item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
- start = (__u8 *)((__le16 *)start + 1);
- return start;
-
- case 3:
- item->size++;
- if ((end - start) < 4)
- return NULL;
- item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
- start = (__u8 *)((__le32 *)start + 1);
- return start;
- }
-
- return NULL;
-}
-
-/*
- * Parse a report description into a hid_device structure. Reports are
- * enumerated, fields are attached to these reports.
- */
-
-static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
-{
- struct hid_device *device;
- struct hid_parser *parser;
- struct hid_item item;
- __u8 *end;
- unsigned i;
- static int (*dispatch_type[])(struct hid_parser *parser,
- struct hid_item *item) = {
- hid_parser_main,
- hid_parser_global,
- hid_parser_local,
- hid_parser_reserved
- };
-
- if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
- return NULL;
-
- if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
- HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
- kfree(device);
- return NULL;
- }
- device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
- for (i = 0; i < HID_REPORT_TYPES; i++)
- INIT_LIST_HEAD(&device->report_enum[i].report_list);
-
- if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
- kfree(device->collection);
- kfree(device);
- return NULL;
- }
- memcpy(device->rdesc, start, size);
- device->rsize = size;
-
- if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
- kfree(device->rdesc);
- kfree(device->collection);
- kfree(device);
- return NULL;
- }
- parser->device = device;
-
- end = start + size;
- while ((start = fetch_item(start, end, &item)) != NULL) {
-
- if (item.format != HID_ITEM_FORMAT_SHORT) {
- dbg("unexpected long global item");
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
-
- if (dispatch_type[item.type](parser, &item)) {
- dbg("item %u %u %u %u parsing failed\n",
- item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
-
- if (start == end) {
- if (parser->collection_stack_ptr) {
- dbg("unbalanced collection at end of report description");
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
- if (parser->local.delimiter_depth) {
- dbg("unbalanced delimiter at end of report description");
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
- }
- kfree(parser);
- return device;
- }
- }
-
- dbg("item fetching failed at offset %d\n", (int)(end - start));
- kfree(device->collection);
- hid_free_device(device);
- kfree(parser);
- return NULL;
-}
-
-/*
- * Convert a signed n-bit integer to signed 32-bit integer. Common
- * cases are done through the compiler, the screwed things has to be
- * done by hand.
- */
-
-static s32 snto32(__u32 value, unsigned n)
-{
- switch (n) {
- case 8: return ((__s8)value);
- case 16: return ((__s16)value);
- case 32: return ((__s32)value);
- }
- return value & (1 << (n - 1)) ? value | (-1 << n) : value;
-}
-
-/*
- * Convert a signed 32-bit integer to a signed n-bit integer.
- */
-
-static u32 s32ton(__s32 value, unsigned n)
-{
- s32 a = value >> (n - 1);
- if (a && a != -1)
- return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
- return value & ((1 << n) - 1);
-}
-
-/*
- * Extract/implement a data field from/to a little endian report (bit array).
- *
- * Code sort-of follows HID spec:
- * http://www.usb.org/developers/devclass_docs/HID1_11.pdf
- *
- * While the USB HID spec allows unlimited length bit fields in "report
- * descriptors", most devices never use more than 16 bits.
- * One model of UPS is claimed to report "LINEV" as a 32-bit field.
- * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
- */
-
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
-{
- u64 x;
-
- WARN_ON(n > 32);
-
- report += offset >> 3; /* adjust byte index */
- offset &= 7; /* now only need bit offset into one byte */
- x = get_unaligned((u64 *) report);
- x = le64_to_cpu(x);
- x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
- return (u32) x;
-}
-
-/*
- * "implement" : set bits in a little endian bit stream.
- * Same concepts as "extract" (see comments above).
- * The data mangled in the bit stream remains in little endian
- * order the whole time. It make more sense to talk about
- * endianness of register values by considering a register
- * a "cached" copy of the little endiad bit stream.
- */
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
-{
- u64 x;
- u64 m = (1ULL << n) - 1;
-
- WARN_ON(n > 32);
-
- WARN_ON(value > m);
- value &= m;
-
- report += offset >> 3;
- offset &= 7;
-
- x = get_unaligned((u64 *)report);
- x &= cpu_to_le64(~(m << offset));
- x |= cpu_to_le64(((u64) value) << offset);
- put_unaligned(x, (u64 *) report);
-}
-
-/*
- * Search an array for a value.
- */
-
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
-{
- while (n--) {
- if (*array++ == value)
- return 0;
- }
- return -1;
-}
-
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
-{
- hid_dump_input(usage, value);
- if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_hid_event(hid, field, usage, value);
- if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
- hiddev_hid_event(hid, field, usage, value);
-}
-
-/*
- * Analyse a received field, and fetch the data from it. The field
- * content is stored for next report processing (we do differential
- * reporting to the layer).
- */
-
-static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
-{
- unsigned n;
- unsigned count = field->report_count;
- unsigned offset = field->report_offset;
- unsigned size = field->report_size;
- __s32 min = field->logical_minimum;
- __s32 max = field->logical_maximum;
- __s32 *value;
-
- if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
- return;
-
- for (n = 0; n < count; n++) {
-
- value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
- extract(data, offset + n * size, size);
-
- if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
- && value[n] >= min && value[n] <= max
- && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
- goto exit;
- }
-
- for (n = 0; n < count; n++) {
-
- if (HID_MAIN_ITEM_VARIABLE & field->flags) {
- hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
- continue;
- }
-
- if (field->value[n] >= min && field->value[n] <= max
- && field->usage[field->value[n] - min].hid
- && search(value, field->value[n], count))
- hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
-
- if (value[n] >= min && value[n] <= max
- && field->usage[value[n] - min].hid
- && search(field->value, value[n], count))
- hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
- }
-
- memcpy(field->value, value, count * sizeof(__s32));
-exit:
- kfree(value);
-}
-
-static int hid_input_report(int type, struct urb *urb, int interrupt)
-{
- struct hid_device *hid = urb->context;
- struct hid_report_enum *report_enum = hid->report_enum + type;
- u8 *data = urb->transfer_buffer;
- int len = urb->actual_length;
- struct hid_report *report;
- int n, size;
-
- if (!len) {
- dbg("empty report");
- return -1;
- }
-
-#ifdef DEBUG_DATA
- printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
-#endif
-
- n = 0; /* Normally report number is 0 */
- if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
- n = *data++;
- len--;
- }
-
-#ifdef DEBUG_DATA
- {
- int i;
- printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len);
- for (i = 0; i < len; i++)
- printk(" %02x", data[i]);
- printk("\n");
- }
-#endif
-
- if (!(report = report_enum->report_id_hash[n])) {
- dbg("undefined report_id %d received", n);
- return -1;
- }
-
- size = ((report->size - 1) >> 3) + 1;
-
- if (len < size) {
- dbg("report %d is too short, (%d < %d)", report->id, len, size);
- memset(data + len, 0, size - len);
- }
-
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- hiddev_report_event(hid, report);
-
- for (n = 0; n < report->maxfield; n++)
- hid_input_field(hid, report->field[n], data, interrupt);
-
- if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_report_event(hid, report);
-
- return 0;
-}
+static int usbhid_pb_fnmode = 1;
+module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
+MODULE_PARM_DESC(pb_fnmode,
+ "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
/*
* Input submission and I/O error handler.
{
unsigned long flags;
int rc = 0;
+ struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irqsave(&hid->inlock, flags);
- if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
- !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
- rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
+ spin_lock_irqsave(&usbhid->inlock, flags);
+ if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+ !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
+ rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
if (rc != 0)
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
}
- spin_unlock_irqrestore(&hid->inlock, flags);
+ spin_unlock_irqrestore(&usbhid->inlock, flags);
return rc;
}
static void hid_retry_timeout(unsigned long _hid)
{
struct hid_device *hid = (struct hid_device *) _hid;
+ struct usbhid_device *usbhid = hid->driver_data;
- dev_dbg(&hid->intf->dev, "retrying intr urb\n");
+ dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
if (hid_start_in(hid))
hid_io_error(hid);
}
/* Workqueue routine to reset the device or clear a halt */
static void hid_reset(struct work_struct *work)
{
- struct hid_device *hid =
- container_of(work, struct hid_device, reset_work);
+ struct usbhid_device *usbhid =
+ container_of(work, struct usbhid_device, reset_work);
+ struct hid_device *hid = usbhid->hid;
int rc_lock, rc = 0;
- if (test_bit(HID_CLEAR_HALT, &hid->iofl)) {
- dev_dbg(&hid->intf->dev, "clear halt\n");
- rc = usb_clear_halt(hid->dev, hid->urbin->pipe);
- clear_bit(HID_CLEAR_HALT, &hid->iofl);
+ if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
+ dev_dbg(&usbhid->intf->dev, "clear halt\n");
+ rc = usb_clear_halt(to_usb_device(hid->dev), usbhid->urbin->pipe);
+ clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
hid_start_in(hid);
}
- else if (test_bit(HID_RESET_PENDING, &hid->iofl)) {
- dev_dbg(&hid->intf->dev, "resetting device\n");
- rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+ else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ dev_dbg(&usbhid->intf->dev, "resetting device\n");
+ rc = rc_lock = usb_lock_device_for_reset(to_usb_device(hid->dev), usbhid->intf);
if (rc_lock >= 0) {
- rc = usb_reset_composite_device(hid->dev, hid->intf);
+ rc = usb_reset_composite_device(to_usb_device(hid->dev), usbhid->intf);
if (rc_lock)
- usb_unlock_device(hid->dev);
+ usb_unlock_device(to_usb_device(hid->dev));
}
- clear_bit(HID_RESET_PENDING, &hid->iofl);
+ clear_bit(HID_RESET_PENDING, &usbhid->iofl);
}
switch (rc) {
case 0:
- if (!test_bit(HID_IN_RUNNING, &hid->iofl))
+ if (!test_bit(HID_IN_RUNNING, &usbhid->iofl))
hid_io_error(hid);
break;
default:
err("can't reset device, %s-%s/input%d, status %d",
- hid->dev->bus->bus_name,
- hid->dev->devpath,
- hid->ifnum, rc);
+ to_usb_device(hid->dev)->bus->bus_name,
+ to_usb_device(hid->dev)->devpath,
+ usbhid->ifnum, rc);
/* FALLTHROUGH */
case -EHOSTUNREACH:
case -ENODEV:
static void hid_io_error(struct hid_device *hid)
{
unsigned long flags;
+ struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irqsave(&hid->inlock, flags);
+ spin_lock_irqsave(&usbhid->inlock, flags);
/* Stop when disconnected */
- if (usb_get_intfdata(hid->intf) == NULL)
+ if (usb_get_intfdata(usbhid->intf) == NULL)
goto done;
/* When an error occurs, retry at increasing intervals */
- if (hid->retry_delay == 0) {
- hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */
- hid->stop_retry = jiffies + msecs_to_jiffies(1000);
- } else if (hid->retry_delay < 100)
- hid->retry_delay *= 2;
+ if (usbhid->retry_delay == 0) {
+ usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */
+ usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
+ } else if (usbhid->retry_delay < 100)
+ usbhid->retry_delay *= 2;
- if (time_after(jiffies, hid->stop_retry)) {
+ if (time_after(jiffies, usbhid->stop_retry)) {
/* Retries failed, so do a port reset */
- if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
- schedule_work(&hid->reset_work);
+ if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ schedule_work(&usbhid->reset_work);
goto done;
}
}
- mod_timer(&hid->io_retry,
- jiffies + msecs_to_jiffies(hid->retry_delay));
+ mod_timer(&usbhid->io_retry,
+ jiffies + msecs_to_jiffies(usbhid->retry_delay));
done:
- spin_unlock_irqrestore(&hid->inlock, flags);
+ spin_unlock_irqrestore(&usbhid->inlock, flags);
}
/*
static void hid_irq_in(struct urb *urb)
{
struct hid_device *hid = urb->context;
+ struct usbhid_device *usbhid = hid->driver_data;
int status;
switch (urb->status) {
case 0: /* success */
- hid->retry_delay = 0;
- hid_input_report(HID_INPUT_REPORT, urb, 1);
+ usbhid->retry_delay = 0;
+ hid_input_report(urb->context, HID_INPUT_REPORT,
+ urb->transfer_buffer,
+ urb->actual_length, 1);
break;
case -EPIPE: /* stall */
- clear_bit(HID_IN_RUNNING, &hid->iofl);
- set_bit(HID_CLEAR_HALT, &hid->iofl);
- schedule_work(&hid->reset_work);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+ schedule_work(&usbhid->reset_work);
return;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN: /* unplug */
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
return;
default: /* error */
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- clear_bit(HID_IN_RUNNING, &hid->iofl);
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) {
err("can't resubmit intr, %s-%s/input%d, status %d",
- hid->dev->bus->bus_name,
- hid->dev->devpath,
- hid->ifnum, status);
+ to_usb_device(hid->dev)->bus->bus_name,
+ to_usb_device(hid->dev)->devpath,
+ usbhid->ifnum, status);
hid_io_error(hid);
}
}
}
-/*
- * Output the field into the report.
- */
-
-static void hid_output_field(struct hid_field *field, __u8 *data)
-{
- unsigned count = field->report_count;
- unsigned offset = field->report_offset;
- unsigned size = field->report_size;
- unsigned n;
-
- for (n = 0; n < count; n++) {
- if (field->logical_minimum < 0) /* signed values */
- implement(data, offset + n * size, size, s32ton(field->value[n], size));
- else /* unsigned values */
- implement(data, offset + n * size, size, field->value[n]);
- }
-}
-
-/*
- * Create a report.
- */
-
-static void hid_output_report(struct hid_report *report, __u8 *data)
-{
- unsigned n;
-
- if (report->id > 0)
- *data++ = report->id;
-
- for (n = 0; n < report->maxfield; n++)
- hid_output_field(report->field[n], data);
-}
-
-/*
- * Set a field value. The report this field belongs to has to be
- * created and transferred to the device, to set this value in the
- * device.
- */
-
-int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
-{
- unsigned size = field->report_size;
-
- hid_dump_input(field->usage + offset, value);
-
- if (offset >= field->report_count) {
- dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count);
- hid_dump_field(field, 8);
- return -1;
- }
- if (field->logical_minimum < 0) {
- if (value != snto32(s32ton(value, size), size)) {
- dbg("value %d is out of range", value);
- return -1;
- }
- }
- field->value[offset] = value;
- return 0;
-}
-
/*
* Find a report field with a specified HID usage.
*/
static int hid_submit_out(struct hid_device *hid)
{
struct hid_report *report;
+ struct usbhid_device *usbhid = hid->driver_data;
- report = hid->out[hid->outtail];
+ report = usbhid->out[usbhid->outtail];
- hid_output_report(report, hid->outbuf);
- hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
- hid->urbout->dev = hid->dev;
+ hid_output_report(report, usbhid->outbuf);
+ usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+ usbhid->urbout->dev = to_usb_device(hid->dev);
dbg("submitting out urb");
- if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) {
+ if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
err("usb_submit_urb(out) failed");
return -1;
}
struct hid_report *report;
unsigned char dir;
int len;
+ struct usbhid_device *usbhid = hid->driver_data;
- report = hid->ctrl[hid->ctrltail].report;
- dir = hid->ctrl[hid->ctrltail].dir;
+ report = usbhid->ctrl[usbhid->ctrltail].report;
+ dir = usbhid->ctrl[usbhid->ctrltail].dir;
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (dir == USB_DIR_OUT) {
- hid_output_report(report, hid->ctrlbuf);
- hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0);
- hid->urbctrl->transfer_buffer_length = len;
+ hid_output_report(report, usbhid->ctrlbuf);
+ usbhid->urbctrl->pipe = usb_sndctrlpipe(to_usb_device(hid->dev), 0);
+ usbhid->urbctrl->transfer_buffer_length = len;
} else {
int maxpacket, padlen;
- hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0);
- maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0);
+ usbhid->urbctrl->pipe = usb_rcvctrlpipe(to_usb_device(hid->dev), 0);
+ maxpacket = usb_maxpacket(to_usb_device(hid->dev), usbhid->urbctrl->pipe, 0);
if (maxpacket > 0) {
padlen = (len + maxpacket - 1) / maxpacket;
padlen *= maxpacket;
- if (padlen > hid->bufsize)
- padlen = hid->bufsize;
+ if (padlen > usbhid->bufsize)
+ padlen = usbhid->bufsize;
} else
padlen = 0;
- hid->urbctrl->transfer_buffer_length = padlen;
+ usbhid->urbctrl->transfer_buffer_length = padlen;
}
- hid->urbctrl->dev = hid->dev;
+ usbhid->urbctrl->dev = to_usb_device(hid->dev);
- hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
- hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
- hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
- hid->cr->wIndex = cpu_to_le16(hid->ifnum);
- hid->cr->wLength = cpu_to_le16(len);
+ usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
+ usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
+ usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
+ usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
+ usbhid->cr->wLength = cpu_to_le16(len);
dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
- hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
- hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength);
+ usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+ usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
- if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) {
+ if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
err("usb_submit_urb(ctrl) failed");
return -1;
}
static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
+ struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags;
int unplug = 0;
warn("output irq status %d received", urb->status);
}
- spin_lock_irqsave(&hid->outlock, flags);
+ spin_lock_irqsave(&usbhid->outlock, flags);
if (unplug)
- hid->outtail = hid->outhead;
+ usbhid->outtail = usbhid->outhead;
else
- hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+ usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
- if (hid->outhead != hid->outtail) {
+ if (usbhid->outhead != usbhid->outtail) {
if (hid_submit_out(hid)) {
- clear_bit(HID_OUT_RUNNING, &hid->iofl);
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
wake_up(&hid->wait);
}
- spin_unlock_irqrestore(&hid->outlock, flags);
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
return;
}
- clear_bit(HID_OUT_RUNNING, &hid->iofl);
- spin_unlock_irqrestore(&hid->outlock, flags);
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
wake_up(&hid->wait);
}
static void hid_ctrl(struct urb *urb)
{
struct hid_device *hid = urb->context;
+ struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags;
int unplug = 0;
- spin_lock_irqsave(&hid->ctrllock, flags);
+ spin_lock_irqsave(&usbhid->ctrllock, flags);
switch (urb->status) {
case 0: /* success */
- if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
- hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0);
+ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+ hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
+ urb->transfer_buffer, urb->actual_length, 0);
break;
case -ESHUTDOWN: /* unplug */
unplug = 1;
}
if (unplug)
- hid->ctrltail = hid->ctrlhead;
+ usbhid->ctrltail = usbhid->ctrlhead;
else
- hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+ usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- if (hid->ctrlhead != hid->ctrltail) {
+ if (usbhid->ctrlhead != usbhid->ctrltail) {
if (hid_submit_ctrl(hid)) {
- clear_bit(HID_CTRL_RUNNING, &hid->iofl);
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
wake_up(&hid->wait);
}
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
return;
}
- clear_bit(HID_CTRL_RUNNING, &hid->iofl);
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
wake_up(&hid->wait);
}
-void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{
int head;
unsigned long flags;
+ struct usbhid_device *usbhid = hid->driver_data;
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
- if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
+ if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
- spin_lock_irqsave(&hid->outlock, flags);
+ spin_lock_irqsave(&usbhid->outlock, flags);
- if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) {
- spin_unlock_irqrestore(&hid->outlock, flags);
+ if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
warn("output queue full");
return;
}
- hid->out[hid->outhead] = report;
- hid->outhead = head;
+ usbhid->out[usbhid->outhead] = report;
+ usbhid->outhead = head;
- if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl))
+ if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
if (hid_submit_out(hid))
- clear_bit(HID_OUT_RUNNING, &hid->iofl);
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
- spin_unlock_irqrestore(&hid->outlock, flags);
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
return;
}
- spin_lock_irqsave(&hid->ctrllock, flags);
+ spin_lock_irqsave(&usbhid->ctrllock, flags);
- if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) {
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
warn("control queue full");
return;
}
- hid->ctrl[hid->ctrlhead].report = report;
- hid->ctrl[hid->ctrlhead].dir = dir;
- hid->ctrlhead = head;
+ usbhid->ctrl[usbhid->ctrlhead].report = report;
+ usbhid->ctrl[usbhid->ctrlhead].dir = dir;
+ usbhid->ctrlhead = head;
- if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl))
+ if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
if (hid_submit_ctrl(hid))
- clear_bit(HID_CTRL_RUNNING, &hid->iofl);
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+}
+
+static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct hid_device *hid = dev->private;
+ struct hid_field *field;
+ int offset;
+
+ if (type == EV_FF)
+ return input_ff_event(dev, type, code, value);
+
+ if (type != EV_LED)
+ return -1;
+
+ if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+ warn("event field not found");
+ return -1;
+ }
+
+ hid_set_field(field, offset, value);
+ usbhid_submit_report(hid, field->report, USB_DIR_OUT);
- spin_unlock_irqrestore(&hid->ctrllock, flags);
+ return 0;
}
-int hid_wait_io(struct hid_device *hid)
+int usbhid_wait_io(struct hid_device *hid)
{
- if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) &&
- !test_bit(HID_OUT_RUNNING, &hid->iofl)),
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
+ !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
10*HZ)) {
dbg("timeout waiting for ctrl or out queue to clear");
return -1;
return result;
}
-int hid_open(struct hid_device *hid)
+int usbhid_open(struct hid_device *hid)
{
++hid->open;
if (hid_start_in(hid))
return 0;
}
-void hid_close(struct hid_device *hid)
+void usbhid_close(struct hid_device *hid)
{
+ struct usbhid_device *usbhid = hid->driver_data;
+
if (!--hid->open)
- usb_kill_urb(hid->urbin);
+ usb_kill_urb(usbhid->urbin);
+}
+
+static int hidinput_open(struct input_dev *dev)
+{
+ struct hid_device *hid = dev->private;
+ return usbhid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+ struct hid_device *hid = dev->private;
+ usbhid_close(hid);
}
#define USB_VENDOR_ID_PANJIT 0x134c
* Initialize all reports
*/
-void hid_init_reports(struct hid_device *hid)
+void usbhid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
+ struct usbhid_device *usbhid = hid->driver_data;
int err, ret;
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
- hid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
- hid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
err = 0;
- ret = hid_wait_io(hid);
+ ret = usbhid_wait_io(hid);
while (ret) {
err |= ret;
- if (test_bit(HID_CTRL_RUNNING, &hid->iofl))
- usb_kill_urb(hid->urbctrl);
- if (test_bit(HID_OUT_RUNNING, &hid->iofl))
- usb_kill_urb(hid->urbout);
- ret = hid_wait_io(hid);
+ if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ usb_kill_urb(usbhid->urbctrl);
+ if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ usb_kill_urb(usbhid->urbout);
+ ret = usbhid_wait_io(hid);
}
if (err)
#define USB_VENDOR_ID_AIRCABLE 0x16CA
#define USB_DEVICE_ID_AIRCABLE1 0x1502
+#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
{ USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
-
+
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+
{ 0, 0 }
};
static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{
- if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->inbuf_dma)))
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
return -1;
- if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->outbuf_dma)))
+ if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
return -1;
- if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), GFP_ATOMIC, &hid->cr_dma)))
+ if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
return -1;
- if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, GFP_ATOMIC, &hid->ctrlbuf_dma)))
+ if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
return -1;
return 0;
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
- if (hid->inbuf)
- usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma);
- if (hid->outbuf)
- usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma);
- if (hid->cr)
- usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma);
- if (hid->ctrlbuf)
- usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (usbhid->inbuf)
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+ if (usbhid->outbuf)
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+ if (usbhid->cr)
+ usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+ if (usbhid->ctrlbuf)
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
/*
unsigned quirks = 0, rsize = 0;
char *rdesc;
int n, len, insize = 0;
+ struct usbhid_device *usbhid;
/* Ignore all Wacom devices */
if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
kfree(rdesc);
hid->quirks = quirks;
- hid->bufsize = HID_MIN_BUFFER_SIZE;
- hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize);
- hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize);
- hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize);
+ if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
+ goto fail;
+
+ hid->driver_data = usbhid;
+ usbhid->hid = hid;
- if (hid->bufsize > HID_MAX_BUFFER_SIZE)
- hid->bufsize = HID_MAX_BUFFER_SIZE;
+ usbhid->bufsize = HID_MIN_BUFFER_SIZE;
+ hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
+ hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
+ hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
+
+ if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
+ usbhid->bufsize = HID_MAX_BUFFER_SIZE;
hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
interval = hid_mousepoll_interval;
if (usb_endpoint_dir_in(endpoint)) {
- if (hid->urbin)
+ if (usbhid->urbin)
continue;
- if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
+ if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
- usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize,
+ usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
hid_irq_in, hid, interval);
- hid->urbin->transfer_dma = hid->inbuf_dma;
- hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+ usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
} else {
- if (hid->urbout)
+ if (usbhid->urbout)
continue;
- if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
+ if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
goto fail;
pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
- usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
+ usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
hid_irq_out, hid, interval);
- hid->urbout->transfer_dma = hid->outbuf_dma;
- hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
+ usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
}
}
- if (!hid->urbin) {
+ if (!usbhid->urbin) {
err("couldn't find an input interrupt endpoint");
goto fail;
}
init_waitqueue_head(&hid->wait);
- INIT_WORK(&hid->reset_work, hid_reset);
- setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+ INIT_WORK(&usbhid->reset_work, hid_reset);
+ setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
- spin_lock_init(&hid->inlock);
- spin_lock_init(&hid->outlock);
- spin_lock_init(&hid->ctrllock);
+ spin_lock_init(&usbhid->inlock);
+ spin_lock_init(&usbhid->outlock);
+ spin_lock_init(&usbhid->ctrllock);
hid->version = le16_to_cpu(hdesc->bcdHID);
hid->country = hdesc->bCountryCode;
- hid->dev = dev;
- hid->intf = intf;
- hid->ifnum = interface->desc.bInterfaceNumber;
+ hid->dev = &dev->dev;
+ usbhid->intf = intf;
+ usbhid->ifnum = interface->desc.bInterfaceNumber;
hid->name[0] = 0;
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
+ hid->bus = BUS_USB;
+ hid->vendor = dev->descriptor.idVendor;
+ hid->product = dev->descriptor.idProduct;
+
usb_make_path(dev, hid->phys, sizeof(hid->phys));
strlcat(hid->phys, "/input", sizeof(hid->phys));
len = strlen(hid->phys);
if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
hid->uniq[0] = 0;
- hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
- if (!hid->urbctrl)
+ usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
+ if (!usbhid->urbctrl)
goto fail;
- usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr,
- hid->ctrlbuf, 1, hid_ctrl, hid);
- hid->urbctrl->setup_dma = hid->cr_dma;
- hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
- hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+ usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
+ usbhid->ctrlbuf, 1, hid_ctrl, hid);
+ usbhid->urbctrl->setup_dma = usbhid->cr_dma;
+ usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
+ usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+ hid->hidinput_input_event = usb_hidinput_input_event;
+ hid->hidinput_open = hidinput_open;
+ hid->hidinput_close = hidinput_close;
+#ifdef CONFIG_USB_HIDDEV
+ hid->hiddev_hid_event = hiddev_hid_event;
+ hid->hiddev_report_event = hiddev_report_event;
+#endif
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+ hid->pb_fnmode = usbhid_pb_fnmode;
+#endif
return hid;
fail:
- usb_free_urb(hid->urbin);
- usb_free_urb(hid->urbout);
- usb_free_urb(hid->urbctrl);
+ usb_free_urb(usbhid->urbin);
+ usb_free_urb(usbhid->urbout);
+ usb_free_urb(usbhid->urbctrl);
hid_free_buffers(dev, hid);
hid_free_device(hid);
static void hid_disconnect(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid;
if (!hid)
return;
- spin_lock_irq(&hid->inlock); /* Sync with error handler */
+ usbhid = hid->driver_data;
+
+ spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
usb_set_intfdata(intf, NULL);
- spin_unlock_irq(&hid->inlock);
- usb_kill_urb(hid->urbin);
- usb_kill_urb(hid->urbout);
- usb_kill_urb(hid->urbctrl);
+ spin_unlock_irq(&usbhid->inlock);
+ usb_kill_urb(usbhid->urbin);
+ usb_kill_urb(usbhid->urbout);
+ usb_kill_urb(usbhid->urbctrl);
- del_timer_sync(&hid->io_retry);
+ del_timer_sync(&usbhid->io_retry);
flush_scheduled_work();
if (hid->claimed & HID_CLAIMED_INPUT)
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
- usb_free_urb(hid->urbin);
- usb_free_urb(hid->urbctrl);
- usb_free_urb(hid->urbout);
+ usb_free_urb(usbhid->urbin);
+ usb_free_urb(usbhid->urbctrl);
+ usb_free_urb(usbhid->urbout);
- hid_free_buffers(hid->dev, hid);
+ hid_free_buffers(to_usb_device(hid->dev), hid);
hid_free_device(hid);
}
if (!(hid = usb_hid_configure(intf)))
return -ENODEV;
- hid_init_reports(hid);
+ usbhid_init_reports(hid);
hid_dump_device(hid);
if (!hidinput_connect(hid))
return -ENODEV;
}
+ /* This only gets called when we are a single-input (most of the
+ * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
+ * only useful in this case, and not for multi-input quirks. */
+ if ((hid->claimed & HID_CLAIMED_INPUT) &&
+ !(hid->quirks & HID_QUIRK_MULTI_INPUT))
+ hid_ff_init(hid);
+
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)
static int hid_suspend(struct usb_interface *intf, pm_message_t message)
{
struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irq(&hid->inlock); /* Sync with error handler */
- set_bit(HID_SUSPENDED, &hid->iofl);
- spin_unlock_irq(&hid->inlock);
- del_timer(&hid->io_retry);
- usb_kill_urb(hid->urbin);
+ spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+ set_bit(HID_SUSPENDED, &usbhid->iofl);
+ spin_unlock_irq(&usbhid->inlock);
+ del_timer(&usbhid->io_retry);
+ usb_kill_urb(usbhid->urbin);
dev_dbg(&intf->dev, "suspend\n");
return 0;
}
static int hid_resume(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid = hid->driver_data;
int status;
- clear_bit(HID_SUSPENDED, &hid->iofl);
- hid->retry_delay = 0;
+ clear_bit(HID_SUSPENDED, &usbhid->iofl);
+ usbhid->retry_delay = 0;
status = hid_start_in(hid);
dev_dbg(&intf->dev, "resume status %d\n", status);
return status;
#undef DEBUG
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
/*
* This table contains pointers to initializers. To add support for new
int hid_ff_init(struct hid_device* hid)
{
struct hid_ff_initializer *init;
- int vendor = le16_to_cpu(hid->dev->descriptor.idVendor);
- int product = le16_to_cpu(hid->dev->descriptor.idProduct);
+ int vendor = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idVendor);
+ int product = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idProduct);
for (init = inits; init->idVendor; init++)
if (init->idVendor == vendor && init->idProduct == product)
return init->init(hid);
}
+EXPORT_SYMBOL_GPL(hid_ff_init);
+
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
struct device_type {
u16 idVendor;
report->field[0]->value[2] = x;
report->field[0]->value[3] = y;
dbg("(x, y)=(%04x, %04x)", x, y);
- hid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
break;
case FF_RUMBLE:
report->field[0]->value[2] = left;
report->field[0]->value[3] = right;
dbg("(left, right)=(%04x, %04x)", left, right);
- hid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
break;
}
return 0;
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+
+#include "usbhid.h"
#define PID_EFFECTS_MAX 64
debug("attack %u => %d", envelope->attack_level,
pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
USB_DIR_OUT);
}
pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
effect->u.constant.level);
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
USB_DIR_OUT);
}
pidff->effect_direction);
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT);
}
pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
USB_DIR_OUT);
}
effect->u.condition[i].left_saturation);
pidff_set(&pidff->set_condition[PID_DEAD_BAND],
effect->u.condition[i].deadband);
- hid_wait_io(pidff->hid);
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
+ usbhid_wait_io(pidff->hid);
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
USB_DIR_OUT);
}
}
effect->u.ramp.start_level);
pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
effect->u.ramp.end_level);
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
USB_DIR_OUT);
}
int j;
pidff->create_new_effect_type->value[0] = efnum;
- hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
USB_DIR_OUT);
debug("create_new_effect sent, type: %d", efnum);
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
pidff->block_load_status->value[0] = 0;
- hid_wait_io(pidff->hid);
+ usbhid_wait_io(pidff->hid);
for (j = 0; j < 60; j++) {
debug("pid_block_load requested");
- hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
USB_DIR_IN);
- hid_wait_io(pidff->hid);
+ usbhid_wait_io(pidff->hid);
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
debug("device reported free memory: %d bytes",
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
}
- hid_wait_io(pidff->hid);
- hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
+ usbhid_wait_io(pidff->hid);
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
USB_DIR_OUT);
}
static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
{
pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
- hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
USB_DIR_OUT);
}
struct pidff_device *pidff = dev->ff->private;
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
- hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT);
}
pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
pidff->set_effect[PID_START_DELAY].value[0] = 0;
- hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT);
}
pidff->device_control->value[0] = pidff->control_id[PID_RESET];
/* We reset twice as sometimes hid_wait_io isn't waiting long enough */
- hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- hid_wait_io(hid);
- hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ usbhid_wait_io(hid);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ usbhid_wait_io(hid);
pidff->device_control->value[0] =
pidff->control_id[PID_ENABLE_ACTUATORS];
- hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ usbhid_wait_io(hid);
/* pool report is sometimes messed up, refetch it */
- hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
+ usbhid_wait_io(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
break;
}
debug("pid_pool requested again");
- hid_submit_report(hid, pidff->reports[PID_POOL],
+ usbhid_submit_report(hid, pidff->reports[PID_POOL],
USB_DIR_IN);
- hid_wait_io(hid);
+ usbhid_wait_io(hid);
}
}
}
if (test_bit(FF_GAIN, dev->ffbit)) {
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
- hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+ usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT);
}
#undef DEBUG
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
tmff->rumble->value[0] = left;
tmff->rumble->value[1] = right;
dbg("(left,right)=(%08x, %08x)", left, right);
- hid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
return 0;
}
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
+#include "usbhid.h"
struct zpff_device {
struct hid_report *report;
zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right;
debug("running with 0x%02x 0x%02x", left, right);
- hid_submit_report(hid, zpff->report, USB_DIR_OUT);
+ usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
return 0;
}
zpff->report->field[1]->value[0] = 0x02;
zpff->report->field[2]->value[0] = 0x00;
zpff->report->field[3]->value[0] = 0x00;
- hid_submit_report(hid, zpff->report, USB_DIR_OUT);
+ usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
printk(KERN_INFO "Force feedback for Zeroplus based devices by "
"Anssi Hannula <anssi.hannula@gmail.com>\n");
#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/usb.h>
-#include "hid.h"
+#include <linux/hid.h>
#include <linux/hiddev.h>
+#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
#define HIDDEV_MINOR_BASE 0
hiddev_send_event(hid, &uref);
}
-
+EXPORT_SYMBOL_GPL(hiddev_hid_event);
void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
{
hiddev_send_event(hid, &uref);
}
+
/*
* fasync file op
*/
if (!--list->hiddev->open) {
if (list->hiddev->exist)
- hid_close(list->hiddev->hid);
+ usbhid_close(list->hiddev->hid);
else
kfree(list->hiddev);
}
if (!list->hiddev->open++)
if (list->hiddev->exist)
- hid_open(hiddev_table[i]->hid);
+ usbhid_open(hiddev_table[i]->hid);
return 0;
}
struct hiddev_list *list = file->private_data;
struct hiddev *hiddev = list->hiddev;
struct hid_device *hid = hiddev->hid;
- struct usb_device *dev = hid->dev;
+ struct usb_device *dev = to_usb_device(hid->dev);
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
+ struct usbhid_device *usbhid = hid->driver_data;
void __user *user_arg = (void __user *)arg;
int i;
dinfo.bustype = BUS_USB;
dinfo.busnum = dev->bus->busnum;
dinfo.devnum = dev->devnum;
- dinfo.ifnum = hid->ifnum;
+ dinfo.ifnum = usbhid->ifnum;
dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
}
case HIDIOCINITREPORT:
- hid_init_reports(hid);
+ usbhid_init_reports(hid);
return 0;
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
- hid_submit_report(hid, report, USB_DIR_IN);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_wait_io(hid);
return 0;
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
- hid_submit_report(hid, report, USB_DIR_OUT);
- hid_wait_io(hid);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_wait_io(hid);
return 0;
int hiddev_connect(struct hid_device *hid)
{
struct hiddev *hiddev;
+ struct usbhid_device *usbhid = hid->driver_data;
int i;
int retval;
if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1;
- retval = usb_register_dev(hid->intf, &hiddev_class);
+ retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
err("Not able to get a minor for this device.");
kfree(hiddev);
hiddev->hid = hid;
hiddev->exist = 1;
- hid->minor = hid->intf->minor;
+ hid->minor = usbhid->intf->minor;
hid->hiddev = hiddev;
- hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+ hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
return 0;
}
void hiddev_disconnect(struct hid_device *hid)
{
struct hiddev *hiddev = hid->hiddev;
+ struct usbhid_device *usbhid = hid->driver_data;
hiddev->exist = 0;
hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
- usb_deregister_dev(hiddev->hid->intf, &hiddev_class);
+ usb_deregister_dev(usbhid->intf, &hiddev_class);
if (hiddev->open) {
- hid_close(hiddev->hid);
+ usbhid_close(hiddev->hid);
wake_up_interruptible(&hiddev->wait);
} else {
kfree(hiddev);
--- /dev/null
+#ifndef __USBHID_H
+#define __USBHID_H
+
+/*
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
+/* API provided by hid-core.c for USB HID drivers */
+int usbhid_wait_io(struct hid_device* hid);
+void usbhid_close(struct hid_device *hid);
+int usbhid_open(struct hid_device *hid);
+void usbhid_init_reports(struct hid_device *hid);
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+
+/*
+ * USB-specific HID struct, to be pointed to
+ * from struct hid_device->driver_data
+ */
+
+struct usbhid_device {
+ struct hid_device *hid; /* pointer to corresponding HID dev */
+
+ struct usb_interface *intf; /* USB interface */
+ int ifnum; /* USB interface number */
+
+ unsigned int bufsize; /* URB buffer size */
+
+ struct urb *urbin; /* Input URB */
+ char *inbuf; /* Input buffer */
+ dma_addr_t inbuf_dma; /* Input buffer dma */
+ spinlock_t inlock; /* Input fifo spinlock */
+
+ struct urb *urbctrl; /* Control URB */
+ struct usb_ctrlrequest *cr; /* Control request struct */
+ dma_addr_t cr_dma; /* Control request struct dma */
+ struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
+ unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
+ char *ctrlbuf; /* Control buffer */
+ dma_addr_t ctrlbuf_dma; /* Control buffer dma */
+ spinlock_t ctrllock; /* Control fifo spinlock */
+
+ struct urb *urbout; /* Output URB */
+ struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
+ unsigned char outhead, outtail; /* Output pipe fifo head & tail */
+ char *outbuf; /* Output buffer */
+ dma_addr_t outbuf_dma; /* Output buffer dma */
+ spinlock_t outlock; /* Output fifo spinlock */
+
+ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+ struct timer_list io_retry; /* Retry timer */
+ unsigned long stop_retry; /* Time to give up, in jiffies */
+ unsigned int retry_delay; /* Delay length in ms */
+ struct work_struct reset_work; /* Task context for resets */
+
+};
+
+#endif
+
case SISUSB_GET_CONFIG:
case SISUSB_COMMAND:
lock_kernel();
- retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+ retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
unlock_kernel();
return retval;
}
static void ark3116_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct ark3116_private *priv = usb_get_serial_port_data(port);
static int ark3116_open(struct usb_serial_port *port, struct file *filp)
{
- struct termios tmp_termios;
+ struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
char *buf;
int result = 0;
static int belkin_sa_open (struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close (struct usb_serial_port *port, struct file *filp);
static void belkin_sa_read_int_callback (struct urb *urb);
-static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state );
static int belkin_sa_tiocmget (struct usb_serial_port *port, struct file *file);
__FUNCTION__, retval);
}
-static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct belkin_sa_private *priv = usb_get_serial_port_data(port);
struct usb_serial_port *port;
int retval = 0;
struct tty_struct *tty;
- struct termios *termios;
+ struct ktermios *termios;
dbg ("%s", __FUNCTION__);
static void cp2101_cleanup(struct usb_serial_port*);
static void cp2101_close(struct usb_serial_port*, struct file*);
static void cp2101_get_termios(struct usb_serial_port*);
-static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
+static void cp2101_set_termios(struct usb_serial_port*, struct ktermios*);
static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
unsigned int, unsigned int);
}
static void cp2101_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
unsigned int cflag, old_cflag=0;
int baud=0, bits;
wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
char prev_status, diff_status; /* used for TIOCMIWAIT */
/* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
- struct termios tmp_termios; /* stores the old termios settings */
+ struct ktermios tmp_termios; /* stores the old termios settings */
};
/* write buffer structure */
static void cypress_send (struct usb_serial_port *port);
static int cypress_write_room (struct usb_serial_port *port);
static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void cypress_set_termios (struct usb_serial_port *port, struct termios * old);
+static void cypress_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int cypress_tiocmget (struct usb_serial_port *port, struct file *file);
static int cypress_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
static int cypress_chars_in_buffer (struct usb_serial_port *port);
switch (cmd) {
case TIOCGSERIAL:
- if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) {
+ if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) {
return -EFAULT;
}
return (0);
break;
case TIOCSSERIAL:
- if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) {
+ if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) {
return -EFAULT;
}
/* here we need to call cypress_set_termios to invoke the new settings */
static void cypress_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
static void digi_rx_throttle (struct usb_serial_port *port);
static void digi_rx_unthrottle (struct usb_serial_port *port);
static void digi_set_termios( struct usb_serial_port *port,
- struct termios *old_termios );
+ struct ktermios *old_termios );
static void digi_break_ctl( struct usb_serial_port *port, int break_state );
static int digi_ioctl( struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg );
static void digi_set_termios( struct usb_serial_port *port,
- struct termios *old_termios )
+ struct ktermios *old_termios )
{
struct digi_port *priv = usb_get_serial_port_data(port);
int ret;
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
- struct termios not_termios;
+ struct ktermios not_termios;
unsigned long flags = 0;
struct file * file,
unsigned int cmd,
unsigned long arg);
-static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void empeg_write_bulk_callback (struct urb *urb);
static void empeg_read_bulk_callback (struct urb *urb);
}
-static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
dbg("%s - port %d", __FUNCTION__, port->number);
static void ftdi_write_bulk_callback (struct urb *urb);
static void ftdi_read_bulk_callback (struct urb *urb);
static void ftdi_process_read (struct work_struct *work);
-static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
+static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file);
static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear);
static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
* WARNING: set_termios calls this with old_termios in kernel space
*/
-static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{ /* ftdi_termios */
struct usb_device *dev = port->serial->dev;
unsigned int cflag = port->tty->termios->c_cflag;
static int edge_chars_in_buffer (struct usb_serial_port *port);
static void edge_throttle (struct usb_serial_port *port);
static void edge_unthrottle (struct usb_serial_port *port);
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
static void edge_break (struct usb_serial_port *port, int break_state);
static int edge_tiocmget (struct usb_serial_port *port, struct file *file);
static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param);
static int calc_baud_rate_divisor (int baud_rate, int *divisor);
static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate);
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios);
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios);
static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue);
static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength);
static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port);
* SerialSetTermios
* this function is called by the tty driver when it wants to change the termios structure
*****************************************************************************/
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
#ifndef CMSPAR
#define CMSPAR 0
#endif
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
{
struct tty_struct *tty;
int baud;
static void stop_read(struct edgeport_port *edge_port);
static int restart_read(struct edgeport_port *edge_port);
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void edge_send(struct usb_serial_port *port);
/* circular buffer */
return status;
}
-static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
{
struct ump_uart_config *config;
struct tty_struct *tty;
return;
}
-static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static void ir_write_bulk_callback (struct urb *urb);
static void ir_read_bulk_callback (struct urb *urb);
-static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static u8 ir_baud = 0;
static u8 ir_xbof = 0;
return;
}
-static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned char *transfer_buffer;
unsigned int cflag;
static void keyspan_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int baud_rate, device_port;
struct keyspan_port_private *p_priv;
unsigned int cmd,
unsigned long arg);
static void keyspan_set_termios (struct usb_serial_port *port,
- struct termios *old);
+ struct ktermios *old);
static void keyspan_break_ctl (struct usb_serial_port *port,
int break_state);
static int keyspan_tiocmget (struct usb_serial_port *port,
static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
unsigned int cflag = port->tty->termios->c_cflag;
static void klsi_105_read_bulk_callback (struct urb *urb);
static void klsi_105_set_termios (struct usb_serial_port *port,
- struct termios * old);
+ struct ktermios *old);
static int klsi_105_ioctl (struct usb_serial_port *port,
struct file * file,
unsigned int cmd,
#define URB_TRANSFER_BUFFER_SIZE 64
struct klsi_105_private {
struct klsi_105_port_settings cfg;
- struct termios termios;
+ struct ktermios termios;
unsigned long line_state; /* modem line settings */
/* write pool */
struct urb * write_urb_pool[NUM_URBS];
static void klsi_105_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
unsigned int iflag = port->tty->termios->c_iflag;
int cur_pos; // index of the next char to send in buf
__u16 device_type;
int line_state;
- struct termios internal_termios;
+ struct ktermios internal_termios;
};
switch (cmd) {
case TCGETS: // 0x5401
- if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) {
+ if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
- if (kernel_termios_to_user_termios((struct termios __user *)arg,
+ if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
&priv->internal_termios))
return -EFAULT;
return 0;
dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
return -ENOTTY;
}
- if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) {
+ if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
if (user_termios_to_kernel_termios(&priv->internal_termios,
- (struct termios __user *)arg))
+ (struct ktermios __user *)arg))
return -EFAULT;
settings = kzalloc(50, GFP_KERNEL);
struct file *filp);
static void mct_u232_read_int_callback (struct urb *urb);
static void mct_u232_set_termios (struct usb_serial_port *port,
- struct termios * old);
+ struct ktermios * old);
static int mct_u232_ioctl (struct usb_serial_port *port,
struct file * file,
unsigned int cmd,
} /* mct_u232_read_int_callback */
static void mct_u232_set_termios (struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
* the specified new settings.
*/
static void change_port_settings(struct moschip_port *mos7720_port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial_port *port;
struct usb_serial *serial;
* termios structure.
*/
static void mos7720_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int status;
unsigned int cflag;
*****************************************************************************/
static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct tty_struct *tty;
int baud;
*****************************************************************************/
static void mos7840_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
int status;
unsigned int cflag;
static int option_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void option_set_termios(struct usb_serial_port *port,
- struct termios *old);
+ struct ktermios *old);
static void option_break_ctl(struct usb_serial_port *port, int break_state);
static int option_tiocmget(struct usb_serial_port *port, struct file *file);
static int option_tiocmset(struct usb_serial_port *port, struct file *file,
}
static void option_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
dbg("%s", __FUNCTION__);
}
static void pl2303_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
static int pl2303_open(struct usb_serial_port *port, struct file *filp)
{
- struct termios tmp_termios;
+ struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned char *buf;
}
static void sierra_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
dbg("%s", __FUNCTION__);
static void ti_unthrottle(struct usb_serial_port *port);
static int ti_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
static void ti_set_termios(struct usb_serial_port *port,
- struct termios *old_termios);
+ struct ktermios *old_termios);
static int ti_tiocmget(struct usb_serial_port *port, struct file *file);
static int ti_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static void ti_set_termios(struct usb_serial_port *port,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct ti_port *tport = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
return retval;
}
-static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{
struct usb_serial_port *port = tty->driver_data;
static int visor_calc_num_ports(struct usb_serial *serial);
static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void visor_write_bulk_callback (struct urb *urb);
static void visor_read_bulk_callback (struct urb *urb);
static void visor_read_int_callback (struct urb *urb);
/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned int cflag;
static int whiteheat_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static int whiteheat_write_room (struct usb_serial_port *port);
static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
+static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios * old);
static int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file);
static int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state);
static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
int retval = 0;
- struct termios old_term;
+ struct ktermios old_term;
dbg("%s - port %d", __FUNCTION__, port->number);
}
-static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
dbg("%s -port %d", __FUNCTION__, port->number);
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BITREVERSE
help
This is the frame buffer device driver for generic TGA graphic
cards. Say Y if you have one of those.
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VIDEO_SELECT
help
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BITREVERSE
help
This driver supports graphics boards with the nVidia chips, TNT
and newer. For very old chipsets, such as the RIVA128, then use
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BITREVERSE
help
This driver supports graphics boards with the nVidia Riva/Geforce
chips.
#endif
fb_info.flags = FBINFO_FLAG_DEFAULT;
- if (register_framebuffer(&fb_info) < 0)
- return;
+ if (register_framebuffer(&fb_info) < 0) {
+ iounmap(fb_info.screen_base);
+ fb_info.screen_base = NULL;
+ return;
+ }
printk("fb%d: S3 Trio frame buffer device on %s\n",
fb_info.node, dp->full_name);
fb_info.fix.smem_len);
if (!videomemory) {
printk("amifb: WARNING! unable to map videomem cached writethrough\n");
- videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
- }
+ fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start);
+ } else
+ fb_info.screen_base = (char *)videomemory;
- fb_info.screen_base = (char *)videomemory;
memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);
/*
{
fb_dealloc_cmap(&fb_info.cmap);
chipfree();
+ if (videomemory)
+ iounmap((void*)videomemory);
release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
custom.dmacon = DMAF_ALL | DMAF_MASTER;
}
unsigned int xres;
p = *ppos;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
fbidx = iminor(inode);
info = registered_fb[fbidx];
atafb_set_disp(-1, &fb_info);
do_install_cmap(0, &fb_info);
- if (register_framebuffer(&fb_info) < 0)
+ if (register_framebuffer(&fb_info) < 0) {
+#ifdef ATAFB_EXT
+ if (external_addr) {
+ iounmap(external_addr);
+ external_addr = NULL;
+ }
+ if (external_vgaiobase) {
+ iounmap((void*)external_vgaiobase);
+ external_vgaiobase = 0;
+ }
+#endif
return -EINVAL;
+ }
printk("Determined %dx%d, depth %d\n",
disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
if (vclk * 12 < c.ppll_min)
vclk = c.ppll_min/12;
+ pll->post_divider = -1;
+
/* now, find an acceptable divider */
for (i = 0; i < sizeof(post_dividers); i++) {
output_freq = post_dividers[i] * vclk;
}
}
+ if (pll->post_divider < 0)
+ return -EINVAL;
+
/* calculate feedback divider */
n = c.ref_divider * output_freq;
d = c.ref_clk;
*/
struct atyfb_par {
- struct aty_cmap_regs __iomem *aty_cmap_regs;
struct { u8 red, green, blue; } palette[256];
const struct aty_dac_ops *dac_ops;
const struct aty_pll_ops *pll_ops;
int mtrr_aper;
int mtrr_reg;
#endif
+ u32 mem_cntl;
};
/*
regindex -= 0x800;
#ifdef CONFIG_ATARI
- return in_le32((volatile u32 *)(par->ati_regbase + regindex));
+ return in_le32(par->ati_regbase + regindex);
#else
return readl(par->ati_regbase + regindex);
#endif
regindex -= 0x800;
#ifdef CONFIG_ATARI
- out_le32((volatile u32 *)(par->ati_regbase + regindex), val);
+ out_le32(par->ati_regbase + regindex, val);
#else
writel(val, par->ati_regbase + regindex);
#endif
if (regindex >= 0x400)
regindex -= 0x800;
#ifdef CONFIG_ATARI
- out_le16((volatile u16 *)(par->ati_regbase + regindex), val);
+ out_le16(par->ati_regbase + regindex, val);
#else
writel(val, par->ati_regbase + regindex);
#endif
void (*set_pll) (const struct fb_info * info, const union aty_pll * pll);
void (*get_pll) (const struct fb_info *info, union aty_pll * pll);
int (*init_pll) (const struct fb_info * info, union aty_pll * pll);
+ void (*resume_pll)(const struct fb_info *info, union aty_pll *pll);
};
extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
* The Hardware parameters for each card
*/
-struct aty_cmap_regs {
- u8 windex;
- u8 lut;
- u8 mask;
- u8 rindex;
- u8 cntl;
-};
-
struct pci_mmap_map {
unsigned long voff;
unsigned long poff;
* Internal routines
*/
-static int aty_init(struct fb_info *info, const char *name);
+static int aty_init(struct fb_info *info);
+static void aty_resume_chip(struct fb_info *info);
#ifdef CONFIG_ATARI
static int store_video_par(char *videopar, unsigned char m64_num);
#endif
aty_st_8(DAC_CNTL, tmp, par);
aty_st_8(DAC_MASK, 0xff, par);
- writeb(i, &par->aty_cmap_regs->rindex);
- atyfb_save.r[enter][i] = readb(&par->aty_cmap_regs->lut);
- atyfb_save.g[enter][i] = readb(&par->aty_cmap_regs->lut);
- atyfb_save.b[enter][i] = readb(&par->aty_cmap_regs->lut);
- writeb(i, &par->aty_cmap_regs->windex);
- writeb(atyfb_save.r[1 - enter][i],
- &par->aty_cmap_regs->lut);
- writeb(atyfb_save.g[1 - enter][i],
- &par->aty_cmap_regs->lut);
- writeb(atyfb_save.b[1 - enter][i],
- &par->aty_cmap_regs->lut);
+ aty_st_8(DAC_R_INDEX, i, par);
+ atyfb_save.r[enter][i] = aty_ld_8(DAC_DATA, par);
+ atyfb_save.g[enter][i] = aty_ld_8(DAC_DATA, par);
+ atyfb_save.b[enter][i] = aty_ld_8(DAC_DATA, par);
+ aty_st_8(DAC_W_INDEX, i, par);
+ aty_st_8(DAC_DATA, atyfb_save.r[1 - enter][i], par);
+ aty_st_8(DAC_DATA, atyfb_save.g[1 - enter][i], par);
+ aty_st_8(DAC_DATA, atyfb_save.b[1 - enter][i], par);
}
}
#if defined(CONFIG_PM) && defined(CONFIG_PCI)
+#ifdef CONFIG_PPC_PMAC
/* Power management routines. Those are used for PowerBook sleep.
*/
static int aty_power_mgmt(int sleep, struct atyfb_par *par)
return timeout ? 0 : -EIO;
}
+#endif
static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct atyfb_par *par = (struct atyfb_par *) info->par;
-#ifndef CONFIG_PPC_PMAC
- /* HACK ALERT ! Once I find a proper way to say to each driver
- * individually what will happen with it's PCI slot, I'll change
- * that. On laptops, the AGP slot is just unclocked, so D2 is
- * expected, while on desktops, the card is powered off
- */
- return 0;
-#endif /* CONFIG_PPC_PMAC */
-
if (state.event == pdev->dev.power.power_state.event)
return 0;
par->asleep = 1;
par->lock_blank = 1;
+#ifdef CONFIG_PPC_PMAC
/* Set chip to "suspend" mode */
if (aty_power_mgmt(1, par)) {
par->asleep = 0;
release_console_sem();
return -EIO;
}
+#else
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
release_console_sem();
acquire_console_sem();
+#ifdef CONFIG_PPC_PMAC
if (pdev->dev.power.power_state.event == 2)
aty_power_mgmt(0, par);
+#else
+ pci_set_power_state(pdev, PCI_D0);
+#endif
+
+ aty_resume_chip(info);
+
par->asleep = 0;
/* Restore display */
}
#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
-static int __devinit aty_init(struct fb_info *info, const char *name)
+static int __devinit aty_init(struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
const char *ramname = NULL, *xtal;
int gtb_memsize, has_var = 0;
struct fb_var_screeninfo var;
- u8 pll_ref_div;
- u32 i;
-#if defined(CONFIG_PPC)
- int sense;
-#endif
init_waitqueue_head(&par->vblank.wait);
spin_lock_init(&par->int_lock);
- par->aty_cmap_regs =
- (struct aty_cmap_regs __iomem *) (par->ati_regbase + 0xc0);
-
#ifdef CONFIG_PPC_PMAC
/* The Apple iBook1 uses non-standard memory frequencies. We detect it
* and set the frequency manually. */
par->pll_limits.mclk = 63;
}
- if (M64_HAS(GTB_DSP)
- && (pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par))) {
- int diff1, diff2;
- diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
- diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
- if (diff1 < 0)
- diff1 = -diff1;
- if (diff2 < 0)
- diff2 = -diff2;
- if (diff2 < diff1) {
- par->ref_clk_per = 1000000000000ULL / 29498928;
- xtal = "29.498928";
+ if (M64_HAS(GTB_DSP)) {
+ u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+
+ if (pll_ref_div) {
+ int diff1, diff2;
+ diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
+ diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
+ if (diff1 < 0)
+ diff1 = -diff1;
+ if (diff2 < 0)
+ diff2 = -diff2;
+ if (diff2 < diff1) {
+ par->ref_clk_per = 1000000000000ULL / 29498928;
+ xtal = "29.498928";
+ }
}
}
#endif /* CONFIG_FB_ATY_CT */
if(par->pll_ops->get_pll)
par->pll_ops->get_pll(info, &saved_pll);
- i = aty_ld_le32(MEM_CNTL, par);
+ par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
gtb_memsize = M64_HAS(GTB_DSP);
if (gtb_memsize)
- switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
+ switch (par->mem_cntl & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
case MEM_SIZE_512K:
info->fix.smem_len = 0x80000;
break;
default:
info->fix.smem_len = 0x80000;
} else
- switch (i & MEM_SIZE_ALIAS) {
+ switch (par->mem_cntl & MEM_SIZE_ALIAS) {
case MEM_SIZE_512K:
info->fix.smem_len = 0x80000;
break;
if (vram) {
info->fix.smem_len = vram * 1024;
- i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+ par->mem_cntl &= ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
if (info->fix.smem_len <= 0x80000)
- i |= MEM_SIZE_512K;
+ par->mem_cntl |= MEM_SIZE_512K;
else if (info->fix.smem_len <= 0x100000)
- i |= MEM_SIZE_1M;
+ par->mem_cntl |= MEM_SIZE_1M;
else if (info->fix.smem_len <= 0x200000)
- i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
else if (info->fix.smem_len <= 0x400000)
- i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
else if (info->fix.smem_len <= 0x600000)
- i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
else
- i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
- aty_st_le32(MEM_CNTL, i, par);
+ par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+ aty_st_le32(MEM_CNTL, par->mem_cntl, par);
}
/*
#endif
if(par->pll_ops->init_pll)
par->pll_ops->init_pll(info, &par->pll);
+ if (par->pll_ops->resume_pll)
+ par->pll_ops->resume_pll(info, &par->pll);
/*
- * Last page of 8 MB (4 MB on ISA) aperture is MMIO
- * FIXME: we should use the auxiliary aperture instead so we can access
- * the full 8 MB of video RAM on 8 MB boards
+ * Last page of 8 MB (4 MB on ISA) aperture is MMIO,
+ * unless the auxiliary register aperture is used.
*/
if (!par->aux_start &&
has_var = 1;
} else {
if (default_vmode == VMODE_CHOOSE) {
+ int sense;
if (M64_HAS(G3_PB_1024x768))
/* G3 PowerBook with 1024x768 LCD */
default_vmode = VMODE_1024_768_60;
fb_list = info;
PRINTKI("fb%d: %s frame buffer device on %s\n",
- info->node, info->fix.id, name);
+ info->node, info->fix.id, par->bus_type == ISA ? "ISA" : "PCI");
return 0;
aty_init_exit:
return -1;
}
+static void aty_resume_chip(struct fb_info *info)
+{
+ struct atyfb_par *par = info->par;
+
+ aty_st_le32(MEM_CNTL, par->mem_cntl, par);
+
+ if (par->pll_ops->resume_pll)
+ par->pll_ops->resume_pll(info, &par->pll);
+
+ if (par->aux_start)
+ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+}
+
#ifdef CONFIG_ATARI
static int __devinit store_video_par(char *video_str, unsigned char m64_num)
{
#endif
gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+ gen_cntl &= ~0x400004c;
switch (blank) {
- case FB_BLANK_UNBLANK:
- gen_cntl &= ~0x400004c;
+ case FB_BLANK_UNBLANK:
break;
case FB_BLANK_NORMAL:
gen_cntl |= 0x4000040;
static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
const struct atyfb_par *par)
{
-#ifdef CONFIG_ATARI
- out_8(&par->aty_cmap_regs->windex, regno);
- out_8(&par->aty_cmap_regs->lut, red);
- out_8(&par->aty_cmap_regs->lut, green);
- out_8(&par->aty_cmap_regs->lut, blue);
-#else
- writeb(regno, &par->aty_cmap_regs->windex);
- writeb(red, &par->aty_cmap_regs->lut);
- writeb(green, &par->aty_cmap_regs->lut);
- writeb(blue, &par->aty_cmap_regs->lut);
-#endif
+ aty_st_8(DAC_W_INDEX, regno, par);
+ aty_st_8(DAC_DATA, red, par);
+ aty_st_8(DAC_DATA, green, par);
+ aty_st_8(DAC_DATA, blue, par);
}
/*
#ifdef __i386__
#ifdef CONFIG_FB_ATY_GENERIC_LCD
-static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
+static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
{
u32 driv_inf_tab, sig;
u16 lcd_ofs;
atyfb_setup_generic_fail:
iounmap(par->ati_regbase);
par->ati_regbase = NULL;
+ if (info->screen_base) {
+ iounmap(info->screen_base);
+ info->screen_base = NULL;
+ }
return ret;
}
pci_set_drvdata(pdev, info);
/* Init chip & register framebuffer */
- if (aty_init(info, "PCI"))
+ if (aty_init(info))
goto err_release_io;
#ifdef __sparc__
#ifdef CONFIG_ATARI
-static int __devinit atyfb_atari_probe(void)
+static int __init atyfb_atari_probe(void)
{
struct atyfb_par *par;
struct fb_info *info;
int m64_num;
u32 clock_r;
+ int num_found = 0;
for (m64_num = 0; m64_num < mach64_count; m64_num++) {
if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
break;
}
- if (aty_init(info, "ISA bus")) {
+ /* Fake pci_id for correct_chipset() */
+ switch (aty_ld_le32(CONFIG_CHIP_ID, par) & CFG_CHIP_TYPE) {
+ case 0x00d7:
+ par->pci_id = PCI_CHIP_MACH64GX;
+ break;
+ case 0x0057:
+ par->pci_id = PCI_CHIP_MACH64CX;
+ break;
+ default:
+ break;
+ }
+
+ if (correct_chipset(par) || aty_init(info)) {
+ iounmap(info->screen_base);
+ iounmap(par->ati_regbase);
framebuffer_release(info);
- /* This is insufficient! kernel_map has added two large chunks!! */
- return -ENXIO;
+ } else {
+ num_found++;
}
}
+
+ return num_found ? 0 : -ENXIO;
}
#endif /* CONFIG_ATARI */
+#ifdef CONFIG_PCI
+
static void __devexit atyfb_remove(struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
framebuffer_release(info);
}
-#ifdef CONFIG_PCI
static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
{
#endif /* CONFIG_PCI */
#ifndef MODULE
-static int __devinit atyfb_setup(char *options)
+static int __init atyfb_setup(char *options)
{
char *this_opt;
}
#endif /* MODULE */
-static int __devinit atyfb_init(void)
+static int __init atyfb_init(void)
{
int err1 = 1, err2 = 1;
#ifndef MODULE
#endif
}
-static void __init aty_get_pll_ct(const struct fb_info *info,
- union aty_pll *pll)
+static void __devinit aty_get_pll_ct(const struct fb_info *info,
+ union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u8 tmp, clock;
}
}
-static int __init aty_init_pll_ct(const struct fb_info *info,
- union aty_pll *pll)
+static int __devinit aty_init_pll_ct(const struct fb_info *info,
+ union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
- u32 q, i, memcntl, trp;
+ u8 mpost_div, xpost_div, sclk_post_div_real;
+ u32 q, memcntl, trp;
u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
#ifdef DEBUG
int pllmclk, pllsclk;
mpost_div += (q < 32*8);
}
sclk_post_div_real = postdividers[mpost_div];
- sclk_fb_div = q * sclk_post_div_real / 8;
- spll_cntl2 = mpost_div << 4;
+ pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
+ pll->ct.spll_cntl2 = mpost_div << 4;
#ifdef DEBUG
- pllsclk = (1000000 * 2 * sclk_fb_div) /
+ pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
(par->ref_clk_per * pll->ct.pll_ref_div);
printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
__FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
#endif
+ }
+
+ /* Disable the extra precision pixel clock controls since we do not use them. */
+ pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par);
+ pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC);
+
+ return 0;
+}
+
+static void aty_resume_pll_ct(const struct fb_info *info,
+ union aty_pll *pll)
+{
+ struct atyfb_par *par = info->par;
+
+ if (par->mclk_per != par->xclk_per) {
+ int i;
/*
* This disables the sclk, crashes the computer as reported:
* aty_st_pll_ct(SPLL_CNTL2, 3, info);
* So it seems the sclk must be enabled before it is used;
* so PLL_GEN_CNTL must be programmed *after* the sclk.
*/
- aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par);
- aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par);
+ aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
+ aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
/*
* The sclk has been started. However, I believe the first clock
* ticks it generates are not very stable. Hope this primitive loop
aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
- /* Disable the extra precision pixel clock controls since we do not use them. */
- aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
- ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
-
- return 0;
+ aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par);
}
static int dummy(void)
.pll_to_var = aty_pll_to_var_ct,
.set_pll = aty_set_pll_ct,
.get_pll = aty_get_pll_ct,
- .init_pll = aty_init_pll_ct
+ .init_pll = aty_init_pll_ct,
+ .resume_pll = aty_resume_pll_ct,
};
if (pedid == NULL)
return mt;
- tmp = (u8 *)kmalloc(EDID_LENGTH, GFP_KERNEL);
+ tmp = kmemdup(pedid, EDID_LENGTH, GFP_KERNEL);
if (!tmp)
return mt;
- memcpy(tmp, pedid, EDID_LENGTH);
*out_EDID = tmp;
return mt;
}
.bpp = 16,
.control_base = 0x0004886A |
LCD_CONTROL_DEFAULT_PO | LCD_CONTROL_DEFAULT_SBPPF |
- LCD_CONTROL_BPP_16,
+ LCD_CONTROL_BPP_16 | LCD_CONTROL_SBB_4,
.clkcontrol_base = 0x00020000,
.horztiming = 0x005aff1f,
.verttiming = 0x16000e57,
#include <linux/err.h>
#include <linux/fb.h>
+
+#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
+ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
+/* This callback gets called when something important happens inside a
+ * framebuffer driver. We're looking if that important event is blanking,
+ * and if it is, we're switching backlight power as well ...
+ */
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct backlight_device *bd;
+ struct fb_event *evdata = data;
+
+ /* If we aren't interested in this event, skip it immediately ... */
+ if (event != FB_EVENT_BLANK)
+ return 0;
+
+ bd = container_of(self, struct backlight_device, fb_notif);
+ down(&bd->sem);
+ if (bd->props)
+ if (!bd->props->check_fb ||
+ bd->props->check_fb(evdata->info)) {
+ bd->props->fb_blank = *(int *)evdata->data;
+ if (likely(bd->props && bd->props->update_status))
+ bd->props->update_status(bd);
+ }
+ up(&bd->sem);
+ return 0;
+}
+
+static int backlight_register_fb(struct backlight_device *bd)
+{
+ memset(&bd->fb_notif, 0, sizeof(bd->fb_notif));
+ bd->fb_notif.notifier_call = fb_notifier_callback;
+
+ return fb_register_client(&bd->fb_notif);
+}
+
+static void backlight_unregister_fb(struct backlight_device *bd)
+{
+ fb_unregister_client(&bd->fb_notif);
+}
+#else
+static inline int backlight_register_fb(struct backlight_device *bd)
+{
+ return 0;
+}
+
+static inline void backlight_unregister_fb(struct backlight_device *bd)
+{
+}
+#endif /* CONFIG_FB */
+
static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
{
int rc = -ENXIO;
.store = _store, \
}
-static struct class_device_attribute bl_class_device_attributes[] = {
+static const struct class_device_attribute bl_class_device_attributes[] = {
DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
};
-/* This callback gets called when something important happens inside a
- * framebuffer driver. We're looking if that important event is blanking,
- * and if it is, we're switching backlight power as well ...
- */
-static int fb_notifier_callback(struct notifier_block *self,
- unsigned long event, void *data)
-{
- struct backlight_device *bd;
- struct fb_event *evdata =(struct fb_event *)data;
-
- /* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
- return 0;
-
- bd = container_of(self, struct backlight_device, fb_notif);
- down(&bd->sem);
- if (bd->props)
- if (!bd->props->check_fb ||
- bd->props->check_fb(evdata->info)) {
- bd->props->fb_blank = *(int *)evdata->data;
- if (likely(bd->props && bd->props->update_status))
- bd->props->update_status(bd);
- }
- up(&bd->sem);
- return 0;
-}
-
/**
* backlight_device_register - create and register a new object of
* backlight_device class.
return ERR_PTR(rc);
}
- memset(&new_bd->fb_notif, 0, sizeof(new_bd->fb_notif));
- new_bd->fb_notif.notifier_call = fb_notifier_callback;
-
- rc = fb_register_client(&new_bd->fb_notif);
+ rc = backlight_register_fb(new_bd);
if (unlikely(rc))
goto error;
&bl_class_device_attributes[i]);
down(&bd->sem);
- if (likely(bd->props && bd->props->update_status)) {
- bd->props->brightness = 0;
- bd->props->power = 0;
- bd->props->update_status(bd);
- }
-
bd->props = NULL;
up(&bd->sem);
- fb_unregister_client(&bd->fb_notif);
+ backlight_unregister_fb(bd);
class_device_unregister(&bd->class_dev);
}
static int corgibl_remove(struct platform_device *dev)
{
+ corgibl_data.power = 0;
+ corgibl_data.brightness = 0;
+ corgibl_send_intensity(corgi_backlight_device);
+
backlight_device_unregister(corgi_backlight_device);
printk("Corgi Backlight Driver Unloaded\n");
static int hp680bl_remove(struct platform_device *dev)
{
+ hp680bl_data.brightness = 0;
+ hp680bl_data.power = 0;
+ hp680bl_send_intensity(hp680_backlight_device);
+
backlight_device_unregister(hp680_backlight_device);
return 0;
#include <linux/err.h>
#include <linux/fb.h>
+#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
+ defined(CONFIG_LCD_CLASS_DEVICE_MODULE))
+/* This callback gets called when something important happens inside a
+ * framebuffer driver. We're looking if that important event is blanking,
+ * and if it is, we're switching lcd power as well ...
+ */
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct lcd_device *ld;
+ struct fb_event *evdata = data;
+
+ /* If we aren't interested in this event, skip it immediately ... */
+ if (event != FB_EVENT_BLANK)
+ return 0;
+
+ ld = container_of(self, struct lcd_device, fb_notif);
+ down(&ld->sem);
+ if (ld->props)
+ if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
+ ld->props->set_power(ld, *(int *)evdata->data);
+ up(&ld->sem);
+ return 0;
+}
+
+static int lcd_register_fb(struct lcd_device *ld)
+{
+ memset(&ld->fb_notif, 0, sizeof(&ld->fb_notif));
+ ld->fb_notif.notifier_call = fb_notifier_callback;
+ return fb_register_client(&ld->fb_notif);
+}
+
+static void lcd_unregister_fb(struct lcd_device *ld)
+{
+ fb_unregister_client(&ld->fb_notif);
+}
+#else
+static int lcd_register_fb(struct lcd_device *ld)
+{
+ return 0;
+}
+
+static inline void lcd_unregister_fb(struct lcd_device *ld)
+{
+}
+#endif /* CONFIG_FB */
+
static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
{
int rc;
.store = _store, \
}
-static struct class_device_attribute lcd_class_device_attributes[] = {
+static const struct class_device_attribute lcd_class_device_attributes[] = {
DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
};
-/* This callback gets called when something important happens inside a
- * framebuffer driver. We're looking if that important event is blanking,
- * and if it is, we're switching lcd power as well ...
- */
-static int fb_notifier_callback(struct notifier_block *self,
- unsigned long event, void *data)
-{
- struct lcd_device *ld;
- struct fb_event *evdata =(struct fb_event *)data;
-
- /* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
- return 0;
-
- ld = container_of(self, struct lcd_device, fb_notif);
- down(&ld->sem);
- if (ld->props)
- if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
- ld->props->set_power(ld, *(int *)evdata->data);
- up(&ld->sem);
- return 0;
-}
-
/**
* lcd_device_register - register a new object of lcd_device class.
* @name: the name of the new object(must be the same as the name of the
return ERR_PTR(rc);
}
- memset(&new_ld->fb_notif, 0, sizeof(new_ld->fb_notif));
- new_ld->fb_notif.notifier_call = fb_notifier_callback;
+ rc = lcd_register_fb(new_ld);
- rc = fb_register_client(&new_ld->fb_notif);
if (unlikely(rc))
goto error;
down(&ld->sem);
ld->props = NULL;
up(&ld->sem);
-
- fb_unregister_client(&ld->fb_notif);
-
+ lcd_unregister_fb(ld);
class_device_unregister(&ld->class_dev);
}
EXPORT_SYMBOL(lcd_device_unregister);
{
unsigned long flags;
+ locomobl_data.brightness = 0;
+ locomobl_data.power = 0;
+ locomolcd_set_intensity(locomolcd_bl_device);
+
backlight_device_unregister(locomolcd_bl_device);
local_irq_save(flags);
locomolcd_dev = NULL;
#define DPRINTK(fmt, args...)
#endif
-static u32 cfb_tab8[] = {
+static const u32 cfb_tab8[] = {
#if defined(__BIG_ENDIAN)
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
#endif
};
-static u32 cfb_tab16[] = {
+static const u32 cfb_tab16[] = {
#if defined(__BIG_ENDIAN)
0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
#elif defined(__LITTLE_ENDIAN)
#endif
};
-static u32 cfb_tab32[] = {
+static const u32 cfb_tab32[] = {
0x00000000, 0xffffffff
};
u32 bit_mask, end_mask, eorx, shift;
const char *s = image->data, *src;
u32 __iomem *dst;
- u32 *tab = NULL;
+ const u32 *tab = NULL;
int i, j, k;
switch (bpp) {
printk ("Cirrus Logic chipset on PCI bus\n");
pci_set_drvdata(pdev, info);
- return cirrusfb_register(cinfo);
+ ret = cirrusfb_register(cinfo);
+ if (ret)
+ iounmap(cinfo->fbmem);
+ return ret;
err_release_legacy:
if (release_io_ports)
printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
zorro_set_drvdata(z, info);
- return cirrusfb_register(cinfo);
+ ret = cirrusfb_register(cinfo);
+ if (ret) {
+ if (btype == BT_PICASSO4) {
+ iounmap(cinfo->fbmem);
+ iounmap(cinfo->regbase - 0x600000);
+ } else if (board_addr > 0x01000000)
+ iounmap(cinfo->fbmem);
+ }
+ return ret;
err_unmap_regbase:
/* Parental advisory: explicit hack */
/*
- * linux/drivers/video/softcursor.c -- Generic software cursor for frame buffer devices
+ * linux/drivers/video/softcursor.c
+ *
+ * Generic software cursor for frame buffer devices
*
* Created 14 Nov 2002 by James Simmons
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
*/
#include <linux/module.h>
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int i, size, dsize, s_pitch, d_pitch;
struct fb_image *image;
- u8 *dst;
+ u8 *src, *dst;
if (info->state != FBINFO_STATE_RUNNING)
return 0;
}
}
- image = (struct fb_image *) (ops->cursor_src + dsize);
+ src = ops->cursor_src + sizeof(struct fb_image);
+ image = (struct fb_image *)ops->cursor_src;
*image = cursor->image;
d_pitch = (s_pitch + scan_align) & ~scan_align;
switch (cursor->rop) {
case ROP_XOR:
for (i = 0; i < dsize; i++)
- ops->cursor_src[i] = image->data[i] ^
- cursor->mask[i];
+ src[i] = image->data[i] ^ cursor->mask[i];
break;
case ROP_COPY:
default:
for (i = 0; i < dsize; i++)
- ops->cursor_src[i] = image->data[i] &
- cursor->mask[i];
+ src[i] = image->data[i] & cursor->mask[i];
break;
}
} else
- memcpy(ops->cursor_src, image->data, dsize);
+ memcpy(src, image->data, dsize);
- fb_pad_aligned_buffer(dst, d_pitch, ops->cursor_src, s_pitch,
- image->height);
+ fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
image->data = dst;
info->fbops->fb_imageblit(info, image);
return 0;
{
}
-static struct consw sti_con = {
+static const struct consw sti_con = {
.owner = THIS_MODULE,
.con_startup = sticon_startup,
.con_init = sticon_init,
static unsigned long vgacon_uni_pagedir[2];
/* Description of the hardware situation */
-static unsigned long vga_vram_base; /* Base of video memory */
-static unsigned long vga_vram_end; /* End of video memory */
-static int vga_vram_size; /* Size of video memory */
-static u16 vga_video_port_reg; /* Video register select port */
-static u16 vga_video_port_val; /* Video register value port */
-static unsigned int vga_video_num_columns; /* Number of text columns */
-static unsigned int vga_video_num_lines; /* Number of text lines */
-static int vga_can_do_color = 0; /* Do we support colors? */
-static unsigned int vga_default_font_height;/* Height of default screen font */
-static unsigned char vga_video_type; /* Card type */
-static unsigned char vga_hardscroll_enabled;
-static unsigned char vga_hardscroll_user_enable = 1;
+static int vga_init_done __read_mostly;
+static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
+static unsigned long vga_vram_end __read_mostly; /* End of video memory */
+static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
+static u16 vga_video_port_reg __read_mostly; /* Video register select port */
+static u16 vga_video_port_val __read_mostly; /* Video register value port */
+static unsigned int vga_video_num_columns; /* Number of text columns */
+static unsigned int vga_video_num_lines; /* Number of text lines */
+static int vga_can_do_color __read_mostly; /* Do we support colors? */
+static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
+static unsigned char vga_video_type __read_mostly; /* Card type */
+static unsigned char vga_hardscroll_enabled __read_mostly;
+static unsigned char vga_hardscroll_user_enable __read_mostly = 1;
static unsigned char vga_font_is_default = 1;
static int vga_vesa_blanked;
static int vga_palette_blanked;
static int vga_is_gfx;
static int vga_512_chars;
static int vga_video_font_height;
-static int vga_scan_lines;
-static unsigned int vga_rolled_over = 0;
-static int vga_init_done;
+static int vga_scan_lines __read_mostly;
+static unsigned int vga_rolled_over;
static int __init no_scroll(char *str)
{
#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
-#define ww_64(regs,reg,dat) (*((volatile unsigned short *)(regs + reg) = dat)
-
struct cyberfb_par {
struct fb_var_screeninfo var;
__u32 type;
if (register_framebuffer(&fb_info) < 0) {
DPRINTK("EXIT - register_framebuffer failed\n");
+ if (CyberBase)
+ iounmap(CyberBase);
release_mem_region(CyberMem_phys, 0x400000);
release_mem_region(CyberRegs_phys, 0x10000);
return -EINVAL;
static ssize_t
epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
unsigned long p = *ppos;
epson1355fb_write(struct file *file, const char *buf,
size_t count, loff_t * ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
unsigned long p = *ppos;
#include <asm/uaccess.h>
-static u16 red2[] = {
+static u16 red2[] __read_mostly = {
0x0000, 0xaaaa
};
-static u16 green2[] = {
+static u16 green2[] __read_mostly = {
0x0000, 0xaaaa
};
-static u16 blue2[] = {
+static u16 blue2[] __read_mostly = {
0x0000, 0xaaaa
};
-static u16 red4[] = {
+static u16 red4[] __read_mostly = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u16 green4[] = {
+static u16 green4[] __read_mostly = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u16 blue4[] = {
+static u16 blue4[] __read_mostly = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
-static u16 red8[] = {
+static u16 red8[] __read_mostly = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
};
-static u16 green8[] = {
+static u16 green8[] __read_mostly = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
};
-static u16 blue8[] = {
+static u16 blue8[] __read_mostly = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
};
-static u16 red16[] = {
+static u16 red16[] __read_mostly = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
};
-static u16 green16[] = {
+static u16 green16[] __read_mostly = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
};
-static u16 blue16[] = {
+static u16 blue16[] __read_mostly = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
};
-static struct fb_cmap default_2_colors = {
- 0, 2, red2, green2, blue2, NULL
+static const struct fb_cmap default_2_colors = {
+ .len=2, .red=red2, .green=green2, .blue=blue2
};
-static struct fb_cmap default_8_colors = {
- 0, 8, red8, green8, blue8, NULL
+static const struct fb_cmap default_8_colors = {
+ .len=8, .red=red8, .green=green8, .blue=blue8
};
-static struct fb_cmap default_4_colors = {
- 0, 4, red4, green4, blue4, NULL
+static const struct fb_cmap default_4_colors = {
+ .len=4, .red=red4, .green=green4, .blue=blue4
};
-static struct fb_cmap default_16_colors = {
- 0, 16, red16, green16, blue16, NULL
+static const struct fb_cmap default_16_colors = {
+ .len=16, .red=red16, .green=green16, .blue=blue16
};
+
/**
* fb_alloc_cmap - allocate a colormap
* @cmap: frame buffer colormap structure
* Copy contents of colormap from @from to @to.
*/
-int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to)
+int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
{
int tooff = 0, fromoff = 0;
int size;
return 0;
}
-int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to)
+int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
{
int tooff = 0, fromoff = 0;
int size;
*
*/
-struct fb_cmap *fb_default_cmap(int len)
+const struct fb_cmap *fb_default_cmap(int len)
{
if (len <= 2)
return &default_2_colors;
{
u_int i;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < ARRAY_SIZE(red2); i++) {
red2[i] = ~red2[i];
green2[i] = ~green2[i];
blue2[i] = ~blue2[i];
}
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ARRAY_SIZE(red4); i++) {
red4[i] = ~red4[i];
green4[i] = ~green4[i];
blue4[i] = ~blue4[i];
}
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < ARRAY_SIZE(red8); i++) {
red8[i] = ~red8[i];
green8[i] = ~green8[i];
blue8[i] = ~blue8[i];
}
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < ARRAY_SIZE(red16); i++) {
red16[i] = ~red16[i];
green16[i] = ~green16[i];
blue16[i] = ~blue16[i];
u32 status;
};
-static int fb_cvt_vbi_tab[] = {
+static const unsigned char fb_cvt_vbi_tab[] = {
4, /* 4:3 */
5, /* 16:9 */
6, /* 16:10 */
#define FBPIXMAPSIZE (1024 * 8)
-struct fb_info *registered_fb[FB_MAX];
-int num_registered_fb;
+struct fb_info *registered_fb[FB_MAX] __read_mostly;
+int num_registered_fb __read_mostly;
/*
* Helpers
const struct linux_logo *logo,
u32 *palette)
{
- unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
+ static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
unsigned char redmask, greenmask, bluemask;
int redshift, greenshift, blueshift;
int i;
int needs_truepalette;
int needs_cmapreset;
const struct linux_logo *logo;
-} fb_logo;
+} fb_logo __read_mostly;
static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
{
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
u32 *buffer, *dst;
fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
u32 *buffer, *src;
static long
fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
- int fbidx = iminor(file->f_dentry->d_inode);
+ int fbidx = iminor(file->f_path.dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
unsigned long off;
return 0;
}
-static struct file_operations fb_fops = {
+static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
return err;
}
-static char *video_options[FB_MAX];
-static int ofonly;
+static char *video_options[FB_MAX] __read_mostly;
+static int ofonly __read_mostly;
extern const char *global_mode_option;
u32 fix;
};
-static struct broken_edid brokendb[] = {
+static const struct broken_edid brokendb[] = {
/* DEC FR-PCXAV-YZ */
{
.manufacturer = "DEC",
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
printk(KERN_ERR "ffb: Could not allocate color map.\n");
+ of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(all->par.dac, sizeof(struct ffb_dac));
kfree(all);
return -ENOMEM;
}
if (err < 0) {
printk(KERN_ERR "ffb: Could not register framebuffer.\n");
fb_dealloc_cmap(&all->info.cmap);
+ of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(all->par.dac, sizeof(struct ffb_dac));
kfree(all);
return err;
}
if (register_framebuffer(info) < 0) {
fb_dealloc_cmap(&info->cmap);
+ iounmap(info->screen_base);
framebuffer_release(info);
zorro_release_device(z);
return -EINVAL;
If unsure, say N.
+config FB_GEODE_GX_SET_FBSIZE
+ bool "Manually specify the Geode GX framebuffer size"
+ depends on FB_GEODE_GX
+ default n
+ ---help---
+ If you want to manually specify the size of your GX framebuffer,
+ say Y here, otherwise say N to dynamically probe it.
+
+ Say N unless you know what you are doing.
+
+config FB_GEODE_GX_FBSIZE
+ hex "Size of the GX framebuffer, in bytes"
+ depends on FB_GEODE_GX_SET_FBSIZE
+ default "0x1600000"
+ ---help---
+ Specify the size of the GX framebuffer. Normally, you will
+ want this to be MB aligned. Common values are 0x80000 (8MB)
+ and 0x1600000 (16MB). Don't change this unless you know what
+ you are doing
+
config FB_GEODE_GX1
tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
depends on FB && FB_GEODE && EXPERIMENTAL
#include "geodefb.h"
#include "display_gx.h"
-int gx_frame_buffer_size(void)
+#ifdef CONFIG_FB_GEODE_GX_SET_FBSIZE
+unsigned int gx_frame_buffer_size(void)
{
- /* Assuming 16 MiB. */
- return 16*1024*1024;
+ return CONFIG_FB_GEODE_GX_FBSIZE;
}
+#else
+unsigned int gx_frame_buffer_size(void)
+{
+ unsigned int val;
+
+ /* FB size is reported by a virtual register */
+ /* Virtual register class = 0x02 */
+ /* VG_MEM_SIZE(512Kb units) = 0x00 */
+
+ outw(0xFC53, 0xAC1C);
+ outw(0x0200, 0xAC1C);
+
+ val = (unsigned int)(inw(0xAC1E)) & 0xFFl;
+ return (val << 19);
+}
+#endif
int gx_line_delta(int xres, int bpp)
{
writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2,
par->dc_regs + DC_LINE_SIZE);
+
/* Enable graphics and video data and unmask address lines. */
dcfg |= DC_DCFG_GDEN | DC_DCFG_VDEN | DC_DCFG_A20M | DC_DCFG_A18M;
#ifndef __DISPLAY_GX_H__
#define __DISPLAY_GX_H__
-int gx_frame_buffer_size(void);
+unsigned int gx_frame_buffer_size(void);
int gx_line_delta(int xres, int bpp);
extern struct geode_dc_ops gx_dc_ops;
+/* MSR that tells us if a TFT or CRT is attached */
+#define GLD_MSR_CONFIG 0xC0002001
+#define GLD_MSR_CONFIG_DM_FP 0x40
+
/* Display controller registers */
#define DC_UNLOCK 0x00
#define DC_PAL_ADDRESS 0x70
#define DC_PAL_DATA 0x74
+#define DC_GLIU0_MEM_OFFSET 0x84
#endif /* !__DISPLAY_GX1_H__ */
#include "display_gx.h"
#include "video_gx.h"
-static char mode_option[32] = "640x480-16@60";
+static char *mode_option;
/* Modes relevant to the GX (taken from modedb.c) */
-static const struct fb_videomode __initdata gx_modedb[] = {
+static const struct fb_videomode gx_modedb[] __initdata = {
/* 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
if (!info->screen_base)
return -ENOMEM;
+ /* Set the 16MB aligned base address of the graphics memory region
+ * in the display controller */
+
+ writel(info->fix.smem_start & 0xFF000000,
+ par->dc_regs + DC_GLIU0_MEM_OFFSET);
+
dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
info->fix.smem_len / 1024, info->fix.smem_start);
struct geodefb_par *par;
struct fb_info *info;
int ret;
+ unsigned long val;
info = gxfb_init_fbinfo(&pdev->dev);
if (!info)
goto err;
}
+ /* Figure out if this is a TFT or CRT part */
+
+ rdmsrl(GLD_MSR_CONFIG, val);
+
+ if ((val & GLD_MSR_CONFIG_DM_FP) == GLD_MSR_CONFIG_DM_FP)
+ par->enable_crt = 0;
+ else
+ par->enable_crt = 1;
+
ret = fb_find_mode(&info->var, info, mode_option,
gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16);
if (ret == 0 || ret == 4) {
goto err;
}
- /* Clear the frame buffer of garbage. */
+
+ /* Clear the frame buffer of garbage. */
memset_io(info->screen_base, 0, info->fix.smem_len);
gxfb_check_var(&info->var, info);
.remove = gxfb_remove,
};
+#ifndef MODULE
+static int __init gxfb_setup(char *options)
+{
+
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+
+ mode_option = opt;
+ }
+
+ return 0;
+}
+#endif
+
static int __init gxfb_init(void)
{
#ifndef MODULE
- if (fb_get_options("gxfb", NULL))
+ char *option = NULL;
+
+ if (fb_get_options("gxfb", &option))
return -ENODEV;
+
+ gxfb_setup(option);
#endif
return pci_register_driver(&gxfb_driver);
}
module_init(gxfb_init);
module_exit(gxfb_cleanup);
-module_param_string(mode, mode_option, sizeof(mode_option), 0444);
-MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode GX");
MODULE_LICENSE("GPL");
} while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
}
+static void
+gx_configure_tft(struct fb_info *info)
+{
+ struct geodefb_par *par = info->par;
+ unsigned long val;
+ unsigned long fp;
+
+ /* Set up the DF pad select MSR */
+
+ rdmsrl(GX_VP_MSR_PAD_SELECT, val);
+ val &= ~GX_VP_PAD_SELECT_MASK;
+ val |= GX_VP_PAD_SELECT_TFT;
+ wrmsrl(GX_VP_MSR_PAD_SELECT, val);
+
+ /* Turn off the panel */
+
+ fp = readl(par->vid_regs + GX_FP_PM);
+ fp &= ~GX_FP_PM_P;
+ writel(fp, par->vid_regs + GX_FP_PM);
+
+ /* Set timing 1 */
+
+ fp = readl(par->vid_regs + GX_FP_PT1);
+ fp &= GX_FP_PT1_VSIZE_MASK;
+ fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT;
+ writel(fp, par->vid_regs + GX_FP_PT1);
+
+ /* Timing 2 */
+ /* Set bits that are always on for TFT */
+
+ fp = 0x0F100000;
+
+ /* Add sync polarity */
+
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ fp |= GX_FP_PT2_VSP;
+
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ fp |= GX_FP_PT2_HSP;
+
+ writel(fp, par->vid_regs + GX_FP_PT2);
+
+ /* Set the dither control */
+ writel(0x70, par->vid_regs + GX_FP_DFC);
+
+ /* Enable the FP data and power (in case the BIOS didn't) */
+
+ fp = readl(par->vid_regs + GX_DCFG);
+ fp |= GX_DCFG_FP_PWR_EN | GX_DCFG_FP_DATA_EN;
+ writel(fp, par->vid_regs + GX_DCFG);
+
+ /* Unblank the panel */
+
+ fp = readl(par->vid_regs + GX_FP_PM);
+ fp |= GX_FP_PM_P;
+ writel(fp, par->vid_regs + GX_FP_PM);
+}
+
static void gx_configure_display(struct fb_info *info)
{
struct geodefb_par *par = info->par;
- u32 dcfg, fp_pm;
+ u32 dcfg, misc;
+
+ /* Set up the MISC register */
+
+ misc = readl(par->vid_regs + GX_MISC);
+
+ /* Power up the DAC */
+ misc &= ~(GX_MISC_A_PWRDN | GX_MISC_DAC_PWRDN);
+
+ /* Disable gamma correction */
+ misc |= GX_MISC_GAM_EN;
+
+ writel(misc, par->vid_regs + GX_MISC);
+ /* Write the display configuration */
dcfg = readl(par->vid_regs + GX_DCFG);
+ /* Disable hsync and vsync */
+ dcfg &= ~(GX_DCFG_VSYNC_EN | GX_DCFG_HSYNC_EN);
+ writel(dcfg, par->vid_regs + GX_DCFG);
+
/* Clear bits from existing mode. */
dcfg &= ~(GX_DCFG_CRT_SYNC_SKW_MASK
| GX_DCFG_CRT_HSYNC_POL | GX_DCFG_CRT_VSYNC_POL
if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
dcfg |= GX_DCFG_CRT_VSYNC_POL;
+ /* Enable the display logic */
+ /* Set up the DACS to blank normally */
+
+ dcfg |= GX_DCFG_CRT_EN | GX_DCFG_DAC_BL_EN;
+
+ /* Enable the external DAC VREF? */
+
writel(dcfg, par->vid_regs + GX_DCFG);
- /* Power on flat panel. */
- fp_pm = readl(par->vid_regs + GX_FP_PM);
- fp_pm |= GX_FP_PM_P;
- writel(fp_pm, par->vid_regs + GX_FP_PM);
+ /* Set up the flat panel (if it is enabled) */
+
+ if (par->enable_crt == 0)
+ gx_configure_tft(info);
}
static int gx_blank_display(struct fb_info *info, int blank_mode)
writel(dcfg, par->vid_regs + GX_DCFG);
/* Power on/off flat panel. */
- fp_pm = readl(par->vid_regs + GX_FP_PM);
- if (blank_mode == FB_BLANK_POWERDOWN)
- fp_pm &= ~GX_FP_PM_P;
- else
- fp_pm |= GX_FP_PM_P;
- writel(fp_pm, par->vid_regs + GX_FP_PM);
+
+ if (par->enable_crt == 0) {
+ fp_pm = readl(par->vid_regs + GX_FP_PM);
+ if (blank_mode == FB_BLANK_POWERDOWN)
+ fp_pm &= ~GX_FP_PM_P;
+ else
+ fp_pm |= GX_FP_PM_P;
+ writel(fp_pm, par->vid_regs + GX_FP_PM);
+ }
return 0;
}
extern struct geode_vid_ops gx_vid_ops;
+/* GX Flatpanel control MSR */
+#define GX_VP_MSR_PAD_SELECT 0xC0002011
+#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF
+#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF
+
/* Geode GX video processor registers */
#define GX_DCFG 0x0008
# define GX_DCFG_HSYNC_EN 0x00000002
# define GX_DCFG_VSYNC_EN 0x00000004
# define GX_DCFG_DAC_BL_EN 0x00000008
+# define GX_DCFG_FP_PWR_EN 0x00000040
+# define GX_DCFG_FP_DATA_EN 0x00000080
# define GX_DCFG_CRT_HSYNC_POL 0x00000100
# define GX_DCFG_CRT_VSYNC_POL 0x00000200
# define GX_DCFG_CRT_SYNC_SKW_MASK 0x0001C000
# define GX_DCFG_GV_GAM 0x00200000
# define GX_DCFG_DAC_VREF 0x04000000
+/* Geode GX MISC video configuration */
+
+#define GX_MISC 0x50
+#define GX_MISC_GAM_EN 0x00000001
+#define GX_MISC_DAC_PWRDN 0x00000400
+#define GX_MISC_A_PWRDN 0x00000800
+
/* Geode GX flat panel display control registers */
+
+#define GX_FP_PT1 0x0400
+#define GX_FP_PT1_VSIZE_MASK 0x7FF0000
+#define GX_FP_PT1_VSIZE_SHIFT 16
+
+#define GX_FP_PT2 0x408
+#define GX_FP_PT2_VSP (1 << 23)
+#define GX_FP_PT2_HSP (1 << 22)
+
#define GX_FP_PM 0x410
# define GX_FP_PM_P 0x01000000
+#define GX_FP_DFC 0x418
+
/* Geode GX clock control MSRs */
#define MSR_GLCP_SYS_RSTPLL 0x4c000014
if (register_framebuffer(&fb_info) < 0) {
fb_dealloc_cmap(&fb_info.cmap);
+ iounmap(fb_info.screen_base);
+ fb_info.screen_base = NULL;
return 1;
}
if (e != NULL) {
DPRINTK("i810-i2c: Getting EDID from BIOS\n");
- edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (edid)
- memcpy(edid, e, EDID_LENGTH);
+ edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
}
}
if (!con_is_present())
return -ENXIO;
- pdev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) {
/*
* XXX We tried to use cyber2000fb.c for IGS 2000.
* But it does not initialize the chip in JavaStation-E, alas.
*/
- pdev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
+ pdev = pci_get_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
if(pdev == NULL) {
return -ENXIO;
}
iga2000 = 1;
}
+ /* We leak a reference here but as it cannot be unloaded this is
+ fine. If you write unload code remember to free it in unload */
size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16;
u8 *edid_d = NULL;
if (edid_s) {
- edid_d = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ edid_d = kmemdup(edid_s, EDID_LENGTH, GFP_KERNEL);
if (edid_d) {
- memcpy(edid_d, edid_s, EDID_LENGTH);
fb_edid_to_monspecs(edid_d,
&dinfo->info->monspecs);
kfree(edid_d);
}
}
+static void __init iounmap_macfb(void)
+{
+ if (valkyrie_cmap_regs)
+ iounmap(valkyrie_cmap_regs);
+ if (dafb_cmap_regs)
+ iounmap(dafb_cmap_regs);
+ if (v8_brazil_cmap_regs)
+ iounmap(v8_brazil_cmap_regs);
+ if (rbv_cmap_regs)
+ iounmap(rbv_cmap_regs);
+ if (civic_cmap_regs)
+ iounmap(civic_cmap_regs);
+ if (csc_cmap_regs)
+ iounmap(csc_cmap_regs);
+}
+
static int __init macfb_init(void)
{
int video_cmap_len, video_is_nubus = 0;
if (!err)
printk("fb%d: %s frame buffer device\n",
fb_info.node, fb_info.fix.id);
+ else {
+ iounmap(fb_info.screen_base);
+ iounmap_macfb();
+ }
return err;
}
struct dentry *clock;
struct dentry *display;
struct dentry *gsctl;
+ struct dentry *sdram;
+ struct dentry *misc;
};
static int open_file_generic(struct inode *inode, struct file *file)
{
char * s = big_buffer;
- s += sprintf(s, "SYSCFG = %08lx\n", SYSCFG);
- s += sprintf(s, "PFBASE = %08lx\n", PFBASE);
- s += sprintf(s, "PFCEIL = %08lx\n", PFCEIL);
- s += sprintf(s, "POLLFLAG = %08lx\n", POLLFLAG);
- s += sprintf(s, "SYSRST = %08lx\n", SYSRST);
+ s += sprintf(s, "SYSCFG = %08x\n", readl(SYSCFG));
+ s += sprintf(s, "PFBASE = %08x\n", readl(PFBASE));
+ s += sprintf(s, "PFCEIL = %08x\n", readl(PFCEIL));
+ s += sprintf(s, "POLLFLAG = %08x\n", readl(POLLFLAG));
+ s += sprintf(s, "SYSRST = %08x\n", readl(SYSRST));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
{
char * s = big_buffer;
- s += sprintf(s, "GSCTRL = %08lx\n", GSCTRL);
- s += sprintf(s, "VSCTRL = %08lx\n", VSCTRL);
- s += sprintf(s, "GBBASE = %08lx\n", GBBASE);
- s += sprintf(s, "VBBASE = %08lx\n", VBBASE);
- s += sprintf(s, "GDRCTRL = %08lx\n", GDRCTRL);
- s += sprintf(s, "VCMSK = %08lx\n", VCMSK);
- s += sprintf(s, "GSCADR = %08lx\n", GSCADR);
- s += sprintf(s, "VSCADR = %08lx\n", VSCADR);
- s += sprintf(s, "VUBASE = %08lx\n", VUBASE);
- s += sprintf(s, "VVBASE = %08lx\n", VVBASE);
- s += sprintf(s, "GSADR = %08lx\n", GSADR);
- s += sprintf(s, "VSADR = %08lx\n", VSADR);
- s += sprintf(s, "HCCTRL = %08lx\n", HCCTRL);
- s += sprintf(s, "HCSIZE = %08lx\n", HCSIZE);
- s += sprintf(s, "HCPOS = %08lx\n", HCPOS);
- s += sprintf(s, "HCBADR = %08lx\n", HCBADR);
- s += sprintf(s, "HCCKMSK = %08lx\n", HCCKMSK);
- s += sprintf(s, "GPLUT = %08lx\n", GPLUT);
+ s += sprintf(s, "GSCTRL = %08x\n", readl(GSCTRL));
+ s += sprintf(s, "VSCTRL = %08x\n", readl(VSCTRL));
+ s += sprintf(s, "GBBASE = %08x\n", readl(GBBASE));
+ s += sprintf(s, "VBBASE = %08x\n", readl(VBBASE));
+ s += sprintf(s, "GDRCTRL = %08x\n", readl(GDRCTRL));
+ s += sprintf(s, "VCMSK = %08x\n", readl(VCMSK));
+ s += sprintf(s, "GSCADR = %08x\n", readl(GSCADR));
+ s += sprintf(s, "VSCADR = %08x\n", readl(VSCADR));
+ s += sprintf(s, "VUBASE = %08x\n", readl(VUBASE));
+ s += sprintf(s, "VVBASE = %08x\n", readl(VVBASE));
+ s += sprintf(s, "GSADR = %08x\n", readl(GSADR));
+ s += sprintf(s, "VSADR = %08x\n", readl(VSADR));
+ s += sprintf(s, "HCCTRL = %08x\n", readl(HCCTRL));
+ s += sprintf(s, "HCSIZE = %08x\n", readl(HCSIZE));
+ s += sprintf(s, "HCPOS = %08x\n", readl(HCPOS));
+ s += sprintf(s, "HCBADR = %08x\n", readl(HCBADR));
+ s += sprintf(s, "HCCKMSK = %08x\n", readl(HCCKMSK));
+ s += sprintf(s, "GPLUT = %08x\n", readl(GPLUT));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
{
char * s = big_buffer;
- s += sprintf(s, "DSCTRL = %08lx\n", DSCTRL);
- s += sprintf(s, "DHT01 = %08lx\n", DHT01);
- s += sprintf(s, "DHT02 = %08lx\n", DHT02);
- s += sprintf(s, "DHT03 = %08lx\n", DHT03);
- s += sprintf(s, "DVT01 = %08lx\n", DVT01);
- s += sprintf(s, "DVT02 = %08lx\n", DVT02);
- s += sprintf(s, "DVT03 = %08lx\n", DVT03);
- s += sprintf(s, "DBCOL = %08lx\n", DBCOL);
- s += sprintf(s, "BGCOLOR = %08lx\n", BGCOLOR);
- s += sprintf(s, "DINTRS = %08lx\n", DINTRS);
- s += sprintf(s, "DINTRE = %08lx\n", DINTRE);
- s += sprintf(s, "DINTRCNT = %08lx\n", DINTRCNT);
- s += sprintf(s, "DSIG = %08lx\n", DSIG);
- s += sprintf(s, "DMCTRL = %08lx\n", DMCTRL);
- s += sprintf(s, "CLIPCTRL = %08lx\n", CLIPCTRL);
- s += sprintf(s, "SPOCTRL = %08lx\n", SPOCTRL);
- s += sprintf(s, "SVCTRL = %08lx\n", SVCTRL);
- s += sprintf(s, "DLSTS = %08lx\n", DLSTS);
- s += sprintf(s, "DLLCTRL = %08lx\n", DLLCTRL);
- s += sprintf(s, "DVLNUM = %08lx\n", DVLNUM);
- s += sprintf(s, "DUCTRL = %08lx\n", DUCTRL);
- s += sprintf(s, "DVECTRL = %08lx\n", DVECTRL);
- s += sprintf(s, "DHDET = %08lx\n", DHDET);
- s += sprintf(s, "DVDET = %08lx\n", DVDET);
- s += sprintf(s, "DODMSK = %08lx\n", DODMSK);
- s += sprintf(s, "CSC01 = %08lx\n", CSC01);
- s += sprintf(s, "CSC02 = %08lx\n", CSC02);
- s += sprintf(s, "CSC03 = %08lx\n", CSC03);
- s += sprintf(s, "CSC04 = %08lx\n", CSC04);
- s += sprintf(s, "CSC05 = %08lx\n", CSC05);
+ s += sprintf(s, "DSCTRL = %08x\n", readl(DSCTRL));
+ s += sprintf(s, "DHT01 = %08x\n", readl(DHT01));
+ s += sprintf(s, "DHT02 = %08x\n", readl(DHT02));
+ s += sprintf(s, "DHT03 = %08x\n", readl(DHT03));
+ s += sprintf(s, "DVT01 = %08x\n", readl(DVT01));
+ s += sprintf(s, "DVT02 = %08x\n", readl(DVT02));
+ s += sprintf(s, "DVT03 = %08x\n", readl(DVT03));
+ s += sprintf(s, "DBCOL = %08x\n", readl(DBCOL));
+ s += sprintf(s, "BGCOLOR = %08x\n", readl(BGCOLOR));
+ s += sprintf(s, "DINTRS = %08x\n", readl(DINTRS));
+ s += sprintf(s, "DINTRE = %08x\n", readl(DINTRE));
+ s += sprintf(s, "DINTRCNT = %08x\n", readl(DINTRCNT));
+ s += sprintf(s, "DSIG = %08x\n", readl(DSIG));
+ s += sprintf(s, "DMCTRL = %08x\n", readl(DMCTRL));
+ s += sprintf(s, "CLIPCTRL = %08x\n", readl(CLIPCTRL));
+ s += sprintf(s, "SPOCTRL = %08x\n", readl(SPOCTRL));
+ s += sprintf(s, "SVCTRL = %08x\n", readl(SVCTRL));
+ s += sprintf(s, "DLSTS = %08x\n", readl(DLSTS));
+ s += sprintf(s, "DLLCTRL = %08x\n", readl(DLLCTRL));
+ s += sprintf(s, "DVLNUM = %08x\n", readl(DVLNUM));
+ s += sprintf(s, "DUCTRL = %08x\n", readl(DUCTRL));
+ s += sprintf(s, "DVECTRL = %08x\n", readl(DVECTRL));
+ s += sprintf(s, "DHDET = %08x\n", readl(DHDET));
+ s += sprintf(s, "DVDET = %08x\n", readl(DVDET));
+ s += sprintf(s, "DODMSK = %08x\n", readl(DODMSK));
+ s += sprintf(s, "CSC01 = %08x\n", readl(CSC01));
+ s += sprintf(s, "CSC02 = %08x\n", readl(CSC02));
+ s += sprintf(s, "CSC03 = %08x\n", readl(CSC03));
+ s += sprintf(s, "CSC04 = %08x\n", readl(CSC04));
+ s += sprintf(s, "CSC05 = %08x\n", readl(CSC05));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
{
char * s = big_buffer;
- s += sprintf(s, "SYSCLKSRC = %08lx\n", SYSCLKSRC);
- s += sprintf(s, "PIXCLKSRC = %08lx\n", PIXCLKSRC);
- s += sprintf(s, "CLKSLEEP = %08lx\n", CLKSLEEP);
- s += sprintf(s, "COREPLL = %08lx\n", COREPLL);
- s += sprintf(s, "DISPPLL = %08lx\n", DISPPLL);
- s += sprintf(s, "PLLSTAT = %08lx\n", PLLSTAT);
- s += sprintf(s, "VOVRCLK = %08lx\n", VOVRCLK);
- s += sprintf(s, "PIXCLK = %08lx\n", PIXCLK);
- s += sprintf(s, "MEMCLK = %08lx\n", MEMCLK);
- s += sprintf(s, "M24CLK = %08lx\n", M24CLK);
- s += sprintf(s, "MBXCLK = %08lx\n", MBXCLK);
- s += sprintf(s, "SDCLK = %08lx\n", SDCLK);
- s += sprintf(s, "PIXCLKDIV = %08lx\n", PIXCLKDIV);
+ s += sprintf(s, "SYSCLKSRC = %08x\n", readl(SYSCLKSRC));
+ s += sprintf(s, "PIXCLKSRC = %08x\n", readl(PIXCLKSRC));
+ s += sprintf(s, "CLKSLEEP = %08x\n", readl(CLKSLEEP));
+ s += sprintf(s, "COREPLL = %08x\n", readl(COREPLL));
+ s += sprintf(s, "DISPPLL = %08x\n", readl(DISPPLL));
+ s += sprintf(s, "PLLSTAT = %08x\n", readl(PLLSTAT));
+ s += sprintf(s, "VOVRCLK = %08x\n", readl(VOVRCLK));
+ s += sprintf(s, "PIXCLK = %08x\n", readl(PIXCLK));
+ s += sprintf(s, "MEMCLK = %08x\n", readl(MEMCLK));
+ s += sprintf(s, "M24CLK = %08x\n", readl(M24CLK));
+ s += sprintf(s, "MBXCLK = %08x\n", readl(MBXCLK));
+ s += sprintf(s, "SDCLK = %08x\n", readl(SDCLK));
+ s += sprintf(s, "PIXCLKDIV = %08x\n", readl(PIXCLKDIV));
return simple_read_from_buffer(userbuf, count, ppos,
big_buffer, s-big_buffer);
}
+static ssize_t sdram_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "LMRST = %08x\n", readl(LMRST));
+ s += sprintf(s, "LMCFG = %08x\n", readl(LMCFG));
+ s += sprintf(s, "LMPWR = %08x\n", readl(LMPWR));
+ s += sprintf(s, "LMPWRSTAT = %08x\n", readl(LMPWRSTAT));
+ s += sprintf(s, "LMCEMR = %08x\n", readl(LMCEMR));
+ s += sprintf(s, "LMTYPE = %08x\n", readl(LMTYPE));
+ s += sprintf(s, "LMTIM = %08x\n", readl(LMTIM));
+ s += sprintf(s, "LMREFRESH = %08x\n", readl(LMREFRESH));
+ s += sprintf(s, "LMPROTMIN = %08x\n", readl(LMPROTMIN));
+ s += sprintf(s, "LMPROTMAX = %08x\n", readl(LMPROTMAX));
+ s += sprintf(s, "LMPROTCFG = %08x\n", readl(LMPROTCFG));
+ s += sprintf(s, "LMPROTERR = %08x\n", readl(LMPROTERR));
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t misc_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "LCD_CONFIG = %08x\n", readl(LCD_CONFIG));
+ s += sprintf(s, "ODFBPWR = %08x\n", readl(ODFBPWR));
+ s += sprintf(s, "ODFBSTAT = %08x\n", readl(ODFBSTAT));
+ s += sprintf(s, "ID = %08x\n", readl(ID));
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+
static struct file_operations sysconf_fops = {
.read = sysconf_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
+static struct file_operations sdram_fops = {
+ .read = sdram_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations misc_fops = {
+ .read = misc_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
{
fbi, &display_fops);
dbg->gsctl = debugfs_create_file("gsctl", 0444, dbg->dir,
fbi, &gsctl_fops);
+ dbg->sdram = debugfs_create_file("sdram", 0444, dbg->dir,
+ fbi, &sdram_fops);
+ dbg->misc = debugfs_create_file("misc", 0444, dbg->dir,
+ fbi, &misc_fops);
}
static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
struct mbxfb_info *mfbi = fbi->par;
struct mbxfb_debugfs_data *dbg = mfbi->debugfs_data;
+ debugfs_remove(dbg->misc);
+ debugfs_remove(dbg->sdram);
debugfs_remove(dbg->gsctl);
debugfs_remove(dbg->display);
debugfs_remove(dbg->clock);
/*
* linux/drivers/video/mbx/mbxfb.c
*
+ * Copyright (C) 2006 8D Technologies inc
+ * Raphael Assenat <raph@8d.com>
+ * - Added video overlay support
+ * - Various improvements
+ *
* Copyright (C) 2006 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
+ * - Creation of driver
*
* Based on pxafb.c
*
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/uaccess.h>
#include <asm/io.h>
static unsigned long virt_base_2700;
+#define write_reg(val, reg) do { writel((val), (reg)); } while(0)
+
+/* Without this delay, the graphics appears somehow scaled and
+ * there is a lot of jitter in scanlines. This delay is probably
+ * needed only after setting some specific register(s) somewhere,
+ * not all over the place... */
+#define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
+
#define MIN_XRES 16
#define MIN_YRES 16
#define MAX_XRES 2048
gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
gsctrl |= Gsctrl_Width(info->var.xres) |
Gsctrl_Height(info->var.yres);
- writel(gsctrl, GSCTRL);
- udelay(1000);
+ write_reg_dly(gsctrl, GSCTRL);
gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
(8 * 16) - 1);
- writel(gsadr, GSADR);
- udelay(1000);
+ write_reg_dly(gsadr, GSADR);
/* setup timings */
var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
- writel((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
+ write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
hbps = var->hsync_len;
vfps = vas + var->yres;
vt = vfps + var->lower_margin;
- writel((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
- writel((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
- writel((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
- writel((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
+ write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
+ write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
+ write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
+ write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
- writel((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
- writel((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
- writel((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
- writel((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
- writel((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
+ write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
+ write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
+ write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
+ write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
+ write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+
+ write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
return 0;
}
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_NORMAL:
- writel((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
- udelay(1000);
- writel((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
- udelay(1000);
- writel((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
- udelay(1000);
+ write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
+ write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
break;
case FB_BLANK_UNBLANK:
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
- udelay(1000);
- writel((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
- udelay(1000);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
break;
}
return 0;
}
+static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
+{
+ u32 vsctrl, vbbase, vscadr, vsadr;
+ u32 sssize, spoctrl, svctrl, shctrl;
+ u32 vubase, vvbase;
+ u32 vovrclk;
+
+ if (set->scaled_width==0 || set->scaled_height==0)
+ return -EINVAL;
+
+ /* read registers which have reserved bits
+ * so we can write them back as-is. */
+ vovrclk = readl(VOVRCLK);
+ vsctrl = readl(VSCTRL);
+ vscadr = readl(VSCADR);
+ vubase = readl(VUBASE);
+ vvbase = readl(VVBASE);
+
+ spoctrl = readl(SPOCTRL);
+ sssize = readl(SSSIZE);
+
+
+ vbbase = Vbbase_Glalpha(set->alpha);
+
+ vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) |
+ FMsk(VSCTRL_VSHEIGHT) |
+ FMsk(VSCTRL_VPIXFMT) |
+ VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
+ VSCTRL_COSITED );
+ vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
+ VSCTRL_CSC_EN;
+
+ vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC |
+ FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) |
+ FMsk(VSCADR_VBASE_ADR) );
+ vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
+ vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
+
+ switch (set->fmt)
+ {
+ case MBXFB_FMT_YUV12:
+ vsctrl |= VSCTRL_VPIXFMT_YUV12;
+
+ set->Y_stride = ((set->width) + 0xf ) & ~0xf;
+
+ break;
+ case MBXFB_FMT_UY0VY1:
+ vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_VY0UY1:
+ vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_Y0UY1V:
+ vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_Y0VY1U:
+ vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* VSCTRL has the bits which sets the Video Pixel Format.
+ * When passing from a packed to planar format,
+ * if we write VSCTRL first, VVBASE and VUBASE would
+ * be zero if we would not set them here. (And then,
+ * the chips hangs and only a reset seems to fix it).
+ *
+ * If course, the values calculated here have no meaning
+ * for packed formats.
+ */
+ set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
+ set->U_offset = set->height * set->Y_stride;
+ set->V_offset = set->U_offset +
+ set->height * set->UV_stride;
+ vubase |= Vubase_Ubase_Adr(
+ (0x60000 + set->mem_offset + set->U_offset)>>3);
+ vvbase |= Vvbase_Vbase_Adr(
+ (0x60000 + set->mem_offset + set->V_offset)>>3);
+
+
+ vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB |
+ Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
+
+ if (set->enable)
+ vscadr |= VSCADR_STR_EN;
+
+
+ vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
+ Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
+
+ sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
+ sssize = Sssize_Sc_Width(set->scaled_width-1) |
+ Sssize_Sc_Height(set->scaled_height-1);
+
+ spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
+ SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
+ FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH));
+ spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height)
+ | SPOCTRL_VORDER_2TAP;
+
+ /* Bypass horiz/vert scaler when same size */
+ if (set->scaled_width == set->width)
+ spoctrl |= SPOCTRL_H_SC_BP;
+ if (set->scaled_height == set->height)
+ spoctrl |= SPOCTRL_V_SC_BP;
+
+ svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
+
+ shctrl = Shctrl_Hinitial(4<<11)
+ | Shctrl_Hpitch((set->width<<11)/set->scaled_width);
+
+ /* Video plane registers */
+ write_reg(vsctrl, VSCTRL);
+ write_reg(vbbase, VBBASE);
+ write_reg(vscadr, VSCADR);
+ write_reg(vubase, VUBASE);
+ write_reg(vvbase, VVBASE);
+ write_reg(vsadr, VSADR);
+
+ /* Video scaler registers */
+ write_reg(sssize, SSSIZE);
+ write_reg(spoctrl, SPOCTRL);
+ write_reg(svctrl, SVCTRL);
+ write_reg(shctrl, SHCTRL);
+
+ /* RAPH: Using those coefficients, the scaled
+ * image is quite blurry. I dont know how
+ * to improve them ; The chip documentation
+ * was not helpful.. */
+ write_reg(0x21212121, VSCOEFF0);
+ write_reg(0x21212121, VSCOEFF1);
+ write_reg(0x21212121, VSCOEFF2);
+ write_reg(0x21212121, VSCOEFF3);
+ write_reg(0x21212121, VSCOEFF4);
+ write_reg(0x00000000, HSCOEFF0);
+ write_reg(0x00000000, HSCOEFF1);
+ write_reg(0x00000000, HSCOEFF2);
+ write_reg(0x03020201, HSCOEFF3);
+ write_reg(0x09070604, HSCOEFF4);
+ write_reg(0x0f0e0c0a, HSCOEFF5);
+ write_reg(0x15141211, HSCOEFF6);
+ write_reg(0x19181716, HSCOEFF7);
+ write_reg(0x00000019, HSCOEFF8);
+
+ /* Clock */
+ if (set->enable)
+ vovrclk |= 1;
+ else
+ vovrclk &= ~1;
+
+ write_reg(vovrclk, VOVRCLK);
+
+ return 0;
+}
+
+static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mbxfb_overlaySetup setup;
+ int res;
+
+ if (cmd == MBXFB_IOCX_OVERLAY)
+ {
+ if (copy_from_user(&setup, (void __user*)arg,
+ sizeof(struct mbxfb_overlaySetup)))
+ return -EFAULT;
+
+ res = mbxfb_setupOverlay(&setup);
+ if (res)
+ return res;
+
+ if (copy_to_user((void __user*)arg, &setup,
+ sizeof(struct mbxfb_overlaySetup)))
+ return -EFAULT;
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
static struct fb_ops mbxfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = mbxfb_check_var,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = mbxfb_blank,
+ .fb_ioctl = mbxfb_ioctl,
};
/*
*/
static void __devinit setup_memc(struct fb_info *fbi)
{
- struct mbxfb_info *mfbi = fbi->par;
unsigned long tmp;
int i;
/* FIXME: use platfrom specific parameters */
/* setup SDRAM controller */
- writel((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
+ write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
LMCFG_LMA_TS),
LMCFG);
- udelay(1000);
- writel(LMPWR_MC_PWR_ACT, LMPWR);
- udelay(1000);
+ write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
/* setup SDRAM timings */
- writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
+ write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
Lmtim_Trc(9) | Lmtim_Tdpl(2)),
LMTIM);
- udelay(1000);
/* setup SDRAM refresh rate */
- writel(0xc2b, LMREFRESH);
- udelay(1000);
+ write_reg_dly(0xc2b, LMREFRESH);
/* setup SDRAM type parameters */
- writel((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
+ write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
LMTYPE_COLSZ_8),
LMTYPE);
- udelay(1000);
/* enable memory controller */
- writel(LMPWR_MC_PWR_ACT, LMPWR);
- udelay(1000);
+ write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
/* perform dummy reads */
for ( i = 0; i < 16; i++ ) {
static void enable_clocks(struct fb_info *fbi)
{
/* enable clocks */
- writel(SYSCLKSRC_PLL_2, SYSCLKSRC);
- udelay(1000);
- writel(PIXCLKSRC_PLL_1, PIXCLKSRC);
- udelay(1000);
- writel(0x00000000, CLKSLEEP);
- udelay(1000);
- writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) |
+ write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
+ write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
+ write_reg_dly(0x00000000, CLKSLEEP);
+
+ /* PLL output = (Frefclk * M) / (N * 2^P )
+ *
+ * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
+ * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
+ * */
+ write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
CORE_PLL_EN),
COREPLL);
- udelay(1000);
- writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
+
+ write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
DISP_PLL_EN),
DISPPLL);
- writel(0x00000000, VOVRCLK);
- udelay(1000);
- writel(PIXCLK_EN, PIXCLK);
- udelay(1000);
- writel(MEMCLK_EN, MEMCLK);
- udelay(1000);
- writel(0x00000006, M24CLK);
- udelay(1000);
- writel(0x00000006, MBXCLK);
- udelay(1000);
- writel(SDCLK_EN, SDCLK);
- udelay(1000);
- writel(0x00000001, PIXCLKDIV);
- udelay(1000);
+ write_reg_dly(0x00000000, VOVRCLK);
+ write_reg_dly(PIXCLK_EN, PIXCLK);
+ write_reg_dly(MEMCLK_EN, MEMCLK);
+ write_reg_dly(0x00000006, M24CLK);
+ write_reg_dly(0x00000006, MBXCLK);
+ write_reg_dly(SDCLK_EN, SDCLK);
+ write_reg_dly(0x00000001, PIXCLKDIV);
}
static void __devinit setup_graphics(struct fb_info *fbi)
break;
}
- writel(gsctrl, GSCTRL);
- udelay(1000);
- writel(0x00000000, GBBASE);
- udelay(1000);
- writel(0x00ffffff, GDRCTRL);
- udelay(1000);
- writel((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
- udelay(1000);
- writel(0x00000000, GPLUT);
- udelay(1000);
+ write_reg_dly(gsctrl, GSCTRL);
+ write_reg_dly(0x00000000, GBBASE);
+ write_reg_dly(0x00ffffff, GDRCTRL);
+ write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
+ write_reg_dly(0x00000000, GPLUT);
}
static void __devinit setup_display(struct fb_info *fbi)
dsctrl |= DSCTRL_HS_POL;
if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
dsctrl |= DSCTRL_VS_POL;
- writel(dsctrl, DSCTRL);
- udelay(1000);
- writel(0xd0303010, DMCTRL);
- udelay(1000);
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly(dsctrl, DSCTRL);
+ write_reg_dly(0xd0303010, DMCTRL);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
}
static void __devinit enable_controller(struct fb_info *fbi)
{
- writel(SYSRST_RST, SYSRST);
- udelay(1000);
+ write_reg_dly(SYSRST_RST, SYSRST);
enable_clocks(fbi);
static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
{
/* make frame buffer memory enter self-refresh mode */
- writel(LMPWR_MC_PWR_SRM, LMPWR);
+ write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
; /* empty statement */
/* reset the device, since it's initial state is 'mostly sleeping' */
- writel(SYSRST_RST, SYSRST);
+ write_reg_dly(SYSRST_RST, SYSRST);
return 0;
}
/* setup_graphics(fbi); */
/* setup_display(fbi); */
- writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
return 0;
}
#else
dev_dbg(dev, "mbxfb_probe\n");
+ pdata = dev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&dev->dev, "platform data is required\n");
+ return -EINVAL;
+ }
+
fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
if (fbi == NULL) {
dev_err(&dev->dev, "framebuffer_alloc failed\n");
mfbi = fbi->par;
fbi->pseudo_palette = mfbi->pseudo_palette;
- pdata = dev->dev.platform_data;
+
+
if (pdata->probe)
mfbi->platform_probe = pdata->probe;
if (pdata->remove)
goto err4;
}
- /* FIXME: get from platform */
fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
- fbi->screen_size = 8 * 1024 * 1024; /* 8 Megs */
+ fbi->screen_size = pdata->memsize;
fbi->fbops = &mbxfb_ops;
fbi->var = mbxfb_default;
fbi->fix = mbxfb_fix;
fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
- fbi->fix.smem_len = 8 * 1024 * 1024;
- fbi->fix.line_length = 640 * 2;
+ fbi->fix.smem_len = pdata->memsize;
+ fbi->fix.line_length = mbxfb_default.xres_virtual *
+ mbxfb_default.bits_per_pixel / 8;
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret < 0) {
{
struct fb_info *fbi = platform_get_drvdata(dev);
- writel(SYSRST_RST, SYSRST);
- udelay(1000);
+ write_reg_dly(SYSRST_RST, SYSRST);
mbxfb_debugfs_remove(fbi);
#define GPLUT_LUTDATA Fld(24,0)
#define Gplut_Lutdata(x) ((x) << FShft(GPLUT_LUTDATA))
+/* VSCTRL - Video Surface Control Register */
+#define VSCTRL_VPIXFMT Fld(4,27)
+#define VSCTRL_VPIXFMT_YUV12 ((0x9) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_UY0VY1 ((0xc) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_VY0UY1 ((0xd) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_Y0UY1V ((0xe) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_Y0VY1U ((0xf) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_GAMMA_EN (1 << 26)
+#define VSCTRL_CSC_EN (1 << 25)
+#define VSCTRL_COSITED (1 << 22)
+#define VSCTRL_VSWIDTH Fld(11,11)
+#define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \
+ (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH))
+#define VSCTRL_VSHEIGHT Fld(11,0)
+#define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \
+ (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT))
+
+/* VBBASE - Video Blending Base Register */
+#define VBBASE_GLALPHA Fld(8,24)
+#define Vbbase_Glalpha(x) ((x) << FShft(VBBASE_GLALPHA))
+
+#define VBBASE_COLKEY Fld(24,0)
+#define Vbbase_Colkey(x) ((x) << FShft(VBBASE_COLKEY))
+
+/* VCMSK - Video Color Key Mask Register */
+#define VCMSK_COLKEY_M Fld(24,0)
+#define Vcmsk_colkey_m(x) ((x) << FShft(VCMSK_COLKEY_M))
+
+/* VSCADR - Video Stream Control Rddress Register */
+#define VSCADR_STR_EN (1 << 31)
+#define VSCADR_COLKEY_EN (1 << 30)
+#define VSCADR_COLKEYSRC (1 << 29)
+#define VSCADR_BLEND_M Fld(2,27)
+#define VSCADR_BLEND_NONE ((0x0) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_INV ((0x1) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_GLOB ((0x2) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_PIX ((0x3) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_POS Fld(2,24)
+#define VSCADR_BLEND_GFX ((0x0) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_BLEND_VID ((0x1) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_BLEND_CUR ((0x2) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_VBASE_ADR Fld(23,0)
+#define Vscadr_Vbase_Adr(x) ((x) << FShft(VSCADR_VBASE_ADR))
+
+/* VUBASE - Video U Base Register */
+#define VUBASE_UVHALFSTR (1 << 31)
+#define VUBASE_UBASE_ADR Fld(24,0)
+#define Vubase_Ubase_Adr(x) ((x) << FShft(VUBASE_UBASE_ADR))
+
+/* VVBASE - Video V Base Register */
+#define VVBASE_VBASE_ADR Fld(24,0)
+#define Vvbase_Vbase_Adr(x) ((x) << FShft(VVBASE_VBASE_ADR))
+
+/* VSADR - Video Stride Address Register */
+#define VSADR_SRCSTRIDE Fld(10,22)
+#define Vsadr_Srcstride(x) ((x) << FShft(VSADR_SRCSTRIDE))
+#define VSADR_XSTART Fld(11,11)
+#define Vsadr_Xstart(x) ((x) << FShft(VSADR_XSTART))
+#define VSADR_YSTART Fld(11,0)
+#define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART))
+
/* HCCTRL - Hardware Cursor Register fields */
#define HCCTRL_CUR_EN (1 << 31)
#define HCCTRL_COLKEY_EN (1 << 29)
#define DMCTRL_BURSTLEN Fld(6,0)
#define Dmctrl_Burstlen(x) ((x) << FShft(DMCTRL_BURSTLEN))
+/* DINTRS - Display Interrupt Status Register */
+#define DINTRS_CUR_OR_S (1 << 18)
+#define DINTRS_STR2_OR_S (1 << 17)
+#define DINTRS_STR1_OR_S (1 << 16)
+#define DINTRS_CUR_UR_S (1 << 6)
+#define DINTRS_STR2_UR_S (1 << 5)
+#define DINTRS_STR1_UR_S (1 << 4)
+#define DINTRS_VEVENT1_S (1 << 3)
+#define DINTRS_VEVENT0_S (1 << 2)
+#define DINTRS_HBLNK1_S (1 << 1)
+#define DINTRS_HBLNK0_S (1 << 0)
+
+/* DINTRE - Display Interrupt Enable Register */
+#define DINTRE_CUR_OR_EN (1 << 18)
+#define DINTRE_STR2_OR_EN (1 << 17)
+#define DINTRE_STR1_OR_EN (1 << 16)
+#define DINTRE_CUR_UR_EN (1 << 6)
+#define DINTRE_STR2_UR_EN (1 << 5)
+#define DINTRE_STR1_UR_EN (1 << 4)
+#define DINTRE_VEVENT1_EN (1 << 3)
+#define DINTRE_VEVENT0_EN (1 << 2)
+#define DINTRE_HBLNK1_EN (1 << 1)
+#define DINTRE_HBLNK0_EN (1 << 0)
+
/* DLSTS - display load status register */
#define DLSTS_RLD_ADONE (1 << 23)
#define DLLCTRL_RLD_ADRLN Fld(8,24)
#define Dllctrl_Rld_Adrln(x) ((x) << FShft(DLLCTRL_RLD_ADRLN))
+/* CLIPCTRL - Clipping Control Register */
+#define CLIPCTRL_HSKIP Fld(11,16)
+#define Clipctrl_Hskip ((x) << FShft(CLIPCTRL_HSKIP))
+#define CLIPCTRL_VSKIP Fld(11,0)
+#define Clipctrl_Vskip ((x) << FShft(CLIPCTRL_VSKIP))
+
/* SPOCTRL - Scale Pitch/Order Control Register */
#define SPOCTRL_H_SC_BP (1 << 31)
#define SPOCTRL_V_SC_BP (1 << 30)
#define SPOCTRL_HV_SC_OR (1 << 29)
#define SPOCTRL_VS_UR_C (1 << 27)
-#define SPOCTRL_VORDER Fld(2,16)
+#define SPOCTRL_VORDER Fld(2,16)
#define SPOCTRL_VORDER_1TAP ((0x0) << FShft(SPOCTRL_VORDER))
#define SPOCTRL_VORDER_2TAP ((0x1) << FShft(SPOCTRL_VORDER))
#define SPOCTRL_VORDER_4TAP ((0x3) << FShft(SPOCTRL_VORDER))
-#define SPOCTRL_VPITCH Fld(16,0)
+#define SPOCTRL_VPITCH Fld(16,0)
#define Spoctrl_Vpitch(x) ((x) << FShft(SPOCTRL_VPITCH))
+/* SVCTRL - Scale Vertical Control Register */
+#define SVCTRL_INITIAL1 Fld(16,16)
+#define Svctrl_Initial1(x) ((x) << FShft(SVCTRL_INITIAL1))
+#define SVCTRL_INITIAL2 Fld(16,0)
+#define Svctrl_Initial2(x) ((x) << FShft(SVCTRL_INITIAL2))
+
+/* SHCTRL - Scale Horizontal Control Register */
+#define SHCTRL_HINITIAL Fld(16,16)
+#define Shctrl_Hinitial(x) ((x) << FShft(SHCTRL_HINITIAL))
+#define SHCTRL_HDECIM (1 << 15)
+#define SHCTRL_HPITCH Fld(15,0)
+#define Shctrl_Hpitch(x) ((x) << FShft(SHCTRL_HPITCH))
+
+/* SSSIZE - Scale Surface Size Register */
+#define SSSIZE_SC_WIDTH Fld(11,16)
+#define Sssize_Sc_Width(x) ((x) << FShft(SSSIZE_SC_WIDTH))
+#define SSSIZE_SC_HEIGHT Fld(11,0)
+#define Sssize_Sc_Height(x) ((x) << FShft(SSSIZE_SC_HEIGHT))
+
#endif /* __REG_BITS_2700G_ */
#define HSCOEFF0 __REG_2700G(0x000021b4)
#define HSCOEFF1 __REG_2700G(0x000021b8)
#define HSCOEFF2 __REG_2700G(0x000021bc)
-#define HSCOEFF3 __REG_2700G(0x000021b0)
+#define HSCOEFF3 __REG_2700G(0x000021c0)
#define HSCOEFF4 __REG_2700G(0x000021c4)
#define HSCOEFF5 __REG_2700G(0x000021c8)
#define HSCOEFF6 __REG_2700G(0x000021cc)
* Standard video mode definitions (taken from XFree86)
*/
-#define DEFAULT_MODEDB_INDEX 0
-
static const struct fb_videomode modedb[] = {
{
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
db = modedb;
dbsize = ARRAY_SIZE(modedb);
}
+
if (!default_mode)
- default_mode = &modedb[DEFAULT_MODEDB_INDEX];
+ default_mode = &db[0];
+
if (!default_bpp)
default_bpp = 8;
printk(KERN_DEBUG "--- Neo extended register dump ---\n");
for (int w = 0; w < 0x85; w++)
printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
- (void *) vga_rcrt(NULL, w);
+ (void *) vga_rcrt(NULL, w));
for (int w = 0; w < 0xC7; w++)
printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
(void *) vga_rgfx(NULL, w));
NVDmaKickoff(par);
}
-u8 byte_rev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
int nvidiafb_sync(struct fb_info *info)
{
struct nvidia_par *par = info->par;
/* try to get from firmware */
const u8 *e = fb_firmware_edid(info->device);
- if (e != NULL) {
- edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (edid)
- memcpy(edid, e, EDID_LENGTH);
- }
+ if (e != NULL)
+ edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
}
*out_edid = edid;
#define READ_GET(par) (NV_RD32(&(par)->FIFO[0x0011], 0) >> 2)
#ifdef __LITTLE_ENDIAN
+
+#include <linux/bitrev.h>
+
#define reverse_order(l) \
do { \
u8 *a = (u8 *)(l); \
- *a = byte_rev[*a], a++; \
- *a = byte_rev[*a], a++; \
- *a = byte_rev[*a], a++; \
- *a = byte_rev[*a]; \
+ a[0] = bitrev8(a[0]); \
+ a[1] = bitrev8(a[1]); \
+ a[2] = bitrev8(a[2]); \
+ a[3] = bitrev8(a[3]); \
} while(0)
#else
#define reverse_order(l) do { } while(0)
}
}
if (pedid) {
- *out_edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ *out_edid = kmemdup(pedid, EDID_LENGTH, GFP_KERNEL);
if (*out_edid == NULL)
return -1;
- memcpy(*out_edid, pedid, EDID_LENGTH);
printk(KERN_DEBUG "nvidiafb: Found OF EDID for head %d\n", conn);
return 0;
}
extern void nvidiafb_imageblit(struct fb_info *info,
const struct fb_image *image);
extern int nvidiafb_sync(struct fb_info *info);
-extern u8 byte_rev[256];
/* in nv_backlight.h */
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
fb_alloc_cmap(&info->cmap, 256, 0);
if (register_framebuffer(info) < 0) {
+ iounmap(par->cmap_adr);
+ par->cmap_adr = NULL;
+ iounmap(info->screen_base);
kfree(info);
release_mem_region(res_start, res_size);
return;
rc = platinum_init_fb(info);
if (rc != 0) {
+ iounmap(pinfo->frame_buffer);
+ iounmap(pinfo->platinum_regs);
+ iounmap(pinfo->cmap_regs);
dev_set_drvdata(&odev->dev, NULL);
framebuffer_release(info);
}
static void __init pmagbbfb_osc_setup(struct fb_info *info)
{
static unsigned int pmagbbfb_freqs[] __initdata = {
- 130808, 119843, 104000, 92980, 74367, 72800,
+ 130808, 119843, 104000, 92980, 74370, 72800,
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
struct pmagbbfb_par *par = info->par;
static void pvr2fb_dc_exit(void)
{
+ if (fb_info->screen_base) {
+ iounmap(fb_info->screen_base);
+ fb_info->screen_base = NULL;
+ }
+ if (currentpar->mmio_base) {
+ iounmap((void *)currentpar->mmio_base);
+ currentpar->mmio_base = 0;
+ }
+
free_irq(HW_EVENT_VSYNC, 0);
#ifdef CONFIG_SH_DMA
free_dma(pvr2dma);
static void __devexit pvr2fb_pci_remove(struct pci_dev *pdev)
{
+ if (fb_info->screen_base) {
+ iounmap(fb_info->screen_base);
+ fb_info->screen_base = NULL;
+ }
+ if (currentpar->mmio_base) {
+ iounmap((void *)currentpar->mmio_base);
+ currentpar->mmio_base = 0;
+ }
+
pci_release_regions(pdev);
}
do_install_cmap(0, fb_info);
- if (register_framebuffer(fb_info) < 0)
+ if (register_framebuffer(fb_info) < 0) {
+ iounmap(zinfo->base);
return -EINVAL;
+ }
printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
"video memory\n", fb_info->node,
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/backlight.h>
+#include <linux/bitrev.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
return (VGA_RD08(par->riva.PVIO, 0x3cc));
}
-static u8 byte_rev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
static inline void reverse_order(u32 *l)
{
u8 *a = (u8 *)l;
- *a = byte_rev[*a], a++;
- *a = byte_rev[*a], a++;
- *a = byte_rev[*a], a++;
- *a = byte_rev[*a];
+ a[0] = bitrev8(a[0]);
+ a[1] = bitrev8(a[1]);
+ a[2] = bitrev8(a[2]);
+ a[3] = bitrev8(a[3]);
}
/* ------------------------------------------------------------------------- *
* CALLED FROM:
* rivafb_set_par()
*/
-static void riva_load_video_mode(struct fb_info *info)
+static int riva_load_video_mode(struct fb_info *info)
{
int bpp, width, hDisplaySize, hDisplay, hStart,
hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
+ int rc;
struct riva_par *par = info->par;
struct riva_regs newmode;
else
newmode.misc_output |= 0x80;
- par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
- hDisplaySize, height, dotClock);
+ rc = CalcStateExt(&par->riva, &newmode.ext, bpp, width,
+ hDisplaySize, height, dotClock);
+ if (rc)
+ goto out;
newmode.ext.scale = NV_RD32(par->riva.PRAMDAC, 0x00000848) &
0xfff000ff;
par->current_state = newmode;
riva_load_state(par, &par->current_state);
par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
+
+out:
rivafb_blank(FB_BLANK_UNBLANK, info);
NVTRACE_LEAVE();
+
+ return rc;
}
static void riva_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
static int rivafb_set_par(struct fb_info *info)
{
struct riva_par *par = info->par;
+ int rc = 0;
NVTRACE_ENTER();
/* vgaHWunlock() + riva unlock (0x7F) */
CRTCout(par, 0x11, 0xFF);
par->riva.LockUnlock(&par->riva, 0);
- riva_load_video_mode(info);
+ rc = riva_load_video_mode(info);
+ if (rc)
+ goto out;
if(!(info->flags & FBINFO_HWACCEL_DISABLED))
riva_setup_accel(info);
info->pixmap.scan_align = 1;
else
info->pixmap.scan_align = 4;
+
+out:
NVTRACE_LEAVE();
- return 0;
+ return rc;
}
/**
* Calculate extended mode parameters (SVGA) and save in a
* mode state structure.
*/
-static void CalcStateExt
+int CalcStateExt
(
RIVA_HW_INST *chip,
RIVA_HW_STATE *state,
* Extended RIVA registers.
*/
pixelDepth = (bpp + 1)/8;
- CalcVClock(dotClock, &VClk, &m, &n, &p, chip);
+ if (!CalcVClock(dotClock, &VClk, &m, &n, &p, chip))
+ return -EINVAL;
switch (chip->Architecture)
{
state->pitch1 =
state->pitch2 =
state->pitch3 = pixelDepth * width;
+
+ return 0;
}
/*
* Load fixed function state and pre-calculated/stored state.
*/
chip->Busy = nv3Busy;
chip->ShowHideCursor = ShowHideCursor;
- chip->CalcStateExt = CalcStateExt;
chip->LoadStateExt = LoadStateExt;
chip->UnloadStateExt = UnloadStateExt;
chip->SetStartAddress = SetStartAddress3;
*/
chip->Busy = nv4Busy;
chip->ShowHideCursor = ShowHideCursor;
- chip->CalcStateExt = CalcStateExt;
chip->LoadStateExt = LoadStateExt;
chip->UnloadStateExt = UnloadStateExt;
chip->SetStartAddress = SetStartAddress;
*/
chip->Busy = nv10Busy;
chip->ShowHideCursor = ShowHideCursor;
- chip->CalcStateExt = CalcStateExt;
chip->LoadStateExt = LoadStateExt;
chip->UnloadStateExt = UnloadStateExt;
chip->SetStartAddress = SetStartAddress;
* Common chip functions.
*/
int (*Busy)(struct _riva_hw_inst *);
- void (*CalcStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *,int,int,int,int,int);
void (*LoadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
void (*UnloadStateExt)(struct _riva_hw_inst *,struct _riva_hw_state *);
void (*SetStartAddress)(struct _riva_hw_inst *,U032);
U032 pitch2;
U032 pitch3;
} RIVA_HW_STATE;
+
+/*
+ * function prototypes
+ */
+
+extern int CalcStateExt
+(
+ RIVA_HW_INST *chip,
+ RIVA_HW_STATE *state,
+ int bpp,
+ int width,
+ int hDisplaySize,
+ int height,
+ int dotClock
+);
+
/*
* External routines.
*/
saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
saddr2>>= 1;
- saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH(var->xres);
+ saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);
dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
var->bits_per_pixel = fbi->mach_info->bpp.min;
/* set r/g/b positions */
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ var->red.offset = 0;
+ var->red.length = var->bits_per_pixel;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 8:
+ if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) {
+ /* 8 bpp 332 */
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+ } else {
+ var->red.offset = 0;
+ var->red.length = var->bits_per_pixel;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ break;
+ case 12:
+ /* 12 bpp 444 */
+ var->red.length = 4;
+ var->red.offset = 8;
+ var->green.length = 4;
+ var->green.offset = 4;
+ var->blue.length = 4;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+ break;
+
+ default:
+ case 16:
+ if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) {
+ /* 16 bpp, 565 format */
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ } else {
+ /* 16 bpp, 5551 format */
+ var->red.offset = 11;
+ var->green.offset = 6;
+ var->blue.offset = 1;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ }
+ break;
+ case 24:
+ /* 24 bpp 888 */
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+ break;
- if (var->bits_per_pixel == 16) {
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- var->transp.length = 0;
- } else {
- var->red.length = var->bits_per_pixel;
- var->red.offset = 0;
- var->green.length = var->bits_per_pixel;
- var->green.offset = 0;
- var->blue.length = var->bits_per_pixel;
- var->blue.offset = 0;
- var->transp.length = 0;
- }
+ }
return 0;
}
+
/* s3c2410fb_activate_var
*
* activate (set) the controller from the given framebuffer
static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
struct fb_var_screeninfo *var)
{
+ int hs;
+
fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
+ fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
- switch (var->bits_per_pixel) {
- case 1:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
- break;
- case 2:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
- break;
- case 4:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
- break;
- case 8:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
- break;
- case 16:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
- break;
- }
+ fbi->regs.lcdcon1 |= fbi->mach_info->type;
+
+ if (fbi->mach_info->type == S3C2410_LCDCON1_TFT)
+ switch (var->bits_per_pixel) {
+ case 1:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
+ break;
+ case 2:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
+ break;
+ case 4:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
+ break;
+ case 8:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
+ break;
+ case 16:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
+ break;
+
+ default:
+ /* invalid pixel depth */
+ dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
+ }
+ else
+ switch (var->bits_per_pixel) {
+ case 1:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
+ break;
+ case 2:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
+ break;
+ case 4:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
+ break;
+ case 8:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
+ break;
+ case 12:
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
+ break;
+
+ default:
+ /* invalid pixel depth */
+ dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
+ }
/* check to see if we need to update sync/borders */
fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
+ switch(fbi->mach_info->type) {
+ case S3C2410_LCDCON1_DSCAN4:
+ case S3C2410_LCDCON1_STN8:
+ hs = var->xres / 8;
+ break;
+ case S3C2410_LCDCON1_STN4:
+ hs = var->xres / 4;
+ break;
+ default:
+ case S3C2410_LCDCON1_TFT:
+ hs = var->xres;
+ break;
+
+ }
+
+ /* Special cases : STN color displays */
+ if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \
+ || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) {
+ hs = hs * 3;
+ }
+
+
fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff);
- fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(var->xres - 1);
+ fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1);
if (var->pixclock > 0) {
int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
- clkdiv = (clkdiv / 2) -1;
- if (clkdiv < 0)
- clkdiv = 0;
+ if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) {
+ clkdiv = (clkdiv / 2) -1;
+ if (clkdiv < 0)
+ clkdiv = 0;
+ }
+ else {
+ clkdiv = (clkdiv / 2);
+ if (clkdiv < 2)
+ clkdiv = 2;
+ }
fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff);
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
struct s3c2410fb_info *fbi = info->par;
struct fb_var_screeninfo *var = &info->var;
- if (var->bits_per_pixel == 16)
- fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
- else
- fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ switch (var->bits_per_pixel)
+ {
+ case 16:
+ fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 1:
+ fbi->fb->fix.visual = FB_VISUAL_MONO01;
+ break;
+ default:
+ fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ }
fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8;
/* try to get from firmware */
const u8 *e = fb_firmware_edid(info->device);
- if (e) {
- edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (edid)
- memcpy(edid, e, EDID_LENGTH);
- }
+ if (e)
+ edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
}
*out_edid = edid;
void
SiS_DDC2Delay(struct SiS_Private *SiS_Pr, unsigned int delaytime)
{
- unsigned int i, j;
-
- for(i = 0; i < delaytime; i++) {
- j += SiS_GetReg(SiS_Pr->SiS_P3c4,0x05);
- }
+ while (delaytime-- > 0)
+ SiS_GetReg(SiS_Pr->SiS_P3c4, 0x05);
}
#if defined(SIS300) || defined(SIS315H)
out_err2:
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
out_err0:
kfree(fb);
unregister_framebuffer(sti->info);
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ if (info->screen_base)
+ iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
kfree(info);
}
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/selection.h>
+#include <linux/bitrev.h>
#include <asm/io.h>
#include <video/tgafb.h>
static void
tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
{
- static unsigned char const bitrev[256] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
- };
-
struct tga_par *par = (struct tga_par *) info->par;
u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
unsigned long rincr, line_length, shift, pos, is8bpp;
/* The image data is bit big endian; we need
little endian. */
for (j = 0; j < bwidth; ++j)
- mask |= bitrev[data[j]] << (j * 8);
+ mask |= bitrev8(data[j]) << (j * 8);
__raw_writel(mask << shift, fb_base + pos);
for (i = 0; i < height; ++i) {
for (j = 0; j < bwidth; j += 4) {
u32 mask = 0;
- mask |= bitrev[data[j+0]] << (0 * 8);
- mask |= bitrev[data[j+1]] << (1 * 8);
- mask |= bitrev[data[j+2]] << (2 * 8);
- mask |= bitrev[data[j+3]] << (3 * 8);
+ mask |= bitrev8(data[j+0]) << (0 * 8);
+ mask |= bitrev8(data[j+1]) << (1 * 8);
+ mask |= bitrev8(data[j+2]) << (2 * 8);
+ mask |= bitrev8(data[j+3]) << (3 * 8);
__raw_writel(mask, fb_base + pos + j*bincr);
}
pos += line_length;
for (i = 0; i < height; ++i) {
u32 mask = 0;
for (j = 0; j < bwidth; ++j)
- mask |= bitrev[data[j]] << (j * 8);
+ mask |= bitrev8(data[j]) << (j * 8);
__raw_writel(mask, fb_base + pos);
pos += line_length;
data += rincr;
for (i = 0; i < height; ++i) {
for (j = 0; j < bwidth; j += 2) {
u32 mask = 0;
- mask |= bitrev[data[j+0]] << (0 * 8);
- mask |= bitrev[data[j+1]] << (1 * 8);
+ mask |= bitrev8(data[j+0]) << (0 * 8);
+ mask |= bitrev8(data[j+1]) << (1 * 8);
mask <<= shift;
__raw_writel(mask, fb_base + pos + j*bincr);
}
bwidth = (width & 15) > 8;
for (i = 0; i < height; ++i) {
- u32 mask = bitrev[data[0]];
+ u32 mask = bitrev8(data[0]);
if (bwidth)
- mask |= bitrev[data[1]] << 8;
+ mask |= bitrev8(data[1]) << 8;
mask <<= shift;
__raw_writel(mask, fb_base + pos);
pos += line_length;
return 0;
err1:
+ if (mem_base)
+ iounmap(mem_base);
release_mem_region(bar0_start, bar0_len);
err0:
kfree(all);
if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
debug("request_mem_region failed!\n");
- return -1;
+ err = -1;
+ goto out_unmap;
}
fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
if (!fb_info.screen_base) {
release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
debug("ioremap failed\n");
- return -1;
+ err = -1;
+ goto out_unmap;
}
output("%s board found\n", pci_name(dev));
#endif
fb_info.pseudo_palette = pseudo_pal;
- if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp))
- return -EINVAL;
+ if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) {
+ err = -EINVAL;
+ goto out_unmap;
+ }
fb_alloc_cmap(&fb_info.cmap,256,0);
if (defaultaccel && acc)
default_var.accel_flags |= FB_ACCELF_TEXT;
fb_info.device = &dev->dev;
if (register_framebuffer(&fb_info) < 0) {
printk(KERN_ERR "tridentfb: could not register Trident framebuffer\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto out_unmap;
}
output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
fb_info.node, fb_info.fix.id,default_var.xres,
default_var.yres,default_var.bits_per_pixel);
return 0;
+
+out_unmap:
+ if (default_par.io_virt)
+ iounmap(default_par.io_virt);
+ if (fb_info.screen_base)
+ iounmap(fb_info.screen_base);
+ return err;
}
static void __devexit trident_pci_remove(struct pci_dev * dev)
.accel = FB_ACCEL_NONE,
};
-static int inverse = 0;
-static int mtrr = 0; /* disable mtrr */
-static int vram_remap __initdata = 0; /* Set amount of memory to be used */
-static int vram_total __initdata = 0; /* Set total amount of memory */
-static int pmi_setpal = 1; /* pmi for palette changes ??? */
-static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */
-static unsigned short *pmi_base = NULL;
-static void (*pmi_start)(void);
-static void (*pmi_pal)(void);
-static int depth;
-static int vga_compat;
+static int inverse __read_mostly;
+static int mtrr __read_mostly; /* disable mtrr */
+static int vram_remap __initdata; /* Set amount of memory to be used */
+static int vram_total __initdata; /* Set total amount of memory */
+static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */
+static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */
+static void (*pmi_start)(void) __read_mostly;
+static void (*pmi_pal) (void) __read_mostly;
+static int depth __read_mostly;
+static int vga_compat __read_mostly;
/* --------------------------------------------------------------------- */
static int vesafb_pan_display(struct fb_var_screeninfo *var,
ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
if (ypan || pmi_setpal) {
+ unsigned short *pmi_base;
pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
info->node, info->fix.id);
return 0;
err:
+ if (info->screen_base)
+ iounmap(info->screen_base);
framebuffer_release(info);
release_mem_region(vesafb_fix.smem_start, size_total);
return err;
const struct fb_info *info,
int mul, int div)
{
- static struct {
+ static const struct {
u32 pixclock;
u8 misc;
u8 seq_clock_mode;
static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
{
- static unsigned char map[] = { 000, 001, 010, 011 };
+ static const unsigned char map[] = { 000, 001, 010, 011 };
int val;
if (regno >= 16)
}
}
-#ifdef __LITTLE_ENDIAN
-static unsigned int transl_l[] =
-{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
-static unsigned int transl_h[] =
-{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
- 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
-#else
-#ifdef __BIG_ENDIAN
-static unsigned int transl_h[] =
-{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
-static unsigned int transl_l[] =
-{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
- 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
+#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
+#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
+ 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
+
+#if defined(__LITTLE_ENDIAN)
+static const u16 transl_l[] = TRANS_MASK_LOW;
+static const u16 transl_h[] = TRANS_MASK_HIGH;
+#elif defined(__BIG_ENDIAN)
+static const u16 transl_l[] = TRANS_MASK_HIGH;
+static const u16 transl_h[] = TRANS_MASK_LOW;
#else
#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
#endif
-#endif
static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
{
#warning release resources
printk(KERN_ERR "virgefb.c: register_framebuffer failed\n");
DPRINTK("EXIT\n");
- return -EINVAL;
+ goto out_unmap;
}
printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n",
DPRINTK("EXIT\n");
return 0;
+
+out_unmap:
+ if (board_addr >= 0x01000000) {
+ if (v_ram)
+ iounmap((void*)v_ram);
+ if (vgaio_regs)
+ iounmap(vgaio_regs);
+ if (mmio_regs)
+ iounmap(mmio_regs);
+ if (vcode_switch_base)
+ iounmap((void*)vcode_switch_base);
+ v_ram = vcode_switch_base = 0;
+ vgaio_regs = mmio_regs = NULL;
+ }
+ return -EINVAL;
}
static ssize_t
proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct inode *ino = file->f_dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
struct proc_dir_entry *dp = PDE(ino);
struct zorro_dev *z = dp->data;
struct ConfigDev cd;
int retval = -EIO;
loff_t offset = page_offset(page);
int count = PAGE_CACHE_SIZE;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
int rsize = v9ses->maxdata - V9FS_IOHDRSZ;
struct v9fs_fid *v9f = filp->private_data;
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct v9fs_fcall *fcall = NULL;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *file = filp->private_data;
unsigned int i, n, s;
struct v9fs_stat stat;
int over = 0;
- dprintk(DEBUG_VFS, "name %s\n", filp->f_dentry->d_name.name);
+ dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = file->fid;
dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
- vfid = v9fs_fid_lookup(file->f_dentry);
+ vfid = v9fs_fid_lookup(file->f_path.dentry);
if (!vfid) {
dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
return -EBADF;
static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
{
int res = 0;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
v9fs_file_read(struct file *filp, char __user * data, size_t count,
loff_t * offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *v9f = filp->private_data;
struct v9fs_fcall *fcall = NULL;
v9fs_file_write(struct file *filp, const char __user * data,
size_t count, loff_t * offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct v9fs_fid *v9fid = filp->private_data;
struct v9fs_fcall *fcall;
ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
- pnode.o drop_caches.o splice.o sync.o utimes.o
+ pnode.o drop_caches.o splice.o sync.o utimes.o \
+ stack.o
ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
static int
adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
struct object_info obj;
static int
affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
struct buffer_head *dir_bh;
struct buffer_head *fh_bh;
stored++;
}
if (f_pos == 1) {
- if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0)
+ if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_path.dentry), DT_DIR) < 0)
return stored;
filp->f_pos = f_pos = 2;
stored++;
unsigned fpos;
int ret;
- _enter("{%Ld,{%lu}}", file->f_pos, file->f_dentry->d_inode->i_ino);
+ _enter("{%Ld,{%lu}}", file->f_pos, file->f_path.dentry->d_inode->i_ino);
fpos = file->f_pos;
- ret = afs_dir_iterate(file->f_dentry->d_inode, &fpos, cookie, filldir);
+ ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, cookie, filldir);
file->f_pos = fpos;
_leave(" = %d", ret);
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include "super.h"
#include "cell.h"
#include "volume.h"
{
kenter("%p,%p{%p{%s},%s}",
inode, file,
- file->f_dentry->d_parent,
- file->f_dentry->d_parent ?
- file->f_dentry->d_parent->d_name.name :
+ file->f_path.dentry->d_parent,
+ file->f_path.dentry->d_parent ?
+ file->f_path.dentry->d_parent->d_name.name :
(const unsigned char *) "",
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
return -EREMOTE;
} /* end afs_mntpt_open() */
struct autofs_dir_ent *ent = NULL;
struct autofs_dirhash *dirhash;
struct autofs_sb_info *sbi;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
off_t onr, nr;
lock_kernel();
case AUTOFS_IOC_SETTIMEOUT:
return autofs_get_set_timeout(sbi, argp);
case AUTOFS_IOC_EXPIRE:
- return autofs_expire_run(inode->i_sb, sbi, filp->f_vfsmnt,
+ return autofs_expire_run(inode->i_sb, sbi, filp->f_path.mnt,
argp);
default:
return -ENOSYS;
static inline void autofs4_copy_atime(struct file *src, struct file *dst)
{
- dst->f_dentry->d_inode->i_atime = src->f_dentry->d_inode->i_atime;
+ dst->f_path.dentry->d_inode->i_atime =
+ src->f_path.dentry->d_inode->i_atime;
return;
}
static int autofs4_root_readdir(struct file *file, void *dirent,
filldir_t filldir)
{
- struct autofs_sb_info *sbi = autofs4_sbi(file->f_dentry->d_sb);
+ struct autofs_sb_info *sbi = autofs4_sbi(file->f_path.dentry->d_sb);
int oz_mode = autofs4_oz_mode(sbi);
DPRINTK("called, filp->f_pos = %lld", file->f_pos);
static int autofs4_dir_open(struct inode *inode, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
- struct vfsmount *mnt = file->f_vfsmnt;
+ struct dentry *dentry = file->f_path.dentry;
+ struct vfsmount *mnt = file->f_path.mnt;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct dentry *cursor;
int status;
static int autofs4_dir_close(struct inode *inode, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct dentry *cursor = file->private_data;
int status = 0;
static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct dentry *cursor = file->private_data;
int status;
return autofs4_ask_reghost(sbi, p);
case AUTOFS_IOC_ASKUMOUNT:
- return autofs4_ask_umount(filp->f_vfsmnt, p);
+ return autofs4_ask_umount(filp->f_path.mnt, p);
/* return a single thing to expire */
case AUTOFS_IOC_EXPIRE:
- return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi, p);
+ return autofs4_expire_run(inode->i_sb,filp->f_path.mnt,sbi, p);
/* same as above, but can send multiple expires through pipe */
case AUTOFS_IOC_EXPIRE_MULTI:
- return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi, p);
+ return autofs4_expire_multi(inode->i_sb,filp->f_path.mnt,sbi, p);
default:
return -ENOSYS;
static int
befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
befs_off_t value;
char keybuf[BEFS_NAME_LEN + 1];
char *nlsname;
int nlsnamelen;
- const char *dirname = filp->f_dentry->d_name.name;
+ const char *dirname = filp->f_path.dentry->d_name.name;
befs_debug(sb, "---> befs_readdir() "
"name %s, inode %ld, filp->f_pos %Ld",
static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
{
- struct inode * dir = f->f_dentry->d_inode;
+ struct inode * dir = f->f_path.dentry->d_inode;
struct buffer_head * bh;
struct bfs_dirent * de;
unsigned int offset;
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- i_size_read(bprm->file->f_dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ i_size_read(bprm->file->f_path.dentry->d_inode) < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
- bprm->file->f_dentry->d_name.name);
+ bprm->file->f_path.dentry->d_name.name);
error_time = jiffies;
}
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
{
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert library: %s\n",
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
error_time = jiffies;
}
down_write(¤t->mm->mmap_sem);
/* Dump shared memory only if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED)
- return vma->vm_file->f_dentry->d_inode->i_nlink == 0;
+ return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0;
/* If it hasn't been written to, don't write it out */
if (!vma->anon_vma)
prstatus->pr_pid = p->pid;
prstatus->pr_ppid = p->parent->pid;
prstatus->pr_pgrp = process_group(p);
- prstatus->pr_sid = p->signal->session;
+ prstatus->pr_sid = process_session(p);
if (thread_group_leader(p)) {
/*
* This is the record for the group leader. Add in the
psinfo->pr_pid = p->pid;
psinfo->pr_ppid = p->parent->pid;
psinfo->pr_pgrp = process_group(p);
- psinfo->pr_sid = p->signal->session;
+ psinfo->pr_sid = process_session(p);
i = p->state ? ffz(~p->state) + 1 : 0;
psinfo->pr_state = i;
dynamic_error:
printk("ELF FDPIC %s with invalid DYNAMIC section (inode=%lu)\n",
- what, file->f_dentry->d_inode->i_ino);
+ what, file->f_path.dentry->d_inode->i_ino);
return -ELIBBAD;
}
/* Dump shared memory only if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED) {
- if (vma->vm_file->f_dentry->d_inode->i_nlink == 0) {
+ if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) {
kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags);
return 1;
}
prstatus->pr_pid = p->pid;
prstatus->pr_ppid = p->parent->pid;
prstatus->pr_pgrp = process_group(p);
- prstatus->pr_sid = p->signal->session;
+ prstatus->pr_sid = process_session(p);
if (thread_group_leader(p)) {
/*
* This is the record for the group leader. Add in the
psinfo->pr_pid = p->pid;
psinfo->pr_ppid = p->parent->pid;
psinfo->pr_pgrp = process_group(p);
- psinfo->pr_sid = p->signal->session;
+ psinfo->pr_sid = process_session(p);
i = p->state ? ffz(~p->state) + 1 : 0;
psinfo->pr_state = i;
int ret;
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
- inode = bprm->file->f_dentry->d_inode;
+ inode = bprm->file->f_path.dentry->d_inode;
text_len = ntohl(hdr->data_start);
data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start);
static ssize_t
bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
{
- Node *e = file->f_dentry->d_inode->i_private;
+ Node *e = file->f_path.dentry->d_inode->i_private;
loff_t pos = *ppos;
ssize_t res;
char *page;
size_t count, loff_t *ppos)
{
struct dentry *root;
- Node *e = file->f_dentry->d_inode->i_private;
+ Node *e = file->f_path.dentry->d_inode->i_private;
int res = parse_command(buffer, count);
switch (res) {
break;
case 2: set_bit(Enabled, &e->flags);
break;
- case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
+ case 3: root = dget(file->f_path.mnt->mnt_sb->s_root);
mutex_lock(&root->d_inode->i_mutex);
kill_node(e);
Node *e;
struct inode *inode;
struct dentry *root, *dentry;
- struct super_block *sb = file->f_vfsmnt->mnt_sb;
+ struct super_block *sb = file->f_path.mnt->mnt_sb;
int err = 0;
e = create_entry(buffer, count);
switch (res) {
case 1: enabled = 0; break;
case 2: enabled = 1; break;
- case 3: root = dget(file->f_vfsmnt->mnt_sb->s_root);
+ case 3: root = dget(file->f_path.mnt->mnt_sb->s_root);
mutex_lock(&root->d_inode->i_mutex);
while (!list_empty(&entries))
/*
* private llseek:
- * for a block special file file->f_dentry->d_inode->i_size is zero
+ * for a block special file file->f_path.dentry->d_inode->i_size is zero
* so we compute the size by hand (just as in block_read/write above)
*/
static loff_t block_llseek(struct file *file, loff_t offset, int origin)
if (!bo)
return -ENOMEM;
- mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION);
+ mutex_lock(&bdev->bd_mutex);
res = bd_claim(bdev, holder);
if (res == 0) {
found = find_bd_holder(bdev, bo);
if (!kobj)
return;
- mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION);
+ mutex_lock(&bdev->bd_mutex);
bd_release(bdev);
if ((bo = del_bd_holder(bdev, kobj)))
free_bd_holder(bo);
EXPORT_SYMBOL(open_by_devnum);
-static int
-blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags);
-
-struct block_device *open_partition_by_devnum(dev_t dev, unsigned mode)
-{
- struct block_device *bdev = bdget(dev);
- int err = -ENOMEM;
- int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY;
- if (bdev)
- err = blkdev_get_partition(bdev, mode, flags);
- return err ? ERR_PTR(err) : bdev;
-}
-
-EXPORT_SYMBOL(open_partition_by_devnum);
-
-
/*
* This routine checks whether a removable media has been changed,
* and invalidates all buffer-cache-entries in that case. This
}
EXPORT_SYMBOL(bd_set_size);
-static int __blkdev_put(struct block_device *bdev, unsigned int subclass)
-{
- int ret = 0;
- struct inode *bd_inode = bdev->bd_inode;
- struct gendisk *disk = bdev->bd_disk;
-
- mutex_lock_nested(&bdev->bd_mutex, subclass);
- lock_kernel();
- if (!--bdev->bd_openers) {
- sync_blockdev(bdev);
- kill_bdev(bdev);
- }
- if (bdev->bd_contains == bdev) {
- if (disk->fops->release)
- ret = disk->fops->release(bd_inode, NULL);
- } else {
- mutex_lock_nested(&bdev->bd_contains->bd_mutex,
- subclass + 1);
- bdev->bd_contains->bd_part_count--;
- mutex_unlock(&bdev->bd_contains->bd_mutex);
- }
- if (!bdev->bd_openers) {
- struct module *owner = disk->fops->owner;
-
- put_disk(disk);
- module_put(owner);
-
- if (bdev->bd_contains != bdev) {
- kobject_put(&bdev->bd_part->kobj);
- bdev->bd_part = NULL;
- }
- bdev->bd_disk = NULL;
- bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
- if (bdev != bdev->bd_contains)
- __blkdev_put(bdev->bd_contains, subclass + 1);
- bdev->bd_contains = NULL;
- }
- unlock_kernel();
- mutex_unlock(&bdev->bd_mutex);
- bdput(bdev);
- return ret;
-}
-
-int blkdev_put(struct block_device *bdev)
-{
- return __blkdev_put(bdev, BD_MUTEX_NORMAL);
-}
-EXPORT_SYMBOL(blkdev_put);
-
-int blkdev_put_partition(struct block_device *bdev)
-{
- return __blkdev_put(bdev, BD_MUTEX_PARTITION);
-}
-EXPORT_SYMBOL(blkdev_put_partition);
+static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
+ int for_part);
+static int __blkdev_put(struct block_device *bdev, int for_part);
-static int
-blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags);
-
-static int
-do_open(struct block_device *bdev, struct file *file, unsigned int subclass)
+static int do_open(struct block_device *bdev, struct file *file, int for_part)
{
struct module *owner = NULL;
struct gendisk *disk;
}
owner = disk->fops->owner;
- mutex_lock_nested(&bdev->bd_mutex, subclass);
-
+ mutex_lock_nested(&bdev->bd_mutex, for_part);
if (!bdev->bd_openers) {
bdev->bd_disk = disk;
bdev->bd_contains = bdev;
ret = -ENOMEM;
if (!whole)
goto out_first;
- ret = blkdev_get_whole(whole, file->f_mode, file->f_flags);
+ BUG_ON(for_part);
+ ret = __blkdev_get(whole, file->f_mode, file->f_flags, 1);
if (ret)
goto out_first;
bdev->bd_contains = whole;
- mutex_lock_nested(&whole->bd_mutex, BD_MUTEX_WHOLE);
- whole->bd_part_count++;
p = disk->part[part - 1];
bdev->bd_inode->i_data.backing_dev_info =
whole->bd_inode->i_data.backing_dev_info;
if (!(disk->flags & GENHD_FL_UP) || !p || !p->nr_sects) {
- whole->bd_part_count--;
- mutex_unlock(&whole->bd_mutex);
ret = -ENXIO;
goto out_first;
}
kobject_get(&p->kobj);
bdev->bd_part = p;
bd_set_size(bdev, (loff_t) p->nr_sects << 9);
- mutex_unlock(&whole->bd_mutex);
}
} else {
put_disk(disk);
}
if (bdev->bd_invalidated)
rescan_partitions(bdev->bd_disk, bdev);
- } else {
- mutex_lock_nested(&bdev->bd_contains->bd_mutex,
- BD_MUTEX_WHOLE);
- bdev->bd_contains->bd_part_count++;
- mutex_unlock(&bdev->bd_contains->bd_mutex);
}
}
bdev->bd_openers++;
+ if (for_part)
+ bdev->bd_part_count++;
mutex_unlock(&bdev->bd_mutex);
unlock_kernel();
return 0;
bdev->bd_disk = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains)
- __blkdev_put(bdev->bd_contains, BD_MUTEX_WHOLE);
+ __blkdev_put(bdev->bd_contains, 1);
bdev->bd_contains = NULL;
put_disk(disk);
module_put(owner);
return ret;
}
-int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags)
+static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
+ int for_part)
{
/*
* This crockload is due to bad choice of ->open() type.
struct dentry fake_dentry = {};
fake_file.f_mode = mode;
fake_file.f_flags = flags;
- fake_file.f_dentry = &fake_dentry;
+ fake_file.f_path.dentry = &fake_dentry;
fake_dentry.d_inode = bdev->bd_inode;
- return do_open(bdev, &fake_file, BD_MUTEX_NORMAL);
+ return do_open(bdev, &fake_file, for_part);
}
-EXPORT_SYMBOL(blkdev_get);
-
-static int
-blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags)
-{
- /*
- * This crockload is due to bad choice of ->open() type.
- * It will go away.
- * For now, block device ->open() routine must _not_
- * examine anything in 'inode' argument except ->i_rdev.
- */
- struct file fake_file = {};
- struct dentry fake_dentry = {};
- fake_file.f_mode = mode;
- fake_file.f_flags = flags;
- fake_file.f_dentry = &fake_dentry;
- fake_dentry.d_inode = bdev->bd_inode;
-
- return do_open(bdev, &fake_file, BD_MUTEX_WHOLE);
-}
-
-static int
-blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags)
+int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags)
{
- /*
- * This crockload is due to bad choice of ->open() type.
- * It will go away.
- * For now, block device ->open() routine must _not_
- * examine anything in 'inode' argument except ->i_rdev.
- */
- struct file fake_file = {};
- struct dentry fake_dentry = {};
- fake_file.f_mode = mode;
- fake_file.f_flags = flags;
- fake_file.f_dentry = &fake_dentry;
- fake_dentry.d_inode = bdev->bd_inode;
-
- return do_open(bdev, &fake_file, BD_MUTEX_PARTITION);
+ return __blkdev_get(bdev, mode, flags, 0);
}
+EXPORT_SYMBOL(blkdev_get);
static int blkdev_open(struct inode * inode, struct file * filp)
{
if (bdev == NULL)
return -ENOMEM;
- res = do_open(bdev, filp, BD_MUTEX_NORMAL);
+ res = do_open(bdev, filp, 0);
if (res)
return res;
return res;
}
+static int __blkdev_put(struct block_device *bdev, int for_part)
+{
+ int ret = 0;
+ struct inode *bd_inode = bdev->bd_inode;
+ struct gendisk *disk = bdev->bd_disk;
+ struct block_device *victim = NULL;
+
+ mutex_lock_nested(&bdev->bd_mutex, for_part);
+ lock_kernel();
+ if (for_part)
+ bdev->bd_part_count--;
+
+ if (!--bdev->bd_openers) {
+ sync_blockdev(bdev);
+ kill_bdev(bdev);
+ }
+ if (bdev->bd_contains == bdev) {
+ if (disk->fops->release)
+ ret = disk->fops->release(bd_inode, NULL);
+ }
+ if (!bdev->bd_openers) {
+ struct module *owner = disk->fops->owner;
+
+ put_disk(disk);
+ module_put(owner);
+
+ if (bdev->bd_contains != bdev) {
+ kobject_put(&bdev->bd_part->kobj);
+ bdev->bd_part = NULL;
+ }
+ bdev->bd_disk = NULL;
+ bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
+ if (bdev != bdev->bd_contains)
+ victim = bdev->bd_contains;
+ bdev->bd_contains = NULL;
+ }
+ unlock_kernel();
+ mutex_unlock(&bdev->bd_mutex);
+ bdput(bdev);
+ if (victim)
+ __blkdev_put(victim, 1);
+ return ret;
+}
+
+int blkdev_put(struct block_device *bdev)
+{
+ return __blkdev_put(bdev, 0);
+}
+EXPORT_SYMBOL(blkdev_put);
+
static int blkdev_close(struct inode * inode, struct file * filp)
{
struct block_device *bdev = I_BDEV(filp->f_mapping->host);
static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
ssize_t written;
written = generic_file_aio_write(iocb, iov, nr_segs, pos);
{
/* origin == SEEK_END => we must revalidate the cached file length */
if (origin == SEEK_END) {
- int retval = cifs_revalidate(file->f_dentry);
+ int retval = cifs_revalidate(file->f_path.dentry);
if (retval < 0)
return (loff_t)retval;
}
return 0;
xid = GetXid();
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if(full_path == NULL) {
rc = -ENOMEM;
/* if not oplocked, invalidate inode pages if mtime or file
size changed */
temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
- if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
- (file->f_dentry->d_inode->i_size ==
+ if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
+ (file->f_path.dentry->d_inode->i_size ==
(loff_t)le64_to_cpu(buf->EndOfFile))) {
cFYI(1, ("inode unchanged on server"));
} else {
- if (file->f_dentry->d_inode->i_mapping) {
+ if (file->f_path.dentry->d_inode->i_mapping) {
/* BB no need to lock inode until after invalidate
since namei code should already have it locked? */
- filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
+ filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
}
cFYI(1, ("invalidating remote inode since open detected it "
"changed"));
- invalidate_remote_inode(file->f_dentry->d_inode);
+ invalidate_remote_inode(file->f_path.dentry->d_inode);
}
client_can_cache:
if (pTcon->ses->capabilities & CAP_UNIX)
- rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
+ rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
full_path, inode->i_sb, xid);
else
- rc = cifs_get_inode_info(&file->f_dentry->d_inode,
+ rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
full_path, buf, inode->i_sb, xid);
if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
cFYI(1, ("Exclusive Oplock granted on inode %p",
- file->f_dentry->d_inode));
+ file->f_path.dentry->d_inode));
} else if ((*oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = TRUE;
if (file->f_flags & O_CREAT) {
/* search inode for this file and fill in file->private_data */
- pCifsInode = CIFS_I(file->f_dentry->d_inode);
+ pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &pCifsInode->openFileList) {
pCifsFile = list_entry(tmp, struct cifsFileInfo,
}
}
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &pTcon->openFileList);
- pCifsInode = CIFS_I(file->f_dentry->d_inode);
+ pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
if (pCifsInode) {
rc = cifs_open_inode_helper(inode, file, pCifsInode,
pCifsFile, pTcon,
return 0;
}
- if (file->f_dentry == NULL) {
+ if (file->f_path.dentry == NULL) {
up(&pCifsFile->fh_sem);
cFYI(1, ("failed file reopen, no valid name if dentry freed"));
FreeXid(xid);
those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
up(&pCifsFile->fh_sem);
FreeXid(xid);
pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE;
cFYI(1, ("Exclusive Oplock granted on inode %p",
- file->f_dentry->d_inode));
+ file->f_path.dentry->d_inode));
} else if ((oplock & 0xF) == OPLOCK_READ) {
pCifsInode->clientCanCacheRead = TRUE;
pCifsInode->clientCanCacheAll = FALSE;
if (pCFileStruct) {
struct cifsTconInfo *pTcon;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
} else
cFYI(1, ("Unknown type of lock"));
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (file->private_data == NULL) {
int xid, long_op;
struct cifsFileInfo *open_file;
- if (file->f_dentry == NULL)
+ if (file->f_path.dentry == NULL)
return -EBADF;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (cifs_sb == NULL)
return -EBADF;
/* cFYI(1,
(" write %d bytes to offset %lld of %s", write_size,
- *poffset, file->f_dentry->d_name.name)); */
+ *poffset, file->f_path.dentry->d_name.name)); */
if (file->private_data == NULL)
return -EBADF;
open_file = (struct cifsFileInfo *) file->private_data;
xid = GetXid();
- if (file->f_dentry->d_inode == NULL) {
+ if (file->f_path.dentry->d_inode == NULL) {
FreeXid(xid);
return -EBADF;
}
- if (*poffset > file->f_dentry->d_inode->i_size)
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */
else
long_op = 1;
return -EBADF;
}
if (open_file->invalidHandle) {
- if ((file->f_dentry == NULL) ||
- (file->f_dentry->d_inode == NULL)) {
+ if ((file->f_path.dentry == NULL) ||
+ (file->f_path.dentry->d_inode == NULL)) {
FreeXid(xid);
return total_written;
}
filemap_fdatawait from here so tell
reopen_file not to flush data to server
now */
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, FALSE);
if (rc != 0)
break;
cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
- if (file->f_dentry) {
- if (file->f_dentry->d_inode) {
- struct inode *inode = file->f_dentry->d_inode;
+ if (file->f_path.dentry) {
+ if (file->f_path.dentry->d_inode) {
+ struct inode *inode = file->f_path.dentry->d_inode;
inode->i_ctime = inode->i_mtime =
current_fs_time(inode->i_sb);
if (total_written > 0) {
- if (*poffset > file->f_dentry->d_inode->i_size)
- i_size_write(file->f_dentry->d_inode,
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
+ i_size_write(file->f_path.dentry->d_inode,
*poffset);
}
- mark_inode_dirty_sync(file->f_dentry->d_inode);
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
}
FreeXid(xid);
int xid, long_op;
struct cifsFileInfo *open_file;
- if (file->f_dentry == NULL)
+ if (file->f_path.dentry == NULL)
return -EBADF;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (cifs_sb == NULL)
return -EBADF;
pTcon = cifs_sb->tcon;
cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
- *poffset, file->f_dentry->d_name.name));
+ *poffset, file->f_path.dentry->d_name.name));
if (file->private_data == NULL)
return -EBADF;
open_file = (struct cifsFileInfo *)file->private_data;
xid = GetXid();
- if (file->f_dentry->d_inode == NULL) {
+ if (file->f_path.dentry->d_inode == NULL) {
FreeXid(xid);
return -EBADF;
}
- if (*poffset > file->f_dentry->d_inode->i_size)
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */
else
long_op = 1;
return -EBADF;
}
if (open_file->invalidHandle) {
- if ((file->f_dentry == NULL) ||
- (file->f_dentry->d_inode == NULL)) {
+ if ((file->f_path.dentry == NULL) ||
+ (file->f_path.dentry->d_inode == NULL)) {
FreeXid(xid);
return total_written;
}
filemap_fdatawait from here so tell
reopen_file not to flush data to
server now */
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, FALSE);
if (rc != 0)
break;
cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */
- if (file->f_dentry) {
- if (file->f_dentry->d_inode) {
- file->f_dentry->d_inode->i_ctime =
- file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+ if (file->f_path.dentry) {
+ if (file->f_path.dentry->d_inode) {
+ file->f_path.dentry->d_inode->i_ctime =
+ file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;
if (total_written > 0) {
- if (*poffset > file->f_dentry->d_inode->i_size)
- i_size_write(file->f_dentry->d_inode,
+ if (*poffset > file->f_path.dentry->d_inode->i_size)
+ i_size_write(file->f_path.dentry->d_inode,
*poffset);
}
- mark_inode_dirty_sync(file->f_dentry->d_inode);
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
}
FreeXid(xid);
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
rc = cifs_reopen_file(
- file->f_dentry->d_inode, file);
+ file->f_path.dentry->d_inode, file);
if (rc != 0)
break;
}
{
int xid;
int rc = 0;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
xid = GetXid();
*/
int cifs_flush(struct file *file, fl_owner_t id)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
int rc = 0;
/* Rather than do the steps manually:
struct smb_com_read_rsp *pSMBr;
xid = GetXid();
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (file->private_data == NULL) {
int buf_type = CIFS_NO_BUFFER;
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, TRUE);
if (rc != 0)
break;
int buf_type = CIFS_NO_BUFFER;
xid = GetXid();
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (file->private_data == NULL) {
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, TRUE);
if (rc != 0)
break;
int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int rc, xid;
xid = GetXid();
return -EBADF;
}
open_file = (struct cifsFileInfo *)file->private_data;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
pagevec_init(&lru_pvec, 0);
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_dentry->d_inode,
+ rc = cifs_reopen_file(file->f_path.dentry->d_inode,
file, TRUE);
if (rc != 0)
break;
else
cFYI(1, ("Bytes read %d",rc));
- file->f_dentry->d_inode->i_atime =
- current_fs_time(file->f_dentry->d_inode->i_sb);
+ file->f_path.dentry->d_inode->i_atime =
+ current_fs_time(file->f_path.dentry->d_inode->i_sb);
if (PAGE_CACHE_SIZE > rc)
memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
int rc = 0;
cFYI(1, ("For %s", qstring->name));
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
qstring->hash = full_name_hash(qstring->name, qstring->len);
- tmp_dentry = d_lookup(file->f_dentry, qstring);
+ tmp_dentry = d_lookup(file->f_path.dentry, qstring);
if (tmp_dentry) {
cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if(*ptmp_inode == NULL) {
- *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
if(*ptmp_inode == NULL)
return rc;
rc = 1;
}
} else {
- tmp_dentry = d_alloc(file->f_dentry, qstring);
+ tmp_dentry = d_alloc(file->f_path.dentry, qstring);
if(tmp_dentry == NULL) {
cERROR(1,("Failed allocating dentry"));
*ptmp_inode = NULL;
return rc;
}
- *ptmp_inode = new_inode(file->f_dentry->d_sb);
+ *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
if (pTcon->nocase)
tmp_dentry->d_op = &cifs_ci_dentry_ops;
else
cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return -ENOENT;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if(cifs_sb == NULL)
return -EINVAL;
if(pTcon == NULL)
return -EINVAL;
- full_path = build_path_from_dentry(file->f_dentry);
+ full_path = build_path_from_dentry(file->f_path.dentry);
if(full_path == NULL) {
return -ENOMEM;
struct inode * inode;
struct cifsInodeInfo *cifsInfo;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return 0;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if(inode == NULL)
return 0;
if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
return -ENOENT;
- if(file->f_dentry == NULL)
+ if(file->f_path.dentry == NULL)
return -ENOENT;
rc = cifs_entry_is_dot(pfindEntry,pCifsF);
if(rc != 0)
return 0;
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
qstring.name = scratch_buf;
rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
xid = GetXid();
- if(file->f_dentry == NULL) {
+ if(file->f_path.dentry == NULL) {
FreeXid(xid);
return -EIO;
}
- cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+ cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if(pTcon == NULL)
return -EINVAL;
switch ((int) file->f_pos) {
case 0:
if (filldir(direntry, ".", 1, file->f_pos,
- file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
+ file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for current dir failed"));
rc = -ENOMEM;
break;
file->f_pos++;
case 1:
if (filldir(direntry, "..", 2, file->f_pos,
- file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+ file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for parent dir failed"));
rc = -ENOMEM;
break;
/* file operations for directories */
int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
{
- struct dentry *coda_dentry = coda_file->f_dentry;
+ struct dentry *coda_dentry = coda_file->f_path.dentry;
struct coda_file_info *cfi;
struct file *host_file;
struct inode *host_inode;
coda_vfs_stat.readdir++;
- host_inode = host_file->f_dentry->d_inode;
+ host_inode = host_file->f_path.dentry->d_inode;
mutex_lock(&host_inode->i_mutex);
host_file->f_pos = coda_file->f_pos;
/* catch truncated reads */
if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
printk("coda_venus_readdir: short read: %ld\n",
- filp->f_dentry->d_inode->i_ino);
+ filp->f_path.dentry->d_inode->i_ino);
ret = -EBADF;
break;
}
/* validate whether the directory file actually makes sense */
if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
printk("coda_venus_readdir: Invalid dir: %ld\n",
- filp->f_dentry->d_inode->i_ino);
+ filp->f_path.dentry->d_inode->i_ino);
ret = -EBADF;
break;
}
static ssize_t
coda_file_write(struct file *coda_file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
+ struct inode *host_inode, *coda_inode = coda_file->f_path.dentry->d_inode;
struct coda_file_info *cfi;
struct file *host_file;
ssize_t ret;
if (!host_file->f_op || !host_file->f_op->write)
return -EINVAL;
- host_inode = host_file->f_dentry->d_inode;
+ host_inode = host_file->f_path.dentry->d_inode;
mutex_lock(&coda_inode->i_mutex);
ret = host_file->f_op->write(host_file, buf, count, ppos);
if (!host_file->f_op || !host_file->f_op->mmap)
return -ENODEV;
- coda_inode = coda_file->f_dentry->d_inode;
- host_inode = host_file->f_dentry->d_inode;
+ coda_inode = coda_file->f_path.dentry->d_inode;
+ host_inode = host_file->f_path.dentry->d_inode;
coda_file->f_mapping = host_file->f_mapping;
if (coda_inode->i_mapping == &coda_inode->i_data)
coda_inode->i_mapping = host_inode->i_mapping;
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
- coda_inode = coda_file->f_dentry->d_inode;
+ coda_inode = coda_file->f_path.dentry->d_inode;
err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
coda_file->f_uid);
err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
coda_flags, coda_file->f_uid);
- host_inode = cfi->cfi_container->f_dentry->d_inode;
+ host_inode = cfi->cfi_container->f_path.dentry->d_inode;
cii = ITOC(coda_inode);
/* did we mmap this file? */
coda_vfs_stat.fsync++;
if (host_file->f_op && host_file->f_op->fsync) {
- host_dentry = host_file->f_dentry;
+ host_dentry = host_file->f_path.dentry;
host_inode = host_dentry->d_inode;
mutex_lock(&host_inode->i_mutex);
err = host_file->f_op->fsync(host_file, host_dentry, datasync);
file = fget(data->fd);
inode = NULL;
if(file)
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if(!inode || !S_ISCHR(inode->i_mode) ||
imajor(inode) != CODA_PSDEV_MAJOR) {
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_dentry, &tmp);
+ error = vfs_statfs(file->f_path.dentry, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
fput(file);
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_dentry, &tmp);
+ error = vfs_statfs(file->f_path.dentry, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
fput(file);
/* find the name of the device. */
path = (char *)__get_free_page(GFP_KERNEL);
if (path) {
- fn = d_path(filp->f_dentry, filp->f_vfsmnt, path, PAGE_SIZE);
+ fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
if (IS_ERR(fn))
fn = "?";
}
case FIBMAP:
case FIGETBSZ:
case FIONREAD:
- if (S_ISREG(filp->f_dentry->d_inode->i_mode))
+ if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
break;
/*FALL THROUGH*/
goto found_handler;
}
- if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) &&
+ if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
error = siocdevprivate_ioctl(fd, cmd, arg);
} else {
if (iov != iovstack)
kfree(iov);
if ((ret + (type == READ)) > 0) {
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
if (type == READ)
fsnotify_access(dentry);
else
static int vt_check(struct file *file)
{
struct tty_struct *tty;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (file->f_op->ioctl != tty_ioctl)
return -EINVAL;
static int configfs_dir_open(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct configfs_dirent * parent_sd = dentry->d_fsdata;
mutex_lock(&dentry->d_inode->i_mutex);
static int configfs_dir_close(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct configfs_dirent * cursor = file->private_data;
mutex_lock(&dentry->d_inode->i_mutex);
static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct configfs_dirent * parent_sd = dentry->d_fsdata;
struct configfs_dirent *cursor = filp->private_data;
struct list_head *p, *q = &cursor->s_sibling;
static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
mutex_lock(&dentry->d_inode->i_mutex);
switch (origin) {
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
down(&buffer->sem);
if (buffer->needs_read_fill) {
- if ((retval = fill_read_buffer(file->f_dentry,buffer)))
+ if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
down(&buffer->sem);
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
- len = flush_write_buffer(file->f_dentry, buffer, count);
+ len = flush_write_buffer(file->f_path.dentry, buffer, count);
if (len > 0)
*ppos += len;
up(&buffer->sem);
static int check_perm(struct inode * inode, struct file * file)
{
- struct config_item *item = configfs_get_config_item(file->f_dentry->d_parent);
- struct configfs_attribute * attr = to_attr(file->f_dentry);
+ struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent);
+ struct configfs_attribute * attr = to_attr(file->f_path.dentry);
struct configfs_buffer * buffer;
struct configfs_item_operations * ops = NULL;
int error = 0;
static int configfs_release(struct inode * inode, struct file * filp)
{
- struct config_item * item = to_item(filp->f_dentry->d_parent);
- struct configfs_attribute * attr = to_attr(filp->f_dentry);
+ struct config_item * item = to_item(filp->f_path.dentry->d_parent);
+ struct configfs_attribute * attr = to_attr(filp->f_path.dentry);
struct module * owner = attr->ca_owner;
struct configfs_buffer * buffer = filp->private_data;
*/
static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
char *buf;
unsigned int offset;
struct dnotify_struct **prev;
struct inode *inode;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (!S_ISDIR(inode->i_mode))
return;
spin_lock(&inode->i_lock);
}
if (!dir_notify_enable)
return -EINVAL;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (!S_ISDIR(inode->i_mode))
return -ENOTDIR;
dn = kmem_cache_alloc(dn_cache, GFP_KERNEL);
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file *filp = list_entry(p, struct file, f_u.fu_list);
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
- struct dentry *dentry = dget(filp->f_dentry);
+ struct dentry *dentry = dget(filp->f_path.dentry);
file_list_unlock();
sb->dq_op->initialize(inode, type);
dput(dentry);
static void print_warning(struct dquot *dquot, const char warntype)
{
char *msg = NULL;
+ struct tty_struct *tty;
int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B :
((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0);
return;
mutex_lock(&tty_mutex);
- if (!current->signal->tty)
+ tty = get_current_tty();
+ if (!tty)
goto out_lock;
- tty_write_message(current->signal->tty, dquot->dq_sb->s_id);
+ tty_write_message(tty, dquot->dq_sb->s_id);
if (warntype == ISOFTWARN || warntype == BSOFTWARN)
- tty_write_message(current->signal->tty, ": warning, ");
+ tty_write_message(tty, ": warning, ");
else
- tty_write_message(current->signal->tty, ": write failed, ");
- tty_write_message(current->signal->tty, quotatypes[dquot->dq_type]);
+ tty_write_message(tty, ": write failed, ");
+ tty_write_message(tty, quotatypes[dquot->dq_type]);
switch (warntype) {
case IHARDWARN:
msg = " file limit reached.\r\n";
msg = " block quota exceeded.\r\n";
break;
}
- tty_write_message(current->signal->tty, msg);
+ tty_write_message(tty, msg);
out_lock:
mutex_unlock(&tty_mutex);
}
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
struct inode *lower_inode =
ecryptfs_inode_to_lower(dentry->d_inode);
- ecryptfs_copy_attr_all(dentry->d_inode, lower_inode);
+ fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);
}
out:
return rc;
#include <keys/user-type.h>
#include <linux/fs.h>
+#include <linux/fs_stack.h>
+#include <linux/namei.h>
#include <linux/scatterlist.h>
/* Version verification for shared data structures w/ userspace */
/* dentry private data. Each dentry must keep track of a lower
* vfsmount too. */
struct ecryptfs_dentry_info {
- struct dentry *wdi_dentry;
- struct vfsmount *lower_mnt;
+ struct path lower_path;
struct ecryptfs_crypt_stat *crypt_stat;
};
static inline struct dentry *
ecryptfs_dentry_to_lower(struct dentry *dentry)
{
- return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry;
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry;
}
static inline void
ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
{
- ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry =
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry =
lower_dentry;
}
static inline struct vfsmount *
ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
{
- return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt;
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt;
}
static inline void
ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
{
- ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt =
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt =
lower_mnt;
}
const char *name, int length,
char **encoded_name);
struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
-void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src);
-void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src);
-void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src);
void ecryptfs_dump_hex(char *data, int bytes);
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
int sg_size);
#include <linux/security.h>
#include <linux/smp_lock.h>
#include <linux/compat.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
}
ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
if (expanding_file) {
- rc = ecryptfs_truncate(file->f_dentry, new_end_pos);
+ rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos);
if (rc) {
rv = rc;
ecryptfs_printk(KERN_ERR, "Error on attempt to "
if (-EIOCBQUEUED == rc)
rc = wait_on_sync_kiocb(iocb);
if (rc >= 0) {
- lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry);
- lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry);
+ lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);
+ lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);
touch_atime(lower_vfsmount, lower_dentry);
}
return rc;
lower_file = ecryptfs_file_to_lower(file);
lower_file->f_pos = file->f_pos;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
memset(&buf, 0, sizeof(buf));
buf.dirent = dirent;
- buf.dentry = file->f_dentry;
+ buf.dentry = file->f_path.dentry;
buf.filldir = filldir;
retry:
buf.filldir_called = 0;
goto retry;
file->f_pos = lower_file->f_pos;
if (rc >= 0)
- ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
+ fsstack_copy_attr_atime(inode, lower_file->f_path.dentry->d_inode);
return rc;
}
int rc = 0;
struct ecryptfs_crypt_stat *crypt_stat = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
- struct dentry *ecryptfs_dentry = file->f_dentry;
+ struct dentry *ecryptfs_dentry = file->f_path.dentry;
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup() */
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/crypto.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
static struct dentry *lock_parent(struct dentry *dentry)
dput(dir);
}
-void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src)
-{
- i_size_write(dst, i_size_read((struct inode *)src));
- dst->i_blocks = src->i_blocks;
-}
-
-void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src)
-{
- dest->i_atime = src->i_atime;
-}
-
-static void ecryptfs_copy_attr_times(struct inode *dest,
- const struct inode *src)
-{
- dest->i_atime = src->i_atime;
- dest->i_mtime = src->i_mtime;
- dest->i_ctime = src->i_ctime;
-}
-
-static void ecryptfs_copy_attr_timesizes(struct inode *dest,
- const struct inode *src)
-{
- dest->i_atime = src->i_atime;
- dest->i_mtime = src->i_mtime;
- dest->i_ctime = src->i_ctime;
- ecryptfs_copy_inode_size(dest, src);
-}
-
-void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src)
-{
- dest->i_mode = src->i_mode;
- dest->i_nlink = src->i_nlink;
- dest->i_uid = src->i_uid;
- dest->i_gid = src->i_gid;
- dest->i_rdev = src->i_rdev;
- dest->i_atime = src->i_atime;
- dest->i_mtime = src->i_mtime;
- dest->i_ctime = src->i_ctime;
- dest->i_blkbits = src->i_blkbits;
- dest->i_flags = src->i_flags;
-}
-
/**
* ecryptfs_create_underlying_file
* @lower_dir_inode: inode of the parent in the lower fs of the new file
ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
goto out_lock;
}
- ecryptfs_copy_attr_timesizes(directory_inode,
- lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
out_lock:
unlock_dir(lower_dir_dentry);
out:
struct ecryptfs_file_info tmp_file_info;
memset(&fake_file, 0, sizeof(fake_file));
- fake_file.f_dentry = ecryptfs_dentry;
+ fake_file.f_path.dentry = ecryptfs_dentry;
memset(&tmp_file_info, 0, sizeof(tmp_file_info));
ecryptfs_set_file_private(&fake_file, &tmp_file_info);
ecryptfs_set_file_lower(&fake_file, lower_file);
"d_name.name = [%s]\n", lower_dentry,
lower_dentry->d_name.name);
lower_inode = lower_dentry->d_inode;
- ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_atime(dir, lower_dir_dentry->d_inode);
BUG_ON(!atomic_read(&lower_dentry->d_count));
ecryptfs_set_dentry_private(dentry,
kmem_cache_alloc(ecryptfs_dentry_info_cache,
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
if (rc)
goto out_lock;
- ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);
old_dentry->d_inode->i_nlink =
ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
i_size_write(new_dentry->d_inode, file_size_save);
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
goto out_unlock;
}
- ecryptfs_copy_attr_times(dir, lower_dir_inode);
+ fsstack_copy_attr_times(dir, lower_dir_inode);
dentry->d_inode->i_nlink =
ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
dentry->d_inode->i_ctime = dir->i_ctime;
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
if (rc)
goto out_lock;
- ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out_lock:
unlock_dir(lower_dir_dentry);
dput(lower_dentry);
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
if (rc)
goto out;
- ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
out:
unlock_dir(lower_dir_dentry);
dput(lower_dentry);
if (!rc)
d_delete(lower_dentry);
- ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
unlock_dir(lower_dir_dentry);
if (!rc)
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
if (rc)
goto out;
- ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
out:
unlock_dir(lower_dir_dentry);
if (!dentry->d_inode)
lower_new_dir_dentry->d_inode, lower_new_dentry);
if (rc)
goto out_lock;
- ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
+ fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
if (new_dir != old_dir)
- ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+ fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL);
out_lock:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_new_dentry->d_parent);
rc = -EFAULT;
}
kfree(decoded_name);
- ecryptfs_copy_attr_atime(dentry->d_inode,
- lower_dentry->d_inode);
+ fsstack_copy_attr_atime(dentry->d_inode,
+ lower_dentry->d_inode);
}
out_free_lower_buf:
kfree(lower_buf);
* the file in the underlying filesystem so that the
* truncation has an effect there as well. */
memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));
- fake_ecryptfs_file.f_dentry = dentry;
+ fake_ecryptfs_file.f_path.dentry = dentry;
/* Released at out_free: label */
ecryptfs_set_file_private(&fake_ecryptfs_file,
kmem_cache_alloc(ecryptfs_file_info_cache,
}
rc = notify_change(lower_dentry, ia);
out:
- ecryptfs_copy_attr_all(inode, lower_inode);
+ fsstack_copy_attr_all(inode, lower_inode, NULL);
return rc;
}
#include <linux/pagemap.h>
#include <linux/key.h>
#include <linux/parser.h>
+#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
/**
d_add(dentry, inode);
else
d_instantiate(dentry, inode);
- ecryptfs_copy_attr_all(inode, lower_inode);
+ fsstack_copy_attr_all(inode, lower_inode, NULL);
/* This size will be overwritten for real files w/ headers and
* other metadata */
- ecryptfs_copy_inode_size(inode, lower_inode);
+ fsstack_copy_inode_size(inode, lower_inode);
out:
return rc;
}
struct inode *inode;
struct address_space *mapping;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
page = read_cache_page(mapping, index,
int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
{
int rc = 0;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
pgoff_t old_end_page_index = 0;
pgoff_t index = old_end_page_index;
char *lower_page_data;
const struct address_space_operations *lower_a_ops;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
lower_file = ecryptfs_file_to_lower(file);
lower_dentry = ecryptfs_dentry_to_lower(dentry);
inode = dentry->d_inode;
int rc = 0;
struct ecryptfs_crypt_stat *crypt_stat;
- BUG_ON(!(file && file->f_dentry && file->f_dentry->d_inode));
- crypt_stat =
- &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+ BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode));
+ crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
+ ->crypt_stat;
if (!crypt_stat
|| !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)
|| ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
lower_inode = ecryptfs_inode_to_lower(inode);
lower_file = ecryptfs_file_to_lower(file);
mutex_lock(&lower_inode->i_mutex);
- crypt_stat =
- &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+ crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)
+ ->crypt_stat;
if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
"crypt_stat at memory location [%p]\n", crypt_stat);
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct buffer_head *bh;
struct efs_dir *dirblock;
goto eexit_4;
dentry->d_op = &eventpollfs_dentry_operations;
d_add(dentry, inode);
- file->f_vfsmnt = mntget(eventpoll_mnt);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(eventpoll_mnt);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_pos = 0;
#include <linux/binfmts.h>
#include <linux/swap.h>
#include <linux/utsname.h>
+#include <linux/pid_namespace.h>
#include <linux/module.h>
#include <linux/namei.h>
#include <linux/proc_fs.h>
* Reparenting needs write_lock on tasklist_lock,
* so it is safe to do it under read_lock.
*/
- if (unlikely(tsk->group_leader == child_reaper))
- child_reaper = tsk;
+ if (unlikely(tsk->group_leader == child_reaper(tsk)))
+ tsk->nsproxy->pid_ns->child_reaper = tsk;
zap_other_threads(tsk);
read_unlock(&tasklist_lock);
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
- struct inode * inode = bprm->file->f_dentry->d_inode;
+ struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;
mode = inode->i_mode;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
- if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
+ if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
current->personality &= ~PER_CLEAR_ON_SETID;
0600);
if (IS_ERR(file))
goto fail_unlock;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
- if (!ispipe && d_unhashed(file->f_dentry))
+ if (!ispipe && d_unhashed(file->f_path.dentry))
goto close_fail;
/* AK: actually i see no reason to not allow this for named pipes etc.,
goto close_fail;
if (!file->f_op->write)
goto close_fail;
- if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0)
+ if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
{
loff_t pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned int offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
#ifdef CONFIG_COMPAT
long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
return 1;
}
-#define log2(n) ffz(~(n))
-
/*
* Maximal file size. There is a direct, and {,double-,triple-}indirect
* block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
sbi->s_sbh = bh;
sbi->s_mount_state = le16_to_cpu(es->s_state);
sbi->s_addr_per_block_bits =
- log2 (EXT2_ADDR_PER_BLOCK(sb));
+ ilog2 (EXT2_ADDR_PER_BLOCK(sb));
sbi->s_desc_per_block_bits =
- log2 (EXT2_DESC_PER_BLOCK(sb));
+ ilog2 (EXT2_DESC_PER_BLOCK(sb));
if (sb->s_magic != EXT2_SUPER_MAGIC)
goto cantfind_ext2;
struct ext3_dir_entry_2 *de;
struct super_block *sb;
int err;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
sb = inode->i_sb;
* We don't set the inode dirty flag since it's not
* critical that it get flushed back to the disk.
*/
- EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
+ EXT3_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
}
#endif
stored = 0;
{
struct dir_private_info *info = filp->private_data;
loff_t curr_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb;
int error;
void * dirent, filldir_t filldir)
{
struct dir_private_info *info = filp->private_data;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct fname *fname;
int ret;
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t ret;
int err;
#ifdef CONFIG_COMPAT
long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
start_minor_hash));
- dir = dir_file->f_dentry->d_inode;
+ dir = dir_file->f_path.dentry->d_inode;
if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
}
hinfo.hash = start_hash;
hinfo.minor_hash = 0;
- frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+ frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err);
if (!frame)
return err;
sb->s_flags = s_flags; /* Restore MS_RDONLY status */
}
-#define log2(n) ffz(~(n))
-
/*
* Maximal file size. There is a direct, and {,double-,triple-}indirect
* block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc);
sbi->s_sbh = bh;
sbi->s_mount_state = le16_to_cpu(es->s_state);
- sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
- sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
+ sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb));
+ sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb));
for (i=0; i < 4; i++)
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
sbi->s_def_hash_version = es->s_def_hash_version;
struct ext4_dir_entry_2 *de;
struct super_block *sb;
int err;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
sb = inode->i_sb;
* We don't set the inode dirty flag since it's not
* critical that it get flushed back to the disk.
*/
- EXT4_I(filp->f_dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL;
+ EXT4_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL;
}
#endif
stored = 0;
{
struct dir_private_info *info = filp->private_data;
loff_t curr_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb;
int error;
void * dirent, filldir_t filldir)
{
struct dir_private_info *info = filp->private_data;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct fname *fname;
int ret;
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t ret;
int err;
from, to, NULL, do_journal_get_write_access);
if (ret)
/* fatal error, just put the handle and return */
- journal_stop(handle);
+ ext4_journal_stop(handle);
}
return ret;
#ifdef CONFIG_COMPAT
long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
start_minor_hash));
- dir = dir_file->f_dentry->d_inode;
+ dir = dir_file->f_path.dentry->d_inode;
if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) {
hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
}
hinfo.hash = start_hash;
hinfo.minor_hash = 0;
- frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+ frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err);
if (!frame)
return err;
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
inum = inode->i_ino;
else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
- inum = parent_ino(filp->f_dentry);
+ inum = parent_ino(filp->f_path.dentry);
} else {
loff_t i_pos = fat_make_i_pos(sb, bh, de);
struct inode *tmp = fat_iget(sb, i_pos);
static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
}
set_fs(KERNEL_DS);
lock_kernel();
- ret = fat_dir_ioctl(file->f_dentry->d_inode, file,
+ ret = fat_dir_ioctl(file->f_path.dentry->d_inode, file,
cmd, (unsigned long) &d);
unlock_kernel();
set_fs(oldfs);
}
/* This MUST be done before doing anything irreversible... */
- err = notify_change(filp->f_dentry, &ia);
+ err = notify_change(filp->f_path.dentry, &ia);
if (err)
goto up;
static int setfl(int fd, struct file * filp, unsigned long arg)
{
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
int error = 0;
/*
*/
void fastcall __fput(struct file *file)
{
- struct dentry *dentry = file->f_dentry;
- struct vfsmount *mnt = file->f_vfsmnt;
+ struct dentry *dentry = file->f_path.dentry;
+ struct vfsmount *mnt = file->f_path.mnt;
struct inode *inode = dentry->d_inode;
might_sleep();
put_write_access(inode);
put_pid(file->f_owner.pid);
file_kill(file);
- file->f_dentry = NULL;
- file->f_vfsmnt = NULL;
+ file->f_path.dentry = NULL;
+ file->f_path.mnt = NULL;
file_free(file);
dput(dentry);
mntput(mnt);
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file *file = list_entry(p, struct file, f_u.fu_list);
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
/* File with pending delete? */
if (inode->i_nlink == 0)
static int
vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
{
- struct inode *ip = fp->f_dentry->d_inode;
+ struct inode *ip = fp->f_path.dentry->d_inode;
struct super_block *sbp = ip->i_sb;
u_long bsize = sbp->s_blocksize;
u_long page, npages, block, pblocks, nblocks, offset;
{
struct fuse_conn *fc;
mutex_lock(&fuse_mutex);
- fc = file->f_dentry->d_inode->i_private;
+ fc = file->f_path.dentry->d_inode->i_private;
if (fc)
fc = fuse_conn_get(fc);
mutex_unlock(&fuse_mutex);
int err;
size_t nbytes;
struct page *page;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
/* Hold vfsmount and dentry until release is finished */
- req->vfsmount = mntget(file->f_vfsmnt);
- req->dentry = dget(file->f_dentry);
+ req->vfsmount = mntget(file->f_path.mnt);
+ req->dentry = dget(file->f_path.dentry);
request_send_background(fc, req);
}
static int fuse_flush(struct file *file, fl_owner_t id)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_req *req;
static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
size_t count, loff_t *ppos, int write)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
size_t nmax = write ? fc->max_write : fc->max_read;
loff_t pos = *ppos;
static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
ssize_t res;
/* Don't allow parallel writes to the same file */
mutex_lock(&inode->i_mutex);
static void fuse_lk_fill(struct fuse_req *req, struct file *file,
const struct file_lock *fl, int opcode, pid_t pid)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_lk_in *arg = &req->misc.lk_in;
static int fuse_getlk(struct file *file, struct file_lock *fl)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_lk_out outarg;
static int fuse_setlk(struct file *file, struct file_lock *fl)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
int err;
static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
int error;
*/
static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh;
{
struct gfs2_file *fp = file->private_data;
struct gfs2_holder *fl_gh = &fp->f_fl_gh;
- struct gfs2_inode *ip = GFS2_I(file->f_dentry->d_inode);
+ struct gfs2_inode *ip = GFS2_I(file->f_path.dentry->d_inode);
struct gfs2_glock *gl;
unsigned int state;
int flags;
*/
static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFS_MAX_NAMELEN];
const struct iovec *iov, loff_t offset, unsigned long nr_segs)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
+ struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfs_get_block, NULL);
static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
int len, err;
char strbuf[HFSPLUS_MAX_STRLEN + 1];
const struct iovec *iov, loff_t offset, unsigned long nr_segs)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
+ struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfsplus_get_block, NULL);
return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
}
-#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode)
+#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
int hostfs_d_delete(struct dentry *dentry)
{
unsigned long long next, ino;
int error, len;
- name = dentry_name(file->f_dentry, 0);
+ name = dentry_name(file->f_path.dentry, 0);
if(name == NULL) return(-ENOMEM);
dir = open_dir(name, &error);
kfree(name);
if(w)
r = 1;
- name = dentry_name(file->f_dentry, 0);
+ name = dentry_name(file->f_path.dentry, 0);
if(name == NULL)
return(-ENOMEM);
loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
loff_t pos;
struct quad_buffer_head qbh;
- struct inode *i = filp->f_dentry->d_inode;
+ struct inode *i = filp->f_path.dentry->d_inode;
struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
struct super_block *s = i->i_sb;
static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
struct quad_buffer_head qbh;
struct hpfs_dirent *de;
retval = do_sync_write(file, buf, count, ppos);
if (retval > 0)
- hpfs_i(file->f_dentry->d_inode)->i_dirty = 1;
+ hpfs_i(file->f_path.dentry->d_inode)->i_dirty = 1;
return retval;
}
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t n;
- read = file->f_dentry->d_inode->i_fop->read;
+ read = file->f_path.dentry->d_inode->i_fop->read;
if(!is_user)
set_fs(KERNEL_DS);
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
int err;
- write = proc_file->f_dentry->d_inode->i_fop->write;
+ write = proc_file->f_path.dentry->d_inode->i_fop->write;
proc_file->f_pos = file->f_pos;
err = (*write)(proc_file, buf, len, &proc_file->f_pos);
if(data == NULL)
goto out;
- host_file = dentry_name(file->f_dentry, strlen("/rw"));
+ host_file = dentry_name(file->f_path.dentry, strlen("/rw"));
if(host_file == NULL)
goto out_free2;
loff_t (*llseek)(struct file *, loff_t, int);
loff_t ret;
- llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
+ llseek = proc_file->f_path.dentry->d_inode->i_fop->llseek;
if(llseek != NULL){
ret = (*llseek)(proc_file, off, where);
if(ret < 0)
struct hppfs_dirent dirent = ((struct hppfs_dirent)
{ .vfs_dirent = ent,
.filldir = filldir,
- .dentry = file->f_dentry } );
+ .dentry = file->f_path.dentry } );
int err;
- readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
+ readdir = proc_file->f_path.dentry->d_inode->i_fop->readdir;
proc_file->f_pos = file->f_pos;
err = (*readdir)(proc_file, &dirent, hppfs_filldir);
static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
loff_t len, vma_len;
int ret;
d_instantiate(dentry, inode);
inode->i_size = size;
inode->i_nlink = 0;
- file->f_vfsmnt = mntget(hugetlbfs_vfsmount);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(hugetlbfs_vfsmount);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_op = &hugetlbfs_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ;
void file_update_time(struct file *file)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct timespec now;
int sync_it = 0;
dev->ih = ih;
filp->f_op = &inotify_fops;
- filp->f_vfsmnt = mntget(inotify_mnt);
- filp->f_dentry = dget(inotify_mnt->mnt_root);
- filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_path.mnt = mntget(inotify_mnt);
+ filp->f_path.dentry = dget(inotify_mnt->mnt_root);
+ filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
filp->f_mode = FMODE_READ;
filp->f_flags = O_RDONLY;
filp->private_data = dev;
goto out;
} else if (filp->f_op->ioctl) {
lock_kernel();
- error = filp->f_op->ioctl(filp->f_dentry->d_inode,
+ error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
filp, cmd, arg);
unlock_kernel();
}
{
int error;
int block;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
int __user *p = (int __user *)arg;
switch (cmd) {
break;
case FIOQSIZE:
- if (S_ISDIR(filp->f_dentry->d_inode->i_mode) ||
- S_ISREG(filp->f_dentry->d_inode->i_mode) ||
- S_ISLNK(filp->f_dentry->d_inode->i_mode)) {
- loff_t res = inode_get_bytes(filp->f_dentry->d_inode);
+ if (S_ISDIR(filp->f_path.dentry->d_inode->i_mode) ||
+ S_ISREG(filp->f_path.dentry->d_inode->i_mode) ||
+ S_ISLNK(filp->f_path.dentry->d_inode->i_mode)) {
+ loff_t res = inode_get_bytes(filp->f_path.dentry->d_inode);
error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0;
}
else
error = -ENOTTY;
break;
default:
- if (S_ISREG(filp->f_dentry->d_inode->i_mode))
+ if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
error = file_ioctl(filp, cmd, arg);
else
error = do_ioctl(filp, cmd, arg);
*/
static int zisofs_readpage(struct file *file, struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned int maxpage, xpage, fpage, blockindex;
unsigned long offset;
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
- inode_number = parent_ino(filp->f_dentry);
+ inode_number = parent_ino(filp->f_path.dentry);
if (filldir(dirent, "..", 2, filp->f_pos, inode_number, DT_DIR) < 0)
break;
filp->f_pos += de_len;
int result;
char * tmpname;
struct iso_directory_record * tmpde;
- struct inode *inode = filp->f_dentry->d_inode;
-
+ struct inode *inode = filp->f_path.dentry->d_inode;
tmpname = (char *)__get_free_page(GFP_KERNEL);
if (tmpname == NULL)
jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct jffs_file *f;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info;
int j;
struct jffs_control *c;
struct jffs_file *f;
struct jffs_node *node;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int recoverable = 0;
size_t written = 0;
loff_t pos = *ppos;
int err;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
D2(printk("***jffs_file_write(): inode: 0x%p (ino: %lu), "
"filp: 0x%p, buf: 0x%p, count: %d\n",
{
struct jffs2_inode_info *f;
struct jffs2_sb_info *c;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct jffs2_full_dirent *fd;
unsigned long offset, curofs;
- D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_dentry->d_inode->i_ino));
+ D1(printk(KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", filp->f_path.dentry->d_inode->i_ino));
f = JFFS2_INODE_INFO(inode);
c = JFFS2_SB_INFO(inode->i_sb);
offset++;
}
if (offset == 1) {
- unsigned long pino = parent_ino(filp->f_dentry);
+ unsigned long pino = parent_ino(filp->f_path.dentry);
D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino));
if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0)
goto out;
*/
int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *ip = filp->f_dentry->d_inode;
+ struct inode *ip = filp->f_path.dentry->d_inode;
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
int rc = 0;
loff_t dtpos; /* legacy OS/2 style position */
{
static struct qstr cursor_name = {.len = 1, .name = "."};
- file->private_data = d_alloc(file->f_dentry, &cursor_name);
+ file->private_data = d_alloc(file->f_path.dentry, &cursor_name);
return file->private_data ? 0 : -ENOMEM;
}
loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin)
{
- mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
switch (origin) {
case 1:
offset += file->f_pos;
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
spin_lock(&dcache_lock);
list_del(&cursor->d_u.d_child);
- p = file->f_dentry->d_subdirs.next;
- while (n && p != &file->f_dentry->d_subdirs) {
+ p = file->f_path.dentry->d_subdirs.next;
+ while (n && p != &file->f_path.dentry->d_subdirs) {
struct dentry *next;
next = list_entry(p, struct dentry, d_u.d_child);
if (!d_unhashed(next) && next->d_inode)
spin_unlock(&dcache_lock);
}
}
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return offset;
}
int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct dentry *cursor = filp->private_data;
struct list_head *p, *q = &cursor->d_u.d_child;
ino_t ino;
continue;
if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
continue;
- if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_dentry->d_inode) ,fh) != 0)
+ if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue;
/* Alright, we found a lock. Set the return status
* and wake up the caller
nlmclnt_next_cookie(&argp->cookie);
argp->state = nsm_local_state;
- memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
+ memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh));
lock->caller = utsname()->nodename;
lock->oh.data = req->a_owner;
lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
__be32 ret;
dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_type, lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end,
struct nlm_lock *conflock)
{
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_type,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
int error;
dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
int status = 0;
dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
- file->f_file->f_dentry->d_inode->i_sb->s_id,
- file->f_file->f_dentry->d_inode->i_ino,
+ file->f_file->f_path.dentry->d_inode->i_sb->s_id,
+ file->f_file->f_path.dentry->d_inode->i_ino,
lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
static inline void nlm_debug_print_file(char *msg, struct nlm_file *file)
{
- struct inode *inode = file->f_file->f_dentry->d_inode;
+ struct inode *inode = file->f_file->f_path.dentry->d_inode;
dprintk("lockd: %s %s/%ld\n",
msg, inode->i_sb->s_id, inode->i_ino);
start = filp->f_pos;
break;
case SEEK_END:
- start = i_size_read(filp->f_dentry->d_inode);
+ start = i_size_read(filp->f_path.dentry->d_inode);
break;
default:
return -EINVAL;
start = filp->f_pos;
break;
case SEEK_END:
- start = i_size_read(filp->f_dentry->d_inode);
+ start = i_size_read(filp->f_path.dentry->d_inode);
break;
default:
return -EINVAL;
struct file_lock *cfl;
lock_kernel();
- for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
+ for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl))
continue;
if (posix_locks_conflict(cfl, fl))
{
struct file_lock *new_fl = NULL;
struct file_lock **before;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
int error = 0;
int found = 0;
*/
int posix_lock_file(struct file *filp, struct file_lock *fl)
{
- return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL);
+ return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL);
}
EXPORT_SYMBOL(posix_lock_file);
int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
struct file_lock *conflock)
{
- return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock);
+ return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock);
}
EXPORT_SYMBOL(posix_lock_file_conf);
int type = F_UNLCK;
lock_kernel();
- time_out_leases(filp->f_dentry->d_inode);
- for (fl = filp->f_dentry->d_inode->i_flock; fl && IS_LEASE(fl);
+ time_out_leases(filp->f_path.dentry->d_inode);
+ for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);
fl = fl->fl_next) {
if (fl->fl_file == filp) {
type = fl->fl_type & ~F_INPROGRESS;
static int __setlease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
int setlease(struct file *filp, long arg, struct file_lock **lease)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error;
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
struct file_lock fl, *flp = &fl;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error;
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
* posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway.
*/
- if (!filp->f_dentry->d_inode->i_flock)
+ if (!filp->f_path.dentry->d_inode->i_flock)
return;
lock.fl_type = F_UNLCK;
*/
void locks_remove_flock(struct file *filp)
{
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode * inode = filp->f_path.dentry->d_inode;
struct file_lock *fl;
struct file_lock **before;
struct inode *inode = NULL;
if (fl->fl_file != NULL)
- inode = fl->fl_file->f_dentry->d_inode;
+ inode = fl->fl_file->f_path.dentry->d_inode;
out += sprintf(out, "%d:%s ", id, pfx);
if (IS_POSIX(fl)) {
static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned long pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
*/
int file_permission(struct file *file, int mask)
{
- return permission(file->f_dentry->d_inode, mask, NULL);
+ return permission(file->f_path.dentry->d_inode, mask, NULL);
}
/*
int deny_write_access(struct file * file)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
spin_lock(&inode->i_lock);
if (atomic_read(&inode->i_writecount) > 0) {
*/
void release_open_intent(struct nameidata *nd)
{
- if (nd->intent.open.file->f_dentry == NULL)
+ if (nd->intent.open.file->f_path.dentry == NULL)
put_filp(nd->intent.open.file);
else
fput(nd->intent.open.file);
return PTR_ERR(link);
}
-struct path {
- struct vfsmount *mnt;
- struct dentry *dentry;
-};
-
static inline void dput_path(struct path *path, struct nameidata *nd)
{
dput(path->dentry);
if (!file)
goto out_fail;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
retval = -ENOTDIR;
if (!S_ISDIR(dentry->d_inode->i_mode))
if (retval)
goto fput_fail;
- nd->mnt = mntget(file->f_vfsmnt);
+ nd->mnt = mntget(file->f_path.mnt);
nd->dentry = dget(dentry);
fput_light(file, fput_needed);
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/seq_file.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/mount.h>
static inline int check_mnt(struct vfsmount *mnt)
{
- return mnt->mnt_namespace == current->nsproxy->namespace;
+ return mnt->mnt_ns == current->nsproxy->mnt_ns;
}
-static void touch_namespace(struct namespace *ns)
+static void touch_mnt_namespace(struct mnt_namespace *ns)
{
if (ns) {
ns->event = ++event;
}
}
-static void __touch_namespace(struct namespace *ns)
+static void __touch_mnt_namespace(struct mnt_namespace *ns)
{
if (ns && ns->event != event) {
ns->event = event;
struct vfsmount *parent = mnt->mnt_parent;
struct vfsmount *m;
LIST_HEAD(head);
- struct namespace *n = parent->mnt_namespace;
+ struct mnt_namespace *n = parent->mnt_ns;
BUG_ON(parent == mnt);
list_add_tail(&head, &mnt->mnt_list);
list_for_each_entry(m, &head, mnt_list)
- m->mnt_namespace = n;
+ m->mnt_ns = n;
list_splice(&head, n->list.prev);
list_add_tail(&mnt->mnt_hash, mount_hashtable +
hash(parent, mnt->mnt_mountpoint));
list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
- touch_namespace(n);
+ touch_mnt_namespace(n);
}
static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
/* iterator */
static void *m_start(struct seq_file *m, loff_t *pos)
{
- struct namespace *n = m->private;
+ struct mnt_namespace *n = m->private;
struct list_head *p;
loff_t l = *pos;
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct namespace *n = m->private;
+ struct mnt_namespace *n = m->private;
struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;
(*pos)++;
return p == &n->list ? NULL : list_entry(p, struct vfsmount, mnt_list);
list_for_each_entry(p, kill, mnt_hash) {
list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list);
- __touch_namespace(p->mnt_namespace);
- p->mnt_namespace = NULL;
+ __touch_mnt_namespace(p->mnt_ns);
+ p->mnt_ns = NULL;
list_del_init(&p->mnt_child);
if (p->mnt_parent != p)
p->mnt_mountpoint->d_mounted--;
if (parent_nd) {
detach_mnt(source_mnt, parent_nd);
attach_mnt(source_mnt, nd);
- touch_namespace(current->nsproxy->namespace);
+ touch_mnt_namespace(current->nsproxy->mnt_ns);
} else {
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
commit_tree(source_mnt);
*/
if (!propagate_mount_busy(mnt, 2)) {
/* delete from the namespace */
- touch_namespace(mnt->mnt_namespace);
+ touch_mnt_namespace(mnt->mnt_ns);
list_del_init(&mnt->mnt_list);
- mnt->mnt_namespace = NULL;
+ mnt->mnt_ns = NULL;
umount_tree(mnt, 1, umounts);
spin_unlock(&vfsmount_lock);
} else {
*/
static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts)
{
- struct namespace *namespace;
+ struct mnt_namespace *ns;
struct vfsmount *mnt;
while (!list_empty(graveyard)) {
/* don't do anything if the namespace is dead - all the
* vfsmounts from it are going away anyway */
- namespace = mnt->mnt_namespace;
- if (!namespace || !namespace->root)
+ ns = mnt->mnt_ns;
+ if (!ns || !ns->root)
continue;
- get_namespace(namespace);
+ get_mnt_ns(ns);
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
up_write(&namespace_sem);
release_mounts(&umounts);
mntput(mnt);
- put_namespace(namespace);
+ put_mnt_ns(ns);
spin_lock(&vfsmount_lock);
}
}
* Allocate a new namespace structure and populate it with contents
* copied from the namespace of the passed in task structure.
*/
-struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
+struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk,
+ struct fs_struct *fs)
{
- struct namespace *namespace = tsk->nsproxy->namespace;
- struct namespace *new_ns;
+ struct mnt_namespace *mnt_ns = tsk->nsproxy->mnt_ns;
+ struct mnt_namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
struct vfsmount *p, *q;
- new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL);
+ new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns)
return NULL;
down_write(&namespace_sem);
/* First pass: copy the tree topology */
- new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root,
+ new_ns->root = copy_tree(mnt_ns->root, mnt_ns->root->mnt_root,
CL_COPY_ALL | CL_EXPIRE);
if (!new_ns->root) {
up_write(&namespace_sem);
* as belonging to new namespace. We have already acquired a private
* fs_struct, so tsk->fs->lock is not needed.
*/
- p = namespace->root;
+ p = mnt_ns->root;
q = new_ns->root;
while (p) {
- q->mnt_namespace = new_ns;
+ q->mnt_ns = new_ns;
if (fs) {
if (p == fs->rootmnt) {
rootmnt = p;
fs->altrootmnt = mntget(q);
}
}
- p = next_mnt(p, namespace->root);
+ p = next_mnt(p, mnt_ns->root);
q = next_mnt(q, new_ns->root);
}
up_write(&namespace_sem);
return new_ns;
}
-int copy_namespace(int flags, struct task_struct *tsk)
+int copy_mnt_ns(int flags, struct task_struct *tsk)
{
- struct namespace *namespace = tsk->nsproxy->namespace;
- struct namespace *new_ns;
+ struct mnt_namespace *ns = tsk->nsproxy->mnt_ns;
+ struct mnt_namespace *new_ns;
int err = 0;
- if (!namespace)
+ if (!ns)
return 0;
- get_namespace(namespace);
+ get_mnt_ns(ns);
if (!(flags & CLONE_NEWNS))
return 0;
goto out;
}
- new_ns = dup_namespace(tsk, tsk->fs);
+ new_ns = dup_mnt_ns(tsk, tsk->fs);
if (!new_ns) {
err = -ENOMEM;
goto out;
}
- tsk->nsproxy->namespace = new_ns;
+ tsk->nsproxy->mnt_ns = new_ns;
out:
- put_namespace(namespace);
+ put_mnt_ns(ns);
return err;
}
detach_mnt(user_nd.mnt, &root_parent);
attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */
attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
- touch_namespace(current->nsproxy->namespace);
+ touch_mnt_namespace(current->nsproxy->mnt_ns);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&user_nd, &new_nd);
security_sb_post_pivotroot(&user_nd, &new_nd);
static void __init init_mount_tree(void)
{
struct vfsmount *mnt;
- struct namespace *namespace;
+ struct mnt_namespace *ns;
mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
if (IS_ERR(mnt))
panic("Can't create rootfs");
- namespace = kmalloc(sizeof(*namespace), GFP_KERNEL);
- if (!namespace)
+ ns = kmalloc(sizeof(*ns), GFP_KERNEL);
+ if (!ns)
panic("Can't allocate initial namespace");
- atomic_set(&namespace->count, 1);
- INIT_LIST_HEAD(&namespace->list);
- init_waitqueue_head(&namespace->poll);
- namespace->event = 0;
- list_add(&mnt->mnt_list, &namespace->list);
- namespace->root = mnt;
- mnt->mnt_namespace = namespace;
-
- init_task.nsproxy->namespace = namespace;
- get_namespace(namespace);
-
- set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
- set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
+ atomic_set(&ns->count, 1);
+ INIT_LIST_HEAD(&ns->list);
+ init_waitqueue_head(&ns->poll);
+ ns->event = 0;
+ list_add(&mnt->mnt_list, &ns->list);
+ ns->root = mnt;
+ mnt->mnt_ns = ns;
+
+ init_task.nsproxy->mnt_ns = ns;
+ get_mnt_ns(ns);
+
+ set_fs_pwd(current->fs, ns->root, ns->root->mnt_root);
+ set_fs_root(current->fs, ns->root, ns->root->mnt_root);
}
void __init mnt_init(unsigned long mempages)
init_mount_tree();
}
-void __put_namespace(struct namespace *namespace)
+void __put_mnt_ns(struct mnt_namespace *ns)
{
- struct vfsmount *root = namespace->root;
+ struct vfsmount *root = ns->root;
LIST_HEAD(umount_list);
- namespace->root = NULL;
+ ns->root = NULL;
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
spin_lock(&vfsmount_lock);
spin_unlock(&vfsmount_lock);
up_write(&namespace_sem);
release_mounts(&umount_list);
- kfree(namespace);
+ kfree(ns);
}
static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct page *page = NULL;
struct ncp_server *server = NCP_SERVER(inode);
ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
struct ncp_cache_control *ctrl, struct ncp_entry_info *entry)
{
- struct dentry *newdent, *dentry = filp->f_dentry;
+ struct dentry *newdent, *dentry = filp->f_path.dentry;
struct inode *newino, *inode = dentry->d_inode;
struct ncp_cache_control ctl = *ctrl;
struct qstr qname;
ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
struct ncp_cache_control *ctl)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_volume_info info;
ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
struct ncp_cache_control *ctl)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *dir = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(dir);
struct nw_search_sequence seq;
static ssize_t
ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
size_t already_read = 0;
off_t pos;
static ssize_t
ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
size_t already_written = 0;
off_t pos;
if (!ncp_filp)
goto out;
error = -ENOTSOCK;
- sock_inode = ncp_filp->f_dentry->d_inode;
+ sock_inode = ncp_filp->f_path.dentry->d_inode;
if (!S_ISSOCK(sock_inode->i_mode))
goto out_fput;
sock = SOCKET_I(sock_inode);
if (!server->info_filp)
goto out_fput;
error = -ENOTSOCK;
- sock_inode = server->info_filp->f_dentry->d_inode;
+ sock_inode = server->info_filp->f_path.dentry->d_inode;
if (!S_ISSOCK(sock_inode->i_mode))
goto out_fput2;
info_sock = SOCKET_I(sock_inode);
ncp_get_fs_info(struct ncp_server * server, struct file *file,
struct ncp_fs_info __user *arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info info;
if ((file_permission(file, MAY_WRITE) != 0)
ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
struct ncp_fs_info_v2 __user * arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info_v2 info2;
if ((file_permission(file, MAY_WRITE) != 0)
ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
struct compat_ncp_fs_info_v2 __user * arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct compat_ncp_fs_info_v2 info2;
if ((file_permission(file, MAY_WRITE) != 0)
#ifdef CONFIG_COMPAT
long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
lock_kernel();
unsigned long address, int *type)
{
struct file *file = area->vm_file;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct page* page;
char *pg_addr;
/* This is used for a general mmap of a ncp file */
int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
DPRINTK("ncp_mmap: called\n");
int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
{
struct file *file = desc->file;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct rpc_cred *cred = nfs_file_cred(file);
unsigned long timestamp;
int error;
again:
timestamp = jiffies;
- error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
+ error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, desc->entry->cookie, page,
NFS_SERVER(inode)->dtsize, desc->plus);
if (error < 0) {
/* We requested READDIRPLUS, but the server doesn't grok it */
static inline
int find_dirent_page(nfs_readdir_descriptor_t *desc)
{
- struct inode *inode = desc->file->f_dentry->d_inode;
+ struct inode *inode = desc->file->f_path.dentry->d_inode;
struct page *page;
int status;
filldir_t filldir)
{
struct file *file = desc->file;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
int status;
status = -ENOMEM;
goto out;
}
- desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, *desc->dir_cookie,
+ desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
page,
NFS_SERVER(inode)->dtsize,
desc->plus);
*/
static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
nfs_readdir_descriptor_t my_desc,
*desc = &my_desc;
loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
{
- mutex_lock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
switch (origin) {
case 1:
offset += filp->f_pos;
((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;
}
out:
- mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
return offset;
}
static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
{
- struct dentry *parent = desc->file->f_dentry;
+ struct dentry *parent = desc->file->f_path.dentry;
struct inode *dir = parent->d_inode;
struct nfs_entry *entry = desc->entry;
struct dentry *dentry, *alias;
ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs)
{
dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n",
- iocb->ki_filp->f_dentry->d_name.name,
+ iocb->ki_filp->f_path.dentry->d_name.name,
(long long) pos, nr_segs);
return -EINVAL;
size_t count = iov[0].iov_len;
dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
- file->f_dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name,
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
size_t count = iov[0].iov_len;
dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
- file->f_dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name,
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
nfs_file_flush(struct file *file, fl_owner_t id)
{
struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int status;
dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- struct dentry * dentry = iocb->ki_filp->f_dentry;
+ struct dentry * dentry = iocb->ki_filp->f_path.dentry;
struct inode * inode = dentry->d_inode;
ssize_t result;
size_t count = iov_length(iov, nr_segs);
nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
read_actor_t actor, void *target)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
ssize_t res;
static int
nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
int status;
static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- struct dentry * dentry = iocb->ki_filp->f_dentry;
+ struct dentry * dentry = iocb->ki_filp->f_path.dentry;
struct inode * inode = dentry->d_inode;
ssize_t result;
size_t count = iov_length(iov, nr_segs);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
{
dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
- filp->f_dentry->d_inode->i_sb->s_id,
- filp->f_dentry->d_inode->i_ino,
+ filp->f_path.dentry->d_inode->i_sb->s_id,
+ filp->f_path.dentry->d_inode->i_ino,
fl->fl_type, fl->fl_flags);
/*
#include <linux/nfs_idmap.h>
#include <linux/vfs.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/security.h>
#include <asm/system.h>
static ssize_t
idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
{
- struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
+ struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
struct idmap *idmap = (struct idmap *)rpci->private;
struct idmap_msg im_in, *im = &idmap->idmap_im;
struct idmap_hashtable *h;
*/
static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
filp->private_data = get_nfs_open_context(ctx);
static void nfs_file_clear_open_context(struct file *filp)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
if (ctx) {
cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
if (IS_ERR(cred))
return PTR_ERR(cred);
- ctx = alloc_nfs_open_context(filp->f_vfsmnt, filp->f_dentry, cred);
+ ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred);
put_rpccred(cred);
if (ctx == NULL)
return -ENOMEM;
static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
- return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
+ return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl);
}
const struct nfs_rpc_ops nfs_v3_clientops = {
static int
nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
- return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
+ return nlmclnt_proc(filp->f_path.dentry->d_inode, cmd, fl);
}
nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
- file->f_dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name, count,
+ file->f_path.dentry->d_parent->d_name.name,
+ file->f_path.dentry->d_name.name, count,
(long long)(page_offset(page) +offset));
/* If we're not using byte range locks, and we know the page
{
struct dentry *dentry = resp->fh.fh_dentry;
struct inode *inode = dentry->d_inode;
- int w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
struct kvec *head = rqstp->rq_res.head;
unsigned int base;
int n;
+ int w;
if (dentry == NULL || dentry->d_inode == NULL)
return 0;
return 0;
base = (char *)p - (char *)head->iov_base;
- rqstp->rq_res.page_len = w;
+ rqstp->rq_res.page_len = w = nfsacl_size(
+ (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
+ (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
while (w > 0) {
if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0 && dentry && dentry->d_inode) {
struct inode *inode = dentry->d_inode;
- int w = nfsacl_size(
- (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
struct kvec *head = rqstp->rq_res.head;
unsigned int base;
int n;
+ int w;
*p++ = htonl(resp->mask);
if (!xdr_ressize_check(rqstp, p))
return 0;
base = (char *)p - (char *)head->iov_base;
- rqstp->rq_res.page_len = w;
+ rqstp->rq_res.page_len = w = nfsacl_size(
+ (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
+ (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
while (w > 0) {
if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
printk("nfsd4: non-file found in client recovery directory\n");
return -EINVAL;
}
- mutex_lock(&dir->d_inode->i_mutex);
+ mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
status = vfs_unlink(dir->d_inode, dentry);
mutex_unlock(&dir->d_inode->i_mutex);
return status;
nfs4_file_downgrade(struct file *filp, unsigned int share_access)
{
if (share_access & NFS4_SHARE_ACCESS_WRITE) {
- put_write_access(filp->f_dentry->d_inode);
+ put_write_access(filp->f_path.dentry->d_inode);
filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;
}
}
nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
{
struct file *filp = stp->st_vfs_file;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int share_access, new_writer;
__be32 status;
static inline int
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
{
- return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_dentry->d_inode;
+ return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
}
static int
* only the dentry:inode set.
*/
memset(&file, 0, sizeof (struct file));
- file.f_dentry = current_fh->fh_dentry;
+ file.f_path.dentry = current_fh->fh_dentry;
status = nfs_ok;
if (posix_test_lock(&file, &file_lock, &conflock)) {
check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
{
struct file_lock **flpp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int status = 0;
lock_kernel();
printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
CACHESIZE, CACHESIZE-i);
- hash_list = kmalloc (HASHSIZE * sizeof(struct hlist_head), GFP_KERNEL);
+ hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
if (!hash_list) {
nfsd_cache_shutdown();
printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
HASHSIZE * sizeof(struct hlist_head));
return;
}
- memset(hash_list, 0, HASHSIZE * sizeof(struct hlist_head));
cache_disabled = 0;
}
static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
- ino_t ino = file->f_dentry->d_inode->i_ino;
+ ino_t ino = file->f_path.dentry->d_inode->i_ino;
char *data;
ssize_t rv;
nfsd_sync(struct file *filp)
{
int err;
- struct inode *inode = filp->f_dentry->d_inode;
- dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
mutex_lock(&inode->i_mutex);
- err=nfsd_dosync(filp, filp->f_dentry, filp->f_op);
+ err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
mutex_unlock(&inode->i_mutex);
return err;
int host_err;
err = nfserr_perm;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
(!lock_may_read(inode, offset, *count)))
nfsdstats.io_read += host_err;
*count = host_err;
err = 0;
- fsnotify_access(file->f_dentry);
+ fsnotify_access(file->f_path.dentry);
} else
err = nfserrno(host_err);
out:
err = nfserr_perm;
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- (!lock_may_write(file->f_dentry->d_inode, offset, cnt)))
+ (!lock_may_write(file->f_path.dentry->d_inode, offset, cnt)))
goto out;
#endif
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
exp = fhp->fh_export;
set_fs(oldfs);
if (host_err >= 0) {
nfsdstats.io_write += cnt;
- fsnotify_modify(file->f_dentry);
+ fsnotify_modify(file->f_path.dentry);
}
/* clear setuid/setgid flag after write */
return 0;
if (cache_size < 2*RAPARM_HASH_SIZE)
cache_size = 2*RAPARM_HASH_SIZE;
- raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);
-
- if (raparml != NULL) {
- dprintk("nfsd: allocating %d readahead buffers.\n",
- cache_size);
- for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
- raparm_hash[i].pb_head = NULL;
- spin_lock_init(&raparm_hash[i].pb_lock);
- }
- nperbucket = cache_size >> RAPARM_HASH_BITS;
- memset(raparml, 0, sizeof(struct raparms) * cache_size);
- for (i = 0; i < cache_size - 1; i++) {
- if (i % nperbucket == 0)
- raparm_hash[j++].pb_head = raparml + i;
- if (i % nperbucket < nperbucket-1)
- raparml[i].p_next = raparml + i + 1;
- }
- } else {
+ raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);
+
+ if (!raparml) {
printk(KERN_WARNING
- "nfsd: Could not allocate memory read-ahead cache.\n");
+ "nfsd: Could not allocate memory read-ahead cache.\n");
return -ENOMEM;
}
+
+ dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
+ for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
+ raparm_hash[i].pb_head = NULL;
+ spin_lock_init(&raparm_hash[i].pb_lock);
+ }
+ nperbucket = cache_size >> RAPARM_HASH_BITS;
+ for (i = 0; i < cache_size - 1; i++) {
+ if (i % nperbucket == 0)
+ raparm_hash[j++].pb_head = raparml + i;
+ if (i % nperbucket < nperbucket-1)
+ raparml[i].p_next = raparml + i + 1;
+ }
+
nfsdstats.ra_size = cache_size;
return 0;
}
{
s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
loff_t fpos, i_size;
- struct inode *bmp_vi, *vdir = filp->f_dentry->d_inode;
+ struct inode *bmp_vi, *vdir = filp->f_path.dentry->d_inode;
struct super_block *sb = vdir->i_sb;
ntfs_inode *ndir = NTFS_I(vdir);
ntfs_volume *vol = NTFS_SB(sb);
if (fpos == 1) {
ntfs_debug("Calling filldir for .. with len 2, fpos 0x1, "
"inode 0x%lx, DT_DIR.",
- (unsigned long)parent_ino(filp->f_dentry));
+ (unsigned long)parent_ino(filp->f_path.dentry));
rc = filldir(dirent, "..", 2, fpos,
- parent_ino(filp->f_dentry), DT_DIR);
+ parent_ino(filp->f_path.dentry), DT_DIR);
if (rc)
goto done;
fpos++;
goto out;
if (!count)
goto out;
- err = remove_suid(file->f_dentry);
+ err = remove_suid(file->f_path.dentry);
if (err)
goto out;
file_update_time(file);
ssize_t bytes,
void *private)
{
- struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+ struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
/* this io's submitter should not have unlocked this before we could */
BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
unsigned long nr_segs)
{
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
+ struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
int ret;
mlog_entry_void();
struct buffer_head * bh, * tmp;
struct ocfs2_dir_entry * de;
int err;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block * sb = inode->i_sb;
unsigned int ra_sectors = 16;
int lock_level = 0;
int bytes_left;
ssize_t readlen;
char *lvb_buf;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
mlog(0, "inode %lu, count = %zu, *ppos = %llu\n",
inode->i_ino, count, *ppos);
int bytes_left;
ssize_t writelen;
char *lvb_buf;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
mlog(0, "inode %lu, count = %zu, *ppos = %llu\n",
inode->i_ino, count, *ppos);
struct ocfs2_inode_info *oi = OCFS2_I(inode);
mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,
- file->f_dentry->d_name.len, file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.len, file->f_path.dentry->d_name.name);
spin_lock(&oi->ip_lock);
struct ocfs2_inode_info *oi = OCFS2_I(inode);
mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,
- file->f_dentry->d_name.len,
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.len,
+ file->f_path.dentry->d_name.name);
spin_lock(&oi->ip_lock);
if (!--oi->ip_open_count)
{
int ret, rw_level, have_alloc_sem = 0;
struct file *filp = iocb->ki_filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int appending = filp->f_flags & O_APPEND ? 1 : 0;
mlog_entry("(0x%p, %u, '%.*s')\n", filp,
(unsigned int)nr_segs,
- filp->f_dentry->d_name.len,
- filp->f_dentry->d_name.name);
+ filp->f_path.dentry->d_name.len,
+ filp->f_path.dentry->d_name.name);
/* happy write of zero bytes */
if (iocb->ki_left == 0)
goto out;
}
- ret = ocfs2_prepare_inode_for_write(filp->f_dentry, &iocb->ki_pos,
+ ret = ocfs2_prepare_inode_for_write(filp->f_path.dentry, &iocb->ki_pos,
iocb->ki_left, appending);
if (ret < 0) {
mlog_errno(ret);
unsigned int flags)
{
int ret;
- struct inode *inode = out->f_dentry->d_inode;
+ struct inode *inode = out->f_path.dentry->d_inode;
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe,
(unsigned int)len,
- out->f_dentry->d_name.len,
- out->f_dentry->d_name.name);
+ out->f_path.dentry->d_name.len,
+ out->f_path.dentry->d_name.name);
inode_double_lock(inode, pipe->inode);
goto out;
}
- ret = ocfs2_prepare_inode_for_write(out->f_dentry, ppos, len, 0);
+ ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, ppos, len, 0);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
unsigned int flags)
{
int ret = 0;
- struct inode *inode = in->f_dentry->d_inode;
+ struct inode *inode = in->f_path.dentry->d_inode;
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe,
(unsigned int)len,
- in->f_dentry->d_name.len,
- in->f_dentry->d_name.name);
+ in->f_path.dentry->d_name.len,
+ in->f_path.dentry->d_name.name);
/*
* See the comment in ocfs2_file_aio_read()
{
int ret = 0, rw_level = -1, have_alloc_sem = 0, lock_level = 0;
struct file *filp = iocb->ki_filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
mlog_entry("(0x%p, %u, '%.*s')\n", filp,
(unsigned int)nr_segs,
- filp->f_dentry->d_name.len,
- filp->f_dentry->d_name.name);
+ filp->f_path.dentry->d_name.len,
+ filp->f_path.dentry->d_name.name);
if (!inode) {
ret = -EINVAL;
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_native(file->f_dentry, &tmp);
+ error = vfs_statfs_native(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs64(file->f_dentry, &tmp);
+ error = vfs_statfs64(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
if (file->f_flags & O_LARGEFILE)
small = 0;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
error = -EINVAL;
if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
if (!file)
goto out;
- dentry = file->f_dentry;
- mnt = file->f_vfsmnt;
+ dentry = file->f_path.dentry;
+ mnt = file->f_path.mnt;
inode = dentry->d_inode;
error = -ENOTDIR;
if (!file)
goto out;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
audit_inode(NULL, inode);
if (!file)
goto out;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
audit_inode(NULL, dentry->d_inode);
error = chown_common(dentry, user, group);
fput(file);
}
f->f_mapping = inode->i_mapping;
- f->f_dentry = dentry;
- f->f_vfsmnt = mnt;
+ f->f_path.dentry = dentry;
+ f->f_path.mnt = mnt;
f->f_pos = 0;
f->f_op = fops_get(inode->i_fop);
file_move(f, &inode->i_sb->s_files);
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
file_kill(f);
- f->f_dentry = NULL;
- f->f_vfsmnt = NULL;
+ f->f_path.dentry = NULL;
+ f->f_path.mnt = NULL;
cleanup_file:
put_filp(f);
dput(dentry);
/* Pick up the filp from the open intent */
filp = nd->intent.open.file;
/* Has the filesystem initialised the file for us? */
- if (filp->f_dentry == NULL)
+ if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
else
path_release(nd);
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
- fsnotify_open(f->f_dentry);
+ fsnotify_open(f->f_path.dentry);
fd_install(fd, f);
}
}
asmlinkage long sys_vhangup(void)
{
if (capable(CAP_SYS_TTY_CONFIG)) {
+ /* XXX: this needs locking */
tty_vhangup(current->signal->tty);
return 0;
}
static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct op_inode_info *oi = OP_I(inode);
struct device_node *dp = oi->u.node;
struct device_node *child;
.show = part_stat_read
};
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+
+static ssize_t part_fail_store(struct hd_struct * p,
+ const char *buf, size_t count)
+{
+ int i;
+
+ if (count > 0 && sscanf(buf, "%d", &i) > 0)
+ p->make_it_fail = (i == 0) ? 0 : 1;
+
+ return count;
+}
+static ssize_t part_fail_read(struct hd_struct * p, char *page)
+{
+ return sprintf(page, "%d\n", p->make_it_fail);
+}
+static struct part_attribute part_attr_fail = {
+ .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR },
+ .store = part_fail_store,
+ .show = part_fail_read
+};
+
+#endif
+
static struct attribute * default_attrs[] = {
&part_attr_uevent.attr,
&part_attr_dev.attr,
&part_attr_start.attr,
&part_attr_size.attr,
&part_attr_stat.attr,
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+ &part_attr_fail.attr,
+#endif
NULL,
};
unsigned long nr_segs, loff_t pos)
{
struct file *filp = iocb->ki_filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe;
int do_wakeup;
ssize_t ret;
unsigned long nr_segs, loff_t ppos)
{
struct file *filp = iocb->ki_filp;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe;
ssize_t ret;
int do_wakeup;
pipe_ioctl(struct inode *pino, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe;
int count, buf, nrbufs;
pipe_poll(struct file *filp, poll_table *wait)
{
unsigned int mask;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe = inode->i_pipe;
int nrbufs;
static int
pipe_read_fasync(int fd, struct file *filp, int on)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int retval;
mutex_lock(&inode->i_mutex);
static int
pipe_write_fasync(int fd, struct file *filp, int on)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int retval;
mutex_lock(&inode->i_mutex);
static int
pipe_rdwr_fasync(int fd, struct file *filp, int on)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct pipe_inode_info *pipe = inode->i_pipe;
int retval;
*/
dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, inode);
- f->f_vfsmnt = mntget(pipe_mnt);
- f->f_dentry = dentry;
+ f->f_path.mnt = mntget(pipe_mnt);
+ f->f_path.dentry = dentry;
f->f_mapping = inode->i_mapping;
f->f_flags = O_WRONLY;
void free_write_pipe(struct file *f)
{
- mntput(f->f_vfsmnt);
- dput(f->f_dentry);
+ mntput(f->f_path.mnt);
+ dput(f->f_path.dentry);
put_filp(f);
}
return ERR_PTR(-ENFILE);
/* Grab pipe from the writer */
- f->f_vfsmnt = mntget(wrf->f_vfsmnt);
- f->f_dentry = dget(wrf->f_dentry);
- f->f_mapping = wrf->f_dentry->d_inode->i_mapping;
+ f->f_path.mnt = mntget(wrf->f_path.mnt);
+ f->f_path.dentry = dget(wrf->f_path.dentry);
+ f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
f->f_pos = 0;
f->f_flags = O_RDONLY;
* Author : Ram Pai (linuxram@us.ibm.com)
*
*/
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/fs.h>
#include "pnode.h"
#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED)
#define IS_MNT_SLAVE(mnt) (mnt->mnt_master)
-#define IS_MNT_NEW(mnt) (!mnt->mnt_namespace)
+#define IS_MNT_NEW(mnt) (!mnt->mnt_ns)
#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED)
#define IS_MNT_UNBINDABLE(mnt) (mnt->mnt_flags & MNT_UNBINDABLE)
sigemptyset(&sigcatch);
cutime = cstime = utime = stime = cputime_zero;
- mutex_lock(&tty_mutex);
rcu_read_lock();
if (lock_task_sighand(task, &flags)) {
struct signal_struct *sig = task->signal;
- struct tty_struct *tty = sig->tty;
-
- if (tty) {
- /*
- * sig->tty is not stable, but tty_mutex
- * protects us from release_dev(tty)
- */
- barrier();
- tty_pgrp = tty->pgrp;
- tty_nr = new_encode_dev(tty_devnum(tty));
+
+ if (sig->tty) {
+ tty_pgrp = sig->tty->pgrp;
+ tty_nr = new_encode_dev(tty_devnum(sig->tty));
}
num_threads = atomic_read(&sig->count);
stime = cputime_add(stime, sig->stime);
}
- sid = sig->session;
+ sid = signal_session(sig);
pgid = process_group(task);
ppid = rcu_dereference(task->real_parent)->tgid;
unlock_task_sighand(task, &flags);
}
rcu_read_unlock();
- mutex_unlock(&tty_mutex);
if (!whole || num_threads<2)
wchan = get_wchan(task);
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/rcupdate.h>
static int mounts_open(struct inode *inode, struct file *file)
{
struct task_struct *task = get_proc_task(inode);
- struct namespace *namespace = NULL;
+ struct mnt_namespace *ns = NULL;
struct proc_mounts *p;
int ret = -EINVAL;
if (task) {
task_lock(task);
- namespace = task->nsproxy->namespace;
- if (namespace)
- get_namespace(namespace);
+ ns = task->nsproxy->mnt_ns;
+ if (ns)
+ get_mnt_ns(ns);
task_unlock(task);
put_task_struct(task);
}
- if (namespace) {
+ if (ns) {
ret = -ENOMEM;
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
if (p) {
file->private_data = &p->m;
ret = seq_open(file, &mounts_op);
if (!ret) {
- p->m.private = namespace;
- p->event = namespace->event;
+ p->m.private = ns;
+ p->event = ns->event;
return 0;
}
kfree(p);
}
- put_namespace(namespace);
+ put_mnt_ns(ns);
}
return ret;
}
static int mounts_release(struct inode *inode, struct file *file)
{
struct seq_file *m = file->private_data;
- struct namespace *namespace = m->private;
- put_namespace(namespace);
+ struct mnt_namespace *ns = m->private;
+ put_mnt_ns(ns);
return seq_release(inode, file);
}
static unsigned mounts_poll(struct file *file, poll_table *wait)
{
struct proc_mounts *p = file->private_data;
- struct namespace *ns = p->m.private;
+ struct mnt_namespace *ns = p->m.private;
unsigned res = 0;
poll_wait(file, &ns->poll, wait);
if (!ret) {
struct seq_file *m = file->private_data;
- struct namespace *namespace = NULL;
+ struct mnt_namespace *mnt_ns = NULL;
struct task_struct *task = get_proc_task(inode);
if (task) {
task_lock(task);
if (task->nsproxy)
- namespace = task->nsproxy->namespace;
- if (namespace)
- get_namespace(namespace);
+ mnt_ns = task->nsproxy->mnt_ns;
+ if (mnt_ns)
+ get_mnt_ns(mnt_ns);
task_unlock(task);
put_task_struct(task);
}
- if (namespace)
- m->private = namespace;
+ if (mnt_ns)
+ m->private = mnt_ns;
else {
seq_release(inode, file);
ret = -EINVAL;
static ssize_t proc_info_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
unsigned long page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
static ssize_t mem_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char *page;
unsigned long src = *ppos;
int ret = -ESRCH;
{
int copied;
char *page;
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
unsigned long dst = *ppos;
copied = -ESRCH;
static ssize_t oom_adjust_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char buffer[PROC_NUMBUF];
size_t len;
int oom_adjust;
return -EINVAL;
if (*end == '\n')
end++;
- task = get_proc_task(file->f_dentry->d_inode);
+ task = get_proc_task(file->f_path.dentry->d_inode);
if (!task)
return -ESRCH;
if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
ssize_t length;
char tmpbuf[TMPBUFLEN];
static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page, *tmp;
ssize_t length;
uid_t loginuid;
};
#endif /* CONFIG_SECCOMP */
+#ifdef CONFIG_FAULT_INJECTION
+static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ char buffer[PROC_NUMBUF];
+ size_t len;
+ int make_it_fail;
+ loff_t __ppos = *ppos;
+
+ if (!task)
+ return -ESRCH;
+ make_it_fail = task->make_it_fail;
+ put_task_struct(task);
+
+ len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
+ if (__ppos >= len)
+ return 0;
+ if (count > len-__ppos)
+ count = len-__ppos;
+ if (copy_to_user(buf, buffer + __ppos, count))
+ return -EFAULT;
+ *ppos = __ppos + count;
+ return count;
+}
+
+static ssize_t proc_fault_inject_write(struct file * file,
+ const char __user * buf, size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF], *end;
+ int make_it_fail;
+
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EPERM;
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ make_it_fail = simple_strtol(buffer, &end, 0);
+ if (*end == '\n')
+ end++;
+ task = get_proc_task(file->f_dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ task->make_it_fail = make_it_fail;
+ put_task_struct(task);
+ if (end - buffer == 0)
+ return -EIO;
+ return end - buffer;
+}
+
+static struct file_operations proc_fault_inject_operations = {
+ .read = proc_fault_inject_read,
+ .write = proc_fault_inject_write,
+};
+#endif
+
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
char *name, int len,
instantiate_t instantiate, struct task_struct *task, void *ptr)
{
- struct dentry *child, *dir = filp->f_dentry;
+ struct dentry *child, *dir = filp->f_path.dentry;
struct inode *inode;
struct qstr qname;
ino_t ino = 0;
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
- *mnt = mntget(file->f_vfsmnt);
- *dentry = dget(file->f_dentry);
+ *mnt = mntget(file->f_path.mnt);
+ *dentry = dget(file->f_path.dentry);
spin_unlock(&files->file_lock);
put_files_struct(files);
return 0;
static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *p = get_proc_task(inode);
unsigned int fd, tid, ino;
{
int i;
int pid;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
struct pid_entry *p, *last;
static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
unsigned long page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
goto out;
length = security_getprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ (char*)file->f_path.dentry->d_name.name,
(void*)page, count);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
goto out_free;
length = security_setprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ (char*)file->f_path.dentry->d_name.name,
(void*)page, count);
out_free:
free_page((unsigned long) page);
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
+#ifdef CONFIG_FAULT_INJECTION
+ REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
};
static int proc_tgid_base_readdir(struct file * filp,
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
- struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode);
+ struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode);
struct task_struct *task;
int tgid;
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
+#ifdef CONFIG_FAULT_INJECTION
+ REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
};
static int proc_tid_base_readdir(struct file * filp,
/* for the /proc/TGID/task/ directories */
static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *leader = get_proc_task(inode);
struct task_struct *task;
proc_file_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page;
ssize_t retval=0;
int eof=0;
proc_file_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct proc_dir_entry * dp;
dp = PDE(inode);
struct proc_dir_entry * de;
unsigned int ino;
int i;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int ret = 0;
lock_kernel();
/* fall through */
case 1:
if (filldir(dirent, "..", 2, i,
- parent_ino(filp->f_dentry),
+ parent_ino(filp->f_path.dentry),
DT_DIR) < 0)
goto out;
i++;
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file * filp = list_entry(p, struct file, f_u.fu_list);
- struct dentry * dentry = filp->f_dentry;
+ struct dentry * dentry = filp->f_path.dentry;
struct inode * inode;
const struct file_operations *fops;
file = vma->vm_file;
if (file) {
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
if (len < 1)
len = 1;
seq_printf(m, "%*c", len, ' ');
- seq_path(m, file->f_vfsmnt, file->f_dentry, "");
+ seq_path(m, file->f_path.mnt, file->f_path.dentry, "");
}
seq_putc(m, '\n');
#include <linux/seq_file.h>
#include <linux/times.h>
#include <linux/profile.h>
+#include <linux/utsname.h>
#include <linux/blkdev.h>
#include <linux/hugetlb.h>
#include <linux/jiffies.h>
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
-#include <linux/pspace.h>
+#include <linux/pid_namespace.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
LOAD_INT(c), LOAD_FRAC(c),
- nr_running(), nr_threads, init_pspace.last_pid);
+ nr_running(), nr_threads, current->nsproxy->pid_ns->last_pid);
return proc_calc_metrics(page, start, off, count, eof, len);
}
{
int len;
- strcpy(page, linux_banner);
- len = strlen(page);
+ len = sprintf(page, linux_banner,
+ utsname()->release, utsname()->version);
return proc_calc_metrics(page, start, off, count, eof, len);
}
}
if (vma) {
- *mnt = mntget(vma->vm_file->f_vfsmnt);
- *dentry = dget(vma->vm_file->f_dentry);
+ *mnt = mntget(vma->vm_file->f_path.mnt);
+ *dentry = dget(vma->vm_file->f_path.dentry);
result = 0;
}
int len;
if (file) {
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
*/
if (file) {
pad_len_spaces(m, len);
- seq_path(m, file->f_vfsmnt, file->f_dentry, "\n");
+ seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n");
} else {
const char *name = arch_vma_name(vma);
if (!name) {
}
if (vma) {
- *mnt = mntget(vma->vm_file->f_vfsmnt);
- *dentry = dget(vma->vm_file->f_dentry);
+ *mnt = mntget(vma->vm_file->f_path.mnt);
+ *dentry = dget(vma->vm_file->f_path.dentry);
result = 0;
}
static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int offset;
struct buffer_head *bh;
struct qnx4_inode_entry *de;
unsigned long pgoff, unsigned long flags)
{
unsigned long maxpages, lpages, nr, loop, ret;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct page **pages = NULL, **ptr, *page;
loff_t isize;
lock_kernel();
switch (origin) {
case 2:
- offset += i_size_read(file->f_dentry->d_inode);
+ offset += i_size_read(file->f_path.dentry->d_inode);
break;
case 1:
offset += file->f_pos;
}
retval = -EINVAL;
- if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
+ if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) {
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
lock_kernel();
switch (origin) {
case 2:
- offset += i_size_read(file->f_dentry->d_inode);
+ offset += i_size_read(file->f_path.dentry->d_inode);
break;
case 1:
offset += file->f_pos;
if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
goto Einval;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
int retval = locks_mandatory_area(
read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0) {
- fsnotify_access(file->f_dentry);
+ fsnotify_access(file->f_path.dentry);
current->rchar += ret;
}
current->syscr++;
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
- fsnotify_modify(file->f_dentry);
+ fsnotify_modify(file->f_path.dentry);
current->wchar += ret;
}
current->syscw++;
kfree(iov);
if ((ret + (type == READ)) > 0) {
if (type == READ)
- fsnotify_access(file->f_dentry);
+ fsnotify_access(file->f_path.dentry);
else
- fsnotify_modify(file->f_dentry);
+ fsnotify_modify(file->f_path.dentry);
}
return ret;
}
if (!(in_file->f_mode & FMODE_READ))
goto fput_in;
retval = -EINVAL;
- in_inode = in_file->f_dentry->d_inode;
+ in_inode = in_file->f_path.dentry->d_inode;
if (!in_inode)
goto fput_in;
if (!in_file->f_op || !in_file->f_op->sendfile)
retval = -EINVAL;
if (!out_file->f_op || !out_file->f_op->sendpage)
goto fput_out;
- out_inode = out_file->f_dentry->d_inode;
+ out_inode = out_file->f_path.dentry->d_inode;
retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
if (retval < 0)
goto fput_out;
int vfs_readdir(struct file *file, filldir_t filler, void *buf)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int res = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
*/
static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
{
- struct path *path;
+ struct treepath *path;
struct buffer_head *bh;
struct item_head *ih;
int pos_in_item;
//
static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
INITIALIZE_PATH(path_to_entry);
struct buffer_head *bh;
/* Ignore the .reiserfs_priv entry */
if (reiserfs_xattrs(inode->i_sb) &&
!old_format_only(inode->i_sb) &&
- filp->f_dentry == inode->i_sb->s_root &&
+ filp->f_path.dentry == inode->i_sb->s_root &&
REISERFS_SB(inode->i_sb)->priv_root &&
REISERFS_SB(inode->i_sb)->priv_root->d_inode
&& deh_objectid(deh) ==
loff_t pos; // Current position in the file.
ssize_t res; // return value of various functions that we call.
int err = 0;
- struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
+ struct inode *inode = file->f_path.dentry->d_inode; // Inode of the file that we are writing to.
/* To simplify coding at this time, we store
locked pages in array for now */
struct page *prepared_pages[REISERFS_WRITE_PAGES_AT_A_TIME];
if (count == 0)
goto out;
- res = remove_suid(file->f_dentry);
+ res = remove_suid(file->f_path.dentry);
if (res)
goto out;
{
struct buffer_head *p_s_parent;
INITIALIZE_PATH(s_path_to_neighbor_father);
- struct path *p_s_path = p_s_tb->tb_path;
+ struct treepath *p_s_path = p_s_tb->tb_path;
struct cpu_key s_lr_father_key;
int n_counter,
n_position = INT_MAX,
*/
static int get_parents(struct tree_balance *p_s_tb, int n_h)
{
- struct path *p_s_path = p_s_tb->tb_path;
+ struct treepath *p_s_path = p_s_tb->tb_path;
int n_position,
n_ret_value,
n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
static int get_direct_parent(struct tree_balance *p_s_tb, int n_h)
{
struct buffer_head *p_s_bh;
- struct path *p_s_path = p_s_tb->tb_path;
+ struct treepath *p_s_path = p_s_tb->tb_path;
int n_position,
n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
}
/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path)
+ struct inode *inode, struct treepath *path)
{
struct super_block *s = th->t_super;
int len = th->t_blocks_allocated;
long block,
struct inode *inode,
b_blocknr_t * allocated_block_nr,
- struct path *path, int flags)
+ struct treepath *path, int flags)
{
BUG_ON(!th->t_trans_id);
//
// called by read_locked_inode
-static void init_inode(struct inode *inode, struct path *path)
+static void init_inode(struct inode *inode, struct treepath *path)
{
struct buffer_head *bh;
struct item_head *ih;
/* NOTE, you must prepare the buffer head before sending it here,
** and then log it after the call
*/
-static void update_stat_data(struct path *path, struct inode *inode,
+static void update_stat_data(struct treepath *path, struct inode *inode,
loff_t size)
{
struct buffer_head *bh;
containing "." and ".." entries */
static int reiserfs_new_directory(struct reiserfs_transaction_handle *th,
struct inode *inode,
- struct item_head *ih, struct path *path,
+ struct item_head *ih, struct treepath *path,
struct inode *dir)
{
struct super_block *sb = th->t_super;
containing the body of symlink */
static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode of symlink */
struct item_head *ih,
- struct path *path, const char *symname,
+ struct treepath *path, const char *symname,
int item_len)
{
struct super_block *sb = th->t_super;
long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int ret;
/* These are just misnamed, they actually get/put from/to user an int */
// comment? maybe something like set de to point to what the path points to?
static inline void set_de_item_location(struct reiserfs_dir_entry *de,
- struct path *path)
+ struct treepath *path)
{
de->de_bh = get_last_bh(path);
de->de_ih = get_ih(path);
/* The function is NOT SCHEDULE-SAFE! */
int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
- struct path *path, struct reiserfs_dir_entry *de)
+ struct treepath *path, struct reiserfs_dir_entry *de)
{
int retval;
// may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND
// FIXME: should add something like IOERROR
static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
- struct path *path_to_entry,
+ struct treepath *path_to_entry,
struct reiserfs_dir_entry *de)
{
struct cpu_key key_to_search;
}
#if defined( REISERFS_USE_OIDMAPF )
if (sb_info->oidmap.use_file && (sb_info->oidmap.mapf != NULL)) {
- loff_t size = sb_info->oidmap.mapf->f_dentry->d_inode->i_size;
+ loff_t size = sb_info->oidmap.mapf->f_path.dentry->d_inode->i_size;
total_used += size / sizeof(reiserfs_oidinterval_d_t);
}
#endif
of the path, and going upwards. We must check the path's validity at each step. If the key is not in
the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this
case we return a special key, either MIN_KEY or MAX_KEY. */
-static inline const struct reiserfs_key *get_lkey(const struct path
+static inline const struct reiserfs_key *get_lkey(const struct treepath
*p_s_chk_path,
const struct super_block
*p_s_sb)
}
/* Get delimiting key of the buffer at the path and its right neighbor. */
-inline const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
+inline const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
const struct super_block *p_s_sb)
{
int n_position, n_path_offset = p_s_chk_path->path_length;
the path. These delimiting keys are stored at least one level above that buffer in the tree. If the
buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in
this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */
-static inline int key_in_buffer(struct path *p_s_chk_path, /* Path which should be checked. */
+static inline int key_in_buffer(struct treepath *p_s_chk_path, /* Path which should be checked. */
const struct cpu_key *p_s_key, /* Key which should be checked. */
struct super_block *p_s_sb /* Super block pointer. */
)
}
/* Decrement b_count field of the all buffers in the path. */
-void decrement_counters_in_path(struct path *p_s_search_path)
+void decrement_counters_in_path(struct treepath *p_s_search_path)
{
int n_path_offset = p_s_search_path->path_length;
p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
}
-int reiserfs_check_path(struct path *p)
+int reiserfs_check_path(struct treepath *p)
{
RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET,
"path not properly relsed");
**
** only called from fix_nodes()
*/
-void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path)
+void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path)
{
int n_path_offset = p_s_search_path->path_length;
}
/* Release all buffers in the path. */
-void pathrelse(struct path *p_s_search_path)
+void pathrelse(struct treepath *p_s_search_path)
{
int n_path_offset = p_s_search_path->path_length;
correctness of the bottom of the path */
/* The function is NOT SCHEDULE-SAFE! */
int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* Key to search. */
- struct path *p_s_search_path, /* This structure was
+ struct treepath *p_s_search_path,/* This structure was
allocated and initialized
by the calling
function. It is filled up
/* The function is NOT SCHEDULE-SAFE! */
int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the super block. */
const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */
- struct path *p_s_search_path /* Filled up by this function. */
+ struct treepath *p_s_search_path /* Filled up by this function. */
)
{
struct item_head *p_le_ih; /* pointer to on-disk structure */
}
/* Compare given item and item pointed to by the path. */
-int comp_items(const struct item_head *stored_ih, const struct path *p_s_path)
+int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path)
{
struct buffer_head *p_s_bh;
struct item_head *ih;
#define block_in_use(bh) (buffer_locked(bh) || (held_by_others(bh)))
// prepare for delete or cut of direct item
-static inline int prepare_for_direct_item(struct path *path,
+static inline int prepare_for_direct_item(struct treepath *path,
struct item_head *le_ih,
struct inode *inode,
loff_t new_file_length, int *cut_size)
return M_CUT; /* Cut from this item. */
}
-static inline int prepare_for_direntry_item(struct path *path,
+static inline int prepare_for_direntry_item(struct treepath *path,
struct item_head *le_ih,
struct inode *inode,
loff_t new_file_length,
In case of file truncate calculate whether this item must be deleted/truncated or last
unformatted node of this item will be converted to a direct item.
This function returns a determination of what balance mode the calling function should employ. */
-static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed
+static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed
from end of the file. */
int *p_n_cut_size, unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */
)
static void init_tb_struct(struct reiserfs_transaction_handle *th,
struct tree_balance *p_s_tb,
struct super_block *p_s_sb,
- struct path *p_s_path, int n_size)
+ struct treepath *p_s_path, int n_size)
{
BUG_ON(!th->t_trans_id);
#endif
/* Delete object item. */
-int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the deleted item. */
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the deleted item. */
const struct cpu_key *p_s_item_key, /* Key to search for the deleted item. */
struct inode *p_s_inode, /* inode is here just to update i_blocks and quotas */
struct buffer_head *p_s_un_bh)
static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
struct inode *p_s_inode,
struct page *page,
- struct path *p_s_path,
+ struct treepath *p_s_path,
const struct cpu_key *p_s_item_key,
loff_t n_new_file_size, char *p_c_mode)
{
pointer being converted. Therefore we have to delete inserted
direct item(s) */
static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path)
+ struct inode *inode, struct treepath *path)
{
struct cpu_key tail_key;
int tail_len;
/* (Truncate or cut entry) or delete object item. Returns < 0 on failure */
int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
- struct path *p_s_path,
+ struct treepath *p_s_path,
struct cpu_key *p_s_item_key,
struct inode *p_s_inode,
struct page *page, loff_t n_new_file_size)
#ifdef CONFIG_REISERFS_CHECK
// this makes sure, that we __append__, not overwrite or add holes
-static void check_research_for_paste(struct path *path,
+static void check_research_for_paste(struct treepath *path,
const struct cpu_key *p_s_key)
{
struct item_head *found_ih = get_ih(path);
#endif /* config reiserfs check */
/* Paste bytes to the existing item. Returns bytes number pasted into the item. */
-int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct path *p_s_search_path, /* Path to the pasted item. */
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_search_path, /* Path to the pasted item. */
const struct cpu_key *p_s_key, /* Key to search for the needed item. */
struct inode *inode, /* Inode item belongs to */
const char *p_c_body, /* Pointer to the bytes to paste. */
}
/* Insert new item into the buffer at the path. */
-int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the inserteded item. */
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the inserteded item. */
const struct cpu_key *key, struct item_head *p_s_ih, /* Pointer to the item header to insert. */
struct inode *inode, const char *p_c_body)
{ /* Pointer to the bytes to insert. */
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
/* path points to first direct item of the file regarless of how many of
them are there */
int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
- struct path *path, struct buffer_head *unbh,
+ struct treepath *path, struct buffer_head *unbh,
loff_t tail_offset)
{
struct super_block *sb = inode->i_sb;
what we expect from it (number of cut bytes). But when tail remains
in the unformatted node, we set mode to SKIP_BALANCING and unlock
inode */
-int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct path *p_s_path, /* path to the indirect item. */
+int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct treepath *p_s_path, /* path to the indirect item. */
const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
loff_t n_new_file_size, /* New file size. */
char *p_c_mode)
*/
static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
INITIALIZE_PATH(path_to_entry);
struct buffer_head *bh;
static
int xattr_readdir(struct file *file, filldir_t filler, void *buf)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int res = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
goto out;
goto out;
}
- xinode = fp->f_dentry->d_inode;
+ xinode = fp->f_path.dentry->d_inode;
REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
/* we need to copy it off.. */
newattrs.ia_size = buffer_size;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
mutex_lock(&xinode->i_mutex);
- err = notify_change(fp->f_dentry, &newattrs);
+ err = notify_change(fp->f_path.dentry, &newattrs);
if (err)
goto out_filp;
goto out;
}
- xinode = fp->f_dentry->d_inode;
+ xinode = fp->f_path.dentry->d_inode;
isize = xinode->i_size;
REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
static int
romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *i = filp->f_dentry->d_inode;
+ struct inode *i = filp->f_path.dentry->d_inode;
struct romfs_inode ri;
unsigned long offset, maxoff;
int j, ino, nextfh;
/**
* seq_release - free the structures associated with sequential file.
* @file: file in question
- * @inode: file->f_dentry->d_inode
+ * @inode: file->f_path.dentry->d_inode
*
* Frees the structures associated with sequential file; can be used
* as ->f_op->release() if you don't have private data to destroy.
struct smb_cache_control *ctrl, struct qstr *qname,
struct smb_fattr *entry)
{
- struct dentry *newdent, *dentry = filp->f_dentry;
+ struct dentry *newdent, *dentry = filp->f_path.dentry;
struct inode *newino, *inode = dentry->d_inode;
struct smb_cache_control ctl = *ctrl;
int valid = 0;
static int
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *dir = dentry->d_inode;
struct smb_sb_info *server = server_from_dentry(dentry);
union smb_dir_cache *cache = NULL;
static int
smb_dir_open(struct inode *dir, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct smb_sb_info *server;
int error = 0;
VERBOSE("(%s/%s)\n", dentry->d_parent->d_name.name,
- file->f_dentry->d_name.name);
+ file->f_path.dentry->d_name.name);
/*
* Directory timestamps in the core protocol aren't updated
smb_readpage(struct file *file, struct page *page)
{
int error;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
page_cache_get(page);
error = smb_readpage_sync(dentry, page);
smb_updatepage(struct file *file, struct page *page, unsigned long offset,
unsigned int count)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
DEBUG1("(%s/%s %d@%lld)\n", DENTRY_PATH(dentry), count,
((unsigned long long)page->index << PAGE_CACHE_SHIFT) + offset);
unsigned long nr_segs, loff_t pos)
{
struct file * file = iocb->ki_filp;
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
ssize_t status;
VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
static int
smb_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
int status;
VERBOSE("file %s/%s, address %lu - %lu\n",
smb_file_sendfile(struct file *file, loff_t *ppos,
size_t count, read_actor_t actor, void *target)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
ssize_t status;
VERBOSE("file %s/%s, pos=%Ld, count=%d\n",
unsigned long nr_segs, loff_t pos)
{
struct file * file = iocb->ki_filp;
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
ssize_t result;
VERBOSE("file %s/%s, count=%lu@%lu\n",
smb_file_open(struct inode *inode, struct file * file)
{
int result;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int smb_mode = (file->f_mode & O_ACCMODE) - 1;
lock_kernel();
filp = fget(opt->fd);
if (!filp)
goto out;
- if (!smb_valid_socket(filp->f_dentry->d_inode))
+ if (!smb_valid_socket(filp->f_path.dentry->d_inode))
goto out_putf;
server->sock_file = filp;
/*
* Store the server in sock user_data (Only used by sunrpc)
*/
- sk = SOCKET_I(filp->f_dentry->d_inode)->sk;
+ sk = SOCKET_I(filp->f_path.dentry->d_inode)->sk;
sk->sk_user_data = server;
/* chain into the data_ready callback */
smb_proc_readdir_short(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
- struct dentry *dir = filp->f_dentry;
+ struct dentry *dir = filp->f_path.dentry;
struct smb_sb_info *server = server_from_dentry(dir);
struct qstr qname;
struct smb_fattr fattr;
smb_proc_readdir_long(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
- struct dentry *dir = filp->f_dentry;
+ struct dentry *dir = filp->f_path.dentry;
struct smb_sb_info *server = server_from_dentry(dir);
struct qstr qname;
struct smb_fattr fattr;
smb_proc_readdir_null(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
- struct smb_sb_info *server = server_from_dentry(filp->f_dentry);
+ struct smb_sb_info *server = server_from_dentry(filp->f_path.dentry);
if (smb_proc_ops_wait(server) < 0)
return -EIO;
if (server && (file = server->sock_file))
{
#ifdef SMBFS_PARANOIA
- if (!smb_valid_socket(file->f_dentry->d_inode))
+ if (!smb_valid_socket(file->f_path.dentry->d_inode))
PARANOIA("bad socket!\n");
#endif
- return SOCKET_I(file->f_dentry->d_inode);
+ return SOCKET_I(file->f_path.dentry->d_inode);
}
return NULL;
}
ssize_t ret;
int err;
- err = remove_suid(out->f_dentry);
+ err = remove_suid(out->f_path.dentry);
if (unlikely(err))
return err;
ssize_t ret;
int err;
- err = should_remove_suid(out->f_dentry);
+ err = should_remove_suid(out->f_path.dentry);
if (unlikely(err)) {
mutex_lock(&inode->i_mutex);
- err = __remove_suid(out->f_dentry, err);
+ err = __remove_suid(out->f_path.dentry, err);
mutex_unlock(&inode->i_mutex);
if (err)
return err;
* randomly drop data for eg socket -> socket splicing. Use the
* piped splicing for that!
*/
- i_mode = in->f_dentry->d_inode->i_mode;
+ i_mode = in->f_path.dentry->d_inode->i_mode;
if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
return -EINVAL;
loff_t offset, *off;
long ret;
- pipe = pipe_info(in->f_dentry->d_inode);
+ pipe = pipe_info(in->f_path.dentry->d_inode);
if (pipe) {
if (off_in)
return -ESPIPE;
return ret;
}
- pipe = pipe_info(out->f_dentry->d_inode);
+ pipe = pipe_info(out->f_path.dentry->d_inode);
if (pipe) {
if (off_out)
return -ESPIPE;
.ops = &user_page_pipe_buf_ops,
};
- pipe = pipe_info(file->f_dentry->d_inode);
+ pipe = pipe_info(file->f_path.dentry->d_inode);
if (!pipe)
return -EBADF;
if (unlikely(nr_segs > UIO_MAXIOV))
static long do_tee(struct file *in, struct file *out, size_t len,
unsigned int flags)
{
- struct pipe_inode_info *ipipe = pipe_info(in->f_dentry->d_inode);
- struct pipe_inode_info *opipe = pipe_info(out->f_dentry->d_inode);
+ struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode);
+ struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode);
int ret = -EINVAL;
/*
--- /dev/null
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/fs_stack.h>
+
+/* does _NOT_ require i_mutex to be held.
+ *
+ * This function cannot be inlined since i_size_{read,write} is rather
+ * heavy-weight on 32-bit systems
+ */
+void fsstack_copy_inode_size(struct inode *dst, const struct inode *src)
+{
+ i_size_write(dst, i_size_read((struct inode *)src));
+ dst->i_blocks = src->i_blocks;
+}
+EXPORT_SYMBOL_GPL(fsstack_copy_inode_size);
+
+/* copy all attributes; get_nlinks is optional way to override the i_nlink
+ * copying
+ */
+void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
+ int (*get_nlinks)(struct inode *))
+{
+ if (!get_nlinks)
+ dest->i_nlink = src->i_nlink;
+ else
+ dest->i_nlink = (*get_nlinks)(dest);
+
+ dest->i_mode = src->i_mode;
+ dest->i_uid = src->i_uid;
+ dest->i_gid = src->i_gid;
+ dest->i_rdev = src->i_rdev;
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+ dest->i_blkbits = src->i_blkbits;
+ dest->i_flags = src->i_flags;
+
+ fsstack_copy_inode_size(dest, src);
+}
+EXPORT_SYMBOL_GPL(fsstack_copy_attr_all);
int error = -EBADF;
if (f) {
- error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat);
+ error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
fput(f);
}
return error;
file_list_lock();
list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
- if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f))
+ if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f))
f->f_mode &= ~FMODE_WRITE;
}
file_list_unlock();
* livelocks in fsync_buffers_list().
*/
mutex_lock(&mapping->host->i_mutex);
- err = file->f_op->fsync(file, file->f_dentry, datasync);
+ err = file->f_op->fsync(file, file->f_path.dentry, datasync);
if (!ret)
ret = err;
mutex_unlock(&mapping->host->i_mutex);
if (!file)
goto out;
- i_mode = file->f_dentry->d_inode->i_mode;
+ i_mode = file->f_path.dentry->d_inode->i_mode;
ret = -ESPIPE;
if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
!S_ISLNK(i_mode))
read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
{
char *buffer = file->private_data;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
int ret;
size_t count, loff_t * off)
{
char *buffer = file->private_data;
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
static int mmap(struct file *file, struct vm_area_struct *vma)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct bin_attribute *attr = to_bin_attr(dentry);
struct kobject *kobj = to_kobj(dentry->d_parent);
static int open(struct inode * inode, struct file * file)
{
- struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
- struct bin_attribute * attr = to_bin_attr(file->f_dentry);
+ struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
+ struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
int error = -EINVAL;
if (!kobj || !attr)
static int release(struct inode * inode, struct file * file)
{
- struct kobject * kobj = to_kobj(file->f_dentry->d_parent);
- struct bin_attribute * attr = to_bin_attr(file->f_dentry);
+ struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
+ struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
u8 * buffer = file->private_data;
if (kobj)
static int sysfs_dir_open(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
mutex_lock(&dentry->d_inode->i_mutex);
static int sysfs_dir_close(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
struct sysfs_dirent * cursor = file->private_data;
mutex_lock(&dentry->d_inode->i_mutex);
static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
struct sysfs_dirent *cursor = filp->private_data;
struct list_head *p, *q = &cursor->s_sibling;
static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
{
- struct dentry * dentry = file->f_dentry;
+ struct dentry * dentry = file->f_path.dentry;
mutex_lock(&dentry->d_inode->i_mutex);
switch (origin) {
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
down(&buffer->sem);
if (buffer->needs_read_fill) {
- if ((retval = fill_read_buffer(file->f_dentry,buffer)))
+ if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
down(&buffer->sem);
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
- len = flush_write_buffer(file->f_dentry, buffer, len);
+ len = flush_write_buffer(file->f_path.dentry, buffer, len);
if (len > 0)
*ppos += len;
up(&buffer->sem);
static int check_perm(struct inode * inode, struct file * file)
{
- struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
- struct attribute * attr = to_attr(file->f_dentry);
+ struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
+ struct attribute * attr = to_attr(file->f_path.dentry);
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
int error = 0;
static int sysfs_release(struct inode * inode, struct file * filp)
{
- struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
- struct attribute * attr = to_attr(filp->f_dentry);
+ struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
+ struct attribute * attr = to_attr(filp->f_path.dentry);
struct module * owner = attr->owner;
struct sysfs_buffer * buffer = filp->private_data;
static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
{
struct sysfs_buffer * buffer = filp->private_data;
- struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
- struct sysfs_dirent * sd = filp->f_dentry->d_fsdata;
+ struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
+ struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata;
int res = 0;
poll_wait(filp, &kobj->poll, wait);
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned long pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *dir = filp->f_dentry->d_inode;
+ struct inode *dir = filp->f_path.dentry->d_inode;
int result;
lock_kernel();
if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
{
- iblock = parent_ino(filp->f_dentry);
+ iblock = parent_ino(filp->f_path.dentry);
flen = 2;
memcpy(fname, "..", flen);
dt_type = DT_DIR;
{
ssize_t retval;
struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int err, pos;
size_t count = iocb->ki_left;
ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
loff_t pos = filp->f_pos;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned int offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
f = fget(fd);
if (!f)
return error;
- dentry = f->f_dentry;
+ dentry = f->f_path.dentry;
audit_inode(NULL, dentry->d_inode);
error = setxattr(dentry, name, value, size, flags);
fput(f);
f = fget(fd);
if (!f)
return error;
- error = getxattr(f->f_dentry, name, value, size);
+ error = getxattr(f->f_path.dentry, name, value, size);
fput(f);
return error;
}
f = fget(fd);
if (!f)
return error;
- error = listxattr(f->f_dentry, list, size);
+ error = listxattr(f->f_path.dentry, list, size);
fput(f);
return error;
}
f = fget(fd);
if (!f)
return error;
- dentry = f->f_dentry;
+ dentry = f->f_path.dentry;
audit_inode(NULL, dentry->d_inode);
error = removexattr(dentry, name);
fput(f);
loff_t pos)
{
struct file *file = iocb->ki_filp;
- bhv_vnode_t *vp = vn_from_inode(file->f_dentry->d_inode);
+ bhv_vnode_t *vp = vn_from_inode(file->f_path.dentry->d_inode);
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
read_actor_t actor,
void *target)
{
- return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode),
+ return bhv_vop_sendfile(vn_from_inode(filp->f_path.dentry->d_inode),
filp, pos, 0, count, actor, target, NULL);
}
read_actor_t actor,
void *target)
{
- return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode),
+ return bhv_vop_sendfile(vn_from_inode(filp->f_path.dentry->d_inode),
filp, pos, IO_INVIS, count, actor, target, NULL);
}
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode),
+ return bhv_vop_splice_read(vn_from_inode(infilp->f_path.dentry->d_inode),
infilp, ppos, pipe, len, flags, 0, NULL);
}
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode),
+ return bhv_vop_splice_read(vn_from_inode(infilp->f_path.dentry->d_inode),
infilp, ppos, pipe, len, flags, IO_INVIS,
NULL);
}
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode),
+ return bhv_vop_splice_write(vn_from_inode(outfilp->f_path.dentry->d_inode),
pipe, outfilp, ppos, len, flags, 0, NULL);
}
size_t len,
unsigned int flags)
{
- return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode),
+ return bhv_vop_splice_write(vn_from_inode(outfilp->f_path.dentry->d_inode),
pipe, outfilp, ppos, len, flags, IO_INVIS,
NULL);
}
struct file *filp,
fl_owner_t id)
{
- return -bhv_vop_close(vn_from_inode(filp->f_dentry->d_inode), 0,
+ return -bhv_vop_close(vn_from_inode(filp->f_path.dentry->d_inode), 0,
file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL);
}
unsigned long address,
int *type)
{
- struct inode *inode = area->vm_file->f_dentry->d_inode;
+ struct inode *inode = area->vm_file->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
filldir_t filldir)
{
int error = 0;
- bhv_vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode);
+ bhv_vnode_t *vp = vn_from_inode(filp->f_path.dentry->d_inode);
uio_t uio;
iovec_t iov;
int eof = 0;
vma->vm_ops = &xfs_file_vm_ops;
#ifdef CONFIG_XFS_DMAPI
- if (vn_from_inode(filp->f_dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
+ if (vn_from_inode(filp->f_path.dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
vma->vm_ops = &xfs_dmapi_file_vm_ops;
#endif /* CONFIG_XFS_DMAPI */
unsigned long p)
{
int error;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
error = bhv_vop_ioctl(vp, inode, filp, 0, cmd, (void __user *)p);
unsigned long p)
{
int error;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
error = bhv_vop_ioctl(vp, inode, filp, IO_INVIS, cmd, (void __user *)p);
struct vm_area_struct *vma,
unsigned int newflags)
{
- bhv_vnode_t *vp = vn_from_inode(vma->vm_file->f_dentry->d_inode);
+ bhv_vnode_t *vp = vn_from_inode(vma->vm_file->f_path.dentry->d_inode);
int error = 0;
if (vp->v_vfsp->vfs_flag & VFS_DMI) {
if (!file)
return -EBADF;
- ASSERT(file->f_dentry);
- ASSERT(file->f_dentry->d_inode);
- inode = igrab(file->f_dentry->d_inode);
+ ASSERT(file->f_path.dentry);
+ ASSERT(file->f_path.dentry->d_inode);
+ inode = igrab(file->f_path.dentry->d_inode);
fput(file);
break;
}
}
/* Ensure umount returns EBUSY on umounts while this file is open. */
- mntget(parfilp->f_vfsmnt);
+ mntget(parfilp->f_path.mnt);
/* Create file pointer. */
- filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
+ filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags);
if (IS_ERR(filp)) {
put_unused_fd(new_fd);
return -XFS_ERROR(-PTR_ERR(filp));
unsigned cmd,
unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
int error;
!capable(CAP_FSETID)) {
error = xfs_write_clear_setuid(xip);
if (likely(!error))
- error = -remove_suid(file->f_dentry);
+ error = -remove_suid(file->f_path.dentry);
if (unlikely(error)) {
xfs_iunlock(xip, iolock);
goto out_unlock_mutex;
/* Pull information for the target fd */
if (((fp = fget((int)sxp->sx_fdtarget)) == NULL) ||
- ((vp = vn_from_inode(fp->f_dentry->d_inode)) == NULL)) {
+ ((vp = vn_from_inode(fp->f_path.dentry->d_inode)) == NULL)) {
error = XFS_ERROR(EINVAL);
goto error0;
}
}
if (((tfp = fget((int)sxp->sx_fdtmp)) == NULL) ||
- ((tvp = vn_from_inode(tfp->f_dentry->d_inode)) == NULL)) {
+ ((tvp = vn_from_inode(tfp->f_path.dentry->d_inode)) == NULL)) {
error = XFS_ERROR(EINVAL);
goto error0;
}
speed_t c_ospeed; /* output speed */
};
+/* Alpha has matching termios and ktermios */
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t c_line; /* line discipline (== c_cc[19]) */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VEOF 0
#define VEOL 1
struct s3c2410fb_mach_info {
unsigned char fixed_syncs; /* do not update sync/border */
+ /* LCD types */
+ int type;
+
/* Screen size */
int width;
int height;
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
return 31 - bit;
}
+/*
+ * special slimline version of fls() for calculating ilog2_u32()
+ * - note: no protection against n == 0
+ */
+#define ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ int bit;
+ asm("scan %1,gr0,%0" : "=r"(bit) : "r"(n));
+ return 31 - bit;
+}
+
+/*
+ * special slimline version of fls64() for calculating ilog2_u64()
+ * - note: no protection against n == 0
+ */
+#define ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+ union {
+ u64 ll;
+ struct { u32 h, l; };
+ } _;
+ int bit, x, y;
+
+ _.ll = n;
+
+ asm(" subcc %3,gr0,gr0,icc0 \n"
+ " ckeq icc0,cc4 \n"
+ " cscan.p %3,gr0,%0 ,cc4,0 \n"
+ " setlos #63,%1 \n"
+ " cscan.p %4,gr0,%0 ,cc4,1 \n"
+ " setlos #31,%2 \n"
+ " csub.p %1,%0,%0 ,cc4,0 \n"
+ " csub %2,%0,%0 ,cc4,1 \n"
+ : "=&r"(bit), "=r"(x), "=r"(y)
+ : "0r"(_.h), "r"(_.l)
+ : "icc0", "cc4"
+ );
+ return bit;
+}
+
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/hweight.h>
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#include <linux/compiler.h>
#ifdef CONFIG_BUG
+
+#ifdef CONFIG_GENERIC_BUG
+#ifndef __ASSEMBLY__
+struct bug_entry {
+ unsigned long bug_addr;
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+ const char *file;
+ unsigned short line;
+#endif
+ unsigned short flags;
+};
+#endif /* __ASSEMBLY__ */
+
+#define BUGFLAG_WARNING (1<<0)
+#endif /* CONFIG_GENERIC_BUG */
+
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
#define WARN_ON(condition) ({ \
typeof(condition) __ret_warn_on = (condition); \
if (unlikely(__ret_warn_on)) { \
- printk("BUG: warning at %s:%d/%s()\n", __FILE__, \
+ printk("WARNING at %s:%d %s()\n", __FILE__, \
__LINE__, __FUNCTION__); \
dump_stack(); \
} \
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
-#include <linux/compiler.h>
+#include <linux/log2.h>
-/* Pure 2^n version of get_order */
-static __inline__ __attribute_const__ int get_order(unsigned long size)
+/*
+ * non-const pure 2^n version of get_order
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ * more efficiently than using the arch log2 routines
+ * - we use the non-const log2() instead if the arch has defined one suitable
+ */
+#ifndef ARCH_HAS_GET_ORDER
+static inline __attribute__((const))
+int __get_order(unsigned long size, int page_shift)
{
+#if BITS_PER_LONG == 32 && defined(ARCH_HAS_ILOG2_U32)
+ int order = __ilog2_u32(size) - page_shift;
+ return order >= 0 ? order : 0;
+#elif BITS_PER_LONG == 64 && defined(ARCH_HAS_ILOG2_U64)
+ int order = __ilog2_u64(size) - page_shift;
+ return order >= 0 ? order : 0;
+#else
int order;
- size = (size - 1) >> (PAGE_SHIFT - 1);
+ size = (size - 1) >> (page_shift - 1);
order = -1;
do {
size >>= 1;
order++;
} while (size);
return order;
+#endif
}
+#endif
+
+/**
+ * get_order - calculate log2(pages) to hold a block of the specified size
+ * @n - size
+ *
+ * calculate allocation order based on the current page size
+ * - this can be used to initialise global variables from constant data
+ */
+#define get_order(n) \
+( \
+ __builtin_constant_p(n) ? \
+ ((n < (1UL << PAGE_SHIFT)) ? 0 : ilog2(n) - PAGE_SHIFT) : \
+ __get_order(n, PAGE_SHIFT) \
+ )
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
-static inline int user_termio_to_kernel_termios(struct termios *termios,
+static inline int user_termio_to_kernel_termios(struct ktermios *termios,
struct termio __user *termio)
{
unsigned short tmp;
* Translate a "termios" structure into a "termio". Ugh.
*/
static inline int kernel_termios_to_user_termio(struct termio __user *termio,
- struct termios *termios)
+ struct ktermios *termios)
{
if (put_user(termios->c_iflag, &termio->c_iflag) < 0 ||
put_user(termios->c_oflag, &termio->c_oflag) < 0 ||
.stab.indexstr 0 : { *(.stab.indexstr) } \
.comment 0 : { *(.comment) }
+#define BUG_TABLE \
+ . = ALIGN(8); \
+ __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \
+ __start___bug_table = .; \
+ *(__bug_table) \
+ __stop___bug_table = .; \
+ }
+
#define NOTES \
.notes : { *(.note.*) } :note
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
/*
* Tell the user there is some problem.
- * The offending file and line are encoded after the "officially
- * undefined" opcode for parsing in the trap handler.
+ * The offending file and line are encoded encoded in the __bug_table section.
*/
#ifdef CONFIG_BUG
#define HAVE_ARCH_BUG
+
#ifdef CONFIG_DEBUG_BUGVERBOSE
-#define BUG() \
- __asm__ __volatile__( "ud2\n" \
- "\t.word %c0\n" \
- "\t.long %c1\n" \
- : : "i" (__LINE__), "i" (__FILE__))
+#define BUG() \
+ do { \
+ asm volatile("1:\tud2\n" \
+ ".pushsection __bug_table,\"a\"\n" \
+ "2:\t.long 1b, %c0\n" \
+ "\t.word %c1, 0\n" \
+ "\t.org 2b+%c2\n" \
+ ".popsection" \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (sizeof(struct bug_entry))); \
+ for(;;) ; \
+ } while(0)
+
#else
-#define BUG() __asm__ __volatile__("ud2\n")
+#define BUG() \
+ do { \
+ asm volatile("ud2"); \
+ for(;;) ; \
+ } while(0)
#endif
#endif
static __inline__ unsigned long ide_default_io_base(int index)
{
+ struct pci_dev *pdev;
/*
* If PCI is present then it is not safe to poke around
* the other legacy IDE ports. Only 0x1f0 and 0x170 are
* defined compatibility mode ports for PCI. A user can
* override this using ide= but we must default safe.
*/
- if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) {
+ if ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL)) == NULL) {
switch(index) {
case 2: return 0x1e8;
case 3: return 0x168;
case 5: return 0x160;
}
}
+ pci_dev_put(pdev);
switch (index) {
case 0: return 0x1f0;
case 1: return 0x170;
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
static __inline__ int ide_default_irq(unsigned long base)
{
switch (base) {
-#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \
+ || defined(CONFIG_PLAT_OPSPUT)
case 0x1f0: return PLD_IRQ_CFIREQ;
default:
return 0;
#define M32R_MFT5RLD_PORTL (0x0C+M32R_MFT5_OFFSET) /* MFT4 reload */
#define M32R_MFT5CMPRLD_PORTL (0x10+M32R_MFT5_OFFSET) /* MFT4 compare reload */
-#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_M32104)
+#if (defined(CONFIG_CHIP_M32700) && !defined(CONFIG_PLAT_MAPPI2)) \
+ || defined(CONFIG_CHIP_M32104)
#define M32R_MFTCR_MFT0MSK (1UL<<31) /* b0 */
#define M32R_MFTCR_MFT1MSK (1UL<<30) /* b1 */
#define M32R_MFTCR_MFT2MSK (1UL<<29) /* b2 */
#define M32R_MFTCR_MFT3EN (1UL<<20) /* b11 */
#define M32R_MFTCR_MFT4EN (1UL<<19) /* b12 */
#define M32R_MFTCR_MFT5EN (1UL<<18) /* b13 */
-#else /* not CONFIG_CHIP_M32700 && not CONFIG_CHIP_M32104 */
+#else
#define M32R_MFTCR_MFT0MSK (1UL<<15) /* b16 */
#define M32R_MFTCR_MFT1MSK (1UL<<14) /* b17 */
#define M32R_MFTCR_MFT2MSK (1UL<<13) /* b18 */
#define M32R_MFTCR_MFT3EN (1UL<<4) /* b27 */
#define M32R_MFTCR_MFT4EN (1UL<<3) /* b28 */
#define M32R_MFTCR_MFT5EN (1UL<<2) /* b29 */
-#endif /* not CONFIG_CHIP_M32700 && not CONFIG_CHIP_M32104 */
+#endif
#define M32R_MFTMOD_CC_MASK (1UL<<15) /* b16 */
#define M32R_MFTMOD_TCCR (1UL<<13) /* b18 */
#define PT_R15 PT_SP
/* processor status and miscellaneous context registers. */
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
#define PT_ACC0H 15
#define PT_ACC0L 16
-#define PT_ACC1H 17
-#define PT_ACC1L 18
-#define PT_ACCH PT_ACC0H
-#define PT_ACCL PT_ACC0L
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
-#define PT_ACCH 15
-#define PT_ACCL 16
-#define PT_DUMMY_ACC1H 17
-#define PT_DUMMY_ACC1L 18
-#else
-#error unknown isa conifiguration
-#endif
+#define PT_ACC1H 17 /* ISA_DSP_LEVEL2 only */
+#define PT_ACC1L 18 /* ISA_DSP_LEVEL2 only */
#define PT_PSW 19
#define PT_BPC 20
#define PT_BBPSW 21
long syscall_nr;
/* Saved main processor status and miscellaneous context registers. */
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
unsigned long acc0h;
unsigned long acc0l;
- unsigned long acc1h;
- unsigned long acc1l;
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
- unsigned long acch;
- unsigned long accl;
- unsigned long dummy_acc1h;
- unsigned long dummy_acc1l;
-#else
-#error unknown isa configuration
-#endif
+ unsigned long acc1h; /* ISA_DSP_LEVEL2 only */
+ unsigned long acc1l; /* ISA_DSP_LEVEL2 only */
unsigned long psw;
unsigned long bpc; /* saved PC for TRAP syscalls */
unsigned long bbpsw;
unsigned long sc_r12;
/* Saved main processor status and miscellaneous context registers. */
-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)
unsigned long sc_acc0h;
unsigned long sc_acc0l;
- unsigned long sc_acc1h;
- unsigned long sc_acc1l;
-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)
- unsigned long sc_acch;
- unsigned long sc_accl;
- unsigned long sc_dummy_acc1h;
- unsigned long sc_dummy_acc1l;
-#else
-#error unknown isa configuration
-#endif
+ unsigned long sc_acc1h; /* ISA_DSP_LEVEL2 only */
+ unsigned long sc_acc1l; /* ISA_DSP_LEVEL2 only */
unsigned long sc_psw;
unsigned long sc_bpc; /* saved PC for TRAP syscalls */
unsigned long sc_bbpsw;
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0 /* Interrupt character [ISIG]. */
#define VQUIT 1 /* Quit character [ISIG]. */
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
* Return the zero-based bit position (LE, not IBM bit numbering) of
* the most significant 1-bit in a double word.
*/
-static __inline__ int __ilog2(unsigned long x)
+static __inline__ __attribute__((const))
+int __ilog2(unsigned long x)
{
int lz;
return BITS_PER_LONG - 1 - lz;
}
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ int bit;
+ asm ("cntlzw %0,%1" : "=r" (bit) : "r" (n));
+ return 31 - bit;
+}
+
+#ifdef __powerpc64__
+static inline __attribute__((const))
+int __ilog2_u64(u32 n)
+{
+ int bit;
+ asm ("cntlzd %0,%1" : "=r" (bit) : "r" (n));
+ return 63 - bit;
+}
+#endif
+
/*
* Determines the bit position of the least significant 0 bit in the
* specified double word. The returned bit position will be
static inline void clear_page(void *page) { clear_pages(page, 0); }
extern void copy_page(void *to, void *from);
-/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
-{
- int lz;
-
- size = (size-1) >> PAGE_SHIFT;
- asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size));
- return 32 - lz;
-}
+#include <asm-generic/page.h>
#endif /* __ASSEMBLY__ */
speed_t c_ospeed; /* output speed */
};
+/* For PowerPC the termios and ktermios are the same */
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t c_line; /* line discipline (== c_cc[19]) */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
* 0x01: readonly (ro)
* 0x02: use diag discipline (diag)
* 0x04: set the device initially online (internal use only)
+ * 0x08: enable ERP related logging
*/
#define DASD_FEATURE_DEFAULT 0x00
#define DASD_FEATURE_READONLY 0x01
#define DASD_FEATURE_USEDIAG 0x02
#define DASD_FEATURE_INITIAL_ONLINE 0x04
+#define DASD_FEATURE_ERPLOG 0x08
#define DASD_PARTN_BITS 2
return skey;
}
+extern unsigned long max_pfn;
+
+static inline int pfn_valid(unsigned long pfn)
+{
+ unsigned long dummy;
+ int ccode;
+
+ if (pfn >= max_pfn)
+ return 0;
+
+ asm volatile(
+ " lra %0,0(%2)\n"
+ " ipm %1\n"
+ " srl %1,28\n"
+ : "=d" (dummy), "=d" (ccode)
+ : "a" (pfn << PAGE_SHIFT)
+ : "cc");
+ return !ccode;
+}
+
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
#define __va(x) (void *)(unsigned long)(x)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
-
-#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
* Page allocation orders.
*/
#ifndef __s390x__
+# define PTE_ALLOC_ORDER 0
+# define PMD_ALLOC_ORDER 0
# define PGD_ALLOC_ORDER 1
#else /* __s390x__ */
+# define PTE_ALLOC_ORDER 0
# define PMD_ALLOC_ORDER 2
# define PGD_ALLOC_ORDER 2
#endif /* __s390x__ */
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
+extern unsigned long vmalloc_end;
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \
& ~(VMALLOC_OFFSET-1))
+#define VMALLOC_END vmalloc_end
/*
* We need some free virtual space to be able to do vmalloc.
* VMALLOC_MIN_SIZE defines the minimum size of the vmalloc
* area. On a machine with 2GB memory we make sure that we
* have at least 128MB free space for vmalloc. On a machine
- * with 4TB we make sure we have at least 1GB.
+ * with 4TB we make sure we have at least 128GB.
*/
#ifndef __s390x__
#define VMALLOC_MIN_SIZE 0x8000000UL
-#define VMALLOC_END 0x80000000UL
+#define VMALLOC_END_INIT 0x80000000UL
#else /* __s390x__ */
-#define VMALLOC_MIN_SIZE 0x40000000UL
-#define VMALLOC_END 0x40000000000UL
+#define VMALLOC_MIN_SIZE 0x2000000000UL
+#define VMALLOC_END_INIT 0x40000000000UL
#endif /* __s390x__ */
/*
#define kern_addr_valid(addr) (1)
+extern int add_shared_memory(unsigned long start, unsigned long size);
+extern int remove_shared_memory(unsigned long start, unsigned long size);
+
/*
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
+#define __HAVE_ARCH_MEMMAP_INIT
+extern void memmap_init(unsigned long, int, unsigned long, unsigned long);
+
#define __HAVE_ARCH_PTEP_ESTABLISH
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#endif
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t _x_cc[2]; /* We need them to hold vmin/vtime */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#endif
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t _x_cc[2]; /* We need them to hold vmin/vtime */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#ifndef __UM_BUG_H
#define __UM_BUG_H
-#include <asm-generic/bug.h>
+
+#include <asm/arch/bug.h>
+
#endif
cc_t c_cc[NCCS]; /* control characters */
};
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#ifndef __ASM_X8664_BUG_H
#define __ASM_X8664_BUG_H 1
-#include <linux/stringify.h>
-
-/*
- * Tell the user there is some problem. The exception handler decodes
- * this frame.
- */
-struct bug_frame {
- unsigned char ud2[2];
- unsigned char push;
- signed int filename;
- unsigned char ret;
- unsigned short line;
-} __attribute__((packed));
-
#ifdef CONFIG_BUG
#define HAVE_ARCH_BUG
-/* We turn the bug frame into valid instructions to not confuse
- the disassembler. Thanks to Jan Beulich & Suresh Siddha
- for nice instruction selection.
- The magic numbers generate mov $64bitimm,%eax ; ret $offset. */
-#define BUG() \
- asm volatile( \
- "ud2 ; pushq $%c1 ; ret $%c0" :: \
- "i"(__LINE__), "i" (__FILE__))
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define BUG() \
+ do { \
+ asm volatile("1:\tud2\n" \
+ ".pushsection __bug_table,\"a\"\n" \
+ "2:\t.quad 1b, %c0\n" \
+ "\t.word %c1, 0\n" \
+ "\t.org 2b+%c2\n" \
+ ".popsection" \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (sizeof(struct bug_entry))); \
+ for(;;) ; \
+ } while(0)
+#else
+#define BUG() \
+ do { \
+ asm volatile("ud2"); \
+ for(;;) ; \
+ } while(0)
+#endif
+
void out_of_line_bug(void);
#else
static inline void out_of_line_bug(void) { }
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
cc_t c_cc[NCCS]; /* control characters */
};
+struct termios2 {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
/* c_cc characters */
#define VINTR 0
#define VQUIT 1
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000 /* non standard rate */
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 8 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
--- /dev/null
+#ifndef _LINUX_BITREV_H
+#define _LINUX_BITREV_H
+
+#include <linux/types.h>
+
+extern u8 const byte_rev_table[256];
+
+static inline u8 bitrev8(u8 byte)
+{
+ return byte_rev_table[byte];
+}
+
+extern u32 bitrev32(u32 in);
+
+#endif /* _LINUX_BITREV_H */
--- /dev/null
+#ifndef _LINUX_BUG_H
+#define _LINUX_BUG_H
+
+#include <linux/module.h>
+#include <asm/bug.h>
+
+enum bug_trap_type {
+ BUG_TRAP_TYPE_NONE = 0,
+ BUG_TRAP_TYPE_WARN = 1,
+ BUG_TRAP_TYPE_BUG = 2,
+};
+
+#ifdef CONFIG_GENERIC_BUG
+#include <asm-generic/bug.h>
+
+static inline int is_warning_bug(const struct bug_entry *bug)
+{
+ return bug->flags & BUGFLAG_WARNING;
+}
+
+const struct bug_entry *find_bug(unsigned long bugaddr);
+
+enum bug_trap_type report_bug(unsigned long bug_addr);
+
+int module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+ struct module *);
+void module_bug_cleanup(struct module *);
+
+/* These are defined by the architecture */
+int is_valid_bugaddr(unsigned long addr);
+
+#else /* !CONFIG_GENERIC_BUG */
+
+static inline enum bug_trap_type report_bug(unsigned long bug_addr)
+{
+ return BUG_TRAP_TYPE_BUG;
+}
+static inline int module_bug_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *mod)
+{
+ return 0;
+}
+static inline void module_bug_cleanup(struct module *mod) {}
+
+#endif /* CONFIG_GENERIC_BUG */
+#endif /* _LINUX_BUG_H */
#define _LINUX_CRC32_H
#include <linux/types.h>
+#include <linux/bitrev.h>
extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len);
extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len);
-extern u32 bitreverse(u32 in);
#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length)
* is in bit nr 0], thus it must be reversed before use. Except for
* nics that bit swap the result internally...
*/
-#define ether_crc(length, data) bitreverse(crc32_le(~0, data, length))
+#define ether_crc(length, data) bitrev32(crc32_le(~0, data, length))
#define ether_crc_le(length, data) crc32_le(~0, data, length)
#endif /* _LINUX_CRC32_H */
* The map function must return:
* < 0: error
* = 0: The target will handle the io by resubmitting it later
- * > 0: simple remap complete
+ * = 1: simple remap complete
+ * = 2: The target wants to push back the io
*/
typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio,
union map_info *map_context);
* 0 : ended successfully
* 1 : for some reason the io has still not completed (eg,
* multipath target might want to requeue a failed io).
+ * 2 : The target wants to push back the io
*/
typedef int (*dm_endio_fn) (struct dm_target *ti,
struct bio *bio, int error,
/*
* A device can still be used while suspended, but I/O is deferred.
*/
-int dm_suspend(struct mapped_device *md, int with_lockfs);
+int dm_suspend(struct mapped_device *md, unsigned suspend_flags);
int dm_resume(struct mapped_device *md);
/*
const char *dm_device_name(struct mapped_device *md);
struct gendisk *dm_disk(struct mapped_device *md);
int dm_suspended(struct mapped_device *md);
+int dm_noflush_suspending(struct dm_target *ti);
/*
* Geometry functions.
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
#define DM_VERSION_MAJOR 4
-#define DM_VERSION_MINOR 10
+#define DM_VERSION_MINOR 11
#define DM_VERSION_PATCHLEVEL 0
-#define DM_VERSION_EXTRA "-ioctl (2006-09-14)"
+#define DM_VERSION_EXTRA "-ioctl (2006-10-12)"
/* Status bits */
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
*/
#define DM_SKIP_LOCKFS_FLAG (1 << 10) /* In */
+/*
+ * Set this to suspend without flushing queued ios.
+ */
+#define DM_NOFLUSH_FLAG (1 << 11) /* In */
+
#endif /* _LINUX_DM_IOCTL_H */
--- /dev/null
+#ifndef _LINUX_FAULT_INJECT_H
+#define _LINUX_FAULT_INJECT_H
+
+#ifdef CONFIG_FAULT_INJECTION
+
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include <asm/atomic.h>
+
+/*
+ * For explanation of the elements of this struct, see
+ * Documentation/fault-injection/fault-injection.txt
+ */
+struct fault_attr {
+ unsigned long probability;
+ unsigned long interval;
+ atomic_t times;
+ atomic_t space;
+ unsigned long verbose;
+ u32 task_filter;
+ unsigned long stacktrace_depth;
+ unsigned long require_start;
+ unsigned long require_end;
+ unsigned long reject_start;
+ unsigned long reject_end;
+
+ unsigned long count;
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+ struct {
+ struct dentry *dir;
+
+ struct dentry *probability_file;
+ struct dentry *interval_file;
+ struct dentry *times_file;
+ struct dentry *space_file;
+ struct dentry *verbose_file;
+ struct dentry *task_filter_file;
+ struct dentry *stacktrace_depth_file;
+ struct dentry *require_start_file;
+ struct dentry *require_end_file;
+ struct dentry *reject_start_file;
+ struct dentry *reject_end_file;
+ } dentries;
+
+#endif
+};
+
+#define FAULT_ATTR_INITIALIZER { \
+ .interval = 1, \
+ .times = ATOMIC_INIT(1), \
+ .require_end = ULONG_MAX, \
+ .stacktrace_depth = 32, \
+ .verbose = 2, \
+ }
+
+#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER
+int setup_fault_attr(struct fault_attr *attr, char *str);
+void should_fail_srandom(unsigned long entropy);
+bool should_fail(struct fault_attr *attr, ssize_t size);
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+int init_fault_attr_dentries(struct fault_attr *attr, const char *name);
+void cleanup_fault_attr_dentries(struct fault_attr *attr);
+
+#else /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+static inline int init_fault_attr_dentries(struct fault_attr *attr,
+ const char *name)
+{
+ return -ENODEV;
+}
+
+static inline void cleanup_fault_attr_dentries(struct fault_attr *attr)
+{
+}
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#endif /* CONFIG_FAULT_INJECTION */
+
+#endif /* _LINUX_FAULT_INJECT_H */
/* drivers/video/fbcmap.c */
extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp);
extern void fb_dealloc_cmap(struct fb_cmap *cmap);
-extern int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to);
-extern int fb_cmap_to_user(struct fb_cmap *from, struct fb_cmap_user *to);
+extern int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to);
+extern int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to);
extern int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info);
extern int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *fb_info);
-extern struct fb_cmap *fb_default_cmap(int len);
+extern const struct fb_cmap *fb_default_cmap(int len);
extern void fb_invert_cmaps(void);
struct fb_videomode {
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/dcache.h>
+#include <linux/namei.h>
#include <linux/stat.h>
#include <linux/cache.h>
#include <linux/kobject.h>
unsigned long bd_private;
};
-/*
- * bdev->bd_mutex nesting subclasses for the lock validator:
- *
- * 0: normal
- * 1: 'whole'
- * 2: 'partition'
- */
-enum bdev_bd_mutex_lock_class
-{
- BD_MUTEX_NORMAL,
- BD_MUTEX_WHOLE,
- BD_MUTEX_PARTITION
-};
-
-
/*
* Radix-tree tags, for tagging dirty and writeback pages within the pagecache
* radix trees
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
- struct dentry *f_dentry;
- struct vfsmount *f_vfsmnt;
+ struct path f_path;
+#define f_dentry f_path.dentry
+#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
static inline void file_accessed(struct file *file)
{
if (!(file->f_flags & O_NOATIME))
- touch_atime(file->f_vfsmnt, file->f_dentry);
+ touch_atime(file->f_path.mnt, file->f_path.dentry);
}
int sync_inode(struct inode *inode, struct writeback_control *wbc);
extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
extern struct block_device *open_by_devnum(dev_t, unsigned);
-extern struct block_device *open_partition_by_devnum(dev_t, unsigned);
extern const struct address_space_operations def_blk_aops;
#else
static inline void bd_forget(struct inode *inode) {}
extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
extern int blkdev_get(struct block_device *, mode_t, unsigned);
extern int blkdev_put(struct block_device *);
-extern int blkdev_put_partition(struct block_device *);
extern int bd_claim(struct block_device *, void *);
extern void bd_release(struct block_device *);
#ifdef CONFIG_SYSFS
static inline void allow_write_access(struct file *file)
{
if (file)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
+ atomic_inc(&file->f_path.dentry->d_inode->i_writecount);
}
extern int do_pipe(int *);
extern struct file *create_read_pipe(struct file *f);
--- /dev/null
+#ifndef _LINUX_FS_STACK_H
+#define _LINUX_FS_STACK_H
+
+/* This file defines generic functions used primarily by stackable
+ * filesystems; none of these functions require i_mutex to be held.
+ */
+
+#include <linux/fs.h>
+
+/* externs for fs/stack.c */
+extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src,
+ int (*get_nlinks)(struct inode *));
+
+extern void fsstack_copy_inode_size(struct inode *dst, const struct inode *src);
+
+/* inlines */
+static inline void fsstack_copy_attr_atime(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+}
+
+static inline void fsstack_copy_attr_times(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+}
+
+#endif /* _LINUX_FS_STACK_H */
*/
static inline void fsnotify_close(struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
const char *name = dentry->d_name.name;
mode_t mode = file->f_mode;
int gs_block_til_ready(void *port, struct file *filp);
void gs_close(struct tty_struct *tty, struct file *filp);
void gs_set_termios (struct tty_struct * tty,
- struct termios * old_termios);
+ struct ktermios * old_termios);
int gs_init_port(struct gs_port *port);
int gs_setserial(struct gs_port *port, struct serial_struct __user *sp);
int gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
struct kobject *holder_dir;
unsigned ios[2], sectors[2]; /* READs and WRITEs */
int policy, partno;
+#ifdef CONFIG_FAIL_MAKE_REQUEST
+ int make_it_fail;
+#endif
};
#define GENHD_FL_REMOVABLE 1
#define GENHD_FL_CD 8
#define GENHD_FL_UP 16
#define GENHD_FL_SUPPRESS_PARTITION_INFO 32
+#define GENHD_FL_FAIL 64
struct disk_stats {
unsigned long sectors[2]; /* READs and WRITEs */
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2006 Jiri Kosina
*/
/*
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <linux/input.h>
/*
* USB HID (Human Interface Device) interface class code
#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000
#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000
#define HID_QUIRK_INVERT_HWHEEL 0x00004000
-#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000
+#define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000
+#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000
/*
* This is the global environment of the parser. This information is
unsigned collection_size; /* Number of allocated hid_collections */
unsigned maxcollection; /* Number of parsed collections */
unsigned maxapplication; /* Number of applications */
+ unsigned short bus; /* BUS ID */
+ unsigned short vendor; /* Vendor ID */
+ unsigned short product; /* Product ID */
unsigned version; /* HID version */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
- struct usb_device *dev; /* USB device */
- struct usb_interface *intf; /* USB interface */
- int ifnum; /* USB interface number */
-
- unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
- struct timer_list io_retry; /* Retry timer */
- unsigned long stop_retry; /* Time to give up, in jiffies */
- unsigned int retry_delay; /* Delay length in ms */
- struct work_struct reset_work; /* Task context for resets */
-
- unsigned int bufsize; /* URB buffer size */
-
- struct urb *urbin; /* Input URB */
- char *inbuf; /* Input buffer */
- dma_addr_t inbuf_dma; /* Input buffer dma */
- spinlock_t inlock; /* Input fifo spinlock */
-
- struct urb *urbctrl; /* Control URB */
- struct usb_ctrlrequest *cr; /* Control request struct */
- dma_addr_t cr_dma; /* Control request struct dma */
- struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
- unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
- char *ctrlbuf; /* Control buffer */
- dma_addr_t ctrlbuf_dma; /* Control buffer dma */
- spinlock_t ctrllock; /* Control fifo spinlock */
-
- struct urb *urbout; /* Output URB */
- struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
- unsigned char outhead, outtail; /* Output pipe fifo head & tail */
- char *outbuf; /* Output buffer */
- dma_addr_t outbuf_dma; /* Output buffer dma */
- spinlock_t outlock; /* Output fifo spinlock */
+ struct device *dev; /* device */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
char phys[64]; /* Device physical location */
char uniq[64]; /* Device unique identifier (serial #) */
+ void *driver_data;
+
+ /* device-specific function pointers */
+ int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
+ int (*hidinput_open) (struct input_dev *);
+ void (*hidinput_close) (struct input_dev *);
+
+ /* hiddev event handler */
+ void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
+ struct hid_usage *, __s32);
+ void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+ unsigned int pb_fnmode;
unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
#endif
#define resolv_event(a,b) do { } while (0)
#endif
-#endif
-
-#ifdef CONFIG_USB_HIDINPUT
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
+
+/* HID core API */
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
extern int hidinput_connect(struct hid_device *);
extern void hidinput_disconnect(struct hid_device *);
-#else
-#define IS_INPUT_APPLICATION(a) (0)
-static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
-static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { }
-static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
-static inline void hidinput_disconnect(struct hid_device *hid) { }
-#endif
-int hid_open(struct hid_device *);
-void hid_close(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
-void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
-void hid_init_reports(struct hid_device *hid);
-int hid_wait_io(struct hid_device* hid);
-
+int hid_input_report(struct hid_device *, int type, u8 *, int, int);
+int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
+void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
+void hid_output_report(struct hid_report *report, __u8 *data);
+void hid_free_device(struct hid_device *device);
+struct hid_device *hid_parse_report(__u8 *start, unsigned size);
#ifdef CONFIG_HID_FF
int hid_ff_init(struct hid_device *hid);
#else
static inline int hid_ff_init(struct hid_device *hid) { return -1; }
#endif
+#ifdef DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
+ __FILE__ , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
+ __FILE__ , ## arg)
+#endif
#include <linux/utsname.h>
#include <linux/lockdep.h>
#include <linux/ipc.h>
+#include <linux/pid_namespace.h>
#define INIT_FDTABLE \
{ \
.cpu_vm_mask = CPU_MASK_ALL, \
}
-#define INIT_SIGNALS(sig) { \
- .count = ATOMIC_INIT(1), \
+#define INIT_SIGNALS(sig) { \
+ .count = ATOMIC_INIT(1), \
.wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
- .shared_pending = { \
+ .shared_pending = { \
.list = LIST_HEAD_INIT(sig.shared_pending.list), \
- .signal = {{0}}}, \
+ .signal = {{0}}}, \
.posix_timers = LIST_HEAD_INIT(sig.posix_timers), \
.cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \
.rlim = INIT_RLIMITS, \
.pgrp = 1, \
- .session = 1, \
+ .tty_old_pgrp = 0, \
+ { .__session = 1}, \
}
extern struct nsproxy init_nsproxy;
#define INIT_NSPROXY(nsproxy) { \
+ .pid_ns = &init_pid_ns, \
.count = ATOMIC_INIT(1), \
.nslock = __SPIN_LOCK_UNLOCKED(nsproxy.nslock), \
+ .id = 0, \
.uts_ns = &init_uts_ns, \
- .namespace = NULL, \
+ .mnt_ns = NULL, \
INIT_IPC_NS(ipc_ns) \
}
#define BUS_GSC 0x1A
/*
- * Values describing the status of an effect
+ * Values describing the status of a force-feedback effect
*/
#define FF_STATUS_STOPPED 0x00
#define FF_STATUS_PLAYING 0x01
*/
/**
- * struct ff_replay - defines scheduling of the effect
+ * struct ff_replay - defines scheduling of the force-feedback effect
* @length: duration of the effect
* @delay: delay before effect should start playing
*/
};
/**
- * struct ff_trigger - defines what triggers the effect
+ * struct ff_trigger - defines what triggers the force-feedback effect
* @button: number of the button triggering the effect
* @interval: controls how soon the effect can be re-triggered
*/
};
/**
- * struct ff_envelope - generic effect envelope
+ * struct ff_envelope - generic force-feedback effect envelope
* @attack_length: duration of the attack (ms)
* @attack_level: level at the beginning of the attack
* @fade_length: duration of fade (ms)
};
/**
- * struct ff_constant_effect - defines parameters of a constant effect
+ * struct ff_constant_effect - defines parameters of a constant force-feedback effect
* @level: strength of the effect; may be negative
* @envelope: envelope data
*/
};
/**
- * struct ff_ramp_effect - defines parameters of a ramp effect
+ * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect
* @start_level: beginning strength of the effect; may be negative
* @end_level: final strength of the effect; may be negative
* @envelope: envelope data
};
/**
- * struct ff_condition_effect - defines a spring or friction effect
+ * struct ff_condition_effect - defines a spring or friction force-feedback effect
* @right_saturation: maximum level when joystick moved all way to the right
* @left_saturation: same for the left side
* @right_coeff: controls how fast the force grows when the joystick moves
};
/**
- * struct ff_periodic_effect - defines parameters of a periodic effect
+ * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect
* @waveform: kind of the effect (wave)
* @period: period of the wave (ms)
* @magnitude: peak value
};
/**
- * struct ff_rumble_effect - defines parameters of a periodic effect
+ * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect
* @strong_magnitude: magnitude of the heavy motor
* @weak_magnitude: magnitude of the light one
*
#endif
struct tty_struct *tty; /* Pointer to corresponding tty */
atemu emu; /* AT-emulator data */
- struct termios normal_termios; /* For saving termios structs */
- struct termios callout_termios;
+ struct ktermios normal_termios; /* For saving termios structs */
+ struct ktermios callout_termios;
wait_queue_head_t open_wait, close_wait;
struct semaphore write_sem;
spinlock_t readlock;
int refcount; /* Number of opens */
struct tty_driver *tty_modem; /* tty-device */
struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
- struct termios *modem_termios[ISDN_MAX_CHANNELS];
- struct termios *modem_termios_locked[ISDN_MAX_CHANNELS];
+ struct ktermios *modem_termios[ISDN_MAX_CHANNELS];
+ struct ktermios *modem_termios_locked[ISDN_MAX_CHANNELS];
modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
} isdn_modem_t;
* communication with the slave board will always be on a per port
* basis.
*/
-typedef struct {
+struct stliport {
unsigned long magic;
- int portnr;
- int panelnr;
- int brdnr;
+ unsigned int portnr;
+ unsigned int panelnr;
+ unsigned int brdnr;
unsigned long state;
- int devnr;
+ unsigned int devnr;
int flags;
int baud_base;
int custom_divisor;
wait_queue_head_t close_wait;
wait_queue_head_t raw_wait;
struct work_struct tqhangup;
- asysigs_t asig;
+ struct asysigs asig;
unsigned long addr;
unsigned long rxoffset;
unsigned long txoffset;
unsigned char reqbit;
unsigned char portidx;
unsigned char portbit;
-} stliport_t;
+};
/*
* Use a structure of function pointers to do board level operations.
* These include, enable/disable, paging shared memory, interrupting, etc.
*/
-typedef struct stlibrd {
+struct stlibrd {
unsigned long magic;
- int brdnr;
- int brdtype;
- int state;
- int nrpanels;
- int nrports;
- int nrdevs;
+ unsigned int brdnr;
+ unsigned int brdtype;
+ unsigned int state;
+ unsigned int nrpanels;
+ unsigned int nrports;
+ unsigned int nrdevs;
unsigned int iobase;
int iosize;
unsigned long memaddr;
void __iomem *membase;
- int memsize;
+ unsigned long memsize;
int pagesize;
int hostoffset;
int slaveoffset;
int bitsize;
int enabval;
- int panels[STL_MAXPANELS];
+ unsigned int panels[STL_MAXPANELS];
int panelids[STL_MAXPANELS];
void (*init)(struct stlibrd *brdp);
void (*enable)(struct stlibrd *brdp);
void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
void (*intr)(struct stlibrd *brdp);
void (*reset)(struct stlibrd *brdp);
- stliport_t *ports[STL_MAXPORTS];
-} stlibrd_t;
+ struct stliport *ports[STL_MAXPORTS];
+};
/*
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/bitops.h>
+#include <linux/log2.h>
#include <asm/byteorder.h>
#include <asm/bug.h>
unsigned long int_sqrt(unsigned long);
-static inline int __attribute_pure__ long_log2(unsigned long x)
-{
- int r = 0;
- for (x >>= 1; x > 0; x >>= 1)
- r++;
- return r;
-}
-
-static inline unsigned long
-__attribute_const__ roundup_pow_of_two(unsigned long x)
-{
- return 1UL << fls_long(x - 1);
-}
-
extern int printk_ratelimit(void);
extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
static __inline__ struct inode *
nlmsvc_file_inode(struct nlm_file *file)
{
- return file->f_file->f_dentry->d_inode;
+ return file->f_file->f_path.dentry->d_inode;
}
/*
--- /dev/null
+/* Integer base 2 logarithm calculation
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_LOG2_H
+#define _LINUX_LOG2_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const, noreturn))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ * more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+#ifndef CONFIG_ARCH_HAS_ILOG2_U32
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+ return fls(n) - 1;
+}
+#endif
+
+#ifndef CONFIG_ARCH_HAS_ILOG2_U64
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+ return fls64(n) - 1;
+}
+#endif
+
+/*
+ * round up to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __roundup_pow_of_two(unsigned long n)
+{
+ return 1UL << fls_long(n - 1);
+}
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ * the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n) < 1 ? ____ilog2_NaN() : \
+ (n) & (1ULL << 63) ? 63 : \
+ (n) & (1ULL << 62) ? 62 : \
+ (n) & (1ULL << 61) ? 61 : \
+ (n) & (1ULL << 60) ? 60 : \
+ (n) & (1ULL << 59) ? 59 : \
+ (n) & (1ULL << 58) ? 58 : \
+ (n) & (1ULL << 57) ? 57 : \
+ (n) & (1ULL << 56) ? 56 : \
+ (n) & (1ULL << 55) ? 55 : \
+ (n) & (1ULL << 54) ? 54 : \
+ (n) & (1ULL << 53) ? 53 : \
+ (n) & (1ULL << 52) ? 52 : \
+ (n) & (1ULL << 51) ? 51 : \
+ (n) & (1ULL << 50) ? 50 : \
+ (n) & (1ULL << 49) ? 49 : \
+ (n) & (1ULL << 48) ? 48 : \
+ (n) & (1ULL << 47) ? 47 : \
+ (n) & (1ULL << 46) ? 46 : \
+ (n) & (1ULL << 45) ? 45 : \
+ (n) & (1ULL << 44) ? 44 : \
+ (n) & (1ULL << 43) ? 43 : \
+ (n) & (1ULL << 42) ? 42 : \
+ (n) & (1ULL << 41) ? 41 : \
+ (n) & (1ULL << 40) ? 40 : \
+ (n) & (1ULL << 39) ? 39 : \
+ (n) & (1ULL << 38) ? 38 : \
+ (n) & (1ULL << 37) ? 37 : \
+ (n) & (1ULL << 36) ? 36 : \
+ (n) & (1ULL << 35) ? 35 : \
+ (n) & (1ULL << 34) ? 34 : \
+ (n) & (1ULL << 33) ? 33 : \
+ (n) & (1ULL << 32) ? 32 : \
+ (n) & (1ULL << 31) ? 31 : \
+ (n) & (1ULL << 30) ? 30 : \
+ (n) & (1ULL << 29) ? 29 : \
+ (n) & (1ULL << 28) ? 28 : \
+ (n) & (1ULL << 27) ? 27 : \
+ (n) & (1ULL << 26) ? 26 : \
+ (n) & (1ULL << 25) ? 25 : \
+ (n) & (1ULL << 24) ? 24 : \
+ (n) & (1ULL << 23) ? 23 : \
+ (n) & (1ULL << 22) ? 22 : \
+ (n) & (1ULL << 21) ? 21 : \
+ (n) & (1ULL << 20) ? 20 : \
+ (n) & (1ULL << 19) ? 19 : \
+ (n) & (1ULL << 18) ? 18 : \
+ (n) & (1ULL << 17) ? 17 : \
+ (n) & (1ULL << 16) ? 16 : \
+ (n) & (1ULL << 15) ? 15 : \
+ (n) & (1ULL << 14) ? 14 : \
+ (n) & (1ULL << 13) ? 13 : \
+ (n) & (1ULL << 12) ? 12 : \
+ (n) & (1ULL << 11) ? 11 : \
+ (n) & (1ULL << 10) ? 10 : \
+ (n) & (1ULL << 9) ? 9 : \
+ (n) & (1ULL << 8) ? 8 : \
+ (n) & (1ULL << 7) ? 7 : \
+ (n) & (1ULL << 6) ? 6 : \
+ (n) & (1ULL << 5) ? 5 : \
+ (n) & (1ULL << 4) ? 4 : \
+ (n) & (1ULL << 3) ? 3 : \
+ (n) & (1ULL << 2) ? 2 : \
+ (n) & (1ULL << 1) ? 1 : \
+ (n) & (1ULL << 0) ? 0 : \
+ ____ilog2_NaN() \
+ ) : \
+ (sizeof(n) <= 4) ? \
+ __ilog2_u32(n) : \
+ __ilog2_u64(n) \
+ )
+
+/**
+ * roundup_pow_of_two - round the given value up to nearest power of two
+ * @n - parameter
+ *
+ * round the given balue up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ (n == 1) ? 0 : \
+ (1UL << (ilog2((n) - 1) + 1)) \
+ ) : \
+ __roundup_pow_of_two(n) \
+ )
+
+#endif /* _LINUX_LOG2_H */
--- /dev/null
+#ifndef _NAMESPACE_H_
+#define _NAMESPACE_H_
+#ifdef __KERNEL__
+
+#include <linux/mount.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+
+struct mnt_namespace {
+ atomic_t count;
+ struct vfsmount * root;
+ struct list_head list;
+ wait_queue_head_t poll;
+ int event;
+};
+
+extern int copy_mnt_ns(int, struct task_struct *);
+extern void __put_mnt_ns(struct mnt_namespace *ns);
+extern struct mnt_namespace *dup_mnt_ns(struct task_struct *,
+ struct fs_struct *);
+
+static inline void put_mnt_ns(struct mnt_namespace *ns)
+{
+ if (atomic_dec_and_lock(&ns->count, &vfsmount_lock))
+ /* releases vfsmount_lock */
+ __put_mnt_ns(ns);
+}
+
+static inline void exit_mnt_ns(struct task_struct *p)
+{
+ struct mnt_namespace *ns = p->nsproxy->mnt_ns;
+ if (ns)
+ put_mnt_ns(ns);
+}
+
+static inline void get_mnt_ns(struct mnt_namespace *ns)
+{
+ atomic_inc(&ns->count);
+}
+
+#endif
+#endif
unsigned int taints; /* same bits as kernel:tainted */
+#ifdef CONFIG_GENERIC_BUG
+ /* Support for BUG */
+ struct list_head bug_list;
+ struct bug_entry *bug_table;
+ unsigned num_bugs;
+#endif
+
#ifdef CONFIG_MODULE_UNLOAD
/* Reference counts */
struct module_ref ref[NR_CPUS];
struct super_block;
struct vfsmount;
struct dentry;
-struct namespace;
+struct mnt_namespace;
#define MNT_NOSUID 0x01
#define MNT_NODEV 0x02
struct list_head mnt_slave_list;/* list of slave mounts */
struct list_head mnt_slave; /* slave list entry */
struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
- struct namespace *mnt_namespace; /* containing namespace */
+ struct mnt_namespace *mnt_ns; /* containing namespace */
int mnt_pinned;
};
#ifdef CONFIG_DEBUG_LOCK_ALLOC
extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+extern int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass);
#else
# define mutex_lock_nested(lock, subclass) mutex_lock(lock)
+# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
#endif
/*
} intent;
};
+struct path {
+ struct vfsmount *mnt;
+ struct dentry *dentry;
+};
+
/*
* Type of the last component on LOOKUP_PARENT
*/
+++ /dev/null
-#ifndef _NAMESPACE_H_
-#define _NAMESPACE_H_
-#ifdef __KERNEL__
-
-#include <linux/mount.h>
-#include <linux/sched.h>
-#include <linux/nsproxy.h>
-
-struct namespace {
- atomic_t count;
- struct vfsmount * root;
- struct list_head list;
- wait_queue_head_t poll;
- int event;
-};
-
-extern int copy_namespace(int, struct task_struct *);
-extern void __put_namespace(struct namespace *namespace);
-extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *);
-
-static inline void put_namespace(struct namespace *namespace)
-{
- if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock))
- /* releases vfsmount_lock */
- __put_namespace(namespace);
-}
-
-static inline void exit_namespace(struct task_struct *p)
-{
- struct namespace *namespace = p->nsproxy->namespace;
- if (namespace) {
- put_namespace(namespace);
- }
-}
-
-static inline void get_namespace(struct namespace *namespace)
-{
- atomic_inc(&namespace->count);
-}
-
-#endif
-#endif
#include <linux/spinlock.h>
#include <linux/sched.h>
-struct namespace;
+struct mnt_namespace;
struct uts_namespace;
struct ipc_namespace;
+struct pid_namespace;
/*
* A structure to contain pointers to all per-process
struct nsproxy {
atomic_t count;
spinlock_t nslock;
+ unsigned long id;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
- struct namespace *namespace;
+ struct mnt_namespace *mnt_ns;
+ struct pid_namespace *pid_ns;
};
extern struct nsproxy init_nsproxy;
#define PCI_DEVICE_ID_MOXA_C104 0x1040
#define PCI_DEVICE_ID_MOXA_CP104U 0x1041
#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042
+#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043
#define PCI_DEVICE_ID_MOXA_CT114 0x1140
#define PCI_DEVICE_ID_MOXA_CP114 0x1141
#define PCI_DEVICE_ID_MOXA_CP118U 0x1180
+#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181
#define PCI_DEVICE_ID_MOXA_CP132 0x1320
#define PCI_DEVICE_ID_MOXA_CP132U 0x1321
#define PCI_DEVICE_ID_MOXA_CP134U 0x1340
#define PCI_DEVICE_ID_MOXA_C168 0x1680
#define PCI_DEVICE_ID_MOXA_CP168U 0x1681
+#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682
#define PCI_VENDOR_ID_CCD 0x1397
#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0
*
* Holding a reference to struct pid solves both of these problems.
* It is small so holding a reference does not consume a lot of
- * resources, and since a new struct pid is allocated when the numeric
- * pid value is reused we don't mistakenly refer to new processes.
+ * resources, and since a new struct pid is allocated when the numeric pid
+ * value is reused (when pids wrap around) we don't mistakenly refer to new
+ * processes.
*/
struct pid
--- /dev/null
+#ifndef _LINUX_PID_NS_H
+#define _LINUX_PID_NS_H
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <linux/pid.h>
+#include <linux/nsproxy.h>
+#include <linux/kref.h>
+
+struct pidmap {
+ atomic_t nr_free;
+ void *page;
+};
+
+#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
+
+struct pid_namespace {
+ struct kref kref;
+ struct pidmap pidmap[PIDMAP_ENTRIES];
+ int last_pid;
+ struct task_struct *child_reaper;
+};
+
+extern struct pid_namespace init_pid_ns;
+
+static inline void get_pid_ns(struct pid_namespace *ns)
+{
+ kref_get(&ns->kref);
+}
+
+extern int copy_pid_ns(int flags, struct task_struct *tsk);
+extern void free_pid_ns(struct kref *kref);
+
+static inline void put_pid_ns(struct pid_namespace *ns)
+{
+ kref_put(&ns->kref, free_pid_ns);
+}
+
+static inline struct task_struct *child_reaper(struct task_struct *tsk)
+{
+ return tsk->nsproxy->pid_ns->child_reaper;
+}
+
+#endif /* _LINUX_PID_NS_H */
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/cdrom.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+/* default bio write queue congestion marks */
+#define PKT_WRITE_CONGESTION_ON 10000
+#define PKT_WRITE_CONGESTION_OFF 9000
+
struct packet_settings
{
};
#define PSD_POOL_SIZE 64
+struct pktcdvd_kobj
+{
+ struct kobject kobj;
+ struct pktcdvd_device *pd;
+};
+#define to_pktcdvdkobj(_k) \
+ ((struct pktcdvd_kobj*)container_of(_k,struct pktcdvd_kobj,kobj))
+
struct pktcdvd_device
{
struct block_device *bdev; /* dev attached */
struct packet_iosched iosched;
struct gendisk *disk;
+
+ int write_congestion_off;
+ int write_congestion_on;
+
+ struct class_device *clsdev; /* sysfs pktcdvd[0-7] class dev */
+ struct pktcdvd_kobj *kobj_stat; /* sysfs pktcdvd[0-7]/stat/ */
+ struct pktcdvd_kobj *kobj_wqueue; /* sysfs pktcdvd[0-7]/write_queue/ */
+
+ struct dentry *dfs_d_root; /* debugfs: devname directory */
+ struct dentry *dfs_f_info; /* debugfs: info file */
};
#endif /* __KERNEL__ */
+++ /dev/null
-#ifndef _LINUX_PSPACE_H
-#define _LINUX_PSPACE_H
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/threads.h>
-#include <linux/pid.h>
-
-struct pidmap {
- atomic_t nr_free;
- void *page;
-};
-
-#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
-
-struct pspace {
- struct pidmap pidmap[PIDMAP_ENTRIES];
- int last_pid;
-};
-
-extern struct pspace init_pspace;
-
-#endif /* _LINUX_PSPACE_H */
#define PATH_READA 0x1 /* do read ahead */
#define PATH_READA_BACK 0x2 /* read backwards */
-struct path {
+struct treepath {
int path_length; /* Length of the array above. */
int reada;
struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */
#define pos_in_item(path) ((path)->pos_in_item)
#define INITIALIZE_PATH(var) \
-struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
/* Get path element by path and path position. */
#define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset))
int need_balance_dirty;
struct super_block *tb_sb;
struct reiserfs_transaction_handle *transaction_handle;
- struct path *tb_path;
+ struct treepath *tb_path;
struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */
struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */
struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */
memcpy(to, from, KEY_SIZE);
}
-int comp_items(const struct item_head *stored_ih, const struct path *p_s_path);
-const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
+int comp_items(const struct item_head *stored_ih, const struct treepath *p_s_path);
+const struct reiserfs_key *get_rkey(const struct treepath *p_s_chk_path,
const struct super_block *p_s_sb);
int search_by_key(struct super_block *, const struct cpu_key *,
- struct path *, int);
+ struct treepath *, int);
#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
int search_for_position_by_key(struct super_block *p_s_sb,
const struct cpu_key *p_s_cpu_key,
- struct path *p_s_search_path);
+ struct treepath *p_s_search_path);
extern void decrement_bcount(struct buffer_head *p_s_bh);
-void decrement_counters_in_path(struct path *p_s_search_path);
-void pathrelse(struct path *p_s_search_path);
-int reiserfs_check_path(struct path *p);
-void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path);
+void decrement_counters_in_path(struct treepath *p_s_search_path);
+void pathrelse(struct treepath *p_s_search_path);
+int reiserfs_check_path(struct treepath *p);
+void pathrelse_and_restore(struct super_block *s, struct treepath *p_s_search_path);
int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
const struct cpu_key *key,
struct item_head *ih,
struct inode *inode, const char *body);
int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
const struct cpu_key *key,
struct inode *inode,
const char *body, int paste_size);
int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
struct cpu_key *key,
struct inode *inode,
struct page *page, loff_t new_file_size);
int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
- struct path *path,
+ struct treepath *path,
const struct cpu_key *key,
struct inode *inode, struct buffer_head *p_s_un_bh);
#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */
int restart_transaction(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path);
+ struct inode *inode, struct treepath *path);
void reiserfs_read_locked_inode(struct inode *inode,
struct reiserfs_iget_args *args);
int reiserfs_find_actor(struct inode *inode, void *p);
/* namei.c */
void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
- struct path *path, struct reiserfs_dir_entry *de);
+ struct treepath *path, struct reiserfs_dir_entry *de);
struct dentry *reiserfs_get_parent(struct dentry *);
/* procfs.c */
/* tail_conversion.c */
int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
- struct path *, struct buffer_head *, loff_t);
+ struct treepath *, struct buffer_head *, loff_t);
int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
- struct page *, struct path *, const struct cpu_key *,
+ struct page *, struct treepath *, const struct cpu_key *,
loff_t, char *);
void reiserfs_unmap_buffer(struct buffer_head *);
struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */
long block; /* file offset, in blocks */
struct in_core_key key;
- struct path *path; /* search path, used by allocator to deternine search_start by
+ struct treepath *path; /* search path, used by allocator to deternine search_start by
* various ways */
struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
* bitmap blocks changes */
static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
*th, struct inode *inode,
b_blocknr_t * new_blocknrs,
- struct path *path, long block)
+ struct treepath *path, long block)
{
reiserfs_blocknr_hint_t hint = {
.th = th,
static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
*th, struct inode *inode,
b_blocknr_t * new_blocknrs,
- struct path *path, long block)
+ struct treepath *path, long block)
{
reiserfs_blocknr_hint_t hint = {
.th = th,
/* job control IDs */
pid_t pgrp;
pid_t tty_old_pgrp;
- pid_t session;
+
+ union {
+ pid_t session __deprecated;
+ pid_t __session;
+ };
+
/* boolean value for session group leader */
int leader;
#ifdef CONFIG_TASK_DELAY_ACCT
struct task_delay_info *delays;
#endif
+#ifdef CONFIG_FAULT_INJECTION
+ int make_it_fail;
+#endif
};
static inline pid_t process_group(struct task_struct *tsk)
return tsk->signal->pgrp;
}
+static inline pid_t signal_session(struct signal_struct *sig)
+{
+ return sig->__session;
+}
+
+static inline pid_t process_session(struct task_struct *tsk)
+{
+ return signal_session(tsk->signal);
+}
+
+static inline void set_signal_session(struct signal_struct *sig, pid_t session)
+{
+ sig->__session = session;
+}
+
static inline struct pid *task_pid(struct task_struct *task)
{
return task->pids[PIDTYPE_PID].pid;
#define find_task_by_pid(nr) find_task_by_pid_type(PIDTYPE_PID, nr)
extern struct task_struct *find_task_by_pid_type(int type, int pid);
-extern void set_special_pids(pid_t session, pid_t pgrp);
extern void __set_special_pids(pid_t session, pid_t pgrp);
/* per-UID process charging. */
extern void daemonize(const char *, ...);
extern int allow_signal(int);
extern int disallow_signal(int);
-extern struct task_struct *child_reaper;
extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *);
- void (*set_termios)(struct uart_port *, struct termios *new,
- struct termios *old);
+ void (*set_termios)(struct uart_port *, struct ktermios *new,
+ struct ktermios *old);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
*/
void uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int baud);
-unsigned int uart_get_baud_rate(struct uart_port *port, struct termios *termios,
- struct termios *old, unsigned int min,
+unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old, unsigned int min,
unsigned int max);
unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
void serio_unregister_port(struct serio *serio);
void serio_unregister_child_port(struct serio *serio);
-void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
-static inline void serio_unregister_port_delayed(struct serio *serio)
-{
- __serio_unregister_port_delayed(serio, THIS_MODULE);
-}
-
-void __serio_register_driver(struct serio_driver *drv, struct module *owner);
-static inline void serio_register_driver(struct serio_driver *drv)
-{
- __serio_register_driver(drv, THIS_MODULE);
-}
+int serio_register_driver(struct serio_driver *drv);
void serio_unregister_driver(struct serio_driver *drv);
static inline int serio_write(struct serio *serio, unsigned char data)
* protection - since "write" code only needs to change the head, and
* interrupt code only needs to change the tail.
*/
-typedef struct {
+struct stlrq {
char *buf;
char *head;
char *tail;
-} stlrq_t;
+};
/*
* Port, panel and board structures to hold status info about each.
* is associated with, this makes it (fairly) easy to get back to the
* board/panel info for a port.
*/
-typedef struct stlport {
+struct stlport {
unsigned long magic;
- int portnr;
- int panelnr;
- int brdnr;
+ unsigned int portnr;
+ unsigned int panelnr;
+ unsigned int brdnr;
int ioaddr;
int uartaddr;
- int pagenr;
+ unsigned int pagenr;
long istate;
int flags;
int baud_base;
wait_queue_head_t close_wait;
struct work_struct tqueue;
comstats_t stats;
- stlrq_t tx;
-} stlport_t;
+ struct stlrq tx;
+};
-typedef struct stlpanel {
+struct stlpanel {
unsigned long magic;
- int panelnr;
- int brdnr;
- int pagenr;
- int nrports;
+ unsigned int panelnr;
+ unsigned int brdnr;
+ unsigned int pagenr;
+ unsigned int nrports;
int iobase;
void *uartp;
void (*isr)(struct stlpanel *panelp, unsigned int iobase);
unsigned int hwid;
unsigned int ackmask;
- stlport_t *ports[STL_PORTSPERPANEL];
-} stlpanel_t;
+ struct stlport *ports[STL_PORTSPERPANEL];
+};
-typedef struct stlbrd {
+struct stlbrd {
unsigned long magic;
- int brdnr;
- int brdtype;
- int state;
- int nrpanels;
- int nrports;
- int nrbnks;
+ unsigned int brdnr;
+ unsigned int brdtype;
+ unsigned int state;
+ unsigned int nrpanels;
+ unsigned int nrports;
+ unsigned int nrbnks;
int irq;
int irqtype;
int (*isr)(struct stlbrd *brdp);
unsigned long clk;
unsigned int bnkpageaddr[STL_MAXBANKS];
unsigned int bnkstataddr[STL_MAXBANKS];
- stlpanel_t *bnk2panel[STL_MAXBANKS];
- stlpanel_t *panels[STL_MAXPANELS];
-} stlbrd_t;
+ struct stlpanel *bnk2panel[STL_MAXBANKS];
+ struct stlpanel *panels[STL_MAXPANELS];
+};
/*
int index;
struct tty_ldisc ldisc;
struct mutex termios_mutex;
- struct termios *termios, *termios_locked;
+ struct ktermios *termios, *termios_locked;
char name[64];
int pgrp;
int session;
extern void tty_write_flush(struct tty_struct *);
-extern struct termios tty_std_termios;
+extern struct ktermios tty_std_termios;
extern int kmsg_redirect;
extern void do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
extern void tty_flip_buffer_push(struct tty_struct *tty);
-extern int tty_get_baud_rate(struct tty_struct *tty);
-extern int tty_termios_baud_rate(struct termios *termios);
+extern speed_t tty_get_baud_rate(struct tty_struct *tty);
+extern speed_t tty_termios_baud_rate(struct ktermios *termios);
+extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
extern void tty_ldisc_deref(struct tty_ldisc *);
extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg);
+extern dev_t tty_devnum(struct tty_struct *tty);
+extern void proc_clear_tty(struct task_struct *p);
+extern void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+extern void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+extern struct tty_struct *get_current_tty(void);
+
extern struct mutex tty_mutex;
/* n_tty.c */
extern int vt_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
-static inline dev_t tty_devnum(struct tty_struct *tty)
-{
- return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-
#endif /* __KERNEL__ */
#endif
* device-specific ioctl's. If the ioctl number passed in cmd
* is not recognized by the driver, it should return ENOIOCTLCMD.
*
- * void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
* This routine allows the tty driver to be notified when
* device's termios settings have changed. Note that a
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
int num; /* number of devices allocated */
short type; /* type of tty driver */
short subtype; /* subtype of tty driver */
- struct termios init_termios; /* Initial termios */
+ struct ktermios init_termios; /* Initial termios */
int flags; /* tty driver flags */
int refcount; /* for loadable tty drivers */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
- struct termios **termios;
- struct termios **termios_locked;
+ struct ktermios **termios;
+ struct ktermios **termios_locked;
void *driver_state; /* only used for the PTY driver */
/*
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
* low-level driver can "grab" an ioctl request before the line
* discpline has a chance to see it.
*
- * void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
* This function notifies the line discpline that a change has
* been made to the termios structure.
const unsigned char * buf, size_t nr);
int (*ioctl)(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
unsigned int (*poll)(struct tty_struct *, struct file *,
struct poll_table_struct *);
int (*hangup)(struct tty_struct *tty);
int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count);
int (*write_room) (struct usb_serial_port *port);
int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios) (struct usb_serial_port *port, struct termios * old);
+ void (*set_termios) (struct usb_serial_port *port, struct ktermios * old);
void (*break_ctl) (struct usb_serial_port *port, int break_state);
int (*chars_in_buffer) (struct usb_serial_port *port);
void (*throttle) (struct usb_serial_port *port);
extern int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
extern void ircomm_tty_set_termios(struct tty_struct *tty,
- struct termios *old_termios);
+ struct ktermios *old_termios);
extern hashbin_t *ircomm_tty;
#endif
#ifndef __MBX_FB_H
#define __MBX_FB_H
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
struct mbxfb_val {
unsigned int defval;
unsigned int min;
int (*remove)(struct fb_info *fb);
};
+/* planar */
+#define MBXFB_FMT_YUV12 0
+
+/* packed */
+#define MBXFB_FMT_UY0VY1 1
+#define MBXFB_FMT_VY0UY1 2
+#define MBXFB_FMT_Y0UY1V 3
+#define MBXFB_FMT_Y0VY1U 4
+struct mbxfb_overlaySetup {
+ __u32 enable;
+ __u32 x, y;
+ __u32 width, height;
+ __u32 alpha;
+ __u32 fmt;
+ __u32 mem_offset;
+ __u32 scaled_width;
+ __u32 scaled_height;
+
+ /* Filled by the driver */
+ __u32 U_offset;
+ __u32 V_offset;
+
+ __u16 Y_stride;
+ __u16 UV_stride;
+};
+
+#define MBXFB_IOCX_OVERLAY _IOWR(0xF4, 0x00,struct mbxfb_overlaySetup)
+
#endif /* __MBX_FB_H */
#define PM3FBDestReadModeOr 0xac98
#define PM3FBDestReadMode_ReadDisable 0<<0
#define PM3FBDestReadMode_ReadEnable 1<<0
- #define PM3FBDestReadMode_StripePitch(sp) (((sp)&0x7)<<2
- #define PM3FBDestReadMode_StripeHeight(sh) (((sh)&0x7)<<7
+ #define PM3FBDestReadMode_StripePitch(sp) (((sp)&0x7)<<2)
+ #define PM3FBDestReadMode_StripeHeight(sh) (((sh)&0x7)<<7)
#define PM3FBDestReadMode_Enable0 1<<8
#define PM3FBDestReadMode_Enable1 1<<9
#define PM3FBDestReadMode_Enable2 1<<10
#define PM3FBDestReadMode_Enable3 1<<11
- #define PM3FBDestReadMode_Layout0(l) (((l)&0x3)<<12
- #define PM3FBDestReadMode_Layout1(l) (((l)&0x3)<<14
- #define PM3FBDestReadMode_Layout2(l) (((l)&0x3)<<16
- #define PM3FBDestReadMode_Layout3(l) (((l)&0x3)<<18
+ #define PM3FBDestReadMode_Layout0(l) (((l)&0x3)<<12)
+ #define PM3FBDestReadMode_Layout1(l) (((l)&0x3)<<14)
+ #define PM3FBDestReadMode_Layout2(l) (((l)&0x3)<<16)
+ #define PM3FBDestReadMode_Layout3(l) (((l)&0x3)<<18)
#define PM3FBDestReadMode_Origin0 1<<20
#define PM3FBDestReadMode_Origin1 1<<21
#define PM3FBDestReadMode_Origin2 1<<22
#define PM3FBSourceReadModeOr 0xaca8
#define PM3FBSourceReadMode_ReadDisable (0<<0)
#define PM3FBSourceReadMode_ReadEnable (1<<0)
- #define PM3FBSourceReadMode_StripePitch(sp) (((sp)&0x7)<<2
- #define PM3FBSourceReadMode_StripeHeight(sh) (((sh)&0x7)<<7
- #define PM3FBSourceReadMode_Layout(l) (((l)&0x3)<<8
+ #define PM3FBSourceReadMode_StripePitch(sp) (((sp)&0x7)<<2)
+ #define PM3FBSourceReadMode_StripeHeight(sh) (((sh)&0x7)<<7)
+ #define PM3FBSourceReadMode_Layout(l) (((l)&0x3)<<8)
#define PM3FBSourceReadMode_Origin 1<<10
#define PM3FBSourceReadMode_Blocking 1<<11
#define PM3FBSourceReadMode_UserTexelCoord 1<<13
#define PM3FBSourceReadMode_WrapXEnable 1<<14
#define PM3FBSourceReadMode_WrapYEnable 1<<15
- #define PM3FBSourceReadMode_WrapX(w) (((w)&0xf)<<16
- #define PM3FBSourceReadMode_WrapY(w) (((w)&0xf)<<20
+ #define PM3FBSourceReadMode_WrapX(w) (((w)&0xf)<<16)
+ #define PM3FBSourceReadMode_WrapY(w) (((w)&0xf)<<20)
#define PM3FBSourceReadMode_ExternalSourceData 1<<24
#define PM3FBWriteBufferAddr0 0xb000
#define PM3FBWriteBufferAddr1 0xb008
#define PM3Window 0x8980
#define PM3Window_ForceLBUpdate 1<<3
#define PM3Window_LBUpdateSource 1<<4
- #define PM3Window_FrameCount(c) (((c)&0xff)<<9
+ #define PM3Window_FrameCount(c) (((c)&0xff)<<9)
#define PM3Window_StencilFCP 1<<17
#define PM3Window_DepthFCP 1<<18
#define PM3Window_OverrideWriteFiltering 1<<19
# dependencies on generated files need to be listed explicitly
+$(obj)/main.o: include/linux/compile.h
$(obj)/version.o: include/linux/compile.h
# compile.h changes depending on hostname, generation number, etc,
#include <linux/buffer_head.h>
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
+#include <linux/utsrelease.h>
+#include <linux/pid_namespace.h>
+#include <linux/compile.h>
#include <asm/io.h>
#include <asm/bugs.h>
boot_cpu_init();
page_address_init();
printk(KERN_NOTICE);
- printk(linux_banner);
+ printk(linux_banner, UTS_RELEASE, UTS_VERSION);
setup_arch(&command_line);
unwind_setup();
setup_per_cpu_areas();
}
__setup("initcall_debug", initcall_debug_setup);
-struct task_struct *child_reaper = &init_task;
-
extern initcall_t __initcall_start[], __initcall_end[];
static void __init do_initcalls(void)
* assumptions about where in the task array this
* can be found.
*/
- child_reaper = current;
+ init_pid_ns.child_reaper = current;
cad_pid = task_pid(current);
EXPORT_SYMBOL_GPL(init_uts_ns);
const char linux_banner[] =
- "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
- LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
+ "Linux version %s (" LINUX_COMPILE_BY "@"
+ LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") %s\n";
+
static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
size_t count, loff_t * off)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
char buffer[FILENT_SIZE];
size_t slen;
loff_t o;
return -EFAULT;
*off = o + count;
- filp->f_dentry->d_inode->i_atime = filp->f_dentry->d_inode->i_ctime = CURRENT_TIME;
+ filp->f_path.dentry->d_inode->i_atime = filp->f_path.dentry->d_inode->i_ctime = CURRENT_TIME;
return count;
}
static int mqueue_flush_file(struct file *filp, fl_owner_t id)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
spin_lock(&info->lock);
if (task_tgid(current) == info->notify_owner)
static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab)
{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
+ struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
int retval = 0;
poll_wait(filp, &info->wait_q, poll_tab);
if (unlikely(!filp))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
if (unlikely(!filp))
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
if (!filp)
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
if (!filp)
goto out;
- inode = filp->f_dentry->d_inode;
+ inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
static void shm_open(struct vm_area_struct *shmd)
{
shm_inc(shm_file_ns(shmd->vm_file),
- shmd->vm_file->f_dentry->d_inode->i_ino);
+ shmd->vm_file->f_path.dentry->d_inode->i_ino);
}
/*
if (!is_file_hugepages(shp->shm_file))
shmem_lock(shp->shm_file, 0, shp->mlock_user);
else
- user_shm_unlock(shp->shm_file->f_dentry->d_inode->i_size,
+ user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
shp->mlock_user);
fput (shp->shm_file);
security_shm_free(shp);
static void shm_close (struct vm_area_struct *shmd)
{
struct file * file = shmd->vm_file;
- int id = file->f_dentry->d_inode->i_ino;
+ int id = file->f_path.dentry->d_inode->i_ino;
struct shmid_kernel *shp;
struct ipc_namespace *ns;
vma->vm_ops = &shm_vm_ops;
if (!(vma->vm_flags & VM_WRITE))
vma->vm_flags &= ~VM_MAYWRITE;
- shm_inc(shm_file_ns(file), file->f_dentry->d_inode->i_ino);
+ shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino);
}
return ret;
shp->shm_nattch = 0;
shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
shp->shm_file = file;
- file->f_dentry->d_inode->i_ino = shp->id;
+ file->f_path.dentry->d_inode->i_ino = shp->id;
shm_file_ns(file) = get_ipc_ns(ns);
if(!shp)
continue;
- inode = shp->shm_file->f_dentry->d_inode;
+ inode = shp->shm_file->f_path.dentry->d_inode;
if (is_file_hugepages(shp->shm_file)) {
struct address_space *mapping = inode->i_mapping;
}
file = shp->shm_file;
- size = i_size_read(file->f_dentry->d_inode);
+ size = i_size_read(file->f_path.dentry->d_inode);
shp->shm_nattch++;
shm_unlock(shp);
(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
- size = vma->vm_file->f_dentry->d_inode->i_size;
+ size = vma->vm_file->f_path.dentry->d_inode->i_size;
do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
/*
* We discovered the size of the shm segment, so
spin_unlock(&acct_globals.lock);
/* May block */
- if (vfs_statfs(file->f_dentry, &sbuf))
+ if (vfs_statfs(file->f_path.dentry, &sbuf))
return res;
suspend = sbuf.f_blocks * SUSPEND;
resume = sbuf.f_blocks * RESUME;
add_timer(&acct_globals.timer);
}
if (old_acct) {
- mnt_unpin(old_acct->f_vfsmnt);
+ mnt_unpin(old_acct->f_path.mnt);
spin_unlock(&acct_globals.lock);
do_acct_process(old_acct);
filp_close(old_acct, NULL);
if (IS_ERR(file))
return PTR_ERR(file);
- if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
+ if (!S_ISREG(file->f_path.dentry->d_inode->i_mode)) {
filp_close(file, NULL);
return -EACCES;
}
}
spin_lock(&acct_globals.lock);
- mnt_pin(file->f_vfsmnt);
+ mnt_pin(file->f_path.mnt);
acct_file_reopen(file);
spin_unlock(&acct_globals.lock);
- mntput(file->f_vfsmnt); /* it's pinned, now give up active reference */
+ mntput(file->f_path.mnt); /* it's pinned, now give up active reference */
return 0;
}
void acct_auto_close_mnt(struct vfsmount *m)
{
spin_lock(&acct_globals.lock);
- if (acct_globals.file && acct_globals.file->f_vfsmnt == m)
+ if (acct_globals.file && acct_globals.file->f_path.mnt == m)
acct_file_reopen(NULL);
spin_unlock(&acct_globals.lock);
}
{
spin_lock(&acct_globals.lock);
if (acct_globals.file &&
- acct_globals.file->f_vfsmnt->mnt_sb == sb) {
+ acct_globals.file->f_path.mnt->mnt_sb == sb) {
acct_file_reopen(NULL);
}
spin_unlock(&acct_globals.lock);
u64 elapsed;
u64 run_time;
struct timespec uptime;
+ struct tty_struct *tty;
/*
* First check to see if there is enough free_space to continue
ac.ac_ppid = current->parent->tgid;
#endif
- mutex_lock(&tty_mutex);
- /* FIXME: Whoever is responsible for current->signal locking needs
- to use the same locking all over the kernel and document it */
- read_lock(&tasklist_lock);
- ac.ac_tty = current->signal->tty ?
- old_encode_dev(tty_devnum(current->signal->tty)) : 0;
- read_unlock(&tasklist_lock);
- mutex_unlock(&tty_mutex);
-
spin_lock_irq(¤t->sighand->siglock);
+ tty = current->signal->tty;
+ ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
ac.ac_flag = pacct->ac_flag;
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
audit_log_d_path(ab, "exe=",
- vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
+ vma->vm_file->f_path.dentry,
+ vma->vm_file->f_path.mnt);
break;
}
vma = vma->vm_next;
context->return_code);
mutex_lock(&tty_mutex);
+ read_lock(&tasklist_lock);
if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
tty = tsk->signal->tty->name;
else
tty = "(none)";
+ read_unlock(&tasklist_lock);
audit_log_format(ab,
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
" ppid=%d pid=%d auid=%u uid=%u gid=%u"
*
*
* When reading/writing to a file:
- * - the cpuset to use in file->f_dentry->d_parent->d_fsdata
- * - the 'cftype' of the file is file->f_dentry->d_fsdata
+ * - the cpuset to use in file->f_path.dentry->d_parent->d_fsdata
+ * - the 'cftype' of the file is file->f_path.dentry->d_fsdata
*/
struct cftype {
const char __user *userbuf,
size_t nbytes, loff_t *unused_ppos)
{
- struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
cpuset_filetype_t type = cft->private;
char *buffer;
char *pathbuf = NULL;
size_t nbytes, loff_t *ppos)
{
ssize_t retval = 0;
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
if (!cft)
return -ENODEV;
static ssize_t cpuset_common_file_read(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
- struct cftype *cft = __d_cft(file->f_dentry);
- struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
+ struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);
cpuset_filetype_t type = cft->private;
char *page;
ssize_t retval = 0;
loff_t *ppos)
{
ssize_t retval = 0;
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
if (!cft)
return -ENODEV;
if (err)
return err;
- cft = __d_cft(file->f_dentry);
+ cft = __d_cft(file->f_path.dentry);
if (!cft)
return -ENODEV;
if (cft->open)
static int cpuset_file_release(struct inode *inode, struct file *file)
{
- struct cftype *cft = __d_cft(file->f_dentry);
+ struct cftype *cft = __d_cft(file->f_path.dentry);
if (cft->release)
return cft->release(inode, file);
return 0;
*/
static int cpuset_tasks_open(struct inode *unused, struct file *file)
{
- struct cpuset *cs = __d_cs(file->f_dentry->d_parent);
+ struct cpuset *cs = __d_cs(file->f_path.dentry->d_parent);
struct ctr_struct *ctr;
pid_t *pidarray;
int npids;
#include <linux/completion.h>
#include <linux/personality.h>
#include <linux/tty.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/key.h>
#include <linux/security.h>
#include <linux/cpu.h>
#include <linux/file.h>
#include <linux/binfmts.h>
#include <linux/nsproxy.h>
+#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/profile.h>
#include <linux/mount.h>
#include <asm/mmu_context.h>
extern void sem_exit (void);
-extern struct task_struct *child_reaper;
static void exit_mm(struct task_struct * tsk);
int session_of_pgrp(int pgrp)
{
struct task_struct *p;
- int sid = -1;
+ int sid = 0;
read_lock(&tasklist_lock);
- do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
- if (p->signal->session > 0) {
- sid = p->signal->session;
- goto out;
- }
- } while_each_task_pid(pgrp, PIDTYPE_PGID, p);
- p = find_task_by_pid(pgrp);
- if (p)
- sid = p->signal->session;
-out:
+
+ p = find_task_by_pid_type(PIDTYPE_PGID, pgrp);
+ if (p == NULL)
+ p = find_task_by_pid(pgrp);
+ if (p != NULL)
+ sid = process_session(p);
+
read_unlock(&tasklist_lock);
-
+
return sid;
}
|| p->exit_state
|| is_init(p->real_parent))
continue;
- if (process_group(p->real_parent) != pgrp
- && p->real_parent->signal->session == p->signal->session) {
+ if (process_group(p->real_parent) != pgrp &&
+ process_session(p->real_parent) == process_session(p)) {
ret = 0;
break;
}
}
/**
- * reparent_to_init - Reparent the calling kernel thread to the init task.
+ * reparent_to_init - Reparent the calling kernel thread to the init task
+ * of the pid space that the thread belongs to.
*
* If a kernel thread is launched as a result of a system call, or if
* it ever exits, it should generally reparent itself to init so that
ptrace_unlink(current);
/* Reparent to init */
remove_parent(current);
- current->parent = child_reaper;
- current->real_parent = child_reaper;
+ current->parent = child_reaper(current);
+ current->real_parent = child_reaper(current);
add_parent(current);
/* Set the exit signal to SIGCHLD so we signal init on exit */
{
struct task_struct *curr = current->group_leader;
- if (curr->signal->session != session) {
+ if (process_session(curr) != session) {
detach_pid(curr, PIDTYPE_SID);
- curr->signal->session = session;
+ set_signal_session(curr->signal, session);
attach_pid(curr, PIDTYPE_SID, session);
}
if (process_group(curr) != pgrp) {
}
}
-void set_special_pids(pid_t session, pid_t pgrp)
+static void set_special_pids(pid_t session, pid_t pgrp)
{
write_lock_irq(&tasklist_lock);
__set_special_pids(session, pgrp);
exit_mm(current);
set_special_pids(1, 1);
- mutex_lock(&tty_mutex);
- current->signal->tty = NULL;
- mutex_unlock(&tty_mutex);
+ proc_clear_tty(current);
/* Block and flush all signals */
sigfillset(&blocked);
* outside, so the child pgrp is now orphaned.
*/
if ((process_group(p) != process_group(father)) &&
- (p->signal->session == father->signal->session)) {
+ (process_session(p) == process_session(father))) {
int pgrp = process_group(p);
- if (will_become_orphaned_pgrp(pgrp, NULL) && has_stopped_jobs(pgrp)) {
+ if (will_become_orphaned_pgrp(pgrp, NULL) &&
+ has_stopped_jobs(pgrp)) {
__kill_pg_info(SIGHUP, SEND_SIG_PRIV, pgrp);
__kill_pg_info(SIGCONT, SEND_SIG_PRIV, pgrp);
}
* When we die, we re-parent all our children.
* Try to give them to another thread in our thread
* group, and if no such member exists, give it to
- * the global child reaper process (ie "init")
+ * the child reaper process (ie "init") in our pid
+ * space.
*/
static void
forget_original_parent(struct task_struct *father, struct list_head *to_release)
do {
reaper = next_thread(reaper);
if (reaper == father) {
- reaper = child_reaper;
+ reaper = child_reaper(father);
break;
}
} while (reaper->exit_state);
t = tsk->real_parent;
if ((process_group(t) != process_group(tsk)) &&
- (t->signal->session == tsk->signal->session) &&
+ (process_session(t) == process_session(tsk)) &&
will_become_orphaned_pgrp(process_group(tsk), tsk) &&
has_stopped_jobs(process_group(tsk))) {
__kill_pg_info(SIGHUP, SEND_SIG_PRIV, process_group(tsk));
panic("Aiee, killing interrupt handler!");
if (unlikely(!tsk->pid))
panic("Attempted to kill the idle task!");
- if (unlikely(tsk == child_reaper))
- panic("Attempted to kill init!");
+ if (unlikely(tsk == child_reaper(tsk))) {
+ if (tsk->nsproxy->pid_ns != &init_pid_ns)
+ tsk->nsproxy->pid_ns->child_reaper = init_pid_ns.child_reaper;
+ else
+ panic("Attempted to kill init!");
+ }
+
if (unlikely(current->ptrace & PT_TRACE_EXIT)) {
current->ptrace_message = code;
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/completion.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/personality.h>
#include <linux/mempolicy.h>
#include <linux/sem.h>
anon_vma_link(tmp);
file = tmp->vm_file;
if (file) {
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
get_file(file);
if (tmp->vm_flags & VM_DENYWRITE)
atomic_dec(&inode->i_writecount);
if (thread_group_leader(p)) {
p->signal->tty = current->signal->tty;
p->signal->pgrp = process_group(current);
- p->signal->session = current->signal->session;
+ set_signal_session(p->signal, process_session(current));
attach_pid(p, PIDTYPE_PGID, process_group(p));
- attach_pid(p, PIDTYPE_SID, p->signal->session);
+ attach_pid(p, PIDTYPE_SID, process_session(p));
list_add_tail_rcu(&p->tasks, &init_task.tasks);
__get_cpu_var(process_counts)++;
}
/*
- * Unshare the namespace structure if it is being shared
+ * Unshare the mnt_namespace structure if it is being shared
*/
-static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
+static int unshare_mnt_namespace(unsigned long unshare_flags,
+ struct mnt_namespace **new_nsp, struct fs_struct *new_fs)
{
- struct namespace *ns = current->nsproxy->namespace;
+ struct mnt_namespace *ns = current->nsproxy->mnt_ns;
if ((unshare_flags & CLONE_NEWNS) && ns) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- *new_nsp = dup_namespace(current, new_fs ? new_fs : current->fs);
+ *new_nsp = dup_mnt_ns(current, new_fs ? new_fs : current->fs);
if (!*new_nsp)
return -ENOMEM;
}
}
/*
- * Unsharing of sighand for tasks created with CLONE_SIGHAND is not
- * supported yet
+ * Unsharing of sighand is not supported yet
*/
static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
{
struct sighand_struct *sigh = current->sighand;
- if ((unshare_flags & CLONE_SIGHAND) &&
- (sigh && atomic_read(&sigh->count) > 1))
+ if ((unshare_flags & CLONE_SIGHAND) && atomic_read(&sigh->count) > 1)
return -EINVAL;
else
return 0;
{
int err = 0;
struct fs_struct *fs, *new_fs = NULL;
- struct namespace *ns, *new_ns = NULL;
- struct sighand_struct *sigh, *new_sigh = NULL;
+ struct mnt_namespace *ns, *new_ns = NULL;
+ struct sighand_struct *new_sigh = NULL;
struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
struct files_struct *fd, *new_fd = NULL;
struct sem_undo_list *new_ulist = NULL;
goto bad_unshare_out;
if ((err = unshare_fs(unshare_flags, &new_fs)))
goto bad_unshare_cleanup_thread;
- if ((err = unshare_namespace(unshare_flags, &new_ns, new_fs)))
+ if ((err = unshare_mnt_namespace(unshare_flags, &new_ns, new_fs)))
goto bad_unshare_cleanup_fs;
if ((err = unshare_sighand(unshare_flags, &new_sigh)))
goto bad_unshare_cleanup_ns;
}
}
- if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
+ if (new_fs || new_ns || new_mm || new_fd || new_ulist ||
new_uts || new_ipc) {
task_lock(current);
}
if (new_ns) {
- ns = current->nsproxy->namespace;
- current->nsproxy->namespace = new_ns;
+ ns = current->nsproxy->mnt_ns;
+ current->nsproxy->mnt_ns = new_ns;
new_ns = ns;
}
- if (new_sigh) {
- sigh = current->sighand;
- rcu_assign_pointer(current->sighand, new_sigh);
- new_sigh = sigh;
- }
-
if (new_mm) {
mm = current->mm;
active_mm = current->active_mm;
bad_unshare_cleanup_ns:
if (new_ns)
- put_namespace(new_ns);
+ put_mnt_ns(new_ns);
bad_unshare_cleanup_fs:
if (new_fs)
/*
* Get parameters which are the keys for a futex.
*
- * For shared mappings, it's (page->index, vma->vm_file->f_dentry->d_inode,
+ * For shared mappings, it's (page->index, vma->vm_file->f_path.dentry->d_inode,
* offset_within_page). For private mappings, it's (uaddr, current->mm).
* We can usually work out the index without swapping in the page.
*
/*
* Linear file mappings are also simple.
*/
- key->shared.inode = vma->vm_file->f_dentry->d_inode;
+ key->shared.inode = vma->vm_file->f_path.dentry->d_inode;
key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
goto out;
}
filp->f_op = &futex_fops;
- filp->f_vfsmnt = mntget(futex_mnt);
- filp->f_dentry = dget(futex_mnt->mnt_root);
- filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_path.mnt = mntget(futex_mnt);
+ filp->f_path.dentry = dget(futex_mnt->mnt_root);
+ filp->f_mapping = filp->f_path.dentry->d_inode->i_mapping;
if (signal) {
err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1);
unsigned int irq = (int)(long)data, full_count = count, err;
cpumask_t new_value, tmp;
- if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
+ if (!irq_desc[irq].chip->set_affinity || no_irq_affinity ||
+ CHECK_IRQ_PER_CPU(irq_desc[irq].status))
return -EIO;
err = cpumask_parse_user(buffer, count, new_value);
#endif
/* These will be re-linked against their real values during the second link stage */
-extern unsigned long kallsyms_addresses[] __attribute__((weak));
-extern unsigned long kallsyms_num_syms __attribute__((weak,section("data")));
-extern u8 kallsyms_names[] __attribute__((weak));
+extern const unsigned long kallsyms_addresses[] __attribute__((weak));
+extern const unsigned long kallsyms_num_syms __attribute__((weak));
+extern const u8 kallsyms_names[] __attribute__((weak));
-extern u8 kallsyms_token_table[] __attribute__((weak));
-extern u16 kallsyms_token_index[] __attribute__((weak));
+extern const u8 kallsyms_token_table[] __attribute__((weak));
+extern const u16 kallsyms_token_index[] __attribute__((weak));
-extern unsigned long kallsyms_markers[] __attribute__((weak));
+extern const unsigned long kallsyms_markers[] __attribute__((weak));
static inline int is_kernel_inittext(unsigned long addr)
{
static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
{
int len, skipped_first = 0;
- u8 *tptr, *data;
+ const u8 *tptr, *data;
/* get the compressed symbol length from the first symbol byte */
data = &kallsyms_names[off];
* kallsyms array */
static unsigned int get_symbol_offset(unsigned long pos)
{
- u8 *name;
+ const u8 *name;
int i;
/* use the closest marker we have. We have markers every 256 positions,
#include <linux/kmod.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/completion.h>
#include <linux/file.h>
#include <linux/workqueue.h>
}
EXPORT_SYMBOL_GPL(mutex_lock_nested);
+
+int __sched
+mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
+{
+ might_sleep();
+ return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, subclass);
+}
+
+EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
#endif
/*
#include <linux/version.h>
#include <linux/nsproxy.h>
#include <linux/init_task.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/utsname.h>
+#include <linux/pid_namespace.h>
struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
struct nsproxy *ns;
ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL);
- if (ns)
+ if (ns) {
atomic_set(&ns->count, 1);
+ ns->id = -1;
+ }
return ns;
}
struct nsproxy *ns = clone_namespaces(orig);
if (ns) {
- if (ns->namespace)
- get_namespace(ns->namespace);
+ if (ns->mnt_ns)
+ get_mnt_ns(ns->mnt_ns);
if (ns->uts_ns)
get_uts_ns(ns->uts_ns);
if (ns->ipc_ns)
get_ipc_ns(ns->ipc_ns);
+ if (ns->pid_ns)
+ get_pid_ns(ns->pid_ns);
}
return ns;
tsk->nsproxy = new_ns;
- err = copy_namespace(flags, tsk);
+ err = copy_mnt_ns(flags, tsk);
if (err)
goto out_ns;
if (err)
goto out_ipc;
+ err = copy_pid_ns(flags, tsk);
+ if (err)
+ goto out_pid;
+
out:
put_nsproxy(old_ns);
return err;
+out_pid:
+ if (new_ns->ipc_ns)
+ put_ipc_ns(new_ns->ipc_ns);
out_ipc:
if (new_ns->uts_ns)
put_uts_ns(new_ns->uts_ns);
out_uts:
- if (new_ns->namespace)
- put_namespace(new_ns->namespace);
+ if (new_ns->mnt_ns)
+ put_mnt_ns(new_ns->mnt_ns);
out_ns:
tsk->nsproxy = old_ns;
kfree(new_ns);
void free_nsproxy(struct nsproxy *ns)
{
- if (ns->namespace)
- put_namespace(ns->namespace);
- if (ns->uts_ns)
- put_uts_ns(ns->uts_ns);
- if (ns->ipc_ns)
- put_ipc_ns(ns->ipc_ns);
- kfree(ns);
+ if (ns->mnt_ns)
+ put_mnt_ns(ns->mnt_ns);
+ if (ns->uts_ns)
+ put_uts_ns(ns->uts_ns);
+ if (ns->ipc_ns)
+ put_ipc_ns(ns->ipc_ns);
+ if (ns->pid_ns)
+ put_pid_ns(ns->pid_ns);
+ kfree(ns);
}
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/hash.h>
-#include <linux/pspace.h>
+#include <linux/pid_namespace.h>
#define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
static struct hlist_head *pid_hash;
#define BITS_PER_PAGE (PAGE_SIZE*8)
#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
-static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off)
+static inline int mk_pid(struct pid_namespace *pid_ns,
+ struct pidmap *map, int off)
{
- return (map - pspace->pidmap)*BITS_PER_PAGE + off;
+ return (map - pid_ns->pidmap)*BITS_PER_PAGE + off;
}
#define find_next_offset(map, off) \
* value does not cause lots of bitmaps to be allocated, but
* the scheme scales to up to 4 million PIDs, runtime.
*/
-struct pspace init_pspace = {
+struct pid_namespace init_pid_ns = {
+ .kref = {
+ .refcount = ATOMIC_INIT(2),
+ },
.pidmap = {
[ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
},
- .last_pid = 0
+ .last_pid = 0,
+ .child_reaper = &init_task
};
/*
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock);
-static fastcall void free_pidmap(struct pspace *pspace, int pid)
+static fastcall void free_pidmap(struct pid_namespace *pid_ns, int pid)
{
- struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE;
+ struct pidmap *map = pid_ns->pidmap + pid / BITS_PER_PAGE;
int offset = pid & BITS_PER_PAGE_MASK;
clear_bit(offset, map->page);
atomic_inc(&map->nr_free);
}
-static int alloc_pidmap(struct pspace *pspace)
+static int alloc_pidmap(struct pid_namespace *pid_ns)
{
- int i, offset, max_scan, pid, last = pspace->last_pid;
+ int i, offset, max_scan, pid, last = pid_ns->last_pid;
struct pidmap *map;
pid = last + 1;
if (pid >= pid_max)
pid = RESERVED_PIDS;
offset = pid & BITS_PER_PAGE_MASK;
- map = &pspace->pidmap[pid/BITS_PER_PAGE];
+ map = &pid_ns->pidmap[pid/BITS_PER_PAGE];
max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset;
for (i = 0; i <= max_scan; ++i) {
if (unlikely(!map->page)) {
do {
if (!test_and_set_bit(offset, map->page)) {
atomic_dec(&map->nr_free);
- pspace->last_pid = pid;
+ pid_ns->last_pid = pid;
return pid;
}
offset = find_next_offset(map, offset);
- pid = mk_pid(pspace, map, offset);
+ pid = mk_pid(pid_ns, map, offset);
/*
* find_next_offset() found a bit, the pid from it
* is in-bounds, and if we fell back to the last
(i != max_scan || pid < last ||
!((last+1) & BITS_PER_PAGE_MASK)));
}
- if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
+ if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
++map;
offset = 0;
} else {
- map = &pspace->pidmap[0];
+ map = &pid_ns->pidmap[0];
offset = RESERVED_PIDS;
if (unlikely(last == offset))
break;
}
- pid = mk_pid(pspace, map, offset);
+ pid = mk_pid(pid_ns, map, offset);
}
return -1;
}
-static int next_pidmap(struct pspace *pspace, int last)
+static int next_pidmap(struct pid_namespace *pid_ns, int last)
{
int offset;
struct pidmap *map, *end;
offset = (last + 1) & BITS_PER_PAGE_MASK;
- map = &pspace->pidmap[(last + 1)/BITS_PER_PAGE];
- end = &pspace->pidmap[PIDMAP_ENTRIES];
+ map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];
+ end = &pid_ns->pidmap[PIDMAP_ENTRIES];
for (; map < end; map++, offset = 0) {
if (unlikely(!map->page))
continue;
offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
if (offset < BITS_PER_PAGE)
- return mk_pid(pspace, map, offset);
+ return mk_pid(pid_ns, map, offset);
}
return -1;
}
hlist_del_rcu(&pid->pid_chain);
spin_unlock_irqrestore(&pidmap_lock, flags);
- free_pidmap(&init_pspace, pid->nr);
+ free_pidmap(current->nsproxy->pid_ns, pid->nr);
call_rcu(&pid->rcu, delayed_put_pid);
}
if (!pid)
goto out;
- nr = alloc_pidmap(&init_pspace);
+ nr = alloc_pidmap(current->nsproxy->pid_ns);
if (nr < 0)
goto out_free;
pid = find_pid(nr);
if (pid)
break;
- nr = next_pidmap(&init_pspace, nr);
+ nr = next_pidmap(current->nsproxy->pid_ns, nr);
} while (nr > 0);
return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);
+int copy_pid_ns(int flags, struct task_struct *tsk)
+{
+ struct pid_namespace *old_ns = tsk->nsproxy->pid_ns;
+ int err = 0;
+
+ if (!old_ns)
+ return 0;
+
+ get_pid_ns(old_ns);
+ return err;
+}
+
+void free_pid_ns(struct kref *kref)
+{
+ struct pid_namespace *ns;
+
+ ns = container_of(kref, struct pid_namespace, kref);
+ kfree(ns);
+}
+
/*
* The pid hash table is scaled according to the amount of memory in the
* machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or
void __init pidmap_init(void)
{
- init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
/* Reserve PID 0. We never call free_pidmap(0) */
- set_bit(0, init_pspace.pidmap[0].page);
- atomic_dec(&init_pspace.pidmap[0].nr_free);
+ set_bit(0, init_pid_ns.pidmap[0].page);
+ atomic_dec(&init_pid_ns.pidmap[0].nr_free);
pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
__alignof__(struct pid),
if (!desc->count)
return 0;
- mutex_lock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_lock(&filp->f_path.dentry->d_inode->i_mutex);
do {
if (!relay_file_read_avail(buf, *ppos))
break;
*ppos = relay_file_read_end_pos(buf, read_start, ret);
}
} while (desc->count && ret);
- mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
+ mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
return desc->written;
}
#include <linux/signal.h>
#include <linux/capability.h>
#include <linux/freezer.h>
+#include <linux/pid_namespace.h>
+#include <linux/nsproxy.h>
+
#include <asm/param.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
error = -EPERM;
if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
&& ((sig != SIGCONT) ||
- (current->signal->session != t->signal->session))
+ (process_session(current) != process_session(t)))
&& (current->euid ^ t->suid) && (current->euid ^ t->uid)
&& (current->uid ^ t->suid) && (current->uid ^ t->uid)
&& !capable(CAP_KILL))
if (sig_kernel_ignore(signr)) /* Default is nothing. */
continue;
- /* Init gets no signals it doesn't want. */
- if (current == child_reaper)
+ /*
+ * Init of a pid space gets no signals it doesn't want from
+ * within that pid space. It can of course get signals from
+ * its parent pid space.
+ */
+ if (current == child_reaper(current))
continue;
if (sig_kernel_stop(signr)) {
if (p->real_parent == group_leader) {
err = -EPERM;
- if (p->signal->session != group_leader->signal->session)
+ if (process_session(p) != process_session(group_leader))
goto out;
err = -EACCES;
if (p->did_exec)
goto out;
if (pgid != pid) {
- struct task_struct *p;
+ struct task_struct *g =
+ find_task_by_pid_type(PIDTYPE_PGID, pgid);
- do_each_task_pid(pgid, PIDTYPE_PGID, p) {
- if (p->signal->session == group_leader->signal->session)
- goto ok_pgid;
- } while_each_task_pid(pgid, PIDTYPE_PGID, p);
- goto out;
+ if (!g || process_session(g) != process_session(group_leader))
+ goto out;
}
-ok_pgid:
err = security_task_setpgid(p, pgid);
if (err)
goto out;
asmlinkage long sys_getsid(pid_t pid)
{
if (!pid)
- return current->signal->session;
+ return process_session(current);
else {
int retval;
struct task_struct *p;
if (p) {
retval = security_task_getsid(p);
if (!retval)
- retval = p->signal->session;
+ retval = process_session(p);
}
read_unlock(&tasklist_lock);
return retval;
pid_t session;
int err = -EPERM;
- mutex_lock(&tty_mutex);
write_lock_irq(&tasklist_lock);
/* Fail if I am already a session leader */
group_leader->signal->leader = 1;
__set_special_pids(session, session);
+
+ spin_lock(&group_leader->sighand->siglock);
group_leader->signal->tty = NULL;
group_leader->signal->tty_old_pgrp = 0;
+ spin_unlock(&group_leader->sighand->siglock);
+
err = process_group(group_leader);
out:
write_unlock_irq(&tasklist_lock);
- mutex_unlock(&tty_mutex);
return err;
}
extern int sg_big_buff;
#endif
#ifdef CONFIG_SYSVIPC
-static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
+static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context);
+
+#ifdef CONFIG_SYSVIPC
+static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context);
+#endif
+
#ifdef CONFIG_PROC_SYSCTL
static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
int sysctl_legacy_va_layout;
#endif
+static void *get_uts(ctl_table *table, int write)
+{
+ char *which = table->data;
+#ifdef CONFIG_UTS_NS
+ struct uts_namespace *uts_ns = current->nsproxy->uts_ns;
+ which = (which - (char *)&init_uts_ns) + (char *)uts_ns;
+#endif
+ if (!write)
+ down_read(&uts_sem);
+ else
+ down_write(&uts_sem);
+ return which;
+}
+
+static void put_uts(ctl_table *table, int write, void *which)
+{
+ if (!write)
+ up_read(&uts_sem);
+ else
+ up_write(&uts_sem);
+}
+
+#ifdef CONFIG_SYSVIPC
+static void *get_ipc(ctl_table *table, int write)
+{
+ char *which = table->data;
+ struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
+ which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
+ return which;
+}
+#else
+#define get_ipc(T,W) ((T)->data)
+#endif
+
/* /proc declarations: */
#ifdef CONFIG_PROC_SYSCTL
};
static ctl_table kern_table[] = {
-#ifndef CONFIG_UTS_NS
{
.ctl_name = KERN_OSTYPE,
.procname = "ostype",
.maxlen = sizeof(init_uts_ns.name.sysname),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_OSRELEASE,
.maxlen = sizeof(init_uts_ns.name.release),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_VERSION,
.maxlen = sizeof(init_uts_ns.name.version),
.mode = 0444,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_NODENAME,
.maxlen = sizeof(init_uts_ns.name.nodename),
.mode = 0644,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
{
.ctl_name = KERN_DOMAINNAME,
.maxlen = sizeof(init_uts_ns.name.domainname),
.mode = 0644,
.proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
-#else /* !CONFIG_UTS_NS */
- {
- .ctl_name = KERN_OSTYPE,
- .procname = "ostype",
- .data = NULL,
- /* could maybe use __NEW_UTS_LEN here? */
- .maxlen = FIELD_SIZEOF(struct new_utsname, sysname),
- .mode = 0444,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_OSRELEASE,
- .procname = "osrelease",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, release),
- .mode = 0444,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_VERSION,
- .procname = "version",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, version),
- .mode = 0444,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_NODENAME,
- .procname = "hostname",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, nodename),
- .mode = 0644,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
- },
- {
- .ctl_name = KERN_DOMAINNAME,
- .procname = "domainname",
- .data = NULL,
- .maxlen = FIELD_SIZEOF(struct new_utsname, domainname),
- .mode = 0644,
- .proc_handler = &proc_do_uts_string,
- .strategy = &sysctl_string,
+ .strategy = &sysctl_uts_string,
},
-#endif /* !CONFIG_UTS_NS */
{
.ctl_name = KERN_PANIC,
.procname = "panic",
{
.ctl_name = KERN_SHMMAX,
.procname = "shmmax",
- .data = NULL,
- .maxlen = sizeof (size_t),
+ .data = &init_ipc_ns.shm_ctlmax,
+ .maxlen = sizeof (init_ipc_ns.shm_ctlmax),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_doulongvec_minmax,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_SHMALL,
.procname = "shmall",
- .data = NULL,
- .maxlen = sizeof (size_t),
+ .data = &init_ipc_ns.shm_ctlall,
+ .maxlen = sizeof (init_ipc_ns.shm_ctlall),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_doulongvec_minmax,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_SHMMNI,
.procname = "shmmni",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.shm_ctlmni,
+ .maxlen = sizeof (init_ipc_ns.shm_ctlmni),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_MSGMAX,
.procname = "msgmax",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.msg_ctlmax,
+ .maxlen = sizeof (init_ipc_ns.msg_ctlmax),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_MSGMNI,
.procname = "msgmni",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.msg_ctlmni,
+ .maxlen = sizeof (init_ipc_ns.msg_ctlmni),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_MSGMNB,
.procname = "msgmnb",
- .data = NULL,
- .maxlen = sizeof (int),
+ .data = &init_ipc_ns.msg_ctlmnb,
+ .maxlen = sizeof (init_ipc_ns.msg_ctlmnb),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
{
.ctl_name = KERN_SEM,
.procname = "sem",
- .data = NULL,
+ .data = &init_ipc_ns.sem_ctls,
.maxlen = 4*sizeof (int),
.mode = 0644,
- .proc_handler = &proc_do_ipc_string,
+ .proc_handler = &proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
},
#endif
#ifdef CONFIG_MAGIC_SYSRQ
size_t count, loff_t *ppos)
{
int op;
- struct proc_dir_entry *de = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *de = PDE(file->f_path.dentry->d_inode);
struct ctl_table *table;
size_t res;
ssize_t error = -ENOTDIR;
* Special case of dostring for the UTS structure. This has locks
* to observe. Should this be in kernel/sys.c ????
*/
-
-#ifndef CONFIG_UTS_NS
-static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- int r;
- if (!write) {
- down_read(&uts_sem);
- r=proc_dostring(table,0,filp,buffer,lenp, ppos);
- up_read(&uts_sem);
- } else {
- down_write(&uts_sem);
- r=proc_dostring(table,1,filp,buffer,lenp, ppos);
- up_write(&uts_sem);
- }
- return r;
-}
-#else /* !CONFIG_UTS_NS */
static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int r;
- struct uts_namespace* uts_ns = current->nsproxy->uts_ns;
- char* which;
-
- switch (table->ctl_name) {
- case KERN_OSTYPE:
- which = uts_ns->name.sysname;
- break;
- case KERN_NODENAME:
- which = uts_ns->name.nodename;
- break;
- case KERN_OSRELEASE:
- which = uts_ns->name.release;
- break;
- case KERN_VERSION:
- which = uts_ns->name.version;
- break;
- case KERN_DOMAINNAME:
- which = uts_ns->name.domainname;
- break;
- default:
- r = -EINVAL;
- goto out;
- }
-
- if (!write) {
- down_read(&uts_sem);
- r=_proc_do_string(which,table->maxlen,0,filp,buffer,lenp, ppos);
- up_read(&uts_sem);
- } else {
- down_write(&uts_sem);
- r=_proc_do_string(which,table->maxlen,1,filp,buffer,lenp, ppos);
- up_write(&uts_sem);
- }
- out:
+ void *which;
+ which = get_uts(table, write);
+ r = _proc_do_string(which, table->maxlen,write,filp,buffer,lenp, ppos);
+ put_uts(table, write, which);
return r;
}
-#endif /* !CONFIG_UTS_NS */
static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
int *valp,
}
#ifdef CONFIG_SYSVIPC
-static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
- void *data;
- struct ipc_namespace *ns;
-
- ns = current->nsproxy->ipc_ns;
-
- switch (table->ctl_name) {
- case KERN_SHMMAX:
- data = &ns->shm_ctlmax;
- goto proc_minmax;
- case KERN_SHMALL:
- data = &ns->shm_ctlall;
- goto proc_minmax;
- case KERN_SHMMNI:
- data = &ns->shm_ctlmni;
- break;
- case KERN_MSGMAX:
- data = &ns->msg_ctlmax;
- break;
- case KERN_MSGMNI:
- data = &ns->msg_ctlmni;
- break;
- case KERN_MSGMNB:
- data = &ns->msg_ctlmnb;
- break;
- case KERN_SEM:
- data = &ns->sem_ctls;
- break;
- default:
- return -EINVAL;
- }
-
- return __do_proc_dointvec(data, table, write, filp, buffer,
+ void *which;
+ which = get_ipc(table, write);
+ return __do_proc_dointvec(which, table, write, filp, buffer,
lenp, ppos, NULL, NULL);
-proc_minmax:
- return __do_proc_doulongvec_minmax(data, table, write, filp, buffer,
+}
+
+static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
+ struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ void *which;
+ which = get_ipc(table, write);
+ return __do_proc_doulongvec_minmax(which, table, write, filp, buffer,
lenp, ppos, 1l, 1l);
}
+
#endif
static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
return 1;
}
+
+/* The generic string strategy routine: */
+static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
+{
+ struct ctl_table uts_table;
+ int r, write;
+ write = newval && newlen;
+ memcpy(&uts_table, table, sizeof(uts_table));
+ uts_table.data = get_uts(table, write);
+ r = sysctl_string(&uts_table, name, nlen,
+ oldval, oldlenp, newval, newlen, context);
+ put_uts(table, write, uts_table.data);
+ return r;
+}
+
+#ifdef CONFIG_SYSVIPC
+/* The generic sysctl ipc data routine. */
+static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
+{
+ size_t len;
+ void *data;
+
+ /* Get out of I don't have a variable */
+ if (!table->data || !table->maxlen)
+ return -ENOTDIR;
+
+ data = get_ipc(table, 1);
+ if (!data)
+ return -ENOTDIR;
+
+ if (oldval && oldlenp) {
+ if (get_user(len, oldlenp))
+ return -EFAULT;
+ if (len) {
+ if (len > table->maxlen)
+ len = table->maxlen;
+ if (copy_to_user(oldval, data, len))
+ return -EFAULT;
+ if (put_user(len, oldlenp))
+ return -EFAULT;
+ }
+ }
+
+ if (newval && newlen) {
+ if (newlen > table->maxlen)
+ newlen = table->maxlen;
+
+ if (copy_from_user(data, newval, newlen))
+ return -EFAULT;
+ }
+ return 1;
+}
+#endif
+
#else /* CONFIG_SYSCTL_SYSCALL */
return -ENOSYS;
}
+static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
+{
+ return -ENOSYS;
+}
+static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen, void **context)
+{
+ return -ENOSYS;
+}
#endif /* CONFIG_SYSCTL_SYSCALL */
/*
menu "Library routines"
+config BITREVERSE
+ tristate
+
config CRC_CCITT
tristate "CRC-CCITT functions"
help
config CRC32
tristate "CRC32 functions"
default y
+ select BITREVERSE
help
This option is provided for the case where no in-kernel-tree
modules require CRC32 functions, but a module built outside the
config DEBUG_BUGVERBOSE
bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
depends on BUG
- depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV || SUPERH
+ depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG
default !EMBEDDED
help
Say Y here to make BUG() panics output the file name and line number
Documentation on how to use the module can be found in
drivers/misc/lkdtm.c
+
+config FAULT_INJECTION
+ bool "Fault-injection framework"
+ depends on DEBUG_KERNEL
+ depends on STACKTRACE
+ select FRAME_POINTER
+ help
+ Provide fault-injection framework.
+ For more details, see Documentation/fault-injection/.
+
+config FAILSLAB
+ bool "Fault-injection capability for kmalloc"
+ depends on FAULT_INJECTION
+ help
+ Provide fault-injection capability for kmalloc.
+
+config FAIL_PAGE_ALLOC
+ bool "Fault-injection capabilitiy for alloc_pages()"
+ depends on FAULT_INJECTION
+ help
+ Provide fault-injection capability for alloc_pages().
+
+config FAIL_MAKE_REQUEST
+ bool "Fault-injection capabilitiy for disk IO"
+ depends on FAULT_INJECTION
+ help
+ Provide fault-injection capability for disk IO.
+
+config FAULT_INJECTION_DEBUG_FS
+ bool "Debugfs entries for fault-injection capabilities"
+ depends on FAULT_INJECTION && SYSFS && DEBUG_FS
+ help
+ Enable configuration of fault-injection capabilities via debugfs.
lib-y += dec_and_lock.o
endif
+obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_AUDIT_GENERIC) += audit.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
+obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+
+lib-$(CONFIG_GENERIC_BUG) += bug.o
hostprogs-y := gen_crc32table
clean-files := crc32table.h
--- /dev/null
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bitrev.h>
+
+const u8 byte_rev_table[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+EXPORT_SYMBOL_GPL(byte_rev_table);
+
+static __always_inline u16 bitrev16(u16 x)
+{
+ return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8);
+}
+
+/**
+ * bitrev32 - reverse the order of bits in a u32 value
+ * @x: value to be bit-reversed
+ */
+u32 bitrev32(u32 x)
+{
+ return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16);
+}
+EXPORT_SYMBOL(bitrev32);
--- /dev/null
+/*
+ Generic support for BUG()
+
+ This respects the following config options:
+
+ CONFIG_BUG - emit BUG traps. Nothing happens without this.
+ CONFIG_GENERIC_BUG - enable this code.
+ CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
+
+ CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
+ (though they're generally always on).
+
+ CONFIG_GENERIC_BUG is set by each architecture using this code.
+
+ To use this, your architecture must:
+
+ 1. Set up the config options:
+ - Enable CONFIG_GENERIC_BUG if CONFIG_BUG
+
+ 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON)
+ - Define HAVE_ARCH_BUG
+ - Implement BUG() to generate a faulting instruction
+ - NOTE: struct bug_entry does not have "file" or "line" entries
+ when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate
+ the values accordingly.
+
+ 3. Implement the trap
+ - In the illegal instruction trap handler (typically), verify
+ that the fault was in kernel mode, and call report_bug()
+ - report_bug() will return whether it was a false alarm, a warning,
+ or an actual bug.
+ - You must implement the is_valid_bugaddr(bugaddr) callback which
+ returns true if the eip is a real kernel address, and it points
+ to the expected BUG trap instruction.
+
+ Jeremy Fitzhardinge <jeremy@goop.org> 2006
+ */
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/bug.h>
+
+extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
+
+#ifdef CONFIG_MODULES
+static LIST_HEAD(module_bug_list);
+
+static const struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+ struct module *mod;
+
+ list_for_each_entry(mod, &module_bug_list, bug_list) {
+ const struct bug_entry *bug = mod->bug_table;
+ unsigned i;
+
+ for (i = 0; i < mod->num_bugs; ++i, ++bug)
+ if (bugaddr == bug->bug_addr)
+ return bug;
+ }
+ return NULL;
+}
+
+int module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *mod)
+{
+ char *secstrings;
+ unsigned int i;
+
+ mod->bug_table = NULL;
+ mod->num_bugs = 0;
+
+ /* Find the __bug_table section, if present */
+ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
+ continue;
+ mod->bug_table = (void *) sechdrs[i].sh_addr;
+ mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
+ break;
+ }
+
+ /*
+ * Strictly speaking this should have a spinlock to protect against
+ * traversals, but since we only traverse on BUG()s, a spinlock
+ * could potentially lead to deadlock and thus be counter-productive.
+ */
+ list_add(&mod->bug_list, &module_bug_list);
+
+ return 0;
+}
+
+void module_bug_cleanup(struct module *mod)
+{
+ list_del(&mod->bug_list);
+}
+
+#else
+
+static inline const struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+ return NULL;
+}
+#endif
+
+const struct bug_entry *find_bug(unsigned long bugaddr)
+{
+ const struct bug_entry *bug;
+
+ for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
+ if (bugaddr == bug->bug_addr)
+ return bug;
+
+ return module_find_bug(bugaddr);
+}
+
+enum bug_trap_type report_bug(unsigned long bugaddr)
+{
+ const struct bug_entry *bug;
+ const char *file;
+ unsigned line, warning;
+
+ if (!is_valid_bugaddr(bugaddr))
+ return BUG_TRAP_TYPE_NONE;
+
+ bug = find_bug(bugaddr);
+
+ printk(KERN_EMERG "------------[ cut here ]------------\n");
+
+ file = NULL;
+ line = 0;
+ warning = 0;
+
+ if (bug) {
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+ file = bug->file;
+ line = bug->line;
+#endif
+ warning = (bug->flags & BUGFLAG_WARNING) != 0;
+ }
+
+ if (warning) {
+ /* this is a WARN_ON rather than BUG/BUG_ON */
+ if (file)
+ printk(KERN_ERR "Badness at %s:%u\n",
+ file, line);
+ else
+ printk(KERN_ERR "Badness at %p "
+ "[verbose debug info unavailable]\n",
+ (void *)bugaddr);
+
+ dump_stack();
+ return BUG_TRAP_TYPE_WARN;
+ }
+
+ if (file)
+ printk(KERN_CRIT "kernel BUG at %s:%u!\n",
+ file, line);
+ else
+ printk(KERN_CRIT "Kernel BUG at %p "
+ "[verbose debug info unavailable]\n",
+ (void *)bugaddr);
+
+ return BUG_TRAP_TYPE_BUG;
+}
}
#endif
-/**
- * bitreverse - reverse the order of bits in a u32 value
- * @x: value to be bit-reversed
- */
-u32 bitreverse(u32 x)
-{
- x = (x >> 16) | (x << 16);
- x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
- x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
- x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
- x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
- return x;
-}
-
EXPORT_SYMBOL(crc32_le);
EXPORT_SYMBOL(crc32_be);
-EXPORT_SYMBOL(bitreverse);
/*
* A brief CRC tutorial.
static void bytereverse(unsigned char *buf, size_t len)
{
while (len--) {
- unsigned char x = *buf;
- x = (x >> 4) | (x << 4);
- x = (x >> 2 & 0x33) | (x << 2 & 0xcc);
- x = (x >> 1 & 0x55) | (x << 1 & 0xaa);
+ unsigned char x = bitrev8(*buf);
*buf++ = x;
}
}
/* Now swap it around for the other test */
bytereverse(buf, len + 4);
- init = bitreverse(init);
- crc2 = bitreverse(crc1);
- if (crc1 != bitreverse(crc2))
+ init = bitrev32(init);
+ crc2 = bitrev32(crc1);
+ if (crc1 != bitrev32(crc2))
printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
- crc1, crc2, bitreverse(crc2));
+ crc1, crc2, bitrev32(crc2));
crc1 = crc32_le(init, buf, len);
if (crc1 != crc2)
printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/unwind.h>
+#include <linux/stacktrace.h>
+#include <linux/kallsyms.h>
+#include <linux/fault-inject.h>
+
+/*
+ * setup_fault_attr() is a helper function for various __setup handlers, so it
+ * returns 0 on error, because that is what __setup handlers do.
+ */
+int __init setup_fault_attr(struct fault_attr *attr, char *str)
+{
+ unsigned long probability;
+ unsigned long interval;
+ int times;
+ int space;
+
+ /* "<interval>,<probability>,<space>,<times>" */
+ if (sscanf(str, "%lu,%lu,%d,%d",
+ &interval, &probability, &space, ×) < 4) {
+ printk(KERN_WARNING
+ "FAULT_INJECTION: failed to parse arguments\n");
+ return 0;
+ }
+
+ attr->probability = probability;
+ attr->interval = interval;
+ atomic_set(&attr->times, times);
+ atomic_set(&attr->space, space);
+
+ return 1;
+}
+
+static void fail_dump(struct fault_attr *attr)
+{
+ if (attr->verbose > 0)
+ printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure\n");
+ if (attr->verbose > 1)
+ dump_stack();
+}
+
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+
+static bool fail_task(struct fault_attr *attr, struct task_struct *task)
+{
+ return !in_interrupt() && task->make_it_fail;
+}
+
+#define MAX_STACK_TRACE_DEPTH 32
+
+#ifdef CONFIG_STACK_UNWIND
+
+static asmlinkage int fail_stacktrace_callback(struct unwind_frame_info *info,
+ void *arg)
+{
+ int depth;
+ struct fault_attr *attr = arg;
+ bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
+
+ for (depth = 0; depth < attr->stacktrace_depth
+ && unwind(info) == 0 && UNW_PC(info); depth++) {
+ if (arch_unw_user_mode(info))
+ break;
+ if (attr->reject_start <= UNW_PC(info) &&
+ UNW_PC(info) < attr->reject_end)
+ return false;
+ if (attr->require_start <= UNW_PC(info) &&
+ UNW_PC(info) < attr->require_end)
+ found = true;
+ }
+ return found;
+}
+
+static bool fail_stacktrace(struct fault_attr *attr)
+{
+ struct unwind_frame_info info;
+
+ return unwind_init_running(&info, fail_stacktrace_callback, attr);
+}
+
+#elif defined(CONFIG_STACKTRACE)
+
+static bool fail_stacktrace(struct fault_attr *attr)
+{
+ struct stack_trace trace;
+ int depth = attr->stacktrace_depth;
+ unsigned long entries[MAX_STACK_TRACE_DEPTH];
+ int n;
+ bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
+
+ if (depth == 0)
+ return found;
+
+ trace.nr_entries = 0;
+ trace.entries = entries;
+ trace.max_entries = depth;
+ trace.skip = 1;
+ trace.all_contexts = 0;
+
+ save_stack_trace(&trace, NULL);
+ for (n = 0; n < trace.nr_entries; n++) {
+ if (attr->reject_start <= entries[n] &&
+ entries[n] < attr->reject_end)
+ return false;
+ if (attr->require_start <= entries[n] &&
+ entries[n] < attr->require_end)
+ found = true;
+ }
+ return found;
+}
+
+#else
+
+static inline bool fail_stacktrace(struct fault_attr *attr)
+{
+ static bool firsttime = true;
+
+ if (firsttime) {
+ printk(KERN_WARNING
+ "This architecture does not implement save_stack_trace()\n");
+ firsttime = false;
+ }
+ return false;
+}
+
+#endif
+
+/*
+ * This code is stolen from failmalloc-1.0
+ * http://www.nongnu.org/failmalloc/
+ */
+
+bool should_fail(struct fault_attr *attr, ssize_t size)
+{
+ if (attr->task_filter && !fail_task(attr, current))
+ return false;
+
+ if (atomic_read(&attr->times) == 0)
+ return false;
+
+ if (atomic_read(&attr->space) > size) {
+ atomic_sub(size, &attr->space);
+ return false;
+ }
+
+ if (attr->interval > 1) {
+ attr->count++;
+ if (attr->count % attr->interval)
+ return false;
+ }
+
+ if (attr->probability <= random32() % 100)
+ return false;
+
+ if (!fail_stacktrace(attr))
+ return false;
+
+ fail_dump(attr);
+
+ if (atomic_read(&attr->times) != -1)
+ atomic_dec_not_zero(&attr->times);
+
+ return true;
+}
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static void debugfs_ul_set(void *data, u64 val)
+{
+ *(unsigned long *)data = val;
+}
+
+static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val)
+{
+ *(unsigned long *)data =
+ val < MAX_STACK_TRACE_DEPTH ?
+ val : MAX_STACK_TRACE_DEPTH;
+}
+
+static u64 debugfs_ul_get(void *data)
+{
+ return *(unsigned long *)data;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n");
+
+static struct dentry *debugfs_create_ul(const char *name, mode_t mode,
+ struct dentry *parent, unsigned long *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_ul);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_ul_MAX_STACK_TRACE_DEPTH, debugfs_ul_get,
+ debugfs_ul_set_MAX_STACK_TRACE_DEPTH, "%llu\n");
+
+static struct dentry *debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
+ const char *name, mode_t mode,
+ struct dentry *parent, unsigned long *value)
+{
+ return debugfs_create_file(name, mode, parent, value,
+ &fops_ul_MAX_STACK_TRACE_DEPTH);
+}
+
+static void debugfs_atomic_t_set(void *data, u64 val)
+{
+ atomic_set((atomic_t *)data, val);
+}
+
+static u64 debugfs_atomic_t_get(void *data)
+{
+ return atomic_read((atomic_t *)data);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
+ debugfs_atomic_t_set, "%lld\n");
+
+static struct dentry *debugfs_create_atomic_t(const char *name, mode_t mode,
+ struct dentry *parent, atomic_t *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_atomic_t);
+}
+
+void cleanup_fault_attr_dentries(struct fault_attr *attr)
+{
+ debugfs_remove(attr->dentries.probability_file);
+ attr->dentries.probability_file = NULL;
+
+ debugfs_remove(attr->dentries.interval_file);
+ attr->dentries.interval_file = NULL;
+
+ debugfs_remove(attr->dentries.times_file);
+ attr->dentries.times_file = NULL;
+
+ debugfs_remove(attr->dentries.space_file);
+ attr->dentries.space_file = NULL;
+
+ debugfs_remove(attr->dentries.verbose_file);
+ attr->dentries.verbose_file = NULL;
+
+ debugfs_remove(attr->dentries.task_filter_file);
+ attr->dentries.task_filter_file = NULL;
+
+ debugfs_remove(attr->dentries.stacktrace_depth_file);
+ attr->dentries.stacktrace_depth_file = NULL;
+
+ debugfs_remove(attr->dentries.require_start_file);
+ attr->dentries.require_start_file = NULL;
+
+ debugfs_remove(attr->dentries.require_end_file);
+ attr->dentries.require_end_file = NULL;
+
+ debugfs_remove(attr->dentries.reject_start_file);
+ attr->dentries.reject_start_file = NULL;
+
+ debugfs_remove(attr->dentries.reject_end_file);
+ attr->dentries.reject_end_file = NULL;
+
+ if (attr->dentries.dir)
+ WARN_ON(!simple_empty(attr->dentries.dir));
+
+ debugfs_remove(attr->dentries.dir);
+ attr->dentries.dir = NULL;
+}
+
+int init_fault_attr_dentries(struct fault_attr *attr, const char *name)
+{
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+
+ memset(&attr->dentries, 0, sizeof(attr->dentries));
+
+ dir = debugfs_create_dir(name, NULL);
+ if (!dir)
+ goto fail;
+ attr->dentries.dir = dir;
+
+ attr->dentries.probability_file =
+ debugfs_create_ul("probability", mode, dir, &attr->probability);
+
+ attr->dentries.interval_file =
+ debugfs_create_ul("interval", mode, dir, &attr->interval);
+
+ attr->dentries.times_file =
+ debugfs_create_atomic_t("times", mode, dir, &attr->times);
+
+ attr->dentries.space_file =
+ debugfs_create_atomic_t("space", mode, dir, &attr->space);
+
+ attr->dentries.verbose_file =
+ debugfs_create_ul("verbose", mode, dir, &attr->verbose);
+
+ attr->dentries.task_filter_file = debugfs_create_bool("task-filter",
+ mode, dir, &attr->task_filter);
+
+ attr->dentries.stacktrace_depth_file =
+ debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
+ "stacktrace-depth", mode, dir, &attr->stacktrace_depth);
+
+ attr->dentries.require_start_file =
+ debugfs_create_ul("require-start", mode, dir, &attr->require_start);
+
+ attr->dentries.require_end_file =
+ debugfs_create_ul("require-end", mode, dir, &attr->require_end);
+
+ attr->dentries.reject_start_file =
+ debugfs_create_ul("reject-start", mode, dir, &attr->reject_start);
+
+ attr->dentries.reject_end_file =
+ debugfs_create_ul("reject-end", mode, dir, &attr->reject_end);
+
+
+ if (!attr->dentries.probability_file || !attr->dentries.interval_file
+ || !attr->dentries.times_file || !attr->dentries.space_file
+ || !attr->dentries.verbose_file || !attr->dentries.task_filter_file
+ || !attr->dentries.stacktrace_depth_file
+ || !attr->dentries.require_start_file
+ || !attr->dentries.require_end_file
+ || !attr->dentries.reject_start_file
+ || !attr->dentries.reject_end_file
+ )
+ goto fail;
+
+ return 0;
+fail:
+ cleanup_fault_attr_dentries(attr);
+ return -ENOMEM;
+}
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
if (!file)
return -EBADF;
- if (S_ISFIFO(file->f_dentry->d_inode->i_mode)) {
+ if (S_ISFIFO(file->f_path.dentry->d_inode->i_mode)) {
ret = -ESPIPE;
goto out;
}
if (count == 0)
goto out;
- err = remove_suid(file->f_dentry);
+ err = remove_suid(file->f_path.dentry);
if (err)
goto out;
if (count == 0)
goto out_backing;
- ret = remove_suid(filp->f_dentry);
+ ret = remove_suid(filp->f_path.dentry);
if (ret)
goto out_backing;
if (file) {
seq_printf(m, " file=");
- seq_path(m, file->f_vfsmnt, file->f_dentry, "\n\t= ");
+ seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n\t= ");
} else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
seq_printf(m, " heap");
} else if (vma->vm_start <= mm->start_stack &&
struct file *file, struct address_space *mapping)
{
if (vma->vm_flags & VM_DENYWRITE)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
+ atomic_inc(&file->f_path.dentry->d_inode->i_writecount);
if (vma->vm_flags & VM_SHARED)
mapping->i_mmap_writable--;
struct address_space *mapping = file->f_mapping;
if (vma->vm_flags & VM_DENYWRITE)
- atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ atomic_dec(&file->f_path.dentry->d_inode->i_writecount);
if (vma->vm_flags & VM_SHARED)
mapping->i_mmap_writable++;
* mounted, in which case we dont add PROT_EXEC.)
*/
if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
- if (!(file && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)))
+ if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC)))
prot |= PROT_EXEC;
if (!len)
return -EAGAIN;
}
- inode = file ? file->f_dentry->d_inode : NULL;
+ inode = file ? file->f_path.dentry->d_inode : NULL;
if (file) {
switch (flags & MAP_TYPE) {
case MAP_PRIVATE:
if (!(file->f_mode & FMODE_READ))
return -EACCES;
- if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
+ if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
if (vm_flags & VM_EXEC)
return -EPERM;
vm_flags &= ~VM_MAYEXEC;
*/
mapping = file->f_mapping;
if (!mapping)
- mapping = file->f_dentry->d_inode->i_mapping;
+ mapping = file->f_path.dentry->d_inode->i_mapping;
capabilities = 0;
if (mapping && mapping->backing_dev_info)
if (!capabilities) {
/* no explicit capabilities set, so assume some
* defaults */
- switch (file->f_dentry->d_inode->i_mode & S_IFMT) {
+ switch (file->f_path.dentry->d_inode->i_mode & S_IFMT) {
case S_IFREG:
case S_IFBLK:
capabilities = BDI_CAP_MAP_COPY;
!(file->f_mode & FMODE_WRITE))
return -EACCES;
- if (IS_APPEND(file->f_dentry->d_inode) &&
+ if (IS_APPEND(file->f_path.dentry->d_inode) &&
(file->f_mode & FMODE_WRITE))
return -EACCES;
- if (locks_verify_locked(file->f_dentry->d_inode))
+ if (locks_verify_locked(file->f_path.dentry->d_inode))
return -EAGAIN;
if (!(capabilities & BDI_CAP_MAP_DIRECT))
/* handle executable mappings and implied executable
* mappings */
- if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
+ if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
if (prot & PROT_EXEC)
return -EPERM;
}
continue;
/* search for overlapping mappings on the same file */
- if (vma->vm_file->f_dentry->d_inode != file->f_dentry->d_inode)
+ if (vma->vm_file->f_path.dentry->d_inode != file->f_path.dentry->d_inode)
continue;
if (vma->vm_pgoff >= pgoff + pglen)
#include <linux/sort.h>
#include <linux/pfn.h>
#include <linux/backing-dev.h>
+#include <linux/fault-inject.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
+#ifdef CONFIG_FAIL_PAGE_ALLOC
+
+static struct fail_page_alloc_attr {
+ struct fault_attr attr;
+
+ u32 ignore_gfp_highmem;
+ u32 ignore_gfp_wait;
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+ struct dentry *ignore_gfp_highmem_file;
+ struct dentry *ignore_gfp_wait_file;
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+} fail_page_alloc = {
+ .attr = FAULT_ATTR_INITIALIZER,
+ .ignore_gfp_wait = 1,
+ .ignore_gfp_highmem = 1,
+};
+
+static int __init setup_fail_page_alloc(char *str)
+{
+ return setup_fault_attr(&fail_page_alloc.attr, str);
+}
+__setup("fail_page_alloc=", setup_fail_page_alloc);
+
+static int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+{
+ if (gfp_mask & __GFP_NOFAIL)
+ return 0;
+ if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
+ return 0;
+ if (fail_page_alloc.ignore_gfp_wait && (gfp_mask & __GFP_WAIT))
+ return 0;
+
+ return should_fail(&fail_page_alloc.attr, 1 << order);
+}
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static int __init fail_page_alloc_debugfs(void)
+{
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+ int err;
+
+ err = init_fault_attr_dentries(&fail_page_alloc.attr,
+ "fail_page_alloc");
+ if (err)
+ return err;
+ dir = fail_page_alloc.attr.dentries.dir;
+
+ fail_page_alloc.ignore_gfp_wait_file =
+ debugfs_create_bool("ignore-gfp-wait", mode, dir,
+ &fail_page_alloc.ignore_gfp_wait);
+
+ fail_page_alloc.ignore_gfp_highmem_file =
+ debugfs_create_bool("ignore-gfp-highmem", mode, dir,
+ &fail_page_alloc.ignore_gfp_highmem);
+
+ if (!fail_page_alloc.ignore_gfp_wait_file ||
+ !fail_page_alloc.ignore_gfp_highmem_file) {
+ err = -ENOMEM;
+ debugfs_remove(fail_page_alloc.ignore_gfp_wait_file);
+ debugfs_remove(fail_page_alloc.ignore_gfp_highmem_file);
+ cleanup_fault_attr_dentries(&fail_page_alloc.attr);
+ }
+
+ return err;
+}
+
+late_initcall(fail_page_alloc_debugfs);
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#else /* CONFIG_FAIL_PAGE_ALLOC */
+
+static inline int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
+{
+ return 0;
+}
+
+#endif /* CONFIG_FAIL_PAGE_ALLOC */
+
/*
* Return 1 if free pages are above 'mark'. This takes into account the order
* of the allocation.
might_sleep_if(wait);
+ if (should_fail_alloc_page(gfp_mask, order))
+ return NULL;
+
restart:
z = zonelist->zones; /* the list of zones suitable for gfp_mask */
if (numentries > max)
numentries = max;
- log2qty = long_log2(numentries);
+ log2qty = ilog2(numentries);
do {
size = bucketsize << log2qty;
printk("%s hash table entries: %d (order: %d, %lu bytes)\n",
tablename,
(1U << log2qty),
- long_log2(size) - PAGE_SHIFT,
+ ilog2(size) - PAGE_SHIFT,
size);
if (_hash_shift)
*
* Note that @filp is purely used for passing on to the ->readpage[s]()
* handler: it may refer to a different file from @mapping (so we may not use
- * @filp->f_mapping or @filp->f_dentry->d_inode here).
+ * @filp->f_mapping or @filp->f_path.dentry->d_inode here).
* Also, @ra may not be equal to &@filp->f_ra.
*
*/
struct page *shmem_nopage(struct vm_area_struct *vma, unsigned long address, int *type)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
struct page *page = NULL;
unsigned long idx;
int error;
unsigned long addr, unsigned long len,
pgprot_t prot, unsigned long pgoff, int nonblock)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
struct mm_struct *mm = vma->vm_mm;
enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
unsigned long size;
#ifdef CONFIG_NUMA
int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
{
- struct inode *i = vma->vm_file->f_dentry->d_inode;
+ struct inode *i = vma->vm_file->f_path.dentry->d_inode;
return mpol_set_shared_policy(&SHMEM_I(i)->policy, vma, new);
}
struct mempolicy *
shmem_get_policy(struct vm_area_struct *vma, unsigned long addr)
{
- struct inode *i = vma->vm_file->f_dentry->d_inode;
+ struct inode *i = vma->vm_file->f_path.dentry->d_inode;
unsigned long idx;
idx = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
int shmem_lock(struct file *file, int lock, struct user_struct *user)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct shmem_inode_info *info = SHMEM_I(inode);
int retval = -ENOMEM;
static ssize_t
shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
loff_t pos;
unsigned long written;
ssize_t err;
if (err || !count)
goto out;
- err = remove_suid(file->f_dentry);
+ err = remove_suid(file->f_path.dentry);
if (err)
goto out;
static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned long index, offset;
d_instantiate(dentry, inode);
inode->i_size = size;
inode->i_nlink = 0; /* It is unlinked */
- file->f_vfsmnt = mntget(shm_mnt);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(shm_mnt);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_op = &shmem_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ;
#include <linux/nodemask.h>
#include <linux/mempolicy.h>
#include <linux/mutex.h>
+#include <linux/fault-inject.h>
#include <linux/rtmutex.h>
#include <asm/cacheflush.h>
#define cache_alloc_debugcheck_after(a,b,objp,d) (objp)
#endif
+#ifdef CONFIG_FAILSLAB
+
+static struct failslab_attr {
+
+ struct fault_attr attr;
+
+ u32 ignore_gfp_wait;
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+ struct dentry *ignore_gfp_wait_file;
+#endif
+
+} failslab = {
+ .attr = FAULT_ATTR_INITIALIZER,
+ .ignore_gfp_wait = 1,
+};
+
+static int __init setup_failslab(char *str)
+{
+ return setup_fault_attr(&failslab.attr, str);
+}
+__setup("failslab=", setup_failslab);
+
+static int should_failslab(struct kmem_cache *cachep, gfp_t flags)
+{
+ if (cachep == &cache_cache)
+ return 0;
+ if (flags & __GFP_NOFAIL)
+ return 0;
+ if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT))
+ return 0;
+
+ return should_fail(&failslab.attr, obj_size(cachep));
+}
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static int __init failslab_debugfs(void)
+{
+ mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+ struct dentry *dir;
+ int err;
+
+ err = init_fault_attr_dentries(&failslab.attr, "failslab");
+ if (err)
+ return err;
+ dir = failslab.attr.dentries.dir;
+
+ failslab.ignore_gfp_wait_file =
+ debugfs_create_bool("ignore-gfp-wait", mode, dir,
+ &failslab.ignore_gfp_wait);
+
+ if (!failslab.ignore_gfp_wait_file) {
+ err = -ENOMEM;
+ debugfs_remove(failslab.ignore_gfp_wait_file);
+ cleanup_fault_attr_dentries(&failslab.attr);
+ }
+
+ return err;
+}
+
+late_initcall(failslab_debugfs);
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
+
+#else /* CONFIG_FAILSLAB */
+
+static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags)
+{
+ return 0;
+}
+
+#endif /* CONFIG_FAILSLAB */
+
static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
{
void *objp;
struct array_cache *ac;
check_irq_off();
+
+ if (should_failslab(cachep, flags))
+ return NULL;
+
ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
STATS_INC_ALLOCHIT(cachep);
for (z = zonelist->zones; *z && !obj; z++) {
nid = zone_to_nid(*z);
- if (cpuset_zone_allowed(*z, flags) &&
+ if (cpuset_zone_allowed(*z, flags | __GFP_HARDWALL) &&
cache->nodelists[nid] &&
cache->nodelists[nid]->free_objects)
obj = ____cache_alloc_node(cache,
}
file = ptr->swap_file;
- len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+ len = seq_path(swap, file->f_path.mnt, file->f_path.dentry, " \t\n\\");
seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",
len < 40 ? 40 - len : 1, " ",
- S_ISBLK(file->f_dentry->d_inode->i_mode) ?
+ S_ISBLK(file->f_path.dentry->d_inode->i_mode) ?
"partition" : "file\t",
ptr->pages << (PAGE_SHIFT - 10),
ptr->inuse_pages << (PAGE_SHIFT - 10),
d_instantiate(dentry, inode);
inode->i_nlink = 0; /* It is unlinked */
- file->f_vfsmnt = mntget(shm_mnt);
- file->f_dentry = dentry;
+ file->f_path.mnt = mntget(shm_mnt);
+ file->f_path.dentry = dentry;
file->f_mapping = inode->i_mapping;
file->f_op = &ramfs_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ;
if (count == 0) return 0;
page = get_zeroed_page(GFP_KERNEL);
if (!page) return -ENOMEM;
- dev = PDE(file->f_dentry->d_inode)->data;
+ dev = PDE(file->f_path.dentry->d_inode)->data;
if (!dev->ops->proc_read)
length = -EINVAL;
else {
return -ENOIOCTLCMD;
}
-static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct termios *new = (struct termios *) tty->termios;
+ struct ktermios *new = tty->termios;
int old_baud_rate = tty_termios_baud_rate(old);
int new_baud_rate = tty_termios_baud_rate(new);
{
#define PROC_WRITELEN 10
char buffer[PROC_WRITELEN+1];
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct clusterip_config *c = pde->data;
unsigned long nodenum;
static ssize_t recent_proc_write(struct file *file, const char __user *input,
size_t size, loff_t *loff)
{
- struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct recent_table *t = pde->data;
struct recent_entry *e;
char buf[sizeof("+255.255.255.255")], *c = buf;
* do something rational.
*/
void ircomm_tty_set_termios(struct tty_struct *tty,
- struct termios *old_termios)
+ struct ktermios *old_termios)
{
struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
struct sock *netlink_getsockbyfilp(struct file *filp)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct sock *sock;
if (!S_ISSOCK(inode->i_mode))
this.name = name;
this.hash = 0;
- file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
- if (unlikely(!file->f_dentry))
+ file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+ if (unlikely(!file->f_path.dentry))
return -ENOMEM;
- file->f_dentry->d_op = &sockfs_dentry_operations;
+ file->f_path.dentry->d_op = &sockfs_dentry_operations;
/*
* We dont want to push this dentry into global dentry hash table.
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
* This permits a working /proc/$pid/fd/XXX on sockets
*/
- file->f_dentry->d_flags &= ~DCACHE_UNHASHED;
- d_instantiate(file->f_dentry, SOCK_INODE(sock));
- file->f_vfsmnt = mntget(sock_mnt);
- file->f_mapping = file->f_dentry->d_inode->i_mapping;
+ file->f_path.dentry->d_flags &= ~DCACHE_UNHASHED;
+ d_instantiate(file->f_path.dentry, SOCK_INODE(sock));
+ file->f_path.mnt = mntget(sock_mnt);
+ file->f_mapping = file->f_path.dentry->d_inode->i_mapping;
sock->file = file;
file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops;
if (file->f_op == &socket_file_ops)
return file->private_data; /* set in sock_map_fd */
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!S_ISSOCK(inode->i_mode)) {
*err = -ENOTSOCK;
return NULL;
if (!buf)
goto out;
- clnt = RPC_I(filp->f_dentry->d_inode)->private;
+ clnt = RPC_I(filp->f_path.dentry->d_inode)->private;
err = -EFAULT;
if (copy_from_user(buf, src, mlen))
goto err;
{
struct cache_reader *rp = filp->private_data;
struct cache_request *rq;
- struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
int err;
if (count == 0)
loff_t *ppos)
{
int err;
- struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
if (count == 0)
return 0;
unsigned int mask;
struct cache_reader *rp = filp->private_data;
struct cache_queue *cq;
- struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data;
poll_wait(filp, &queue_wait, wait);
static ssize_t read_flush(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct cache_detail *cd = PDE(file->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
char tbuf[20];
unsigned long p = *ppos;
int len;
static ssize_t write_flush(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct cache_detail *cd = PDE(file->f_dentry->d_inode)->data;
+ struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
char tbuf[20];
char *ep;
long flushtime;
static ssize_t
rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct rpc_inode *rpci = RPC_I(inode);
struct rpc_pipe_msg *msg;
int res = 0;
static ssize_t
rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct rpc_inode *rpci = RPC_I(inode);
int res;
struct rpc_inode *rpci;
unsigned int mask = 0;
- rpci = RPC_I(filp->f_dentry->d_inode);
+ rpci = RPC_I(filp->f_path.dentry->d_inode);
poll_wait(filp, &rpci->waitq, wait);
mask = POLLOUT | POLLWRNORM;
rpc_pipe_ioctl(struct inode *ino, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
+ struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
int len;
switch (cmd) {
static struct sock *unix_get_socket(struct file *filp)
{
struct sock *u_sock = NULL;
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_path.dentry->d_inode;
/*
* Socket ?
printf("#define ALGN .align 4\n");
printf("#endif\n");
- printf(".data\n");
+ printf("\t.section .rodata, \"a\"\n");
/* Provide proper symbols relocatability by their '_text'
* relativeness. The symbol names cannot be used to construct
{
struct task_security_struct *tsec = tsk->security;
struct file_security_struct *fsec = file->f_security;
- struct vfsmount *mnt = file->f_vfsmnt;
- struct dentry *dentry = file->f_dentry;
+ struct vfsmount *mnt = file->f_path.mnt;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct avc_audit_data ad;
int rc;
static int selinux_bprm_set_security(struct linux_binprm *bprm)
{
struct task_security_struct *tsec;
- struct inode *inode = bprm->file->f_dentry->d_inode;
+ struct inode *inode = bprm->file->f_path.dentry->d_inode;
struct inode_security_struct *isec;
struct bprm_security_struct *bsec;
u32 newsid;
}
AVC_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.mnt = bprm->file->f_vfsmnt;
- ad.u.fs.dentry = bprm->file->f_dentry;
+ ad.u.fs.mnt = bprm->file->f_path.mnt;
+ ad.u.fs.dentry = bprm->file->f_path.dentry;
- if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)
+ if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
newsid = tsec->sid;
if (tsec->sid == newsid) {
struct tty_struct *tty;
struct fdtable *fdt;
long j = -1;
+ int drop_tty = 0;
mutex_lock(&tty_mutex);
- tty = current->signal->tty;
+ tty = get_current_tty();
if (tty) {
file_list_lock();
file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
than using file_has_perm, as this particular open
file may belong to another process and we are only
interested in the inode-based check here. */
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (inode_has_perm(current, inode,
FILE__READ | FILE__WRITE, NULL)) {
- /* Reset controlling tty. */
- current->signal->tty = NULL;
- current->signal->tty_old_pgrp = 0;
+ drop_tty = 1;
}
}
file_list_unlock();
+
+ /* Reset controlling tty. */
+ if (drop_tty)
+ proc_set_tty(current, NULL);
}
mutex_unlock(&tty_mutex);
static int selinux_file_permission(struct file *file, int mask)
{
int rc;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
if (!mask) {
/* No permission to check. Existence test. */
switch (cmd) {
case F_SETFL:
- if (!file->f_dentry || !file->f_dentry->d_inode) {
+ if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
err = -EINVAL;
break;
}
case F_SETLK64:
case F_SETLKW64:
#endif
- if (!file->f_dentry || !file->f_dentry->d_inode) {
+ if (!file->f_path.dentry || !file->f_path.dentry->d_inode) {
err = -EINVAL;
break;
}
static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
- ino_t ino = file->f_dentry->d_inode->i_ino;
+ ino_t ino = file->f_path.dentry->d_inode->i_ino;
char *data;
ssize_t rv;
goto out;
}
- inode = filep->f_dentry->d_inode;
+ inode = filep->f_path.dentry->d_inode;
cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
if (cur_enforcing < 0) {
ret = cur_enforcing;
if (new_value)
new_value = 1;
- inode = filep->f_dentry->d_inode;
+ inode = filep->f_path.dentry->d_inode;
bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
length = count;
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file * filp = list_entry(p, struct file, f_u.fu_list);
- struct dentry * dentry = filp->f_dentry;
+ struct dentry * dentry = filp->f_path.dentry;
if (dentry->d_parent != de) {
continue;
static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
struct snd_info_private_data *data;
struct snd_info_entry *entry;
file = fget(fd);
if (!file)
return NULL;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (!S_ISCHR(inode->i_mode) ||
imajor(inode) != snd_major) {
fput(file);
if (file->f_mode & FMODE_WRITE) {
if (write_sq.busy)
- rc = sq_fsync(file, file->f_dentry);
+ rc = sq_fsync(file, file->f_path.dentry);
sq_reset_output() ; /* make sure dma is stopped and all is quiet */
write_sq_release_buffers();
if ((file->f_mode & FMODE_READ) && dmasound.mach.record)
sq_reset_input() ;
if (file->f_mode & FMODE_WRITE) {
- result = sq_fsync(file, file->f_dentry);
+ result = sq_fsync(file, file->f_path.dentry);
sq_reset_output() ;
}
/* if we are the shared resource owner then release them */
static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_t *off)
{
- int minor = iminor(file->f_dentry->d_inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
if (minor == dev.dsp_minor)
return dsp_read(buf, count);
else
static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
- int minor = iminor(file->f_dentry->d_inode);
+ int minor = iminor(file->f_path.dentry->d_inode);
if (minor == dev.dsp_minor)
return dsp_write(buf, count);
else
static ssize_t sound_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
int ret = -EINVAL;
/*
static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
int ret = -EINVAL;
lock_kernel();
static unsigned int sound_poll(struct file *file, poll_table * wait)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int dev = iminor(inode);
DEB(printk("sound_poll(dev=%d)\n", dev));
int dev_class;
unsigned long size;
struct dma_buffparms *dmap = NULL;
- int dev = iminor(file->f_dentry->d_inode);
+ int dev = iminor(file->f_path.dentry->d_inode);
dev_class = dev & 0x0f;
dev >>= 4;
printk(KERN_INFO "Unable to load '%s'.\n", fn);
return 0;
}
- l = filp->f_dentry->d_inode->i_size;
+ l = filp->f_path.dentry->d_inode->i_size;
if (l <= 0 || l > 131072)
{
printk(KERN_INFO "Invalid firmware '%s'\n", fn);