aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavem <davem>2001-12-05 23:43:46 +0000
committerdavem <davem>2001-12-05 23:43:46 +0000
commit2c0c74546941be513fb3c85deb5a386c59bc23b6 (patch)
tree5449db624fd7006284e55507583e11a2690336e3
parent0c3fc2be470a61cc411b070a85dca0592c415273 (diff)
downloadnetdev-vger-cvs-2c0c74546941be513fb3c85deb5a386c59bc23b6.tar.gz
Merge mainline to 2.4.17-pre4
-rw-r--r--CREDITS10
-rw-r--r--Documentation/Configure.help27
-rw-r--r--Documentation/filesystems/devfs/ChangeLog10
-rw-r--r--MAINTAINERS8
-rw-r--r--Makefile2
-rw-r--r--arch/i386/config.in6
-rw-r--r--drivers/ide/ide-tape.c1
-rw-r--r--drivers/isdn/Config.in1
-rw-r--r--drivers/isdn/hisax/Makefile3
-rw-r--r--drivers/isdn/hisax/config.c8
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c1001
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.h57
-rw-r--r--drivers/isdn/hisax/hisax_isac.c896
-rw-r--r--drivers/isdn/hisax/hisax_isac.h45
-rw-r--r--drivers/net/eepro100.c16
-rw-r--r--drivers/sound/ad1848.c7
-rw-r--r--drivers/sound/cs46xx.c2
-rw-r--r--drivers/sound/ymfpci.c102
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/devices.c5
-rw-r--r--drivers/usb/serial/visor.c5
-rw-r--r--drivers/video/aty/atyfb_base.c134
-rw-r--r--drivers/video/modedb.c2
-rw-r--r--fs/coda/cache.c4
-rw-r--r--fs/coda/cnode.c6
-rw-r--r--fs/coda/dir.c21
-rw-r--r--fs/coda/file.c5
-rw-r--r--fs/coda/inode.c16
-rw-r--r--fs/coda/pioctl.c3
-rw-r--r--fs/coda/psdev.c7
-rw-r--r--fs/coda/sysctl.c3
-rw-r--r--fs/coda/upcall.c11
-rw-r--r--fs/cramfs/inode.c20
-rw-r--r--fs/devfs/base.c34
-rw-r--r--include/linux/coda_linux.h6
-rw-r--r--include/linux/mm.h6
-rw-r--r--include/linux/pci_ids.h1
-rw-r--r--include/linux/usb.h5
-rw-r--r--kernel/time.c8
-rw-r--r--mm/memory.c19
40 files changed, 2296 insertions, 228 deletions
diff --git a/CREDITS b/CREDITS
index ae2ea995c..9d23d88cd 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1147,6 +1147,16 @@ S: 77 Clarence Mews
S: London SE16 1GD
S: United Kingdom
+N: Jan Harkes
+E: jaharkes@cs.cmu.edu
+W: http://www.coda.cs.cmu.edu/
+D: Coda file system
+S: Computer Science Department
+S: Carnegie Mellon University
+S: 5000 Forbes Avenue
+S: Pittsburgh, Pennsylvania 15213
+S: USA
+
N: Kai Harrekilde-Petersen
E: kai.harrekilde@get2net.dk
D: Original author of the ftape-HOWTO, i82078 fdc detection code.
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index f24201259..5c02e7f8c 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -13818,30 +13818,11 @@ Virtual memory file system support
CONFIG_TMPFS
Tmpfs is a file system which keeps all files in virtual memory.
- In contrast to RAM disks, which get allocated a fixed amount of
- physical RAM, tmpfs grows and shrinks to accommodate the files it
- contains and is able to swap unneeded pages out to swap space.
+ Everything in tmpfs is temporary in the sense that no files will be
+ created on your hard drive. If you reboot, everything in tmpfs will
+ be lost.
- Everything is "virtual" in the sense that no files will be created
- on your hard drive; if you reboot, everything in tmpfs will be
- lost.
-
- You should mount the file system somewhere to be able to use
- POSIX shared memory. Adding the following line to /etc/fstab should
- take care of things:
-
- tmpfs /dev/shm tmpfs defaults 0 0
-
- Remember to create the directory that you intend to mount tmpfs on
- if necessary (/dev/shm is automagically created if you use devfs).
-
- You can set limits for the number of blocks and inodes used by the
- file system with the mount options "size", "nr_blocks" and
- "nr_inodes". These parameters accept a suffix k, m or g for kilo,
- mega and giga and can be changed on remount.
-
- The initial permissions of the root directory can be set with the
- mount option "mode".
+ See <file:Documentation/filesystems/tmpfs.txt> for details
Simple RAM-based file system support
CONFIG_RAMFS
diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog
index 3a8b9b5eb..f8b1c4899 100644
--- a/Documentation/filesystems/devfs/ChangeLog
+++ b/Documentation/filesystems/devfs/ChangeLog
@@ -1805,3 +1805,13 @@ Changes for patch v199
- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd
or children
+===============================================================================
+Changes for patch v199.1
+
+- Fixed bug in <devfsd_read>: was dereferencing freed pointer
+===============================================================================
+Changes for patch v199.2
+
+- Fixed bug in <devfsd_close>: was dereferencing freed pointer
+
+- Added process group check for devfsd privileges
diff --git a/MAINTAINERS b/MAINTAINERS
index 8e2f75c31..a92b3d077 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -285,6 +285,14 @@ P: Nils Faerber (port to kernel 2.4)
M: Nils Faerber <nils@kernelconcepts.de>
S: Maintained
+CODA FILE SYSTEM
+P: Jan Harkes
+M: jaharkes@cs.cmu.edu
+M: coda@cs.cmu.edu
+L: codalist@coda.cs.cmu.edu
+W: http://www.coda.cs.cmu.edu/
+S: Maintained
+
COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
P: Amy Vanzant-Hodge
M: Amy Vanzant-Hodge (fibrechannel@compaq.com)
diff --git a/Makefile b/Makefile
index 6287f3704..a9848f311 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 17
-EXTRAVERSION =-pre2
+EXTRAVERSION =-pre4
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff --git a/arch/i386/config.in b/arch/i386/config.in
index a4c4efd7a..76c3a2dba 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -52,6 +52,7 @@ if [ "$CONFIG_M386" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 4
define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+ define_bool CONFIG_X86_PPRO_FENCE y
else
define_bool CONFIG_X86_WP_WORKS_OK y
define_bool CONFIG_X86_INVLPG y
@@ -66,17 +67,20 @@ if [ "$CONFIG_M486" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 4
define_bool CONFIG_X86_USE_STRING_486 y
define_bool CONFIG_X86_ALIGNMENT_16 y
+ define_bool CONFIG_X86_PPRO_FENCE y
fi
if [ "$CONFIG_M586" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_USE_STRING_486 y
define_bool CONFIG_X86_ALIGNMENT_16 y
+ define_bool CONFIG_X86_PPRO_FENCE y
fi
if [ "$CONFIG_M586TSC" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_USE_STRING_486 y
define_bool CONFIG_X86_ALIGNMENT_16 y
define_bool CONFIG_X86_TSC y
+ define_bool CONFIG_X86_PPRO_FENCE y
fi
if [ "$CONFIG_M586MMX" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
@@ -84,6 +88,7 @@ if [ "$CONFIG_M586MMX" = "y" ]; then
define_bool CONFIG_X86_ALIGNMENT_16 y
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_GOOD_APIC y
+ define_bool CONFIG_X86_PPRO_FENCE y
fi
if [ "$CONFIG_M686" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
@@ -91,6 +96,7 @@ if [ "$CONFIG_M686" = "y" ]; then
define_bool CONFIG_X86_GOOD_APIC y
define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+ define_bool CONFIG_X86_PPRO_FENCE y
fi
if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index d31630b24..a29fc5488 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -6182,6 +6182,7 @@ static struct file_operations idetape_fops = {
};
MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
static void __exit idetape_exit (void)
{
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 30ccb26c3..707940b33 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -81,6 +81,7 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
+ dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
fi
endmenu
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 9f1a1f657..0b49772e8 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -6,7 +6,7 @@ O_TARGET := vmlinux-obj.o
# Objects that export symbols.
-export-objs := config.o fsm.o
+export-objs := config.o fsm.o hisax_isac.o
# Multipart objects.
@@ -58,6 +58,7 @@ obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
+obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 0af9a604c..583fec931 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1505,15 +1505,9 @@ static int __init HiSax_init(void)
nrcards, (nrcards > 1) ? "s" : "");
/* Install only, if at least one card found */
- if (!HiSax_inithardware(NULL)) {
- retval = -EIO;
- goto out_isdnl1;
- }
-
+ HiSax_inithardware(NULL);
return 0;
- out_isdnl1:
- Isdnl1Free();
out_tei:
TeiFree();
out_isdnl2:
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
new file mode 100644
index 000000000..479e18fa8
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -0,0 +1,1001 @@
+/*
+ * Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards
+ *
+ * Author Kai Germaschewski
+ * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ * 2001 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * based upon Karsten Keil's original avm_pci.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
+ * SoHaNet Technology GmbH, Berlin
+ * for supporting the development of this driver
+ */
+
+
+/* TODO:
+ *
+ * o POWER PC
+ * o clean up debugging
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include "hisax_fcpcipnp.h"
+
+// debugging cruft
+#define __debug_variable debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 0;
+MODULE_PARM(debug, "i");
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");
+
+static struct pci_device_id fcpci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1 , PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI" },
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI v2" },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, fcpci_ids);
+
+static struct isapnp_device_id fcpnp_ids[] __devinitdata = {
+ { ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
+ ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
+ (unsigned long) "Fritz!Card PnP" },
+ { }
+};
+MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
+
+static int protocol = 2; /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+// ----------------------------------------------------------------------
+
+#define AVM_INDEX 0x04
+#define AVM_DATA 0x10
+
+#define AVM_IDX_HDLC_1 0x00
+#define AVM_IDX_HDLC_2 0x01
+#define AVM_IDX_ISAC_FIFO 0x02
+#define AVM_IDX_ISAC_REG_LOW 0x04
+#define AVM_IDX_ISAC_REG_HIGH 0x06
+
+#define AVM_STATUS0 0x02
+
+#define AVM_STATUS0_IRQ_ISAC 0x01
+#define AVM_STATUS0_IRQ_HDLC 0x02
+#define AVM_STATUS0_IRQ_TIMER 0x04
+#define AVM_STATUS0_IRQ_MASK 0x07
+
+#define AVM_STATUS0_RESET 0x01
+#define AVM_STATUS0_DIS_TIMER 0x02
+#define AVM_STATUS0_RES_TIMER 0x04
+#define AVM_STATUS0_ENA_IRQ 0x08
+#define AVM_STATUS0_TESTBIT 0x10
+
+#define AVM_STATUS1 0x03
+#define AVM_STATUS1_ENA_IOM 0x80
+
+#define HDLC_FIFO 0x0
+#define HDLC_STATUS 0x4
+#define HDLC_CTRL 0x4
+
+#define HDLC_MODE_ITF_FLG 0x01
+#define HDLC_MODE_TRANS 0x02
+#define HDLC_MODE_CCR_7 0x04
+#define HDLC_MODE_CCR_16 0x08
+#define HDLC_MODE_TESTLOOP 0x80
+
+#define HDLC_INT_XPR 0x80
+#define HDLC_INT_XDU 0x40
+#define HDLC_INT_RPR 0x20
+#define HDLC_INT_MASK 0xE0
+
+#define HDLC_STAT_RME 0x01
+#define HDLC_STAT_RDO 0x10
+#define HDLC_STAT_CRCVFRRAB 0x0E
+#define HDLC_STAT_CRCVFR 0x06
+#define HDLC_STAT_RML_MASK 0x3f00
+
+#define HDLC_CMD_XRS 0x80
+#define HDLC_CMD_XME 0x01
+#define HDLC_CMD_RRS 0x20
+#define HDLC_CMD_XML_MASK 0x3f00
+
+#define AVM_HDLC_FIFO_1 0x10
+#define AVM_HDLC_FIFO_2 0x18
+
+#define AVM_HDLC_STATUS_1 0x14
+#define AVM_HDLC_STATUS_2 0x1c
+
+#define AVM_ISACSX_INDEX 0x04
+#define AVM_ISACSX_DATA 0x08
+
+// ----------------------------------------------------------------------
+// Fritz!PCI
+
+static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned char idx = (offset > 0x2f) ?
+ AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
+ unsigned char val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outb(idx, adapter->io + AVM_INDEX);
+ val = inb(adapter->io + AVM_DATA + (offset & 0xf));
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ DBG(0x1000, " port %#x, value %#x",
+ offset, val);
+ return val;
+}
+
+static void fcpci_write_isac(struct isac *isac, unsigned char offset,
+ unsigned char value)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned char idx = (offset > 0x2f) ?
+ AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
+ unsigned long flags;
+
+ DBG(0x1000, " port %#x, value %#x",
+ offset, value);
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outb(idx, adapter->io + AVM_INDEX);
+ outb(value, adapter->io + AVM_DATA + (offset & 0xf));
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci_read_isac_fifo(struct isac *isac, unsigned char * data,
+ int size)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
+ insb(adapter->io + AVM_DATA, data, size);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci_write_isac_fifo(struct isac *isac, unsigned char * data,
+ int size)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX);
+ outsb(adapter->io + AVM_DATA, data, size);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr)
+{
+ u32 val;
+ int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outl(idx, adapter->io + AVM_INDEX);
+ val = inl(adapter->io + AVM_DATA + HDLC_STATUS);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ return val;
+}
+
+static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+
+ DBG(0x40, "hdlc %c wr%x ctrl %x",
+ 'A' + bcs->channel, which, bcs->ctrl.ctrl);
+
+ outl(idx, adapter->io + AVM_INDEX);
+ outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL);
+}
+
+static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ __fcpci_write_ctrl(bcs, which);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+// ----------------------------------------------------------------------
+// Fritz!PCI v2
+
+static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned char val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outl(offset, adapter->io + AVM_ISACSX_INDEX);
+ val = inl(adapter->io + AVM_ISACSX_DATA);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ DBG(0x1000, " port %#x, value %#x",
+ offset, val);
+
+ return val;
+}
+
+static void fcpci2_write_isac(struct isac *isac, unsigned char offset,
+ unsigned char value)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned long flags;
+
+ DBG(0x1000, " port %#x, value %#x",
+ offset, value);
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outl(offset, adapter->io + AVM_ISACSX_INDEX);
+ outl(value, adapter->io + AVM_ISACSX_DATA);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char * data,
+ int size)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outl(0, adapter->io + AVM_ISACSX_INDEX);
+ for (i = 0; i < size; i++)
+ data[i] = inl(adapter->io + AVM_ISACSX_DATA);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char * data,
+ int size)
+{
+ struct fritz_adapter *adapter = isac->priv;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outl(0, adapter->io + AVM_ISACSX_INDEX);
+ for (i = 0; i < size; i++)
+ outl(data[i], adapter->io + AVM_ISACSX_DATA);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr)
+{
+ int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
+
+ return inl(adapter->io + offset);
+}
+
+static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1;
+
+ DBG(0x40, "hdlc %c wr%x ctrl %x",
+ 'A' + bcs->channel, which, bcs->ctrl.ctrl);
+
+ outl(bcs->ctrl.ctrl, adapter->io + offset);
+}
+
+// ----------------------------------------------------------------------
+// Fritz!PnP (ISAC access as for Fritz!PCI)
+
+static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr)
+{
+ unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outb(idx, adapter->io + AVM_INDEX);
+ val = inb(adapter->io + AVM_DATA + HDLC_STATUS);
+ if (val & HDLC_INT_RPR)
+ val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8;
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ return val;
+}
+
+static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+
+ DBG(0x40, "hdlc %c wr%x ctrl %x",
+ 'A' + bcs->channel, which, bcs->ctrl.ctrl);
+
+ outb(idx, adapter->io + AVM_INDEX);
+ if (which & 4)
+ outb(bcs->ctrl.sr.mode,
+ adapter->io + AVM_DATA + HDLC_STATUS + 2);
+ if (which & 2)
+ outb(bcs->ctrl.sr.xml,
+ adapter->io + AVM_DATA + HDLC_STATUS + 1);
+ if (which & 1)
+ outb(bcs->ctrl.sr.cmd,
+ adapter->io + AVM_DATA + HDLC_STATUS + 0);
+}
+
+static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ __fcpnp_write_ctrl(bcs, which);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+}
+
+// ----------------------------------------------------------------------
+
+static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
+
+ DBG(2, "pr %#x", pr);
+ ifc->l1l2(ifc, pr, arg);
+}
+
+static void hdlc_fill_fifo(struct fritz_bcs *bcs)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ struct sk_buff *skb = bcs->tx_skb;
+ int count;
+ int fifo_size = 32;
+ unsigned long flags;
+ unsigned char *p;
+
+ DBG(0x40, "hdlc_fill_fifo");
+
+ if (!skb)
+ BUG();
+
+ if (skb->len == 0)
+ BUG();
+
+ bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME;
+ if (bcs->tx_skb->len > fifo_size) {
+ count = fifo_size;
+ } else {
+ count = bcs->tx_skb->len;
+ if (bcs->mode != L1_MODE_TRANS)
+ bcs->ctrl.sr.cmd |= HDLC_CMD_XME;
+ }
+ DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len);
+ p = bcs->tx_skb->data;
+ skb_pull(bcs->tx_skb, count);
+ bcs->tx_cnt += count;
+ bcs->ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
+
+ switch (adapter->type) {
+ case AVM_FRITZ_PCI:
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ // sets the correct AVM_INDEX, too
+ __fcpci_write_ctrl(bcs, 3);
+ outsl(adapter->io + AVM_DATA + HDLC_FIFO,
+ p, (count + 3) / 4);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ break;
+ case AVM_FRITZ_PCIV2:
+ fcpci2_write_ctrl(bcs, 3);
+ outsl(adapter->io +
+ (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
+ p, (count + 3) / 4);
+ break;
+ case AVM_FRITZ_PNP:
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ // sets the correct AVM_INDEX, too
+ __fcpnp_write_ctrl(bcs, 3);
+ outsb(adapter->io + AVM_DATA, p, count);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+ break;
+ }
+}
+
+static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ unsigned char *p;
+ unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1;
+
+ DBG(0x10, "hdlc_empty_fifo %d", count);
+ if (bcs->rcvidx + count > HSCX_BUFMAX) {
+ DBG(0x10, "hdlc_empty_fifo: incoming packet too large");
+ return;
+ }
+ p = bcs->rcvbuf + bcs->rcvidx;
+ bcs->rcvidx += count;
+ switch (adapter->type) {
+ case AVM_FRITZ_PCI:
+ spin_lock(&adapter->hw_lock);
+ outl(idx, adapter->io + AVM_INDEX);
+ insl(adapter->io + AVM_DATA + HDLC_FIFO,
+ p, (count + 3) / 4);
+ spin_unlock(&adapter->hw_lock);
+ break;
+ case AVM_FRITZ_PCIV2:
+ insl(adapter->io +
+ (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1),
+ p, (count + 3) / 4);
+ break;
+ case AVM_FRITZ_PNP:
+ spin_lock(&adapter->hw_lock);
+ outb(idx, adapter->io + AVM_INDEX);
+ insb(adapter->io + AVM_DATA, p, count);
+ spin_unlock(&adapter->hw_lock);
+ break;
+ }
+}
+
+static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+ struct sk_buff *skb;
+ int len;
+
+ if (stat & HDLC_STAT_RDO) {
+ DBG(0x10, "RDO");
+ bcs->ctrl.sr.xml = 0;
+ bcs->ctrl.sr.cmd |= HDLC_CMD_RRS;
+ adapter->write_ctrl(bcs, 1);
+ bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
+ adapter->write_ctrl(bcs, 1);
+ bcs->rcvidx = 0;
+ return;
+ }
+
+ len = (stat & HDLC_STAT_RML_MASK) >> 8;
+ if (len == 0)
+ len = 32;
+
+ hdlc_empty_fifo(bcs, len);
+
+ if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
+ if (((stat & HDLC_STAT_CRCVFRRAB)== HDLC_STAT_CRCVFR) ||
+ (bcs->mode == L1_MODE_TRANS)) {
+ skb = dev_alloc_skb(bcs->rcvidx);
+ if (!skb) {
+ printk(KERN_WARNING "HDLC: receive out of memory\n");
+ } else {
+ memcpy(skb_put(skb, bcs->rcvidx), bcs->rcvbuf,
+ bcs->rcvidx);
+ DBG_SKB(1, skb);
+ B_L1L2(bcs, PH_DATA | INDICATION, skb);
+ }
+ bcs->rcvidx = 0;
+ } else {
+ DBG(0x10, "ch%d invalid frame %#x",
+ bcs->channel, stat);
+ bcs->rcvidx = 0;
+ }
+ }
+}
+
+static inline void hdlc_xdu_irq(struct fritz_bcs *bcs)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ bcs->ctrl.sr.xml = 0;
+ bcs->ctrl.sr.cmd |= HDLC_CMD_XRS;
+ adapter->write_ctrl(bcs, 1);
+ bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+ adapter->write_ctrl(bcs, 1);
+
+ if (!bcs->tx_skb) {
+ DBG(0x10, "XDU without skb");
+ return;
+ }
+ skb_push(bcs->tx_skb, bcs->tx_cnt);
+ bcs->tx_cnt = 0;
+}
+
+static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
+{
+ struct sk_buff *skb;
+
+ skb = bcs->tx_skb;
+ if (!skb)
+ return;
+
+ if (skb->len) {
+ hdlc_fill_fifo(bcs);
+ return;
+ }
+ bcs->tx_cnt = 0;
+ bcs->tx_skb = NULL;
+ B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+ dev_kfree_skb_irq(skb);
+}
+
+static void hdlc_irq(struct fritz_bcs *bcs, u32 stat)
+{
+ DBG(0x10, "ch%d stat %#x", bcs->channel, stat);
+ if (stat & HDLC_INT_RPR) {
+ DBG(0x10, "RPR");
+ hdlc_rpr_irq(bcs, stat);
+ }
+ if (stat & HDLC_INT_XDU) {
+ DBG(0x10, "XDU");
+ hdlc_xdu_irq(bcs);
+ }
+ if (stat & HDLC_INT_XPR) {
+ DBG(0x10, "XPR");
+ hdlc_xpr_irq(bcs);
+ }
+}
+
+static inline void hdlc_interrupt(struct fritz_adapter *adapter)
+{
+ int nr;
+ u32 stat;
+
+ for (nr = 0; nr < 2; nr++) {
+ stat = adapter->read_hdlc_status(adapter, nr);
+ DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat);
+ if (stat & HDLC_INT_MASK)
+ hdlc_irq(&adapter->bcs[nr], stat);
+ }
+}
+
+static void modehdlc(struct fritz_bcs *bcs, int mode)
+{
+ struct fritz_adapter *adapter = bcs->adapter;
+
+ DBG(0x40, "hdlc %c mode %d --> %d",
+ 'A' + bcs->channel, bcs->mode, mode);
+
+ if (bcs->mode == mode)
+ return;
+
+ bcs->ctrl.ctrl = 0;
+ bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ switch (mode) {
+ case L1_MODE_NULL:
+ bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+ adapter->write_ctrl(bcs, 5);
+ break;
+ case L1_MODE_TRANS:
+ bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+ adapter->write_ctrl(bcs, 5);
+ bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
+ adapter->write_ctrl(bcs, 1);
+ bcs->ctrl.sr.cmd = 0;
+ break;
+ case L1_MODE_HDLC:
+ bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+ adapter->write_ctrl(bcs, 5);
+ bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
+ adapter->write_ctrl(bcs, 1);
+ bcs->ctrl.sr.cmd = 0;
+ break;
+ }
+ bcs->mode = mode;
+}
+
+static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
+{
+ struct fritz_bcs *bcs = ifc->priv;
+ struct sk_buff *skb = arg;
+ int mode;
+
+ DBG(0x10, "pr %#x", pr);
+
+ switch (pr) {
+ case PH_DATA | REQUEST:
+ if (bcs->tx_skb)
+ BUG();
+
+ bcs->tx_skb = skb;
+ DBG_SKB(1, skb);
+ hdlc_fill_fifo(bcs);
+ break;
+ case PH_ACTIVATE | REQUEST:
+ mode = (int) arg;
+ DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
+ modehdlc(bcs, mode);
+ B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
+ break;
+ case PH_DEACTIVATE | REQUEST:
+ DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
+ modehdlc(bcs, L1_MODE_NULL);
+ B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------
+
+static void fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
+{
+ struct fritz_adapter *adapter = dev;
+ unsigned char val;
+
+ val = inb(adapter->io + AVM_STATUS0);
+ if (!(val & AVM_STATUS0_IRQ_MASK))
+ /* hopefully a shared IRQ reqest */
+ return;
+ DBG(2, "STATUS0 %#x", val);
+ if (val & AVM_STATUS0_IRQ_ISAC)
+ isacsx_interrupt(&adapter->isac);
+
+ if (val & AVM_STATUS0_IRQ_HDLC)
+ hdlc_interrupt(adapter);
+}
+
+static void fcpci_irq(int intno, void *dev, struct pt_regs *regs)
+{
+ struct fritz_adapter *adapter = dev;
+ unsigned char sval;
+
+ sval = inb(adapter->io + 2);
+ if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)
+ /* possibly a shared IRQ reqest */
+ return;
+ DBG(2, "sval %#x", sval);
+ if (!(sval & AVM_STATUS0_IRQ_ISAC))
+ isac_interrupt(&adapter->isac);
+
+ if (!(sval & AVM_STATUS0_IRQ_HDLC))
+ hdlc_interrupt(adapter);
+}
+
+// ----------------------------------------------------------------------
+
+static inline void fcpci2_init(struct fritz_adapter *adapter)
+{
+ outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0);
+ outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
+
+}
+
+static inline void fcpci_init(struct fritz_adapter *adapter)
+{
+ outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
+ AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
+
+ outb(AVM_STATUS1_ENA_IOM | adapter->irq,
+ adapter->io + AVM_STATUS1);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(50*HZ / 1000); /* Timeout 50ms */
+}
+
+// ----------------------------------------------------------------------
+
+static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)
+{
+ u32 val = 0;
+ int retval;
+
+ DBG(1,"");
+
+ isac_init(&adapter->isac); // FIXME is this okay now
+
+ retval = -EBUSY;
+ if (!request_region(adapter->io, 32, "fcpcipnp"))
+ goto err;
+
+ switch (adapter->type) {
+ case AVM_FRITZ_PCIV2:
+ retval = request_irq(adapter->irq, fcpci2_irq, SA_SHIRQ,
+ "fcpcipnp", adapter);
+ break;
+ case AVM_FRITZ_PCI:
+ retval = request_irq(adapter->irq, fcpci_irq, SA_SHIRQ,
+ "fcpcipnp", adapter);
+ break;
+ case AVM_FRITZ_PNP:
+ retval = request_irq(adapter->irq, fcpci_irq, 0,
+ "fcpcipnp", adapter);
+ break;
+ }
+ if (retval)
+ goto err_region;
+
+ switch (adapter->type) {
+ case AVM_FRITZ_PCIV2:
+ case AVM_FRITZ_PCI:
+ val = inl(adapter->io);
+ break;
+ case AVM_FRITZ_PNP:
+ val = inb(adapter->io);
+ val |= inb(adapter->io + 1) << 8;
+ break;
+ }
+
+ DBG(1, "stat %#x Class %X Rev %d",
+ val, val & 0xff, (val>>8) & 0xff);
+
+ spin_lock_init(&adapter->hw_lock);
+ adapter->isac.priv = adapter;
+ switch (adapter->type) {
+ case AVM_FRITZ_PCIV2:
+ adapter->isac.read_isac = &fcpci2_read_isac;;
+ adapter->isac.write_isac = &fcpci2_write_isac;
+ adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo;
+ adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo;
+
+ adapter->read_hdlc_status = &fcpci2_read_hdlc_status;
+ adapter->write_ctrl = &fcpci2_write_ctrl;
+ break;
+ case AVM_FRITZ_PCI:
+ adapter->isac.read_isac = &fcpci_read_isac;;
+ adapter->isac.write_isac = &fcpci_write_isac;
+ adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;
+ adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
+
+ adapter->read_hdlc_status = &fcpci_read_hdlc_status;
+ adapter->write_ctrl = &fcpci_write_ctrl;
+ break;
+ case AVM_FRITZ_PNP:
+ adapter->isac.read_isac = &fcpci_read_isac;;
+ adapter->isac.write_isac = &fcpci_write_isac;
+ adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo;
+ adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
+
+ adapter->read_hdlc_status = &fcpnp_read_hdlc_status;
+ adapter->write_ctrl = &fcpnp_write_ctrl;
+ break;
+ }
+
+ // Reset
+ outb(0, adapter->io + AVM_STATUS0);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(50 * HZ / 1000); // 50 msec
+ outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(50 * HZ / 1000); // 50 msec
+ outb(0, adapter->io + AVM_STATUS0);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10 * HZ / 1000); // 10 msec
+
+ switch (adapter->type) {
+ case AVM_FRITZ_PCIV2:
+ fcpci2_init(adapter);
+ isacsx_setup(&adapter->isac);
+ break;
+ case AVM_FRITZ_PCI:
+ case AVM_FRITZ_PNP:
+ fcpci_init(adapter);
+ isac_setup(&adapter->isac);
+ break;
+ }
+ val = adapter->read_hdlc_status(adapter, 0);
+ DBG(0x20, "HDLC A STA %x", val);
+ val = adapter->read_hdlc_status(adapter, 1);
+ DBG(0x20, "HDLC B STA %x", val);
+
+ adapter->bcs[0].mode = -1;
+ adapter->bcs[1].mode = -1;
+ modehdlc(&adapter->bcs[0], L1_MODE_NULL);
+ modehdlc(&adapter->bcs[1], L1_MODE_NULL);
+
+ return 0;
+
+ err_region:
+ release_region(adapter->io, 32);
+ err:
+ return retval;
+}
+
+static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)
+{
+ DBG(1,"");
+
+ outb(0, adapter->io + AVM_STATUS0);
+ free_irq(adapter->irq, adapter);
+ release_region(adapter->io, 32);
+}
+
+// ----------------------------------------------------------------------
+
+static struct fritz_adapter * __devinit
+new_adapter(struct pci_dev *pdev)
+{
+ struct fritz_adapter *adapter;
+ struct hisax_b_if *b_if[2];
+ int i;
+
+ adapter = kmalloc(sizeof(struct fritz_adapter), GFP_KERNEL);
+ if (!adapter)
+ return NULL;
+
+ memset(adapter, 0, sizeof(struct fritz_adapter));
+
+ SET_MODULE_OWNER(&adapter->isac.hisax_d_if);
+ adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
+ adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
+
+ for (i = 0; i < 2; i++) {
+ adapter->bcs[i].adapter = adapter;
+ adapter->bcs[i].channel = i;
+ adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
+ adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;
+ }
+
+ pci_set_drvdata(pdev, adapter);
+
+ for (i = 0; i < 2; i++)
+ b_if[i] = &adapter->bcs[i].b_if;
+
+ hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp", protocol);
+
+ return adapter;
+}
+
+static void delete_adapter(struct fritz_adapter *adapter)
+{
+ hisax_unregister(&adapter->isac.hisax_d_if);
+ kfree(adapter);
+}
+
+static int __devinit fcpci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct fritz_adapter *adapter;
+ int retval;
+
+ retval = -ENOMEM;
+ adapter = new_adapter(pdev);
+ if (!adapter)
+ goto err;
+
+ if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
+ adapter->type = AVM_FRITZ_PCIV2;
+ else
+ adapter->type = AVM_FRITZ_PCI;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err_free;
+
+ adapter->io = pci_resource_start(pdev, 1);
+ adapter->irq = pdev->irq;
+
+ printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
+ (char *) ent->driver_data, pdev->slot_name);
+
+ retval = fcpcipnp_setup(adapter);
+ if (retval)
+ goto err_free;
+
+ return 0;
+
+ err_free:
+ delete_adapter(adapter);
+ err:
+ return retval;
+}
+
+static int __devinit fcpnp_probe(struct pci_dev *pdev,
+ const struct isapnp_device_id *ent)
+{
+ struct fritz_adapter *adapter;
+ int retval;
+
+ retval = -ENOMEM;
+ adapter = new_adapter(pdev);
+ if (!adapter)
+ goto err;
+
+ adapter->type = AVM_FRITZ_PNP;
+
+ pdev->prepare(pdev);
+ pdev->deactivate(pdev); // why?
+ pdev->activate(pdev);
+ adapter->io = pdev->resource[0].start;
+ adapter->irq = pdev->irq_resource[0].start;
+
+ printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",
+ (char *) ent->driver_data, adapter->io, adapter->irq);
+
+ retval = fcpcipnp_setup(adapter);
+ if (retval)
+ goto err_free;
+
+ return 0;
+
+ err_free:
+ delete_adapter(adapter);
+ err:
+ return retval;
+}
+
+static void __devexit fcpci_remove(struct pci_dev *pdev)
+{
+ struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+ fcpcipnp_release(adapter);
+ pci_disable_device(pdev);
+ delete_adapter(adapter);
+}
+
+static void __devexit fcpnp_remove(struct pci_dev *pdev)
+{
+ struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+ fcpcipnp_release(adapter);
+ pdev->deactivate(pdev);
+ delete_adapter(adapter);
+}
+
+static struct pci_driver fcpci_driver = {
+ name: "fcpci",
+ probe: fcpci_probe,
+ remove: fcpci_remove,
+ id_table: fcpci_ids,
+};
+
+static struct isapnp_driver fcpnp_driver = {
+ name: "fcpnp",
+ probe: fcpnp_probe,
+ remove: fcpnp_remove,
+ id_table: fcpnp_ids,
+};
+
+static int __init hisax_fcpcipnp_init(void)
+{
+ int retval, pci_nr_found;
+
+ printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
+
+ retval = pci_register_driver(&fcpci_driver);
+ if (retval < 0)
+ goto out;
+ pci_nr_found = retval;
+
+ retval = isapnp_register_driver(&fcpnp_driver);
+ if (retval < 0)
+ goto out_unregister_pci;
+
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+ if (pci_nr_found + retval == 0) {
+ retval = -ENODEV;
+ goto out_unregister_isapnp;
+ }
+#endif
+ return 0;
+
+#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
+ out_unregister_isapnp:
+ isapnp_unregister_driver(&fcpnp_driver);
+#endif
+ out_unregister_pci:
+ pci_unregister_driver(&fcpci_driver);
+ out:
+ return retval;
+}
+
+static void __exit hisax_fcpcipnp_exit(void)
+{
+ isapnp_unregister_driver(&fcpnp_driver);
+ pci_unregister_driver(&fcpci_driver);
+}
+
+module_init(hisax_fcpcipnp_init);
+module_exit(hisax_fcpcipnp_exit);
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h
new file mode 100644
index 000000000..e0fb0b98b
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.h
@@ -0,0 +1,57 @@
+#include "hisax_if.h"
+#include "hisax_isac.h"
+#include <linux/pci.h>
+
+#define HSCX_BUFMAX 4096
+
+enum {
+ AVM_FRITZ_PCI,
+ AVM_FRITZ_PNP,
+ AVM_FRITZ_PCIV2,
+};
+
+struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+ u_char fill __attribute__((packed));
+ u_char mode __attribute__((packed));
+ u_char xml __attribute__((packed));
+ u_char cmd __attribute__((packed));
+#else
+ u_char cmd __attribute__((packed));
+ u_char xml __attribute__((packed));
+ u_char mode __attribute__((packed));
+ u_char fill __attribute__((packed));
+#endif
+};
+
+struct fritz_bcs {
+ struct hisax_b_if b_if;
+ struct fritz_adapter *adapter;
+ int mode;
+ int channel;
+
+ union {
+ u_int ctrl;
+ struct hdlc_stat_reg sr;
+ } ctrl;
+ u_int stat;
+ int rcvidx;
+ u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
+
+ int tx_cnt; /* B-Channel transmit counter */
+ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+};
+
+struct fritz_adapter {
+ int type;
+ spinlock_t hw_lock;
+ unsigned int io;
+ unsigned int irq;
+ struct isac isac;
+
+ struct fritz_bcs bcs[2];
+
+ u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr);
+ void (*write_ctrl) (struct fritz_bcs *bcs, int which);
+};
+
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
new file mode 100644
index 000000000..9a6a5065b
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -0,0 +1,896 @@
+/*
+ * Driver for ISAC-S and ISAC-SX
+ * ISDN Subscriber Access Controller for Terminals
+ *
+ * Author Kai Germaschewski
+ * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ * 2001 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * based upon Karsten Keil's original isac.c driver
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
+ * SoHaNet Technology GmbH, Berlin
+ * for supporting the development of this driver
+ */
+
+/* TODO:
+ * specifically handle level vs edge triggered?
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include "hisax_isac.h"
+
+// debugging cruft
+
+#define __debug_variable debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 1;
+MODULE_PARM(debug, "i");
+
+static char *ISACVer[] = {
+ "2086/2186 V1.1",
+ "2085 B1",
+ "2085 B2",
+ "2085 V2.3"
+};
+#endif
+
+MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
+
+#define DBG_WARN 0x0001
+#define DBG_IRQ 0x0002
+#define DBG_L1M 0x0004
+#define DBG_PR 0x0008
+#define DBG_RFIFO 0x0100
+#define DBG_RPACKET 0x0200
+#define DBG_XFIFO 0x1000
+#define DBG_XPACKET 0x2000
+
+// we need to distinguish ISAC-S and ISAC-SX
+#define TYPE_ISAC 0x00
+#define TYPE_ISACSX 0x01
+
+// registers etc.
+#define ISAC_MASK 0x20
+#define ISAC_ISTA 0x20
+#define ISAC_ISTA_EXI 0x01
+#define ISAC_ISTA_SIN 0x02
+#define ISAC_ISTA_CISQ 0x04
+#define ISAC_ISTA_XPR 0x10
+#define ISAC_ISTA_RSC 0x20
+#define ISAC_ISTA_RPF 0x40
+#define ISAC_ISTA_RME 0x80
+
+#define ISAC_STAR 0x21
+#define ISAC_CMDR 0x21
+#define ISAC_CMDR_XRES 0x01
+#define ISAC_CMDR_XME 0x02
+#define ISAC_CMDR_XTF 0x08
+#define ISAC_CMDR_RRES 0x40
+#define ISAC_CMDR_RMC 0x80
+
+#define ISAC_EXIR 0x24
+#define ISAC_EXIR_MOS 0x04
+#define ISAC_EXIR_XDU 0x40
+#define ISAC_EXIR_XMR 0x80
+
+#define ISAC_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_CIR0_CIC0 0x02
+#define ISAC_CIR0_CIC1 0x01
+
+#define ISAC_CIR1 0x33
+#define ISAC_CIX1 0x33
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+
+#define ISAC_RSTA 0x27
+#define ISAC_RSTA_RDO 0x40
+#define ISAC_RSTA_CRC 0x20
+#define ISAC_RSTA_RAB 0x10
+
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_RBCH_XAC 0x80
+
+#define ISAC_CMD_TIM 0x0
+#define ISAC_CMD_RES 0x1
+#define ISAC_CMD_SSP 0x2
+#define ISAC_CMD_SCP 0x3
+#define ISAC_CMD_AR8 0x8
+#define ISAC_CMD_AR10 0x9
+#define ISAC_CMD_ARL 0xa
+#define ISAC_CMD_DI 0xf
+
+#define ISACSX_MASK 0x60
+#define ISACSX_ISTA 0x60
+#define ISACSX_ISTA_ICD 0x01
+#define ISACSX_ISTA_CIC 0x10
+
+#define ISACSX_MASKD 0x20
+#define ISACSX_ISTAD 0x20
+#define ISACSX_ISTAD_XDU 0x04
+#define ISACSX_ISTAD_XMR 0x08
+#define ISACSX_ISTAD_XPR 0x10
+#define ISACSX_ISTAD_RFO 0x20
+#define ISACSX_ISTAD_RPF 0x40
+#define ISACSX_ISTAD_RME 0x80
+
+#define ISACSX_CMDRD 0x21
+#define ISACSX_CMDRD_XRES 0x01
+#define ISACSX_CMDRD_XME 0x02
+#define ISACSX_CMDRD_XTF 0x08
+#define ISACSX_CMDRD_RRES 0x40
+#define ISACSX_CMDRD_RMC 0x80
+
+#define ISACSX_MODED 0x22
+
+#define ISACSX_RBCLD 0x26
+
+#define ISACSX_RSTAD 0x28
+#define ISACSX_RSTAD_RAB 0x10
+#define ISACSX_RSTAD_CRC 0x20
+#define ISACSX_RSTAD_RDO 0x40
+#define ISACSX_RSTAD_VFR 0x80
+
+#define ISACSX_CIR0 0x2e
+#define ISACSX_CIR0_CIC0 0x08
+#define ISACSX_CIX0 0x2e
+
+#define ISACSX_TR_CONF0 0x30
+
+#define ISACSX_TR_CONF2 0x32
+
+static struct Fsm l1fsm;
+
+enum {
+ ST_L1_RESET,
+ ST_L1_F3_PDOWN,
+ ST_L1_F3_PUP,
+ ST_L1_F3_PEND_DEACT,
+ ST_L1_F4,
+ ST_L1_F5,
+ ST_L1_F6,
+ ST_L1_F7,
+ ST_L1_F8,
+};
+
+#define L1_STATE_COUNT (ST_L1_F8+1)
+
+static char *strL1State[] =
+{
+ "ST_L1_RESET",
+ "ST_L1_F3_PDOWN",
+ "ST_L1_F3_PUP",
+ "ST_L1_F3_PEND_DEACT",
+ "ST_L1_F4",
+ "ST_L1_F5",
+ "ST_L1_F6",
+ "ST_L1_F7",
+ "ST_L1_F8",
+};
+
+enum {
+ EV_PH_DR, // 0000
+ EV_PH_RES, // 0001
+ EV_PH_TMA, // 0010
+ EV_PH_SLD, // 0011
+ EV_PH_RSY, // 0100
+ EV_PH_DR6, // 0101
+ EV_PH_EI, // 0110
+ EV_PH_PU, // 0111
+ EV_PH_AR, // 1000
+ EV_PH_9, // 1001
+ EV_PH_ARL, // 1010
+ EV_PH_CVR, // 1011
+ EV_PH_AI8, // 1100
+ EV_PH_AI10, // 1101
+ EV_PH_AIL, // 1110
+ EV_PH_DC, // 1111
+ EV_PH_ACTIVATE_REQ,
+ EV_PH_DEACTIVATE_REQ,
+ EV_TIMER3,
+};
+
+#define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+static char *strL1Event[] =
+{
+ "EV_PH_DR", // 0000
+ "EV_PH_RES", // 0001
+ "EV_PH_TMA", // 0010
+ "EV_PH_SLD", // 0011
+ "EV_PH_RSY", // 0100
+ "EV_PH_DR6", // 0101
+ "EV_PH_EI", // 0110
+ "EV_PH_PU", // 0111
+ "EV_PH_AR", // 1000
+ "EV_PH_9", // 1001
+ "EV_PH_ARL", // 1010
+ "EV_PH_CVR", // 1011
+ "EV_PH_AI8", // 1100
+ "EV_PH_AI10", // 1101
+ "EV_PH_AIL", // 1110
+ "EV_PH_DC", // 1111
+ "EV_PH_ACTIVATE_REQ",
+ "EV_PH_DEACTIVATE_REQ",
+ "EV_TIMER3",
+};
+
+static inline void D_L1L2(struct isac *isac, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
+
+ DBG(DBG_PR, "pr %#x", pr);
+ ifc->l1l2(ifc, pr, arg);
+}
+
+static void ph_command(struct isac *isac, unsigned int command)
+{
+ DBG(DBG_L1M, "ph_command %#x", command);
+ switch (isac->type) {
+ case TYPE_ISAC:
+ isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
+ break;
+ case TYPE_ISACSX:
+ isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
+ break;
+ }
+}
+
+// ----------------------------------------------------------------------
+
+static void l1_di(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_RESET);
+ ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_RESET);
+ D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+ ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F3_PDOWN);
+}
+
+static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
+ D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+ ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
+ ph_command(isac, ISAC_CMD_DI);
+}
+
+static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F4);
+}
+
+static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F5);
+}
+
+static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F6);
+}
+
+static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_F6);
+ D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmDelTimer(&isac->timer, 0);
+ FsmChangeState(fi, ST_L1_F7);
+ ph_command(isac, ISAC_CMD_AR8);
+ D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
+}
+
+static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L1_F8);
+}
+
+static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmChangeState(fi, ST_L1_F8);
+ D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+static void l1_ar8(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+ ph_command(isac, ISAC_CMD_AR8);
+}
+
+static void l1_timer3(struct FsmInst *fi, int event, void *arg)
+{
+ struct isac *isac = fi->userdata;
+
+ ph_command(isac, ISAC_CMD_DI);
+ D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+// state machines according to data sheet PSB 2186 / 3186
+
+static struct FsmNode L1FnList[] __initdata =
+{
+ {ST_L1_RESET, EV_PH_RES, l1_di},
+ {ST_L1_RESET, EV_PH_EI, l1_di},
+ {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
+ {ST_L1_RESET, EV_PH_AR, l1_go_f6},
+ {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
+
+ {ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
+ {ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
+ {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
+ {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
+ {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
+ {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
+ {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
+ {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
+
+ {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
+ {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
+ {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
+ {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
+ {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
+ {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
+
+ {ST_L1_F4, EV_PH_RES, l1_di},
+ {ST_L1_F4, EV_PH_EI, l1_di},
+ {ST_L1_F4, EV_PH_RSY, l1_go_f5},
+ {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
+ {ST_L1_F4, EV_TIMER3, l1_timer3},
+ {ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
+
+ {ST_L1_F5, EV_PH_RES, l1_di},
+ {ST_L1_F5, EV_PH_EI, l1_di},
+ {ST_L1_F5, EV_PH_AR, l1_go_f6},
+ {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
+ {ST_L1_F5, EV_TIMER3, l1_timer3},
+ {ST_L1_F5, EV_PH_DR, l1_go_f3pend},
+ {ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
+
+ {ST_L1_F6, EV_PH_RES, l1_di},
+ {ST_L1_F6, EV_PH_EI, l1_di},
+ {ST_L1_F6, EV_PH_RSY, l1_go_f8},
+ {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
+ {ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
+ {ST_L1_F6, EV_TIMER3, l1_timer3},
+ {ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
+
+ {ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
+ {ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
+ {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
+ {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
+ {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
+
+ {ST_L1_F8, EV_PH_RES, l1_di},
+ {ST_L1_F8, EV_PH_EI, l1_di},
+ {ST_L1_F8, EV_PH_AR, l1_go_f6},
+ {ST_L1_F8, EV_PH_DR, l1_go_f3pend},
+ {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
+ {ST_L1_F8, EV_TIMER3, l1_timer3},
+ {ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
+};
+
+static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+ va_list args;
+ char buf[256];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ DBG(DBG_L1M, "%s", buf);
+ va_end(args);
+}
+
+static void isac_version(struct isac *cs)
+{
+ int val;
+
+ val = cs->read_isac(cs, ISAC_RBCH);
+ DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
+}
+
+static void isac_empty_fifo(struct isac *isac, int count)
+{
+ // this also works for isacsx, since
+ // CMDR(D) register works the same
+ u_char *ptr;
+
+ DBG(DBG_IRQ, "count %d", count);
+
+ if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+ DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
+ isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
+ isac->rcvidx = 0;
+ return;
+ }
+ ptr = isac->rcvbuf + isac->rcvidx;
+ isac->rcvidx += count;
+ isac->read_isac_fifo(isac, ptr, count);
+ isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
+ DBG_PACKET(DBG_RFIFO, ptr, count);
+}
+
+static void isac_fill_fifo(struct isac *isac)
+{
+ // this also works for isacsx, since
+ // CMDR(D) register works the same
+
+ int count;
+ unsigned char cmd;
+ u_char *ptr;
+
+ if (!isac->tx_skb)
+ BUG();
+
+ count = isac->tx_skb->len;
+ if (count <= 0)
+ BUG();
+
+ DBG(DBG_IRQ, "count %d", count);
+
+ if (count > 0x20) {
+ count = 0x20;
+ cmd = ISAC_CMDR_XTF;
+ } else {
+ cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
+ }
+
+ ptr = isac->tx_skb->data;
+ skb_pull(isac->tx_skb, count);
+ isac->tx_cnt += count;
+ DBG_PACKET(DBG_XFIFO, ptr, count);
+ isac->write_isac_fifo(isac, ptr, count);
+ isac->write_isac(isac, ISAC_CMDR, cmd);
+}
+
+static void isac_retransmit(struct isac *isac)
+{
+ if (!isac->tx_skb) {
+ DBG(DBG_WARN, "no skb");
+ return;
+ }
+ skb_push(isac->tx_skb, isac->tx_cnt);
+ isac->tx_cnt = 0;
+}
+
+
+static inline void isac_cisq_interrupt(struct isac *isac)
+{
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISAC_CIR0);
+ DBG(DBG_IRQ, "CIR0 %#x", val);
+ if (val & ISAC_CIR0_CIC0) {
+ DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
+ FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
+ }
+ if (val & ISAC_CIR0_CIC1) {
+ val = isac->read_isac(isac, ISAC_CIR1);
+ DBG(DBG_WARN, "ISAC CIR1 %#x", val );
+ }
+}
+
+static inline void isac_rme_interrupt(struct isac *isac)
+{
+ unsigned char val;
+ int count;
+ struct sk_buff *skb;
+
+ val = isac->read_isac(isac, ISAC_RSTA);
+ if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB) )
+ != ISAC_RSTA_CRC) {
+ DBG(DBG_WARN, "RSTA %#x, dropped", val);
+ isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
+ goto out;
+ }
+
+ count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
+ DBG(DBG_IRQ, "RBCL %#x", count);
+ if (count == 0)
+ count = 0x20;
+
+ isac_empty_fifo(isac, count);
+ count = isac->rcvidx;
+ if (count < 1) {
+ DBG(DBG_WARN, "count %d < 1", count);
+ goto out;
+ }
+
+ skb = alloc_skb(count, GFP_ATOMIC);
+ if (!skb) {
+ DBG(DBG_WARN, "no memory, dropping\n");
+ goto out;
+ }
+ memcpy(skb_put(skb, count), isac->rcvbuf, count);
+ DBG_SKB(DBG_RPACKET, skb);
+ D_L1L2(isac, PH_DATA | INDICATION, skb);
+ out:
+ isac->rcvidx = 0;
+}
+
+static inline void isac_xpr_interrupt(struct isac *isac)
+{
+ if (!isac->tx_skb)
+ return;
+
+ if (isac->tx_skb->len > 0) {
+ isac_fill_fifo(isac);
+ return;
+ }
+ dev_kfree_skb_irq(isac->tx_skb);
+ isac->tx_cnt = 0;
+ isac->tx_skb = NULL;
+ D_L1L2(isac, PH_DATA | CONFIRM, NULL);
+}
+
+static inline void isac_exi_interrupt(struct isac *isac)
+{
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISAC_EXIR);
+ DBG(2, "EXIR %#x", val);
+
+ if (val & ISAC_EXIR_XMR) {
+ DBG(DBG_WARN, "ISAC XMR");
+ isac_retransmit(isac);
+ }
+ if (val & ISAC_EXIR_XDU) {
+ DBG(DBG_WARN, "ISAC XDU");
+ isac_retransmit(isac);
+ }
+ if (val & ISAC_EXIR_MOS) { /* MOS */
+ DBG(DBG_WARN, "MOS");
+ val = isac->read_isac(isac, ISAC_MOSR);
+ DBG(2, "ISAC MOSR %#x", val);
+ }
+}
+
+void isac_interrupt(struct isac *isac)
+{
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISAC_ISTA);
+ DBG(DBG_IRQ, "ISTA %#x", val);
+
+ if (val & ISAC_ISTA_EXI) {
+ DBG(DBG_IRQ, "EXI");
+ isac_exi_interrupt(isac);
+ }
+ if (val & ISAC_ISTA_XPR) {
+ DBG(DBG_IRQ, "XPR");
+ isac_xpr_interrupt(isac);
+ }
+ if (val & ISAC_ISTA_RME) {
+ DBG(DBG_IRQ, "RME");
+ isac_rme_interrupt(isac);
+ }
+ if (val & ISAC_ISTA_RPF) {
+ DBG(DBG_IRQ, "RPF");
+ isac_empty_fifo(isac, 0x20);
+ }
+ if (val & ISAC_ISTA_CISQ) {
+ DBG(DBG_IRQ, "CISQ");
+ isac_cisq_interrupt(isac);
+ }
+ if (val & ISAC_ISTA_RSC) {
+ DBG(DBG_WARN, "RSC");
+ }
+ if (val & ISAC_ISTA_SIN) {
+ DBG(DBG_WARN, "SIN");
+ }
+ isac->write_isac(isac, ISAC_MASK, 0xff);
+ isac->write_isac(isac, ISAC_MASK, 0x00);
+}
+
+// ======================================================================
+
+static inline void isacsx_cic_interrupt(struct isac *isac)
+{
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISACSX_CIR0);
+ DBG(DBG_IRQ, "CIR0 %#x", val);
+ if (val & ISACSX_CIR0_CIC0) {
+ DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
+ FsmEvent(&isac->l1m, val >> 4, NULL);
+ }
+}
+
+static inline void isacsx_rme_interrupt(struct isac *isac)
+{
+ int count;
+ struct sk_buff *skb;
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISACSX_RSTAD);
+ if ((val & (ISACSX_RSTAD_VFR |
+ ISACSX_RSTAD_RDO |
+ ISACSX_RSTAD_CRC |
+ ISACSX_RSTAD_RAB))
+ != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
+ DBG(DBG_WARN, "RSTAD %#x, dropped", val);
+ isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
+ goto out;
+ }
+
+ count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
+ DBG(DBG_IRQ, "RBCLD %#x", count);
+ if (count == 0)
+ count = 0x20;
+
+ isac_empty_fifo(isac, count);
+ // strip trailing status byte
+ count = isac->rcvidx - 1;
+ if (count < 1) {
+ DBG(DBG_WARN, "count %d < 1", count);
+ goto out;
+ }
+
+ skb = dev_alloc_skb(count);
+ if (!skb) {
+ DBG(DBG_WARN, "no memory, dropping");
+ goto out;
+ }
+ memcpy(skb_put(skb, count), isac->rcvbuf, count);
+ DBG_SKB(DBG_RPACKET, skb);
+ D_L1L2(isac, PH_DATA | INDICATION, skb);
+ out:
+ isac->rcvidx = 0;
+}
+
+static inline void isacsx_xpr_interrupt(struct isac *isac)
+{
+ if (!isac->tx_skb)
+ return;
+
+ if (isac->tx_skb->len > 0) {
+ isac_fill_fifo(isac);
+ return;
+ }
+ dev_kfree_skb_irq(isac->tx_skb);
+ isac->tx_skb = NULL;
+ isac->tx_cnt = 0;
+ D_L1L2(isac, PH_DATA | CONFIRM, NULL);
+}
+
+static inline void isacsx_icd_interrupt(struct isac *isac)
+{
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISACSX_ISTAD);
+ DBG(DBG_IRQ, "ISTAD %#x", val);
+ if (val & ISACSX_ISTAD_XDU) {
+ DBG(DBG_WARN, "ISTAD XDU");
+ isac_retransmit(isac);
+ }
+ if (val & ISACSX_ISTAD_XMR) {
+ DBG(DBG_WARN, "ISTAD XMR");
+ isac_retransmit(isac);
+ }
+ if (val & ISACSX_ISTAD_XPR) {
+ DBG(DBG_IRQ, "ISTAD XPR");
+ isacsx_xpr_interrupt(isac);
+ }
+ if (val & ISACSX_ISTAD_RFO) {
+ DBG(DBG_WARN, "ISTAD RFO");
+ isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
+ }
+ if (val & ISACSX_ISTAD_RME) {
+ DBG(DBG_IRQ, "ISTAD RME");
+ isacsx_rme_interrupt(isac);
+ }
+ if (val & ISACSX_ISTAD_RPF) {
+ DBG(DBG_IRQ, "ISTAD RPF");
+ isac_empty_fifo(isac, 0x20);
+ }
+}
+
+void isacsx_interrupt(struct isac *isac)
+{
+ unsigned char val;
+
+ val = isac->read_isac(isac, ISACSX_ISTA);
+ DBG(DBG_IRQ, "ISTA %#x", val);
+
+ if (val & ISACSX_ISTA_ICD)
+ isacsx_icd_interrupt(isac);
+ if (val & ISACSX_ISTA_CIC)
+ isacsx_cic_interrupt(isac);
+}
+
+void isac_init(struct isac *isac)
+{
+ isac->tx_skb = NULL;
+ isac->l1m.fsm = &l1fsm;
+ isac->l1m.state = ST_L1_RESET;
+#ifdef CONFIG_HISAX_DEBUG
+ isac->l1m.debug = 1;
+#else
+ isac->l1m.debug = 0;
+#endif
+ isac->l1m.userdata = isac;
+ isac->l1m.printdebug = l1m_debug;
+ FsmInitTimer(&isac->l1m, &isac->timer);
+}
+
+void isac_setup(struct isac *isac)
+{
+ int val, eval;
+
+ isac->type = TYPE_ISAC;
+ isac_version(isac);
+
+ ph_command(isac, ISAC_CMD_RES);
+
+ isac->write_isac(isac, ISAC_MASK, 0xff);
+ isac->mocr = 0xaa;
+ if (test_bit(ISAC_IOM1, &isac->flags)) {
+ /* IOM 1 Mode */
+ isac->write_isac(isac, ISAC_ADF2, 0x0);
+ isac->write_isac(isac, ISAC_SPCR, 0xa);
+ isac->write_isac(isac, ISAC_ADF1, 0x2);
+ isac->write_isac(isac, ISAC_STCR, 0x70);
+ isac->write_isac(isac, ISAC_MODE, 0xc9);
+ } else {
+ /* IOM 2 Mode */
+ if (!isac->adf2)
+ isac->adf2 = 0x80;
+ isac->write_isac(isac, ISAC_ADF2, isac->adf2);
+ isac->write_isac(isac, ISAC_SQXR, 0x2f);
+ isac->write_isac(isac, ISAC_SPCR, 0x00);
+ isac->write_isac(isac, ISAC_STCR, 0x70);
+ isac->write_isac(isac, ISAC_MODE, 0xc9);
+ isac->write_isac(isac, ISAC_TIMR, 0x00);
+ isac->write_isac(isac, ISAC_ADF1, 0x00);
+ }
+ val = isac->read_isac(isac, ISAC_STAR);
+ DBG(2, "ISAC STAR %x", val);
+ val = isac->read_isac(isac, ISAC_MODE);
+ DBG(2, "ISAC MODE %x", val);
+ val = isac->read_isac(isac, ISAC_ADF2);
+ DBG(2, "ISAC ADF2 %x", val);
+ val = isac->read_isac(isac, ISAC_ISTA);
+ DBG(2, "ISAC ISTA %x", val);
+ if (val & 0x01) {
+ eval = isac->read_isac(isac, ISAC_EXIR);
+ DBG(2, "ISAC EXIR %x", eval);
+ }
+ val = isac->read_isac(isac, ISAC_CIR0);
+ DBG(2, "ISAC CIR0 %x", val);
+ FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
+
+ isac->write_isac(isac, ISAC_MASK, 0x0);
+ // RESET Receiver and Transmitter
+ isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
+}
+
+void isacsx_setup(struct isac *isac)
+{
+ isac->type = TYPE_ISACSX;
+ // clear LDD
+ isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
+ // enable transmitter
+ isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
+ // transparent mode 0, RAC, stop/go
+ isac->write_isac(isac, ISACSX_MODED, 0xc9);
+ // all HDLC IRQ unmasked
+ isac->write_isac(isac, ISACSX_MASKD, 0x03);
+ // unmask ICD, CID IRQs
+ isac->write_isac(isac, ISACSX_MASK,
+ ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
+}
+
+void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
+{
+ struct isac *isac = hisax_d_if->priv;
+ struct sk_buff *skb = arg;
+
+ DBG(DBG_PR, "pr %#x", pr);
+
+ switch (pr) {
+ case PH_ACTIVATE | REQUEST:
+ FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
+ break;
+ case PH_DEACTIVATE | REQUEST:
+ FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
+ break;
+ case PH_DATA | REQUEST:
+ DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
+ DBG_SKB(DBG_XPACKET, skb);
+ if (isac->l1m.state != ST_L1_F7) {
+ DBG(1, "L1 wrong state %d\n", isac->l1m.state);
+ dev_kfree_skb(skb);
+ break;
+ }
+ if (isac->tx_skb)
+ BUG();
+
+ isac->tx_skb = skb;
+ isac_fill_fifo(isac);
+ break;
+ }
+}
+
+static int __init hisax_isac_init(void)
+{
+ printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
+
+ l1fsm.state_count = L1_STATE_COUNT;
+ l1fsm.event_count = L1_EVENT_COUNT;
+ l1fsm.strState = strL1State;
+ l1fsm.strEvent = strL1Event;
+ return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
+}
+
+static void __exit hisax_isac_exit(void)
+{
+ FsmFree(&l1fsm);
+}
+
+EXPORT_SYMBOL(isac_init);
+EXPORT_SYMBOL(isac_d_l2l1);
+
+EXPORT_SYMBOL(isacsx_setup);
+EXPORT_SYMBOL(isacsx_interrupt);
+
+EXPORT_SYMBOL(isac_setup);
+EXPORT_SYMBOL(isac_interrupt);
+
+module_init(hisax_isac_init);
+module_exit(hisax_isac_exit);
diff --git a/drivers/isdn/hisax/hisax_isac.h b/drivers/isdn/hisax/hisax_isac.h
new file mode 100644
index 000000000..6b8d2dfa0
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_isac.h
@@ -0,0 +1,45 @@
+#ifndef __HISAX_ISAC_H__
+#define __HISAX_ISAC_H__
+
+#include <linux/kernel.h>
+#include "fsm.h"
+#include "hisax_if.h"
+
+#define TIMER3_VALUE 7000
+#define MAX_DFRAME_LEN_L1 300
+
+#define ISAC_IOM1 0
+
+struct isac {
+ void *priv;
+
+ u_long flags;
+ struct hisax_d_if hisax_d_if;
+ struct FsmInst l1m;
+ struct FsmTimer timer;
+ u_char mocr;
+ u_char adf2;
+ int type;
+
+ u_char rcvbuf[MAX_DFRAME_LEN_L1];
+ int rcvidx;
+
+ struct sk_buff *tx_skb;
+ int tx_cnt;
+
+ u_char (*read_isac) (struct isac *, u_char);
+ void (*write_isac) (struct isac *, u_char, u_char);
+ void (*read_isac_fifo) (struct isac *, u_char *, int);
+ void (*write_isac_fifo)(struct isac *, u_char *, int);
+};
+
+void isac_init(struct isac *isac);
+void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
+
+void isac_setup(struct isac *isac);
+void isac_interrupt(struct isac *isac);
+
+void isacsx_setup(struct isac *isac);
+void isacsx_interrupt(struct isac *isac);
+
+#endif
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index ddeccc817..c33d5eccf 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -2273,6 +2273,22 @@ static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_7,
PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1032,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1033,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1034,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1038,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1227,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x1228,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x5200,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, 0x5201,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c
index 521ec9423..e54f47b35 100644
--- a/drivers/sound/ad1848.c
+++ b/drivers/sound/ad1848.c
@@ -134,7 +134,7 @@ static int timer_installed = -1;
static int loaded;
-static int ad_format_mask[10 /*devc->model */ ] =
+static int ad_format_mask[13 /*devc->model */ ] =
{
0,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
@@ -145,7 +145,10 @@ static int ad_format_mask[10 /*devc->model */ ] =
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
AFMT_U8 | AFMT_S16_LE /* CS4235 */,
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW /* Ensoniq Soundscape*/,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM
};
static ad1848_info adev_info[MAX_AUDIO_DEV];
diff --git a/drivers/sound/cs46xx.c b/drivers/sound/cs46xx.c
index e79662a95..067ea4352 100644
--- a/drivers/sound/cs46xx.c
+++ b/drivers/sound/cs46xx.c
@@ -3003,7 +3003,7 @@ static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return -ENODEV;
case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
+ return 0;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
diff --git a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c
index c557925d0..e412b2919 100644
--- a/drivers/sound/ymfpci.c
+++ b/drivers/sound/ymfpci.c
@@ -39,6 +39,9 @@
* native synthesizer through a playback slot.
* - Use new 2.3.x cache coherent PCI DMA routines instead of virt_to_bus.
* - Make the thing big endian compatible. ALSA has it done.
+ * - 2001/10/25 Since Civ:CTP forced redzone outside of pre-set fragments,
+ * all ioctls that report free space lie a little. Adjust their returns.
+ * - 2001/11/29 ac97_save_state
*/
#include <linux/config.h>
@@ -173,19 +176,19 @@ static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val)
static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
{
- ymfpci_t *codec = dev->private_data;
+ ymfpci_t *unit = dev->private_data;
+ int i;
- if (ymfpci_codec_ready(codec, 0, 0))
+ if (ymfpci_codec_ready(unit, 0, 0))
return ~0;
- ymfpci_writew(codec, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
- if (ymfpci_codec_ready(codec, 0, 0))
+ ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
+ if (ymfpci_codec_ready(unit, 0, 0))
return ~0;
- if (codec->pci->device == PCI_DEVICE_ID_YAMAHA_744 && codec->rev < 2) {
- int i;
+ if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
for (i = 0; i < 600; i++)
- ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+ ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
}
- return ymfpci_readw(codec, YDSXGR_PRISTATUSDATA);
+ return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
}
/*
@@ -1512,9 +1515,11 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case OSS_GETVERSION:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
return put_user(SOUND_VERSION, (int *)arg);
case SNDCTL_DSP_RESET:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
@@ -1536,6 +1541,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_SYNC:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
dmabuf = &state->wpcm.dmabuf;
if (file->f_flags & O_NONBLOCK) {
@@ -1554,6 +1560,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_SPEED: /* set smaple rate */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
if (val >= 8000 && val <= 48000) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
@@ -1585,6 +1592,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
dmabuf = &state->wpcm.dmabuf;
@@ -1606,24 +1614,31 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_GETBLKSIZE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf(state, 0)))
return val;
- return put_user(state->wpcm.dmabuf.fragsize, (int *)arg);
+ val = state->wpcm.dmabuf.fragsize;
+ YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
+ return put_user(val, (int *)arg);
}
if (file->f_mode & FMODE_READ) {
if ((val = prog_dmabuf(state, 1)))
return val;
- return put_user(state->rpcm.dmabuf.fragsize, (int *)arg);
+ val = state->rpcm.dmabuf.fragsize;
+ YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
+ return put_user(val, (int *)arg);
}
return -EINVAL;
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Select sample format */
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
if (val == AFMT_S16_LE || val == AFMT_U8) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
@@ -1649,6 +1664,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_CHANNELS:
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
if (val != 0) {
if (file->f_mode & FMODE_WRITE) {
ymf_wait_dac(state);
@@ -1676,6 +1692,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return put_user(state->format.voices, (int *)arg);
case SNDCTL_DSP_POST:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
/*
* Quoting OSS PG:
* The ioctl SNDCTL_DSP_POST is a lightweight version of
@@ -1697,6 +1714,10 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, (int *)arg))
return -EFAULT;
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
+ cmd,
+ (val >> 16) & 0xFFFF, val & 0xFFFF,
+ (val >> 16) & 0xFFFF, val & 0xFFFF);
dmabuf = &state->wpcm.dmabuf;
dmabuf->ossfragshift = val & 0xffff;
dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
@@ -1707,6 +1728,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return 0;
case SNDCTL_DSP_GETOSPACE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
@@ -1721,6 +1743,7 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
@@ -1735,15 +1758,18 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_GETCAPS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
(int *)arg); */
return put_user(0, (int *)arg);
case SNDCTL_DSP_GETIPTR:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
dmabuf = &state->rpcm.dmabuf;
@@ -1755,9 +1781,12 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
+ cinfo.ptr, cinfo.bytes);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETOPTR:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
dmabuf = &state->wpcm.dmabuf;
@@ -1769,18 +1798,24 @@ static int ymf_ioctl(struct inode *inode, struct file *file,
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize-1;
spin_unlock_irqrestore(&state->unit->reg_lock, flags);
+ YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
+ cinfo.ptr, cinfo.bytes);
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */
+ YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
return -EINVAL;
case SOUND_PCM_READ_RATE:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
return put_user(state->format.rate, (int *)arg);
case SOUND_PCM_READ_CHANNELS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
return put_user(state->format.voices, (int *)arg);
case SOUND_PCM_READ_BITS:
+ YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
return put_user(AFMT_S16_LE, (int *)arg);
case SNDCTL_DSP_MAPINBUF:
@@ -1866,13 +1901,12 @@ static int ymf_open(struct inode *inode, struct file *file)
}
#if 0 /* test if interrupts work */
- ymfpci_writew(codec, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
- ymfpci_writeb(codec, YDSXGR_TIMERCTRL,
+ ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
+ ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
(YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
#endif
up(&unit->open_sem);
- MOD_INC_USE_COUNT;
return 0;
out_nodma:
@@ -1896,13 +1930,13 @@ out_nodma:
static int ymf_release(struct inode *inode, struct file *file)
{
struct ymf_state *state = (struct ymf_state *)file->private_data;
- ymfpci_t *codec = state->unit;
+ ymfpci_t *unit = state->unit;
#if 0 /* test if interrupts work */
- ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
+ ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
#endif
- down(&codec->open_sem);
+ down(&unit->open_sem);
/*
* XXX Solve the case of O_NONBLOCK close - don't deallocate here.
@@ -1919,9 +1953,8 @@ static int ymf_release(struct inode *inode, struct file *file)
file->private_data = NULL; /* Can you tell I programmed Solaris */
kfree(state);
- up(&codec->open_sem);
+ up(&unit->open_sem);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -1930,10 +1963,10 @@ static int ymf_release(struct inode *inode, struct file *file)
*/
static int ymf_open_mixdev(struct inode *inode, struct file *file)
{
- int i;
int minor = MINOR(inode->i_rdev);
struct list_head *list;
ymfpci_t *unit;
+ int i;
list_for_each(list, &ymf_devs) {
unit = list_entry(list, ymfpci_t, ymf_devs);
@@ -1949,7 +1982,6 @@ static int ymf_open_mixdev(struct inode *inode, struct file *file)
match:
file->private_data = unit->ac97_codec[i];
- MOD_INC_USE_COUNT;
return 0;
}
@@ -1963,11 +1995,11 @@ static int ymf_ioctl_mixdev(struct inode *inode, struct file *file,
static int ymf_release_mixdev(struct inode *inode, struct file *file)
{
- MOD_DEC_USE_COUNT;
return 0;
}
static /*const*/ struct file_operations ymf_fops = {
+ owner: THIS_MODULE,
llseek: no_llseek,
read: ymf_read,
write: ymf_write,
@@ -1979,6 +2011,7 @@ static /*const*/ struct file_operations ymf_fops = {
};
static /*const*/ struct file_operations ymf_mixer_fops = {
+ owner: THIS_MODULE,
llseek: no_llseek,
ioctl: ymf_ioctl_mixdev,
open: ymf_open_mixdev,
@@ -1990,23 +2023,26 @@ static /*const*/ struct file_operations ymf_mixer_fops = {
static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
{
- int i;
struct ymf_unit *unit = pci_get_drvdata(pcidev);
unsigned long flags;
struct ymf_dmabuf *dmabuf;
struct list_head *p;
struct ymf_state *state;
struct ac97_codec *codec;
+ int i;
spin_lock_irqsave(&unit->reg_lock, flags);
unit->suspended = 1;
+ /*
+ * XXX Talk to Kai to remove ac97_save_state before it's too late!
+ * Other drivers call ac97_reset, which does not have
+ * a save counterpart. Current ac97_save_state is empty.
+ */
for (i = 0; i < NR_AC97; i++) {
- codec = unit->ac97_codec[i];
- if (!codec)
- continue;
- ac97_save_state(codec);
+ if ((codec = unit->ac97_codec[i]) != NULL)
+ ac97_save_state(codec);
}
list_for_each(p, &unit->states) {
@@ -2033,23 +2069,16 @@ static int ymf_suspend(struct pci_dev *pcidev, u32 unused)
static int ymf_resume(struct pci_dev *pcidev)
{
- int i;
struct ymf_unit *unit = pci_get_drvdata(pcidev);
unsigned long flags;
struct list_head *p;
struct ymf_state *state;
struct ac97_codec *codec;
+ int i;
ymfpci_aclink_reset(unit->pci);
ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */
- for (i = 0; i < NR_AC97; i++) {
- codec = unit->ac97_codec[i];
- if (!codec)
- continue;
- ac97_restore_state(codec);
- }
-
#ifdef CONFIG_SOUND_YMFPCI_LEGACY
/* XXX At this time the legacy registers are probably deprogrammed. */
#endif
@@ -2065,6 +2094,11 @@ static int ymf_resume(struct pci_dev *pcidev)
unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
}
+ for (i = 0; i < NR_AC97; i++) {
+ if ((codec = unit->ac97_codec[i]) != NULL)
+ ac97_restore_state(codec);
+ }
+
unit->suspended = 0;
list_for_each(p, &unit->states) {
state = list_entry(p, struct ymf_state, chain);
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 0d70c1626..3c1cbb475 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
# Object files in subdirectories
+mod-subdirs := serial
subdir-$(CONFIG_USB_SERIAL) += serial
subdir-$(CONFIG_USB_STORAGE) += storage
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index e3071c874..c732e45be 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -139,9 +139,12 @@ static const struct class_info clas_info[] =
{USB_CLASS_PHYSICAL, "PID"},
{USB_CLASS_PRINTER, "print"},
{USB_CLASS_MASS_STORAGE, "stor."},
- {USB_CLASS_DATA, "data"},
+ {USB_CLASS_CDC_DATA, "data"},
{USB_CLASS_APP_SPEC, "app."},
{USB_CLASS_VENDOR_SPEC, "vend."},
+ {USB_CLASS_STILL_IMAGE, "still"},
+ {USB_CLASS_CSCID, "scard"},
+ {USB_CLASS_CONTENT_SEC, "c-sec"},
{-1, "unk."} /* leave as last */
};
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 8c2d37c7e..5147acebc 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -714,9 +714,8 @@ static void visor_shutdown (struct usb_serial *serial)
/* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i) {
- while (serial->port[i].open_count > 0) {
- visor_close (&serial->port[i], NULL);
- }
+ serial->port[i].active = 0;
+ serial->port[i].open_count = 0;
}
}
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 7db95c120..207fa355e 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -88,6 +88,9 @@
#include <linux/adb.h>
#include <linux/pmu.h>
#endif
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif
#ifdef CONFIG_NVRAM
#include <linux/nvram.h>
#endif
@@ -251,11 +254,11 @@ static int default_pll __initdata = 0;
static int default_mclk __initdata = 0;
#ifndef MODULE
-static const char *mode_option __initdata = NULL;
+static char *mode_option __initdata = NULL;
#endif
#ifdef CONFIG_PPC
-#ifdef CONFIG_NVRAM_NOT_DEFINED
+#ifndef CONFIG_NVRAM
static int default_vmode __initdata = VMODE_NVRAM;
static int default_cmode __initdata = CMODE_NVRAM;
#else
@@ -271,31 +274,35 @@ static unsigned long phys_size[FB_MAX] __initdata = { 0, };
static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
#endif
-static const char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
-static const char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
-static const char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
-static const char m64n_et[] __initdata = "mach64ET (ATI264ET)";
-static const char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
-static const char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
-static const char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
-static const char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
-static const char m64n_gt[] __initdata = "3D RAGE (GT)";
-static const char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
-static const char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
-static const char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
-static const char m64n_lt[] __initdata = "3D RAGE LT";
-static const char m64n_ltg[] __initdata = "3D RAGE LT-G";
-static const char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
-static const char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
-static const char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
-static const char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
-static const char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
-static const char m64n_xl[] __initdata = "3D RAGE (XL)";
-static const char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
-static const char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
-static const char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
-static const char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
+#ifdef CONFIG_FB_ATY_GX
+static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
+static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
+#endif /* CONFIG_FB_ATY_GX */
+#ifdef CONFIG_FB_ATY_CT
+static char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
+static char m64n_et[] __initdata = "mach64ET (ATI264ET)";
+static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
+static char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
+static char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
+static char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
+static char m64n_gt[] __initdata = "3D RAGE (GT)";
+static char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
+static char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
+static char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
+static char m64n_lt[] __initdata = "3D RAGE LT";
+static char m64n_ltg[] __initdata = "3D RAGE LT-G";
+static char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
+static char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
+static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
+static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
+static char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
+static char m64n_xl[] __initdata = "3D RAGE (XL)";
+static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
+static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
+static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
+static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
+#endif /* CONFIG_FB_ATY_CT */
static const struct {
u16 pci_id, chip_type;
@@ -357,24 +364,32 @@ static const struct {
#endif /* CONFIG_FB_ATY_CT */
};
-static const char ram_dram[] __initdata = "DRAM";
-static const char ram_vram[] __initdata = "VRAM";
-static const char ram_edo[] __initdata = "EDO";
-static const char ram_sdram[] __initdata = "SDRAM";
-static const char ram_sgram[] __initdata = "SGRAM";
-static const char ram_wram[] __initdata = "WRAM";
-static const char ram_off[] __initdata = "OFF";
-static const char ram_resv[] __initdata = "RESV";
+#if defined(CONFIG_FB_ATY_GX) || defined(CONFIG_FB_ATY_CT)
+static char ram_dram[] __initdata = "DRAM";
+#endif /* CONFIG_FB_ATY_GX || CONFIG_FB_ATY_CT */
#ifdef CONFIG_FB_ATY_GX
-static const char *aty_gx_ram[8] __initdata = {
+static char ram_vram[] __initdata = "VRAM";
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+static char ram_edo[] __initdata = "EDO";
+static char ram_sdram[] __initdata = "SDRAM";
+static char ram_sgram[] __initdata = "SGRAM";
+static char ram_wram[] __initdata = "WRAM";
+static char ram_off[] __initdata = "OFF";
+static char ram_resv[] __initdata = "RESV";
+#endif /* CONFIG_FB_ATY_CT */
+
+#ifdef CONFIG_FB_ATY_GX
+static char *aty_gx_ram[8] __initdata = {
ram_dram, ram_vram, ram_vram, ram_dram,
ram_dram, ram_vram, ram_vram, ram_resv
};
#endif /* CONFIG_FB_ATY_GX */
#ifdef CONFIG_FB_ATY_CT
-static const char *aty_ct_ram[8] __initdata = {
+static char *aty_ct_ram[8] __initdata = {
ram_off, ram_dram, ram_edo, ram_edo,
ram_sdram, ram_sgram, ram_wram, ram_resv
};
@@ -819,6 +834,13 @@ static void atyfb_set_par(const struct atyfb_par *par,
display_info.disp_reg_address = info->ati_regbase_phys;
}
#endif /* CONFIG_FB_COMPAT_XPMAC */
+#ifdef CONFIG_BOOTX_TEXT
+ btext_update_display(info->frame_buffer_phys,
+ (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8,
+ ((par->crtc.v_tot_disp>>16) & 0x7ff)+1,
+ par->crtc.bpp,
+ par->crtc.vxres*par->crtc.bpp/8);
+#endif /* CONFIG_BOOTX_TEXT */
}
static int atyfb_decode_var(const struct fb_var_screeninfo *var,
@@ -1638,6 +1660,8 @@ static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
}
break;
case PBOOK_SLEEP_NOW:
+ if (currcon >= 0)
+ fb_display[currcon].dispsw = &fbcon_dummy;
if (info->blitter_may_be_busy)
wait_for_idle(info);
/* Stop accel engine (stop bus mastering) */
@@ -1667,7 +1691,11 @@ static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
info->save_framebuffer = 0;
}
/* Restore display */
- atyfb_set_par(&info->current_par, info);
+ if (currcon >= 0) {
+ atyfb_set_dispsw(&fb_display[currcon],
+ info, info->current_par.crtc.bpp,
+ info->current_par.accel_flags & FB_ACCELF_TEXT);
+ }
atyfbcon_blank(0, (struct fb_info *)info);
break;
}
@@ -2020,13 +2048,6 @@ found:
if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
var = default_var;
} else {
-#ifdef CONFIG_NVRAM
- if (default_vmode == VMODE_NVRAM) {
- default_vmode = nvram_read_byte(NV_VMODE);
- if (default_vmode <= 0 || default_vmode > VMODE_MAX)
- default_vmode = VMODE_CHOOSE;
- }
-#endif
if (default_vmode == VMODE_CHOOSE) {
if (M64_HAS(G3_PB_1024x768))
/* G3 PowerBook with 1024x768 LCD */
@@ -2139,11 +2160,16 @@ int __init atyfb_init(void)
return -ENXIO;
#else
u16 tmp;
+ int aux_app;
+ unsigned long raddr;
#endif
while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
struct resource *rp;
+#ifndef __sparc__
+ struct resource *rrp;
+#endif
for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--)
if (pdev->device == aty_chips[i].pci_id)
@@ -2375,9 +2401,19 @@ int __init atyfb_init(void)
}
#else /* __sparc__ */
- info->ati_regbase_phys = 0x7ff000 + addr;
- info->ati_regbase = (unsigned long)
- ioremap(info->ati_regbase_phys, 0x1000);
+ aux_app = 0;
+ raddr = addr + 0x7ff000UL;
+ rrp = &pdev->resource[2];
+ if ((rrp->flags & IORESOURCE_MEM)
+ && request_mem_region(rrp->start, rrp->end - rrp->start + 1,
+ "atyfb")) {
+ aux_app = 1;
+ raddr = rrp->start;
+ printk(KERN_INFO "atyfb: using auxiliary register aperture\n");
+ }
+
+ info->ati_regbase_phys = raddr;
+ info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000);
if(!info->ati_regbase) {
kfree(info);
@@ -2385,8 +2421,8 @@ int __init atyfb_init(void)
return -ENOMEM;
}
- info->ati_regbase_phys += 0xc00;
- info->ati_regbase += 0xc00;
+ info->ati_regbase_phys += aux_app? 0x400: 0xc00;
+ info->ati_regbase += aux_app? 0x400: 0xc00;
/*
* Enable memory-space accesses using config-space
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index c0a00a113..bcdbfb7f4 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -41,7 +41,7 @@ const char *global_mode_option = NULL;
#define DEFAULT_MODEDB_INDEX 0
-static const struct fb_videomode modedb[] __initdata = {
+static struct fb_videomode modedb[] __initdata = {
{
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 65d1cb0e9..2d8386310 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -29,7 +29,6 @@
void coda_cache_enter(struct inode *inode, int mask)
{
struct coda_inode_info *cii = ITOC(inode);
- ENTRY;
if ( !coda_cred_ok(&cii->c_cached_cred) ) {
coda_load_creds(&cii->c_cached_cred);
@@ -42,7 +41,6 @@ void coda_cache_enter(struct inode *inode, int mask)
void coda_cache_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
- ENTRY;
cii->c_cached_perm = 0;
}
@@ -53,7 +51,6 @@ void coda_cache_clear_all(struct super_block *sb, struct coda_cred *cred)
struct coda_inode_info *cii;
struct list_head *tmp;
- ENTRY;
sbi = coda_sbp(sb);
if (!sbi) BUG();
@@ -119,7 +116,6 @@ void coda_flag_inode_children(struct inode *inode, int flag)
{
struct dentry *alias_de;
- ENTRY;
if ( !inode || !S_ISDIR(inode->i_mode))
return;
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index ff426ff29..a3ddd60b1 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -102,8 +102,6 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
struct coda_vattr attr;
int error;
- ENTRY;
-
/* We get inode numbers from Venus -- see venus source */
error = venus_getattr(sb, fid, &attr);
if ( error ) {
@@ -111,21 +109,18 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
"coda_cnode_make: coda_getvattr returned %d for %s.\n",
error, coda_f2s(fid));
*inode = NULL;
- EXIT;
return error;
}
*inode = coda_iget(sb, fid, &attr);
if ( IS_ERR(*inode) ) {
printk("coda_cnode_make: coda_iget failed\n");
- EXIT;
return PTR_ERR(*inode);
}
CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n",
(*inode)->i_ino, atomic_read(&(*inode)->i_count),
coda_f2s(&ITOC(*inode)->c_fid));
- EXIT;
return 0;
}
@@ -154,7 +149,6 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
ino_t nr;
struct inode *inode;
struct coda_inode_info *cii;
- ENTRY;
if ( !sb ) {
printk("coda_fid_to_inode: no sb!\n");
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index d5b60d226..782f017ff 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -103,8 +103,6 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
const char *name = entry->d_name.name;
size_t length = entry->d_name.len;
- ENTRY;
-
if ( length > CODA_MAXNAMLEN ) {
printk("name too long: lookup, %s (%*s)\n",
coda_i2s(dir), (int)length, name);
@@ -154,7 +152,6 @@ exit:
d_drop(entry);
coda_flag_inode(res_inode, C_VATTR);
}
- EXIT;
return NULL;
}
@@ -163,7 +160,6 @@ int coda_permission(struct inode *inode, int mask)
{
int error;
- ENTRY;
coda_vfs_stat.permission++;
if ( mask == 0 )
@@ -217,7 +213,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
struct ViceFid newfid;
struct coda_vattr attrs;
- ENTRY;
coda_vfs_stat.create++;
CDEBUG(D_INODE, "name: %s, length %d, mode %o\n", name, length, mode);
@@ -300,7 +295,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
int error;
struct ViceFid newfid;
- ENTRY;
coda_vfs_stat.mkdir++;
if (coda_isroot(dir) && coda_iscontrol(name, len))
@@ -344,7 +338,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int len = de->d_name.len;
int error;
- ENTRY;
coda_vfs_stat.link++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
@@ -368,7 +361,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
out:
CDEBUG(D_INODE, "link result %d\n",error);
- EXIT;
return(error);
}
@@ -381,7 +373,6 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
int symlen;
int error=0;
- ENTRY;
coda_vfs_stat.symlink++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
@@ -406,7 +397,6 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
coda_dir_changed(dir_inode, 0);
CDEBUG(D_INODE, "in symlink result %d\n",error);
- EXIT;
return error;
}
@@ -417,7 +407,6 @@ int coda_unlink(struct inode *dir, struct dentry *de)
const char *name = de->d_name.name;
int len = de->d_name.len;
- ENTRY;
coda_vfs_stat.unlink++;
CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name ,
@@ -441,7 +430,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
int error;
- ENTRY;
coda_vfs_stat.rmdir++;
if (!d_unhashed(de))
@@ -471,7 +459,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
int link_adjust = 0;
int error;
- ENTRY;
coda_vfs_stat.rename++;
CDEBUG(D_INODE, "old: %s, (%d length), new: %s"
@@ -499,7 +486,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
CDEBUG(D_INODE, "result %d\n", error);
- EXIT;
return error;
}
@@ -513,7 +499,6 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
struct file *cfile, fakefile;
struct coda_inode_info *cii = ITOC(inode);
- ENTRY;
coda_vfs_stat.readdir++;
cfile = cii->c_container;
@@ -534,7 +519,6 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
result = vfs_readdir(file, filldir, dirent);
}
- EXIT;
return result;
}
@@ -549,6 +533,7 @@ static void coda_prepare_fakefile(struct file *coda_file,
fake_file->f_pos = coda_file->f_pos;
fake_file->f_version = coda_file->f_version;
fake_file->f_op = cont_dentry->d_inode->i_fop;
+ fake_file->f_flags = coda_file->f_flags;
return ;
}
@@ -577,8 +562,6 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
int string_offset = (int) (&((struct venus_dirent *)(0))->d_name);
int i;
- ENTRY;
-
CODA_ALLOC(buff, char *, DIR_BUFSIZE);
if ( !buff ) {
printk("coda_venus_readdir: out of memory.\n");
@@ -664,7 +647,6 @@ static int coda_dentry_revalidate(struct dentry *de, int flags)
{
struct inode *inode = de->d_inode;
struct coda_inode_info *cii;
- ENTRY;
if (!inode)
return 1;
@@ -740,7 +722,6 @@ int coda_revalidate_inode(struct dentry *dentry)
struct inode *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
- ENTRY;
CDEBUG(D_INODE, "revalidating: %*s/%*s\n",
dentry->d_name.len, dentry->d_name.name,
dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
diff --git a/fs/coda/file.c b/fs/coda/file.c
index fa1d150e3..6a655a243 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -102,7 +102,6 @@ int coda_open(struct inode *i, struct file *f)
struct coda_inode_info *cii;
lock_kernel();
- ENTRY;
coda_vfs_stat.open++;
CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n",
@@ -140,7 +139,6 @@ int coda_open(struct inode *i, struct file *f)
fh->f_dentry->d_inode->i_ino,
atomic_read(&fh->f_dentry->d_inode->i_count),
fh->f_dentry->d_inode->i_op);
- EXIT;
unlock_kernel();
return 0;
}
@@ -155,7 +153,6 @@ int coda_flush(struct file *file)
struct inode *cinode, *inode;
int err = 0, fcnt;
- ENTRY;
coda_vfs_stat.flush++;
/* No need to make an upcall when we have not made any modifications
@@ -200,7 +197,6 @@ int coda_release(struct inode *i, struct file *f)
int err = 0;
lock_kernel();
- ENTRY;
coda_vfs_stat.release++;
if (!use_coda_close) {
@@ -244,7 +240,6 @@ int coda_fsync(struct file *file, struct dentry *dentry, int datasync)
struct inode *cinode, *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
int err = 0;
- ENTRY;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index fad286d0e..c7d890a37 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -99,7 +99,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
ViceFid fid;
int error;
int idx;
- ENTRY;
idx = get_device_index((struct coda_mount_data *) data);
@@ -112,19 +111,16 @@ static struct super_block * coda_read_super(struct super_block *sb,
vc = &coda_comms[idx];
if (!vc->vc_inuse) {
printk("coda_read_super: No pseudo device\n");
- EXIT;
return NULL;
}
if ( vc->vc_sb ) {
printk("coda_read_super: Device already mounted\n");
- EXIT;
return NULL;
}
sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
if(!sbi) {
- EXIT;
return NULL;
}
@@ -159,11 +155,9 @@ static struct super_block * coda_read_super(struct super_block *sb,
printk("coda_read_super: rootinode is %ld dev %d\n",
root->i_ino, root->i_dev);
sb->s_root = d_alloc_root(root);
- EXIT;
return sb;
error:
- EXIT;
if (sbi) {
kfree(sbi);
if(vc)
@@ -179,16 +173,12 @@ static void coda_put_super(struct super_block *sb)
{
struct coda_sb_info *sbi;
- ENTRY;
-
sbi = coda_sbp(sb);
sbi->sbi_vcomm->vc_sb = NULL;
list_del_init(&sbi->sbi_cihead);
printk("Coda: Bye bye.\n");
kfree(sbi);
-
- EXIT;
}
/* all filling in of inodes postponed until lookup */
@@ -196,7 +186,6 @@ static void coda_read_inode(struct inode *inode)
{
struct coda_sb_info *sbi = coda_sbp(inode->i_sb);
struct coda_inode_info *cii;
- ENTRY;
if (!sbi) BUG();
@@ -229,7 +218,6 @@ static void coda_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
- ENTRY;
CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n",
inode->i_ino, atomic_read(&inode->i_count));
CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
@@ -244,8 +232,6 @@ static void coda_clear_inode(struct inode *inode)
cii_free(inode->u.generic_ip);
inode->u.generic_ip = NULL;
#endif
-
- EXIT;
}
int coda_notify_change(struct dentry *de, struct iattr *iattr)
@@ -254,7 +240,6 @@ int coda_notify_change(struct dentry *de, struct iattr *iattr)
struct coda_vattr vattr;
int error;
- ENTRY;
memset(&vattr, 0, sizeof(vattr));
coda_iattr_to_vattr(iattr, &vattr);
@@ -270,7 +255,6 @@ int coda_notify_change(struct dentry *de, struct iattr *iattr)
}
CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error);
- EXIT;
return error;
}
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 6deeb927c..e011c8953 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -45,8 +45,6 @@ struct file_operations coda_ioctl_operations = {
/* the coda pioctl inode ops */
static int coda_ioctl_permission(struct inode *inode, int mask)
{
- ENTRY;
-
return 0;
}
@@ -59,7 +57,6 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
struct inode *target_inode = NULL;
struct coda_inode_info *cnp;
- ENTRY;
/* get the Pioctl data arguments from user space */
if (copy_from_user(&data, (int *)user_data, sizeof(data))) {
return -EINVAL;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 2fe942f7c..023ce45b5 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -292,7 +292,6 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
{
struct venus_comm *vcp;
int idx;
- ENTRY;
lock_kernel();
idx = MINOR(inode->i_rdev);
@@ -319,7 +318,6 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
CDEBUG(D_PSDEV, "device %i - inuse: %d\n", idx, vcp->vc_inuse);
- EXIT;
unlock_kernel();
return 0;
}
@@ -330,7 +328,6 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
struct venus_comm *vcp = (struct venus_comm *) file->private_data;
struct upc_req *req;
struct list_head *lh, *next;
- ENTRY;
lock_kernel();
if ( !vcp->vc_inuse ) {
@@ -371,7 +368,6 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
}
CDEBUG(D_PSDEV, "Done.\n");
- EXIT;
unlock_kernel();
return 0;
}
@@ -410,6 +406,7 @@ static int init_coda_psdev(void)
MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
+MODULE_LICENSE("GPL");
static int __init init_coda(void)
{
@@ -436,8 +433,6 @@ static void __exit exit_coda(void)
{
int err;
- ENTRY;
-
err = unregister_filesystem(&coda_fs_type);
if ( err != 0 ) {
printk("coda: failed to unregister filesystem\n");
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index e2b867310..9e60aa994 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -359,7 +359,6 @@ int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
char tmpbuf[80];
int tmplen = 0;
- ENTRY;
/* this works as long as we are below 1024 characters! */
if ( offset < 80 )
len += sprintf( buffer,"%-79s\n", "Coda upcall statistics");
@@ -392,7 +391,7 @@ int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
len = length;
if ( len < 0 )
len = 0;
- EXIT;
+
return len;
}
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index e21829beb..cf01630c6 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -80,7 +80,6 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp)
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
- ENTRY;
insize = SIZE(root);
UPARG(CODA_ROOT);
@@ -96,7 +95,6 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp)
}
CODA_FREE(inp, insize);
- EXIT;
return error;
}
@@ -106,7 +104,6 @@ int venus_getattr(struct super_block *sb, struct ViceFid *fid,
union inputArgs *inp;
union outputArgs *outp;
int insize, outsize, error;
- ENTRY;
insize = SIZE(getattr);
UPARG(CODA_GETATTR);
@@ -117,7 +114,6 @@ int venus_getattr(struct super_block *sb, struct ViceFid *fid,
*attr = outp->coda_getattr.attr;
CODA_FREE(inp, insize);
- EXIT;
return error;
}
@@ -432,7 +428,6 @@ int venus_readlink(struct super_block *sb, struct ViceFid *fid,
}
CDEBUG(D_INODE, " result %d\n",error);
- EXIT;
CODA_FREE(inp, insize);
return error;
}
@@ -462,7 +457,6 @@ int venus_link(struct super_block *sb, struct ViceFid *fid,
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
CDEBUG(D_INODE, " result %d\n",error);
- EXIT;
CODA_FREE(inp, insize);
return error;
}
@@ -499,7 +493,6 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
CDEBUG(D_INODE, " result %d\n",error);
- EXIT;
CODA_FREE(inp, insize);
return error;
}
@@ -536,7 +529,6 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
- EXIT;
return error;
}
@@ -633,7 +625,6 @@ int venus_statfs(struct super_block *sb, struct statfs *sfs)
}
CDEBUG(D_INODE, " result %d\n",error);
- EXIT;
CODA_FREE(inp, insize);
return error;
}
@@ -722,8 +713,6 @@ static int coda_upcall(struct coda_sb_info *sbi,
struct upc_req *req;
int error = 0;
- ENTRY;
-
vcommp = sbi->sbi_vcomm;
if ( !vcommp->vc_inuse ) {
printk("No pseudo device in upcall comms at %p\n", vcommp);
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 3827163c5..7582c9dd8 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -19,6 +19,7 @@
#include <linux/locks.h>
#include <linux/blkdev.h>
#include <linux/cramfs_fs.h>
+#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -33,6 +34,9 @@ static struct inode_operations cramfs_dir_inode_operations;
static struct file_operations cramfs_directory_operations;
static struct address_space_operations cramfs_aops;
+static DECLARE_MUTEX(read_mutex);
+
+
/* These two macros may change in future, to provide better st_ino
semantics. */
#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1)
@@ -199,8 +203,10 @@ static struct super_block * cramfs_read_super(struct super_block *sb, void *data
for (i = 0; i < READ_BUFFERS; i++)
buffer_blocknr[i] = -1;
+ down(&read_mutex);
/* Read the first block and get the superblock from it */
memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
+ up(&read_mutex);
/* Do sanity checks on the superblock */
if (super.magic != CRAMFS_MAGIC) {
@@ -291,7 +297,9 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
char *name;
int namelen, error;
+ down(&read_mutex);
de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
+ up(&read_mutex);
name = (char *)(de+1);
/*
@@ -332,7 +340,9 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
char *name;
int namelen, retval;
+ down(&read_mutex);
de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256);
+ up(&read_mutex);
name = (char *)(de+1);
/* Try to take advantage of sorted directories */
@@ -384,18 +394,22 @@ static int cramfs_readpage(struct file *file, struct page * page)
u32 start_offset, compr_len;
start_offset = OFFSET(inode) + maxblock*4;
+ down(&read_mutex);
if (page->index)
start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
- compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4)
- - start_offset);
+ compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
+ up(&read_mutex);
pgdata = kmap(page);
if (compr_len == 0)
; /* hole */
- else
+ else {
+ down(&read_mutex);
bytes_filled = cramfs_uncompress_block(pgdata,
PAGE_CACHE_SIZE,
cramfs_read(sb, start_offset, compr_len),
compr_len);
+ up(&read_mutex);
+ }
} else
pgdata = kmap(page);
memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 6204dcaa1..c5a57e284 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -569,6 +569,13 @@
Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from
devfsd or children.
v1.2
+ 20011202 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed bug in <devfsd_read>: was dereferencing freed pointer.
+ v1.3
+ 20011203 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed bug in <devfsd_close>: was dereferencing freed pointer.
+ Added process group check for devfsd privileges.
+ v1.4
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -601,7 +608,7 @@
#include <asm/bitops.h>
#include <asm/atomic.h>
-#define DEVFS_VERSION "1.2 (20011127)"
+#define DEVFS_VERSION "1.4 (20011203)"
#define DEVFS_NAME "devfs"
@@ -747,6 +754,7 @@ struct fs_info /* This structure is for the mounted devfs */
struct devfsd_buf_entry *devfsd_last_event;
volatile int devfsd_sleeping;
volatile struct task_struct *devfsd_task;
+ volatile pid_t devfsd_pgrp;
volatile struct file *devfsd_file;
struct devfsd_notify_struct *devfsd_info;
volatile unsigned long devfsd_event_mask;
@@ -1322,10 +1330,14 @@ static int is_devfsd_or_child (struct fs_info *fs_info)
{
struct task_struct *p;
- for (p = current; p != &init_task; p = p->p_opptr)
+ if (current == fs_info->devfsd_task) return (TRUE);
+ if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
+ for (p = current->p_opptr; p != &init_task; p = p->p_opptr)
{
if (p == fs_info->devfsd_task) return (TRUE);
}
+#endif
return (FALSE);
} /* End Function is_devfsd_or_child */
@@ -3243,11 +3255,17 @@ static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
tlen = rpos - *ppos;
if (done)
{
+ devfs_handle_t parent;
+
spin_lock (&fs_info->devfsd_buffer_lock);
fs_info->devfsd_first_event = entry->next;
if (entry->next == NULL) fs_info->devfsd_last_event = NULL;
spin_unlock (&fs_info->devfsd_buffer_lock);
- for (; de != NULL; de = de->parent) devfs_put (de);
+ for (; de != NULL; de = parent)
+ {
+ parent = de->parent;
+ devfs_put (de);
+ }
kmem_cache_free (devfsd_buf_cache, entry);
if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
*ppos = 0;
@@ -3284,6 +3302,8 @@ static int devfsd_ioctl (struct inode *inode, struct file *file,
}
fs_info->devfsd_task = current;
spin_unlock (&lock);
+ fs_info->devfsd_pgrp = (current->pgrp == current->pid) ?
+ current->pgrp : 0;
fs_info->devfsd_file = file;
fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
GFP_KERNEL);
@@ -3314,7 +3334,7 @@ static int devfsd_ioctl (struct inode *inode, struct file *file,
static int devfsd_close (struct inode *inode, struct file *file)
{
- struct devfsd_buf_entry *entry;
+ struct devfsd_buf_entry *entry, *next;
struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
if (fs_info->devfsd_file != file) return 0;
@@ -3330,10 +3350,14 @@ static int devfsd_close (struct inode *inode, struct file *file)
fs_info->devfsd_info = NULL;
}
spin_unlock (&fs_info->devfsd_buffer_lock);
+ fs_info->devfsd_pgrp = 0;
fs_info->devfsd_task = NULL;
wake_up (&fs_info->revalidate_wait_queue);
- for (; entry; entry = entry->next)
+ for (; entry; entry = next)
+ {
+ next = entry->next;
kmem_cache_free (devfsd_buf_cache, entry);
+ }
return 0;
} /* End Function devfsd_close */
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index 9b2215560..d514f908a 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -92,12 +92,6 @@ void coda_sysctl_clean(void);
printk(format, ## a); } \
} while (0)
-#define ENTRY \
- if(coda_print_entry) printk("Process %d entered %s\n",current->pid,__FUNCTION__)
-
-#define EXIT \
- if(coda_print_entry) printk("Process %d leaving %s\n",current->pid,__FUNCTION__)
-
#define CODA_ALLOC(ptr, cast, size) \
do { \
if (size < PAGE_SIZE) { \
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0efb476e3..186fe152a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -557,11 +557,13 @@ static inline int expand_stack(struct vm_area_struct * vma, unsigned long addres
* before relocating the vma range ourself.
*/
address &= PAGE_MASK;
+ spin_lock(&vma->vm_mm->page_table_lock);
grow = (vma->vm_start - address) >> PAGE_SHIFT;
if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
- ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
+ ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) {
+ spin_unlock(&vma->vm_mm->page_table_lock);
return -ENOMEM;
- spin_lock(&vma->vm_mm->page_table_lock);
+ }
vma->vm_start = address;
vma->vm_pgoff -= grow;
vma->vm_mm->total_vm += grow;
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d5ab6ab27..a8753bec7 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1229,6 +1229,7 @@
#define PCI_DEVICE_ID_AVM_B1 0x0700
#define PCI_DEVICE_ID_AVM_C4 0x0800
#define PCI_DEVICE_ID_AVM_A1 0x0a00
+#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00
#define PCI_DEVICE_ID_AVM_C2 0x1100
#define PCI_DEVICE_ID_AVM_T1 0x1200
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e813425c3..28f683623 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -11,10 +11,13 @@
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
-#define USB_CLASS_DATA 10
+#define USB_CLASS_CDC_DATA 0x0a
+#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
diff --git a/kernel/time.c b/kernel/time.c
index ffad77ad6..1a1e73564 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -70,11 +70,11 @@ extern rwlock_t xtime_lock;
*/
asmlinkage long sys_time(int * tloc)
{
- int i;
+ struct timeval now;
+ int i;
- /* SMP: This is fairly trivial. We grab CURRENT_TIME and
- stuff it to user space. No side effects */
- i = CURRENT_TIME;
+ do_gettimeofday(&now);
+ i = now.tv_sec;
if (tloc) {
if (put_user(i,tloc))
i = -EFAULT;
diff --git a/mm/memory.c b/mm/memory.c
index 8ade31111..19924efce 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1022,16 +1022,10 @@ out_unlock:
do_expand:
limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
- if (limit != RLIM_INFINITY) {
- if (inode->i_size >= limit) {
- send_sig(SIGXFSZ, current, 0);
- goto out;
- }
- if (offset > limit) {
- send_sig(SIGXFSZ, current, 0);
- offset = limit;
- }
- }
+ if (limit != RLIM_INFINITY && offset > limit)
+ goto out_sig;
+ if (offset > inode->i_sb->s_maxbytes)
+ goto out;
inode->i_size = offset;
out_truncate:
@@ -1040,8 +1034,11 @@ out_truncate:
inode->i_op->truncate(inode);
unlock_kernel();
}
-out:
return 0;
+out_sig:
+ send_sig(SIGXFSZ, current, 0);
+out:
+ return -EFBIG;
}
/*