diff options
author | davem <davem> | 2001-12-05 23:43:46 +0000 |
---|---|---|
committer | davem <davem> | 2001-12-05 23:43:46 +0000 |
commit | 2c0c74546941be513fb3c85deb5a386c59bc23b6 (patch) | |
tree | 5449db624fd7006284e55507583e11a2690336e3 | |
parent | 0c3fc2be470a61cc411b070a85dca0592c415273 (diff) | |
download | netdev-vger-cvs-2c0c74546941be513fb3c85deb5a386c59bc23b6.tar.gz |
Merge mainline to 2.4.17-pre4
40 files changed, 2296 insertions, 228 deletions
@@ -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) @@ -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; } /* |