summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acorn/block/Makefile3
-rw-r--r--drivers/acorn/scsi/Makefile3
-rw-r--r--drivers/atm/Makefile28
-rw-r--r--drivers/atm/ambassador.c551
-rw-r--r--drivers/atm/ambassador.h22
-rw-r--r--drivers/atm/atmdev_init.c2
-rw-r--r--drivers/atm/atmtcp.c61
-rw-r--r--drivers/atm/eni.c271
-rw-r--r--drivers/atm/eni.h3
-rw-r--r--drivers/atm/fore200e.c174
-rw-r--r--drivers/atm/fore200e.h33
-rw-r--r--drivers/atm/horizon.c124
-rw-r--r--drivers/atm/horizon.h2
-rw-r--r--drivers/atm/idt77105.c64
-rw-r--r--drivers/atm/iphase.c161
-rw-r--r--drivers/atm/nicstar.c141
-rw-r--r--drivers/atm/nicstar.h2
-rw-r--r--drivers/atm/suni.c169
-rw-r--r--drivers/atm/suni.h4
-rw-r--r--drivers/atm/uPD98402.c123
-rw-r--r--drivers/atm/zatm.c26
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/lvm.c9
-rw-r--r--drivers/block/md.c4
-rw-r--r--drivers/block/paride/paride.c4
-rw-r--r--drivers/cdrom/cm206.c2
-rw-r--r--drivers/char/acquirewdt.c10
-rw-r--r--drivers/char/amigamouse.c6
-rw-r--r--drivers/char/amiserial.c2
-rw-r--r--drivers/char/applicom.c1167
-rw-r--r--drivers/char/atixlmouse.c22
-rw-r--r--drivers/char/bttv.c206
-rw-r--r--drivers/char/bttv.h11
-rw-r--r--drivers/char/busmouse.c126
-rw-r--r--drivers/char/busmouse.h2
-rw-r--r--drivers/char/misc.c34
-rw-r--r--drivers/char/rtc.c10
-rw-r--r--drivers/char/serial.c290
-rw-r--r--drivers/char/sysrq.c36
-rw-r--r--drivers/char/tty_io.c3
-rw-r--r--drivers/char/wdt.c6
-rw-r--r--drivers/i2c/i2c-algo-pcf.c2
-rw-r--r--drivers/ide/Config.in9
-rw-r--r--drivers/ide/aec6210.c16
-rw-r--r--drivers/ide/ali14xx.c2
-rw-r--r--drivers/ide/alim15x3.c54
-rw-r--r--drivers/ide/amd7409.c109
-rw-r--r--drivers/ide/buddha.c2
-rw-r--r--drivers/ide/cmd640.c2
-rw-r--r--drivers/ide/cmd64x.c203
-rw-r--r--drivers/ide/cs5530.c21
-rw-r--r--drivers/ide/cy82c693.c15
-rw-r--r--drivers/ide/dtc2278.c2
-rw-r--r--drivers/ide/falconide.c2
-rw-r--r--drivers/ide/gayle.c2
-rw-r--r--drivers/ide/hd.c2
-rw-r--r--drivers/ide/hpt34x.c123
-rw-r--r--drivers/ide/hpt366.c125
-rw-r--r--drivers/ide/ht6560b.c2
-rw-r--r--drivers/ide/icside.c2
-rw-r--r--drivers/ide/ide-cd.c23
-rw-r--r--drivers/ide/ide-cd.h2
-rw-r--r--drivers/ide/ide-disk.c21
-rw-r--r--drivers/ide/ide-dma.c28
-rw-r--r--drivers/ide/ide-features.c2
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-geometry.c6
-rw-r--r--drivers/ide/ide-pci.c4
-rw-r--r--drivers/ide/ide-pmac.c4
-rw-r--r--drivers/ide/ide-pnp.c2
-rw-r--r--drivers/ide/ide-probe.c2
-rw-r--r--drivers/ide/ide-proc.c2
-rw-r--r--drivers/ide/ide-tape.c2
-rw-r--r--drivers/ide/ide.c33
-rw-r--r--drivers/ide/ide_modes.h2
-rw-r--r--drivers/ide/ns87415.c15
-rw-r--r--drivers/ide/opti621.c2
-rw-r--r--drivers/ide/pdc202xx.c311
-rw-r--r--drivers/ide/piix.c45
-rw-r--r--drivers/ide/q40ide.c2
-rw-r--r--drivers/ide/qd6580.c2
-rw-r--r--drivers/ide/rapide.c2
-rw-r--r--drivers/ide/rz1000.c2
-rw-r--r--drivers/ide/sis5513.c240
-rw-r--r--drivers/ide/sl82c105.c2
-rw-r--r--drivers/ide/trm290.c9
-rw-r--r--drivers/ide/umc8672.c2
-rw-r--r--drivers/ide/via82cxxx.c186
-rw-r--r--drivers/ieee1394/Config.in3
-rw-r--r--drivers/ieee1394/csr.c168
-rw-r--r--drivers/ieee1394/csr.h1
-rw-r--r--drivers/ieee1394/highlevel.c61
-rw-r--r--drivers/ieee1394/highlevel.h41
-rw-r--r--drivers/ieee1394/ieee1394.h99
-rw-r--r--drivers/ieee1394/ieee1394_core.c161
-rw-r--r--drivers/ieee1394/ieee1394_core.h17
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c37
-rw-r--r--drivers/ieee1394/ieee1394_types.h3
-rw-r--r--drivers/ieee1394/ohci1394.c195
-rw-r--r--drivers/ieee1394/ohci1394.h35
-rw-r--r--drivers/ieee1394/pcilynx.c78
-rw-r--r--drivers/ieee1394/pcilynx.h118
-rw-r--r--drivers/ieee1394/raw1394.c161
-rw-r--r--drivers/ieee1394/raw1394.h7
-rw-r--r--drivers/isdn/Config.in10
-rw-r--r--drivers/isdn/Makefile4
-rw-r--r--drivers/isdn/avmb1/Makefile133
-rw-r--r--drivers/isdn/avmb1/avm_cs.c528
-rw-r--r--drivers/isdn/avmb1/b1dma.c2
-rw-r--r--drivers/isdn/avmb1/b1pcmcia.c9
-rw-r--r--drivers/isdn/avmb1/c4.c110
-rw-r--r--drivers/isdn/avmb1/capi.c1777
-rw-r--r--drivers/isdn/avmb1/capicmd.h17
-rw-r--r--drivers/isdn/avmb1/capidev.h35
-rw-r--r--drivers/isdn/avmb1/capidrv.c100
-rw-r--r--drivers/isdn/avmb1/capifs.c595
-rw-r--r--drivers/isdn/avmb1/capifs.h25
-rw-r--r--drivers/isdn/avmb1/capiutil.c23
-rw-r--r--drivers/isdn/avmb1/capiutil.h72
-rw-r--r--drivers/isdn/avmb1/kcapi.c274
-rw-r--r--drivers/isdn/divert/divert_procfs.c26
-rw-r--r--drivers/isdn/eicon/eicon_idi.c32
-rw-r--r--drivers/isdn/hisax/callc.c18
-rw-r--r--drivers/isdn/hisax/l3dss1.c131
-rw-r--r--drivers/isdn/hisax/md5sums.asc14
-rw-r--r--drivers/isdn/hisax/q931.c28
-rw-r--r--drivers/isdn/hisax/w6692.c21
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c23
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c28
-rw-r--r--drivers/isdn/isdn_audio.c29
-rw-r--r--drivers/isdn/isdn_common.c8
-rw-r--r--drivers/isdn/isdn_concap.c20
-rw-r--r--drivers/isdn/isdn_net.c420
-rw-r--r--drivers/isdn/isdn_net.h106
-rw-r--r--drivers/isdn/isdn_ppp.c210
-rw-r--r--drivers/isdn/isdn_v110.c167
-rw-r--r--drivers/isdn/isdn_v110.h22
-rw-r--r--drivers/net/3c509.c4
-rw-r--r--drivers/net/3c515.c4
-rw-r--r--drivers/net/3c59x.c5
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/8390.c87
-rw-r--r--drivers/net/Config.in14
-rw-r--r--drivers/net/defxx.c2
-rw-r--r--drivers/net/epic100.c14
-rw-r--r--drivers/net/irda/irport.c8
-rw-r--r--drivers/net/irda/irtty.c12
-rw-r--r--drivers/net/irda/nsc-ircc.c4
-rw-r--r--drivers/net/irda/toshoboe.c4
-rw-r--r--drivers/net/irda/w83977af_ir.c4
-rw-r--r--drivers/net/ne2k-pci.c294
-rw-r--r--drivers/net/net_init.c28
-rw-r--r--drivers/net/pcmcia/3c575_cb.c724
-rw-r--r--drivers/net/pcmcia/Config.in1
-rw-r--r--drivers/net/pcmcia/Makefile3
-rw-r--r--drivers/net/pcmcia/xircom_tulip_cb.c3153
-rw-r--r--drivers/net/plip.c3
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/sgiseeq.c3
-rw-r--r--drivers/net/shaper.c4
-rw-r--r--drivers/net/starfire.c351
-rw-r--r--drivers/net/tlan.c15
-rw-r--r--drivers/net/tokenring/lanstreamer.c344
-rw-r--r--drivers/net/tokenring/lanstreamer.h11
-rw-r--r--drivers/net/tulip/21142.c1
-rw-r--r--drivers/net/tulip/eeprom.c43
-rw-r--r--drivers/net/tulip/interrupt.c6
-rw-r--r--drivers/net/tulip/media.c1
-rw-r--r--drivers/net/tulip/pnic.c1
-rw-r--r--drivers/net/tulip/timer.c7
-rw-r--r--drivers/net/tulip/tulip.h29
-rw-r--r--drivers/net/tulip/tulip_core.c109
-rw-r--r--drivers/net/via-rhine.c421
-rw-r--r--drivers/net/wan/Config.in6
-rw-r--r--drivers/parport/ChangeLog9
-rw-r--r--drivers/parport/init.c6
-rw-r--r--drivers/parport/parport_pc.c7
-rw-r--r--drivers/pci/pci.c52
-rw-r--r--drivers/pcmcia/ti113x.h26
-rw-r--r--drivers/pcmcia/yenta.c19
-rw-r--r--drivers/pnp/isapnp.c47
-rw-r--r--drivers/sbus/char/envctrl.c13
-rw-r--r--drivers/sbus/char/sunmouse.c15
-rw-r--r--drivers/sbus/char/sunserial.c4
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/advansys.c26
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/qlogicisp.c10
-rw-r--r--drivers/scsi/scsi.c8
-rw-r--r--drivers/scsi/st.c20
-rw-r--r--drivers/scsi/u14-34f.c2
-rw-r--r--drivers/sound/ac97_codec.c2
-rw-r--r--drivers/sound/awe_hw.h4
-rw-r--r--drivers/sound/awe_wave.c1692
-rw-r--r--drivers/sound/awe_wave.h18
-rw-r--r--drivers/sound/sb.h1
-rw-r--r--drivers/sound/sb_card.c237
-rw-r--r--drivers/sound/sb_common.c5
-rw-r--r--drivers/sound/sb_mixer.c6
-rw-r--r--drivers/usb/Config.in1
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/hid-debug.h1
-rw-r--r--drivers/usb/hid.c54
-rw-r--r--drivers/usb/hid.h8
-rw-r--r--drivers/usb/keybdev.c21
-rw-r--r--drivers/usb/mdc800.c931
-rw-r--r--drivers/usb/mousedev.c4
-rw-r--r--drivers/usb/pegasus.c42
-rw-r--r--drivers/usb/serial/Makefile-keyspan_pda_fw2
-rw-r--r--drivers/usb/serial/keyspan_pda.S1124
-rw-r--r--drivers/usb/serial/usb-serial.c857
-rw-r--r--drivers/usb/serial/usb-serial.h116
-rw-r--r--drivers/usb/uhci.c21
-rw-r--r--drivers/usb/usb-ohci.c97
-rw-r--r--drivers/usb/usb-ohci.h137
-rw-r--r--drivers/usb/usb-storage.c324
-rw-r--r--drivers/usb/usb-uhci.c32
-rw-r--r--drivers/usb/usb.c49
-rw-r--r--drivers/usb/wacom.c485
-rw-r--r--drivers/video/Makefile8
-rw-r--r--drivers/video/amifb.c26
-rw-r--r--drivers/video/cgthreefb.c10
-rw-r--r--drivers/video/macmodes.c121
-rw-r--r--drivers/video/modedb.c15
-rw-r--r--drivers/video/offb.c109
-rw-r--r--drivers/video/riva/fbdev.c2
226 files changed, 17000 insertions, 7332 deletions
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
index 481d7f328..b52bc245f 100644
--- a/drivers/acorn/block/Makefile
+++ b/drivers/acorn/block/Makefile
@@ -51,9 +51,6 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
-
fd1772_mod.o: $(FLOPPY)
$(LD) -r -o $@ $(FLOPPY)
diff --git a/drivers/acorn/scsi/Makefile b/drivers/acorn/scsi/Makefile
index a2c94a0d5..35bc69a18 100644
--- a/drivers/acorn/scsi/Makefile
+++ b/drivers/acorn/scsi/Makefile
@@ -49,8 +49,5 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
include $(TOPDIR)/Rules.make
-.S.o:
- $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $<
-
acornscsi_mod.o: acornscsi.o acornscsi-io.o
$(LD) $(LD_RFLAG) -r -o $@ acornscsi.o acornscsi-io.o
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index f126bd232..8dbf1364a 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -3,15 +3,15 @@
# Makefile for the Linux network (ATM) device drivers.
#
-L_TARGET := atm.a
-L_OBJS := atmdev_init.o
+O_TARGET := atm.o
+O_OBJS := atmdev_init.o
M_OBJS :=
MOD_LIST_NAME := ATM_MODULES
include ../../.config
ifeq ($(CONFIG_ATM_ENI),y)
-L_OBJS += eni.o
+O_OBJS += eni.o
NEED_SUNI_LX = suni.o
else
ifeq ($(CONFIG_ATM_ENI),m)
@@ -21,8 +21,8 @@ else
endif
ifeq ($(CONFIG_ATM_ZATM),y)
-L_OBJS += zatm.o
-LX_OBJS += uPD98402.o
+O_OBJS += zatm.o
+OX_OBJS += uPD98402.o
else
ifeq ($(CONFIG_ATM_ZATM),m)
M_OBJS += zatm.o
@@ -31,11 +31,11 @@ else
endif
ifeq ($(CONFIG_ATM_TNETA1570),y)
-L_OBJS += tneta1570.o suni.o
+O_OBJS += tneta1570.o suni.o
endif
ifeq ($(CONFIG_ATM_NICSTAR),y)
-L_OBJS += nicstar.o
+O_OBJS += nicstar.o
ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
NEED_SUNI_LX = suni.o
endif
@@ -55,7 +55,7 @@ else
endif
ifeq ($(CONFIG_ATM_HORIZON),y)
-L_OBJS += horizon.o
+O_OBJS += horizon.o
else
ifeq ($(CONFIG_ATM_HORIZON),m)
M_OBJS += horizon.o
@@ -63,7 +63,7 @@ else
endif
ifeq ($(CONFIG_ATM_AMBASSADOR),y)
-L_OBJS += ambassador.o
+O_OBJS += ambassador.o
else
ifeq ($(CONFIG_ATM_AMBASSADOR),m)
M_OBJS += ambassador.o
@@ -71,7 +71,7 @@ else
endif
ifeq ($(CONFIG_ATM_TCP),y)
-L_OBJS += atmtcp.o
+O_OBJS += atmtcp.o
else
ifeq ($(CONFIG_ATM_TCP),m)
M_OBJS += atmtcp.o
@@ -79,7 +79,7 @@ else
endif
ifeq ($(CONFIG_ATM_IA),y)
-L_OBJS += iphase.o
+O_OBJS += iphase.o
NEED_SUNI_LX = suni.o
else
ifeq ($(CONFIG_ATM_IA),m)
@@ -91,13 +91,13 @@ endif
ifeq ($(NEED_SUNI_LX),)
MX_OBJS += $(NEED_SUNI_MX)
else
- LX_OBJS += $(NEED_SUNI_LX)
+ OX_OBJS += $(NEED_SUNI_LX)
endif
ifeq ($(NEED_IDT77105_LX),)
MX_OBJS += $(NEED_IDT77105_MX)
else
- LX_OBJS += $(NEED_IDT77105_LX)
+ OX_OBJS += $(NEED_IDT77105_LX)
endif
ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
@@ -114,7 +114,7 @@ FORE200E_FW_OBJS += fore200e_sba_fw.o
endif
endif
ifeq ($(CONFIG_ATM_FORE200E),y)
-L_OBJS += fore200e.o $(FORE200E_FW_OBJS)
+O_OBJS += fore200e.o $(FORE200E_FW_OBJS)
else
ifeq ($(CONFIG_ATM_FORE200E),m)
M_OBJS += fore_200e.o
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 8ec9960c1..a71884db7 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -39,7 +40,7 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Ambassador driver"
-#define version_string "1.2"
+#define version_string "1.2.4"
static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
@@ -97,8 +98,8 @@ static inline void __init show_version (void) {
The adapter is quite intelligent (fast) and has a simple interface
(few features). VPI is always zero, 1024 VCIs are supported. There
- is limited cell rate support. UBR channels can be kept and ABR
- (explicit rate, bu not EFCI) is supported. There is no CBR or VBR
+ is limited cell rate support. UBR channels can be capped and ABR
+ (explicit rate, but not EFCI) is supported. There is no CBR or VBR
support.
1. Driver <-> Adapter Communication
@@ -321,8 +322,29 @@ static unsigned int rxs_bs[NUM_RX_POOLS] = { 4080, 12240, 36720, 65535 };
static unsigned int rx_lats = 7;
static unsigned char pci_lat = 0;
+static const unsigned long onegigmask = -1 << 30;
+
/********** access to adapter **********/
+static inline void wr_plain (const amb_dev * dev, const u32 * addr, u32 data) {
+ PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x", addr, data);
+#ifdef AMB_MMIO
+ dev->membase[addr - (u32 *) 0] = data;
+#else
+ outl (data, dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
+#endif
+}
+
+static inline u32 rd_plain (const amb_dev * dev, const u32 * addr) {
+#ifdef AMB_MMIO
+ u32 data = dev->membase[addr - (u32 *) 0];
+#else
+ u32 data = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
+#endif
+ PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x", addr, data);
+ return data;
+}
+
static const amb_mem * const mem = 0;
static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) {
@@ -342,7 +364,7 @@ static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
u32 be = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
#endif
u32 data = be32_to_cpu (be);
- PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be);
+ PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be);
return data;
}
@@ -350,14 +372,18 @@ static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
static inline void dump_registers (const amb_dev * dev) {
#ifdef DEBUG_AMBASSADOR
- // u32 * i;
- // PRINTD (DBG_REGS, "mailboxes: ");
- // for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i)
- // PRINTD (DBG_REGS, "%08x ", rd_mem (dev, i));
- PRINTD (DBG_REGS, "doorb %08x", rd_mem (dev, (u32 *) 0x60));
- PRINTD (DBG_REGS, "irqev %08x", rd_mem (dev, (u32 *) 0x64));
- PRINTD (DBG_REGS, "irqen %08x", rd_mem (dev, (u32 *) 0x68));
- PRINTD (DBG_REGS, "reset %08x", rd_mem (dev, (u32 *) 0x6c));
+ if (debug & DBG_REGS) {
+ u32 * i;
+ PRINTD (DBG_REGS, "reading PLX control: ");
+ for (i = (u32 *) 0x00; i < (u32 *) 0x30; ++i)
+ rd_mem (dev, i);
+ PRINTD (DBG_REGS, "reading mailboxes: ");
+ for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i)
+ rd_mem (dev, i);
+ PRINTD (DBG_REGS, "reading doorb irqev irqen reset:");
+ for (i = (u32 *) 0x60; i < (u32 *) 0x70; ++i)
+ rd_mem (dev, i);
+ }
#else
(void) dev;
#endif
@@ -414,8 +440,8 @@ static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * sk
static inline int check_area (void * start, size_t length) {
// assumes length > 0
- const u32 fourmegmask = (-1)<<22;
- const u32 twofivesixmask = (-1)<<8;
+ const u32 fourmegmask = -1 << 22;
+ const u32 twofivesixmask = -1 << 8;
const u32 starthole = 0xE0000000;
u32 startaddress = virt_to_bus (start);
u32 lastaddress = startaddress+length-1;
@@ -435,7 +461,7 @@ static inline void amb_kfree_skb (struct sk_buff * skb) {
if (ATM_SKB(skb)->vcc->pop) {
ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
} else {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
}
@@ -448,7 +474,7 @@ static inline void tx_complete (amb_dev * dev, tx_out * tx) {
PRINTD (DBG_FLOW|DBG_TX, "tx_complete %p %p", dev, tx);
// VC layer stats
- ATM_SKB(skb)->vcc->stats->tx++;
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
// free the descriptor
kfree (tx_descr);
@@ -489,7 +515,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
dump_skb ("<<<", vc, skb);
// VC layer stats
- atm_vcc->stats->rx++;
+ atomic_inc(&atm_vcc->stats->rx);
skb->stamp = xtime;
// end of our responsability
atm_vcc->push (atm_vcc, skb);
@@ -504,7 +530,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
} else {
PRINTK (KERN_INFO, "dropped over-size frame");
// should we count this?
- atm_vcc->stats->rx_drop++;
+ atomic_inc(&atm_vcc->stats->rx_drop);
}
} else {
@@ -524,7 +550,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
dev->stats.rx.unused++;
}
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
@@ -548,7 +574,8 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
// sometimes does 16-bit accesses (yuk yuk yuk)
static int command_do (amb_dev * dev, command * cmd) {
- volatile amb_cq * cq = &dev->cq;
+ amb_cq * cq = &dev->cq;
+ volatile amb_cq_ptrs * ptrs = &cq->ptrs;
command * my_slot;
unsigned long timeout;
@@ -562,18 +589,18 @@ static int command_do (amb_dev * dev, command * cmd) {
// if not full...
if (cq->pending < cq->maximum) {
// remember my slot for later
- my_slot = cq->in;
+ my_slot = ptrs->in;
PRINTD (DBG_CMD, "command in slot %p", my_slot);
dump_command (cmd);
// copy command in
- *cq->in = *cmd;
+ *ptrs->in = *cmd;
cq->pending++;
- cq->in = NEXTQ (cq->in, cq->start, cq->limit);
+ ptrs->in = NEXTQ (ptrs->in, ptrs->start, ptrs->limit);
// mail the command
- wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (cq->in));
+ wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (ptrs->in));
// prepare to wait for cq->pending milliseconds
// effectively one centisecond on i386
@@ -591,13 +618,13 @@ static int command_do (amb_dev * dev, command * cmd) {
}
// wait for my slot to be reached (all waiters are here or above, until...)
- while (cq->out != my_slot) {
- PRINTD (DBG_CMD, "wait: command slot (now at %p)", cq->out);
+ while (ptrs->out != my_slot) {
+ PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out);
schedule();
}
// wait on my slot (... one gets to its slot, and... )
- while (cq->out->request != cpu_to_be32 (SRB_COMPLETE)) {
+ while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) {
PRINTD (DBG_CMD, "wait: command slot completion");
schedule();
}
@@ -607,12 +634,13 @@ static int command_do (amb_dev * dev, command * cmd) {
spin_lock (&cq->lock);
cq->pending--;
// copy command out
- *cmd = *cq->out;
- cq->out = NEXTQ (cq->out, cq->start, cq->limit);
+ *cmd = *ptrs->out;
+ ptrs->out = NEXTQ (ptrs->out, ptrs->start, ptrs->limit);
spin_unlock (&cq->lock);
return 0;
} else {
+ cq->filled++;
spin_unlock (&cq->lock);
return -EAGAIN;
}
@@ -796,7 +824,7 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority
return;
}
if (check_area (skb->data, skb->truesize)) {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
// cast needed as there is no %? for pointer differences
@@ -805,14 +833,14 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority
rx.handle = virt_to_bus (skb);
rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
if (rx_give (dev, &rx, pool))
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
return;
}
-// top up all RX pools (also called as a bottom half)
+// top up all RX pools (can also be called as a bottom half)
static void fill_rx_pools (amb_dev * dev) {
unsigned char pool;
@@ -827,25 +855,23 @@ static void fill_rx_pools (amb_dev * dev) {
/********** enable host interrupts **********/
static inline void interrupts_on (amb_dev * dev) {
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- | AMB_INTERRUPT_BITS);
+ wr_plain (dev, &mem->interrupt_control,
+ rd_plain (dev, &mem->interrupt_control)
+ | AMB_INTERRUPT_BITS);
}
/********** disable host interrupts **********/
static inline void interrupts_off (amb_dev * dev) {
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- &~ AMB_INTERRUPT_BITS);
+ wr_plain (dev, &mem->interrupt_control,
+ rd_plain (dev, &mem->interrupt_control)
+ &~ AMB_INTERRUPT_BITS);
}
/********** interrupt handling **********/
static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) {
amb_dev * dev = amb_devs;
- unsigned int irq_ok;
- unsigned int irq_ok_old;
(void) pt_regs;
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
@@ -860,50 +886,56 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs)
break;
dev = dev->prev;
}
+ // impossible - unless we add the device to our list after both
+ // registering the IRQ handler for it and enabling interrupts, AND
+ // the card generates an IRQ at startup - should not happen again
if (!dev) {
- PRINTD (DBG_IRQ, "irq not for me: %d", irq);
+ PRINTD (DBG_IRQ, "irq for unknown device: %d", irq);
return;
}
+ // impossible - unless we have memory corruption of dev or kernel
if (irq != dev->irq) {
PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq);
return;
}
- // definitely for us
- irq_ok = 0;
- irq_ok_old = -1;
+ {
+ u32 interrupt = rd_plain (dev, &mem->interrupt);
- // perhaps disable interrupts? (disabled at PIC by Linux)
- // interrupts_off (dev);
+ // for us or someone else sharing the same interrupt
+ if (!interrupt) {
+ PRINTD (DBG_IRQ, "irq not for me: %d", irq);
+ return;
+ }
+
+ // definitely for us
+ PRINTD (DBG_IRQ, "FYI: interrupt was %08x", interrupt);
+ wr_plain (dev, &mem->interrupt, -1);
+ }
- while (irq_ok_old != irq_ok && irq_ok < 100) {
+ {
+ unsigned int irq_work = 0;
unsigned char pool;
- PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u",
- rd_mem (dev, &mem->interrupt), irq_ok);
- wr_mem (dev, &mem->interrupt, -1);
- irq_ok_old = irq_ok;
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
while (!rx_take (dev, pool))
- ++irq_ok;
+ ++irq_work;
while (!tx_take (dev))
- ++irq_ok;
- }
+ ++irq_work;
- if (irq_ok) {
-#if 0
- queue_task (&dev->bh, &tq_immediate);
- mark_bh (IMMEDIATE_BH);
+ if (irq_work) {
+#ifdef FILL_RX_POOLS_IN_BH
+ queue_task (&dev->bh, &tq_immediate);
+ mark_bh (IMMEDIATE_BH);
#else
- fill_rx_pools (dev);
+ fill_rx_pools (dev);
#endif
- PRINTD (DBG_IRQ, "work done: %u", irq_ok);
- } else {
- PRINTD (DBG_IRQ|DBG_WARN, "no work done");
+ PRINTD (DBG_IRQ, "work done: %u", irq_work);
+ } else {
+ PRINTD (DBG_IRQ|DBG_WARN, "no work done");
+ }
}
- // perhaps re-enable interrupts? (re-enabled at PIC by Linux)
- // interrupts_on (dev);
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id);
return;
}
@@ -913,6 +945,7 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs)
#ifdef DEBUG_AMBASSADOR
static void dont_panic (amb_dev * dev) {
amb_cq * cq = &dev->cq;
+ volatile amb_cq_ptrs * ptrs = &cq->ptrs;
amb_txq * txq;
amb_rxq * rxq;
command * cmd;
@@ -926,10 +959,11 @@ static void dont_panic (amb_dev * dev) {
cli();
PRINTK (KERN_INFO, "don't panic - putting adapter into reset");
- wr_mem (dev, &mem->reset_control, rd_mem (dev, &mem->reset_control) | AMB_RESET);
+ wr_plain (dev, &mem->reset_control,
+ rd_plain (dev, &mem->reset_control) | AMB_RESET_BITS);
PRINTK (KERN_INFO, "marking all commands complete");
- for (cmd = cq->start; cmd < cq->limit; ++cmd)
+ for (cmd = ptrs->start; cmd < ptrs->limit; ++cmd)
cmd->request = cpu_to_be32 (SRB_COMPLETE);
PRINTK (KERN_INFO, "completing all TXs");
@@ -952,7 +986,7 @@ static void dont_panic (amb_dev * dev) {
if (rx == rxq->in.start)
rx = rxq->in.limit;
--rx;
- dev_kfree_skb (bus_to_virt (rx->handle));
+ dev_kfree_skb_any (bus_to_virt (rx->handle));
}
}
@@ -972,18 +1006,19 @@ static unsigned int make_rate (unsigned int rate, rounding r,
PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate);
- // rates in cells per second, ITU format (nasty 16bit fp)
+ // rates in cells per second, ITU format (nasty 16-bit floating-point)
// given 5-bit e and 9-bit m:
// rate = EITHER (1+m/2^9)*2^e OR 0
// bits = EITHER 1<<14 | e<<9 | m OR 0
// (bit 15 is "reserved", bit 14 "non-zero")
// smallest rate is 0 (special representation)
// largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1)
+ // smallest non-zero rate is (1+0/512)*2^0 = 1 (> 0)
// simple algorithm:
// find position of top bit, this gives e
// remove top bit and shift (rounding if feeling clever) by 9-e
- // ucode bug: please don't set bit 14! 0 not representable
+ // ucode bug: please don't set bit 14! so 0 rate not representable
if (rate > 0xffc00000U) {
// larger than largest representable rate
@@ -1228,7 +1263,7 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
// we are not really "immediately before allocating the connection
// identifier in hardware", but it will just have to do!
- atm_vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&atm_vcc->flags);
if (txtp->traffic_class != ATM_NONE) {
command cmd;
@@ -1303,7 +1338,7 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
atm_vcc->vci = vci;
// indicate readiness
- atm_vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&atm_vcc->flags);
MOD_INC_USE_COUNT;
return 0;
@@ -1319,7 +1354,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
PRINTD (DBG_VCC|DBG_FLOW, "amb_close");
// indicate unreadiness
- atm_vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&atm_vcc->flags);
// disable TXing
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
@@ -1384,7 +1419,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
kfree (vcc);
// say the VPI/VCI is free again
- atm_vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
MOD_DEC_USE_COUNT;
}
@@ -1394,6 +1429,8 @@ static void amb_close (struct atm_vcc * atm_vcc) {
static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) {
unsigned short newdebug;
if (cmd == AMB_SETDEBUG) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
if (copy_from_user (&newdebug, arg, sizeof(newdebug))) {
// moan
return -EFAULT;
@@ -1402,6 +1439,8 @@ static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) {
return 0;
}
} else if (cmd == AMB_DONTPANIC) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
dont_panic (dev);
} else {
// moan
@@ -1453,7 +1492,7 @@ static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
}
if (check_area (skb->data, skb->len)) {
- atm_vcc->stats->tx_err++;
+ atomic_inc(&atm_vcc->stats->tx_err);
return -ENOMEM; // ?
}
@@ -1564,7 +1603,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
// at. However, I note that the ATM layer calls kfree_skb rather
// than dev_kfree_skb at this point so we are least covered as far
// as buffer locking goes. There may be bugs if pcap clones RX skbs.
-
+
PRINTD (DBG_FLOW|DBG_SKB, "amb_rx_free skb %p (atm_vcc %p, vcc %p)",
skb, atm_vcc, vcc);
@@ -1582,7 +1621,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
}
// just do what the ATM layer would have done
- kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
@@ -1733,12 +1772,12 @@ static int __init create_queues (amb_dev * dev, unsigned int cmds,
cq->high = 0;
cq->maximum = cmds - 1;
- cq->start = cmd;
- cq->in = cmd;
- cq->out = cmd;
- cq->limit = cmd + cmds;
+ cq->ptrs.start = cmd;
+ cq->ptrs.in = cmd;
+ cq->ptrs.out = cmd;
+ cq->ptrs.limit = cmd + cmds;
- memory = cq->limit;
+ memory = cq->ptrs.limit;
}
PRINTD (DBG_TX, "TX queue pair at %p", memory);
@@ -1810,7 +1849,7 @@ static int __init create_queues (amb_dev * dev, unsigned int cmds,
static void destroy_queues (amb_dev * dev) {
// all queues assumed empty
- void * memory = dev->cq.start;
+ void * memory = dev->cq.ptrs.start;
// includes txq.in, txq.out, rxq[].in and rxq[].out
PRINTD (DBG_FLOW, "destroy_queues %p", dev);
@@ -1823,9 +1862,8 @@ static void destroy_queues (amb_dev * dev) {
/********** basic loader commands and error handling **********/
-static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
- volatile loader_block * lb) {
-
+static int __init do_loader_command (volatile loader_block * lb,
+ const amb_dev * dev, loader_command cmd) {
// centisecond timeouts - guessing away here
unsigned int command_timeouts [] = {
[host_memory_test] = 15,
@@ -1939,8 +1977,9 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
lb->result = 0;
lb->command = cpu_to_be32 (cmd);
lb->valid = cpu_to_be32 (DMA_VALID);
+ // dump_registers (dev);
// dump_loader_block (lb);
- wr_mem (dev, &mem->doorbell, virt_to_bus (lb));
+ wr_mem (dev, &mem->doorbell, virt_to_bus (lb) & ~onegigmask);
timeout = command_timeouts[cmd] * HZ/100;
@@ -1957,7 +1996,7 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
if (cmd == adapter_start) {
// wait for start command to acknowledge...
timeout = HZ/10;
- while (rd_mem (dev, &mem->doorbell))
+ while (rd_plain (dev, &mem->doorbell))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -1975,27 +2014,27 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
/* loader: determine loader version */
-static int __init get_loader_version (const amb_dev * dev, u32 * version) {
- loader_block lb;
+static int __init get_loader_version (loader_block * lb,
+ const amb_dev * dev, u32 * version) {
int res;
PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version");
- res = do_loader_command (dev, get_version_number, &lb);
+ res = do_loader_command (lb, dev, get_version_number);
if (res)
return res;
if (version)
- *version = be32_to_cpu (lb.payload.version);
+ *version = be32_to_cpu (lb->payload.version);
return 0;
}
-/* loader: read or verify memory data blocks */
+/* loader: write memory data blocks */
-static int __init loader_write (const amb_dev * dev, const u32 * data,
+static int __init loader_write (loader_block * lb,
+ const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
- loader_block lb;
- transfer_block * tb = &lb.payload.transfer;
+ transfer_block * tb = &lb->payload.transfer;
PRINTD (DBG_FLOW|DBG_LOAD, "loader_write");
@@ -2005,14 +2044,16 @@ static int __init loader_write (const amb_dev * dev, const u32 * data,
tb->count = cpu_to_be32 (count);
for (i = 0; i < count; ++i)
tb->data[i] = cpu_to_be32 (data[i]);
- return do_loader_command (dev, write_adapter_memory, &lb);
+ return do_loader_command (lb, dev, write_adapter_memory);
}
-static int __init loader_verify (const amb_dev * dev, const u32 * data,
+/* loader: verify memory data blocks */
+
+static int __init loader_verify (loader_block * lb,
+ const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
- loader_block lb;
- transfer_block * tb = &lb.payload.transfer;
+ transfer_block * tb = &lb->payload.transfer;
int res;
PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify");
@@ -2021,7 +2062,7 @@ static int __init loader_verify (const amb_dev * dev, const u32 * data,
return -EINVAL;
tb->address = cpu_to_be32 (address);
tb->count = cpu_to_be32 (count);
- res = do_loader_command (dev, read_adapter_memory, &lb);
+ res = do_loader_command (lb, dev, read_adapter_memory);
if (!res)
for (i = 0; i < count; ++i)
if (tb->data[i] != cpu_to_be32 (data[i])) {
@@ -2031,13 +2072,14 @@ static int __init loader_verify (const amb_dev * dev, const u32 * data,
return res;
}
-static int __init loader_start (const amb_dev * dev, u32 address) {
- loader_block lb;
-
+/* loader: start microcode */
+
+static int __init loader_start (loader_block * lb,
+ const amb_dev * dev, u32 address) {
PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
- lb.payload.start = cpu_to_be32 (address);
- return do_loader_command (dev, adapter_start, &lb);
+ lb->payload.start = cpu_to_be32 (address);
+ return do_loader_command (lb, dev, adapter_start);
}
/********** reset card **********/
@@ -2047,19 +2089,21 @@ static int amb_reset (amb_dev * dev, int diags) {
PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset");
- word = rd_mem (dev, &mem->reset_control);
-#if 0
- // clear all interrupts just in case
- wr_mem (dev, &mem->interrupt, -1);
-#endif
+ word = rd_plain (dev, &mem->reset_control);
// put card into reset state
- wr_mem (dev, &mem->reset_control, word | AMB_RESET);
+ wr_plain (dev, &mem->reset_control, word | AMB_RESET_BITS);
// wait a short while
udelay (10);
+#if 1
+ // put card into known good state
+ wr_plain (dev, &mem->interrupt_control, AMB_DOORBELL_BITS);
+ // clear all interrupts just in case
+ wr_plain (dev, &mem->interrupt, -1);
+#endif
// clear self-test done flag
- wr_mem (dev, &mem->mb.loader.ready, 0);
+ wr_plain (dev, &mem->mb.loader.ready, 0);
// take card out of reset state
- wr_mem (dev, &mem->reset_control, word &~ AMB_RESET);
+ wr_plain (dev, &mem->reset_control, word &~ AMB_RESET_BITS);
if (diags) {
unsigned long timeout;
@@ -2069,7 +2113,7 @@ static int amb_reset (amb_dev * dev, int diags) {
timeout = schedule_timeout (timeout);
// half second time-out
timeout = HZ/2;
- while (!rd_mem (dev, &mem->mb.loader.ready))
+ while (!rd_plain (dev, &mem->mb.loader.ready))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -2078,6 +2122,7 @@ static int amb_reset (amb_dev * dev, int diags) {
}
// get results of self-test
+ // XXX double check byte-order
word = rd_mem (dev, &mem->mb.loader.result);
if (word & SELF_TEST_FAILURE) {
void sf (const char * msg) {
@@ -2105,7 +2150,7 @@ static int amb_reset (amb_dev * dev, int diags) {
/********** transfer and start the microcode **********/
-static int __init ucode_init (amb_dev * dev) {
+static int __init ucode_init (loader_block * lb, amb_dev * dev) {
unsigned int i = 0;
unsigned int total = 0;
const u32 * pointer = ucode_data;
@@ -2125,10 +2170,10 @@ static int __init ucode_init (amb_dev * dev) {
else
words = MAX_TRANSFER_DATA;
total += words;
- res = loader_write (dev, pointer, address, words);
+ res = loader_write (lb, dev, pointer, address, words);
if (res)
return res;
- res = loader_verify (dev, pointer, address, words);
+ res = loader_verify (lb, dev, pointer, address, words);
if (res)
return res;
count -= words;
@@ -2138,7 +2183,7 @@ static int __init ucode_init (amb_dev * dev) {
i += 1;
}
if (*pointer == 0xdeadbeef) {
- return loader_start (dev, ucode_start);
+ return loader_start (lb, dev, ucode_start);
} else {
// cast needed as there is no %? for pointer differnces
PRINTD (DBG_LOAD|DBG_ERR,
@@ -2156,14 +2201,14 @@ static int __init amb_talk (amb_dev * dev) {
unsigned char pool;
unsigned long timeout;
- static inline u32 x (void * addr) {
+ u32 x (void * addr) {
return cpu_to_be32 (virt_to_bus (addr));
}
PRINTD (DBG_FLOW, "amb_talk %p", dev);
- a.command_start = x (dev->cq.start);
- a.command_end = x (dev->cq.limit);
+ a.command_start = x (dev->cq.ptrs.start);
+ a.command_end = x (dev->cq.ptrs.limit);
a.tx_start = x (dev->txq.in.start);
a.tx_end = x (dev->txq.in.limit);
a.txcom_start = x (dev->txq.out.start);
@@ -2192,7 +2237,7 @@ static int __init amb_talk (amb_dev * dev) {
timeout = schedule_timeout (timeout);
// give the adapter another half second?
timeout = HZ/2;
- while (rd_mem (dev, &mem->doorbell))
+ while (rd_plain (dev, &mem->doorbell))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -2259,38 +2304,55 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) {
}
static int __init amb_init (amb_dev * dev) {
- u32 version;
+ loader_block lb;
+
+ void fixup_plx_window (void) {
+ // fix up the PLX-mapped window base address to match the block
+ unsigned long blb;
+ u32 mapreg;
+ blb = virt_to_bus (&lb);
+ // the kernel stack had better not ever cross a 1Gb boundary!
+ mapreg = rd_plain (dev, &mem->stuff[10]);
+ mapreg &= ~onegigmask;
+ mapreg |= blb & onegigmask;
+ wr_plain (dev, &mem->stuff[10], mapreg);
+ return;
+ }
- /* enable adapter doorbell */
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- | AMB_DOORBELL_BITS);
+ u32 version;
if (amb_reset (dev, 1)) {
PRINTK (KERN_ERR, "card reset failed!");
- } else if (get_loader_version (dev, &version)) {
- PRINTK (KERN_INFO, "failed to get loader version");
} else {
- PRINTK (KERN_INFO, "loader version is %08x", version);
+ fixup_plx_window ();
- if (ucode_init (dev)) {
- PRINTK (KERN_ERR, "microcode failure");
- } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {
- PRINTK (KERN_ERR, "failed to get memory for queues");
+ if (get_loader_version (&lb, dev, &version)) {
+ PRINTK (KERN_INFO, "failed to get loader version");
} else {
+ PRINTK (KERN_INFO, "loader version is %08x", version);
- if (amb_talk (dev)) {
- PRINTK (KERN_ERR, "adapter did not accept queues");
+ if (ucode_init (&lb, dev)) {
+ PRINTK (KERN_ERR, "microcode failure");
+ } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {
+ PRINTK (KERN_ERR, "failed to get memory for queues");
} else {
- amb_ucode_version (dev);
- return 0;
- } /* amb_talk */
+ if (amb_talk (dev)) {
+ PRINTK (KERN_ERR, "adapter did not accept queues");
+ } else {
+
+ amb_ucode_version (dev);
+ return 0;
+
+ } /* amb_talk */
+
+ destroy_queues (dev);
+ } /* create_queues, ucode_init */
- destroy_queues (dev);
- } /* create_queues, ucode_init */
+ amb_reset (dev, 0);
+ } /* get_loader_version */
- } /* get_loader_version, amb_reset */
+ } /* amb_reset */
return -1;
}
@@ -2303,81 +2365,57 @@ static int __init amb_probe (void) {
amb_dev * dev;
// read resources from PCI configuration space
- u32 * membase = bus_to_virt
- (pci_dev->resource[0].start);
- u32 iobase = pci_dev->resource[1].start;
u8 irq = pci_dev->irq;
+ u32 * membase = bus_to_virt (pci_dev->resource[0].start);
+ u32 iobase = pci_dev->resource[1].start;
- // check IO region
- if (check_region (iobase, AMB_EXTENT)) {
- PRINTK (KERN_ERR, "IO range already in use!");
- return;
- }
-
- dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
- if (!dev) {
- // perhaps we should be nice: deregister all adapters and abort?
- PRINTK (KERN_ERR, "out of memory!");
- return;
- }
- memset (dev, 0, sizeof(amb_dev));
-
- // set up known dev items straight away
- dev->pci_dev = pci_dev;
-
- dev->iobase = iobase;
- dev->irq = irq;
- dev->membase = membase;
-
- // flags (currently only dead)
- dev->flags = 0;
-
- // Allocate cell rates (fibre)
- // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
- // to be really pedantic, this should be ATM_OC3c_PCR
- dev->tx_avail = ATM_OC3_PCR;
- dev->rx_avail = ATM_OC3_PCR;
-
-#if 0
- // initialise bottom half
- dev->bh.next = 0;
- dev->bh.sync = 0;
- dev->bh.routine = (void (*)(void *)) fill_rx_pools;
- dev->bh.data = dev;
-#endif
-
- // semaphore for txer/rxer modifications - we cannot use a
- // spinlock as the critical region needs to switch processes
- init_MUTEX (&dev->vcc_sf);
- // queue manipulation spinlocks; we want atomic reads and
- // writes to the queue descriptors (handles IRQ and SMP)
- // consider replacing "int pending" -> "atomic_t available"
- // => problem related to who gets to move queue pointers
- spin_lock_init (&dev->cq.lock);
- spin_lock_init (&dev->txq.lock);
- {
+ void setup_dev (void) {
unsigned char pool;
+ memset (dev, 0, sizeof(amb_dev));
+
+ // set up known dev items straight away
+ dev->pci_dev = pci_dev;
+
+ dev->iobase = iobase;
+ dev->irq = irq;
+ dev->membase = membase;
+
+ // flags (currently only dead)
+ dev->flags = 0;
+
+ // Allocate cell rates (fibre)
+ // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
+ // to be really pedantic, this should be ATM_OC3c_PCR
+ dev->tx_avail = ATM_OC3_PCR;
+ dev->rx_avail = ATM_OC3_PCR;
+
+#ifdef FILL_RX_POOLS_IN_BH
+ // initialise bottom half
+ dev->bh.next = 0;
+ dev->bh.sync = 0;
+ dev->bh.routine = (void (*)(void *)) fill_rx_pools;
+ dev->bh.data = dev;
+#endif
+
+ // semaphore for txer/rxer modifications - we cannot use a
+ // spinlock as the critical region needs to switch processes
+ init_MUTEX (&dev->vcc_sf);
+ // queue manipulation spinlocks; we want atomic reads and
+ // writes to the queue descriptors (handles IRQ and SMP)
+ // consider replacing "int pending" -> "atomic_t available"
+ // => problem related to who gets to move queue pointers
+ spin_lock_init (&dev->cq.lock);
+ spin_lock_init (&dev->txq.lock);
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
spin_lock_init (&dev->rxq[pool].lock);
}
- // grab (but share) IRQ and install handler
- if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
- PRINTK (KERN_ERR, "request IRQ failed!");
- // free_irq is at "endif"
- } else {
-
+ void setup_pci_dev (void) {
unsigned char lat;
- // reserve IO region
- request_region (iobase, AMB_EXTENT, DEV_LABEL);
-
- PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at IO %x, IRQ %u, MEM %p",
- iobase, irq, membase);
-
// enable bus master accesses
pci_set_master (pci_dev);
-
+
// frobnicate latency (upwards, usually)
pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
if (pci_lat) {
@@ -2389,43 +2427,78 @@ static int __init amb_probe (void) {
"increasing", lat, MIN_PCI_LATENCY);
pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY);
}
+ }
+
+ PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
+ " IO %x, IRQ %u, MEM %p", iobase, irq, membase);
+
+ // check IO region
+ if (check_region (iobase, AMB_EXTENT)) {
+ PRINTK (KERN_ERR, "IO range already in use!");
+ return;
+ }
+
+ dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
+ if (!dev) {
+ // perhaps we should be nice: deregister all adapters and abort?
+ PRINTK (KERN_ERR, "out of memory!");
+ return;
+ }
+
+ setup_dev();
+
+ if (amb_init (dev)) {
+ PRINTK (KERN_ERR, "adapter initialisation failure");
+ } else {
+
+ setup_pci_dev();
- if (amb_init (dev)) {
- PRINTK (KERN_ERR, "adapter initialisation failure");
- } else if (!(dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, 0))) {
- PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ // grab (but share) IRQ and install handler
+ if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
+ PRINTK (KERN_ERR, "request IRQ failed!");
+ // free_irq is at "endif"
} else {
- PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
- dev->atm_dev->number, dev, dev->atm_dev);
- dev->atm_dev->dev_data = (void *) dev;
+ // reserve IO region
+ request_region (iobase, AMB_EXTENT, DEV_LABEL);
- // register our address
- amb_esi (dev, dev->atm_dev->esi);
-
- // 0 bits for vpi, 10 bits for vci
- dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
- dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
-
- fill_rx_pools (dev);
-
- /* enable host interrupts */
- interrupts_on (dev);
-
- // update count and linked list
- ++devs;
- dev->prev = amb_devs;
- amb_devs = dev;
- // success
- return;
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
+ if (!dev->atm_dev) {
+ PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ } else {
+
+ PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
+ dev->atm_dev->number, dev, dev->atm_dev);
+ dev->atm_dev->dev_data = (void *) dev;
+
+ // register our address
+ amb_esi (dev, dev->atm_dev->esi);
+
+ // 0 bits for vpi, 10 bits for vci
+ dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
+ dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
+
+ // update count and linked list
+ ++devs;
+ dev->prev = amb_devs;
+ amb_devs = dev;
+
+ // enable host interrupts
+ interrupts_on (dev);
+
+ // success
+ return;
+
+ // not currently reached
+ atm_dev_deregister (dev->atm_dev);
+ } /* atm_dev_register */
- // not currently reached
- atm_dev_deregister (dev->atm_dev);
- } /* atm_dev_register, amb_init */
+ release_region (iobase, AMB_EXTENT);
+ free_irq (irq, dev);
+ } /* request_region, request_irq */
- release_region (iobase, AMB_EXTENT);
- free_irq (irq, dev);
- } /* request_region, request_irq */
+ amb_reset (dev, 0);
+ } /* amb_init */
kfree (dev);
} /* kmalloc, end-of-fn */
@@ -2529,7 +2602,6 @@ int init_module (void) {
show_version();
- // check arguments
amb_check_args();
// get the juice
@@ -2566,8 +2638,8 @@ void cleanup_module (void) {
PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
// the drain should not be necessary
drain_rx_pools (dev);
- amb_reset (dev, 0);
interrupts_off (dev);
+ amb_reset (dev, 0);
destroy_queues (dev);
atm_dev_deregister (dev->atm_dev);
free_irq (dev->irq, dev);
@@ -2594,7 +2666,6 @@ int __init amb_detect (void) {
show_version();
- // check arguments
amb_check_args();
// get the juice
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index 93e458644..11ce866da 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -237,8 +237,6 @@
#define FP_155_RATE 0x24b1
#define FP_25_RATE 0x1f9d
-#define AMB_RESET 0x40
-
/* #define VERSION_NUMBER 0x01000000 // initial release */
/* #define VERSION_NUMBER 0x01010000 // fixed startup probs PLX MB0 not cleared */
/* #define VERSION_NUMBER 0x01020000 // changed SUNI reset timings; allowed r/w onchip */
@@ -333,9 +331,10 @@ typedef struct {
u32 reset_control;
} amb_mem;
-/* IRQ (card to host) and doorbell (host to card) enable bits */
-#define AMB_INTERRUPT_BITS 0x00030000
-#define AMB_DOORBELL_BITS 0x00000300
+/* RESET bit, IRQ (card to host) and doorbell (host to card) enable bits */
+#define AMB_RESET_BITS 0x40000000
+#define AMB_INTERRUPT_BITS 0x00000300
+#define AMB_DOORBELL_BITS 0x00030000
/* loader commands */
@@ -543,14 +542,19 @@ typedef enum {
( (current)+1 < (limit) ? (current)+1 : (start) )
typedef struct {
- spinlock_t lock;
- unsigned int pending;
- unsigned int high;
- unsigned int maximum; // size - 1 (q implementation)
command * start;
command * in;
command * out;
command * limit;
+} amb_cq_ptrs;
+
+typedef struct {
+ spinlock_t lock;
+ unsigned int pending;
+ unsigned int high;
+ unsigned int filled;
+ unsigned int maximum; // size - 1 (q implementation)
+ amb_cq_ptrs ptrs;
} amb_cq;
typedef struct {
diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c
index 357cbdbe0..443831a82 100644
--- a/drivers/atm/atmdev_init.c
+++ b/drivers/atm/atmdev_init.c
@@ -39,7 +39,7 @@ int __init atmdev_init(void)
devs = 0;
#ifdef CONFIG_ATM_ENI
- devs += eni_detect();
+// devs += eni_detect();
#endif
#ifdef CONFIG_ATM_ZATM
devs += zatm_detect();
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index cc13eb06f..64c25420e 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -7,7 +7,9 @@
#include <linux/wait.h>
#include <linux/atmdev.h>
#include <linux/atm_tcp.h>
+#include <linux/bitops.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */
@@ -36,12 +38,14 @@ struct atmtcp_dev_data {
static int atmtcp_send_control(struct atm_vcc *vcc,int type,
- const struct atmtcp_control *msg,unsigned short flag)
+ const struct atmtcp_control *msg,int flag)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *out_vcc;
struct sk_buff *skb;
struct atmtcp_control *new_msg;
- unsigned short old_flags;
+ int old_test;
+ int error = 0;
out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
if (!out_vcc) return -EUNATCH;
@@ -60,16 +64,21 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type,
new_msg->type = type;
memset(&new_msg->vcc,0,sizeof(atm_kptr_t));
*(struct atm_vcc **) &new_msg->vcc = vcc;
- old_flags = vcc->flags;
+ old_test = test_bit(flag,&vcc->flags);
out_vcc->push(out_vcc,skb);
- while (!((vcc->flags ^ old_flags) & flag)) {
+ add_wait_queue(&vcc->sleep,&wait);
+ while (test_bit(flag,&vcc->flags) == old_test) {
mb();
out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
- if (!out_vcc) return -EUNATCH;
- sleep_on(&vcc->sleep);
-
+ if (!out_vcc) {
+ error = -EUNATCH;
+ break;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
}
- return 0;
+ remove_wait_queue(&vcc->sleep,&wait);
+ return error;
}
@@ -83,10 +92,10 @@ static int atmtcp_recv_control(const struct atmtcp_control *msg)
vcc->reply = msg->result;
switch (msg->type) {
case ATMTCP_CTRL_OPEN:
- vcc->flags ^= ATM_VF_READY;
+ change_bit(ATM_VF_READY,&vcc->flags);
break;
case ATMTCP_CTRL_CLOSE:
- vcc->flags ^= ATM_VF_ADDR;
+ change_bit(ATM_VF_ADDR,&vcc->flags);
break;
default:
printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n",
@@ -120,8 +129,8 @@ static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci)
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0;
msg.type = ATMTCP_CTRL_OPEN;
msg.qos = vcc->qos;
- vcc->flags |= ATM_VF_ADDR;
- vcc->flags &= ~ATM_VF_READY; /* just in case ... */
+ set_bit(ATM_VF_ADDR,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */
error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY);
if (error) return error;
return vcc->reply;
@@ -136,7 +145,7 @@ static void atmtcp_v_close(struct atm_vcc *vcc)
msg.addr.sap_family = AF_ATMPVC;
msg.addr.sap_addr.vpi = vcc->vpi;
msg.addr.sap_addr.vci = vcc->vci;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
(void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR);
}
@@ -168,13 +177,18 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
struct atmtcp_hdr *hdr;
int size;
+ if (vcc->qos.txtp.traffic_class == ATM_NONE) {
+ if (vcc->pop) vcc->pop(vcc,skb);
+ else dev_kfree_skb(skb);
+ return -EINVAL;
+ }
dev_data = PRIV(vcc->dev);
if (dev_data) out_vcc = dev_data->vcc;
if (!dev_data || !out_vcc) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
if (dev_data) return 0;
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
return -ENOLINK;
}
size = skb->len+sizeof(struct atmtcp_hdr);
@@ -182,7 +196,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (!new_skb) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
return -ENOBUFS;
}
hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr));
@@ -193,8 +207,8 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
out_vcc->push(out_vcc,new_skb);
- vcc->stats->tx++;
- out_vcc->stats->rx++;
+ atomic_inc(&vcc->stats->tx);
+ atomic_inc(&out_vcc->stats->rx);
return 0;
}
@@ -251,7 +265,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
out_vcc->qos.rxtp.traffic_class != ATM_NONE)
break;
if (!out_vcc) {
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
goto done;
}
skb_pull(skb,sizeof(struct atmtcp_hdr));
@@ -263,8 +277,8 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
new_skb->stamp = xtime;
memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
out_vcc->push(out_vcc,new_skb);
- vcc->stats->tx++;
- out_vcc->stats->rx++;
+ atomic_inc(&vcc->stats->tx);
+ atomic_inc(&out_vcc->stats->rx);
done:
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
@@ -305,7 +319,7 @@ static struct atm_dev atmtcp_control_dev = {
999, /* dummy device number */
NULL,NULL, /* pretend not to have any VCCs */
NULL,NULL, /* no data */
- 0, /* no flags */
+ { 0 }, /* no flags */
NULL, /* no local address */
{ 0 } /* no ESI, no statistics */
};
@@ -318,7 +332,7 @@ static int atmtcp_create(int itf,int persist,struct atm_dev **result)
dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
if (!dev_data) return -ENOMEM;
- dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,0);
+ dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
if (!dev) {
kfree(dev_data);
return itf == -1 ? -ENOMEM : -EBUSY;
@@ -352,7 +366,8 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf)
}
PRIV(dev)->vcc = vcc;
bind_vcc(vcc,&atmtcp_control_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
vcc->dev_data = dev;
(void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */
vcc->stats = &atmtcp_control_dev.stats.aal5;
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 081fcdfed..b3240d498 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -19,8 +19,10 @@
#include <linux/uio.h>
#include <linux/init.h>
#include <linux/atm_eni.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -526,7 +528,7 @@ static int rx_aal0(struct atm_vcc *vcc)
DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n",
vcc->dev->number);
length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
length = ATM_CELL_SIZE-1; /* no HEC */
@@ -581,7 +583,7 @@ static int rx_aal5(struct atm_vcc *vcc)
size);
}
eff = length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);
@@ -598,7 +600,7 @@ static int rx_aal5(struct atm_vcc *vcc)
"(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n",
vcc->dev->number,vcc->vci,length,size << 2,descr);
length = eff = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
}
skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL;
@@ -663,6 +665,7 @@ static void poll_rx(struct atm_dev *dev)
if (rx_vcc(curr)) return;
eni_dev->fast = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
while ((curr = eni_dev->slow)) {
@@ -670,6 +673,7 @@ static void poll_rx(struct atm_dev *dev)
if (rx_vcc(curr)) return;
eni_dev->slow = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
}
@@ -768,7 +772,7 @@ rx_dequeued++;
vcc->push(vcc,skb);
pushed++;
}
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
wake_up(&eni_dev->rx_wait);
}
@@ -836,10 +840,10 @@ static int open_rx_second(struct atm_vcc *vcc)
static void close_rx(struct atm_vcc *vcc)
{
- unsigned long here,flags;
+ DECLARE_WAITQUEUE(wait,current);
+ unsigned long here;
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
- u32 tmp;
eni_vcc = ENI_VCC(vcc);
if (!eni_vcc->rx) return;
@@ -858,25 +862,41 @@ static void close_rx(struct atm_vcc *vcc)
/* wait for RX queue to drain */
DPRINTK("eni_close: waiting for RX ...\n");
EVENT("RX closing\n",0,0);
- save_flags(flags);
- cli();
- while (eni_vcc->rxing || eni_vcc->servicing) {
+ add_wait_queue(&eni_dev->rx_wait,&wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ barrier();
+ for (;;) {
+ /* transition service->rx: rxing++, servicing-- */
+ if (!eni_vcc->servicing) {
+ barrier();
+ if (!eni_vcc->rxing) break;
+ }
EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing,
eni_vcc->servicing);
printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing,
eni_vcc->rxing);
- sleep_on(&eni_dev->rx_wait);
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
}
- while (eni_vcc->rx_pos != (tmp =
- readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ)>>
- MID_VCI_READ_SHIFT) {
+ for (;;) {
+ unsigned long flags;
+ int at_end;
+ u32 tmp;
+
+ spin_lock_irqsave(&eni_dev->lock,flags);
+ tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ;
+ at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT;
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
+ if (at_end) break;
EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",
eni_vcc->rx_pos,tmp);
printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n",
eni_vcc->rx_pos,tmp);
- sleep_on(&eni_dev->rx_wait);
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
}
- restore_flags(flags);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&eni_dev->rx_wait,&wait);
}
eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2);
eni_vcc->rx = NULL;
@@ -1054,8 +1074,9 @@ static enum enq_res do_tx(struct sk_buff *skb)
* 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-)
*/
+ aal5 = vcc->qos.aal == ATM_AAL5;
/* check space in buffer */
- if (!(aal5 = vcc->qos.aal == ATM_AAL5))
+ if (!aal5)
size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE;
/* cell without HEC plus segmentation header (includes
four-byte cell header) */
@@ -1207,7 +1228,7 @@ static void dequeue_tx(struct atm_dev *dev)
PCI_DMA_TODEVICE);
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb_irq(skb);
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&eni_dev->tx_wait);
dma_complete++;
}
@@ -1366,34 +1387,40 @@ static int open_tx_second(struct atm_vcc *vcc)
static void close_tx(struct atm_vcc *vcc)
{
+ DECLARE_WAITQUEUE(wait,current);
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
- unsigned long flags;
eni_vcc = ENI_VCC(vcc);
if (!eni_vcc->tx) return;
eni_dev = ENI_DEV(vcc->dev);
/* wait for TX queue to drain */
DPRINTK("eni_close: waiting for TX ...\n");
- save_flags(flags);
- cli();
- while (skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing) {
+ add_wait_queue(&eni_dev->tx_wait,&wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ for (;;) {
+ unsigned long flags;
+ int txing;
+
+ spin_lock_irqsave(&eni_dev->lock,flags);
+ txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing;
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
+ if (!txing) break;
DPRINTK("%d TX left\n",eni_vcc->txing);
- sleep_on(&eni_dev->tx_wait);
- }
- /*
- * Looping a few times in here is probably far cheaper than keeping
- * track of TX completions all the time, so let's poll a bit ...
- */
- while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
- eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
schedule();
- restore_flags(flags);
-#if 0
- if (skb_peek(&eni_vcc->tx->backlog))
- printk(KERN_CRIT DEV_LABEL "SKBs in BACKLOG !!!\n");
-#endif
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&eni_dev->tx_wait,&wait);
if (eni_vcc->tx != eni_dev->ubr) {
+ /*
+ * Looping a few times in here is probably far cheaper than
+ * keeping track of TX completions all the time, so let's poll
+ * a bit ...
+ */
+ while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
+ eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
+ schedule();
eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2);
eni_vcc->tx->send = 0;
eni_dev->tx_bw += eni_vcc->tx->reserved;
@@ -1496,28 +1523,36 @@ static void eni_int(int irq,void *dev_id,struct pt_regs *regs)
if (reason & MID_RX_DMA_COMPLETE) {
EVENT("INT: RX DMA complete, starting dequeue_rx\n",
0,0);
+ spin_lock(&eni_dev->lock);
dequeue_rx(dev);
EVENT("dequeue_rx done, starting poll_rx\n",0,0);
poll_rx(dev);
+ spin_unlock(&eni_dev->lock);
EVENT("poll_rx done\n",0,0);
/* poll_tx ? */
}
if (reason & MID_SERVICE) {
EVENT("INT: service, starting get_service\n",0,0);
+ spin_lock(&eni_dev->lock);
get_service(dev);
EVENT("get_service done, starting poll_rx\n",0,0);
poll_rx(dev);
+ spin_unlock(&eni_dev->lock);
EVENT("poll_rx done\n",0,0);
}
if (reason & MID_TX_DMA_COMPLETE) {
EVENT("INT: TX DMA COMPLETE\n",0,0);
+ spin_lock(&eni_dev->lock);
dequeue_tx(dev);
+ spin_unlock(&eni_dev->lock);
}
if (reason & MID_TX_COMPLETE) {
EVENT("INT: TX COMPLETE\n",0,0);
tx_complete++;
- wake_up(&eni_dev->tx_wait);
+ spin_lock(&eni_dev->lock);
poll_tx(dev);
+ spin_unlock(&eni_dev->lock);
+ wake_up(&eni_dev->tx_wait);
/* poll_rx ? */
}
if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK |
@@ -1532,7 +1567,7 @@ tx_complete++;
/*--------------------------------- entries ---------------------------------*/
-static const char *media_name[] __initdata = {
+static const char *media_name[] __devinitdata = {
"MMF", "SMF", "MMF", "03?", /* 0- 3 */
"UTP", "05?", "06?", "07?", /* 4- 7 */
"TAXI","09?", "10?", "11?", /* 8-11 */
@@ -1556,7 +1591,7 @@ static const char *media_name[] __initdata = {
} })
-static int __init get_esi_asic(struct atm_dev *dev)
+static int __devinit get_esi_asic(struct atm_dev *dev)
{
struct eni_dev *eni_dev;
unsigned char tonga;
@@ -1648,7 +1683,7 @@ static int __init get_esi_asic(struct atm_dev *dev)
#undef GET_SEPROM
-static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base)
+static int __devinit get_esi_fpga(struct atm_dev *dev,unsigned long base)
{
unsigned long mac_base;
int i;
@@ -1659,7 +1694,7 @@ static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base)
}
-static int __init eni_init(struct atm_dev *dev)
+static int __devinit eni_do_init(struct atm_dev *dev)
{
struct midway_eprom *eprom;
struct eni_dev *eni_dev;
@@ -1748,7 +1783,7 @@ static int __init eni_init(struct atm_dev *dev)
}
-static int __init eni_start(struct atm_dev *dev)
+static int __devinit eni_start(struct atm_dev *dev)
{
struct eni_dev *eni_dev;
unsigned long buf,buffer_mem;
@@ -1788,6 +1823,7 @@ static int __init eni_start(struct atm_dev *dev)
DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n",
eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,
eni_dev->service,buf);
+ spin_lock_init(&eni_dev->lock);
/* initialize memory management */
buffer_mem = eni_dev->mem-(buf-eni_dev->ram);
eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
@@ -1830,14 +1866,14 @@ static void eni_close(struct atm_vcc *vcc)
{
DPRINTK(">eni_close\n");
if (!ENI_VCC(vcc)) return;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
close_rx(vcc);
close_tx(vcc);
DPRINTK("eni_close: done waiting\n");
/* deallocate memory */
kfree(ENI_VCC(vcc));
ENI_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
/*foo();*/
}
@@ -1855,8 +1891,8 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
for (walk = vcc->dev->vccs; walk;
walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) &&
- walk->vci == *vci &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags)
+ && walk->vci == *vci &&
walk->qos.txtp.traffic_class !=
ATM_NONE)
break;
@@ -1872,7 +1908,7 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
return -EADDRINUSE;
if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
for (walk = vcc->dev->vccs; walk; walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) && walk->vci == *vci &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
walk->qos.txtp.traffic_class != ATM_NONE)
return -EADDRINUSE;
return 0;
@@ -1887,19 +1923,19 @@ static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
DPRINTK(">eni_open\n");
EVENT("eni_open\n",0,0);
- if (!(vcc->flags & ATM_VF_PARTIAL)) ENI_VCC(vcc) = NULL;
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL;
eni_dev = ENI_DEV(vcc->dev);
error = get_ci(vcc,&vpi,&vci);
if (error) return error;
vcc->vpi = vpi;
vcc->vci = vci;
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5)
return -EINVAL;
DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,
vcc->vci);
- if (!(vcc->flags & ATM_VF_PARTIAL)) {
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL);
if (!eni_vcc) return -ENOMEM;
ENI_VCC(vcc) = eni_vcc;
@@ -1922,7 +1958,7 @@ static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
eni_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
/* should power down SUNI while !ref_count @@@ */
return 0;
}
@@ -1953,8 +1989,7 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs)
* Walk through the send buffer and patch the rate information in all
* segmentation buffer descriptors of this VCC.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eni_dev->lock,flags);
for (skb = eni_dev->tx_queue.next; skb !=
(struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) {
unsigned long dsc;
@@ -1965,7 +2000,7 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs)
(tx->prescaler << MID_SEG_PR_SHIFT) |
(tx->resolution << MID_SEG_RATE_SHIFT), dsc);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
return 0;
}
@@ -2049,14 +2084,13 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
}
submitted++;
ATM_SKB(skb)->vcc = vcc;
- save_flags(flags);
- cli(); /* brute force */
+ spin_lock_irqsave(&ENI_DEV(vcc->dev)->lock,flags); /* brute force */
if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) {
skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);
ENI_VCC(vcc)->tx->backlog_len++;
backlogged++;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags);
return 0;
}
@@ -2206,79 +2240,86 @@ static const struct atmdev_ops ops = {
};
-int __init eni_detect(void)
+static int __devinit eni_init_one(struct pci_dev *pci_dev,
+ const struct pci_device_id *ent)
{
struct atm_dev *dev;
struct eni_dev *eni_dev;
- int devs,type;
- struct sk_buff *skb;
+ int error = -ENOMEM;
- DPRINTK("eni_detect\n");
- if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
- printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
- sizeof(skb->cb),sizeof(struct eni_skb_prv));
- return 0;
- }
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),
- GFP_KERNEL);
+ DPRINTK("eni_init_one\n");
+ eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL);
if (!eni_dev) return -ENOMEM;
- devs = 0;
- for (type = 0; type < 2; type++) {
- struct pci_dev *pci_dev;
-
- pci_dev = NULL;
- while ((pci_dev = pci_find_device(PCI_VENDOR_ID_EF,type ?
- PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA,
- pci_dev))) {
- if (!devs) {
- cpu_zeroes = pci_alloc_consistent(pci_dev,
- ENI_ZEROES_SIZE,&zeroes);
- if (!cpu_zeroes) {
- kfree(eni_dev);
- return -ENOMEM;
- }
- }
- dev = atm_dev_register(DEV_LABEL,&ops,-1,0);
- if (!dev) break;
- eni_dev->pci_dev = pci_dev;
- ENI_DEV(dev) = eni_dev;
- eni_dev->asic = type;
- if (eni_init(dev) || eni_start(dev)) {
- atm_dev_deregister(dev);
- break;
- }
- eni_dev->more = eni_boards;
- eni_boards = dev;
- devs++;
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct
- eni_dev),GFP_KERNEL);
- if (!eni_dev) break;
- }
- }
- if (!devs && cpu_zeroes) {
- pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,
- cpu_zeroes,zeroes);
- cpu_zeroes = NULL;
- }
+ if (!cpu_zeroes) {
+ cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE,
+ &zeroes);
+ if (!cpu_zeroes) goto out1;
+ }
+ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
+ if (!dev) goto out2;
+ pci_dev->driver_data = dev;
+ eni_dev->pci_dev = pci_dev;
+ ENI_DEV(dev) = eni_dev;
+ eni_dev->asic = ent->driver_data;
+ error = eni_do_init(dev);
+ if (error) goto out3;
+ error = eni_start(dev);
+ if (error) goto out3;
+ eni_dev->more = eni_boards;
+ eni_boards = dev;
+ MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */
+ return 0;
+out3:
+ atm_dev_deregister(dev);
+out2:
+ pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,cpu_zeroes,zeroes);
+ cpu_zeroes = NULL;
+out1:
kfree(eni_dev);
- return devs;
+ return error;
}
-#ifdef MODULE
+static struct pci_device_id eni_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 0 /* FPGA */ },
+ { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 1 /* ASIC */ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci,eni_pci_tbl);
+
-int init_module(void)
+static void __devexit eni_remove_one(struct pci_dev *pci_dev)
{
- if (!eni_detect()) {
- printk(KERN_ERR DEV_LABEL ": no adapter found\n");
- return -ENXIO;
+ /* grrr */
+}
+
+
+static struct pci_driver eni_driver = {
+ name: DEV_LABEL,
+ id_table: eni_pci_tbl,
+ probe: eni_init_one,
+ remove: eni_remove_one,
+};
+
+
+static int __init eni_init(void)
+{
+ struct sk_buff *skb; /* dummy for sizeof */
+
+ if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
+ printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
+ sizeof(skb->cb),sizeof(struct eni_skb_prv));
+ return -EIO;
}
- MOD_INC_USE_COUNT;
- return 0;
+ if (pci_register_driver(&eni_driver) > 0) return 0;
+ pci_unregister_driver (&eni_driver);
+ return -ENODEV;
}
-void cleanup_module(void)
+static void __exit eni_cleanup(void)
{
/*
* Well, there's no way to get rid of the driver yet, so we don't
@@ -2286,4 +2327,6 @@ void cleanup_module(void)
*/
}
-#endif
+
+module_init(eni_init);
+module_exit(eni_cleanup);
diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h
index 76d0dd482..23ba60fb1 100644
--- a/drivers/atm/eni.h
+++ b/drivers/atm/eni.h
@@ -12,6 +12,7 @@
#include <linux/skbuff.h>
#include <linux/time.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include "midway.h"
@@ -65,6 +66,8 @@ struct eni_vcc {
};
struct eni_dev {
+ /*-------------------------------- spinlock */
+ spinlock_t lock; /* sync with interrupt */
/*-------------------------------- base pointers into Midway address
space */
unsigned long phy; /* PHY interface chip registers */
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 4c07f2e7f..96c022842 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -1,5 +1,5 @@
/*
- $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $
+ $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $
A FORE Systems 200E-series driver for ATM on Linux.
Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000.
@@ -35,6 +35,7 @@
#include <linux/atmdev.h>
#include <linux/sonet.h>
#include <linux/atm_suni.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/segment.h>
@@ -43,6 +44,7 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#ifdef CONFIG_ATM_FORE200E_PCA
#include <linux/pci.h>
@@ -67,7 +69,7 @@
#define FORE200E_52BYTE_AAL0_SDU
#endif
-#define FORE200E_VERSION "0.2a"
+#define FORE200E_VERSION "0.2b"
#define FORE200E "fore200e: "
@@ -187,10 +189,10 @@ fore200e_kfree(void* chunk)
/* allocate and align a chunk of memory intended to hold the data behing exchanged
- between the driver and the adapter (using streaming DVMA on SBUS hosts) */
+ between the driver and the adapter (using streaming DVMA) */
static int
-fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment)
+fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction)
{
unsigned long offset = 0;
@@ -199,6 +201,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->alloc_size = size + alignment;
chunk->align_size = size;
+ chunk->direction = direction;
chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
if (chunk->alloc_addr == NULL)
@@ -209,7 +212,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->align_addr = chunk->alloc_addr + offset;
- chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size);
+ chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction);
return 0;
}
@@ -220,7 +223,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
static void
fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{
- fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
+ fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction);
fore200e_kfree(chunk->alloc_addr);
}
@@ -463,34 +466,32 @@ static void fore200e_pca_write(u32 val, volatile u32* addr)
static u32
-fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL);
+ u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction);
- DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n",
- virt_addr, size, dma_addr);
+ DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
return dma_addr;
}
static void
-fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
- PCI_DMA_BIDIRECTIONAL);
+ pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
static void
-fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
- PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
@@ -511,10 +512,8 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int
chunk->align_addr = chunk->alloc_addr;
#else
- if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0)
+ if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0)
return -ENOMEM;
-
- chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size);
#endif
return 0;
@@ -532,8 +531,6 @@ fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
chunk->alloc_addr,
chunk->dma_addr);
#else
- fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
-
fore200e_chunk_free(fore200e, chunk);
#endif
}
@@ -685,7 +682,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
opcode.opcode = OPCODE_GET_PROM;
opcode.pad = 0;
- prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data));
+ prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE);
fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr);
@@ -697,7 +694,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data));
+ fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name);
@@ -748,31 +745,32 @@ fore200e_sba_write(u32 val, volatile u32* addr)
static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size);
+ u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
- DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr);
+ DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
return dma_addr;
}
static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction);
- sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+ sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
static void
-fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+ sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
@@ -1002,7 +1000,8 @@ fore200e_irq_tx(struct fore200e* fore200e)
kfree(entry->data);
/* remove DMA mapping */
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ FORE200E_DMA_TODEVICE);
/* notify tx completion */
if (entry->vcc->pop)
@@ -1012,9 +1011,9 @@ fore200e_irq_tx(struct fore200e* fore200e)
/* check error condition */
if (*entry->status & STATUS_ERROR)
- entry->vcc->stats->tx_err++;
+ atomic_inc(&entry->vcc->stats->tx_err);
else
- entry->vcc->stats->tx++;
+ atomic_inc(&entry->vcc->stats->tx);
*entry->status = STATUS_FREE;
@@ -1127,7 +1126,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
if (skb == NULL) {
printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return;
}
@@ -1146,7 +1145,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
/* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length);
+ fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE);
memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length);
}
@@ -1169,7 +1168,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
}
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
@@ -1404,7 +1403,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
return 0;
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
vcc->itf = vcc->dev->number;
DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
@@ -1467,7 +1466,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536;
fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0;
- vcc->flags |= ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
@@ -1552,11 +1551,14 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if(--retry > 0)
goto retry_here;
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
fore200e->name, fore200e->cp_queues->heartbeat);
-
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
return -EIO;
}
}
@@ -1584,6 +1586,10 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (entry->data == NULL) {
spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
return -ENOMEM;
}
@@ -1591,11 +1597,11 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (skb_len < tx_len)
memset(entry->data + skb_len, 0x00, tx_len - skb_len);
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len);
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE);
}
else {
entry->data = NULL;
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len);
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE);
}
tpd->tsd[ 0 ].length = tx_len;
@@ -1606,7 +1612,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
spin_unlock_irqrestore(&fore200e->tx_lock, flags);
/* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE);
DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n",
vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
@@ -1661,27 +1667,29 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10);
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ FORE200E_DMA_TODEVICE);
- if (ok == 0) {
- printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
-
- entry->vcc->stats->tx_err++;
- return -EIO;
- }
- entry->vcc->stats->tx++;
-
- DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
-
/* free tmp copy of misaligned data */
if (entry->data)
kfree(entry->data);
-
+
/* notify tx completion */
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
+
+ if (ok == 0) {
+ printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
+
+ atomic_inc(&entry->vcc->stats->tx_err);
+ return -EIO;
+ }
+ atomic_inc(&entry->vcc->stats->tx);
+
+ DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
+
}
#endif
@@ -1704,7 +1712,7 @@ fore200e_getstats(struct fore200e* fore200e)
return -ENOMEM;
}
- stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats));
+ stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1721,7 +1729,7 @@ fore200e_getstats(struct fore200e* fore200e)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats));
+ fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get statistics from device %s\n", fore200e->name);
@@ -1766,7 +1774,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
int ok;
u32 oc3_regs_dma_addr;
- oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs));
+ oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1785,7 +1793,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
*entry->status = STATUS_FREE;
- fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs));
+ fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name);
@@ -1842,16 +1850,16 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode)
switch (loop_mode) {
- case SUNI_LM_NONE:
+ case ATM_LM_NONE:
mct_value = 0;
mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE;
break;
- case SUNI_LM_DIAG:
+ case ATM_LM_LOC_PHY:
mct_value = mct_mask = SUNI_MCT_DLE;
break;
- case SUNI_LM_LOOP:
+ case ATM_LM_RMT_PHY:
mct_value = mct_mask = SUNI_MCT_LLE;
break;
@@ -1921,12 +1929,16 @@ fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg)
case SONET_GETDIAG:
return put_user(0, (int*)arg) ? -EFAULT : 0;
-
- case SUNI_SETLOOP:
+
+ case ATM_SETLOOP:
return fore200e_setloop(fore200e, (int)(unsigned long)arg);
- case SUNI_GETLOOP:
+ case ATM_GETLOOP:
return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0;
+
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ?
+ -EFAULT : 0;
}
return -ENOSYS; /* not implemented */
@@ -1967,7 +1979,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
/* update rate control parameters */
fore200e_rate_ctrl(qos, &fore200e_vcc->rate);
- vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&vcc->flags);
return 0;
}
@@ -2051,7 +2063,8 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
/* allocate the receive buffer body */
if (fore200e_chunk_alloc(fore200e,
- &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) {
+ &buffer[ i ].data, size, fore200e->bus->buffer_alignment,
+ FORE200E_DMA_FROMDEVICE) < 0) {
while (i > 0)
fore200e_chunk_free(fore200e, &buffer[ --i ].data);
@@ -2485,7 +2498,8 @@ fore200e_register(struct fore200e* fore200e)
DPRINTK(2, "device %s being registered\n", fore200e->name);
- atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0);
+ atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1,
+ NULL);
if (atm_dev == NULL) {
printk(FORE200E "unable to register device %s\n", fore200e->name);
return -ENODEV;
@@ -2690,17 +2704,29 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
static const char* oc3_mode[] = {
"normal operation",
"diagnostic loopback",
- "line loopback"
+ "line loopback",
+ "unknown"
};
u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release);
u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release);
u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision);
u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
+ u32 oc3_index;
if (media_index < 0 || media_index > 4)
media_index = 5;
+ switch(fore200e->loop_mode) {
+ case ATM_LM_NONE: oc3_index = 0;
+ break;
+ case ATM_LM_LOC_PHY: oc3_index = 1;
+ break;
+ case ATM_LM_RMT_PHY: oc3_index = 2;
+ break;
+ default: oc3_index = 3;
+ }
+
return sprintf(page,
" firmware release:\t\t%d.%d.%d\n"
" monitor release:\t\t%d.%d\n"
@@ -2711,7 +2737,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
mon960_release >> 16, mon960_release << 16 >> 16,
media_name[ media_index ],
oc3_revision,
- oc3_mode[ fore200e->loop_mode ]);
+ oc3_mode[ oc3_index ]);
}
if (!left--) {
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index eea20162b..f29fbde97 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -2,6 +2,7 @@
#define _FORE200E_H
#ifdef __KERNEL__
+#include <linux/config.h>
/* rx buffer sizes */
@@ -559,6 +560,7 @@ typedef struct chunk {
void* alloc_addr; /* base address of allocated chunk */
void* align_addr; /* base address of aligned chunk */
u32 dma_addr; /* DMA address of aligned chunk */
+ int direction; /* direction of DMA mapping */
u32 alloc_size; /* length of allocated chunk */
u32 align_size; /* length of aligned chunk */
} chunk_t;
@@ -796,9 +798,9 @@ typedef struct fore200e_bus {
const unsigned int* fw_size; /* address of firmware data size */
u32 (*read)(volatile u32*);
void (*write)(u32, volatile u32*);
- u32 (*dma_map)(struct fore200e*, void*, int);
- void (*dma_unmap)(struct fore200e*, u32, int);
- void (*dma_sync)(struct fore200e*, u32, int);
+ u32 (*dma_map)(struct fore200e*, void*, int, int);
+ void (*dma_unmap)(struct fore200e*, u32, int, int);
+ void (*dma_sync)(struct fore200e*, u32, int, int);
int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
void (*dma_chunk_free)(struct fore200e*, struct chunk*);
struct fore200e* (*detect)(const struct fore200e_bus*, int);
@@ -814,6 +816,31 @@ typedef struct fore200e_bus {
} fore200e_bus_t;
+#if defined(CONFIG_ATM_FORE200E_SBA)
+# if defined(CONFIG_ATM_FORE200E_PCA)
+# if (PCI_DMA_BIDIRECTIONAL == SBUS_DMA_BIDIRECTIONAL) && \
+ (PCI_DMA_TODEVICE == SBUS_DMA_TODEVICE) && \
+ (PCI_DMA_FROMDEVICE == SBUS_DMA_FROMDEVICE)
+# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE
+# else
+ /* in that case, we'll need to add an extra indirection, e.g.
+ fore200e->bus->dma_direction[ fore200e_dma_direction ] */
+# error PCI and SBUS DMA direction flags differ!
+# endif
+# else
+# define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE SBA_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE SBA_DMA_FROMDEVICE
+# endif
+#else
+# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE
+#endif
+
+
/* per-device data */
typedef struct fore200e {
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 0a412667e..f0dff7011 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -42,6 +42,7 @@
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -50,7 +51,7 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Horizon [Ultra] driver"
-#define version_string "1.2"
+#define version_string "1.2.1"
static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
@@ -246,7 +247,7 @@ static inline void __init show_version (void) {
Atomic test and set tx_busy until we succeed; we should implement
some sort of timeout so that tx_busy will never be stuck at true.
- If no TX channel is setup for this VC we wait for an idle one (if
+ If no TX channel is set up for this VC we wait for an idle one (if
necessary) and set it up.
At this point we have a TX channel ready for use. We wait for enough
@@ -276,7 +277,7 @@ static inline void __init show_version (void) {
available handler is locked out over the same period.
Data available on the card triggers an interrupt. If the data is not
- suitable for out existing RX channels or we cannot allocate a buffer
+ suitable for our existing RX channels or we cannot allocate a buffer
it is flushed. Otherwise an RX receive is scheduled. Multiple RX
transfers may be scheduled for the same frame.
@@ -321,7 +322,7 @@ static inline void __init show_version (void) {
and the frame continues to be received.
The solution is to make sure any received frames are flushed when
- ready. This is currently done just before the solution to 3.
+ ready. This is currently done just before the solution to 2.
4. PCI bus (original Horizon only, fixed in Ultra)
@@ -608,7 +609,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r,
u32 pre;
// local fn to build the timer bits
- inline int set_cr (void) {
+ int set_cr (void) {
// paranoia
if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) {
PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u",
@@ -813,7 +814,7 @@ static inline void hrz_kfree_skb (struct sk_buff * skb) {
if (ATM_SKB(skb)->vcc->pop) {
ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
} else {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
}
@@ -961,12 +962,11 @@ static void hrz_close_rx (hrz_dev * dev, u16 vc) {
static void rx_schedule (hrz_dev * dev, int irq) {
unsigned int rx_bytes;
- int pio_instead;
+ int pio_instead = 0;
#ifndef TAILRECURSIONWORKS
- do {
+ pio_instead = 1;
+ while (pio_instead) {
#endif
- pio_instead = 0;
-
// bytes waiting for RX transfer
rx_bytes = dev->rx_bytes;
@@ -1047,7 +1047,7 @@ static void rx_schedule (hrz_dev * dev, int irq) {
{
struct atm_vcc * vcc = ATM_SKB(skb)->vcc;
// VC layer stats
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
skb->stamp = xtime;
// end of our responsability
vcc->push (vcc, skb);
@@ -1078,12 +1078,12 @@ static void rx_schedule (hrz_dev * dev, int irq) {
#ifdef TAILRECURSIONWORKS
// and we all bless optimised tail calls
if (pio_instead)
- rx_schedule (dev, 0);
+ return rx_schedule (dev, 0);
return;
#else
// grrrrrrr!
irq = 0;
- } while (pio_instead);
+ }
return;
#endif
}
@@ -1130,11 +1130,11 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
int append_desc = 0;
- int pio_instead;
+ int pio_instead = 0;
#ifndef TAILRECURSIONWORKS
- do {
+ pio_instead = 1;
+ while (pio_instead) {
#endif
- pio_instead = 0;
// bytes in current region waiting for TX transfer
tx_bytes = dev->tx_bytes;
@@ -1201,7 +1201,7 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
dev->tx_iovec = 0;
// VC layer stats
- ATM_SKB(skb)->vcc->stats->tx++;
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
// free the skb
hrz_kfree_skb (skb);
@@ -1236,12 +1236,12 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
#ifdef TAILRECURSIONWORKS
// and we all bless optimised tail calls
if (pio_instead)
- tx_schedule (dev, 0);
+ return tx_schedule (dev, 0);
return;
#else
// grrrrrrr!
irq = 0;
- } while (pio_instead);
+ }
return;
#endif
}
@@ -1340,37 +1340,33 @@ static inline void rx_data_av_handler (hrz_dev * dev) {
if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) {
if (rx_len <= atm_vcc->qos.rxtp.max_sdu) {
- struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC);
-
- // If everyone has to call atm_pdu2... why isn't it part of
- // atm_charge? B'cos some people already have skb->truesize!
- // WA: well. even if they think they do, they might not ... :-)
-
- if (skb) {
- // remember this so we can push it later
- dev->rx_skb = skb;
- // remember this so we can flush it later
- dev->rx_channel = rx_channel;
-
- // prepare socket buffer
- skb_put (skb, rx_len);
- ATM_SKB(skb)->vcc = atm_vcc;
-
- // simple transfer
- // dev->rx_regions = 0;
- // dev->rx_iovec = 0;
- dev->rx_bytes = rx_len;
- dev->rx_addr = skb->data;
- PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)",
- skb->data, rx_len);
-
- // do the business
- rx_schedule (dev, 0);
- return;
-
- } else {
- PRINTD (DBG_INFO, "failed to get skb");
- }
+
+ struct sk_buff * skb = atm_alloc_charge (atm_vcc, rx_len, GFP_ATOMIC);
+ if (skb) {
+ // remember this so we can push it later
+ dev->rx_skb = skb;
+ // remember this so we can flush it later
+ dev->rx_channel = rx_channel;
+
+ // prepare socket buffer
+ skb_put (skb, rx_len);
+ ATM_SKB(skb)->vcc = atm_vcc;
+
+ // simple transfer
+ // dev->rx_regions = 0;
+ // dev->rx_iovec = 0;
+ dev->rx_bytes = rx_len;
+ dev->rx_addr = skb->data;
+ PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)",
+ skb->data, rx_len);
+
+ // do the business
+ rx_schedule (dev, 0);
+ return;
+
+ } else {
+ PRINTD (DBG_SKB|DBG_WARN, "failed to get skb");
+ }
} else {
PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel);
@@ -1662,6 +1658,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
if (!channel) {
PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel");
+ hrz_kfree_skb (skb);
return -EIO;
}
@@ -1699,9 +1696,11 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
#endif
// wait until TX is free and grab lock
- if (tx_hold (dev))
+ if (tx_hold (dev)) {
+ hrz_kfree_skb (skb);
return -ERESTARTSYS;
-
+ }
+
// Wait for enough space to be available in transmit buffer memory.
// should be number of cells needed + 2 (according to hardware docs)
@@ -1722,6 +1721,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d",
free_buffers, buffers_required);
tx_release (dev);
+ hrz_kfree_skb (skb);
return -ERESTARTSYS;
}
}
@@ -1820,12 +1820,12 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
u32 ctrl = rd_regl (dev, CONTROL_0_REG);
- inline void WRITE_IT_WAIT (void) {
+ void WRITE_IT_WAIT (void) {
wr_regl (dev, CONTROL_0_REG, ctrl);
udelay (5);
}
- inline void CLOCK_IT (void) {
+ void CLOCK_IT (void) {
// DI must be valid around rising SK edge
ctrl &= ~SEEPROM_SK;
WRITE_IT_WAIT();
@@ -2530,7 +2530,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
// this is "immediately before allocating the connection identifier
// in hardware" - so long as the next call does not fail :)
- atm_vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&atm_vcc->flags);
// any errors here are very serious and should never occur
@@ -2554,7 +2554,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
atm_vcc->dev_data = (void *) vccp;
// indicate readiness
- atm_vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&atm_vcc->flags);
MOD_INC_USE_COUNT;
return 0;
@@ -2569,7 +2569,7 @@ static void hrz_close (struct atm_vcc * atm_vcc) {
PRINTD (DBG_VCC|DBG_FLOW, "hrz_close");
// indicate unreadiness
- atm_vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&atm_vcc->flags);
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
unsigned int i;
@@ -2611,7 +2611,7 @@ static void hrz_close (struct atm_vcc * atm_vcc) {
// free our structure
kfree (vcc);
// say the VPI/VCI is free again
- atm_vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
MOD_DEC_USE_COUNT;
}
@@ -2758,13 +2758,13 @@ static int __init hrz_probe (void) {
devs = 0;
pci_dev = NULL;
while ((pci_dev = pci_find_device
- (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev)
- )) {
+ (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev)
+ )) {
hrz_dev * dev;
// adapter slot free, read resources from PCI configuration space
u32 iobase = pci_dev->resource[0].start;
- u32 * membase = bus_to_virt(pci_dev->resource[1].start);
+ u32 * membase = bus_to_virt (pci_dev->resource[1].start);
u8 irq = pci_dev->irq;
// check IO region
@@ -2795,7 +2795,7 @@ static int __init hrz_probe (void) {
PRINTD (DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p",
iobase, irq, membase);
- dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0);
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, NULL);
if (!(dev->atm_dev)) {
PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
} else {
diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h
index be5e5c726..6655bdc1c 100644
--- a/drivers/atm/horizon.h
+++ b/drivers/atm/horizon.h
@@ -31,10 +31,8 @@
#define DRIVER_ATM_HORIZON_H
#include <linux/config.h>
-
#include <linux/version.h>
-
#ifdef CONFIG_ATM_HORIZON_DEBUG
#define DEBUG_HORIZON
#endif
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 3d305858a..31503ed1e 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -157,36 +157,54 @@ static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ int diag;
+
+ diag = GET(DIAG) & ~IDT77105_DIAG_LCMASK;
+ switch (mode) {
+ case ATM_LM_NONE:
+ break;
+ case ATM_LM_LOC_ATM:
+ diag |= IDT77105_DIAG_LC_PHY_LOOPBACK;
+ break;
+ case ATM_LM_RMT_ATM:
+ diag |= IDT77105_DIAG_LC_LINE_LOOPBACK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(diag,DIAG);
+ printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", dev->type,
+ dev->number,
+ (mode == ATM_LM_NONE ? "NONE" :
+ (mode == ATM_LM_LOC_ATM ? "DIAG (local)" :
+ (mode == IDT77105_DIAG_LC_LINE_LOOPBACK ? "LOOP (remote)" :
+ "unknown")))
+ );
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number);
switch (cmd) {
case IDT77105_GETSTATZ:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ /* fall through */
case IDT77105_GETSTAT:
return fetch_stats(dev,(struct idt77105_stats *) arg,
cmd == IDT77105_GETSTATZ);
- case IDT77105_SETLOOP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if ((int) arg < 0 || (int) arg > IDT77105_LM_LOOP)
- return -EINVAL;
- PUT((GET(DIAG) & ~IDT77105_DIAG_LCMASK) |
- ((int) arg == IDT77105_LM_NONE ? IDT77105_DIAG_LC_NORMAL : 0) |
- ((int) arg == IDT77105_LM_DIAG ? IDT77105_DIAG_LC_PHY_LOOPBACK : 0) |
- ((int) arg == IDT77105_LM_LOOP ? IDT77105_DIAG_LC_LINE_LOOPBACK : 0),
- DIAG);
- printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n",
- dev->type, dev->number,
- ((int) arg == IDT77105_LM_NONE ? "NONE" :
- ((int) arg == IDT77105_LM_DIAG ? "DIAG (local)" :
- ((int) arg == IDT77105_LM_LOOP ? "LOOP (remote)" :
- "unknown")))
- );
- PRIV(dev)->loop_mode = (int) arg;
- return 0;
- case IDT77105_GETLOOP:
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
- -EFAULT : sizeof(int);
+ -EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM,
+ (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
@@ -266,13 +284,13 @@ static int idt77105_start(struct atm_dev *dev)
/* initialise loop mode from hardware */
switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) {
case IDT77105_DIAG_LC_NORMAL:
- PRIV(dev)->loop_mode = IDT77105_LM_NONE;
+ PRIV(dev)->loop_mode = ATM_LM_NONE;
break;
case IDT77105_DIAG_LC_PHY_LOOPBACK:
- PRIV(dev)->loop_mode = IDT77105_LM_DIAG;
+ PRIV(dev)->loop_mode = ATM_LM_LOC_ATM;
break;
case IDT77105_DIAG_LC_LINE_LOOPBACK:
- PRIV(dev)->loop_mode = IDT77105_LM_LOOP;
+ PRIV(dev)->loop_mode = ATM_LM_RMT_ATM;
break;
}
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 84bdda6d6..cd1714a53 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -59,6 +59,7 @@
#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -68,7 +69,7 @@
#include "suni.h"
#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
struct suni_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
+ struct k_sonet_stats sonet_stats; /* link diagnostics */
unsigned char loop_mode; /* loopback mode */
struct atm_dev *dev; /* device back-pointer */
struct suni_priv *next; /* next SUNI */
@@ -625,12 +626,12 @@ static int ia_que_tx (IADEV *iadev) {
num_desc = ia_avail_descs(iadev);
while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) {
if (!(vcc = ATM_SKB(skb)->vcc)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
printk("ia_que_tx: Null vcc\n");
break;
}
- if ((vcc->flags & ATM_VF_READY) == 0 ) {
- dev_kfree_skb(skb);
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ dev_kfree_skb_any(skb);
printk("Free the SKB on closed vci %d \n", vcc->vci);
break;
}
@@ -658,14 +659,14 @@ void ia_tx_poll (IADEV *iadev) {
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("ia_tx_poll: vcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
iavcc = INPH_IA_VCC(vcc);
if (!iavcc) {
printk("ia_tx_poll: iavcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
@@ -682,7 +683,7 @@ void ia_tx_poll (IADEV *iadev) {
(long)skb1);)
}
else
- dev_kfree_skb(skb1);
+ dev_kfree_skb_any(skb1);
skb1 = skb_dequeue(&iavcc->txing_skb);
}
if (!skb1) {
@@ -696,7 +697,7 @@ void ia_tx_poll (IADEV *iadev) {
IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);)
}
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
kfree(rtne);
}
ia_que_tx(iadev);
@@ -1128,7 +1129,7 @@ static int rx_pkt(struct atm_dev *dev)
status = (u_short) (buf_desc_ptr->desc_mode);
if (status & (RX_CER | RX_PTE | RX_OFL))
{
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
IF_ERR(printk("IA: bad packet, dropping it");)
if (status & RX_CER) {
IF_ERR(printk(" cause: packet CRC error\n");)
@@ -1152,7 +1153,7 @@ static int rx_pkt(struct atm_dev *dev)
len = dma_addr - buf_addr;
if (len > iadev->rx_buf_sz) {
printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
free_desc(dev, desc);
return 0;
}
@@ -1166,7 +1167,7 @@ static int rx_pkt(struct atm_dev *dev)
if (!skb)
{
IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");)
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
atm_return(vcc, atm_pdu2truesize(len));
free_desc(dev, desc);
return 0;
@@ -1297,7 +1298,7 @@ static void rx_dle_intr(struct atm_dev *dev)
if (!skb->len)
{
printk("rx_dle_intr: skb len 0\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
else
{
@@ -1308,15 +1309,15 @@ static void rx_dle_intr(struct atm_dev *dev)
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("IA: null vcc\n");
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
goto INCR_DLE;
}
ia_vcc = INPH_IA_VCC(vcc);
if (ia_vcc == NULL)
{
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
#if LINUX_VERSION_CODE >= 0x20312
atm_return(vcc, atm_guess_pdu2truesize(skb->len));
#else
@@ -1331,8 +1332,8 @@ static void rx_dle_intr(struct atm_dev *dev)
if ((length > iadev->rx_buf_sz) || (length >
(skb->len - sizeof(struct cpcs_trailer))))
{
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)",
length, skb->len);)
#if LINUX_VERSION_CODE >= 0x20312
@@ -1351,7 +1352,7 @@ static void rx_dle_intr(struct atm_dev *dev)
IF_RX(printk("rx_dle_intr: skb push");)
vcc->push(vcc,skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
iadev->rx_pkt_cnt++;
}
INCR_DLE:
@@ -1710,13 +1711,13 @@ static void tx_dle_intr(struct atm_dev *dev)
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("tx_dle_intr: vcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
iavcc = INPH_IA_VCC(vcc);
if (!iavcc) {
printk("tx_dle_intr: iavcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
if (vcc->qos.txtp.pcr >= iadev->rate_limit) {
@@ -1725,7 +1726,7 @@ static void tx_dle_intr(struct atm_dev *dev)
vcc->pop(vcc, skb);
}
else {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
else { /* Hold the rate-limited skb for flow control */
@@ -2601,7 +2602,7 @@ static void ia_close(struct atm_vcc *vcc)
IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n",
ia_vcc->vc_desc_cnt,vcc->vci);)
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
skb_queue_head_init (&tmp_tx_backlog);
skb_queue_head_init (&tmp_vcc_backlog);
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
@@ -2611,7 +2612,7 @@ static void ia_close(struct atm_vcc *vcc)
while((skb = skb_dequeue(&iadev->tx_backlog))) {
if (ATM_SKB(skb)->vcc == vcc){
if (vcc->pop) vcc->pop(vcc, skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
}
else
skb_queue_tail(&tmp_tx_backlog, skb);
@@ -2669,7 +2670,7 @@ static void ia_close(struct atm_vcc *vcc)
kfree(INPH_IA_VCC(vcc));
ia_vcc = NULL;
INPH_IA_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return;
}
@@ -2678,7 +2679,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
IADEV *iadev;
struct ia_vcc *ia_vcc;
int error;
- if (!(vcc->flags & ATM_VF_PARTIAL))
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
{
IF_EVENT(printk("ia: not partially allocated resources\n");)
INPH_IA_VCC(vcc) = NULL;
@@ -2695,7 +2696,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
{
IF_EVENT(printk("iphase open: unspec part\n");)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
}
if (vcc->qos.aal != ATM_AAL5)
return -EINVAL;
@@ -2721,7 +2722,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
#ifndef MODULE
{
@@ -2749,7 +2750,7 @@ static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags)
static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
{
- PIA_CMDBUF ia_cmds;
+ IA_CMDBUF ia_cmds;
IADEV *iadev;
int i, board;
u16 *tmps;
@@ -2757,34 +2758,37 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
if (cmd != IA_CMD) {
if (!dev->phy->ioctl) return -EINVAL;
return dev->phy->ioctl(dev,cmd,arg);
- }
- ia_cmds = (PIA_CMDBUF)arg;
- board = ia_cmds->status;
+ }
+ if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT;
+ board = ia_cmds.status;
if ((board < 0) || (board > iadev_count))
board = 0;
iadev = ia_dev[board];
- switch (ia_cmds->cmd) {
+ switch (ia_cmds.cmd) {
case MEMDUMP:
{
- switch (ia_cmds->sub_cmd) {
+ switch (ia_cmds.sub_cmd) {
case MEMDUMP_DEV:
- memcpy((char*)ia_cmds->buf, (char*)iadev,
- sizeof(IADEV));
- ia_cmds->status = 0;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (copy_to_user(ia_cmds.buf, iadev, sizeof(IADEV)))
+ return -EFAULT;
+ ia_cmds.status = 0;
break;
case MEMDUMP_SEGREG:
- tmps = (u16 *)ia_cmds->buf;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ tmps = (u16 *)ia_cmds.buf;
for(i=0; i<0x80; i+=2, tmps++)
- *tmps = *(u16*)(iadev->seg_reg+i);
- ia_cmds->status = 0;
- ia_cmds->len = 0x80;
+ if(put_user(*(u16*)(iadev->seg_reg+i), tmps)) return -EFAULT;
+ ia_cmds.status = 0;
+ ia_cmds.len = 0x80;
break;
case MEMDUMP_REASSREG:
- tmps = (u16 *)ia_cmds->buf;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ tmps = (u16 *)ia_cmds.buf;
for(i=0; i<0x80; i+=2, tmps++)
- *tmps = *(u16*)(iadev->reass_reg+i);
- ia_cmds->status = 0;
- ia_cmds->len = 0x80;
+ if(put_user(*(u16*)(iadev->reass_reg+i), tmps)) return -EFAULT;
+ ia_cmds.status = 0;
+ ia_cmds.len = 0x80;
break;
case MEMDUMP_FFL:
{
@@ -2792,6 +2796,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
ffredn_t *ffL = &regs_local.ffredn;
rfredn_t *rfL = &regs_local.rfredn;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
/* Copy real rfred registers into the local copy */
for (i=0; i<(sizeof (rfredn_t))/4; i++)
((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff;
@@ -2799,63 +2804,67 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
for (i=0; i<(sizeof (ffredn_t))/4; i++)
((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff;
- memcpy((char*)ia_cmds->buf,(char*)&regs_local,sizeof(ia_regs_t));
+ if (copy_to_user(ia_cmds.buf, &regs_local,sizeof(ia_regs_t)))
+ return -EFAULT;
printk("Board %d registers dumped\n", board);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
}
break;
case READ_REG:
{
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
desc_dbg(iadev);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
}
break;
case 0x6:
{
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
printk("skb = 0x%lx\n", (long)skb_peek(&iadev->tx_backlog));
printk("rtn_q: 0x%lx\n",(long)ia_deque_rtn_q(&iadev->tx_return_q));
}
break;
case 0x8:
{
- struct sonet_stats *stats;
+ struct k_sonet_stats *stats;
stats = &PRIV(_ia_dev[board])->sonet_stats;
- printk("section_bip: %d\n", stats->section_bip);
- printk("line_bip : %d\n", stats->line_bip);
- printk("path_bip : %d\n", stats->path_bip);
- printk("line_febe : %d\n", stats->line_febe);
- printk("path_febe : %d\n", stats->path_febe);
- printk("corr_hcs : %d\n", stats->corr_hcs);
- printk("uncorr_hcs : %d\n", stats->uncorr_hcs);
- printk("tx_cells : %d\n", stats->tx_cells);
- printk("rx_cells : %d\n", stats->rx_cells);
+ printk("section_bip: %d\n", atomic_read(&stats->section_bip));
+ printk("line_bip : %d\n", atomic_read(&stats->line_bip));
+ printk("path_bip : %d\n", atomic_read(&stats->path_bip));
+ printk("line_febe : %d\n", atomic_read(&stats->line_febe));
+ printk("path_febe : %d\n", atomic_read(&stats->path_febe));
+ printk("corr_hcs : %d\n", atomic_read(&stats->corr_hcs));
+ printk("uncorr_hcs : %d\n", atomic_read(&stats->uncorr_hcs));
+ printk("tx_cells : %d\n", atomic_read(&stats->tx_cells));
+ printk("rx_cells : %d\n", atomic_read(&stats->rx_cells));
}
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
case 0x9:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
for (i = 1; i <= iadev->num_rx_desc; i++)
free_desc(_ia_dev[board], i);
writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD),
iadev->reass_reg+REASS_MASK_REG);
iadev->rxing = 1;
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
case 0xb:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
IaFrontEndIntr(iadev);
break;
case 0xa:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
{
- ia_cmds->status = 0;
- IADebugFlag = ia_cmds->maddr;
+ ia_cmds.status = 0;
+ IADebugFlag = ia_cmds.maddr;
printk("New debug option loaded\n");
}
break;
default:
- memcpy((char*)ia_cmds->buf, (char*)ia_cmds->maddr, ia_cmds->len);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
}
}
@@ -2896,7 +2905,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (!iavcc->txing) {
printk("discard packet on closed VC\n");
if (vcc->pop) vcc->pop(vcc, skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
}
if (skb->len > iadev->tx_buf_sz - 8) {
@@ -2904,7 +2913,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
if ((u32)skb->data & 3) {
@@ -2912,7 +2921,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
/* Get a descriptor number from our free descriptor queue
@@ -2929,11 +2938,11 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if ((desc == 0) || (desc > iadev->num_tx_desc))
{
IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);)
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0; /* return SUCCESS */
}
@@ -3038,14 +3047,14 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
ATM_DESC(skb) = vcc->vci;
skb_queue_tail(&iadev->tx_dma_q, skb);
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
iadev->tx_pkt_cnt++;
/* Increment transaction counter */
writel(2, iadev->dma+IPHASE5575_TX_COUNTER);
#if 0
/* add flow control logic */
- if (vcc->stats->tx % 20 == 0) {
+ if (atomic_read(&vcc->stats->tx) % 20 == 0) {
if (iavcc->vc_desc_cnt > 10) {
vcc->tx_quota = vcc->tx_quota * 3 / 4;
printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota );
@@ -3074,12 +3083,12 @@ static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
if (!skb)
printk(KERN_CRIT "null skb in ia_send\n");
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
return -EINVAL;
}
spin_lock_irqsave(&iadev->tx_lock, flags);
- if ((vcc->flags & ATM_VF_READY) == 0){
- dev_kfree_skb(skb);
+ if (!test_bit(ATM_VF_READY,&vcc->flags)){
+ dev_kfree_skb_any(skb);
spin_unlock_irqrestore(&iadev->tx_lock, flags);
return -EINVAL;
}
@@ -3197,7 +3206,7 @@ __initfunc(int ia_detect(void))
IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn),
PCI_FUNC(iadev->pci->devfn));)
- dev = atm_dev_register(DEV_LABEL, &ops, -1, 0);
+ dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
if (!dev) break;
IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n",
dev->number);)
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 3e4930fdd..767fd75fb 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -37,8 +37,10 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "nicstar.h"
#include "nicstarmac.h"
#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
@@ -284,7 +286,7 @@ void cleanup_module(void)
card = cards[i];
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == IDT_25_PCR) {
+ if (card->max_pcr == ATM_25_PCR) {
idt77105_stop(card->atmdev);
}
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
@@ -311,7 +313,7 @@ void cleanup_module(void)
PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
{
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
j++;
}
PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
@@ -319,14 +321,14 @@ void cleanup_module(void)
PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
{
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
j++;
}
PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- kfree_skb(lb);
+ dev_kfree_skb_any(lb);
while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- kfree_skb(sb);
+ dev_kfree_skb_any(sb);
free_scq(card->scq0, NULL);
for (j = 0; j < NS_FRSCD_NUM; j++)
{
@@ -547,7 +549,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
switch(data) {
case 0x00000009:
printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
- card->max_pcr = IDT_25_PCR;
+ card->max_pcr = ATM_25_PCR;
while(CMD_BUSY(card));
writel(0x00000008, card->membase + DR0);
writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
@@ -857,7 +859,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
card->efbie = 1;
/* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL);
+ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
if (card->atmdev == NULL)
{
printk("nicstar%d: can't register device.\n", i);
@@ -891,7 +893,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == IDT_25_PCR) {
+ if (card->max_pcr == ATM_25_PCR) {
idt77105_init(card->atmdev);
/* Note that for the IDT77105 PHY we don't need the awful
* module count hack that the SUNI needs because we can
@@ -936,26 +938,26 @@ static void ns_init_card_error(ns_dev *card, int error)
{
struct sk_buff *iovb;
while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
if (error >= 15)
{
struct sk_buff *sb;
while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- kfree_skb(sb);
+ dev_kfree_skb_any(sb);
free_scq(card->scq0, NULL);
}
if (error >= 14)
{
struct sk_buff *lb;
while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- kfree_skb(lb);
+ dev_kfree_skb_any(lb);
}
if (error >= 13)
{
struct sk_buff *hb;
while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
if (error >= 12)
{
@@ -1039,7 +1041,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
else /* vcc must be != NULL */
@@ -1048,7 +1050,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
{
printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
for (i = 0; i < scq->num_entries; i++)
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
else
for (i = 0; i < scq->num_entries; i++)
@@ -1058,7 +1060,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
}
@@ -1130,9 +1132,9 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
if (card->sbfqc >= card->sbnr.max)
{
skb_unlink((struct sk_buff *) handle1);
- kfree_skb((struct sk_buff *) handle1);
+ dev_kfree_skb_any((struct sk_buff *) handle1);
skb_unlink((struct sk_buff *) handle2);
- kfree_skb((struct sk_buff *) handle2);
+ dev_kfree_skb_any((struct sk_buff *) handle2);
return;
}
else
@@ -1143,9 +1145,9 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
if (card->lbfqc >= card->lbnr.max)
{
skb_unlink((struct sk_buff *) handle1);
- kfree_skb((struct sk_buff *) handle1);
+ dev_kfree_skb_any((struct sk_buff *) handle1);
skb_unlink((struct sk_buff *) handle2);
- kfree_skb((struct sk_buff *) handle2);
+ dev_kfree_skb_any((struct sk_buff *) handle2);
return;
}
else
@@ -1420,16 +1422,16 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
return -EINVAL;
}
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
/* NOTE: You are not allowed to modify an open connection's QOS. To change
that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
needed to do that. */
- if (!(vcc->flags & ATM_VF_PARTIAL))
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
{
scq_info *scq;
- vcc->flags |= ATM_VF_PARTIAL;
+ set_bit(ATM_VF_PARTIAL,&vcc->flags);
if (vcc->qos.txtp.traffic_class == ATM_CBR)
{
/* Check requested cell rate and availability of SCD */
@@ -1438,7 +1440,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
{
PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
@@ -1461,7 +1464,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
{
PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
}
@@ -1469,14 +1473,16 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
if (n == 0)
{
printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
if (n > (card->tst_free_entries - NS_TST_RESERVED))
{
PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
else
@@ -1495,7 +1501,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
{
PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
card->tst_free_entries += n;
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EBUSY;
}
@@ -1507,7 +1514,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
card->scd2vc[frscdi] = NULL;
card->tst_free_entries += n;
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -ENOMEM;
}
vc->scq = scq;
@@ -1553,7 +1561,7 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
MOD_INC_USE_COUNT;
return 0;
}
@@ -1572,7 +1580,7 @@ static void ns_close(struct atm_vcc *vcc)
PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
(int) vcc->vpi, vcc->vci);
- vcc->flags &= ~(ATM_VF_READY);
+ clear_bit(ATM_VF_READY,&vcc->flags);
if (vcc->qos.rxtp.traffic_class != ATM_NONE)
{
@@ -1681,7 +1689,8 @@ static void ns_close(struct atm_vcc *vcc)
}
vcc->dev_data = NULL;
- vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
MOD_DEC_USE_COUNT;
#ifdef RX_DEBUG
@@ -1778,32 +1787,32 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
if ((vc = (vc_map *) vcc->dev_data) == NULL)
{
printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (!vc->tx)
{
printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
{
printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (ATM_SKB(skb)->iovcnt != 0)
{
printk("nicstar%d: No scatter-gather yet.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
@@ -1847,11 +1856,11 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (push_scqe(card, vc, scq, &scqe, skb) != 0)
{
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EIO;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
return 0;
}
@@ -2071,7 +2080,7 @@ static void drain_scq(ns_dev *card, scq_info *scq, int pos)
if (vcc->pop != NULL)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
scq->skb[i] = NULL;
}
if (++i == scq->num_entries)
@@ -2155,15 +2164,15 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
{
printk("nicstar%d: Can't allocate buffers for aal0.\n",
card->index);
- vcc->stats->rx_drop += i;
+ atomic_add(i,&vcc->stats->rx_drop);
break;
}
if (!atm_charge(vcc, sb->truesize))
{
RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
card->index);
- vcc->stats->rx_drop += i - 1; /* already increased by 1 */
- kfree_skb(sb);
+ atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */
+ dev_kfree_skb_any(sb);
break;
}
/* Rebuild the header */
@@ -2177,7 +2186,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
cell += ATM_CELL_PAYLOAD;
}
@@ -2196,7 +2205,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
if (iovb == NULL)
{
printk("nicstar%d: Out of iovec buffers.\n", card->index);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
recycle_rx_buf(card, skb);
return;
}
@@ -2223,7 +2232,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
{
printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
ATM_SKB(iovb)->iovcnt = 0;
iovb->len = 0;
@@ -2242,7 +2251,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk("nicstar%d: Expected a small buffer, and this is not one.\n",
card->index);
which_list(card, skb);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_rx_buf(card, skb);
vc->rx_iov = NULL;
recycle_iov_buf(card, iovb);
@@ -2256,7 +2265,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk("nicstar%d: Expected a large buffer, and this is not one.\n",
card->index);
which_list(card, skb);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2280,7 +2289,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk(" - PDU size mismatch.\n");
else
printk(".\n");
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2308,7 +2317,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
@@ -2335,7 +2344,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
push_rxbufs(card, BUF_LG, (u32) skb,
@@ -2361,7 +2370,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
@@ -2384,7 +2393,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
if (hb == NULL)
{
printk("nicstar%d: Out of huge buffers.\n", card->index);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2431,7 +2440,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
card->hbpool.count++;
}
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
else
{
@@ -2467,7 +2476,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
#endif /* NS_USE_DESTRUCTORS */
hb->stamp = xtime;
vcc->push(vcc, hb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
@@ -2556,7 +2565,7 @@ static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
@@ -2578,7 +2587,7 @@ static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
}
@@ -2593,7 +2602,7 @@ static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
card->iovpool.count++;
}
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
@@ -2700,7 +2709,7 @@ static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
/* Dump 25.6 Mbps PHY registers */
/* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
here just in case it's needed for debugging. */
- if (card->max_pcr == IDT_25_PCR && !left--)
+ if (card->max_pcr == ATM_25_PCR && !left--)
{
u32 phy_regs[4];
u32 i;
@@ -2787,7 +2796,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
return -EFAULT;
case NS_SETBUFLEV:
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl)))
return -EFAULT;
@@ -2836,7 +2845,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
return 0;
case NS_ADJBUFLEV:
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
btype = (int) arg; /* an int is the same size as a pointer */
switch (btype)
@@ -2882,7 +2891,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
printk("nicstar%d: huge buffer count inconsistent.\n",
card->index);
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
while (card->hbpool.count < card->hbnr.init)
@@ -2912,7 +2921,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
printk("nicstar%d: iovec buffer count inconsistent.\n",
card->index);
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
while (card->iovpool.count < card->iovnr.init)
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
index 61b89efe0..4e90650c0 100644
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -100,8 +100,6 @@
#define NS_IOREMAP_SIZE 4096
-#define IDT_25_PCR ((25600000 / 8 - 8000) / 54)
-
#define BUF_SM 0x00000000 /* These two are used for push_rxbufs() */
#define BUF_LG 0x00000001 /* CMD, Write_FreeBufQ, LBUF bit */
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index 7335bbb32..0de6e8ead 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -1,4 +1,4 @@
-/* drivers/atm/suni.c - PMC SUNI (PHY) driver */
+/* drivers/atm/suni.c - PMC PM5346 SUNI (PHY) driver */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
@@ -18,6 +18,7 @@
#include <asm/system.h>
#include <asm/param.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "suni.h"
@@ -30,8 +31,8 @@
struct suni_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
- unsigned char loop_mode; /* loopback mode */
+ struct k_sonet_stats sonet_stats; /* link diagnostics */
+ int loop_mode; /* loopback mode */
struct atm_dev *dev; /* device back-pointer */
struct suni_priv *next; /* next SUNI */
};
@@ -46,69 +47,62 @@ struct suni_priv {
static struct timer_list poll_timer;
-static int start_timer = 1;
static struct suni_priv *sunis = NULL;
+static spinlock_t sunis_lock = SPIN_LOCK_UNLOCKED;
-static void suni_hz(unsigned long dummy)
+#define ADD_LIMITED(s,v) \
+ atomic_add((v),&stats->s); \
+ if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX);
+
+
+static void suni_hz(unsigned long from_timer)
{
struct suni_priv *walk;
struct atm_dev *dev;
- struct sonet_stats *stats;
+ struct k_sonet_stats *stats;
for (walk = sunis; walk; walk = walk->next) {
dev = walk->dev;
stats = &walk->sonet_stats;
PUT(0,MRI); /* latch counters */
udelay(1);
- stats->section_bip += (GET(RSOP_SBL) & 0xff) |
- ((GET(RSOP_SBM) & 0xff) << 8);
- if (stats->section_bip < 0) stats->section_bip = LONG_MAX;
- stats->line_bip += (GET(RLOP_LBL) & 0xff) |
+ ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) |
+ ((GET(RSOP_SBM) & 0xff) << 8));
+ ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) |
((GET(RLOP_LB) & 0xff) << 8) |
- ((GET(RLOP_LBM) & 0xf) << 16);
- if (stats->line_bip < 0) stats->line_bip = LONG_MAX;
- stats->path_bip += (GET(RPOP_PBL) & 0xff) |
- ((GET(RPOP_PBM) & 0xff) << 8);
- if (stats->path_bip < 0) stats->path_bip = LONG_MAX;
- stats->line_febe += (GET(RLOP_LFL) & 0xff) |
+ ((GET(RLOP_LBM) & 0xf) << 16));
+ ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) |
+ ((GET(RPOP_PBM) & 0xff) << 8));
+ ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) |
((GET(RLOP_LF) & 0xff) << 8) |
- ((GET(RLOP_LFM) & 0xf) << 16);
- if (stats->line_febe < 0) stats->line_febe = LONG_MAX;
- stats->path_febe += (GET(RPOP_PFL) & 0xff) |
- ((GET(RPOP_PFM) & 0xff) << 8);
- if (stats->path_febe < 0) stats->path_febe = LONG_MAX;
- stats->corr_hcs += GET(RACP_CHEC) & 0xff;
- if (stats->corr_hcs < 0) stats->corr_hcs = LONG_MAX;
- stats->uncorr_hcs += GET(RACP_UHEC) & 0xff;
- if (stats->uncorr_hcs < 0) stats->uncorr_hcs = LONG_MAX;
- stats->rx_cells += (GET(RACP_RCCL) & 0xff) |
+ ((GET(RLOP_LFM) & 0xf) << 16));
+ ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) |
+ ((GET(RPOP_PFM) & 0xff) << 8));
+ ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff);
+ ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff);
+ ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) |
((GET(RACP_RCC) & 0xff) << 8) |
- ((GET(RACP_RCCM) & 7) << 16);
- if (stats->rx_cells < 0) stats->rx_cells = LONG_MAX;
- stats->tx_cells += (GET(TACP_TCCL) & 0xff) |
+ ((GET(RACP_RCCM) & 7) << 16));
+ ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) |
((GET(TACP_TCC) & 0xff) << 8) |
- ((GET(TACP_TCCM) & 7) << 16);
- if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX;
+ ((GET(TACP_TCCM) & 7) << 16));
}
- if (!start_timer) mod_timer(&poll_timer,jiffies+HZ);
+ if (from_timer) mod_timer(&poll_timer,jiffies+HZ);
}
+#undef ADD_LIMITED
+
+
static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
{
- unsigned long flags;
- int error;
-
- error = 0;
- save_flags(flags);
- cli();
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->sonet_stats,
- sizeof(struct sonet_stats));
- if (zero && !error)
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
- restore_flags(flags);
+ struct sonet_stats tmp;
+ int error = 0;
+
+ sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
+ if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
return error ? -EFAULT : 0;
}
@@ -158,6 +152,29 @@ static int get_diag(struct atm_dev *dev,void *arg)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ unsigned char control;
+
+ control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE);
+ switch (mode) {
+ case ATM_LM_NONE:
+ break;
+ case ATM_LM_LOC_PHY:
+ control |= SUNI_MCT_DLE;
+ break;
+ case ATM_LM_RMT_PHY:
+ control |= SUNI_MCT_LLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(control,MCT);
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
+
static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
switch (cmd) {
@@ -172,7 +189,6 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
case SONET_GETDIAG:
return get_diag(dev,arg);
case SONET_SETFRAMING:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
if (arg != SONET_FRAME_SONET) return -EINVAL;
return 0;
case SONET_GETFRAMING:
@@ -180,23 +196,14 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
-EFAULT : 0;
case SONET_GETFRSENSE:
return -EINVAL;
- case SUNI_SETLOOP:
- {
- int int_arg = (int) (long) arg;
-
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (int_arg < 0 || int_arg > SUNI_LM_LOOP)
- return -EINVAL;
- PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE))
- | (int_arg == SUNI_LM_DIAG ? SUNI_MCT_DLE :
- 0) | (int_arg == SUNI_LM_LOOP ?
- SUNI_MCT_LLE : 0),MCT);
- PRIV(dev)->loop_mode = int_arg;
- return 0;
- }
- case SUNI_GETLOOP:
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
-EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY,
+ (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
@@ -221,33 +228,31 @@ static void suni_int(struct atm_dev *dev)
static int suni_start(struct atm_dev *dev)
{
unsigned long flags;
+ int first;
if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
return -ENOMEM;
PRIV(dev)->dev = dev;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&sunis_lock,flags);
+ first = !sunis;
PRIV(dev)->next = sunis;
sunis = PRIV(dev);
- restore_flags(flags);
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
+ spin_unlock_irqrestore(&sunis_lock,flags);
+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
/* interrupt on loss of signal */
poll_los(dev); /* ... and clear SUNI interrupts */
if (dev->signal == ATM_PHY_SIG_LOST)
printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
dev->number);
- PRIV(dev)->loop_mode = SUNI_LM_NONE;
+ PRIV(dev)->loop_mode = ATM_LM_NONE;
suni_hz(0); /* clear SUNI counters */
(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
- cli();
- if (!start_timer) restore_flags(flags);
- else {
- start_timer = 0;
- restore_flags(flags);
+ if (first) {
init_timer(&poll_timer);
poll_timer.expires = jiffies+HZ;
poll_timer.function = suni_hz;
+ poll_timer.data = 1;
#if 0
printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
(unsigned long) poll_timer.next);
@@ -258,10 +263,28 @@ printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
}
+static int suni_stop(struct atm_dev *dev)
+{
+ struct suni_priv **walk;
+ unsigned long flags;
+
+ /* let SAR driver worry about stopping interrupts */
+ spin_lock_irqsave(&sunis_lock,flags);
+ for (walk = &sunis; *walk != PRIV(dev);
+ walk = &PRIV((*walk)->dev)->next);
+ *walk = PRIV((*walk)->dev)->next;
+ if (!sunis) del_timer_sync(&poll_timer);
+ spin_unlock_irqrestore(&sunis_lock,flags);
+ kfree(PRIV(dev));
+ return 0;
+}
+
+
static const struct atmphy_ops suni_ops = {
- suni_start,
- suni_ioctl,
- suni_int
+ start: suni_start,
+ ioctl: suni_ioctl,
+ interrupt: suni_int,
+ stop: suni_stop,
};
diff --git a/drivers/atm/suni.h b/drivers/atm/suni.h
index f72cdc7be..ae6d39abb 100644
--- a/drivers/atm/suni.h
+++ b/drivers/atm/suni.h
@@ -1,6 +1,6 @@
-/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */
+/* drivers/atm/suni.h - PMC PM5346 SUNI (PHY) declarations */
-/* Written 1995,1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef DRIVER_ATM_SUNI_H
diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c
index 36fd70b17..7c5f57579 100644
--- a/drivers/atm/uPD98402.c
+++ b/drivers/atm/uPD98402.c
@@ -11,6 +11,7 @@
#include <linux/sonet.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "uPD98402.h"
@@ -23,8 +24,9 @@
struct uPD98402_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
+ struct k_sonet_stats sonet_stats;/* link diagnostics */
unsigned char framing; /* SONET/SDH framing */
+ int loop_mode; /* loopback mode */
};
@@ -36,23 +38,18 @@ struct uPD98402_priv {
static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
{
- unsigned long flags;
- int error;
+ struct sonet_stats tmp;
+ int error = 0;
- error = 0;
- save_flags(flags);
- cli();
- PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT);
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->sonet_stats,
- sizeof(struct sonet_stats));
+ atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs);
+ sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
if (zero && !error) {
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
- PRIV(dev)->sonet_stats.corr_hcs = -1;
- PRIV(dev)->sonet_stats.tx_cells = -1;
- PRIV(dev)->sonet_stats.rx_cells = -1;
+ /* unused fields are reported as -1, but we must not "adjust"
+ them */
+ tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0;
+ sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
}
- restore_flags(flags);
return error ? -EFAULT : 0;
}
@@ -102,6 +99,39 @@ static int get_sense(struct atm_dev *dev,u8 *arg)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ unsigned char mode_reg;
+
+ mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP |
+ uPD98402_MDR_RPLP);
+ switch (__ATM_LM_XTLOC(mode)) {
+ case __ATM_LM_NONE:
+ break;
+ case __ATM_LM_PHY:
+ mode_reg |= uPD98402_MDR_TPLP;
+ break;
+ case __ATM_LM_ATM:
+ mode_reg |= uPD98402_MDR_ALP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (__ATM_LM_XTRMT(mode)) {
+ case __ATM_LM_NONE:
+ break;
+ case __ATM_LM_PHY:
+ mode_reg |= uPD98402_MDR_RPLP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(mode_reg,MDR);
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
+
static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
switch (cmd) {
@@ -117,35 +147,42 @@ static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
-EFAULT : 0;
case SONET_GETFRSENSE:
return get_sense(dev,arg);
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
+ return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
+ -EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM |
+ ATM_LM_RMT_PHY,(int *) arg) ? -EFAULT : 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOIOCTLCMD;
}
}
+#define ADD_LIMITED(s,v) \
+ { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \
+ if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \
+ atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); }
+
+
static void stat_event(struct atm_dev *dev)
{
unsigned char events;
events = GET(PCR);
- if (events & uPD98402_PFM_PFEB)
- if ((PRIV(dev)->sonet_stats.path_febe += GET(PFECB)) < 0)
- PRIV(dev)->sonet_stats.path_febe = LONG_MAX;
- if (events & uPD98402_PFM_LFEB)
- if ((PRIV(dev)->sonet_stats.line_febe += GET(LECCT)) < 0)
- PRIV(dev)->sonet_stats.line_febe = LONG_MAX;
- if (events & uPD98402_PFM_B3E)
- if ((PRIV(dev)->sonet_stats.path_bip += GET(B3ECT)) < 0)
- PRIV(dev)->sonet_stats.path_bip = LONG_MAX;
- if (events & uPD98402_PFM_B2E)
- if ((PRIV(dev)->sonet_stats.line_bip += GET(B2ECT)) < 0)
- PRIV(dev)->sonet_stats.line_bip = LONG_MAX;
- if (events & uPD98402_PFM_B1E)
- if ((PRIV(dev)->sonet_stats.section_bip += GET(B1ECT)) < 0)
- PRIV(dev)->sonet_stats.section_bip = LONG_MAX;
+ if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB);
+ if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT);
+ if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT);
+ if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT);
+ if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT);
}
+#undef ADD_LIMITED
+
+
static void uPD98402_int(struct atm_dev *dev)
{
static unsigned long silence = 0;
@@ -158,7 +195,8 @@ static void uPD98402_int(struct atm_dev *dev)
if (reason & uPD98402_INT_PFM) stat_event(dev);
if (reason & uPD98402_INT_PCO) {
(void) GET(PCOCR); /* clear interrupt cause */
- PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT);
+ atomic_add(GET(HECCT),
+ &PRIV(dev)->sonet_stats.uncorr_hcs);
}
if ((reason & uPD98402_INT_RFO) &&
(time_after(jiffies, silence) || silence == 0)) {
@@ -172,10 +210,10 @@ static void uPD98402_int(struct atm_dev *dev)
static int uPD98402_start(struct atm_dev *dev)
{
-DPRINTK("phy_start\n");
+ DPRINTK("phy_start\n");
if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
return -ENOMEM;
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
(void) GET(PCR); /* clear performance events */
PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */
(void) GET(PCOCR); /* clear overflows */
@@ -184,15 +222,26 @@ DPRINTK("phy_start\n");
PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO |
uPD98402_INT_LOS),PIMR); /* enable them */
(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
+ atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1);
+ atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1);
+ atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1);
return 0;
}
+static int uPD98402_stop(struct atm_dev *dev)
+{
+ /* let SAR driver worry about stopping interrupts */
+ kfree(PRIV(dev));
+ return 0;
+}
+
static const struct atmphy_ops uPD98402_ops = {
- uPD98402_start,
- uPD98402_ioctl, /* no ioctl yet */
- uPD98402_int
+ start: uPD98402_start,
+ ioctl: uPD98402_ioctl,
+ interrupt: uPD98402_int,
+ stop: uPD98402_stop,
};
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 26c8c9d90..1b68f5529 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -21,10 +21,12 @@
#include <linux/init.h>
#include <linux/atm_zatm.h>
#include <linux/capability.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/string.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include "uPD98401.h"
@@ -637,7 +639,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
}
if (!size) {
dev_kfree_skb_irq(skb);
- if (vcc) vcc->stats->rx_err++;
+ if (vcc) atomic_inc(&vcc->stats->rx_err);
continue;
}
if (!atm_charge(vcc,skb->truesize)) {
@@ -647,7 +649,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
skb->len = size;
ATM_SKB(skb)->vcc = vcc;
vcc->push(vcc,skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
zout(pos & 0xffff,MTA(mbx));
#if 0 /* probably a stupid idea */
@@ -914,7 +916,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP |
skb_queue_head(&zatm_vcc->backlog,skb);
break;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&zatm_vcc->tx_wait);
}
@@ -1537,7 +1539,7 @@ static void zatm_close(struct atm_vcc *vcc)
{
DPRINTK(">zatm_close\n");
if (!ZATM_VCC(vcc)) return;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
close_rx(vcc);
EVENT("close_tx\n",0,0);
close_tx(vcc);
@@ -1545,7 +1547,7 @@ static void zatm_close(struct atm_vcc *vcc)
/* deallocate memory */
kfree(ZATM_VCC(vcc));
ZATM_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
}
@@ -1557,20 +1559,20 @@ static int zatm_open(struct atm_vcc *vcc,short vpi,int vci)
DPRINTK(">zatm_open\n");
zatm_dev = ZATM_DEV(vcc->dev);
- if (!(vcc->flags & ATM_VF_PARTIAL)) ZATM_VCC(vcc) = NULL;
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL;
error = atm_find_ci(vcc,&vpi,&vci);
if (error) return error;
vcc->vpi = vpi;
vcc->vci = vci;
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */
DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,
vcc->vci);
- if (!(vcc->flags & ATM_VF_PARTIAL)) {
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL);
if (!zatm_vcc) {
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -ENOMEM;
}
ZATM_VCC(vcc) = zatm_vcc;
@@ -1593,7 +1595,7 @@ static int zatm_open(struct atm_vcc *vcc,short vpi,int vci)
zatm_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
@@ -1733,7 +1735,7 @@ static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb)
int error;
EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0);
- if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) {
+ if (!ZATM_VCC(vcc)->tx_chan || !test_bit(ATM_VF_READY,&vcc->flags)) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
return -EINVAL;
@@ -1809,7 +1811,7 @@ int __init zatm_detect(void)
while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
pci_dev))) {
- dev = atm_dev_register(DEV_LABEL,&ops,-1,0);
+ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
if (!dev) break;
zatm_dev->pci_dev = pci_dev;
ZATM_DEV(dev) = zatm_dev;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 3209aa46b..668cb5096 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -190,7 +190,7 @@ static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
page = grab_cache_page(mapping, index);
if (!page)
goto fail;
- if (aops->prepare_write(page, offset, offset+size))
+ if (aops->prepare_write(file, page, offset, offset+size))
goto unlock;
kaddr = (char*)page_address(page);
if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c
index beb4f1364..0986ff7df 100644
--- a/drivers/block/lvm.c
+++ b/drivers/block/lvm.c
@@ -2527,6 +2527,15 @@ void __init
*
* Is this the real thing?
*
+ * No, it's bollocks. md.c tries to do a bit different thing that might
+ * _somewhat_ work eons ago. Neither does any good these days. mount() couldn't
+ * care less for icache (it cares only for ->s_root->d_count and if we want
+ * loopback mounts even that will stop). BTW, with the form used here mount()
+ * would have to scan the _whole_ icache to detect the attempt - how on the
+ * Earth could it guess the i_ino of your dummy inode? Official line on the
+ * exclusion between mount()/swapon()/open()/etc. is Just Don't Do It(tm).
+ * If you can convince Linus that it's worth changing - fine, then you'll need
+ * to do blkdev_get()/blkdev_put(). Until then...
*/
struct inode *lvm_get_inode(int dev)
{
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 171b3b659..dd8a83764 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -1098,7 +1098,7 @@ static int md_import_device (kdev_t newdev, int on_disk)
}
memset(rdev, 0, sizeof(*rdev));
- if (!fs_may_mount(newdev)) {
+ if (get_super(newdev)) {
printk("md: can not import %s, has active inodes!\n",
partition_name(newdev));
err = -EBUSY;
@@ -1722,7 +1722,7 @@ static int do_md_stop (mddev_t * mddev, int ro)
int err = 0, resync_interrupted = 0;
kdev_t dev = mddev_to_kdev(mddev);
- if (!ro && !fs_may_mount (dev)) {
+ if (!ro && get_super(dev)) {
printk (STILL_MOUNTED, mdidx(mddev));
OUT(-EBUSY);
}
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index f05196389..9c4cabbbf 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/config.h>
+#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -336,6 +337,9 @@ int pi_init(PIA *pi, int autoprobe, int port, int mode,
s = protocol; e = s+1;
+ if (!protocols[0])
+ request_module ("paride_protocol");
+
if (autoprobe) {
s = 0;
e = MAX_PROTOS;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 27ea344b9..8f8580cf5 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -1483,6 +1483,6 @@ __setup("cm206=", cm206_setup);
#endif /* !MODULE */
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -D__SMP__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c"
* End:
*/
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 2a8da5960..9d86479dc 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -37,8 +37,10 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
static int acq_is_open=0;
+static spinlock_t acq_lock;
/*
* You must set these - there is no sane way to probe for this board.
@@ -117,8 +119,12 @@ static int acq_open(struct inode *inode, struct file *file)
switch(MINOR(inode->i_rdev))
{
case WATCHDOG_MINOR:
+ spin_lock(&acq_lock);
if(acq_is_open)
+ {
+ spin_unlock(&acq_lock);
return -EBUSY;
+ }
MOD_INC_USE_COUNT;
/*
* Activate
@@ -126,6 +132,7 @@ static int acq_open(struct inode *inode, struct file *file)
acq_is_open=1;
inb_p(WDT_START);
+ spin_unlock(&acq_lock);
return 0;
default:
return -ENODEV;
@@ -136,10 +143,12 @@ static int acq_close(struct inode *inode, struct file *file)
{
if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
{
+ spin_lock(&acq_lock);
#ifndef CONFIG_WATCHDOG_NOWAYOUT
inb_p(WDT_STOP);
#endif
acq_is_open=0;
+ spin_unlock(&acq_lock);
}
MOD_DEC_USE_COUNT;
return 0;
@@ -211,6 +220,7 @@ int __init acq_init(void)
{
printk("WDT driver for Acquire single board computer initialising.\n");
+ spin_lock_init(&acq_lock);
misc_register(&acq_miscdev);
request_region(WDT_STOP, 1, "Acquire WDT");
request_region(WDT_START, 1, "Acquire WDT");
diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
index 823ec88ea..0cdfc264a 100644
--- a/drivers/char/amigamouse.c
+++ b/drivers/char/amigamouse.c
@@ -162,6 +162,10 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
+ /* Lock module first - request_irq might sleep */
+
+ MOD_INC_USE_COUNT;
+
/*
* use VBL to poll mouse deltas
*/
@@ -169,10 +173,10 @@ static int open_mouse(struct inode * inode, struct file * file)
if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
"Amiga mouse", mouse_interrupt)) {
printk(KERN_INFO "Installing Amiga mouse failed.\n");
+ MOD_DEC_USE_COUNT;
return -EIO;
}
- MOD_INC_USE_COUNT;
#if AMIGA_OLD_INT
AMI_MSE_INT_ON();
#endif
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 969a75331..7ede5fdc6 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -2259,6 +2259,6 @@ void cleanup_module(void)
/*
Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c amiserial.c"
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c amiserial.c"
End:
*/
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index f6304943a..65be2102f 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -14,7 +14,7 @@
/* et passe en argument a acinit, mais est scrute sur le bus pour s'adapter */
/* au nombre de cartes presentes sur le bus. IOCL code 6 affichait V2.4.3 */
/* F.LAFORSE 28/11/95 creation de fichiers acXX.o avec les differentes */
-/* adresses de base des cartes, IOCTL 6 plus complet */
+/* adresses de base des cartes, IOCTL 6 plus complet */
/* J.PAGET le 19/08/96 copie de la version V2.6 en V2.8.0 sans modification */
/* de code autre que le texte V2.6.1 en V2.8.0 */
/*****************************************************************************/
@@ -37,108 +37,102 @@
#undef DEBUG
#define DEVPRIO PZERO+8
#define FALSE 0
-#define TRUE ~FALSE
-#define MAX_BOARD 8 /* maximum of pc board possible */
+#define TRUE ~FALSE
+#define MAX_BOARD 8 /* maximum of pc board possible */
#define MAX_ISA_BOARD 4
#define LEN_RAM_IO 0x800
#define AC_MINOR 157
#ifndef PCI_VENDOR_ID_APPLICOM
-#define PCI_VENDOR_ID_APPLICOM 0x1389
+#define PCI_VENDOR_ID_APPLICOM 0x1389
#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
#define MAX_PCI_DEVICE_NUM 3
#endif
-static char *applicom_pci_devnames[]={
- "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"};
+static char *applicom_pci_devnames[] = {
+ "PCI board", "PCI2000IBS / PCI2000CAN", "PCI2000PFB"
+};
MODULE_AUTHOR("David Woodhouse & Applicom International");
MODULE_DESCRIPTION("Driver for Applicom Profibus card");
MODULE_PARM(irq, "i");
MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
-MODULE_PARM(mem,"i");
+MODULE_PARM(mem, "i");
MODULE_PARM_DESC(mem, "Shared Memory Address of Applicom board");
MODULE_SUPPORTED_DEVICE("ac");
struct applicom_board {
- unsigned long PhysIO;
- unsigned long RamIO;
+ unsigned long PhysIO;
+ unsigned long RamIO;
#if LINUX_VERSION_CODE > 0x20300
- wait_queue_head_t FlagSleepSend;
+ wait_queue_head_t FlagSleepSend;
#else
- struct wait_queue *FlagSleepSend;
+ struct wait_queue *FlagSleepSend;
#endif
- long irq;
+ long irq;
} apbs[MAX_BOARD];
-static unsigned int irq=0; /* interrupt number IRQ */
-static unsigned long mem=0; /* physical segment of board */
+static unsigned int irq = 0; /* interrupt number IRQ */
+static unsigned long mem = 0; /* physical segment of board */
-static unsigned int numboards; /* number of installed boards */
+static unsigned int numboards; /* number of installed boards */
static volatile unsigned char Dummy;
#if LINUX_VERSION_CODE > 0x20300
-static DECLARE_WAIT_QUEUE_HEAD (FlagSleepRec);
+static DECLARE_WAIT_QUEUE_HEAD(FlagSleepRec);
#else
static struct wait_queue *FlagSleepRec;
#endif
-static unsigned int WriteErrorCount; /* number of write error */
-static unsigned int ReadErrorCount; /* number of read error */
-static unsigned int DeviceErrorCount; /* number of device error */
+static unsigned int WriteErrorCount; /* number of write error */
+static unsigned int ReadErrorCount; /* number of read error */
+static unsigned int DeviceErrorCount; /* number of device error */
static loff_t ac_llseek(struct file *file, loff_t offset, int origin);
static int ac_open(struct inode *inode, struct file *filp);
-static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr);
-static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos);
+static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr);
+static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int ac_release(struct inode *inode, struct file *file);
static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-struct file_operations ac_fops={
- llseek: ac_llseek,
- read: ac_read,
- write: ac_write,
- ioctl: ac_ioctl,
- open: ac_open,
- release: ac_release,
+struct file_operations ac_fops = {
+ llseek:ac_llseek,
+ read:ac_read,
+ write:ac_write,
+ ioctl:ac_ioctl,
+ open:ac_open,
+ release:ac_release,
};
-struct miscdevice ac_miscdev={
- AC_MINOR,
- "ac",
- &ac_fops
+struct miscdevice ac_miscdev = {
+ AC_MINOR,
+ "ac",
+ &ac_fops
};
-int ac_register_board(unsigned long physloc, unsigned long loc,
- unsigned char boardno)
+int ac_register_board(unsigned long physloc, unsigned long loc, unsigned char boardno)
{
volatile unsigned char byte_reset_it;
- if((readb(loc + CONF_END_TEST) != 0x00) ||
- (readb(loc + CONF_END_TEST + 1) != 0x55) ||
- (readb(loc + CONF_END_TEST + 2) != 0xAA) ||
- (readb(loc + CONF_END_TEST + 3) != 0xFF))
- return 0;
+ if ((readb(loc + CONF_END_TEST) != 0x00) || (readb(loc + CONF_END_TEST + 1) != 0x55) || (readb(loc + CONF_END_TEST + 2) != 0xAA) || (readb(loc + CONF_END_TEST + 3) != 0xFF))
+ return 0;
if (!boardno)
- boardno = readb(loc + NUMCARD_OWNER_TO_PC);
+ boardno = readb(loc + NUMCARD_OWNER_TO_PC);
- if (!boardno && boardno > MAX_BOARD)
- {
- printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n",boardno, physloc, MAX_BOARD);
- return 0;
- }
+ if (!boardno && boardno > MAX_BOARD) {
+ printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", boardno, physloc, MAX_BOARD);
+ return 0;
+ }
- if (apbs[boardno-1].RamIO)
- {
- printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n",
- boardno, physloc, boardno, apbs[boardno-1].PhysIO);
- return 0;
- }
+ if (apbs[boardno - 1].RamIO) {
+ printk(KERN_WARNING "Board #%d (at 0x%lx) conflicts with previous board #%d (at 0x%lx)\n", boardno, physloc, boardno, apbs[boardno - 1].PhysIO);
+ return 0;
+ }
boardno--;
@@ -152,7 +146,7 @@ int ac_register_board(unsigned long physloc, unsigned long loc,
byte_reset_it = readb(loc + RAM_IT_TO_PC);
numboards++;
- return boardno+1;
+ return boardno + 1;
}
#ifdef MODULE
@@ -164,22 +158,21 @@ void cleanup_module(void)
int i;
misc_deregister(&ac_miscdev);
- for (i=0; i< MAX_BOARD; i++)
- {
- if (!apbs[i].RamIO)
- continue;
- iounmap((void *)apbs[i].RamIO);
- if (apbs[i].irq)
- free_irq(apbs[i].irq,&ac_open);
- }
- // printk("Removing Applicom module\n");
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+ iounmap((void *) apbs[i].RamIO);
+ if (apbs[i].irq)
+ free_irq(apbs[i].irq, &ac_open);
+ }
+ // printk("Removing Applicom module\n");
}
-#endif /* MODULE */
+#endif /* MODULE */
int __init applicom_init(void)
{
- int i, numisa=0;
+ int i, numisa = 0;
struct pci_dev *dev = NULL;
void *RamIO;
int boardno;
@@ -190,157 +183,137 @@ int __init applicom_init(void)
#endif
printk(KERN_INFO "Applicom driver: $Id: ac.c,v 1.16 1999/08/28 15:11:50 dwmw2 Exp $\n");
-
+
/* No mem and irq given - check for a PCI card */
-
- while ( (dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev)))
- {
- // mem = dev->base_address[0];
- // irq = dev->irq;
-
- RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
-
- if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev));
- return -EIO;
- }
-
- printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
- applicom_pci_devnames[dev->device-1], PCI_BASE_ADDRESS(dev),
- dev->irq);
-
- if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev),
- (unsigned long)RamIO,0)))
- {
- printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
- iounmap(RamIO);
- continue;
- }
-
- if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open))
- {
- printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
- iounmap(RamIO);
- apbs[boardno-1].RamIO = 0;
- continue;
- }
-
- /* Enable interrupts. */
-
- writeb(0x40, apbs[boardno-1].RamIO + RAM_IT_FROM_PC);
-
- apbs[boardno-1].irq = dev->irq;
- }
-
+
+ while ((dev = pci_find_device(PCI_VENDOR_ID_APPLICOM, 1, dev))) {
+ // mem = dev->base_address[0];
+ // irq = dev->irq;
+
+ RamIO = ioremap(PCI_BASE_ADDRESS(dev), LEN_RAM_IO);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", PCI_BASE_ADDRESS(dev));
+ return -EIO;
+ }
+
+ printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n", applicom_pci_devnames[dev->device - 1], PCI_BASE_ADDRESS(dev), dev->irq);
+
+ if (!(boardno = ac_register_board(PCI_BASE_ADDRESS(dev), (unsigned long) RamIO, 0))) {
+ printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
+ iounmap(RamIO);
+ continue;
+ }
+
+ if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) {
+ printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
+ iounmap(RamIO);
+ apbs[boardno - 1].RamIO = 0;
+ continue;
+ }
+
+ /* Enable interrupts. */
+
+ writeb(0x40, apbs[boardno - 1].RamIO + RAM_IT_FROM_PC);
+
+ apbs[boardno - 1].irq = dev->irq;
+ }
+
/* Finished with PCI cards. If none registered,
* and there was no mem/irq specified, exit */
- if (!mem || !irq)
- {
- if (numboards)
- goto fin;
- else
- {
- printk(KERN_INFO "ac.o: No PCI boards found.\n");
- printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n");
- return -ENXIO;
- }
- }
-
+ if (!mem || !irq) {
+ if (numboards)
+ goto fin;
+ else {
+ printk(KERN_INFO "ac.o: No PCI boards found.\n");
+ printk(KERN_INFO "ac.o: For an ISA board you must supply memory and irq parameters.\n");
+ return -ENXIO;
+ }
+ }
+
/* Now try the specified ISA cards */
- RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
+ RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n",mem);
+ printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem);
+ }
+
+ for (i = 0; i < MAX_ISA_BOARD; i++) {
+ RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
+
+ if (!RamIO) {
+ printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1);
+ continue;
+ }
+
+ if (!(boardno = ac_register_board((unsigned long) mem + (LEN_RAM_IO * i), (unsigned long) RamIO, i + 1))) {
+ iounmap(RamIO);
+ continue;
+ }
+
+ printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO * i), irq);
+
+ if (!numisa) {
+ if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) {
+ printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq);
+ iounmap((void *) RamIO);
+ apbs[boardno - 1].RamIO = 0;
+ }
+ apbs[boardno - 1].irq = irq;
+ } else
+ apbs[boardno - 1].irq = 0;
+
+ numisa++;
}
-
- for (i=0; i< MAX_ISA_BOARD; i++)
- {
- RamIO = ioremap(mem+ (LEN_RAM_IO*i), LEN_RAM_IO);
-
- if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n",i+1);
- continue;
- }
-
- if (!(boardno = ac_register_board((unsigned long)mem+ (LEN_RAM_IO*i),
- (unsigned long)RamIO,i+1))) {
- iounmap(RamIO);
- continue;
- }
-
- printk("Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
-
- if (!numisa)
- {
- if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open))
- {
- printk("Could not allocate IRQ %d for ISA Applicom device.\n", irq);
- iounmap((void *)RamIO);
- apbs[boardno-1].RamIO = 0;
- }
- apbs[boardno-1].irq=irq;
- }
- else
- apbs[boardno-1].irq=0;
-
- numisa++;
- }
if (!numisa)
- printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n",mem);
+ printk("ac.o: No valid ISA Applicom boards found at mem 0x%lx\n", mem);
#if LINUX_VERSION_CODE > 0x20300
init_waitqueue_head(&FlagSleepRec);
#else
- FlagSleepRec = NULL;
+ FlagSleepRec = NULL;
#endif
- WriteErrorCount = 0;
- ReadErrorCount = 0;
+ WriteErrorCount = 0;
+ ReadErrorCount = 0;
DeviceErrorCount = 0;
-fin:
- if (numboards)
- {
- misc_register (&ac_miscdev);
- for (i=0; i<MAX_BOARD; i++)
- {
- int serial;
- char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
+ fin:
+ if (numboards) {
+ misc_register(&ac_miscdev);
+ for (i = 0; i < MAX_BOARD; i++) {
+ int serial;
+ char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
- if (!apbs[i].RamIO)
- continue;
-
- for(serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
- boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
- boardname[serial]=0;
-
+ if (!apbs[i].RamIO)
+ continue;
- printk("Applicom board %d: %s, PROM V%d.%d",
- i+1, boardname,
- (int)(readb(apbs[i].RamIO + VERS) >> 4),
- (int)(readb(apbs[i].RamIO + VERS) & 0xF));
+ for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
+ boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
+ boardname[serial] = 0;
+
+
+ printk(KERN_INFO "Applicom board %d: %s, PROM V%d.%d", i + 1, boardname, (int) (readb(apbs[i].RamIO + VERS) >> 4), (int) (readb(apbs[i].RamIO + VERS) & 0xF));
+
+ serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2));
+
+ if (serial != 0)
+ printk(" S/N %d\n", serial);
+ else
+ printk("\n");
+ }
+ return 0;
+ }
- serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
-
- if (serial != 0)
- printk (" S/N %d\n", serial);
- else
- printk("\n");
- }
- return 0;
- }
-
else
- return -ENXIO;
+ return -ENXIO;
}
#ifndef MODULE
-__initcall (applicom_init);
+__initcall(applicom_init);
#endif
static loff_t ac_llseek(struct file *file, loff_t offset, int origin)
@@ -361,477 +334,455 @@ static int ac_release(struct inode *inode, struct file *file)
}
-static ssize_t ac_write (struct file *file, const char *buf, size_t count, loff_t *ppos)
+static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
{
- unsigned int NumCard; /* Board number 1 -> 8 */
- unsigned int IndexCard; /* Index board number 0 -> 7 */
- unsigned char TicCard; /* Board TIC to send */
- unsigned long flags; /* Current priority */
- struct st_ram_io st_loc;
- struct mailbox tmpmailbox;
-
- if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
- printk("Hmmm. write() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
- return -EINVAL;
- }
-
- if(copy_from_user (&st_loc, buf, sizeof(struct st_ram_io))) {
- return -EFAULT;
- }
- if(copy_from_user (&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) {
- return -EFAULT;
- }
-
- NumCard = st_loc.num_card; /* board number to send */
- TicCard = st_loc.tic_des_from_pc; /* tic number to send */
- IndexCard = NumCard -1;
- if((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO)
- { /* User board number not OK */
- // printk("Write to invalid Applicom board %d\n", NumCard);
- return -EINVAL; /* Return error code user buffer */
- }
-
+ unsigned int NumCard; /* Board number 1 -> 8 */
+ unsigned int IndexCard; /* Index board number 0 -> 7 */
+ unsigned char TicCard; /* Board TIC to send */
+ unsigned long flags; /* Current priority */
+ struct st_ram_io st_loc;
+ struct mailbox tmpmailbox;
+
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk("Hmmm. write() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&st_loc, buf, sizeof(struct st_ram_io))) {
+ return -EFAULT;
+ }
+ if (copy_from_user(&tmpmailbox, &buf[sizeof(struct st_ram_io)], sizeof(struct mailbox))) {
+ return -EFAULT;
+ }
+
+ NumCard = st_loc.num_card; /* board number to send */
+ TicCard = st_loc.tic_des_from_pc; /* tic number to send */
+ IndexCard = NumCard - 1;
+ if ((NumCard < 1) || (NumCard > MAX_BOARD) || !apbs[IndexCard].RamIO) { /* User board number not OK */
+ // printk("Write to invalid Applicom board %d\n", NumCard);
+ return -EINVAL; /* Return error code user buffer */
+ }
#ifdef DEBUG
- {
- int c;
-
- printk("Write to applicom card #%d. struct st_ram_io follows:",NumCard);
-
-
-
- for (c=0; c< sizeof(struct st_ram_io);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct st_ram_io); c++)
- {
- printk(" %2.2X",((unsigned char *)&st_loc)[c]);
- }
- }
+ {
+ int c;
+
+ printk("Write to applicom card #%d. struct st_ram_io follows:", NumCard);
+
+
+
+ for (c = 0; c < sizeof(struct st_ram_io);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
+ printk(" %2.2X", ((unsigned char *) &st_loc)[c]);
+ }
+ }
+
+ printk("\nstruct mailbox follows:");
+
+ for (c = 0; c < sizeof(struct mailbox);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
+ printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]);
+ }
+ }
+
+ printk("\n");
+ }
- printk("\nstruct mailbox follows:");
-
- for (c=0; c< sizeof(struct mailbox);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&tmpmailbox)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct mailbox); c++)
- {
- printk(" %2.2X",((unsigned char *)&tmpmailbox)[c]);
- }
- }
-
- printk("\n");
- }
-
#endif
- save_flags (flags);
- cli(); /* disable interrupt */
-
- if(readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) /* Test octet ready correct */
- {
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags(flags);
- printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n",
- IndexCard,(int)readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
- DeviceErrorCount++;
- return -EIO;
- }
- while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0)
- {
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags(flags);
- interruptible_sleep_on (&apbs[IndexCard].FlagSleepSend);
- if (signal_pending(current))
- return -EINTR;
- save_flags(flags);
- cli();
- }
- writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
-
- // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
- {
- unsigned char *from = (unsigned char *)&tmpmailbox;
- unsigned long to = (unsigned long)apbs[IndexCard].RamIO + RAM_FROM_PC;
- int c;
-
- for (c=0; c<sizeof(struct mailbox) ; c++)
- writeb(*(from++), to++);
- }
- writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
- writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
- writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
- writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
- writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
- writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags (flags);
- return 0;
+ save_flags(flags);
+ cli(); /* disable interrupt */
+
+ if (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) > 2) { /* Test octet ready correct */
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ printk("APPLICOM driver write error board %d, DataFromPcReady = %d\n", IndexCard, (int) readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY));
+ DeviceErrorCount++;
+ return -EIO;
+ }
+ while (readb(apbs[IndexCard].RamIO + DATA_FROM_PC_READY) != 0) {
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ /*
+ * FIXME: Race on wakeup. Race on re-entering write
+ * in another thread.
+ */
+ interruptible_sleep_on(&apbs[IndexCard].FlagSleepSend);
+ if (signal_pending(current))
+ return -EINTR;
+ save_flags(flags);
+ cli();
+ }
+ writeb(1, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+
+ // memcpy_toio ((void *)apbs[IndexCard].PtrRamFromPc, (void *)&tmpmailbox, sizeof(struct mailbox));
+ {
+ unsigned char *from = (unsigned char *) &tmpmailbox;
+ unsigned long to = (unsigned long) apbs[IndexCard].RamIO + RAM_FROM_PC;
+ int c;
+
+ for (c = 0; c < sizeof(struct mailbox); c++)
+ writeb(*(from++), to++);
+ }
+ writeb(0x20, apbs[IndexCard].RamIO + TIC_OWNER_FROM_PC);
+ writeb(0xff, apbs[IndexCard].RamIO + NUMCARD_OWNER_FROM_PC);
+ writeb(TicCard, apbs[IndexCard].RamIO + TIC_DES_FROM_PC);
+ writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+ writeb(2, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
+ return 0;
}
-static ssize_t ac_read (struct file *filp, char *buf, size_t count, loff_t *ptr)
+static ssize_t ac_read(struct file *filp, char *buf, size_t count, loff_t * ptr)
{
- unsigned int NumCard; /* board number 1 -> 8 */
- unsigned int IndexCard; /* index board number 0 -> 7 */
- unsigned long flags;
- unsigned int i;
- unsigned char tmp=0;
- struct st_ram_io st_loc;
- struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */
-
-
- if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
- printk("Hmmm. read() of Applicom card, length %d != expected %d\n",count,sizeof(struct st_ram_io) + sizeof(struct mailbox));
- return -EINVAL;
- }
-
- save_flags(flags);
- cli();
-
- i = 0;
-
- while (tmp != 2)
- {
- for (i=0; i < MAX_BOARD; i++)
- {
- if (!apbs[i].RamIO)
- continue;
-
- tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
-
- if (tmp == 2)
- break;
-
- if (tmp > 2) /* Test octet ready correct */
- {
- Dummy = readb(apbs[i].RamIO + VERS);
- restore_flags(flags);
- printk("APPLICOM driver read error board %d, DataToPcReady = %d\n",
- i,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
- DeviceErrorCount++;
- return -EIO;
- }
- Dummy = readb(apbs[i].RamIO + VERS);
+ unsigned int NumCard; /* board number 1 -> 8 */
+ unsigned int IndexCard; /* index board number 0 -> 7 */
+ unsigned long flags;
+ unsigned int i;
+ unsigned char tmp = 0;
+ struct st_ram_io st_loc;
+ struct mailbox tmpmailbox; /* bounce buffer - can't copy to user space with cli() */
+
+
+ if (count != sizeof(struct st_ram_io) + sizeof(struct mailbox)) {
+ printk("Hmmm. read() of Applicom card, length %d != expected %d\n", count, sizeof(struct st_ram_io) + sizeof(struct mailbox));
+ return -EINVAL;
+ }
+ save_flags(flags);
+ cli();
+
+ i = 0;
+
+ while (tmp != 2) {
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+
+ tmp = readb(apbs[i].RamIO + DATA_TO_PC_READY);
+
+ if (tmp == 2)
+ break;
+
+ if (tmp > 2) { /* Test octet ready correct */
+ Dummy = readb(apbs[i].RamIO + VERS);
+ restore_flags(flags);
+ printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n", i, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY));
+ DeviceErrorCount++;
+ return -EIO;
+ }
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ }
+ if (tmp != 2) {
+ /*
+ * FIXME: race on wakeup. O_NDELAY not implemented
+ * Parallel read threads race.
+ */
+ restore_flags(flags);
+ interruptible_sleep_on(&FlagSleepRec);
+ if (signal_pending(current))
+ return -EINTR;
+ save_flags(flags);
+ cli();
+ }
}
- if (tmp != 2)
+
+ IndexCard = i;
+ NumCard = i + 1;
+ st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
+ st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+
+
+ // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox));
{
- restore_flags(flags);
- interruptible_sleep_on (&FlagSleepRec);
- if (signal_pending(current))
- return -EINTR;
- save_flags(flags);
- cli();
+ unsigned long from = (unsigned long) apbs[IndexCard].RamIO + RAM_TO_PC;
+ unsigned char *to = (unsigned char *) &tmpmailbox;
+ int c;
+
+ for (c = 0; c < sizeof(struct mailbox); c++)
+ *(to++) = readb(from++);
}
- }
-
- IndexCard = i;
- NumCard = i+1;
- st_loc.tic_owner_to_pc = readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC);
- st_loc.numcard_owner_to_pc = readb(apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
-
-
- // memcpy_fromio(&tmpmailbox, apbs[IndexCard].PtrRamToPc, sizeof(struct mailbox));
- {
- unsigned long from = (unsigned long)apbs[IndexCard].RamIO + RAM_TO_PC;
- unsigned char *to = (unsigned char *)&tmpmailbox;
- int c;
-
- for (c=0; c<sizeof(struct mailbox) ; c++)
- *(to++) = readb(from++);
- }
- writeb(1,apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
- writeb(1,apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
- writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
- writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC),
- apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
- writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
- writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
- writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- restore_flags(flags);
+ writeb(1, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + TYP_ACK_FROM_PC);
+ writeb(NumCard, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+ writeb(readb(apbs[IndexCard].RamIO + TIC_OWNER_TO_PC), apbs[IndexCard].RamIO + TIC_ACK_FROM_PC);
+ writeb(2, apbs[IndexCard].RamIO + ACK_FROM_PC_READY);
+ writeb(0, apbs[IndexCard].RamIO + DATA_TO_PC_READY);
+ writeb(2, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ restore_flags(flags);
#ifdef DEBUG
- { int c;
+ {
+ int c;
- printk("Read from applicom card #%d. struct st_ram_io follows:",NumCard);
-
- for (c=0; c< sizeof(struct st_ram_io);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&st_loc)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct st_ram_io); c++)
- {
- printk(" %2.2X",((unsigned char *)&st_loc)[c]);
- }
- }
+ printk("Read from applicom card #%d. struct st_ram_io follows:", NumCard);
- printk("\nstruct mailbox follows:");
-
- for (c=0; c< sizeof(struct mailbox);)
- {
- printk("\n%5.5X: %2.2X",c,((unsigned char *)&tmpmailbox)[c]);
-
- for (c++ ; c%8 && c<sizeof(struct mailbox); c++)
- {
- printk(" %2.2X",((unsigned char *)&tmpmailbox)[c]);
- }
- }
- printk("\n");
-
- }
+ for (c = 0; c < sizeof(struct st_ram_io);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &st_loc)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct st_ram_io); c++) {
+ printk(" %2.2X", ((unsigned char *) &st_loc)[c]);
+ }
+ }
+
+ printk("\nstruct mailbox follows:");
+
+ for (c = 0; c < sizeof(struct mailbox);) {
+ printk("\n%5.5X: %2.2X", c, ((unsigned char *) &tmpmailbox)[c]);
+
+ for (c++; c % 8 && c < sizeof(struct mailbox); c++) {
+ printk(" %2.2X", ((unsigned char *) &tmpmailbox)[c]);
+ }
+ }
+ printk("\n");
+
+ }
#endif
-
- /* Je suis stupide. DW. */
- if(copy_to_user (buf, &st_loc, sizeof(struct st_ram_io)))
- return -EFAULT;
- if(copy_to_user (&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
- return -EFAULT;
+ /* Je suis stupide. DW. */
- return 0;
+ if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ if (copy_to_user(&buf[sizeof(struct st_ram_io)], &tmpmailbox, sizeof(struct mailbox)))
+ return -EFAULT;
+
+ return 0;
}
static void ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
{
- unsigned int i;
- unsigned int FlagInt;
- unsigned int LoopCount;
- // volatile unsigned char ResetIntBoard;
-
- // printk("Applicom interrupt on IRQ %d occurred\n", vec);
-
- LoopCount = 0;
- // for(i=boardno;i<MAX_BOARD;i++) /* loop for not configured board */
- // if (apbs[i].RamIO)
- // ResetIntBoard = *apbs[i].PtrRamItToPc; /* reset interrupt of unused boards */
-
- do
- {
- FlagInt = FALSE;
- for(i=0;i<MAX_BOARD;i++)
- {
- if (!apbs[i].RamIO)
- continue;
-
- if(readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
- FlagInt = TRUE;
- writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
-
- if(readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2)
- {
- printk("APPLICOM driver interrupt err board %d, DataToPcReady = %d\n",
- i+1,(int)readb(apbs[i].RamIO + DATA_TO_PC_READY));
- DeviceErrorCount++;
- }
- if((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) &&
- (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6))
- {
- printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n",
- i+1,(int)readb(apbs[i].RamIO + DATA_FROM_PC_READY));
- DeviceErrorCount++;
- }
- if(readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) /* mailbox sent by the card ? */
- {
- wake_up_interruptible(&FlagSleepRec);
- }
- if(readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) /* ram i/o free for write by pc ? */
- {
- if(waitqueue_active(&apbs[i].FlagSleepSend)) /* process sleep during read ? */
- {
- wake_up_interruptible(&apbs[i].FlagSleepSend);
- }
- }
- Dummy = readb(apbs[i].RamIO + VERS);
-
- if(readb(apbs[i].RamIO + RAM_IT_TO_PC))
- i--; /* There's another int waiting on this card */
- }
- if(FlagInt) LoopCount = 0;
- else LoopCount++;
- }
- while(LoopCount < 2);
+ unsigned int i;
+ unsigned int FlagInt;
+ unsigned int LoopCount;
+ // volatile unsigned char ResetIntBoard;
+
+ // printk("Applicom interrupt on IRQ %d occurred\n", vec);
+
+ LoopCount = 0;
+ // for(i=boardno;i<MAX_BOARD;i++) /* loop for not configured board */
+ // if (apbs[i].RamIO)
+ // ResetIntBoard = *apbs[i].PtrRamItToPc; /* reset interrupt of unused boards */
+
+ do {
+ FlagInt = FALSE;
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (!apbs[i].RamIO)
+ continue;
+
+ if (readb(apbs[i].RamIO + RAM_IT_TO_PC) != 0)
+ FlagInt = TRUE;
+ writeb(0, apbs[i].RamIO + RAM_IT_TO_PC);
+
+ if (readb(apbs[i].RamIO + DATA_TO_PC_READY) > 2) {
+ printk(KERN_WARNING "APPLICOM driver interrupt err board %d, DataToPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_TO_PC_READY));
+ DeviceErrorCount++;
+ }
+ if ((readb(apbs[i].RamIO + DATA_FROM_PC_READY) > 2) && (readb(apbs[i].RamIO + DATA_FROM_PC_READY) != 6)) {
+ printk("APPLICOM driver interrupt err board %d, DataFromPcReady = %d\n", i + 1, (int) readb(apbs[i].RamIO + DATA_FROM_PC_READY));
+ DeviceErrorCount++;
+ }
+ if (readb(apbs[i].RamIO + DATA_TO_PC_READY) == 2) { /* mailbox sent by the card ? */
+ wake_up_interruptible(&FlagSleepRec);
+ }
+ if (readb(apbs[i].RamIO + DATA_FROM_PC_READY) == 0) { /* ram i/o free for write by pc ? */
+ if (waitqueue_active(&apbs[i].FlagSleepSend)) { /* process sleep during read ? */
+ wake_up_interruptible(&apbs[i].FlagSleepSend);
+ }
+ }
+ Dummy = readb(apbs[i].RamIO + VERS);
+
+ if (readb(apbs[i].RamIO + RAM_IT_TO_PC))
+ i--; /* There's another int waiting on this card */
+ }
+ if (FlagInt)
+ LoopCount = 0;
+ else
+ LoopCount++;
+ }
+ while (LoopCount < 2);
}
static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{ /* @ ADG ou ATO selon le cas */
+ int i;
+ unsigned char IndexCard;
+ unsigned long pmem;
+ volatile unsigned char byte_reset_it;
+ struct st_ram_io adgl;
+ unsigned char TmpRamIo[sizeof(struct st_ram_io)];
-{ /* @ ADG ou ATO selon le cas */
- int i;
- unsigned char IndexCard;
- unsigned long pmem ;
- volatile unsigned char byte_reset_it;
- struct st_ram_io adgl ;
- unsigned char TmpRamIo[sizeof(struct st_ram_io)];
-
-
- if (copy_from_user (&adgl, (void *)arg,sizeof(struct st_ram_io)))
- return -EFAULT;
-
- IndexCard = adgl.num_card-1;
- if(cmd != 0 && cmd != 6 &&
- ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO))
- {
- printk("APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
- printk("apbs[%d].RamIO = %lx\n",IndexCard, apbs[IndexCard].RamIO);
- return -EINVAL;
- }
-
- switch( cmd )
- {
- case 0 :
- pmem = apbs[IndexCard].RamIO;
- for(i=0;i<sizeof(struct st_ram_io);i++)TmpRamIo[i]=readb(pmem++);
- if (copy_to_user((void *)arg, TmpRamIo, sizeof(struct st_ram_io)))
- return -EFAULT;
- break;
- case 1 :
- pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
- for (i=0;i<4;i++)
- adgl.conf_end_test[i] = readb(pmem++);
- for (i=0;i<2;i++)
- adgl.error_code[i] = readb(pmem++);
- for (i=0;i<4;i++)
- adgl.parameter_error[i] = readb(pmem++);
- pmem = apbs[IndexCard].RamIO + VERS;
- adgl.vers = readb(pmem);
- pmem = apbs[IndexCard].RamIO + TYPE_CARD;
- for (i=0;i<20;i++)
- adgl.reserv1[i] = readb(pmem++);
- *(int *)&adgl.reserv1[20] =
- (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) +
- (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) +
- (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2) );
-
- if (copy_to_user ((void *)arg, &adgl, sizeof(struct st_ram_io)))
- return -EFAULT;
- break;
- case 2 :
- pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
- for (i=0;i<10;i++)
- writeb(0xff, pmem++);
- writeb(adgl.data_from_pc_ready,
- apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
-
- writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+
+ if (copy_from_user(&adgl, (void *) arg, sizeof(struct st_ram_io)))
+ return -EFAULT;
+
+ IndexCard = adgl.num_card - 1;
+
+ /*
+ * FIXME: user can flood the console using bogus ioctls
+ */
+
+ if (cmd != 0 && cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+ printk("APPLICOM driver IOCTL, bad board number %d\n", (int) IndexCard + 1);
+ printk("apbs[%d].RamIO = %lx\n", IndexCard, apbs[IndexCard].RamIO);
+ return -EINVAL;
+ }
+
+ /*
+ * FIXME races between ioctls with multiple clients
+ */
+
+ switch (cmd) {
+ case 0:
+ pmem = apbs[IndexCard].RamIO;
+ for (i = 0; i < sizeof(struct st_ram_io); i++)
+ TmpRamIo[i] = readb(pmem++);
+ if (copy_to_user((void *) arg, TmpRamIo, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 1:
+ pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
+ for (i = 0; i < 4; i++)
+ adgl.conf_end_test[i] = readb(pmem++);
+ for (i = 0; i < 2; i++)
+ adgl.error_code[i] = readb(pmem++);
+ for (i = 0; i < 4; i++)
+ adgl.parameter_error[i] = readb(pmem++);
+ pmem = apbs[IndexCard].RamIO + VERS;
+ adgl.vers = readb(pmem);
+ pmem = apbs[IndexCard].RamIO + TYPE_CARD;
+ for (i = 0; i < 20; i++)
+ adgl.reserv1[i] = readb(pmem++);
+ *(int *) &adgl.reserv1[20] = (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[IndexCard].RamIO + SERIAL_NUMBER + 2));
+
+ if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 2:
+ pmem = apbs[IndexCard].RamIO + CONF_END_TEST;
+ for (i = 0; i < 10; i++)
+ writeb(0xff, pmem++);
+ writeb(adgl.data_from_pc_ready, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+
+ /*
+ * FIXME: can trash waitqueue that is active.
+ */
#if LINUX_VERSION_CODE > 0x20300
- init_waitqueue_head (&FlagSleepRec);
+ init_waitqueue_head(&FlagSleepRec);
#else
- FlagSleepRec = NULL;
+ FlagSleepRec = NULL;
#endif
- for (i=0;i<MAX_BOARD;i++)
- {
- if (apbs[i].RamIO)
- {
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (apbs[i].RamIO) {
#if LINUX_VERSION_CODE > 0x20300
- init_waitqueue_head (&apbs[i].FlagSleepSend);
+ init_waitqueue_head(&apbs[i].FlagSleepSend);
#else
- apbs[i].FlagSleepSend = NULL;
+ apbs[i].FlagSleepSend = NULL;
#endif
- byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
- }
- }
- break ;
- case 3 :
- pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
- writeb(adgl.tic_des_from_pc, pmem);
- break;
- case 4 :
- pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
- adgl.tic_owner_to_pc = readb(pmem++);
- adgl.numcard_owner_to_pc = readb(pmem);
- if (copy_to_user ((void *)arg, &adgl,sizeof(struct st_ram_io)))
- return -EFAULT;
- break;
- case 5 :
- writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
- writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
- writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
- writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
- writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
- break ;
- case 6 :
- printk("APPLICOM driver release .... V2.8.0\n");
- printk("Number of installed boards . %d\n",(int)numboards);
- printk("Segment of board ........... %X\n",(int)mem);
- printk("Interrupt IRQ number ....... %d\n",(int)irq);
- for(i=0;i<MAX_BOARD;i++)
- {
- int serial;
- char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
-
- if (!apbs[i].RamIO)
- continue;
-
-
- for(serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
- boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
- boardname[serial]=0;
-
-
- printk("Prom version board %d ....... V%d.%d %s",
- i+1,
- (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
- (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
- boardname);
-
-
- serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) +
- (readb(apbs[i].RamIO + SERIAL_NUMBER + 2) );
-
- if (serial != 0)
- printk (" S/N %d\n", serial);
- else
- printk("\n");
- }
- if(DeviceErrorCount != 0)
- printk("DeviceErrorCount ........... %d\n",DeviceErrorCount);
- if(ReadErrorCount != 0)
- printk("ReadErrorCount ............. %d\n",ReadErrorCount);
- if(WriteErrorCount != 0)
- printk("WriteErrorCount ............ %d\n",WriteErrorCount);
- if(waitqueue_active(&FlagSleepRec))
- printk("Process in read pending\n");
- for(i=0;i<MAX_BOARD;i++)
- {
- if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
- printk("Process in write pending board %d\n",i+1);
- }
- break;
- default :
- printk("APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
- return -EINVAL;
- break;
- }
- Dummy = readb(apbs[IndexCard].RamIO + VERS);
- return 0;
+ byte_reset_it = readb(apbs[i].RamIO + RAM_IT_TO_PC);
+ }
+ }
+ break;
+ case 3:
+ pmem = apbs[IndexCard].RamIO + TIC_DES_FROM_PC;
+ writeb(adgl.tic_des_from_pc, pmem);
+ break;
+ case 4:
+ pmem = apbs[IndexCard].RamIO + TIC_OWNER_TO_PC;
+ adgl.tic_owner_to_pc = readb(pmem++);
+ adgl.numcard_owner_to_pc = readb(pmem);
+ if (copy_to_user((void *) arg, &adgl, sizeof(struct st_ram_io)))
+ return -EFAULT;
+ break;
+ case 5:
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_OWNER_TO_PC);
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_DES_FROM_PC);
+ writeb(adgl.num_card, apbs[IndexCard].RamIO + NUMCARD_ACK_FROM_PC);
+ writeb(4, apbs[IndexCard].RamIO + DATA_FROM_PC_READY);
+ writeb(1, apbs[IndexCard].RamIO + RAM_IT_FROM_PC);
+ break;
+ case 6:
+ printk(KERN_INFO "APPLICOM driver release .... V2.8.0\n");
+ printk(KERN_INFO "Number of installed boards . %d\n", (int) numboards);
+ printk(KERN_INFO "Segment of board ........... %X\n", (int) mem);
+ printk(KERN_INFO "Interrupt IRQ number ....... %d\n", (int) irq);
+ for (i = 0; i < MAX_BOARD; i++) {
+ int serial;
+ char boardname[(SERIAL_NUMBER - TYPE_CARD) + 1];
+
+ if (!apbs[i].RamIO)
+ continue;
+
+
+ for (serial = 0; serial < SERIAL_NUMBER - TYPE_CARD; serial++)
+ boardname[serial] = readb(apbs[i].RamIO + TYPE_CARD + serial);
+ boardname[serial] = 0;
+
+
+ printk(KERN_INFO "Prom version board %d ....... V%d.%d %s", i + 1, (int) (readb(apbs[IndexCard].RamIO + VERS) >> 4), (int) (readb(apbs[IndexCard].RamIO + VERS) & 0xF), boardname);
+
+
+ serial = (readb(apbs[i].RamIO + SERIAL_NUMBER) << 16) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 1) << 8) + (readb(apbs[i].RamIO + SERIAL_NUMBER + 2));
+
+ if (serial != 0)
+ printk(" S/N %d\n", serial);
+ else
+ printk("\n");
+ }
+ if (DeviceErrorCount != 0)
+ printk(KERN_INFO "DeviceErrorCount ........... %d\n", DeviceErrorCount);
+ if (ReadErrorCount != 0)
+ printk(KERN_INFO "ReadErrorCount ............. %d\n", ReadErrorCount);
+ if (WriteErrorCount != 0)
+ printk(KERN_INFO "WriteErrorCount ............ %d\n", WriteErrorCount);
+ if (waitqueue_active(&FlagSleepRec))
+ printk("Process in read pending\n");
+ for (i = 0; i < MAX_BOARD; i++) {
+ if (apbs[i].RamIO && waitqueue_active(&apbs[i].FlagSleepSend))
+ printk("Process in write pending board %d\n", i + 1);
+ }
+ break;
+ default:
+ printk("APPLICOM driver ioctl, unknown function code %d\n", cmd);
+ return -EINVAL;
+ break;
+ }
+ Dummy = readb(apbs[IndexCard].RamIO + VERS);
+ return 0;
}
#ifndef MODULE
static int __init applicom_setup(char *str)
{
int ints[4];
-
- (void)get_options(str, 4, ints);
+
+ (void) get_options(str, 4, ints);
if (ints[0] > 2) {
printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
}
-
+
if (ints[0] < 2) {
printk("applicom numargs: %d\n", ints[0]);
return 0;
}
-
- mem=ints[1];
- irq=ints[2];
+
+ mem = ints[1];
+ irq = ints[2];
return 1;
}
+
#if LINUX_VERSION_CODE > 0x20300
__setup("applicom=", applicom_setup);
#endif
-#endif /* MODULE */
-
+#endif /* MODULE */
diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
index 38de427e6..223793374 100644
--- a/drivers/char/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
@@ -92,10 +92,14 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
+ /* Lock module as request_irq may sleep */
+ MOD_INC_USE_COUNT;
if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
+ {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
+ }
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
- MOD_INC_USE_COUNT;
return 0;
}
@@ -107,7 +111,13 @@ static int __init atixl_busmouse_init(void)
{
unsigned char a,b,c;
- if (check_region(ATIXL_MSE_DATA_PORT, 3))
+ /*
+ * We must request the resource and claim it atomically
+ * nowdays. We can throw it away on error. Otherwise we
+ * may race another module load of the same I/O
+ */
+
+ if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
return -EIO;
a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */
@@ -116,16 +126,20 @@ static int __init atixl_busmouse_init(void)
if (( a != b ) && ( a == c ))
printk(KERN_INFO "\nATI Inport ");
else
+ {
+ release_region(ATIXL_MSE_DATA_PORT,3);
return -EIO;
+ }
outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */
outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */
outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */
- request_region(ATIXL_MSE_DATA_PORT, 3, "atixl");
-
msedev = register_busmouse(&atixlmouse);
if (msedev < 0)
+ {
printk("Bus mouse initialisation error.\n");
+ release_region(ATIXL_MSE_DATA_PORT,3); /* Was missing */
+ }
else
printk("Bus mouse detected and installed.\n");
return msedev < 0 ? msedev : 0;
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 66dfc0fe5..59adf47bc 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -121,6 +121,7 @@ static unsigned int autoload = 0;
#define I2C_GET() (btread(BT848_I2C)&1)
#define BURSTOFFSET 76
+#define BTTV_ERRORS 5
/* ----------------------------------------------------------------------- */
@@ -133,7 +134,6 @@ int bttv_get_id(unsigned int card)
if (card >= bttv_num) {
return -1;
}
-
return bttvs[card].type;
}
@@ -146,10 +146,7 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
}
btv = &bttvs[card];
- down(&btv->lock);
btaor(data, ~mask, BT848_GPIO_OUT_EN);
- up(&btv->lock);
-
return 0;
}
@@ -167,15 +164,9 @@ int bttv_read_gpio(unsigned int card, unsigned long *data)
return -ENODEV;
}
- down(&btv->lock);
-
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because we set direct input on init */
-
*data = btread(BT848_GPIO_DATA);
-
- up(&btv->lock);
-
return 0;
}
@@ -189,15 +180,9 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
btv = &bttvs[card];
- down(&btv->lock);
-
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because direct input is set on init */
-
btaor(data & mask, ~mask, BT848_GPIO_DATA);
-
- up(&btv->lock);
-
return 0;
}
@@ -210,11 +195,9 @@ WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card)
}
btv = &bttvs[card];
-
if (bttvs[card].shutdown) {
return NULL;
}
-
return &btv->gpioq;
}
@@ -787,7 +770,7 @@ static struct tvcard tvcards[] =
4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0,
1,1,1,1,0 },
{ "Hauppauge old",
- 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
+ 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
1,1,0,1,0 },
{ "STB",
3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
@@ -815,7 +798,7 @@ static struct tvcard tvcards[] =
3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0,
1,1,1,1,0 },
{ "Hauppauge new (bt878)",
- 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
+ 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
1,1,0,1,0 },
{ "MIRO PCTV pro",
3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0,
@@ -1213,7 +1196,7 @@ static void make_vbitab(struct bttv *btv)
unsigned int *pe=(unsigned int *) btv->vbi_even;
if (debug)
- printk("bttv%d: vbi: po=%08lx pe=%08lx\n",
+ printk("bttv%d: vbi1: po=%08lx pe=%08lx\n",
btv->nr,virt_to_bus(po), virt_to_bus(pe));
*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
@@ -1233,8 +1216,10 @@ static void make_vbitab(struct bttv *btv)
}
*(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16));
*(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
- DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po));
- DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe));
+
+ if (debug)
+ printk("bttv%d: vbi2: po=%08lx pe=%08lx\n",
+ btv->nr,virt_to_bus(po), virt_to_bus(pe));
}
static int fmtbppx2[16] = {
@@ -1310,7 +1295,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro,
int shift, csize;
if (debug)
- printk("bttv%d: prisc: ro=%08lx re=%08lx\n",
+ printk("bttv%d: prisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
switch(fmt)
@@ -1406,6 +1391,10 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro,
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+ if (debug)
+ printk("bttv%d: prisc2: ro=%08lx re=%08lx\n",
+ btv->nr,virt_to_bus(ro), virt_to_bus(re));
+
return 0;
}
@@ -1428,7 +1417,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
return make_prisctab(btv, ro, re, vbuf, width, height, palette);
if (debug)
- printk("bttv%d: vrisc: ro=%08lx re=%08lx\n",
+ printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
@@ -1478,6 +1467,10 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+
+ if (debug)
+ printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n",
+ btv->nr,virt_to_bus(ro), virt_to_bus(re));
return 0;
}
@@ -1555,7 +1548,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
width=btv->win.width;
height=btv->win.height;
if (debug)
- printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
+ printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
btv->nr,btv->picture.palette,width,height,bpl,bpp);
if(width > 1023)
width = 1023; /* sanity check */
@@ -1662,6 +1655,10 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
*(re++)=cpu_to_le32(BT848_RISC_JUMP);
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+
+ if (debug)
+ printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
+ btv->nr,btv->picture.palette,width,height,bpl,bpp);
}
/*
@@ -1879,7 +1876,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED)
return -EBUSY;
- if(mp->height <0 || mp->width <0)
+ if(mp->height < 32 || mp->width < 32)
return -EINVAL;
if (mp->format >= PALETTEFMT_MAX)
return -EINVAL;
@@ -1891,12 +1888,6 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
return -EINVAL;
/*
- * FIXME: Check the format of the grab here. This is probably
- * also less restrictive than the normal overlay grabs. Stuff
- * like QCIF has meaning as a capture.
- */
-
- /*
* Ok load up the BT848
*/
@@ -1906,7 +1897,8 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
if (debug)
- printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame);
+ printk("bttv%d: cap vgrab: queue %d (%dx%d)\n",
+ btv->nr,mp->frame,mp->width,mp->height);
cli();
btv->gbuf[mp->frame].stat = GBUFFER_GRABBING;
btv->gbuf[mp->frame].fmt = palette2fmt[mp->format];
@@ -1995,6 +1987,26 @@ static inline void burst(int on)
tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0);
}
+static void bt848_restart(struct bttv *btv)
+{
+ if (verbose)
+ printk("bttv%d: resetting chip\n",btv->nr);
+ btwrite(0xfffffUL, BT848_INT_STAT);
+ btand(~15, BT848_GPIO_DMA_CTL);
+ btwrite(0, BT848_SRESET);
+ btwrite(virt_to_bus(btv->risc_jmp+2),
+ BT848_RISC_STRT_ADD);
+
+ /* enforce pll reprogramming */
+ btv->pll.pll_current = 0;
+ set_pll(btv);
+
+ btv->errors = 0;
+ btv->needs_restart = 0;
+ bt848_set_geo(btv,0);
+ bt848_set_risc_jmps(btv,-1);
+}
+
/*
* Open a bttv card. Right now the flags stuff is just playing
*/
@@ -2020,6 +2032,8 @@ static int bttv_open(struct video_device *dev, int flags)
for (i = 0; i < gbuffers; i++)
btv->gbuf[i].stat = GBUFFER_UNUSED;
+ if (btv->needs_restart)
+ bt848_restart(btv);
burst(0);
set_pll(btv);
btv->user++;
@@ -2117,7 +2131,6 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
btaor(datahi, ~1, BT848_O_CONTROL);
}
-
/*
* ioctl routine
*/
@@ -2126,7 +2139,7 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct bttv *btv=(struct bttv *)dev;
- int i,ret;
+ int i,ret = 0;
if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
@@ -2281,7 +2294,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
-
+
if(vw.flags || vw.width < 16 || vw.height < 16)
{
down(&btv->lock);
@@ -2296,6 +2309,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
vw.width &= ~3;
}
down(&btv->lock);
+ if (btv->needs_restart)
+ bt848_restart(btv);
btv->win.x=vw.x;
btv->win.y=vw.y;
btv->win.width=vw.width;
@@ -2551,14 +2566,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EINVAL;
switch (btv->gbuf[i].stat) {
case GBUFFER_UNUSED:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
case GBUFFER_GRABBING:
while(btv->gbuf[i].stat==GBUFFER_GRABBING) {
if (debug)
printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
interruptible_sleep_on(&btv->capq);
- if(signal_pending(current))
- return -EINTR;
+ if(signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
}
/* fall throuth */
case GBUFFER_DONE:
@@ -2567,9 +2585,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (debug)
printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret);
btv->gbuf[i].stat = GBUFFER_UNUSED;
- return ret;
}
- return 0;
+ if (btv->needs_restart) {
+ down(&btv->lock);
+ bt848_restart(btv);
+ up(&btv->lock);
+ }
+ return ret;
case BTTV_FIELDNR:
if(copy_to_user((void *) arg, (void *) &btv->last_field,
@@ -2742,6 +2764,11 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
todo=count;
while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
{
+ if (btv->needs_restart) {
+ down(&btv->lock);
+ bt848_restart(btv);
+ up(&btv->lock);
+ }
if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
return -EFAULT;
todo-=q;
@@ -2796,6 +2823,8 @@ static int vbi_open(struct video_device *dev, int flags)
struct bttv *btv=(struct bttv *)(dev-2);
down(&btv->lock);
+ if (btv->needs_restart)
+ bt848_restart(btv);
btv->vbip=VBIBUF_SIZE;
btv->vbi_on = 1;
bt848_set_risc_jmps(btv,-1);
@@ -2938,8 +2967,8 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
strcpy(v.name, "Radio");
- v.rangelow=(int)(87.5*16);
- v.rangehigh=(int)(108*16);
+ v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */
+ v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */
v.flags= 0; /* XXX */
v.mode = 0; /* XXX */
if(copy_to_user(arg,&v,sizeof(v)))
@@ -3100,12 +3129,10 @@ static void idcard(int i)
/* print which board we have found */
printk(KERN_INFO "bttv%d: model: ",btv->nr);
- sprintf(btv->video_dev.name,"BT%d",btv->id);
- if (btv->id==848 && btv->revision==0x12)
- strcat(btv->video_dev.name,"A");
- strcat(btv->video_dev.name,"(");
- strcat(btv->video_dev.name, tvcards[btv->type].name);
- strcat(btv->video_dev.name,")");
+ sprintf(btv->video_dev.name,"BT%d%s(%.22s)",
+ btv->id,
+ (btv->id==848 && btv->revision==0x12) ? "A" : "",
+ tvcards[btv->type].name);
printk("%s\n",btv->video_dev.name);
/* board specific initialisations */
@@ -3357,6 +3384,9 @@ static int init_bt848(int i)
btv->vbibuf=0;
btv->field=btv->last_field=0;
+ btv->errors=0;
+ btv->needs_restart=0;
+
/* i2c */
btv->tuner_type=-1;
init_bttv_i2c(btv);
@@ -3458,7 +3488,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
{
u32 stat,astat;
u32 dstat;
- int count;
+ int count,i;
struct bttv *btv;
btv=(struct bttv *)dev_id;
@@ -3498,24 +3528,43 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->field++;
}
if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
- printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr,
- (astat&BT848_INT_SCERR) ? " SCERR" : "",
- (astat&BT848_INT_OCERR) ? " OCERR" : "",
- btread(BT848_RISC_COUNT));
- bt848_set_risc_jmps(btv,0);
- btwrite(0, BT848_SRESET);
- btwrite(virt_to_bus(btv->risc_jmp),
- BT848_RISC_STRT_ADD);
- bt848_set_geo(btv,0);
- bt848_set_risc_jmps(btv,-1);
-#if 0
- wake_up_interruptible(&btv->vbiq);
- wake_up_interruptible(&btv->capq);
-#endif
+ if (verbose)
+ printk("bttv%d: irq:%s%s risc_count=%08x\n",
+ btv->nr,
+ (astat&BT848_INT_SCERR) ? " SCERR" : "",
+ (astat&BT848_INT_OCERR) ? " OCERR" : "",
+ btread(BT848_RISC_COUNT));
+ btv->errors++;
+ if (btv->errors < BTTV_ERRORS) {
+ btand(~15, BT848_GPIO_DMA_CTL);
+ btwrite(virt_to_bus(btv->risc_jmp+2),
+ BT848_RISC_STRT_ADD);
+ bt848_set_geo(btv,0);
+ bt848_set_risc_jmps(btv,-1);
+ } else {
+ if (verbose)
+ printk("bttv%d: aiee: error loops\n",btv->nr);
+ /* cancel all outstanding grab requests */
+ btv->gq_in = 0;
+ btv->gq_out = 0;
+ btv->gq_grab = -1;
+ for (i = 0; i < gbuffers; i++)
+ if (btv->gbuf[i].stat == GBUFFER_GRABBING)
+ btv->gbuf[i].stat = GBUFFER_ERROR;
+ /* disable DMA */
+ btv->risc_cap_odd = 0;
+ btv->risc_cap_even = 0;
+ bt848_set_risc_jmps(btv,0);
+
+ btv->needs_restart = 1;
+ wake_up_interruptible(&btv->vbiq);
+ wake_up_interruptible(&btv->capq);
+ }
}
if (astat&BT848_INT_RISCI)
{
- IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr));
+ if (debug > 1)
+ printk("bttv%d: IRQ_RISCI\n",btv->nr);
/* captured VBI frame */
if (stat&(1<<28))
@@ -3527,11 +3576,12 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
/* captured full frame */
- if (stat&(2<<28))
+ if (stat&(2<<28) && btv->gq_grab != -1)
{
btv->last_field=btv->field;
if (debug)
printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab);
+ do_gettimeofday(&btv->gbuf[btv->gq_grab].tv);
btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE;
btv->gq_grab = -1;
if (btv->gq_in != btv->gq_out)
@@ -3662,6 +3712,11 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
btv->id=dev->device;
btv->irq=dev->irq;
btv->bt848_adr=dev->resource[0].start;
+ if (!request_mem_region(pci_resource_start(dev,0),
+ pci_resource_len(dev,0),
+ "bttv")) {
+ return -EBUSY;
+ }
if (btv->id >= 878)
btv->i2c_command = 0x83;
else
@@ -3720,15 +3775,15 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
{
printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
bttv_num);
- return -EINVAL;
+ goto fail;
}
if (result==-EBUSY)
{
printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
- return result;
+ goto fail;
}
if (result < 0)
- return result;
+ goto fail;
pci_set_master(dev);
@@ -3744,11 +3799,16 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
if (!(command&BT878_EN_TBFX))
{
printk("bttv: 430FX compatibility could not be enabled\n");
- return -1;
+ result = -1;
+ goto fail;
}
}
-
return 0;
+
+ fail:
+ release_mem_region(pci_resource_start(btv->dev,0),
+ pci_resource_len(btv->dev,0));
+ return result;
}
static int find_bt848(void)
@@ -3834,6 +3894,8 @@ static void release_bttv(void)
if (radio[btv->nr] && btv->radio_dev.minor != -1)
video_unregister_device(&btv->radio_dev);
+ release_mem_region(pci_resource_start(btv->dev,0),
+ pci_resource_len(btv->dev,0));
/* wake up any waiting processes
because shutdown flag is set, no new processes (in this queue)
are expected
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index 3a2cd7e21..c1e9b3e9a 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -21,7 +21,7 @@
#ifndef _BTTV_H_
#define _BTTV_H_
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,22)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,24)
#include <linux/types.h>
#include <linux/wait.h>
@@ -112,7 +112,8 @@ struct bttv_gbuf {
#define GBUFFER_GRABBING 1
#define GBUFFER_DONE 2
#define GBUFFER_ERROR 3
-
+ struct timeval tv;
+
u16 width;
u16 height;
u16 fmt;
@@ -122,8 +123,7 @@ struct bttv_gbuf {
unsigned long re;
};
-struct bttv
-{
+struct bttv {
struct video_device video_dev;
struct video_device radio_dev;
struct video_device vbi_dev;
@@ -193,6 +193,9 @@ struct bttv
int i2c_command;
int triton1;
+ int errors;
+ int needs_restart;
+
WAIT_QUEUE gpioq;
int shutdown;
};
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 03ff3a033..afc10a697 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -48,8 +47,6 @@
*/
/*#define BROKEN_MOUSE*/
-extern int sun_mouse_init(void);
-
struct busmouse_data {
struct miscdevice miscdev;
struct busmouse *ops;
@@ -70,7 +67,13 @@ struct busmouse_data {
#define DEV_TO_MOUSE(dev) MINOR_TO_MOUSE(MINOR(dev))
#define MINOR_TO_MOUSE(minor) ((minor) - FIRST_MOUSE)
+/*
+ * List of mice and guarding semaphore. You must take the semaphore
+ * before you take the misc device semaphore if you need both
+ */
+
static struct busmouse_data *busmouse_data[NR_MICE];
+static DECLARE_MUTEX(mouse_sem);
/* a mouse driver just has to interface with these functions
* These are !!!OLD!!! Do not use!!!
@@ -98,8 +101,7 @@ int add_mouse_buttonchange(int set, int value)
/* New interface. !!! Use this one !!!
* These routines will most probably be called from interrupt.
*/
-void
-busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
+void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
{
struct busmouse_data *mse = busmouse_data[mousedev];
int changed;
@@ -141,24 +143,21 @@ busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
}
}
-void
-busmouse_add_movement(int mousedev, int dx, int dy)
+void busmouse_add_movement(int mousedev, int dx, int dy)
{
struct busmouse_data *mse = busmouse_data[mousedev];
busmouse_add_movementbuttons(mousedev, dx, dy, mse->buttons);
}
-void
-busmouse_add_buttons(int mousedev, int clear, int eor)
+void busmouse_add_buttons(int mousedev, int clear, int eor)
{
struct busmouse_data *mse = busmouse_data[mousedev];
busmouse_add_movementbuttons(mousedev, 0, 0, (mse->buttons & ~clear) ^ eor);
}
-static int
-busmouse_fasync(int fd, struct file *filp, int on)
+static int busmouse_fasync(int fd, struct file *filp, int on)
{
struct busmouse_data *mse = (struct busmouse_data *)filp->private_data;
int retval;
@@ -169,8 +168,7 @@ busmouse_fasync(int fd, struct file *filp, int on)
return 0;
}
-static int
-busmouse_release(struct inode *inode, struct file *file)
+static int busmouse_release(struct inode *inode, struct file *file)
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
int ret = 0;
@@ -190,33 +188,34 @@ busmouse_release(struct inode *inode, struct file *file)
return ret;
}
-static int
-busmouse_open(struct inode *inode, struct file *file)
+static int busmouse_open(struct inode *inode, struct file *file)
{
struct busmouse_data *mse;
unsigned long flags;
unsigned int mousedev;
- int ret = 0;
+ int ret = -ENODEV;
mousedev = DEV_TO_MOUSE(inode->i_rdev);
if (mousedev >= NR_MICE)
return -EINVAL;
+
+ down(&mouse_sem);
mse = busmouse_data[mousedev];
if (!mse)
/* shouldn't happen, but... */
- return -ENODEV;
-
+ goto end;
+
if (mse->ops &&
mse->ops->open)
ret = mse->ops->open(inode, file);
if (ret)
- return ret;
+ goto end;
file->private_data = mse;
if (mse->active++)
- return 0;
+ goto end;
MOD_INC_USE_COUNT;
@@ -231,18 +230,17 @@ busmouse_open(struct inode *inode, struct file *file)
mse->buttons = 7;
spin_unlock_irqrestore(&mse->lock, flags);
-
- return 0;
+end:
+ up(&mouse_sem);
+ return ret;
}
-static ssize_t
-busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t busmouse_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
-static ssize_t
-busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t busmouse_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
DECLARE_WAITQUEUE(wait, current);
@@ -328,8 +326,7 @@ repeat:
return count;
}
-static unsigned int
-busmouse_poll(struct file *file, poll_table *wait)
+static unsigned int busmouse_poll(struct file *file, poll_table *wait)
{
struct busmouse_data *mse = (struct busmouse_data *)file->private_data;
@@ -351,8 +348,16 @@ struct file_operations busmouse_fops=
fasync: busmouse_fasync,
};
-int
-register_busmouse(struct busmouse *ops)
+/**
+ * register_busmouse - register a bus mouse interface
+ * @ops: busmouse structure for the mouse
+ *
+ * Registers a mouse with the driver. The return is mouse number on
+ * success and a negative errno code on an error. The passed ops
+ * structure most not be freed until the mouser is unregistered
+ */
+
+int register_busmouse(struct busmouse *ops)
{
unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
struct busmouse_data *mse;
@@ -364,13 +369,18 @@ register_busmouse(struct busmouse *ops)
return -EINVAL;
}
- if (busmouse_data[msedev])
- return -EBUSY;
-
mse = kmalloc(sizeof(*mse), GFP_KERNEL);
if (!mse)
return -ENOMEM;
+ down(&mouse_sem);
+ if (busmouse_data[msedev])
+ {
+ up(&mouse_sem);
+ kfree(mse);
+ return -EBUSY;
+ }
+
memset(mse, 0, sizeof(*mse));
mse->miscdev.minor = ops->minor;
@@ -385,13 +395,23 @@ register_busmouse(struct busmouse *ops)
ret = misc_register(&mse->miscdev);
if (!ret)
ret = msedev;
-
+ up(&mouse_sem);
+
return ret;
}
-int
-unregister_busmouse(int mousedev)
+/**
+ * unregister_busmouse - unregister a bus mouse interface
+ * @mousedev: Mouse number to release
+ *
+ * Unregister a previously installed mouse handler. The mousedev
+ * passed is the return code from a previous call to register_busmouse
+ */
+
+
+int unregister_busmouse(int mousedev)
{
+ int err = -EINVAL;
if (mousedev < 0)
return 0;
if (mousedev >= NR_MICE) {
@@ -400,32 +420,27 @@ unregister_busmouse(int mousedev)
return -EINVAL;
}
+ down(&mouse_sem);
+
if (!busmouse_data[mousedev]) {
printk(KERN_WARNING "busmouse: trying to free free mouse"
" on mousedev %d\n", mousedev);
- return -EINVAL;
+ goto fail;
}
if (busmouse_data[mousedev]->active) {
printk(KERN_ERR "busmouse: trying to free active mouse"
" on mousedev %d\n", mousedev);
- return -EINVAL;
+ goto fail;
}
- misc_deregister(&busmouse_data[mousedev]->miscdev);
+ err=misc_deregister(&busmouse_data[mousedev]->miscdev);
kfree(busmouse_data[mousedev]);
busmouse_data[mousedev] = NULL;
- return 0;
-}
-
-int __init
-bus_mouse_init(void)
-{
-#ifdef CONFIG_SUN_MOUSE
- sun_mouse_init();
-#endif
- return 0;
+fail:
+ up(&mouse_sem);
+ return err;
}
EXPORT_SYMBOL(busmouse_add_movementbuttons);
@@ -433,16 +448,3 @@ EXPORT_SYMBOL(busmouse_add_movement);
EXPORT_SYMBOL(busmouse_add_buttons);
EXPORT_SYMBOL(register_busmouse);
EXPORT_SYMBOL(unregister_busmouse);
-
-#ifdef MODULE
-int
-init_module(void)
-{
- return bus_mouse_init();
-}
-
-void
-cleanup_module(void)
-{
-}
-#endif
diff --git a/drivers/char/busmouse.h b/drivers/char/busmouse.h
index 3626334d9..4ba7c9ce4 100644
--- a/drivers/char/busmouse.h
+++ b/drivers/char/busmouse.h
@@ -23,6 +23,4 @@ extern void busmouse_add_buttons(int mousedev, int clear, int eor);
extern int register_busmouse(struct busmouse *ops);
extern int unregister_busmouse(int mousedev);
-extern int bus_mouse_init(void);
-
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 53939959f..30c7f4f89 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -57,6 +57,7 @@
* Head entry for the doubly linked miscdevice list
*/
static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list };
+static DECLARE_MUTEX(misc_sem);
/*
* Assigned numbers, used for dynamic minors
@@ -97,32 +98,42 @@ static int misc_read_proc(char *buf, char **start, off_t offset,
static int misc_open(struct inode * inode, struct file * file)
{
int minor = MINOR(inode->i_rdev);
- struct miscdevice *c = misc_list.next;
+ struct miscdevice *c;
+ int err = -ENODEV;
+
file->f_op = NULL;
+
+ down(&misc_sem);
+
+ c = misc_list.next;
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list) {
char modname[20];
+ up(&misc_sem);
sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
request_module(modname);
+ down(&misc_sem);
c = misc_list.next;
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list)
- return -ENODEV;
+ goto fail;
}
if ((file->f_op = c->fops) && file->f_op->open)
- return file->f_op->open(inode,file);
- else
- return -ENODEV;
+ err=file->f_op->open(inode,file);
+fail:
+ up(&misc_sem);
+ return err;
}
static struct file_operations misc_fops = {
open: misc_open,
};
+
/**
* misc_register - register a miscellaneous device
* @misc: device structure
@@ -145,12 +156,17 @@ int misc_register(struct miscdevice * misc)
if (misc->next || misc->prev)
return -EBUSY;
+ down(&misc_sem);
if (misc->minor == MISC_DYNAMIC_MINOR) {
int i = DYNAMIC_MINORS;
while (--i >= 0)
if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
break;
- if (i<0) return -EBUSY;
+ if (i<0)
+ {
+ up(&misc_sem);
+ return -EBUSY;
+ }
misc->minor = i;
}
if (misc->minor < DYNAMIC_MINORS)
@@ -171,6 +187,7 @@ int misc_register(struct miscdevice * misc)
misc->next = misc_list.next;
misc->prev->next = misc;
misc->next->prev = misc;
+ up(&misc_sem);
return 0;
}
@@ -189,6 +206,7 @@ int misc_deregister(struct miscdevice * misc)
int i = misc->minor;
if (!misc->next || !misc->prev)
return -EINVAL;
+ down(&misc_sem);
misc->prev->next = misc->next;
misc->next->prev = misc->prev;
misc->next = NULL;
@@ -197,6 +215,7 @@ int misc_deregister(struct miscdevice * misc)
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
+ up(&misc_sem);
return 0;
}
@@ -206,9 +225,6 @@ EXPORT_SYMBOL(misc_deregister);
int __init misc_init(void)
{
create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
-#ifdef CONFIG_BUSMOUSE
- bus_mouse_init();
-#endif
#if defined CONFIG_82C710_MOUSE
qpmouse_init();
#endif
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 97014d26a..ea9fded05 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -669,15 +669,15 @@ found:
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(year); /* This should never happen... */
- if (year > 10 && year < 44) {
+ if (year > 20 && year < 48) {
epoch = 1980;
guess = "ARC console";
- } else if (year >= 70 && year <= 72) {
- epoch = 1928;
- guess = "Digital DECstation";
- } else if (year < 96) {
+ } else if (year >= 48 && year < 70) {
epoch = 1952;
guess = "Digital UNIX";
+ } else if (year >= 70 && year < 100) {
+ epoch = 1928;
+ guess = "Digital DECstation";
}
if (guess)
printk("rtc: %s epoch (%lu) detected\n", guess, epoch);
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 2c512ccbf..a29a904dd 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -39,13 +39,17 @@
*
* 8/99: Generalized PCI support added. Theodore Ts'o
*
+ * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a
+ * few races on freeing buffers too.
+ * Alan Modra <alan@linuxcare.com>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/
-static char *serial_version = "4.92";
-static char *serial_revdate = "2000-1-27";
+static char *serial_version = "4.93";
+static char *serial_revdate = "2000-03-20";
/*
* Serial driver configuration section. Here are the various options:
@@ -98,7 +102,7 @@ static char *serial_revdate = "2000-1-27";
#endif
#endif
-#ifdef CONFIG_ISAPNP
+#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
#ifndef ENABLE_SERIAL_PNP
#define ENABLE_SERIAL_PNP
#endif
@@ -133,7 +137,7 @@ static char *serial_revdate = "2000-1-27";
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
-#if (defined(__i386__) && (CPU==386 || CPU==486))
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
#define SERIAL_INLINE
#endif
@@ -220,7 +224,6 @@ extern void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
unsigned int minor);
extern void tty_unregister_devfs (struct tty_driver *driver, unsigned minor);
-
static char *serial_name = "Serial driver";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -253,7 +256,7 @@ static unsigned long break_pressed; /* break, really ... */
#endif
static unsigned detect_uart_irq (struct serial_state * state);
-static void autoconfig(struct serial_state * info);
+static void autoconfig(struct serial_state * state);
static void change_speed(struct async_struct *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -321,9 +324,6 @@ static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
@@ -379,7 +379,7 @@ static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
return inb(info->port+1);
#endif
case SERIAL_IO_MEM:
- return readb(info->iomem_base +
+ return readb((unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
#ifdef CONFIG_SERIAL_GSC
case SERIAL_IO_GSC:
@@ -401,7 +401,7 @@ static _INLINE_ void serial_out(struct async_struct *info, int offset,
break;
#endif
case SERIAL_IO_MEM:
- writeb(value, info->iomem_base +
+ writeb(value, (unsigned long) info->iomem_base +
(offset<<info->iomem_reg_shift));
break;
#ifdef CONFIG_SERIAL_GSC
@@ -481,7 +481,9 @@ static void rs_start(struct tty_struct *tty)
return;
save_flags(flags); cli();
- if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+ if (info->xmit.head != info->xmit.tail
+ && info->xmit.buf
+ && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
@@ -633,7 +635,7 @@ static _INLINE_ void receive_chars(struct async_struct *info,
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
{
int count;
-
+
if (info->x_char) {
serial_outp(info, UART_TX, info->x_char);
info->state->icount.tx++;
@@ -642,8 +644,9 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
*intr_done = 0;
return;
}
- if ((info->xmit_cnt <= 0) || info->tty->stopped ||
- info->tty->hw_stopped) {
+ if (info->xmit.head == info->xmit.tail
+ || info->tty->stopped
+ || info->tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
return;
@@ -651,14 +654,16 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
count = info->xmit_fifo_size;
do {
- serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+ info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
info->state->icount.tx++;
- if (--info->xmit_cnt <= 0)
+ if (info->xmit.head == info->xmit.tail)
break;
} while (--count > 0);
- if (info->xmit_cnt < WAKEUP_CHARS)
+ if (CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
#ifdef SERIAL_DEBUG_INTR
@@ -667,7 +672,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
if (intr_done)
*intr_done = 0;
- if (info->xmit_cnt <= 0) {
+ if (info->xmit.head == info->xmit.tail) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
@@ -759,11 +764,11 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt(%d)...", irq);
#endif
-
+
info = IRQ_ports[irq];
if (!info)
return;
-
+
#ifdef CONFIG_SERIAL_MULTIPORT
multi = &rs_multiport[irq];
if (multi->port_monitor)
@@ -833,7 +838,7 @@ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d)...", irq);
#endif
-
+
info = IRQ_ports[irq];
if (!info || !info->tty)
return;
@@ -888,7 +893,7 @@ static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_multi(%d)...", irq);
#endif
-
+
info = IRQ_ports[irq];
if (!info)
return;
@@ -1026,7 +1031,7 @@ static void rs_timer(void)
serial_out(info, UART_IER, info->IER);
info = info->next_port;
} while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
+#ifdef CONFIG_SERIAL_MULTIPORT
if (rs_multiport[i].port1)
rs_interrupt_multi(i, NULL, NULL);
else
@@ -1117,10 +1122,10 @@ static int startup(struct async_struct * info)
free_page(page);
goto errout;
}
- if (info->xmit_buf)
+ if (info->xmit.buf)
free_page(page);
else
- info->xmit_buf = (unsigned char *) page;
+ info->xmit.buf = (unsigned char *) page;
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
@@ -1298,7 +1303,7 @@ static int startup(struct async_struct * info)
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
/*
* Set up serial timers...
@@ -1393,9 +1398,10 @@ static void shutdown(struct async_struct * info)
free_irq(state->irq, &IRQ_ports[state->irq]);
}
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
+ if (info->xmit.buf) {
+ unsigned long pg = (unsigned long) info->xmit.buf;
+ info->xmit.buf = 0;
+ free_page(pg);
}
info->IER = 0;
@@ -1570,7 +1576,7 @@ static void change_speed(struct async_struct *info,
* when DLL is 0.
*/
if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
- (info->state->revision == 0x5202))
+ (info->state->revision == 0x5201))
quot++;
info->quot = quot;
@@ -1654,7 +1660,7 @@ static void change_speed(struct async_struct *info,
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
}
serial_outp(info, UART_FCR, fcr); /* set fcr */
- }
+ }
restore_flags(flags);
}
@@ -1666,18 +1672,19 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->device, "rs_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!tty || !info->xmit.buf)
return;
save_flags(flags); cli();
- if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+ if (CIRC_SPACE(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) == 0) {
restore_flags(flags);
return;
}
- info->xmit_buf[info->xmit_head++] = ch;
- info->xmit_head &= SERIAL_XMIT_SIZE-1;
- info->xmit_cnt++;
+ info->xmit.buf[info->xmit.head] = ch;
+ info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
restore_flags(flags);
}
@@ -1689,8 +1696,10 @@ static void rs_flush_chars(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return;
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf)
+ if (info->xmit.head == info->xmit.tail
+ || tty->stopped
+ || tty->hw_stopped
+ || !info->xmit.buf)
return;
save_flags(flags); cli();
@@ -1709,16 +1718,19 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
- if (!tty || !info->xmit_buf || !tmp_buf)
+ if (!tty || !info->xmit.buf || !tmp_buf)
return 0;
save_flags(flags);
if (from_user) {
down(&tmp_buf_sem);
while (1) {
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ int c1;
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
if (c <= 0)
break;
@@ -1729,12 +1741,14 @@ static int rs_write(struct tty_struct * tty, int from_user,
break;
}
cli();
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- info->xmit_head = ((info->xmit_head + c) &
+ c1 = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
restore_flags(flags);
buf += c;
count -= c;
@@ -1742,27 +1756,29 @@ static int rs_write(struct tty_struct * tty, int from_user,
}
up(&tmp_buf_sem);
} else {
+ cli();
while (1) {
- cli();
- c = MIN(count,
- MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
if (c <= 0) {
- restore_flags(flags);
break;
}
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) &
+ memcpy(info->xmit.buf + info->xmit.head, buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
(SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- restore_flags(flags);
buf += c;
count -= c;
ret += c;
}
+ restore_flags(flags);
}
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(info->IER & UART_IER_THRI)) {
+ if (info->xmit.head != info->xmit.tail
+ && !tty->stopped
+ && !tty->hw_stopped
+ && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
@@ -1772,14 +1788,10 @@ static int rs_write(struct tty_struct * tty, int from_user,
static int rs_write_room(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
- int ret;
-
+
if (serial_paranoia_check(info, tty->device, "rs_write_room"))
return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
static int rs_chars_in_buffer(struct tty_struct *tty)
@@ -1788,7 +1800,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
return 0;
- return info->xmit_cnt;
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
static void rs_flush_buffer(struct tty_struct *tty)
@@ -1799,7 +1811,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ info->xmit.head = info->xmit.tail = 0;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -2071,8 +2083,9 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
* interrupt happens).
*/
if (info->x_char ||
- ((info->xmit_cnt > 0) && !info->tty->stopped &&
- !info->tty->hw_stopped))
+ ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+ SERIAL_XMIT_SIZE) > 0) &&
+ !info->tty->stopped && !info->tty->hw_stopped))
result &= TIOCSER_TEMT;
if (copy_to_user(value, &result, sizeof(int)))
@@ -2708,8 +2721,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
char_time = char_time / 5;
if (char_time == 0)
char_time = 1;
- if (timeout)
- char_time = MIN(char_time, timeout);
+ if (timeout && timeout < char_time)
+ char_time = timeout;
/*
* If the transmitter hasn't cleared in twice the approximate
* amount of time to send the entire FIFO, it probably won't
@@ -3060,7 +3073,7 @@ static inline int line_info(char *buf, struct serial_state *state)
int ret;
unsigned long flags;
- ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+ ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
state->line, uart_config[state->type].name,
state->port, state->irq);
@@ -3083,9 +3096,9 @@ static inline int line_info(char *buf, struct serial_state *state)
}
save_flags(flags); cli();
status = serial_in(info, UART_MSR);
- control = info ? info->MCR : serial_in(info, UART_MCR);
+ control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
restore_flags(flags);
-
+
stat_buf[0] = 0;
stat_buf[1] = 0;
if (control & UART_MCR_RTS)
@@ -3403,7 +3416,7 @@ static void autoconfig(struct serial_state * state)
state->type = PORT_UNKNOWN;
#ifdef SERIAL_DEBUG_AUTOCONF
- printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line,
+ printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
state->port, (unsigned) state->iomem_base);
#endif
@@ -3743,15 +3756,10 @@ pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
/* enable/disable interrupts */
p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
- if (dev->vendor == PCI_VENDOR_ID_PANACOM) {
- scratch = readl(p + 0x4c);
- if (enable)
- scratch |= 0x40;
- else
- scratch &= ~0x40;
- writel(scratch, p + 0x4c);
- } else
- writel(enable ? 0x41 : 0x00, p + 0x4c);
+ scratch = 0x41;
+ if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+ scratch = 0x43;
+ writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c);
iounmap(p);
if (!enable)
@@ -3806,7 +3814,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
break;
}
- writew(readw(p + 0x28) & data, p + 0x28);
+ writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
iounmap(p);
return 0;
}
@@ -4181,6 +4189,19 @@ static struct pci_board pci_boards[] __initdata = {
{ PCI_VENDOR_ID_USR, 0x1008,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE0, 1, 115200 },
+ /* Titan Electronic cards */
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 1, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 2, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 4, 921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE0, 4, 921600 },
/*
* Untested PCI modems, sent in from various folks...
*/
@@ -4188,10 +4209,9 @@ static struct pci_board pci_boards[] __initdata = {
{ PCI_VENDOR_ID_ROCKWELL, 0x1004,
0x1048, 0x1500,
SPCI_FL_BASE1, 1, 115200 },
-#ifdef CONFIG_DDB5074
+#if 0 /* No definition for PCI_DEVICE_ID_NEC_NILE4 */
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
- * Conditionally compiled in since this is a motherboard device.
*/
{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
PCI_ANY_ID, PCI_ANY_ID,
@@ -4306,18 +4326,41 @@ static void __init probe_serial_pci(void)
#ifdef ENABLE_SERIAL_PNP
static struct pci_board pnp_devices[] __initdata = {
+ /* Motorola VoiceSURFR 56K Modem */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
+ 1, 115200 },
+ /* AZT3005 PnP SOUND DEVICE */
+ { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* Boca Research 33,600 ACF Modem */
{ ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
+ /* Creative Modem Blaster Flash56 DI5601-1 */
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Creative Modem Blaster V.90 DI5660 */
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* Pace 56 Voice Internal Plug & Play Modem */
+ { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
/* SupraExpress 28.8 Data/Fax PnP modem */
{ ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0,
SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* US Robotics Sporster 33600 Modem */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ /* U.S. Robotics 56K FAX INT */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
+ SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+
/* These ID's are taken from M$ documentation */
/* Compaq 14400 Modem */
{ ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
@@ -4334,6 +4377,24 @@ static struct pci_board pnp_devices[] __initdata = {
{ 0, }
};
+static void inline avoid_irq_share(struct pci_dev *dev)
+{
+ int i, map = 0x1FF8;
+ struct serial_state *state = rs_table;
+ struct isapnp_irq *irq;
+ struct isapnp_resources *res = dev->sysdata;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ if (state->type != PORT_UNKNOWN)
+ clear_bit(state->irq, &map);
+ state++;
+ }
+
+ for ( ; res; res = res->alt)
+ for(irq = res->irq; irq; irq = irq->next)
+ irq->map = map;
+}
+
static void __init probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
@@ -4352,9 +4413,9 @@ static void __init probe_serial_pnp(void)
for (board = pnp_devices; board->vendor; board++) {
while ((dev = isapnp_find_dev(NULL, board->vendor,
board->device, dev))) {
-
- start_pci_pnp_board(dev, board);
-
+ if (board->flags & SPCI_FL_NO_SHIRQ)
+ avoid_irq_share(dev);
+ start_pci_pnp_board(dev, board);
}
}
@@ -4417,7 +4478,11 @@ int __init rs_init(void)
#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
#endif
+#if (LINUX_VERSION_CODE > 0x2032D)
serial_driver.name = "tts/%d";
+#else
+ serial_driver.name = "ttyS";
+#endif
serial_driver.major = TTY_MAJOR;
serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
serial_driver.num = NR_PORTS;
@@ -4461,7 +4526,11 @@ int __init rs_init(void)
* major number and the subtype code.
*/
callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D)
callout_driver.name = "cua/%d";
+#else
+ callout_driver.name = "cua";
+#endif
callout_driver.major = TTYAUX_MAJOR;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
#if (LINUX_VERSION_CODE >= 131343)
@@ -4503,7 +4572,7 @@ int __init rs_init(void)
&& (state->flags & ASYNC_AUTO_IRQ)
&& (state->port != 0))
state->irq = detect_uart_irq(state);
- printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->port, state->irq,
@@ -4538,7 +4607,7 @@ int __init rs_init(void)
* The port is then probed and if neccessary the IRQ is autodetected
* If this fails an error is returned.
*
- * On success the port is ready to use and the line number is returned.
+ * On success the port is ready to use and the line number is returned.
*/
int register_serial(struct serial_struct *req)
@@ -4548,8 +4617,7 @@ int register_serial(struct serial_struct *req)
struct serial_state *state;
struct async_struct *info;
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
for (i = 0; i < NR_PORTS; i++) {
if ((rs_table[i].port == req->port) &&
(rs_table[i].iomem_base == req->iomem_base))
@@ -4568,7 +4636,7 @@ int register_serial(struct serial_struct *req)
state = &rs_table[i];
if (rs_table[i].count) {
restore_flags(flags);
- printk("Couldn't configure serial #%d (port=%d,irq=%d): "
+ printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
"device already open\n", i, req->port, req->irq);
return -1;
}
@@ -4598,12 +4666,11 @@ int register_serial(struct serial_struct *req)
if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
state->irq = detect_uart_irq(state);
- printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+ printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
state->iomem_base ? "iomem" : "port",
state->iomem_base ? (unsigned long)state->iomem_base :
- (unsigned long)state->port,
- state->irq, uart_config[state->type].name);
+ state->port, state->irq, uart_config[state->type].name);
tty_register_devfs(&serial_driver, 0,
serial_driver.minor_start + state->line);
tty_register_devfs(&callout_driver, 0,
@@ -4625,8 +4692,7 @@ void unregister_serial(int line)
unsigned long flags;
struct serial_state *state = &rs_table[line];
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
if (state->info && state->info->tty)
tty_hangup(state->info->tty);
state->type = PORT_UNKNOWN;
@@ -4642,12 +4708,7 @@ void unregister_serial(int line)
}
#ifdef MODULE
-int init_module(void)
-{
- return rs_init();
-}
-
-void cleanup_module(void)
+void rs_fini(void)
{
unsigned long flags;
int e1, e2;
@@ -4655,8 +4716,7 @@ void cleanup_module(void)
struct async_struct *info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
timer_active &= ~(1 << RS_TIMER);
timer_table[RS_TIMER].fn = NULL;
timer_table[RS_TIMER].expires = 0;
@@ -4693,12 +4753,16 @@ void cleanup_module(void)
}
#endif
if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
+ unsigned long pg = (unsigned long) tmp_buf;
tmp_buf = NULL;
+ free_page(pg);
}
}
#endif /* MODULE */
+module_init(rs_init);
+module_exit(rs_fini);
+
/*
* ------------------------------------------------------------
@@ -4960,6 +5024,6 @@ void __init serial_console_init(void)
/*
Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
End:
*/
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 48e426623..67deb7f27 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -28,7 +28,7 @@
extern void wakeup_bdflush(int);
extern void reset_vc(unsigned int);
extern int console_loglevel;
-extern struct vfsmount *vfsmntlist;
+extern struct list_head super_blocks;
/* Machine specific power off function */
void (*sysrq_power_off)(void) = NULL;
@@ -174,22 +174,16 @@ static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard
}
}
-static void go_sync(kdev_t dev, int remount_flag)
+static void go_sync(struct super_block *sb, int remount_flag)
{
printk(KERN_INFO "%sing device %s ... ",
remount_flag ? "Remount" : "Sync",
- kdevname(dev));
+ kdevname(sb->s_dev));
if (remount_flag) { /* Remount R/O */
- struct super_block *sb = get_super(dev);
- struct vfsmount *vfsmnt;
int ret, flags;
struct list_head *p;
- if (!sb) {
- printk("Superblock not found\n");
- return;
- }
if (sb->s_flags & MS_RDONLY) {
printk("R/O\n");
return;
@@ -204,7 +198,7 @@ static void go_sync(kdev_t dev, int remount_flag)
}
file_list_unlock();
DQUOT_OFF(sb);
- fsync_dev(dev);
+ fsync_dev(sb->s_dev);
flags = MS_RDONLY;
if (sb->s_op && sb->s_op->remount_fs) {
ret = sb->s_op->remount_fs(sb, &flags, NULL);
@@ -217,7 +211,7 @@ static void go_sync(kdev_t dev, int remount_flag)
} else
printk("nothing to do\n");
} else {
- fsync_dev(dev); /* Sync only */
+ fsync_dev(sb->s_dev); /* Sync only */
printk("OK\n");
}
}
@@ -233,20 +227,24 @@ int emergency_sync_scheduled;
void do_emergency_sync(void)
{
- struct vfsmount *mnt;
+ struct super_block *sb;
int remount_flag;
lock_kernel();
remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
emergency_sync_scheduled = 0;
- for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
- if (is_local_disk(mnt->mnt_dev))
- go_sync(mnt->mnt_dev, remount_flag);
-
- for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
- if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev))
- go_sync(mnt->mnt_dev, remount_flag);
+ for (sb = sb_entry(super_blocks.next);
+ sb != sb_entry(&super_blocks);
+ sb = sb_entry(sb->s_list.next))
+ if (is_local_disk(sb->s_dev))
+ go_sync(sb, remount_flag);
+
+ for (sb = sb_entry(super_blocks.next);
+ sb != sb_entry(&super_blocks);
+ sb = sb_entry(sb->s_list.next))
+ if (!is_local_disk(sb->s_dev) && MAJOR(sb->s_dev))
+ go_sync(sb, remount_flag);
unlock_kernel();
printk(KERN_INFO "Done.\n");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index e1e504b79..1e0c22ee6 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2278,9 +2278,6 @@ void __init tty_init(void)
#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
espserial_init();
#endif
-#ifdef CONFIG_SERIAL
- rs_init();
-#endif
#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
vme_scc_init();
#endif
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index 029a76bd4..0ce42945d 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -159,10 +159,6 @@ static int wdt_status(void)
* Handle an interrupt from the board. These are raised when the status
* map changes in what the board considers an interesting way. That means
* a failure condition occuring.
- *
- * FIXME: We need to pass a dev_id as the PCI card can share irqs
- * although its arguably a _very_ dumb idea to share watchdog
- * irq lines
*/
void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -494,7 +490,7 @@ void cleanup_module(void)
int __init wdt_init(void)
{
printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq);
- if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL))
+ if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", &wdt_miscdev))
{
printk(KERN_ERR "IRQ %d is not free.\n", irq);
return -EIO;
diff --git a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/i2c-algo-pcf.c
index 39a16825e..3f740784e 100644
--- a/drivers/i2c/i2c-algo-pcf.c
+++ b/drivers/i2c/i2c-algo-pcf.c
@@ -581,7 +581,7 @@ int i2c_pcf_del_bus(struct i2c_adapter *adap)
return 0;
}
-static int __init i2c_algo_pcf_init (void)
+int __init i2c_algo_pcf_init (void)
{
printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n");
return 0;
diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in
index 2d4d2228c..15e1fd52b 100644
--- a/drivers/ide/Config.in
+++ b/drivers/ide/Config.in
@@ -38,11 +38,12 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING $CONFIG_BLK_DEV_AEC6210 $CONFIG_IDEDMA_PCI_WIP
dep_bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
dep_bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE $CONFIG_BLK_DEV_AMD7409 $CONFIG_IDEDMA_PCI_WIP
dep_bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID $CONFIG_BLK_DEV_CMD64X $CONFIG_IDEDMA_PCI_WIP
- dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_IDEDMA_PCI_EXPERIMENTAL
+ dep_bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
@@ -53,14 +54,14 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
dep_mbool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
dep_mbool ' PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
fi
- dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_IDEDMA_PCI_EXPERIMENTAL
+ dep_bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
dep_bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
dep_mbool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER $CONFIG_BLK_DEV_PDC202XX $CONFIG_IDEDMA_PCI_WIP
dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
- dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_IDEDMA_PCI_EXPERIMENTAL
- dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_IDEDMA_PCI_EXPERIMENTAL
+ dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+ dep_bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
fi
if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
diff --git a/drivers/ide/aec6210.c b/drivers/ide/aec6210.c
index cc0aca5fd..cf41fa3d0 100644
--- a/drivers/ide/aec6210.c
+++ b/drivers/ide/aec6210.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000
+ * linux/drivers/ide/aec6210.c Version 0.06 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -191,6 +191,7 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
@@ -230,6 +231,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
((id->dma_1word >> 8) & 7) ? ide_dma_on :
ide_dma_off_quietly);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
static void aec6210_tune_drive (ide_drive_t *drive, byte pio)
{
@@ -252,6 +254,7 @@ static void aec6210_tune_drive (ide_drive_t *drive, byte pio)
(void) aec6210_tune_chipset(drive, speed);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -314,6 +317,7 @@ int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_AEC6210_TUNING */
unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
@@ -336,13 +340,13 @@ void __init ide_init_aec6210 (ide_hwif_t *hwif)
{
#ifdef CONFIG_AEC6210_TUNING
hwif->tuneproc = &aec6210_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
- if (hwif->dma_base) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (hwif->dma_base)
hwif->dmaproc = &aec6210_dmaproc;
- } else {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_AEC6210_TUNING */
}
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
index b3ffaa529..ff87917c5 100644
--- a/drivers/ide/ali14xx.c
+++ b/drivers/ide/ali14xx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996
+ * linux/drivers/ide/ali14xx.c Version 0.03 Feb 09, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index bc3d2b9e3..b043d6774 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000
+ * linux/drivers/ide/alim15x3.c Version 0.09 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Michel Aubry, Maintainer
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -37,7 +37,7 @@
static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
extern int (*ali_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-struct pci_dev *bmide_dev;
+static struct pci_dev *bmide_dev;
char *fifo[4] = {
"FIFO Off",
@@ -67,7 +67,7 @@ char *channel_status[8] = {
"error DRQ busy"
};
-static int ali_get_info(char *buffer, char **addr, off_t offset, int count)
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
{
byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
unsigned int bibma;
@@ -356,6 +356,12 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
return (err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ ali15x3_tune_drive(drive, 5);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
{
struct hd_driveid *id = drive->id;
@@ -401,26 +407,21 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- ali15x3_tune_drive(drive, 5);
-}
-
-
static byte ali15x3_can_ultra (ide_drive_t *drive)
{
+#ifdef CONFIG_WDC_ALI15X3
struct hd_driveid *id = drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
-#if 0
- if (m5229_revision < 0x20) {
-#else
if (m5229_revision <= 0x20) {
-#endif
return 0;
} else if ((m5229_revision < 0xC2) &&
- ((drive->media!=ide_disk) ||
- (chip_is_1543c_e &&
- strstr(id->model, "WDC ")))) {
+#ifdef CONFIG_WDC_ALI15X3
+ ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+ (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+ (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
return 0;
} else {
return 1;
@@ -495,6 +496,7 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
{
@@ -519,9 +521,11 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
}
#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
- ali_proc = 1;
- bmide_dev = dev;
- ali_display_info = &ali_get_info;
+ if (!ali_proc) {
+ ali_proc = 1;
+ bmide_dev = dev;
+ ali_display_info = &ali_get_info;
+ }
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
return 0;
@@ -666,18 +670,20 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
}
hwif->tuneproc = &ali15x3_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ hwif->autodma = 0;
+ return;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
/*
* M1543C or newer for DMAing
*/
hwif->dmaproc = &ali15x3_dmaproc;
hwif->autodma = 1;
- } else {
- hwif->autodma = 0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
}
- return;
}
void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
diff --git a/drivers/ide/amd7409.c b/drivers/ide/amd7409.c
index 7d2018029..2d44044dd 100644
--- a/drivers/ide/amd7409.c
+++ b/drivers/ide/amd7409.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000
+ * linux/drivers/ide/amd7409.c Version 0.04 Mar. 18, 2000
*
* Copyright (C) 2000 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -194,49 +194,6 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
return (err);
}
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- byte udma_66 = ((id->hw_config & 0x2000) &&
- (HWIF(drive)->udma_four)) ? 1 : 0;
- byte speed = 0x00;
- int rval;
-
- if ((id->dma_ultra & 0x0010) && (udma_66)) {
- speed = XFER_UDMA_4;
- } else if ((id->dma_ultra & 0x0008) && (udma_66)) {
- speed = XFER_UDMA_3;
- } else if (id->dma_ultra & 0x0004) {
- speed = XFER_UDMA_2;
- } else if (id->dma_ultra & 0x0002) {
- speed = XFER_UDMA_1;
- } else if (id->dma_ultra & 0x0001) {
- speed = XFER_UDMA_0;
- } else if (id->dma_mword & 0x0004) {
- speed = XFER_MW_DMA_2;
- } else if (id->dma_mword & 0x0002) {
- speed = XFER_MW_DMA_1;
- } else if (id->dma_mword & 0x0001) {
- speed = XFER_MW_DMA_0;
- } else {
- return ((int) ide_dma_off_quietly);
- }
-
- (void) amd7409_tune_chipset(drive, speed);
-
- rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
- ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
- ((id->dma_mword >> 8) & 7) ? ide_dma_on :
- ide_dma_off_quietly);
-
- return rval;
-}
-
static void config_chipset_for_pio (ide_drive_t *drive)
{
unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
@@ -288,6 +245,52 @@ static void amd7409_tune_drive (ide_drive_t *drive, byte pio)
(void) amd7409_tune_chipset(drive, speed);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ byte udma_66 = ((id->hw_config & 0x2000) &&
+ (HWIF(drive)->udma_four)) ? 1 : 0;
+ byte speed = 0x00;
+ int rval;
+
+ if ((id->dma_ultra & 0x0010) && (udma_66)) {
+ speed = XFER_UDMA_4;
+ } else if ((id->dma_ultra & 0x0008) && (udma_66)) {
+ speed = XFER_UDMA_3;
+ } else if (id->dma_ultra & 0x0004) {
+ speed = XFER_UDMA_2;
+ } else if (id->dma_ultra & 0x0002) {
+ speed = XFER_UDMA_1;
+ } else if (id->dma_ultra & 0x0001) {
+ speed = XFER_UDMA_0;
+ } else if (id->dma_mword & 0x0004) {
+ speed = XFER_MW_DMA_2;
+ } else if (id->dma_mword & 0x0002) {
+ speed = XFER_MW_DMA_1;
+ } else if (id->dma_mword & 0x0001) {
+ speed = XFER_MW_DMA_0;
+ } else {
+ return ((int) ide_dma_off_quietly);
+ }
+
+ (void) amd7409_tune_chipset(drive, speed);
+
+ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+
+ return rval;
+}
+
+
+
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -351,6 +354,7 @@ int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name)
{
@@ -370,9 +374,11 @@ unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name)
printk("%s: simplex device: DMA will fail!!\n", name);
}
#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
- amd7409_proc = 1;
- bmide_dev = dev;
- amd7409_display_info = &amd7409_get_info;
+ if (!amd7409_proc) {
+ amd7409_proc = 1;
+ bmide_dev = dev;
+ amd7409_display_info = &amd7409_get_info;
+ }
#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
return 0;
@@ -396,8 +402,17 @@ unsigned int __init ata66_amd7409 (ide_hwif_t *hwif)
void __init ide_init_amd7409 (ide_hwif_t *hwif)
{
hwif->tuneproc = &amd7409_tune_drive;
+
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+ return;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
if (hwif->dma_base) {
hwif->dmaproc = &amd7409_dmaproc;
+ hwif->autodma = 1;
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
index 3e1cfcd33..da53155c1 100644
--- a/drivers/ide/buddha.c
+++ b/drivers/ide/buddha.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/buddha.c -- Amiga Buddha and Catweasel IDE Driver
+ * linux/drivers/ide/buddha.c -- Amiga Buddha and Catweasel IDE Driver
*
* Copyright (C) 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index b2077df6d..7a094d497 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996
+ * linux/drivers/ide/cmd640.c Version 1.02 Sep 01, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index b2ae2e6b8..2aaf83b26 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -1,5 +1,7 @@
/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
*
+ * linux/drivers/ide/cmd64x.c Version 1.21 Mar. 18, 2000
+ *
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Note, this driver is not used at all on other systems because
* there the "BIOS" has done all of the following already.
@@ -116,19 +118,27 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
- (reg72&0x80) ? "dis" : " en", (reg7a&0x80) ? "dis" : " en");
+ (reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (reg72&0x20) ? "yes" : "no ", (reg72&0x40) ? "yes" : "no ", (reg7a&0x20) ? "yes" : "no ", (reg7a&0x40) ? "yes" : "no " );
+ (reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no ");
p += sprintf(p, "DMA Mode: %s(%s) %s(%s) %s(%s) %s(%s)\n",
(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
- (reg72&0x20)?(((reg73&0x15)==0x15)?"4":((reg73&0x25)==0x25)?"3":((reg73&0x10)==0x10)?"2":((reg73&0x20)==0x20)?"1":((reg73&0x30)==0x30)?"0":"X"):"?",
+ (reg72&0x20)?( ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+ ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+ ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):"X"):"?",
(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
- (reg72&0x40)?(((reg73&0x4A)==0x4A)?"4":((reg73&0x8A)==0x8A)?"3":((reg73&0x40)==0x40)?"2":((reg73&0x80)==0x80)?"1":((reg73&0xC0)==0xC0)?"0":"X"):"?",
+ (reg72&0x40)?( ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+ ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+ ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):"X"):"?",
(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
- (reg7a&0x20)?(((reg7b&0x15)==0x15)?"4":((reg7b&0x25)==0x25)?"3":((reg7b&0x10)==0x10)?"2":((reg7b&0x20)==0x20)?"1":((reg7b&0x30)==0x30)?"0":"X"):"?",
+ (reg7a&0x20)?( ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+ ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+ ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):"X"):"?",
(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
- (reg7a&0x40)?(((reg7b&0x4A)==0x4A)?"4":((reg7b&0x8A)==0x8A)?"3":((reg7b&0x40)==0x40)?"2":((reg7b&0x80)==0x80)?"1":((reg7b&0xC0)==0xC0)?"0":"X"):"?" );
+ (reg7a&0x40)?( ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+ ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+ ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):"X"):"?" );
p += sprintf(p, "PIO Mode: %s %s %s %s\n",
"?", "?", "?", "?");
@@ -155,6 +165,22 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
return p-buffer; /* => must be less than 4k! */
}
+
+#if 0
+static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
+{
+ char *p = buf;
+ p += sprintf(p, "thingy stuff\n");
+ return (char *)p;
+}
+static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ p = cmd64x_chipset_data(buffer, bmide_dev);
+ return p-buffer; /* hoping it is less than 4K... */
+}
+#endif
+
#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
byte cmd64x_proc = 0;
@@ -305,76 +331,60 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
setup_count, active_count, recovery_count);
}
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ byte speed= 0x00;
+ byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ cmd64x_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
{
-#if 0
- struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- unsigned long dma_base = hwif->dma_base;
byte unit = (drive->select.b.unit & 0x01);
-
- u8 reg72 = 0, reg73 = 0; /* primary */
- u8 reg7a = 0, reg7b = 0; /* secondary */
- u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
- u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
- u8 regU = (hwif->channel) ? 2 : 0;
- u8 regD = (hwif->channel) ? 2 : 0;
-
- (void) pci_read_config_byte(dev, BMIDESR0, &reg72);
- (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
- (void) pci_read_config_byte(dev, BMIDESR1, &reg7a);
- (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
-
+ int err = 0;
+
+ u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+ u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+ u8 regU = 0;
+ u8 regD = 0;
+
+ (void) pci_read_config_byte(dev, pciD, &regD);
+ (void) pci_read_config_byte(dev, pciU, &regU);
+ regD &= ~(unit ? 0x40 : 0x20);
+ regU &= ~(unit ? 0xCA : 0x35);
+ (void) pci_write_config_byte(dev, pciD, regD);
+ (void) pci_write_config_byte(dev, pciU, regU);
+
+ (void) pci_read_config_byte(dev, pciD, &regD);
+ (void) pci_read_config_byte(dev, pciU, &regU);
switch(speed) {
- case XFER_UDMA_4:
- pciU = unit ? 0x4A : 0x15;
- case XFER_UDMA_3:
- pciU = unit ? 0x8A : 0x25;
- case XFER_UDMA_2:
- pciU = unit ? 0x42 : 0x11;
- case XFER_UDMA_1:
- pciU = unit ? 0x82 : 0x21;
- case XFER_UDMA_0:
- pciU = unit ? 0xC2 : 0x31
-(reg73&0x15)?"4":(reg73&0x25)?"3":(reg73&0x11)?"2":(reg73&0x21)?"1":(reg73&0x31)?"0":"X",
-(reg73&0x4A)?"4":(reg73&0x8A)?"3":(reg73&0x42)?"2":(reg73&0x82)?"1":(reg73&0xC2)?"0":"X",
-(reg7b&0x15)?"4":(reg7b&0x25)?"3":(reg7b&0x11)?"2":(reg7b&0x21)?"1":(reg7b&0x31)?"0":"X",
-(reg7b&0x4A)?"4":(reg7b&0x8A)?"3":(reg7b&0x42)?"2":(reg7b&0x82)?"1":(reg7b&0xC2)?"0":"X",
-
- case XFER_MW_DMA_2:
- pciD = unit ? 0x40 : 0x10;
- case XFER_MW_DMA_1:
- pciD = unit ? 0x80 : 0x20;
- case XFER_MW_DMA_0:
- pciD = unit ? 0xC0 : 0x30;
- case XFER_SW_DMA_2:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
-(reg73&0x10)?"2":(reg73&0x20)?"1":(reg73&0x30)?"0":"X",
-(reg73&0x40)?"2":(reg73&0x80)?"1":(reg73&0xC0)?"0":"X",
-(reg7b&0x10)?"2":(reg7b&0x20)?"1":(reg7b&0x30)?"0":"X",
-(reg7b&0x40)?"2":(reg7b&0x80)?"1":(reg7b&0xC0)?"0":"X" );
-
+ case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break;
+ case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break;
+ case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break;
+ case XFER_UDMA_1: regU |= (unit ? 0x82 : 0x21); break;
+ case XFER_UDMA_0: regU |= (unit ? 0xC2 : 0x31); break;
+ case XFER_MW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
+ case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
+ case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
+ case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
+ case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
+ case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
default:
return 1;
}
+ (void) pci_write_config_byte(dev, pciU, regU);
+ err = ide_config_drive_speed(drive, speed);
+ regD |= (unit ? 0x40 : 0x20);
+ (void) pci_write_config_byte(dev, pciD, regD);
- (void) ide_config_drive_speed(drive, speed);
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-#endif
- return 0;
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
- byte speed = 0x00;
- byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
- cmd64x_tuneproc(drive, set_pio);
- speed = XFER_PIO_0 + set_pio;
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
+ return err;
}
static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
@@ -382,21 +392,17 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- unsigned long dma_base = hwif->dma_base;
- byte unit = (drive->select.b.unit & 0x01);
byte speed = 0x00;
byte set_pio = 0x00;
- byte udma_timing_bits = 0x00;
byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
- /* int drive_number = ((hwif->channel ? 2 : 0) + unit); */
int rval;
switch(dev->device) {
- case PCI_DEVICE_ID_CMD_643:
- case PCI_DEVICE_ID_CMD_646:
case PCI_DEVICE_ID_CMD_648:
+ case PCI_DEVICE_ID_CMD_646:
+ case PCI_DEVICE_ID_CMD_643:
default:
break;
}
@@ -416,22 +422,16 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
* in the 646U2.
* So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
*/
-
if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
speed = XFER_UDMA_4;
- udma_timing_bits = 0x10; /* 2 clock */
} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
speed = XFER_UDMA_3;
- udma_timing_bits = 0x20; /* 3 clock */
} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
speed = XFER_UDMA_2;
- udma_timing_bits = 0x10; /* 2 clock */
} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
speed = XFER_UDMA_1;
- udma_timing_bits = 0x20; /* 3 clock */
} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
speed = XFER_UDMA_0;
- udma_timing_bits = 0x30; /* 4 clock */
} else if (id->dma_mword & 0x0004) {
speed = XFER_MW_DMA_2;
} else if (id->dma_mword & 0x0002) {
@@ -453,27 +453,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
if (set_pio)
return ((int) ide_dma_off_quietly);
-#if 1
- /*
- * This the alternate access method. :-(
- * The correct method is to directly setup the pci-config space.
- */
- (void) ide_config_drive_speed(drive, speed);
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-
- if (speed >= XFER_UDMA_0) {
- byte udma_ctrl = inb(dma_base + 3);
- /* Put this channel into UDMA mode. */
- udma_ctrl |= (1 << unit);
- udma_ctrl &= ~(0x04 << unit);
- if (udma_66)
- udma_ctrl |= (0x04 << unit);
- udma_ctrl &= ~(0x30 << (unit * 2));
- udma_ctrl |= (udma_timing_bits << (unit * 2));
- outb(udma_ctrl, dma_base+3);
- }
-#endif
-
if (tune_chipset_for_dma(drive, speed))
return ((int) ide_dma_off);
@@ -500,17 +479,14 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
class_rev &= 0xff;
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
+ can_ultra_66 = 1;
case PCI_DEVICE_ID_CMD_643:
- can_ultra_33 = 1;
- can_ultra_66 = 0;
+ can_ultra_33 = 1;
break;
case PCI_DEVICE_ID_CMD_646:
- can_ultra_33 = (class_rev >= 0x05) ? 1 : 0;
- can_ultra_66 = 0;
- break;
- case PCI_DEVICE_ID_CMD_648:
- can_ultra_33 = 1;
- can_ultra_66 = 1;
+ can_ultra_33 = (class_rev >= 0x05) ? 1 : 0;
+ can_ultra_66 = 0;
break;
default:
return hwif->dmaproc(ide_dma_off, drive);
@@ -595,6 +571,7 @@ static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return cmd64x_dmaproc(func, drive);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
{
@@ -604,9 +581,11 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
-#if 0
- if (dev->resource[PCI_ROM_RESOURCE].start)
+#ifdef __i386__
+ if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+ }
#endif
switch(dev->device) {
@@ -702,7 +681,9 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
+#ifdef CONFIG_BLK_DEV_IDEDMA
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
case PCI_DEVICE_ID_CMD_643:
hwif->dmaproc = &cmd64x_dmaproc;
break;
@@ -714,10 +695,8 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
hwif->dmaproc = &cmd64x_dmaproc;
}
break;
- case PCI_DEVICE_ID_CMD_648:
- hwif->dmaproc = &cmd64x_dmaproc;
- break;
default:
break;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
index bb68f7b2e..b160d7716 100644
--- a/drivers/ide/cs5530.c
+++ b/drivers/ide/cs5530.c
@@ -1,5 +1,8 @@
/*
- * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000
+ * linux/drivers/ide/cs5530.c Version 0.6 Mar. 18, 2000
+ *
+ * Copyright (C) 2000 Andre Hedrick <andre@suse.com>
+ * Ditto of GNU General Public License.
*
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -23,6 +26,7 @@
#include <linux/ide.h>
#include <asm/io.h>
#include <asm/irq.h>
+
#include "ide_modes.h"
#define DISPLAY_CS5530_TIMINGS
@@ -120,6 +124,7 @@ static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "aut
}
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* cs5530_config_dma() handles selection/setting of DMA/UDMA modes
* for both the chipset and drive.
@@ -241,6 +246,7 @@ int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return ide_dmaproc(func, drive);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* Initialize the cs5530 bridge for reliable IDE DMA operation.
@@ -322,9 +328,11 @@ unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
restore_flags(flags);
#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
- cs5530_proc = 1;
- bmide_dev = dev;
- cs5530_display_info = &cs5530_get_info;
+ if (!cs5530_proc) {
+ cs5530_proc = 1;
+ bmide_dev = dev;
+ cs5530_display_info = &cs5530_get_info;
+ }
#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
return 0;
@@ -343,7 +351,12 @@ void __init ide_init_cs5530 (ide_hwif_t *hwif)
} else {
unsigned int basereg, d0_timings;
+#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &cs5530_dmaproc;
+#else
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
hwif->tuneproc = &cs5530_tuneproc;
basereg = CS5530_BASEREG(hwif);
d0_timings = inl(basereg+0);
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index cfff0381c..4498b754b 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999
+ * linux/drivers/ide/cy82c693.c Version 0.34 Dec. 13, 1999
*
* Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer
* Copyright (C) 1998-99 Andre Hedrick, Integrater
@@ -44,6 +44,7 @@
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -176,6 +177,7 @@ static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
p_pclk->time_8 = (byte)clk1;
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* set DMA mode a specific channel for CY82C693
*/
@@ -262,6 +264,7 @@ static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive);
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* tune ide drive - set PIO mode
@@ -432,10 +435,14 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif)
{
hwif->chipset = ide_cy82c693;
hwif->tuneproc = &cy82c693_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &cy82c693_dmaproc;
- } else {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->autodma = 1;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
index d8838e111..28537d048 100644
--- a/drivers/ide/dtc2278.c
+++ b/drivers/ide/dtc2278.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996
+ * linux/drivers/ide/dtc2278.c Version 0.02 Feb 10, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c
index 7bce07517..096d75fc0 100644
--- a/drivers/ide/falconide.c
+++ b/drivers/ide/falconide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/falconide.c -- Atari Falcon IDE Driver
+ * linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
*
* Created 12 Jul 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index 29cceb20e..170bf16f7 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/gayle.c -- Amiga Gayle IDE Driver
+ * linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
*
* Created 9 Jul 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c
index 5520c17b0..b64a9738c 100644
--- a/drivers/ide/hd.c
+++ b/drivers/ide/hd.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hd.c
+ * linux/drivers/ide/hd.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
diff --git a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
index 425ce35a4..a68e7f740 100644
--- a/drivers/ide/hpt34x.c
+++ b/drivers/ide/hpt34x.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000
+ * linux/drivers/ide/hpt34x.c Version 0.30 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -144,6 +144,59 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+
+ byte timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default:
+ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+ break;
+ }
+ (void) hpt34x_tune_chipset(drive, speed);
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+
+ switch(pio) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default: speed = XFER_PIO_0;break;
+ }
+ hpt34x_clear_chipset(drive);
+ (void) hpt34x_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
@@ -195,58 +248,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
ide_dma_off_quietly);
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
-
- byte timing, speed, pio;
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default:
- speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
- break;
- }
- (void) hpt34x_tune_chipset(drive, speed);
-}
-
-static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
-
- switch(pio) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default: speed = XFER_PIO_0;break;
- }
- hpt34x_clear_chipset(drive);
- (void) hpt34x_tune_chipset(drive, speed);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -347,6 +348,7 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* If the BIOS does not set the IO base addaress to XX00, 343 will fail.
@@ -395,9 +397,11 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
__restore_flags(flags); /* local CPU only */
#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
- hpt34x_proc = 1;
- bmide_dev = dev;
- hpt34x_display_info = &hpt34x_get_info;
+ if (!hpt34x_proc) {
+ hpt34x_proc = 1;
+ bmide_dev = dev;
+ hpt34x_display_info = &hpt34x_get_info;
+ }
#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
return dev->irq;
@@ -406,6 +410,8 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
void __init ide_init_hpt34x (ide_hwif_t *hwif)
{
hwif->tuneproc = &hpt34x_tune_drive;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
unsigned short pcicmd = 0;
@@ -416,4 +422,9 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif)
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index d2f2fb433..fd5971ef9 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000
+ * linux/drivers/ide/hpt366.c Version 0.17 Mar. 18, 2000
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -259,6 +259,64 @@ static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ byte timing, speed, pio;
+
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_pio\n", drive->name);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default:
+ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+ break;
+ }
+#if HPT366_DEBUG_DRIVE_INFO
+ printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed);
+#endif /* HPT366_DEBUG_DRIVE_INFO */
+ (void) hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt366_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+ switch(pio) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default: speed = XFER_PIO_0;break;
+ }
+ (void) hpt366_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
@@ -347,63 +405,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
-
-#if HPT366_DEBUG_DRIVE_INFO
- printk("%s: config_chipset_for_pio\n", drive->name);
-#endif /* HPT366_DEBUG_DRIVE_INFO */
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 :
- (drive->id->tPIO & 2) ? 0x02 :
- (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default:
- speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
- break;
- }
-#if HPT366_DEBUG_DRIVE_INFO
- printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed);
-#endif /* HPT366_DEBUG_DRIVE_INFO */
- (void) hpt366_tune_chipset(drive, speed);
-}
-
-static void hpt366_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
- switch(pio) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default: speed = XFER_PIO_0;break;
- }
- (void) hpt366_tune_chipset(drive, speed);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -478,6 +479,7 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
{
@@ -532,13 +534,20 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
hwif->tuneproc = &hpt366_tune_drive;
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &hpt366_dmaproc;
+ hwif->autodma = 1;
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
index 6b7d5af72..1c0b55dac 100644
--- a/drivers/ide/ht6560b.c
+++ b/drivers/ide/ht6560b.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000
+ * linux/drivers/ide/ht6560b.c Version 0.07 Feb 1, 2000
*
* Copyright (C) 1995-2000 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index d0e8f8328..213ddbff0 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/icside.c
+ * linux/drivers/ide/icside.c
*
* Copyright (c) 1996,1997 Russell King.
*
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 641783e9c..17cc3eb88 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1,5 +1,6 @@
/*
- * linux/drivers/block/ide-cd.c
+ * linux/drivers/ide/ide-cd.c
+ *
* Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov>
* Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
* Copyright (C) 1998, 1999 Jens Axboe <axboe@image.dk>
@@ -276,6 +277,7 @@
#define IDECD_VERSION "4.56"
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -2400,21 +2402,10 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
printk (", %dkB Cache", be16_to_cpu(buf.cap.buffer_size));
- if (drive->using_dma) {
- if ((drive->id->field_valid & 4) &&
- (drive->id->hw_config & 0x2000) &&
- (HWIF(drive)->udma_four) &&
- (drive->id->dma_ultra & (drive->id->dma_ultra >> 11) & 3)) {
- printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
- } else if ((drive->id->field_valid & 4) &&
- (drive->id->dma_ultra & (drive->id->dma_ultra >> 8) & 7)) {
- printk(", UDMA(33)"); /* UDMA BIOS-enabled! */
- } else if (drive->id->field_valid & 4) {
- printk(", (U)DMA"); /* Can be BIOS-enabled! */
- } else {
- printk(", DMA");
- }
- }
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (drive->using_dma)
+ (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
return nslots;
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 1eb48ef6c..77937dd4b 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide_cd.h
+ * linux/drivers/ide/ide_cd.h
*
* Copyright (C) 1996-98 Erik Andersen
* Copyright (C) 1998-2000 Jens Axboe
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 2ef50f285..33014bc06 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999
+ * linux/drivers/ide/ide-disk.c Version 1.09 April 23, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -821,21 +821,10 @@ static void idedisk_setup (ide_drive_t *drive)
drive->name, id->model,
capacity/2048L, id->buf_size/2,
drive->bios_cyl, drive->bios_head, drive->bios_sect);
-
- if (drive->using_dma) {
- if ((id->field_valid & 4) && (id->hw_config & 0x2000) &&
- (HWIF(drive)->udma_four) &&
- (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
- printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
- } else if ((id->field_valid & 4) &&
- (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
- printk(", UDMA(33)"); /* UDMA BIOS-enabled! */
- } else if (id->field_valid & 4) {
- printk(", (U)DMA"); /* Can be BIOS-enabled! */
- } else {
- printk(", DMA");
- }
- }
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (drive->using_dma)
+ (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
drive->mult_count = 0;
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 751424831..9caffd2f1 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999
+ * linux/drivers/ide/ide-dma.c Version 4.09 April 23, 1999
*
* Copyright (c) 1999 Andre Hedrick
* May be copied or modified under the terms of the GNU General Public License
@@ -354,6 +354,29 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
return 0;
}
+int report_drive_dmaing (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ if ((id->field_valid & 4) && (id->hw_config & 0x2000) &&
+ (HWIF(drive)->udma_four) &&
+ (id->dma_ultra & (id->dma_ultra >> 11) & 3)) {
+ if ((id->dma_ultra >> 12) & 1) {
+ printk(", UDMA(66)"); /* UDMA BIOS-enabled! */
+ } else {
+ printk(", UDMA(44)"); /* UDMA BIOS-enabled! */
+ }
+ } else if ((id->field_valid & 4) &&
+ (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+ printk(", UDMA(33)"); /* UDMA BIOS-enabled! */
+ } else if (id->field_valid & 4) {
+ printk(", (U)DMA"); /* Can be BIOS-enabled! */
+ } else {
+ printk(", DMA");
+ }
+ return 1;
+}
+
static int config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -453,6 +476,9 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
case ide_dma_bad_drive:
case ide_dma_good_drive:
return check_drive_lists(drive, (func == ide_dma_good_drive));
+ case ide_dma_verbose:
+ return report_drive_dmaing(drive);
+ case ide_dma_retune:
case ide_dma_lostirq:
case ide_dma_timeout:
printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func);
diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
index 3f29ed591..371f57ad8 100644
--- a/drivers/ide/ide-features.c
+++ b/drivers/ide/ide-features.c
@@ -100,6 +100,8 @@ char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
case ide_dma_test_irq: return("ide_dma_test_irq");
case ide_dma_bad_drive: return("ide_dma_bad_drive");
case ide_dma_good_drive: return("ide_dma_good_drive");
+ case ide_dma_verbose: return("ide_dma_verbose");
+ case ide_dma_retune: return("ide_dma_retune");
case ide_dma_lostirq: return("ide_dma_lostirq");
case ide_dma_timeout: return("ide_dma_timeout");
default: return("unknown");
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 58eb2411d..55349e92a 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999
+ * linux/drivers/ide/ide-floppy.c Version 0.9 Jul 4, 1999
*
* Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
*/
diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
index 4c67d0911..29de5bb09 100644
--- a/drivers/ide/ide-geometry.c
+++ b/drivers/ide/ide-geometry.c
@@ -1,9 +1,9 @@
/*
- * linux/drivers/block/ide-geometry.c
+ * linux/drivers/ide/ide-geometry.c
*/
#include <linux/config.h>
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_IDE
#include <linux/ide.h>
#include <asm/io.h>
@@ -211,4 +211,4 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
drive->bios_cyl, drive->bios_head, drive->bios_sect);
return ret;
}
-#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif /* CONFIG_IDE */
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index f667ee6dd..cdd10f6e1 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999
+ * linux/drivers/ide/ide-pci.c Version 1.04 July 27, 1999
*
- * Copyright (c) 1998-1999 Andre Hedrick
+ * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org>
*
* Copyright (c) 1995-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
index e0803e6fa..7f5226db9 100644
--- a/drivers/ide/ide-pmac.c
+++ b/drivers/ide/ide-pmac.c
@@ -1,4 +1,6 @@
/*
+ * linux/drivers/ide/ide-pmac.c Version ?.?? Mar. 18, 2000
+ *
* Support for IDE interfaces on PowerMacs.
* These IDE interfaces are memory-mapped and have a DBDMA channel
* for doing DMA.
@@ -10,7 +12,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Some code taken from drivers/block/ide-dma.c:
+ * Some code taken from drivers/ide/ide-dma.c:
*
* Copyright (c) 1995-1998 Mark Lord
*
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index ffa3ade56..d8edb89c5 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-pnp.c
+ * linux/drivers/ide/ide-pnp.c
*
* This file provides autodetection for ISA PnP IDE interfaces.
* It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 0e617216d..200204ee6 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999
+ * linux/drivers/ide/ide-probe.c Version 1.05 July 3, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 753597e9c..fd33e4e42 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998
+ * linux/drivers/ide/ide-proc.c Version 1.03 January 2, 1998
*
* Copyright (C) 1997-1998 Mark Lord
*/
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 95e780abf..c4424cf90 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999
+ * linux/drivers/ide/ide-tape.c Version 1.16f Dec 15, 1999
*
* Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
*
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 9c409dfb6..89921f7b9 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.30 Dec 28, 1999
+ * linux/drivers/ide/ide.c Version 6.30 Dec 28, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -1809,9 +1809,9 @@ static void revalidate_drives (void)
static void ide_probe_module (void)
{
if (!ide_probe) {
-#ifdef CONFIG_KMOD
+#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
(void) request_module("ide-probe-mod");
-#endif /* CONFIG_KMOD */
+#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
} else {
(void) ide_probe->init();
}
@@ -2491,6 +2491,30 @@ static int ide_ioctl (struct inode *inode, struct file *file,
return 0;
}
+ case HDIO_GETGEO_BIG:
+ {
+ struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+ if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
+ if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
+ if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+ if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+ (unsigned long *) &loc->start)) return -EFAULT;
+ return 0;
+ }
+
+ case HDIO_GETGEO_BIG_RAW:
+ {
+ struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+ if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+ if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
+ if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+ if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+ if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+ (unsigned long *) &loc->start)) return -EFAULT;
+ return 0;
+ }
+
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
@@ -2564,8 +2588,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
}
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- /* should I check here for arg > MAX_HWIFS, or
- just let ide_unregister fail silently? -- shaver */
+ /* (arg > MAX_HWIFS) checked in function */
ide_unregister(arg);
return 0;
case HDIO_SET_NICE:
diff --git a/drivers/ide/ide_modes.h b/drivers/ide/ide_modes.h
index f94d91313..ff71b2c2c 100644
--- a/drivers/ide/ide_modes.h
+++ b/drivers/ide/ide_modes.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide_modes.h
+ * linux/drivers/ide/ide_modes.h
*
* Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord
*/
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
index 0e5675fde..7a24fce25 100644
--- a/drivers/ide/ns87415.c
+++ b/drivers/ide/ns87415.c
@@ -1,12 +1,14 @@
/*
- * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997
+ * linux/drivers/ide/ns87415.c Version 1.01 Mar. 18, 2000
*
- * Copyright (C) 1997-1998 Mark Lord
- * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com>
*
- * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu)
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/timer.h>
@@ -78,6 +80,7 @@ static void ns87415_selectproc (ide_drive_t *drive)
ns87415_prepare_drive (drive, drive->using_dma);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -106,6 +109,7 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
void __init ide_init_ns87415 (ide_hwif_t *hwif)
{
@@ -179,7 +183,10 @@ void __init ide_init_ns87415 (ide_hwif_t *hwif)
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base)
hwif->dmaproc = &ns87415_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
hwif->selectproc = &ns87415_selectproc;
}
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
index cc2aa567c..277f2f490 100644
--- a/drivers/ide/opti621.c
+++ b/drivers/ide/opti621.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999
+ * linux/drivers/ide/opti621.c Version 0.6 Jan 02, 1999
*
* Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
index 9ec7c8997..b93c6ad1b 100644
--- a/drivers/ide/pdc202xx.c
+++ b/drivers/ide/pdc202xx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000
+ * linux/drivers/ide/pdc202xx.c Version 0.30 Mar. 18, 2000
*
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -9,6 +9,9 @@
* Note that BIOS v1.29 is reported to fix the problem. Since this is
* safe chipset tuning, including this support is harmless
*
+ * Promise Ultra66 cards with BIOS v1.11 this
+ * compiled into the kernel if you have more than one card installed.
+ *
* The latest chipset code will support the following ::
* Three Ultra33 controllers and 12 drives.
* 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
@@ -16,60 +19,6 @@
*
* UNLESS you enable "CONFIG_PDC202XX_BURST"
*
- * There is only one BIOS in the three contollers.
- *
- * May 8 20:56:17 Orion kernel:
- * Uniform Multi-Platform E-IDE driver Revision: 6.19
- * PDC20246: IDE controller on PCI bus 00 dev a0
- * PDC20246: not 100% native mode: will probe irqs later
- * PDC20246: ROM enabled at 0xfebd0000
- * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
- * ide0: BM-DMA at 0xef80-0xef87, BIOS settings: hda:DMA, hdb:DMA
- * ide1: BM-DMA at 0xef88-0xef8f, BIOS settings: hdc:pio, hdd:pio
- * PDC20246: IDE controller on PCI bus 00 dev 98
- * PDC20246: not 100% native mode: will probe irqs later
- * PDC20246: ROM enabled at 0xfebc0000
- * PDC20246: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
- * ide2: BM-DMA at 0xef40-0xef47, BIOS settings: hde:DMA, hdf:DMA
- * ide3: BM-DMA at 0xef48-0xef4f, BIOS settings: hdg:DMA, hdh:DMA
- * PDC20246: IDE controller on PCI bus 00 dev 90
- * PDC20246: not 100% native mode: will probe irqs later
- * PDC20246: ROM enabled at 0xfebb0000
- * PDC20246: (U)DMA Burst Bit DISABLED Primary PCI Mode Secondary PCI Mode.
- * PDC20246: FORCING BURST BIT 0x00 -> 0x01 ACTIVE
- * ide4: BM-DMA at 0xef00-0xef07, BIOS settings: hdi:DMA, hdj:pio
- * ide5: BM-DMA at 0xef08-0xef0f, BIOS settings: hdk:pio, hdl:pio
- * PIIX3: IDE controller on PCI bus 00 dev 39
- * PIIX3: device not capable of full native PCI mode
- *
- * ide0 at 0xeff0-0xeff7,0xefe6 on irq 19
- * ide1 at 0xefa8-0xefaf,0xebe6 on irq 19
- * ide2 at 0xefa0-0xefa7,0xef7e on irq 18
- * ide3 at 0xef68-0xef6f,0xef66 on irq 18
- * ide4 at 0xef38-0xef3f,0xef62 on irq 17
- * hda: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=13328/15/63, UDMA(33)
- * hdb: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=6256/16/63, UDMA(33)
- * hde: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=3893/16/63, DMA
- * hdf: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=3158/16/63, DMA
- * hdi: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33)
- * hdj: Maxtor 90680D4, 6485MB w/256kB Cache, CHS=13176/16/63, UDMA(33)
- *
- * Promise Ultra66 cards with BIOS v1.11 this
- * compiled into the kernel if you have more than one card installed.
- *
- * PDC20262: IDE controller on PCI bus 00 dev a0
- * PDC20262: not 100% native mode: will probe irqs later
- * PDC20262: ROM enabled at 0xfebb0000
- * PDC20262: (U)DMA Burst Bit ENABLED Primary PCI Mode Secondary PCI Mode.
- * ide0: BM-DMA at 0xef00-0xef07, BIOS settings: hda:pio, hdb:pio
- * ide1: BM-DMA at 0xef08-0xef0f, BIOS settings: hdc:pio, hdd:pio
- *
- * UDMA 4/2 and UDMA 3/1 only differ by the testing bit 13 in word93.
- * Chipset timing speeds must be identical
- *
- * drive_number
- * = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- * = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
*/
/*
@@ -100,7 +49,7 @@
#define PDC202XX_DEBUG_DRIVE_INFO 0
#define PDC202XX_DECODE_REGISTER_INFO 0
-#undef DISPLAY_PDC202XX_TIMINGS
+#define DISPLAY_PDC202XX_TIMINGS
#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
@@ -111,13 +60,56 @@ extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c
extern char *ide_media_verbose(ide_drive_t *);
static struct pci_dev *bmide_dev;
+char *pdc202xx_pio_verbose (u32 drive_pci)
+{
+ if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+ if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+ if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+ if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+ if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+ if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+ return("PIO ?");
+}
+
+char *pdc202xx_dma_verbose (u32 drive_pci)
+{
+ if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+ if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+ if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+ if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+ if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+ if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+ return("PIO---");
+}
+
+char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+ if ((drive_pci & 0x000ff000) == 0x000ff000)
+ return("NOTSET");
+ if ((drive_pci & 0x00012000) == 0x00012000)
+ return((slow_cable) ? "UDMA 2" : "UDMA 4");
+ if ((drive_pci & 0x00024000) == 0x00024000)
+ return((slow_cable) ? "UDMA 1" : "UDMA 3");
+ if ((drive_pci & 0x00036000) == 0x00036000)
+ return("UDMA 0");
+ return(pdc202xx_dma_verbose(drive_pci));
+}
+
static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
u32 bibma = bmide_dev->resource[4].start;
+ u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+ u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
u8 c0 = 0, c1 = 0;
+ pci_read_config_word(bmide_dev, 0x50, &reg50h);
+ pci_read_config_dword(bmide_dev, 0x60, &reg60h);
+ pci_read_config_dword(bmide_dev, 0x64, &reg64h);
+ pci_read_config_dword(bmide_dev, 0x68, &reg68h);
+ pci_read_config_dword(bmide_dev, 0x6c, &reg6ch);
+
/*
* at that point bibma+0x2 et bibma+0xa are byte registers
* to investigate:
@@ -131,6 +123,7 @@ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count
break;
case PCI_DEVICE_ID_PROMISE_20246:
p += sprintf(p, "\n PDC20246 Chipset.\n");
+ reg50h |= 0x0c00;
break;
default:
p += sprintf(p, "\n PDC202XX Chipset.\n");
@@ -139,17 +132,18 @@ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
+ (c0&0x80)?"dis":" en",(c1&0x80)?"dis":" en");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
- p += sprintf(p, "PIO\n");
-
+ (c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+ p += sprintf(p, "DMA Mode: %s %s %s %s\n",
+ pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+ pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+ pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+ pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+ p += sprintf(p, " PIO Mode: %s %s %s %s\n",
+ pdc202xx_pio_verbose(reg60h),pdc202xx_pio_verbose(reg64h),
+ pdc202xx_pio_verbose(reg68h),pdc202xx_pio_verbose(reg6ch));
return p-buffer; /* => must be less than 4k! */
}
#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -268,6 +262,90 @@ static void decode_registers (byte registers, byte value)
#endif /* PDC202XX_DECODE_REGISTER_INFO */
+/* 0 1 2 3 4 5 6 7 8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ * 180, 150, 120, 90, 60
+ * DMA_Speed
+ * 180, 120, 90, 90, 90, 60, 30
+ * 11, 5, 4, 3, 2, 1, 0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte drive_pci, speed;
+ byte AP, BP, TA, TB;
+
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ int err;
+
+ switch (drive_number) {
+ case 0: drive_pci = 0x60; break;
+ case 1: drive_pci = 0x64; break;
+ case 2: drive_pci = 0x68; break;
+ case 3: drive_pci = 0x6c; break;
+ default: return 1;
+ }
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+
+ if ((AP & 0x0F) || (BP & 0x07)) {
+ /* clear PIO modes of lower 8421 bits of A Register */
+ pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+
+ /* clear PIO modes of lower 421 bits of B Register */
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ }
+
+ pio = (pio == 5) ? 4 : pio;
+ switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
+ case 4:speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
+ case 3:speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
+ case 2:speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
+ case 1:speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
+ case 0:
+ default:speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
+ }
+ pci_write_config_byte(dev, (drive_pci), AP|TA);
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+
+#if PDC202XX_DECODE_REGISTER_INFO
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+ pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+ decode_registers(REG_A, AP);
+ decode_registers(REG_B, BP);
+ decode_registers(REG_C, CP);
+ decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+ err = ide_config_drive_speed(drive, speed);
+
+#if PDC202XX_DEBUG_DRIVE_INFO
+ printk("%s: %s drive%d 0x%08x ",
+ drive->name, ide_xfer_verbose(speed),
+ drive_number, drive_conf);
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+ return err;
+}
+
+static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
+{
+ (void) config_chipset_for_pio(drive, pio);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
@@ -476,91 +554,6 @@ chipset_is_set:
ide_dma_off_quietly);
}
-/* 0 1 2 3 4 5 6 7 8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- * 180, 150, 120, 90, 60
- * DMA_Speed
- * 180, 120, 90, 90, 90, 60, 30
- * 11, 5, 4, 3, 2, 1, 0
- */
-
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- byte drive_pci, speed;
- byte AP, BP, TA, TB;
-
- int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- int err;
-
- switch (drive_number) {
- case 0: drive_pci = 0x60; break;
- case 1: drive_pci = 0x64; break;
- case 2: drive_pci = 0x68; break;
- case 3: drive_pci = 0x6c; break;
- default: return 1;
- }
-
- pci_read_config_byte(dev, (drive_pci), &AP);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-
- if ((AP & 0x0F) || (BP & 0x07)) {
- /* clear PIO modes of lower 8421 bits of A Register */
- pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
- pci_read_config_byte(dev, (drive_pci), &AP);
-
- /* clear PIO modes of lower 421 bits of B Register */
- pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
- pci_read_config_byte(dev, (drive_pci), &AP);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
- }
-
- pio = (pio == 5) ? 4 : pio;
- switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) {
- case 4: speed = XFER_PIO_4; TA=0x01; TB=0x04; break;
- case 3: speed = XFER_PIO_3; TA=0x02; TB=0x06; break;
- case 2: speed = XFER_PIO_2; TA=0x03; TB=0x08; break;
- case 1: speed = XFER_PIO_1; TA=0x05; TB=0x0C; break;
- case 0:
- default: speed = XFER_PIO_0; TA=0x09; TB=0x13; break;
- }
- pci_write_config_byte(dev, (drive_pci), AP|TA);
- pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-
-#if PDC202XX_DECODE_REGISTER_INFO
- pci_read_config_byte(dev, (drive_pci), &AP);
- pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
- pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
- pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
- decode_registers(REG_A, AP);
- decode_registers(REG_B, BP);
- decode_registers(REG_C, CP);
- decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
- err = ide_config_drive_speed(drive, speed);
-
-#if PDC202XX_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d 0x%08x ",
- drive->name, ide_xfer_verbose(speed),
- drive_number, drive_conf);
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-
- return err;
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
-{
- (void) config_chipset_for_pio(drive, pio);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -625,6 +618,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
{
@@ -701,11 +695,12 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
#endif /* CONFIG_PDC202XX_MASTER */
#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
- pdc202xx_proc = 1;
- bmide_dev = dev;
- pdc202xx_display_info = &pdc202xx_get_info;
+ if (!pdc202xx_proc) {
+ pdc202xx_proc = 1;
+ bmide_dev = dev;
+ pdc202xx_display_info = &pdc202xx_get_info;
+ }
#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
-
return dev->irq;
}
@@ -722,10 +717,18 @@ void __init ide_init_pdc202xx (ide_hwif_t *hwif)
{
hwif->tuneproc = &pdc202xx_tune_drive;
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &pdc202xx_dmaproc;
+ hwif->autodma = 1;
} else {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
}
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index 93f20566d..fa453e7d5 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000
+ * linux/drivers/ide/piix.c Version 0.31 Mar. 18, 2000
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
@@ -51,31 +51,6 @@
* pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
*
- * 00:1f.1 IDE interface: Intel Corporation:
- * Unknown device 2411 (rev 01) (prog-if 80 [Master])
- * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop-
- * ParErr- Stepping- SERR- FastB2B-
- * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
- * <TAbort- <MAbort- >SERR- <PERR-
- * Latency: 0 set
- * Region 4: I/O ports at ffa0
- * 00: 86 80 11 24 05 00 80 02 01 80 01 01 00 00 00 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: a1 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 07 a3 03 a3 00 00 00 00 05 00 02 02 00 00 00 00
- * 50: 00 00 00 00 11 04 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 3a 0f 00 00 00 00 00 00
- *
*/
#include <linux/config.h>
@@ -281,6 +256,7 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio)
restore_flags(flags);
}
+#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
static int piix_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -387,13 +363,16 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return ide_dmaproc(func, drive);
}
+#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
{
#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
- piix_proc = 1;
- bmide_dev = dev;
- piix_display_info = &piix_get_info;
+ if (!piix_proc) {
+ piix_proc = 1;
+ bmide_dev = dev;
+ piix_display_info = &piix_get_info;
+ }
#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
return 0;
}
@@ -427,12 +406,12 @@ void __init ide_init_piix (ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ hwif->autodma = 0;
+#else /* CONFIG_BLK_DEV_IDEDMA */
#ifdef CONFIG_PIIX_TUNING
hwif->autodma = 1;
hwif->dmaproc = &piix_dmaproc;
-#else
- if (hwif->autodma)
- hwif->autodma = 0;
-
#endif /* CONFIG_PIIX_TUNING */
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
}
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
index 0f2330370..41d4277d2 100644
--- a/drivers/ide/q40ide.c
+++ b/drivers/ide/q40ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/q40ide.c -- Q40 I/O port IDE Driver
+ * linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
*
* original file created 12 Jul 1997 by Geert Uytterhoeven
*
diff --git a/drivers/ide/qd6580.c b/drivers/ide/qd6580.c
index 31781a9f0..bccf1eb6a 100644
--- a/drivers/ide/qd6580.c
+++ b/drivers/ide/qd6580.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996
+ * linux/drivers/ide/qd6580.c Version 0.02 Feb 09, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c
index 5905aca41..baa293467 100644
--- a/drivers/ide/rapide.c
+++ b/drivers/ide/rapide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/rapide.c
+ * linux/drivers/ide/rapide.c
*
* Copyright (c) 1996-1998 Russell King.
*
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
index 455641c1d..5bd3db7d5 100644
--- a/drivers/ide/rz1000.c
+++ b/drivers/ide/rz1000.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997
+ * linux/drivers/ide/rz1000.c Version 0.05 December 8, 1997
*
* Copyright (C) 1995-1998 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index 942187900..37da5577a 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000
+ * linux/drivers/ide/sis5513.c Version 0.10 Mar. 18, 2000
*
* Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
@@ -109,14 +109,14 @@ static __inline__ char * find_udma_mode (byte cycle_time)
static int sis_get_info(char *, char **, off_t, int);
extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-struct pci_dev *bmide_dev;
+static struct pci_dev *bmide_dev;
-static char *cable_type[] = {
+static char *cable_type[] __initdata = {
"80 pins",
"40 pins"
};
-static char *recovery_time [] ={
+static char *recovery_time [] __initdata ={
"12 PCICLK", "1 PCICLK",
"2 PCICLK", "3 PCICLK",
"4 PCICLK", "5 PCICLCK",
@@ -127,14 +127,14 @@ static char *recovery_time [] ={
"15 PCICLK", "15 PCICLK"
};
-static char *cycle_time [] = {
+static char * cycle_time [] __initdata = {
"Undefined", "2 CLCK",
"3 CLK", "4 CLK",
"5 CLK", "6 CLK",
"7 CLK", "8 CLK"
};
-static char *active_time [] = {
+static char * active_time [] __initdata = {
"8 PCICLK", "1 PCICLCK",
"2 PCICLK", "2 PCICLK",
"4 PCICLK", "5 PCICLK",
@@ -222,6 +222,123 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
byte sis_proc = 0;
extern char *ide_xfer_verbose (byte xfer_rate);
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ byte reg4bh = 0;
+ byte rw_prefetch = (0x11 << drive_number);
+
+ pci_read_config_byte(dev, 0x4b, &reg4bh);
+ if (drive->media != ide_disk)
+ return;
+
+ if ((reg4bh & rw_prefetch) != rw_prefetch)
+ pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+}
+
+static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ byte timing, drive_pci, test1, test2;
+
+ unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+
+#if 0
+ config_drive_art_rwp(drive);
+#endif
+
+ pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+/*
+ * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4
+ * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns)
+ * 0x41 2:0 bits 000 110 100 011 011
+ * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns)
+ * 0x40 3:0 bits 0000 0111 0100 0011 0001
+ * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
+ */
+
+ switch(drive_number) {
+ case 0: drive_pci = 0x40; break;
+ case 1: drive_pci = 0x42; break;
+ case 2: drive_pci = 0x44; break;
+ case 3: drive_pci = 0x46; break;
+ default: return;
+ }
+
+ pci_read_config_byte(dev, drive_pci, &test1);
+ pci_read_config_byte(dev, drive_pci|0x01, &test2);
+
+ /*
+ * Do a blanket clear of active and recovery timings.
+ */
+
+ test1 &= ~0x07;
+ test2 &= ~0x0F;
+
+ switch(timing) {
+ case 4: test1 |= 0x01; test2 |= 0x03; break;
+ case 3: test1 |= 0x03; test2 |= 0x03; break;
+ case 2: test1 |= 0x04; test2 |= 0x04; break;
+ case 1: test1 |= 0x07; test2 |= 0x06; break;
+ default: break;
+ }
+
+ pci_write_config_byte(dev, drive_pci, test1);
+ pci_write_config_byte(dev, drive_pci|0x01, test2);
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
+{
+ int err;
+ byte speed;
+
+ switch(pio) {
+ case 4: speed = XFER_PIO_4; break;
+ case 3: speed = XFER_PIO_3; break;
+ case 2: speed = XFER_PIO_2; break;
+ case 1: speed = XFER_PIO_1; break;
+ default: speed = XFER_PIO_0; break;
+ }
+
+ config_art_rwp_pio(drive, pio);
+ err = ide_config_drive_speed(drive, speed);
+ return err;
+}
+
+#undef SIS5513_TUNEPROC
+
+#ifdef SIS5513_TUNEPROC
+static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
+{
+ (void) config_chipset_for_pio(drive, pio);
+}
+#endif /* SIS5513_TUNEPROC */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
/*
* ((id->hw_config & 0x2000) && (HWIF(drive)->udma_four))
*/
@@ -331,84 +448,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
ide_dma_off_quietly);
}
-static void config_drive_art_rwp (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
-
- byte timing, pio, drive_pci, test1, test2;
-
- unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-
- if (drive->media == ide_disk) {
- struct pci_dev *dev = hwif->pci_dev;
- byte reg4bh = 0;
- byte rw_prefetch = (0x11 << drive_number);
-
- pci_read_config_byte(dev, 0x4b, &reg4bh);
- if ((reg4bh & rw_prefetch) != rw_prefetch)
- pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
- }
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-/*
- * Mode 0 Mode 1 Mode 2 Mode 3 Mode 4
- * Active time 8T (240ns) 6T (180ns) 4T (120ns) 3T (90ns) 3T (90ns)
- * 0x41 2:0 bits 000 110 100 011 011
- * Recovery time 12T (360ns) 7T (210ns) 4T (120ns) 3T (90ns) 1T (30ns)
- * 0x40 3:0 bits 0000 0111 0100 0011 0001
- * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns)
- */
-
- switch(drive_number) {
- case 0: drive_pci = 0x40;break;
- case 1: drive_pci = 0x42;break;
- case 2: drive_pci = 0x44;break;
- case 3: drive_pci = 0x46;break;
- default: return;
- }
-
- pci_read_config_byte(dev, drive_pci, &test1);
- pci_read_config_byte(dev, drive_pci|0x01, &test2);
-
- /*
- * Do a blanket clear of active and recovery timings.
- */
-
- test1 &= ~0x07;
- test2 &= ~0x0F;
-
- switch(timing) {
- case 4: test1 |= 0x01;test2 |= 0x03;break;
- case 3: test1 |= 0x03;test2 |= 0x03;break;
- case 2: test1 |= 0x04;test2 |= 0x04;break;
- case 1: test1 |= 0x07;test2 |= 0x06;break;
- default: break;
- }
-
- pci_write_config_byte(dev, drive_pci, test1);
- pci_write_config_byte(dev, drive_pci|0x01, test2);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -417,9 +456,10 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
if (id && (id->capability & 1) && HWIF(drive)->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
- return HWIF(drive)->dmaproc(ide_dma_off, drive);
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
}
-
+ dma_func = ide_dma_off_quietly;
if (id->field_valid & 4) {
if (id->dma_ultra & 0x001F) {
/* Force if Capable UltraDMA */
@@ -434,13 +474,25 @@ try_dma_modes:
(id->dma_1word & 0x0007)) {
/* Force if Capable regular DMA modes */
dma_func = config_chipset_for_dma(drive, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
}
} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
(id->eide_dma_time > 150)) {
/* Consult the list of known "good" drives */
dma_func = config_chipset_for_dma(drive, 0);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ } else {
+ goto fast_ata_pio;
}
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ dma_func = ide_dma_off_quietly;
+no_dma_set:
+ (void) config_chipset_for_pio(drive, 5);
}
+
return HWIF(drive)->dmaproc(dma_func, drive);
}
@@ -452,12 +504,14 @@ int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
switch (func) {
case ide_dma_check:
config_drive_art_rwp(drive);
+ config_art_rwp_pio(drive, 5);
return config_drive_xfer_rate(drive);
default:
break;
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
{
@@ -492,9 +546,11 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
pci_write_config_byte(dev, 0x52, reg52h|0x04);
}
#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
- sis_proc = 1;
- bmide_dev = dev;
- sis_display_info = &sis_get_info;
+ if (!sis_proc) {
+ sis_proc = 1;
+ bmide_dev = dev;
+ sis_display_info = &sis_get_info;
+ }
#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
}
return 0;
@@ -525,11 +581,16 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
+#ifdef SIS5513_TUNEPROC
+ hwif->tuneproc = &sis5513_tune_drive;
+#endif /* SIS5513_TUNEPROC */
+
if (!(hwif->dma_base))
return;
if (host_dev) {
switch(host_dev->device) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
case PCI_DEVICE_ID_SI_530:
case PCI_DEVICE_ID_SI_540:
case PCI_DEVICE_ID_SI_620:
@@ -540,6 +601,7 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif)
hwif->autodma = 1;
hwif->dmaproc = &sis5513_dmaproc;
break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
default:
hwif->autodma = 0;
break;
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index 483a98fde..c58c612ed 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/sl82c105.c
+ * linux/drivers/ide/sl82c105.c
*
* SL82C105/Winbond 553 IDE driver
*
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
index fb5e8d1af..e7ee2e977 100644
--- a/drivers/ide/trm290.c
+++ b/drivers/ide/trm290.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/trm290.c Version 1.01 December 5, 1997
+ * linux/drivers/ide/trm290.c Version 1.02 Mar. 18, 2000
*
* Copyright (c) 1997-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
@@ -124,6 +124,7 @@
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -171,6 +172,7 @@ static void trm290_selectproc (ide_drive_t *drive)
trm290_prepare_drive(drive, drive->using_dma);
}
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -209,6 +211,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* Invoked from ide-dma.c at boot time.
@@ -247,7 +250,11 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &trm290_dmaproc;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
hwif->selectproc = &trm290_selectproc;
hwif->autodma = 0; /* play it safe for now */
#if 1
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
index 02b581a28..5c1168972 100644
--- a/drivers/ide/umc8672.c
+++ b/drivers/ide/umc8672.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996
+ * linux/drivers/ide/umc8672.c Version 0.05 Jul 31, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & author (see below)
*/
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index afa1cc5b6..bf8e27640 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000
+ * linux/drivers/ide/via82cxxx.c Version 0.08 Mar. 18, 2000
*
* Copyright (C) 1998-99 Michel Aubry, Maintainer
* Copyright (C) 1999 Jeff Garzik, MVP4 Support
@@ -143,14 +143,14 @@ static const struct {
#include <linux/stat.h>
#include <linux/proc_fs.h>
-static char *FIFO_str[] = {
+static char *FIFO_str[] __initdata = {
" 1 ",
"3/4",
"1/2",
"1/4"
};
-static char *control3_str[] = {
+static char *control3_str[] __initdata = {
"No limitation",
"64",
"128",
@@ -516,6 +516,62 @@ static int via_set_fifoconfig(ide_hwif_t *hwif)
#ifdef CONFIG_VIA82CXXX_TUNING
+struct chipset_bus_clock_list_entry {
+ unsigned short bus_speed;
+ byte xfer_speed;
+ byte chipset_settings;
+};
+
+PCI_DEVICE_ID_VIA_82C586_1
+PCI_DEVICE_ID_VIA_82C596
+PCI_DEVICE_ID_VIA_82C686
+PCI_DEVICE_ID_VIA_8231
+
+PCI_DEVICE_ID_VIA_82C586_1 TYPE_1
+PCI_DEVICE_ID_VIA_82C596 TYPE_2
+PCI_DEVICE_ID_VIA_82C686 TYPE_2
+PCI_DEVICE_ID_VIA_82C596 TYPE_3
+PCI_DEVICE_ID_VIA_82C686 TYPE_3
+PCI_DEVICE_ID_VIA_8231 TYPE_4
+
+struct chipset_bus_clock_list_entry ultra_33_base [] = {
+{ TYPE_1,25,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_1,33,0x00,0x00,0x60,0x61,0x62,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_1,37,0x00,0x00,0x60,0x61,0x62,0x03,0x21,0x32,0x76,0x76,0xA9 },
+{ TYPE_2,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_2,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_2,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB },
+{ TYPE_2,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE },
+{ TYPE_3,25,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_3,33,0x00,0x00,0xE0,0xE1,0xE2,0x03,0x20,0x31,0x65,0x65,0xA8 },
+{ TYPE_3,37,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x31,0x42,0x87,0x87,0xDB },
+{ TYPE_3,41,0x00,0x00,0xE1,0xE2,0xE2,0x03,0x32,0x53,0xA8,0xA8,0xFE },
+{ TYPE_4,0,0,0,0,0,0,0,0,0,0,0,0 },
+{ 0,0,0,0,0,0,0,0,0,0,0,0,0 }
+};
+
+struct chipset_bus_clock_list_entry timing_66_base [] = {
+ { 37, XFER_PIO_4, 0x21 },
+ { 37, XFER_PIO_3, 0x32 },
+ { 37, XFER_PIO_2, 0x76 },
+ { 37, XFER_PIO_1, 0x76 },
+ { 37, XFER_PIO_0, 0xA9 },
+ { ANY, XFER_PIO_4, 0x20 },
+ { ANY, XFER_PIO_3, 0x31 },
+ { ANY, XFER_PIO_2, 0x65 },
+ { ANY, XFER_PIO_1, 0x65 },
+ { ANY, XFER_PIO_0, 0xA8 },
+};
+
+static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+ for ( ; chipset_table->xfer_speed ; chipset_table++)
+ if (chipset_table->xfer_speed == speed) {
+ return chipset_table->chipset_settings;
+ }
+ return 0x01208585;
+}
+
static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
{
struct hd_driveid *id = drive->id;
@@ -539,7 +595,7 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break;
case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break;
default:
- return err;
+ return -1;
}
pci_read_config_byte(dev, ata2_pci, &timing);
@@ -575,6 +631,57 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
return(err);
}
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ byte timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+ switch(timing) {
+ case 4: speed = XFER_PIO_4; break;
+ case 3: speed = XFER_PIO_3; break;
+ case 2: speed = XFER_PIO_2; break;
+ case 1: speed = XFER_PIO_1; break;
+ default:
+ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+ break;
+ }
+ (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+ switch(pio) {
+ case 4: speed = XFER_PIO_4; break;
+ case 3: speed = XFER_PIO_3; break;
+ case 2: speed = XFER_PIO_2; break;
+ case 1: speed = XFER_PIO_1; break;
+ default: speed = XFER_PIO_0; break;
+ }
+ (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -617,56 +724,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 :
- (drive->id->tPIO & 2) ? 0x02 :
- (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default:
- speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; break;
- }
- (void) via82cxxx_tune_chipset(drive, speed);
-}
-
-static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
- switch(pio) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default: speed = XFER_PIO_0;break;
- }
- (void) via82cxxx_tune_chipset(drive, speed);
-}
-
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -726,6 +783,7 @@ int via82cxxx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_VIA82CXXX_TUNING */
unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
@@ -745,7 +803,7 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
host_dev = host;
printk(ApolloHostChipInfo[i].name);
-
+ printk("\n");
for (j = 0; j < arraysize (ApolloISAChipInfo) && !isa_dev; j++) {
if (ApolloISAChipInfo[j].host_id !=
ApolloHostChipInfo[i].host_id)
@@ -777,9 +835,11 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
}
#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
- via_proc = 1;
- bmide_dev = dev;
- via_display_info = &via_get_info;
+ if (!via_proc) {
+ via_proc = 1;
+ bmide_dev = dev;
+ via_display_info = &via_get_info;
+ }
#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/
return 0;
@@ -797,13 +857,15 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
#ifdef CONFIG_VIA82CXXX_TUNING
hwif->tuneproc = &via82cxxx_tune_drive;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ hwif->autodma = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->dma_base) {
hwif->dmaproc = &via82cxxx_dmaproc;
- } else {
- hwif->autodma = 0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->autodma = 1;
}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
#endif /* CONFIG_VIA82CXXX_TUNING */
}
diff --git a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in
index 899add490..df0e3cfd2 100644
--- a/drivers/ieee1394/Config.in
+++ b/drivers/ieee1394/Config.in
@@ -14,11 +14,12 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394
-
+
dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
+ bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
fi
endmenu
fi
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index 4ffe0fadd..a884f2a1c 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -14,6 +14,7 @@
#include "highlevel.h"
+/* FIXME: this one won't work on little endian with big endian data */
static u16 csr_crc16(unsigned *data, int length)
{
int check=0, i;
@@ -47,14 +48,18 @@ static void host_reset(struct hpsb_host *host)
host->csr.state &= ~0x100;
}
- host->csr.topology_map[1]++;
- host->csr.topology_map[2] = host->node_count << 16 | host->selfid_count;
- host->csr.topology_map[0] = (host->selfid_count + 2) << 16
- | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2);
-
- /* FIXME - generate speed map */
- host->csr.speed_map[0] = 0x3f1 << 16 | csr_crc16(host->csr.speed_map+1,
- 0x3f1);
+ host->csr.topology_map[1] =
+ cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1);
+ host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
+ | host->selfid_count);
+ host->csr.topology_map[0] =
+ cpu_to_be32((host->selfid_count + 2) << 16
+ | csr_crc16(host->csr.topology_map + 1,
+ host->selfid_count + 2));
+
+ host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
+ | csr_crc16(host->csr.speed_map+1,
+ 0x3f1));
}
@@ -78,8 +83,8 @@ static void add_host(struct hpsb_host *host)
/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
+static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
const char *src;
@@ -100,43 +105,11 @@ static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
return RCODE_COMPLETE;
}
-/* Read FCP register space */
-static int read_fcp(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- const char *src;
-
- if (csraddr + length > CSR_FCP_END) {
- return RCODE_ADDRESS_ERROR;
- }
- src = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
-
- memcpy(buffer, src, length);
- return RCODE_COMPLETE;
-}
-
-/* Write FCP register space */
-static int write_fcp(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- char *dest;
-
- if (csraddr + length > CSR_FCP_END) {
- return RCODE_ADDRESS_ERROR;
- }
- dest = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
-
- memcpy(dest, data, length);
- return RCODE_COMPLETE;
-}
-
#define out if (--length == 0) break
-static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
- unsigned int length)
+static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
int oldcycle;
@@ -149,13 +122,13 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
switch (csraddr) {
case CSR_STATE_CLEAR:
- *(buf++) = host->csr.state;
+ *(buf++) = cpu_to_be32(host->csr.state);
out;
case CSR_STATE_SET:
- *(buf++) = host->csr.state;
+ *(buf++) = cpu_to_be32(host->csr.state);
out;
case CSR_NODE_IDS:
- *(buf++) = host->csr.node_ids;
+ *(buf++) = cpu_to_be32(host->csr.node_ids);
out;
case CSR_RESET_START:
@@ -164,10 +137,10 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
/* address gap - handled by default below */
case CSR_SPLIT_TIMEOUT_HI:
- *(buf++) = host->csr.split_timeout_hi;
+ *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
out;
case CSR_SPLIT_TIMEOUT_LO:
- *(buf++) = host->csr.split_timeout_lo;
+ *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
out;
/* address gap */
@@ -182,7 +155,7 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
/* cycle time wrapped around */
host->csr.bus_time += 1 << 7;
}
- *(buf++) = host->csr.cycle_time;
+ *(buf++) = cpu_to_be32(host->csr.cycle_time);
out;
case CSR_BUS_TIME:
oldcycle = host->csr.cycle_time;
@@ -193,7 +166,8 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
/* cycle time wrapped around */
host->csr.bus_time += (1 << 7);
}
- *(buf++) = host->csr.bus_time | (host->csr.cycle_time >> 25);
+ *(buf++) = cpu_to_be32(host->csr.bus_time
+ | (host->csr.cycle_time >> 25));
out;
/* address gap */
@@ -204,16 +178,16 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
return RCODE_ADDRESS_ERROR;
case CSR_BUS_MANAGER_ID:
- *(buf++) = host->csr.bus_manager_id;
+ *(buf++) = cpu_to_be32(host->csr.bus_manager_id);
out;
case CSR_BANDWIDTH_AVAILABLE:
- *(buf++) = host->csr.bandwidth_available;
+ *(buf++) = cpu_to_be32(host->csr.bandwidth_available);
out;
case CSR_CHANNELS_AVAILABLE_HI:
- *(buf++) = host->csr.channels_available_hi;
+ *(buf++) = cpu_to_be32(host->csr.channels_available_hi);
out;
case CSR_CHANNELS_AVAILABLE_LO:
- *(buf++) = host->csr.channels_available_lo;
+ *(buf++) = cpu_to_be32(host->csr.channels_available_lo);
out;
/* address gap to end - fall through to default */
@@ -224,8 +198,8 @@ static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
return RCODE_COMPLETE;
}
-static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
+static int write_regs(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
@@ -246,7 +220,7 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
case CSR_NODE_IDS:
host->csr.node_ids &= NODE_MASK << 16;
- host->csr.node_ids |= *(data++) & (BUS_MASK << 16);
+ host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
host->node_id = host->csr.node_ids >> 16;
host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
out;
@@ -259,10 +233,12 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
return RCODE_ADDRESS_ERROR;
case CSR_SPLIT_TIMEOUT_HI:
- host->csr.split_timeout_hi = *(data++) & 0x00000007;
+ host->csr.split_timeout_hi =
+ be32_to_cpu(*(data++)) & 0x00000007;
out;
case CSR_SPLIT_TIMEOUT_LO:
- host->csr.split_timeout_lo = *(data++) & 0xfff80000;
+ host->csr.split_timeout_lo =
+ be32_to_cpu(*(data++)) & 0xfff80000;
out;
/* address gap */
@@ -270,11 +246,12 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
case CSR_CYCLE_TIME:
/* should only be set by cycle start packet, automatically */
- host->csr.cycle_time = *data;
- host->template->devctl(host, SET_CYCLE_COUNTER, *(data++));
+ host->csr.cycle_time = be32_to_cpu(*data);
+ host->template->devctl(host, SET_CYCLE_COUNTER,
+ be32_to_cpu(*(data++)));
out;
case CSR_BUS_TIME:
- host->csr.bus_time = *(data++) & 0xffffff80;
+ host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
out;
/* address gap */
@@ -305,13 +282,13 @@ static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
/* helper function for lock_regs */
inline static void compare_swap(quadlet_t *old, quadlet_t data, quadlet_t arg)
{
- if (*old == arg) {
- *old = data;
+ if (*old == be32_to_cpu(arg)) {
+ *old = be32_to_cpu(data);
}
}
-static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int extcode)
+static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int extcode)
{
int csraddr = addr - CSR_REGISTER_BASE;
unsigned long flags;
@@ -327,25 +304,28 @@ static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
switch (csraddr) {
case CSR_BUS_MANAGER_ID:
- *store = host->csr.bus_manager_id;
+ *store = cpu_to_be32(host->csr.bus_manager_id);
compare_swap(&host->csr.bus_manager_id,
data, arg);
break;
case CSR_BANDWIDTH_AVAILABLE:
- *store = host->csr.bandwidth_available;
+ *store = cpu_to_be32(host->
+ csr.bandwidth_available);
compare_swap(&host->csr.bandwidth_available,
data, arg);
break;
case CSR_CHANNELS_AVAILABLE_HI:
- *store = host->csr.channels_available_hi;
+ *store = cpu_to_be32(host->
+ csr.channels_available_hi);
compare_swap(&host->csr.channels_available_hi,
data, arg);
break;
case CSR_CHANNELS_AVAILABLE_LO:
- *store = host->csr.channels_available_lo;
+ *store = cpu_to_be32(host->
+ csr.channels_available_lo);
compare_swap(&host->csr.channels_available_lo,
data, arg);
break;
@@ -377,34 +357,48 @@ static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
}
}
+static int write_fcp(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+
+ if (length > 512) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ switch (csraddr) {
+ case CSR_FCP_COMMAND:
+ highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
+ break;
+ case CSR_FCP_RESPONSE:
+ highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
+ break;
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+
+ return RCODE_COMPLETE;
+}
+
struct hpsb_highlevel_ops csr_ops = {
- add_host,
- NULL,
- host_reset,
- NULL
+ add_host: add_host,
+ host_reset: host_reset,
};
struct hpsb_address_ops map_ops = {
- read_maps,
- NULL,
- NULL,
- NULL
+ read: read_maps,
};
struct hpsb_address_ops fcp_ops = {
- read_fcp,
- write_fcp,
- NULL,
- NULL
+ write: write_fcp,
};
struct hpsb_address_ops reg_ops = {
- read_regs,
- write_regs,
- lock_regs,
- NULL
+ read: read_regs,
+ write: write_regs,
+ lock: lock_regs,
};
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
index 70bacdd10..7bc97f549 100644
--- a/drivers/ieee1394/csr.h
+++ b/drivers/ieee1394/csr.h
@@ -46,7 +46,6 @@ struct csr_control {
quadlet_t topology_map[256];
quadlet_t speed_map[1024];
- quadlet_t fcp_data[1024];
};
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 3b4ac40f5..3e20824aa 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -192,23 +192,35 @@ void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
read_unlock(&hl_drivers_lock);
}
+void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ u8 *data, unsigned int length)
+{
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
+ int cts = data[0];
+
+ read_lock(&hl_drivers_lock);
+ entry = hl_drivers.next;
+
+ while (entry != &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+ if (hl->op->fcp_request) {
+ hl->op->fcp_request(host, nodeid, direction, cts, data,
+ length);
+ }
+ entry = entry->next;
+ }
+ read_unlock(&hl_drivers_lock);
+}
-int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
+int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length)
{
struct hpsb_address_serve *as;
struct list_head *entry;
unsigned int partlength;
int rcode = RCODE_ADDRESS_ERROR;
- if ((addr | length) & 0x3) {
- /* Addresses or lengths not a multiple of a quadlet pose a big
- * problem on little endian machines because we always do this
- * in arch endian and swapping would mess it all up. So we
- * simply don't allow this at all. */
- return RCODE_TYPE_ERROR;
- }
-
read_lock(&addr_space_lock);
entry = addr_space.next;
@@ -220,7 +232,7 @@ int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
length);
if (as->op->read != NULL) {
- rcode = as->op->read(host, buffer, addr,
+ rcode = as->op->read(host, nodeid, buffer, addr,
partlength);
} else {
rcode = RCODE_TYPE_ERROR;
@@ -247,18 +259,14 @@ int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
return rcode;
}
-int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
+int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
{
struct hpsb_address_serve *as;
struct list_head *entry;
unsigned int partlength;
int rcode = RCODE_ADDRESS_ERROR;
- if ((addr | length) & 0x3) {
- return RCODE_TYPE_ERROR;
- }
-
read_lock(&addr_space_lock);
entry = addr_space.next;
@@ -270,7 +278,7 @@ int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
length);
if (as->op->write != NULL) {
- rcode = as->op->write(host, data, addr,
+ rcode = as->op->write(host, nodeid, data, addr,
partlength);
} else {
rcode = RCODE_TYPE_ERROR;
@@ -298,8 +306,8 @@ int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
}
-int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode)
+int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
{
struct hpsb_address_serve *as;
struct list_head *entry;
@@ -313,8 +321,8 @@ int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
while (as->start <= addr) {
if (as->end > addr) {
if (as->op->lock != NULL) {
- rcode = as->op->lock(host, store, addr, data,
- arg, ext_tcode);
+ rcode = as->op->lock(host, nodeid, store, addr,
+ data, arg, ext_tcode);
} else {
rcode = RCODE_TYPE_ERROR;
}
@@ -331,8 +339,8 @@ int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
return rcode;
}
-int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode)
+int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
{
struct hpsb_address_serve *as;
struct list_head *entry;
@@ -346,8 +354,9 @@ int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
while (as->start <= addr) {
if (as->end > addr) {
if (as->op->lock64 != NULL) {
- rcode = as->op->lock64(host, store, addr, data,
- arg, ext_tcode);
+ rcode = as->op->lock64(host, nodeid, store,
+ addr, data, arg,
+ ext_tcode);
} else {
rcode = RCODE_TYPE_ERROR;
}
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index 9bf406742..f4f615a7b 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -55,6 +55,13 @@ struct hpsb_highlevel_ops {
* for channel/host combinations you did not request. */
void (*iso_receive) (struct hpsb_host *host, int channel,
quadlet_t *data, unsigned int length);
+
+ /* A write request was received on either the FCP_COMMAND (direction =
+ * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
+ * contains the cts field (first byte of data).
+ */
+ void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, unsigned int length);
};
struct hpsb_address_ops {
@@ -67,17 +74,17 @@ struct hpsb_address_ops {
*/
/* These functions have to implement block reads for themselves. */
- int (*read) (struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length);
- int (*write) (struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length);
+ int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length);
+ int (*write) (struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length);
/* Lock transactions: write results of ext_tcode operation into
* *store. */
- int (*lock) (struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode);
- int (*lock64) (struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode);
+ int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+ int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
};
@@ -87,17 +94,19 @@ void highlevel_add_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length);
-int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length);
-int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode);
-int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode);
+int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length);
+int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length);
+int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
unsigned int length);
+void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ u8 *data, unsigned int length);
/*
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
index dfca3aef3..c9f42373e 100644
--- a/drivers/ieee1394/ieee1394.h
+++ b/drivers/ieee1394/ieee1394.h
@@ -63,4 +63,103 @@
#define SELFID_PORT_NCONN 0x1
#define SELFID_PORT_NONE 0x0
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN_BITFIELD
+
+struct selfid {
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if true is struct ext_selfid */
+ u32 link_active:1;
+ u32 gap_count:6;
+ /* byte */
+ u32 speed:2;
+ u32 phy_delay:2;
+ u32 contender:1;
+ u32 power_class:3;
+ /* byte */
+ u32 port0:2;
+ u32 port1:2;
+ u32 port2:2;
+ u32 initiated_reset:1;
+ u32 more_packets:1;
+} __attribute__((packed));
+
+struct ext_selfid {
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if false is struct selfid */
+ u32 seq_nr:3;
+ u32 reserved:2;
+ u32 porta:2;
+ /* byte */
+ u32 portb:2;
+ u32 portc:2;
+ u32 portd:2;
+ u32 porte:2;
+ /* byte */
+ u32 portf:2;
+ u32 portg:2;
+ u32 porth:2;
+ u32 reserved2:1;
+ u32 more_packets:1;
+} __attribute__((packed));
+
+#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
+
+/*
+ * Note: these mean to be bit fields of a big endian SelfID as seen on a little
+ * endian machine.
+ */
+
+struct selfid {
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 gap_count:6;
+ u32 link_active:1;
+ u32 extended:1; /* if true is struct ext_selfid */
+ /* byte */
+ u32 power_class:3;
+ u32 contender:1;
+ u32 phy_delay:2;
+ u32 speed:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 initiated_reset:1;
+ u32 port2:2;
+ u32 port1:2;
+ u32 port0:2;
+} __attribute__((packed));
+
+struct ext_selfid {
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 porta:2;
+ u32 reserved:2;
+ u32 seq_nr:3;
+ u32 extended:1; /* if false is struct selfid */
+ /* byte */
+ u32 porte:2;
+ u32 portd:2;
+ u32 portc:2;
+ u32 portb:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 reserved2:1;
+ u32 porth:2;
+ u32 portg:2;
+ u32 portf:2;
+} __attribute__((packed));
+
+#else
+#error What? PDP endian?
+#endif /* __BIG_ENDIAN_BITFIELD */
+
+
#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 771189f0b..c7ce73144 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -2,11 +2,12 @@
* IEEE 1394 for Linux
*
* Core support: hpsb_packet management, packet handling and forwarding to
- * csr or lowlevel code
+ * highlevel or lowlevel code
*
* Copyright (C) 1999, 2000 Andreas E. Bombe
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
@@ -62,7 +63,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
packet->header = header;
if (data_size) {
- data = kmalloc(data_size + 4, kmflags);
+ data = kmalloc(data_size + 8, kmflags);
if (data == NULL) {
kfree(header);
kfree(packet);
@@ -70,18 +71,14 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
}
packet->data = data;
- packet->data_size = data_size - 4;
+ packet->data_size = data_size;
}
INIT_LIST_HEAD(&packet->list);
sema_init(&packet->state_change, 0);
packet->state = unused;
packet->generation = get_hpsb_generation();
-
-#ifdef __BIG_ENDIAN
- /* set default */
packet->data_be = 1;
-#endif
return packet;
}
@@ -133,59 +130,55 @@ static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
{
int nodeid = -1;
int rest_of_selfids = num_of_selfids;
- quadlet_t *sidp = host->topology_map;
- quadlet_t sid = *sidp;
+ struct selfid *sid = (struct selfid *)host->topology_map;
+ struct ext_selfid *esid;
int esid_seq = 23;
- int i;
while (rest_of_selfids--) {
- sid = *(sidp++);
-
- if (!(sid & 0x00800000) /* !extended */) {
+ if (!sid->extended) {
nodeid++;
esid_seq = 0;
-
- if (((sid >> 24) & NODE_MASK) != nodeid) {
+
+ if (sid->phy_id != nodeid) {
HPSB_INFO("SelfIDs failed monotony check with "
- "%d", (sid >> 24) & NODE_MASK);
+ "%d", sid->phy_id);
return 0;
}
-
- /* "if is contender and link active" */
- if ((sid & (1<<11)) && (sid & (1<<22))) {
- host->irm_id = LOCAL_BUS | ((sid >> 24)
- & NODE_MASK);
+
+ if (sid->contender && sid->link_active) {
+ host->irm_id = LOCAL_BUS | sid->phy_id;
}
} else {
- if ((((sid >> 24) & NODE_MASK) != nodeid)
- || (((sid >> 20) & 0x7) != esid_seq)) {
+ esid = (struct ext_selfid *)sid;
+
+ if ((esid->phy_id != nodeid)
+ || (esid->seq_nr != esid_seq)) {
HPSB_INFO("SelfIDs failed monotony check with "
- "%d/%d", (sid >> 24) & NODE_MASK,
- (sid >> 20) & 0x7);
+ "%d/%d", esid->phy_id, esid->seq_nr);
return 0;
}
esid_seq++;
}
- }
-
- sidp--;
- while (sid & 0x00800000 /* extended */) {
- /* check that no ports go to a parent */
- for (i = 2; i < 18; i += 2) {
- if ((sid & (0x3 << i)) == (0x2 << i)) {
+ sid++;
+ }
+
+ esid = (struct ext_selfid *)(sid - 1);
+ while (esid->extended) {
+ if ((esid->porta == 0x2) || (esid->portb == 0x2)
+ || (esid->portc == 0x2) || (esid->portd == 0x2)
+ || (esid->porte == 0x2) || (esid->portf == 0x2)
+ || (esid->portg == 0x2) || (esid->porth == 0x2)) {
HPSB_INFO("SelfIDs failed root check on "
"extended SelfID");
return 0;
- }
}
- sid = *(sidp--);
+ esid--;
}
- for (i = 2; i < 8; i += 2) {
- if ((sid & (0x3 << i)) == (0x2 << i)) {
+ sid = (struct selfid *)esid;
+ if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {
HPSB_INFO("SelfIDs failed root check");
return 0;
- }
}
return nodeid + 1;
@@ -196,7 +189,8 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
char speedcap[nodecount];
char cldcnt[nodecount];
u8 *map = host->speed_map;
- quadlet_t *sidp;
+ struct selfid *sid;
+ struct ext_selfid *esid;
int i, j, n;
for (i = 0; i < (nodecount * 64); i += 64) {
@@ -210,22 +204,26 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
}
/* find direct children count and speed */
- for (sidp = &host->topology_map[host->selfid_count-1],
+ for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
n = nodecount - 1;
- sidp >= host->topology_map; sidp--) {
- if (*sidp & 0x00800000 /* extended */) {
- for (i = 2; i < 18; i += 2) {
- if ((*sidp & (0x3 << i)) == (0x3 << i)) {
- cldcnt[n]++;
- }
- }
+ (void *)sid >= (void *)host->topology_map; sid--) {
+ if (sid->extended) {
+ esid = (struct ext_selfid *)sid;
+
+ if (esid->porta == 0x3) cldcnt[n]++;
+ if (esid->portb == 0x3) cldcnt[n]++;
+ if (esid->portc == 0x3) cldcnt[n]++;
+ if (esid->portd == 0x3) cldcnt[n]++;
+ if (esid->porte == 0x3) cldcnt[n]++;
+ if (esid->portf == 0x3) cldcnt[n]++;
+ if (esid->portg == 0x3) cldcnt[n]++;
+ if (esid->porth == 0x3) cldcnt[n]++;
} else {
- for (i = 2; i < 8; i += 2) {
- if ((*sidp & (0x3 << i)) == (0x3 << i)) {
- cldcnt[n]++;
- }
- }
- speedcap[n] = (*sidp >> 14) & 0x3;
+ if (sid->port0 == 0x3) cldcnt[n]++;
+ if (sid->port1 == 0x3) cldcnt[n]++;
+ if (sid->port2 == 0x3) cldcnt[n]++;
+
+ speedcap[n] = sid->speed;
n--;
}
}
@@ -262,7 +260,7 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
if (host->in_bus_reset) {
- printk("including selfid 0x%x\n", sid);
+ HPSB_DEBUG("including selfid 0x%x", sid);
host->topology_map[host->selfid_count++] = sid;
} else {
/* FIXME - info on which host */
@@ -293,7 +291,12 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
}
/* irm_id is kept up to date by check_selfids() */
- host->is_irm = (host->irm_id == host->node_id);
+ if (host->irm_id == host->node_id) {
+ host->is_irm = 1;
+ host->is_busmgr = 1;
+ host->busmgr_id = host->node_id;
+ host->csr.bus_manager_id = host->node_id;
+ }
host->reset_retries = 0;
inc_hpsb_generation();
@@ -346,6 +349,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64
+ (packet->node_id & NODE_MASK)];
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
switch (packet->speed_code) {
case 2:
dump_packet("send packet 400:", packet->header,
@@ -359,6 +363,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
dump_packet("send packet 100:", packet->header,
packet->header_size);
}
+#endif
return host->template->transmit_packet(host, packet);
}
@@ -459,12 +464,14 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
{
struct hpsb_packet *p;
+ dsize += (dsize % 4 ? 4 - (dsize % 4) : 0);
+
p = alloc_hpsb_packet(dsize);
if (p == NULL) {
/* FIXME - send data_error response */
return NULL;
}
-
+
p->type = async;
p->state = unused;
p->host = host;
@@ -472,6 +479,10 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
p->tlabel = (data[0] >> 10) & 0x3f;
p->no_waiter = 1;
+ if (dsize % 4) {
+ p->data[dsize / 4] = 0;
+ }
+
return p;
}
@@ -479,21 +490,12 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
packet = create_reply_packet(host, data, length); \
if (packet == NULL) break
-inline void swap_quadlets_on_le(quadlet_t *q)
-{
-#ifdef __LITTLE_ENDIAN
- quadlet_t saved = q[0];
- q[0] = q[1];
- q[1] = saved;
-#endif
-}
-
-
void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
size_t size)
{
struct hpsb_packet *packet;
int length, rcode, extcode;
+ int source = data[1] >> 16;
u64 addr;
/* big FIXME - no error checking is done for an out of bounds length */
@@ -501,7 +503,7 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
switch (tcode) {
case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, data+3, addr, 4);
+ rcode = highlevel_write(host, source, data+3, addr, 4);
if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
@@ -513,7 +515,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, data+4, addr, data[3]>>16);
+ rcode = highlevel_write(host, source, data+4, addr,
+ data[3]>>16);
if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
@@ -527,7 +530,7 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
PREP_REPLY_PACKET(0);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, data, addr, 4);
+ rcode = highlevel_read(host, source, data, addr, 4);
fill_async_readquad_resp(packet, rcode, *data);
send_packet_nocare(packet);
break;
@@ -537,7 +540,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
PREP_REPLY_PACKET(length);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, packet->data, addr, length);
+ rcode = highlevel_read(host, source, packet->data, addr,
+ length);
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
break;
@@ -556,35 +560,32 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
switch (length) {
case 4:
- rcode = highlevel_lock(host, packet->data, addr,
+ rcode = highlevel_lock(host, source, packet->data, addr,
data[4], 0, extcode);
fill_async_lock_resp(packet, rcode, extcode, 4);
break;
case 8:
if ((extcode != EXTCODE_FETCH_ADD)
&& (extcode != EXTCODE_LITTLE_ADD)) {
- rcode = highlevel_lock(host, packet->data, addr,
+ rcode = highlevel_lock(host, source,
+ packet->data, addr,
data[5], data[4],
extcode);
fill_async_lock_resp(packet, rcode, extcode, 4);
} else {
- swap_quadlets_on_le(data + 4);
- rcode = highlevel_lock64(host,
+ rcode = highlevel_lock64(host, source,
(octlet_t *)packet->data, addr,
*(octlet_t *)(data + 4), 0ULL,
extcode);
- swap_quadlets_on_le(packet->data);
fill_async_lock_resp(packet, rcode, extcode, 8);
}
break;
case 16:
- swap_quadlets_on_le(data + 4);
- swap_quadlets_on_le(data + 6);
- rcode = highlevel_lock64(host, (octlet_t *)packet->data,
- addr, *(octlet_t *)(data + 6),
+ rcode = highlevel_lock64(host, source,
+ (octlet_t *)packet->data, addr,
+ *(octlet_t *)(data + 6),
*(octlet_t *)(data + 4),
extcode);
- swap_quadlets_on_le(packet->data);
fill_async_lock_resp(packet, rcode, extcode, 8);
break;
default:
@@ -609,7 +610,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size)
return;
}
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
dump_packet("received packet:", data, size);
+#endif
tcode = (data[0] >> 4) & 0xf;
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 171a2fa9f..636aef40e 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -40,29 +40,26 @@ struct hpsb_packet {
unsigned no_waiter:1;
/* Data big endianness flag - may vary from request to request. The
- * header is always in machine byte order. */
+ * header is always in machine byte order.
+ * Not really used currently. */
unsigned data_be:1;
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
unsigned speed_code:2;
- /* --- 16 bytes (one cacheline) --- */
-
- /* *header and *data are guaranteed to be 32-bit DMAable and may be
+ /*
+ * *header and *data are guaranteed to be 32-bit DMAable and may be
* overwritten to allow in-place byte swapping. Neither of these is
* CRCed (the sizes also don't include CRC), but contain space for at
* least one additional quadlet to allow in-place CRCing. The memory is
* also guaranteed to have physical mapping (virt_to_bus() is meaningful
* on these pointers).
- * NOTE: The 32-bit DMA guarantee is currently not enforced.
- * That's a Linux 2.3 issue.
*/
quadlet_t *header;
quadlet_t *data;
size_t header_size;
size_t data_size;
- /* --- 32 bytes --- */
struct hpsb_host *host;
unsigned int generation;
@@ -139,12 +136,14 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
* for other cases (internal errors that don't justify a panic). Safe to call
* from within a transmit packet routine.
*/
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode);
+void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
+ int ackcode);
/*
* Hand over received packet to the core. The contents of data are expected to
* be the full packet but with the CRCs left out (data block follows header
- * immediately) and in machine byte order. *data can be safely overwritten
+ * immediately), with the header (i.e. the first four quadlets) in machine byte
+ * order and the data block in big endian. *data can be safely overwritten
* after this call.
*/
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size);
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index e2eeffc68..6f07a7f6a 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -68,7 +68,7 @@ void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
packet->header[3] = length << 16;
packet->header_size = 16;
- packet->data_size = length;
+ packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data)
@@ -85,8 +85,8 @@ void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length)
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
packet->header[3] = length << 16;
packet->header_size = 16;
- packet->data_size = length;
packet->expect_response = 1;
+ packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
@@ -260,7 +260,7 @@ int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length)
{
if (host->node_id != node) return -1;
- return highlevel_read(host, buffer, addr, length);
+ return highlevel_read(host, node, buffer, addr, length);
}
struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
@@ -284,7 +284,7 @@ struct hpsb_packet *hpsb_make_readbpacket(struct hpsb_host *host, nodeid_t node,
{
struct hpsb_packet *p;
- p = alloc_hpsb_packet(length);
+ p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
if (!p) return NULL;
p->host = host;
@@ -318,9 +318,13 @@ struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
{
struct hpsb_packet *p;
- p = alloc_hpsb_packet(length);
+ p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
if (!p) return NULL;
+ if (length % 4) {
+ p->data[length / 4] = 0;
+ }
+
p->host = host;
p->tlabel = get_tlabel(host, node, 1);
p->node_id = node;
@@ -370,7 +374,7 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
}
if (host->node_id == node) {
- switch(highlevel_read(host, buffer, addr, length)) {
+ switch(highlevel_read(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
@@ -381,16 +385,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
}
}
- if (length & 0x3) {
- /* FIXME: Lengths not multiple of 4 are not implemented. Mainly
- * there is the problem with little endian machines because we
- * always swap to little endian on receive. If we read 5 bytes
- * 12345 we receive them as 12345000 and swap them to 43210005.
- * How should we copy that to the caller? Require *buffer to be
- * a full quadlet multiple in length? */
- return -EACCES;
- }
-
if (length == 4) {
packet = hpsb_make_readqpacket(host, node, addr);
} else {
@@ -432,7 +426,7 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
}
if (host->node_id == node) {
- switch(highlevel_write(host, buffer, addr, length)) {
+ switch(highlevel_write(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
@@ -443,12 +437,6 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
}
}
- if (length & 0x3) {
- /* FIXME: Lengths not multiple of 4 are not implemented. See function
- * hpsb_read for explanation, same reason, different direction. */
- return -EACCES;
- }
-
if (length == 4) {
packet = hpsb_make_writeqpacket(host, node, addr, *buffer);
} else {
@@ -483,7 +471,8 @@ int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
int retval = 0, length;
if (host->node_id == node) {
- switch(highlevel_lock(host, data, addr, *data, arg, extcode)) {
+ switch(highlevel_lock(host, node, data, addr, *data, arg,
+ extcode)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
index d619182dd..d817e61c6 100644
--- a/drivers/ieee1394/ieee1394_types.h
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -6,6 +6,7 @@
#include <linux/types.h>
#include <linux/version.h>
#include <linux/list.h>
+#include <asm/byteorder.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
@@ -24,6 +25,8 @@ static __inline__ void list_add_tail(struct list_head *new, struct list_head *he
__list_add(new, head->prev, head);
}
+#define __constant_cpu_to_be32(x) __constant_htonl((x))
+
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index b8fae7ee2..488e013fb 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -35,9 +35,18 @@
* . Config ROM
*
* Known bugs:
- * . Self-id are not received properly if card
- * is initialized with no other nodes on the
- * bus.
+ * . Self-id are sometimes not received properly
+ * if card is initialized with no other nodes
+ * on the bus
+ */
+
+/*
+ * Acknowledgments:
+ *
+ * Emilie Chung <emilie.chung@axis.com>
+ * .Tip on Async Request Filter
+ * Pascal Drolet <pascal.drolet@informission.ca>
+ * .Various tips for optimization and functionnalities
*/
#include <linux/config.h>
@@ -71,11 +80,15 @@
#include "ieee1394_core.h"
#include "ohci1394.h"
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define OHCI1394_DEBUG
+#endif
+
#ifdef DBGMSG
#undef DBGMSG
#endif
-#if OHCI1394_DEBUG
+#ifdef OHCI1394_DEBUG
#define DBGMSG(card, fmt, args...) \
printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)
#else
@@ -97,10 +110,14 @@ printk(level "ohci1394_%d: " fmt "\n" , card , ## args)
return 1;
int supported_chips[][2] = {
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 },
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
{ PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 },
{ -1, -1 }
};
@@ -213,7 +230,7 @@ inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
if (q[0] == ~q[1]) {
PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd",
q[0]);
- hpsb_selfid_received(host, q[0]);
+ hpsb_selfid_received(host, cpu_to_be32(q[0]));
if (((q[0]&0x3f000000)>>24)==phyid) {
lsid=q[0];
PRINT(KERN_INFO, ohci->id,
@@ -369,6 +386,23 @@ static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
}
+/* Count the number of available iso contexts */
+static int get_nb_iso_ctx(struct ti_ohci *ohci)
+{
+ int i,ctx=0;
+ u32 tmp;
+
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0xffffffff);
+ tmp = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+
+ /* Count the number of contexts */
+ for(i=0; i<32; i++) {
+ if(tmp & 1) ctx++;
+ tmp >>= 1;
+ }
+ return ctx;
+}
+
/* Global initialization */
static int ohci_initialize(struct hpsb_host *host)
{
@@ -411,15 +445,22 @@ static int ohci_initialize(struct hpsb_host *host)
virt_to_bus(ohci->csr_config_rom));
/* Write the config ROM header */
- reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]);
+ reg_write(ohci, OHCI1394_ConfigROMhdr,
+ cpu_to_be32(ohci->csr_config_rom[0]));
/* Set bus options */
- reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]);
-
- /* Write the GUID into the csr config rom */
- ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
- ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
+ reg_write(ohci, OHCI1394_BusOptions,
+ cpu_to_be32(ohci->csr_config_rom[2]));
+ /* Write the GUID into the csr config rom */
+ ohci->csr_config_rom[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
+ ohci->csr_config_rom[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
+
+ ohci->max_packet_size =
+ 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
+ PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes",
+ ohci->max_packet_size);
+
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -427,7 +468,10 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
/* Initialize IR dma */
- for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */
+ ohci->nb_iso_ctx = get_nb_iso_ctx(ohci);
+ PRINT(KERN_INFO, ohci->id, "%d iso contexts available",
+ ohci->nb_iso_ctx);
+ for (i=0;i<ohci->nb_iso_ctx;i++) {
reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
@@ -465,7 +509,6 @@ static int ohci_initialize(struct hpsb_host *host)
* Accept AT requests from all nodes. This probably
* will have to be controlled from the subsystem
* on a per node basis.
- * (Tip by Emilie Chung <emilie.chung@axis.com>)
*/
reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
@@ -578,8 +621,9 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
unsigned char tcode;
int i=50;
- if (packet->data_size >= 4096) {
- PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)",
+ if (packet->data_size >= ohci->max_packet_size) {
+ PRINT(KERN_ERR, ohci->id,
+ "transmit packet size = %d too big",
packet->data_size);
return 0;
}
@@ -587,24 +631,8 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
/* Decide wether we have a request or a response packet */
tcode = (packet->header[0]>>4)&0xf;
- if ((tcode==TCODE_READQ)||
- (tcode==TCODE_WRITEQ)||
- (tcode==TCODE_READB)||
- (tcode==TCODE_WRITEB)||
- (tcode==TCODE_LOCK_REQUEST))
- d = ohci->at_req_context;
-
- else if ((tcode==TCODE_WRITE_RESPONSE)||
- (tcode==TCODE_READQ_RESPONSE)||
- (tcode==TCODE_READB_RESPONSE)||
- (tcode==TCODE_LOCK_RESPONSE))
- d = ohci->at_resp_context;
-
- else {
- PRINT(KERN_ERR, ohci->id,
- "Unexpected packet tcode=%d in AT DMA", tcode);
- return 0;
- }
+ if (tcode & 0x02) d = ohci->at_resp_context;
+ else d = ohci->at_req_context;
spin_lock(&d->lock);
@@ -659,6 +687,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
switch (cmd) {
case RESET_BUS:
+ host->attempt_root=1;
PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
(host->attempt_root ? " and attempting to become root"
: ""));
@@ -679,15 +708,21 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
break;
case ACT_CYCLE_MASTER:
-#if 0
if (arg) {
- /* enable cycleTimer, cycleMaster, cycleSource */
- reg_write(ohci, OHCI1394_LinkControlSet, 0x00700000);
+ /* check if we are root and other nodes are present */
+ u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
+ if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
+ /*
+ * enable cycleTimer cycleMaster cycleSource
+ */
+ DBGMSG(ohci->id, "Cycle master enabled");
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ 0x00700000);
+ }
} else {
/* disable cycleTimer, cycleMaster, cycleSource */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000);
- };
-#endif
+ }
break;
case CANCEL_REQUESTS:
@@ -811,8 +846,20 @@ static void ohci_irq_handler(int irq, void *dev_id,
struct hpsb_host *host = ohci->host;
int phyid = -1, isroot = 0;
+ /* read the interrupt event register */
event=reg_read(ohci, OHCI1394_IntEventSet);
+#if 0
+ /*
+ * clear the interrupt event register, except for the
+ * bus reset event interrupt (if any). This is an
+ * attempt to comply with ohci spec 7.2.3.2
+ */
+ reg_write(ohci, OHCI1394_IntEventClear, event & (~OHCI1394_busReset));
+#else
+ /* The above attempt doesn't work */
+ reg_write(ohci, OHCI1394_IntEventClear, event);
+#endif
if (event & OHCI1394_busReset) {
if (!host->in_bus_reset) {
PRINT(KERN_INFO, ohci->id, "Bus reset");
@@ -821,6 +868,11 @@ static void ohci_irq_handler(int irq, void *dev_id,
dma_trm_reset(ohci->at_req_context);
dma_trm_reset(ohci->at_resp_context);
+#if 0
+ /* clear the bus reset event */
+ reg_write(ohci, OHCI1394_IntEventClear,
+ OHCI1394_busReset);
+#endif
/* Subsystem call */
hpsb_bus_reset(ohci->host);
@@ -891,7 +943,7 @@ static void ohci_irq_handler(int irq, void *dev_id,
if (event & OHCI1394_selfIDComplete) {
if (host->in_bus_reset) {
node_id = reg_read(ohci, OHCI1394_NodeID);
- if (node_id & 0x8000000) { /* NodeID valid */
+ if (node_id & 0x80000000) { /* NodeID valid */
phyid = node_id & 0x0000003f;
isroot = (node_id & 0x40000000) != 0;
@@ -924,8 +976,6 @@ static void ohci_irq_handler(int irq, void *dev_id,
#endif
}
- /* clear the interrupt event register */
- reg_write(ohci, OHCI1394_IntEventClear, event);
}
/* Put the buffer back into the dma context */
@@ -963,44 +1013,34 @@ static int block_length(struct dma_rcv_ctx *d, int idx,
return length;
}
-static int packet_length(struct dma_rcv_ctx *d, int idx,
- quadlet_t *buf_ptr, int offset)
+const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
+ -1, 0, -1, 0, -1, -1, 16, -1};
+
+/*
+ * Determine the length of a packet in the buffer
+ * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
+ */
+static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
+int offset)
{
- unsigned char tcode;
- int length;
+ unsigned char tcode;
+ int length = -1;
/* Let's see what kind of packet is in there */
- tcode = (buf_ptr[0]>>4)&0xf;
-
- if (d->ctx==0) { /* Async Receive Request */
- if (tcode==TCODE_READQ) return 16;
- else if (tcode==TCODE_WRITEQ ||
- tcode==TCODE_READB) return 20;
- else if (tcode==TCODE_WRITEB ||
- tcode==TCODE_LOCK_REQUEST) {
- return block_length(d, idx, buf_ptr, offset) + 20;
- }
- else if (tcode==0xE) { /* Phy packet */
- return 16;
- }
- else return -1;
- }
- else if (d->ctx==1) { /* Async Receive Response */
- if (tcode==TCODE_WRITE_RESPONSE) return 16;
- else if (tcode==TCODE_READQ_RESPONSE) return 20;
- else if (tcode==TCODE_READB_RESPONSE ||
- tcode==TCODE_LOCK_RESPONSE) {
- return block_length(d, idx, buf_ptr, offset) + 20;
- }
- else return -1;
+ tcode = (buf_ptr[0] >> 4) & 0xf;
+
+ if (d->ctx < 2) { /* Async Receive Response/Request */
+ length = TCODE_SIZE[tcode];
+ if (length == 0)
+ length = block_length(d, idx, buf_ptr, offset) + 20;
}
else if (d->ctx==2) { /* Iso receive */
/* Assumption: buffer fill mode with header/trailer */
length = (buf_ptr[0]>>16);
if (length % 4) length += 4 - (length % 4);
- return length+8;
+ length+=8;
}
- return -1;
+ return length;
}
/* Bottom half that processes dma receive buffers */
@@ -1336,6 +1376,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
static int add_card(struct pci_dev *dev)
{
struct ti_ohci *ohci; /* shortcut to currently handled device */
+ int i;
if (num_of_cards == MAX_OHCI1394_CARDS) {
PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
@@ -1344,6 +1385,10 @@ static int add_card(struct pci_dev *dev)
return 1;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ pci_enable_device(dev);
+#endif
+
ohci = &cards[num_of_cards++];
ohci->id = num_of_cards-1;
@@ -1363,7 +1408,11 @@ static int add_card(struct pci_dev *dev)
if (ohci->csr_config_rom == NULL) {
FAIL("failed to allocate buffer config rom");
}
- memcpy(ohci->csr_config_rom, ohci_csr_rom, sizeof(ohci_csr_rom));
+ for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
+ ohci->csr_config_rom[i] = cpu_to_be32(ohci_csr_rom[i]);
+
+ DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
+ *((char *)ohci->csr_config_rom+4));
/* self-id dma buffer allocation */
ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL);
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index 46d9a270f..f0ec83d48 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -4,16 +4,18 @@
#include "ieee1394_types.h"
-#define OHCI1394_DEBUG 1
-
#define OHCI1394_DRIVER_NAME "ohci1394"
-#ifndef PCI_DEVICE_ID_TI_OHCI1394
-#define PCI_DEVICE_ID_TI_OHCI1394 0x8009
-#endif
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV22
+#define PCI_DEVICE_ID_TI_OHCI1394_LV22 0x8009
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV23
+#define PCI_DEVICE_ID_TI_OHCI1394_LV23 0x8019
+#endif
-#ifndef PCI_DEVICE_ID_TI_OHCI1394_2
-#define PCI_DEVICE_ID_TI_OHCI1394_2 0x8019
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV26
+#define PCI_DEVICE_ID_TI_OHCI1394_LV26 0x8020
#endif
#ifndef PCI_DEVICE_ID_VIA_OHCI1394
@@ -28,6 +30,22 @@
#define PCI_DEVICE_ID_SONY_CXD3222 0x8039
#endif
+#ifndef PCI_DEVICE_ID_NEC_1394
+#define PCI_DEVICE_ID_NEC_1394 0x00cd
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72862
+#define PCI_DEVICE_ID_NEC_UPD72862 0x0063
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72870
+#define PCI_DEVICE_ID_NEC_UPD72870 0x00cd
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72871
+#define PCI_DEVICE_ID_NEC_UPD72871 0x00ce
+#endif
+
#define MAX_OHCI1394_CARDS 4
#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
@@ -113,6 +131,8 @@ struct ti_ohci {
quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
quadlet_t *csr_config_rom; /* buffer for csr config rom */
+ unsigned int max_packet_size;
+
/* async receive */
struct dma_rcv_ctx *ar_resp_context;
struct dma_rcv_ctx *ar_req_context;
@@ -125,6 +145,7 @@ struct ti_ohci {
struct dma_rcv_ctx *ir_context;
u64 IR_channel_usage;
spinlock_t IR_channel_lock;
+ int nb_iso_ctx;
/* IEEE-1394 part follows */
struct hpsb_host *host;
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 2714a6eb5..773d68983 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -59,6 +59,13 @@
/* print card specific information */
#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
+#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+#else
+#define PRINT_GD(level, fmt, args...)
+#define PRINTD(level, card, fmt, args...)
+#endif
static struct ti_lynx cards[MAX_PCILYNX_CARDS];
static int num_of_cards = 0;
@@ -313,7 +320,8 @@ static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
}
}
- printk("-%d- generated own selfid 0x%x\n", lynx->id, lsid);
+ cpu_to_be32s(&lsid);
+ PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
return lsid;
}
@@ -322,7 +330,14 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t s
quadlet_t *q = lynx->rcv_page;
int phyid, isroot;
quadlet_t lsid = 0;
+ int i;
+ i = (size > 16 ? 16 : size) / 4 - 1;
+ while (i >= 0) {
+ cpu_to_be32s(&q[i]);
+ i--;
+ }
+
if (!lynx->phyic.reg_1394a) {
lsid = generate_own_selfid(lynx, host);
}
@@ -339,17 +354,20 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t s
}
while (size > 0) {
- if (!lynx->phyic.reg_1394a
- && (q[0] & 0x3f800000) == ((phyid + 1) << 24)) {
+ struct selfid *sid = (struct selfid *)q;
+
+ if (!lynx->phyic.reg_1394a && !sid->extended
+ && (sid->phy_id == (phyid + 1))) {
hpsb_selfid_received(host, lsid);
}
if (q[0] == ~q[1]) {
- printk("-%d- selfid packet 0x%x rcvd\n", lynx->id, q[0]);
+ PRINT(KERN_DEBUG, lynx->id, "selfid packet 0x%x rcvd",
+ q[0]);
hpsb_selfid_received(host, q[0]);
} else {
- printk("-%d- inconsistent selfid 0x%x/0x%x\n", lynx->id,
- q[0], q[1]);
+ PRINT(KERN_INFO, lynx->id,
+ "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
}
q += 2;
size -= 8;
@@ -429,14 +447,14 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
#ifdef __BIG_ENDIAN
- pcl.buffer[0].control = PCL_CMD_RCV | 2048;
- pcl.buffer[1].control = PCL_LAST_BUFF | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#else
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 2048;
- pcl.buffer[1].control = PCL_LAST_BUFF | PCL_BIGENDIAN | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#endif
pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page);
- pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 2048;
+ pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 16;
put_pcl(lynx, lynx->rcv_pcl, &pcl);
pcl.next = pcl_bus(lynx, lynx->async_pcl);
@@ -445,10 +463,11 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_LAST_BUFF | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | 4;
#ifndef __BIG_ENDIAN
pcl.buffer[0].control |= PCL_BIGENDIAN;
#endif
+ pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
for (i = 0; i < NUM_ISORCV_PCL; i++) {
int page = i / ISORCV_PER_PAGE;
@@ -456,6 +475,7 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page])
+ sec * MAX_ISORCV_SIZE;
+ pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
}
@@ -539,6 +559,10 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
}
packet->xnext = NULL;
+ if (packet->tcode == TCODE_WRITEQ
+ || packet->tcode == TCODE_READQ_RESPONSE) {
+ cpu_to_be32s(&packet->header[3]);
+ }
spin_lock_irqsave(&lynx->async_queue_lock, flags);
@@ -1054,8 +1078,8 @@ static void lynx_irq_handler(int irq, void *dev_id,
}
if (linkint & LINK_INT_PHY_REG_RCVD) {
if (!host->in_bus_reset) {
- printk("-%d- phy reg received without reset\n",
- lynx->id);
+ PRINT(KERN_INFO, lynx->id,
+ "phy reg received without reset");
}
}
if (linkint & LINK_INT_ISO_STUCK) {
@@ -1082,7 +1106,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
}
if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
- PRINT(KERN_INFO, lynx->id, "iso receive");
+ PRINTD(KERN_DEBUG, lynx->id, "iso receive");
spin_lock(&lynx->iso_rcv.lock);
@@ -1094,7 +1118,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
|| !lynx->iso_rcv.chan_count) {
- printk("stopped\n");
+ PRINTD(KERN_DEBUG, lynx->id, "stopped");
reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
}
@@ -1125,9 +1149,9 @@ static void lynx_irq_handler(int irq, void *dev_id,
spin_unlock(&lynx->async_queue_lock);
if (ack & DMA_CHAN_STAT_SPECIALACK) {
- printk("-%d- special ack %d\n", lynx->id,
- (ack >> 15) & 0xf);
- ack = ACKX_SEND_ERROR;
+ ack = (ack >> 15) & 0xf;
+ PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
+ ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
} else {
ack = (ack >> 15) & 0xf;
}
@@ -1139,7 +1163,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
/* general receive DMA completed */
int stat = reg_read(lynx, DMA1_CHAN_STAT);
- printk("-%d- received packet size %d\n", lynx->id,
+ PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
stat & 0x1fff);
if (stat & DMA_CHAN_STAT_SELFID) {
@@ -1149,8 +1173,12 @@ static void lynx_irq_handler(int irq, void *dev_id,
| LINK_CONTROL_TX_ASYNC_EN
| LINK_CONTROL_RX_ASYNC_EN);
} else {
- hpsb_packet_received(host, lynx->rcv_page,
- stat & 0x1fff);
+ quadlet_t *q_data = lynx->rcv_page;
+ if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
+ || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
+ cpu_to_be32s(q_data + 3);
+ }
+ hpsb_packet_received(host, q_data, stat & 0x1fff);
}
run_pcl(lynx, lynx->rcv_pcl_start, 1);
@@ -1411,7 +1439,7 @@ static int init_driver()
}
if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
- PRINT_G(KERN_ERR, "allocation of char major number %d failed\n",
+ PRINT_G(KERN_ERR, "allocation of char major number %d failed",
PCILYNX_MAJOR);
return -EBUSY;
}
@@ -1453,13 +1481,13 @@ MODULE_SUPPORTED_DEVICE("pcilynx");
void cleanup_module(void)
{
hpsb_unregister_lowlevel(get_lynx_template());
- PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module\n");
+ PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
}
int init_module(void)
{
if (hpsb_register_lowlevel(get_lynx_template())) {
- PRINT_G(KERN_ERR, "registering failed\n");
+ PRINT_G(KERN_ERR, "registering failed");
return -ENXIO;
} else {
return 0;
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index 2809bde08..f8154bb42 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -462,71 +462,75 @@ inline static void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
#define PCL_BIGENDIAN (1<<16)
+#define _(x) (__constant_cpu_to_be32(x))
+
quadlet_t lynx_csr_rom[] = {
/* bus info block */
- 0x04040000, /* info/CRC length, CRC */
- 0x31333934, /* 1394 magic number */
- 0xf064a000, /* misc. settings */
- 0x08002850, /* vendor ID, chip ID high */
- 0x0000ffff, /* chip ID low */
+ _(0x04040000), /* info/CRC length, CRC */
+ _(0x31333934), /* 1394 magic number */
+ _(0xf064a000), /* misc. settings */
+ _(0x08002850), /* vendor ID, chip ID high */
+ _(0x0000ffff), /* chip ID low */
/* root directory */
- 0x00090000, /* CRC length, CRC */
- 0x03080028, /* vendor ID (Texas Instr.) */
- 0x81000009, /* offset to textual ID */
- 0x0c000200, /* node capabilities */
- 0x8d00000e, /* offset to unique ID */
- 0xc7000010, /* offset to module independent info */
- 0x04000000, /* module hardware version */
- 0x81000026, /* offset to textual ID */
- 0x09000000, /* node hardware version */
- 0x81000026, /* offset to textual ID */
+ _(0x00090000), /* CRC length, CRC */
+ _(0x03080028), /* vendor ID (Texas Instr.) */
+ _(0x81000009), /* offset to textual ID */
+ _(0x0c000200), /* node capabilities */
+ _(0x8d00000e), /* offset to unique ID */
+ _(0xc7000010), /* offset to module independent info */
+ _(0x04000000), /* module hardware version */
+ _(0x81000026), /* offset to textual ID */
+ _(0x09000000), /* node hardware version */
+ _(0x81000026), /* offset to textual ID */
/* module vendor ID textual */
- 0x00080000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54455841, /* "Texas Instruments" */
- 0x5320494e,
- 0x53545255,
- 0x4d454e54,
- 0x53000000,
+ _(0x00080000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54455841), /* "Texas Instruments" */
+ _(0x5320494e),
+ _(0x53545255),
+ _(0x4d454e54),
+ _(0x53000000),
/* node unique ID leaf */
- 0x00020000, /* CRC length, CRC */
- 0x08002850, /* vendor ID, chip ID high */
- 0x0000ffff, /* chip ID low */
+ _(0x00020000), /* CRC length, CRC */
+ _(0x08002850), /* vendor ID, chip ID high */
+ _(0x0000ffff), /* chip ID low */
/* module dependent info */
- 0x00060000, /* CRC length, CRC */
- 0xb8000006, /* offset to module textual ID */
- 0x81000004, /* ??? textual descriptor */
- 0x39010000, /* SRAM size */
- 0x3a010000, /* AUXRAM size */
- 0x3b000000, /* AUX device */
+ _(0x00060000), /* CRC length, CRC */
+ _(0xb8000006), /* offset to module textual ID */
+ _(0x81000004), /* ??? textual descriptor */
+ _(0x39010000), /* SRAM size */
+ _(0x3a010000), /* AUXRAM size */
+ _(0x3b000000), /* AUX device */
/* module textual ID */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54534231, /* "TSB12LV21" */
- 0x324c5632,
- 0x31000000,
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54534231), /* "TSB12LV21" */
+ _(0x324c5632),
+ _(0x31000000),
/* part number */
- 0x00060000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x39383036, /* "9806000-0001" */
- 0x3030342d,
- 0x30303431,
- 0x20000001,
+ _(0x00060000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x39383036), /* "9806000-0001" */
+ _(0x3030342d),
+ _(0x30303431),
+ _(0x20000001),
/* module hardware version textual */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x5453424b, /* "TSBKPCITST" */
- 0x50434954,
- 0x53540000,
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x5453424b), /* "TSBKPCITST" */
+ _(0x50434954),
+ _(0x53540000),
/* node hardware version textual */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54534232, /* "TSB21LV03" */
- 0x313c5630,
- 0x33000000
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54534232), /* "TSB21LV03" */
+ _(0x313c5630),
+ _(0x33000000)
};
+
+#undef _
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 0e63acb33..4a994aba5 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -59,7 +59,7 @@ static void free_pending_request(struct pending_request *req)
{
if (req->ibs) {
if (atomic_dec_and_test(&req->ibs->refcount)) {
- atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size);
+ atomic_sub(req->ibs->data_size, &iso_buffer_size);
kfree(req->ibs);
}
} else if (req->free_data) {
@@ -109,6 +109,7 @@ static void queue_complete_cb(struct pending_request *req)
}
free_tlabel(packet->host, packet->node_id, packet->tlabel);
+
queue_complete_req(req);
}
@@ -215,6 +216,7 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
LIST_HEAD(reqs);
if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ HPSB_INFO("dropped iso packet");
return;
}
@@ -230,22 +232,23 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
continue;
}
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) break;
+
if (!ibs) {
ibs = kmalloc(sizeof(struct iso_block_store)
+ length, SLAB_ATOMIC);
- if (!ibs) break;
+ if (!ibs) {
+ kfree(req);
+ break;
+ }
atomic_add(length, &iso_buffer_size);
atomic_set(&ibs->refcount, 0);
+ ibs->data_size = length;
memcpy(ibs->data, data, length);
}
- req = __alloc_pending_request(SLAB_ATOMIC);
- if (!req) {
- kfree(ibs);
- break;
- }
-
atomic_inc(&ibs->refcount);
req->file_info = fi;
@@ -270,6 +273,75 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
}
}
+static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, unsigned int length)
+{
+ unsigned long flags;
+ struct list_head *lh;
+ struct host_info *hi;
+ struct file_info *fi;
+ struct pending_request *req;
+ struct iso_block_store *ibs = NULL;
+ LIST_HEAD(reqs);
+
+ if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ HPSB_INFO("dropped fcp request");
+ return;
+ }
+
+ spin_lock_irqsave(&host_info_lock, flags);
+ hi = find_host_info(host);
+
+ if (hi != NULL) {
+ for (lh = hi->file_info_list.next; lh != &hi->file_info_list;
+ lh = lh->next) {
+ fi = list_entry(lh, struct file_info, list);
+
+ if (!fi->fcp_buffer) {
+ continue;
+ }
+
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) break;
+
+ if (!ibs) {
+ ibs = kmalloc(sizeof(struct iso_block_store)
+ + length, SLAB_ATOMIC);
+ if (!ibs) {
+ kfree(req);
+ break;
+ }
+
+ atomic_add(length, &iso_buffer_size);
+ atomic_set(&ibs->refcount, 0);
+ ibs->data_size = length;
+ memcpy(ibs->data, data, length);
+ }
+
+ atomic_inc(&ibs->refcount);
+
+ req->file_info = fi;
+ req->ibs = ibs;
+ req->data = ibs->data;
+ req->req.type = RAW1394_REQ_FCP_REQUEST;
+ req->req.generation = get_hpsb_generation();
+ req->req.misc = nodeid | (direction << 16);
+ req->req.recvb = (quadlet_t *)fi->fcp_buffer;
+ req->req.length = length;
+
+ list_add_tail(&req->list, &reqs);
+ }
+ }
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
+ lh = reqs.next;
+ while (lh != &reqs) {
+ req = list_entry(lh, struct pending_request, list);
+ lh = lh->next;
+ queue_complete_req(req);
+ }
+}
+
static int dev_read(struct file *file, char *buffer, size_t count,
loff_t *offset_is_ignored)
@@ -455,8 +527,28 @@ static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
spin_unlock(&host_info_lock);
}
+static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
+{
+ if (req->req.misc) {
+ if (fi->fcp_buffer) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->fcp_buffer = (u8 *)req->req.recvb;
+ }
+ } else {
+ if (!fi->fcp_buffer) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->fcp_buffer = NULL;
+ }
+ }
+
+ req->req.length = 0;
+ queue_complete_req(req);
+}
+
static int handle_local_request(struct file_info *fi,
- struct pending_request *req)
+ struct pending_request *req, int node)
{
u64 addr = req->req.address & 0xffffffffffffULL;
@@ -466,7 +558,7 @@ static int handle_local_request(struct file_info *fi,
switch (req->req.type) {
case RAW1394_REQ_ASYNC_READ:
- req->req.error = highlevel_read(fi->host, req->data, addr,
+ req->req.error = highlevel_read(fi->host, node, req->data, addr,
req->req.length);
break;
@@ -477,8 +569,8 @@ static int handle_local_request(struct file_info *fi,
break;
}
- req->req.error = highlevel_write(fi->host, req->data, addr,
- req->req.length);
+ req->req.error = highlevel_write(fi->host, node, req->data,
+ addr, req->req.length);
req->req.length = 0;
break;
@@ -503,14 +595,16 @@ static int handle_local_request(struct file_info *fi,
}
if (req->req.length == 8) {
- req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[1],
+ req->req.error = highlevel_lock(fi->host, node,
+ req->data, addr,
+ req->data[1],
req->data[0],
req->req.misc);
req->req.length = 4;
} else {
- req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[0], 0,
+ req->req.error = highlevel_lock(fi->host, node,
+ req->data, addr,
+ req->data[0], 0,
req->req.misc);
}
break;
@@ -539,28 +633,27 @@ static int handle_remote_request(struct file_info *fi,
if (!packet) return -ENOMEM;
req->data = &packet->header[3];
- } else if ((req->req.length % 4) == 0) {
+ } else {
packet = hpsb_make_readbpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
req->data = packet->data;
- } else {
- req->req.error = RAW1394_ERROR_UNTIDY_LEN;
}
break;
case RAW1394_REQ_ASYNC_WRITE:
if (req->req.length == 4) {
- packet = hpsb_make_writeqpacket(fi->host, node, addr,
- 0);
- if (!packet) return -ENOMEM;
+ quadlet_t x;
- if (copy_from_user(&packet->header[3], req->req.sendb,
- 4)) {
+ if (copy_from_user(&x, req->req.sendb, 4)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
- } else if ((req->req.length % 4) == 0) {
+
+ packet = hpsb_make_writeqpacket(fi->host, node, addr,
+ x);
+ if (!packet) return -ENOMEM;
+ } else {
packet = hpsb_make_writebpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
@@ -569,8 +662,6 @@ static int handle_remote_request(struct file_info *fi,
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
- } else {
- req->req.error = RAW1394_ERROR_UNTIDY_LEN;
}
req->req.length = 0;
break;
@@ -649,6 +740,11 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
return sizeof(struct raw1394_request);
}
+ if (req->req.type == RAW1394_REQ_FCP_LISTEN) {
+ handle_fcp_listen(fi, req);
+ return sizeof(struct raw1394_request);
+ }
+
if (req->req.length == 0) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
queue_complete_req(req);
@@ -656,7 +752,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
}
if (fi->host->node_id == node) {
- return handle_local_request(fi, req);
+ return handle_local_request(fi, req, node);
}
return handle_remote_request(fi, req, node);
@@ -806,10 +902,11 @@ static int dev_release(struct inode *inode, struct file *file)
}
static struct hpsb_highlevel_ops hl_ops = {
- add_host,
- remove_host,
- host_reset,
- iso_receive
+ add_host: add_host,
+ remove_host: remove_host,
+ host_reset: host_reset,
+ iso_receive: iso_receive,
+ fcp_request: fcp_request,
};
static struct file_operations file_ops = {
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
index b1b0e4b90..f23bfc051 100644
--- a/drivers/ieee1394/raw1394.h
+++ b/drivers/ieee1394/raw1394.h
@@ -5,7 +5,7 @@
#define RAW1394_DEVICE_MAJOR 171
#define RAW1394_DEVICE_NAME "raw1394"
-#define RAW1394_KERNELAPI_VERSION 1
+#define RAW1394_KERNELAPI_VERSION 2
/* state: opened */
#define RAW1394_REQ_INITIALIZE 1
@@ -21,10 +21,12 @@
#define RAW1394_REQ_LOCK64 103
#define RAW1394_REQ_ISO_LISTEN 200
+#define RAW1394_REQ_FCP_LISTEN 201
/* kernel to user */
#define RAW1394_REQ_BUS_RESET 10000
#define RAW1394_REQ_ISO_RECEIVE 10001
+#define RAW1394_REQ_FCP_REQUEST 10002
/* error codes */
#define RAW1394_ERROR_NONE 0
@@ -67,6 +69,7 @@ struct raw1394_khost_list {
struct iso_block_store {
atomic_t refcount;
+ size_t data_size;
quadlet_t data[0];
};
@@ -83,6 +86,8 @@ struct file_info {
spinlock_t reqlists_lock;
wait_queue_head_t poll_wait_complete;
+ u8 *fcp_buffer;
+
u64 listen_channels;
quadlet_t *iso_buffer;
size_t iso_buffer_length;
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index a73c26766..e4ba2cf1f 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -85,8 +85,14 @@ dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
-dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
-if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
+dep_tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ bool 'CAPI2.0 Middleware support' CONFIG_ISDN_CAPI_MIDDLEWARE
+ if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" != "n" ]; then
+ bool 'CAPI2.0 filesystem support' CONFIG_ISDN_CAPIFS
+ fi
+fi
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then
diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile
index c94551716..b1e43f487 100644
--- a/drivers/isdn/Makefile
+++ b/drivers/isdn/Makefile
@@ -97,12 +97,12 @@ else
endif
endif
-ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+ifeq ($(CONFIG_ISDN_CAPI),y)
L_OBJS += avmb1/avmb1.o
SUB_DIRS += avmb1
MOD_SUB_DIRS += avmb1
else
- ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
+ ifeq ($(CONFIG_ISDN_CAPI),m)
MOD_SUB_DIRS += avmb1
endif
endif
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index bfeb81939..77a701611 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $
+# $Id: Makefile,v 1.16 2000/03/17 12:15:44 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -11,6 +11,49 @@
# parent makes..
#
# $Log: Makefile,v $
+# Revision 1.16 2000/03/17 12:15:44 calle
+# ALL_SUB_DIRS were wrong.
+#
+# Revision 1.15 2000/03/16 15:21:03 calle
+# Bugfix in c4_remove: loop 5 times instead of 4 :-(
+#
+# Revision 1.14 2000/03/13 17:50:55 calle
+# Added avm_cs.c for 2.3.x PCMCIA support.
+#
+# Revision 1.13 2000/03/08 17:06:33 calle
+# - changes for devfs and 2.3.49
+# - capifs now configurable (no need with devfs)
+# - New Middleware ioctl CAPI_NCCI_GETUNIT
+# - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+#
+# Revision 1.12 2000/03/06 18:00:23 calle
+# - Middleware extention now working with 2.3.49 (capifs).
+# - Fixed typos in debug section of capi.c
+# - Bugfix: Makefile corrected for b1pcmcia.c
+#
+# Revision 1.11 2000/03/06 09:17:07 calle
+# - capifs: fileoperations now in inode (change for 2.3.49)
+# - Config.in: Middleware extention not a tristate, uups.
+#
+# Revision 1.10 2000/03/03 16:48:38 calle
+# - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+# It is now possible to create a connection with a CAPI2.0 applikation
+# and than to handle the data connection from /dev/capi/ (capifs) and also
+# using async or sync PPP on this connection.
+# The two major device number 190 and 191 are not confirmed yet,
+# but I want to save the code in cvs, before I go on.
+#
+# Revision 1.9 2000/03/03 15:50:42 calle
+# - kernel CAPI:
+# - Changed parameter "param" in capi_signal from __u32 to void *.
+# - rewrote notifier handling in kcapi.c
+# - new notifier NCCI_UP and NCCI_DOWN
+# - User CAPI:
+# - /dev/capi20 is now a cloning device.
+# - middleware extentions prepared.
+# - capidrv.c
+# - locking of list operations and module count updates.
+#
# Revision 1.8 2000/01/25 14:33:38 calle
# - Added Support AVM B1 PCI V4.0 (tested with prototype)
# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
@@ -64,6 +107,9 @@
#
#
+SUB_DIRS :=
+MOD_SUB_DIRS :=
+ALL_SUB_DIRS := # fcpci fcclassic
#
# Objects that don't export a symtab
#
@@ -82,53 +128,78 @@ MX_OBJS := # used as module
O_TARGET := # used for .o targets (from O and OX objects)
L_TARGET := # used for .a targets (from L and LX objects)
-ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+ifeq ($(CONFIG_ISDN_CAPI),y)
O_TARGET += avmb1.o
OX_OBJS += kcapi.o
O_OBJS += capi.o
+ ifdef CONFIG_ISDN_CAPIFS
+ OX_OBJS += capifs.o
+ endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
- O_OBJS += b1isa.o
+ O_OBJS += b1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
- O_OBJS += b1pci.o
+ O_OBJS += b1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
- O_OBJS += t1isa.o
+ O_OBJS += t1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- OX_OBJS += b1pcmcia.o
+ OX_OBJS += b1pcmcia.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
- O_OBJS += t1pci.o
+ O_OBJS += t1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_C4
- O_OBJS += c4.o
+ O_OBJS += c4.o
endif
- OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
-else
- ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
- O_TARGET += kernelcapi.o
- OX_OBJS += kcapi.o
- M_OBJS += capi.o kernelcapi.o
- ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
- M_OBJS += b1isa.o
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
- M_OBJS += b1pci.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI
+ SUB_DIRS += fcpci
+ MOD_SUB_DIRS += fcpci
endif
- ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
- M_OBJS += t1isa.o
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC
+ SUB_DIRS += fcclassic
+ MOD_SUB_DIRS += fcclassic
endif
- ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- MX_OBJS += b1pcmcia.o
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
- M_OBJS += t1pci.o
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_C4
- M_OBJS += c4.o
- endif
- MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
+ OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
+else
+ ifeq ($(CONFIG_ISDN_CAPI),m)
+ O_TARGET += kernelcapi.o
+ OX_OBJS += kcapi.o
+ M_OBJS += capi.o kernelcapi.o
+ ifdef CONFIG_ISDN_CAPIFS
+ MX_OBJS += capifs.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
+ M_OBJS += b1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
+ M_OBJS += b1pci.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
+ M_OBJS += t1isa.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
+ MX_OBJS += b1pcmcia.o
+ ifeq ($(CONFIG_HOTPLUG),y)
+ ifneq ($(CONFIG_PCMCIA),n)
+ M_OBJS += avm_cs.o
+ endif
+ endif
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
+ M_OBJS += t1pci.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_C4
+ M_OBJS += c4.o
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI
+ MOD_SUB_DIRS += fcpci
+ endif
+ ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC
+ MOD_SUB_DIRS += fcclassic
+ endif
+ MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
endif
endif
diff --git a/drivers/isdn/avmb1/avm_cs.c b/drivers/isdn/avmb1/avm_cs.c
new file mode 100644
index 000000000..4b8c9a1b4
--- /dev/null
+++ b/drivers/isdn/avmb1/avm_cs.c
@@ -0,0 +1,528 @@
+/*======================================================================
+
+ A PCMCIA client driver for AVM B1/M1/M2
+
+ Written by Carsten Paeth, calle@calle.in-berlin.de
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <linux/skbuff.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+#include <linux/b1pcmcia.h>
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* This means pick from 15, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static int default_irq_list[10] = { 15, 12, 11, 10, 9, 7, 5, 4, 3, -1 };
+static int irq_list[10] = { -1 };
+
+MODULE_PARM(irq_list, "1-10i");
+
+/*====================================================================*/
+
+/*
+ The event() function is this driver's Card Services event handler.
+ It will be called by Card Services when an appropriate card status
+ event is received. The config() and release() entry points are
+ used to configure or release a socket, in response to card insertion
+ and ejection events. They are invoked from the skeleton event
+ handler.
+*/
+
+static void avmcs_config(dev_link_t *link);
+static void avmcs_release(u_long arg);
+static int avmcs_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+/*
+ The attach() and detach() entry points are used to create and destroy
+ "instances" of the driver, where each instance represents everything
+ needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *avmcs_attach(void);
+static void avmcs_detach(dev_link_t *);
+
+/*
+ The dev_info variable is the "key" that is used to match up this
+ device driver with appropriate cards, through the card configuration
+ database.
+*/
+
+static dev_info_t dev_info = "avm_cs";
+
+/*
+ A linked list of "instances" of the skeleton device. Each actual
+ PCMCIA card corresponds to one device instance, and is described
+ by one dev_link_t structure (defined in ds.h).
+
+ You may not want to use a linked list for this -- for example, the
+ memory card driver uses an array of dev_link_t pointers, where minor
+ device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+ A dev_link_t structure has fields for most things that are needed
+ to keep track of a socket, but there will usually be some device
+ specific information that also needs to be kept track of. The
+ 'priv' pointer in a dev_link_t structure can be used to point to
+ a device-specific private data structure, like this.
+
+ A driver needs to provide a dev_node_t structure for each device
+ on a card. In some cases, there is only one device per card (for
+ example, ethernet cards, modems). In other cases, there may be
+ many actual or logical devices (SCSI adapters, memory cards with
+ multiple partitions). The dev_node_t structures need to be kept
+ in a linked list starting at the 'dev' field of a dev_link_t
+ structure. We allocate them in the card's private data structure,
+ because they generally can't be allocated dynamically.
+*/
+
+typedef struct local_info_t {
+ dev_node_t node;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+ avmcs_attach() creates an "instance" of the driver, allocating
+ local data structures for one device. The device is registered
+ with Card Services.
+
+ The dev_link structure is initialized, but we don't actually
+ configure the card at this point -- we wait until we receive a
+ card insertion event.
+
+======================================================================*/
+
+static dev_link_t *avmcs_attach(void)
+{
+ client_reg_t client_reg;
+ dev_link_t *link;
+ local_info_t *local;
+ int ret, i;
+
+ /* Initialize the dev_link_t structure */
+ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ memset(link, 0, sizeof(struct dev_link_t));
+ link->release.function = &avmcs_release;
+ link->release.data = (u_long)link;
+
+ /* The io structure describes IO port mapping */
+ link->io.NumPorts1 = 16;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.NumPorts2 = 16;
+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+ link->io.IOAddrLines = 5;
+
+ /* Interrupt setup */
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] != -1) {
+ for (i = 0; i < 10 && irq_list[i] > 0; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ } else {
+ for (i = 0; i < 10 && default_irq_list[i] > 0; i++)
+ link->irq.IRQInfo2 |= 1 << default_irq_list[i];
+ }
+
+ /* General socket configuration */
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.ConfigIndex = 1;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Allocate space for private device-specific data */
+ local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ memset(local, 0, sizeof(local_info_t));
+ link->priv = local;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &avmcs_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ avmcs_detach(link);
+ return NULL;
+ }
+
+ return link;
+} /* avmcs_attach */
+
+/*======================================================================
+
+ This deletes a driver "instance". The device is de-registered
+ with Card Services. If it has been released, all local data
+ structures are freed. Otherwise, the structures will be freed
+ when the device is released.
+
+======================================================================*/
+
+static void avmcs_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ /*
+ If the device is currently configured and active, we won't
+ actually delete it yet. Instead, it is marked so that when
+ the release() function is called, that will trigger a proper
+ detach().
+ */
+ if (link->state & DEV_CONFIG) {
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+
+ /* Break the link with Card Services */
+ if (link->handle)
+ CardServices(DeregisterClient, link->handle);
+
+ /* Unlink device structure, free pieces */
+ *linkp = link->next;
+ if (link->priv) {
+ kfree_s(link->priv, sizeof(local_info_t));
+ }
+ kfree_s(link, sizeof(struct dev_link_t));
+
+} /* avmcs_detach */
+
+/*======================================================================
+
+ avmcs_config() is scheduled to run after a CARD_INSERTION event
+ is received, to configure the PCMCIA socket, and to make the
+ ethernet device available to the system.
+
+======================================================================*/
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+ cisparse_t *parse)
+{
+ int i;
+ i = CardServices(fn, handle, tuple);
+ if (i != CS_SUCCESS) return i;
+ i = CardServices(GetTupleData, handle, tuple);
+ if (i != CS_SUCCESS) return i;
+ return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+static void avmcs_config(dev_link_t *link)
+{
+ client_handle_t handle;
+ tuple_t tuple;
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ local_info_t *dev;
+ int i;
+ u_char buf[64];
+ char devname[128];
+ int cardtype;
+ int (*addcard)(unsigned int port, unsigned irq);
+
+ handle = link->handle;
+ dev = link->priv;
+
+ /*
+ This reads the card's CONFIG tuple to find its configuration
+ registers.
+ */
+ do {
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ i = CardServices(GetFirstTuple, handle, &tuple);
+ if (i != CS_SUCCESS) break;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 64;
+ tuple.TupleOffset = 0;
+ i = CardServices(GetTupleData, handle, &tuple);
+ if (i != CS_SUCCESS) break;
+ i = CardServices(ParseTuple, handle, &tuple, &parse);
+ if (i != CS_SUCCESS) break;
+ link->conf.ConfigBase = parse.config.base;
+ } while (0);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, ParseTuple, i);
+ link->state &= ~DEV_CONFIG_PENDING;
+ return;
+ }
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ do {
+
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = 254;
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_VERS_1;
+
+ devname[0] = 0;
+ if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
+ strncpy(devname,parse.version_1.str + parse.version_1.ofs[1],
+ sizeof(devname));
+ }
+ /*
+ * find IO port
+ */
+ tuple.TupleData = (cisdata_t *)buf;
+ tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ i = first_tuple(handle, &tuple, &parse);
+ while (i == CS_SUCCESS) {
+ if (cf->io.nwin > 0) {
+ link->conf.ConfigIndex = cf->index;
+ link->io.BasePort1 = cf->io.win[0].base;
+ link->io.NumPorts1 = cf->io.win[0].len;
+ printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
+ link->io.BasePort1,
+ link->io.BasePort1+link->io.NumPorts1);
+ i = CardServices(RequestIO, link->handle, &link->io);
+ if (i == CS_SUCCESS) goto found_port;
+ }
+ i = next_tuple(handle, &tuple, &parse);
+ }
+
+found_port:
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestIO, i);
+ break;
+ }
+
+ /*
+ * allocate an interrupt line
+ */
+ i = CardServices(RequestIRQ, link->handle, &link->irq);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestIRQ, i);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ break;
+ }
+
+ /*
+ * configure the PCMCIA socket
+ */
+ i = CardServices(RequestConfiguration, link->handle, &link->conf);
+ if (i != CS_SUCCESS) {
+ cs_error(link->handle, RequestConfiguration, i);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+ break;
+ }
+
+ } while (0);
+
+ /* At this point, the dev_node_t structure(s) should be
+ initialized and arranged in a linked list at link->dev. */
+
+ if (devname[0]) {
+ char *s = strrchr(devname, ' ');
+ if (!s)
+ s = devname;
+ else s++;
+ strcpy(dev->node.dev_name, s);
+ if (strcmp("M1", s) == 0) {
+ cardtype = AVM_CARDTYPE_M1;
+ } else if (strcmp("M2", s) == 0) {
+ cardtype = AVM_CARDTYPE_M2;
+ } else {
+ cardtype = AVM_CARDTYPE_B1;
+ }
+ } else {
+ strcpy(dev->node.dev_name, "b1");
+ cardtype = AVM_CARDTYPE_B1;
+ }
+
+ dev->node.major = 64;
+ dev->node.minor = 0;
+ link->dev = &dev->node;
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ /* If any step failed, release any partially configured state */
+ if (i != 0) {
+ avmcs_release((u_long)link);
+ return;
+ }
+
+
+ switch (cardtype) {
+ case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
+ case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
+ default:
+ case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
+ }
+ if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
+ printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
+ dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
+ avmcs_release((u_long)link);
+ return;
+ }
+ dev->node.minor = i;
+
+} /* avmcs_config */
+
+/*======================================================================
+
+ After a card is removed, avmcs_release() will unregister the net
+ device, and release the PCMCIA configuration. If the device is
+ still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void avmcs_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+
+ /*
+ If the device is currently in use, we won't release until it
+ is actually closed.
+ */
+ if (link->open) {
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
+
+ /* Unlink the device chain */
+ link->dev = NULL;
+
+ /* Don't bother checking to see if these succeed or not */
+ CardServices(ReleaseConfiguration, link->handle);
+ CardServices(ReleaseIO, link->handle, &link->io);
+ CardServices(ReleaseIRQ, link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+
+ if (link->state & DEV_STALE_LINK)
+ avmcs_detach(link);
+
+} /* avmcs_release */
+
+/*======================================================================
+
+ The card status event handler. Mostly, this schedules other
+ stuff to run after an event is received. A CARD_REMOVAL event
+ also sets some flags to discourage the net drivers from trying
+ to talk to the card any more.
+
+ When a CARD_REMOVAL event is received, we immediately set a flag
+ to block future accesses to this device. All the functions that
+ actually access the device should check this flag to make sure
+ the card is still present.
+
+======================================================================*/
+
+static int avmcs_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG) {
+ link->release.expires = jiffies + (HZ/20);
+ add_timer(&link->release);
+ }
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ avmcs_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ CardServices(ReleaseConfiguration, link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG)
+ CardServices(RequestConfiguration, link->handle, &link->conf);
+ break;
+ }
+ return 0;
+} /* avmcs_event */
+
+/*====================================================================*/
+
+int init_module(void)
+{
+ servinfo_t serv;
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ printk(KERN_NOTICE "avm_cs: Card Services release "
+ "does not match!\n");
+ return -1;
+ }
+ register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_pccard_driver(&dev_info);
+ while (dev_list != NULL) {
+ if (dev_list->state & DEV_CONFIG)
+ avmcs_release((u_long)dev_list);
+ avmcs_detach(dev_list);
+ }
+}
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
index 1785e1740..d61b88375 100644
--- a/drivers/isdn/avmb1/b1dma.c
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.3 $";
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-static int suppress_pollack = 0;
+int suppress_pollack = 0;
MODULE_PARM(suppress_pollack, "0-1i");
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c
index 6e39c43d2..ff90b42c8 100644
--- a/drivers/isdn/avmb1/b1pcmcia.c
+++ b/drivers/isdn/avmb1/b1pcmcia.c
@@ -1,11 +1,16 @@
/*
- * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1pcmcia.c,v 1.8 2000/03/06 18:00:23 calle Exp $
*
* Module for AVM B1/M1/M2 PCMCIA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pcmcia.c,v $
+ * Revision 1.8 2000/03/06 18:00:23 calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
* Revision 1.7 2000/02/02 18:36:03 calle
* - Modules are now locked while init_module is running
* - fixed problem with memory mapping if address is not aligned
@@ -70,7 +75,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
index 76f34569d..e016bfde2 100644
--- a/drivers/isdn/avmb1/c4.c
+++ b/drivers/isdn/avmb1/c4.c
@@ -1,11 +1,17 @@
/*
- * $Id: c4.c,v 1.4 2000/02/02 18:36:03 calle Exp $
+ * $Id: c4.c,v 1.6 2000/03/17 12:21:08 calle Exp $
*
* Module for AVM C4 card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: c4.c,v $
+ * Revision 1.6 2000/03/17 12:21:08 calle
+ * send patchvalues now working.
+ *
+ * Revision 1.5 2000/03/16 15:21:03 calle
+ * Bugfix in c4_remove: loop 5 times instead of 4 :-(
+ *
* Revision 1.4 2000/02/02 18:36:03 calle
* - Modules are now locked while init_module is running
* - fixed problem with memory mapping if address is not aligned
@@ -40,7 +46,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.6 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
@@ -65,7 +71,7 @@ static char *revision = "$Revision: 1.4 $";
/* ------------------------------------------------------------- */
-static int suppress_pollack = 0;
+int suppress_pollack = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -770,45 +776,78 @@ static void c4_send_init(avmcard *card)
c4_dispatch_tx(card);
}
-static int c4_send_config(avmcard *card, capiloaddatapart * config)
+static int queue_sendconfigword(avmcard *card, __u32 val)
{
struct sk_buff *skb;
- __u8 val[sizeof(__u32)];
void *p;
- unsigned char *dp;
- int left, retval;
-
- skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC);
+
+ skb = alloc_skb(3+4, GFP_ATOMIC);
if (!skb) {
- printk(KERN_CRIT "%s: no memory, can't send config.\n",
+ printk(KERN_CRIT "%s: no memory, send config\n",
card->name);
- return -ENOMEM;
+ return -ENOMEM;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_CONFIG);
- _put_word(&p, 1);
+ _put_word(&p, val);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ return 0;
+}
+
+static int queue_sendconfig(avmcard *card, char cval[4])
+{
+ struct sk_buff *skb;
+ void *p;
+
+ skb = alloc_skb(3+4, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_CRIT "%s: no memory, send config\n",
+ card->name);
+ return -ENOMEM;
+ }
+ p = skb->data;
+ _put_byte(&p, 0);
+ _put_byte(&p, 0);
_put_byte(&p, SEND_CONFIG);
- _put_word(&p, config->len); /* 12 */
+ _put_byte(&p, cval[0]);
+ _put_byte(&p, cval[1]);
+ _put_byte(&p, cval[2]);
+ _put_byte(&p, cval[3]);
+ skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+ skb_queue_tail(&card->dma->send_queue, skb);
+ c4_dispatch_tx(card);
+ return 0;
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+ __u8 val[4];
+ unsigned char *dp;
+ int left, retval;
+
+ if ((retval = queue_sendconfigword(card, 1)) != 0)
+ return retval;
+ if ((retval = queue_sendconfigword(card, config->len)) != 0)
+ return retval;
dp = config->data;
left = config->len;
while (left >= sizeof(__u32)) {
if (config->user) {
retval = copy_from_user(val, dp, sizeof(val));
- if (retval) {
- dev_kfree_skb(skb);
+ if (retval)
return -EFAULT;
- }
} else {
memcpy(val, dp, sizeof(val));
}
- _put_byte(&p, SEND_CONFIG);
- _put_byte(&p, val[0]);
- _put_byte(&p, val[1]);
- _put_byte(&p, val[2]);
- _put_byte(&p, val[3]);
+ if ((retval = queue_sendconfig(card, val)) != 0)
+ return retval;
left -= sizeof(val);
dp += sizeof(val);
}
@@ -816,25 +855,15 @@ static int c4_send_config(avmcard *card, capiloaddatapart * config)
memset(val, 0, sizeof(val));
if (config->user) {
retval = copy_from_user(&val, dp, left);
- if (retval) {
- dev_kfree_skb(skb);
+ if (retval)
return -EFAULT;
- }
} else {
memcpy(&val, dp, left);
}
- _put_byte(&p, SEND_CONFIG);
- _put_byte(&p, val[0]);
- _put_byte(&p, val[1]);
- _put_byte(&p, val[2]);
- _put_byte(&p, val[3]);
+ if ((retval = queue_sendconfig(card, val)) != 0)
+ return retval;
}
- skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
- skb_queue_tail(&card->dma->send_queue, skb);
- c4_dispatch_tx(card);
-
return 0;
}
@@ -871,8 +900,15 @@ static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
restore_flags(flags);
- if (data->configuration.len > 0 && data->configuration.data)
- c4_send_config(card, &data->configuration);
+ if (data->configuration.len > 0 && data->configuration.data) {
+ retval = c4_send_config(card, &data->configuration);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to set config!!\n",
+ card->name);
+ c4_reset(card);
+ return retval;
+ }
+ }
c4_send_init(card);
@@ -904,7 +940,7 @@ static void c4_remove_ctr(struct capi_ctr *ctrl)
c4_reset(card);
- for (i=0; i <= 4; i++) {
+ for (i=0; i < 4; i++) {
cinfo = &card->ctrlinfo[i];
if (cinfo->capi_ctrl)
di->detach_ctr(cinfo->capi_ctrl);
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 6cd9cf3e4..3bbc329e1 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,51 @@
/*
- * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $
+ * $Id: capi.c,v 1.30 2000/03/19 12:31:36 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.30 2000/03/19 12:31:36 calle
+ * PPP over CAPI raw driver disabled for now, ppp_generic has been changed.
+ *
+ * Revision 1.29 2000/03/13 17:48:13 calle
+ * removed unused variable.
+ *
+ * Revision 1.28 2000/03/08 17:06:33 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.27 2000/03/06 18:00:23 calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
+ * Revision 1.26 2000/03/03 16:48:38 calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ * It is now possible to create a connection with a CAPI2.0 applikation
+ * and than to handle the data connection from /dev/capi/ (capifs) and also
+ * using async or sync PPP on this connection.
+ * The two major device number 190 and 191 are not confirmed yet,
+ * but I want to save the code in cvs, before I go on.
+ *
+ * Revision 1.25 2000/03/03 16:37:11 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.24 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.23 2000/02/26 01:00:53 keil
* changes from 2.3.47
*
@@ -114,6 +154,7 @@
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -126,52 +167,686 @@
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#include <linux/tty.h>
+#ifdef CONFIG_PPP
+#include <linux/netdevice.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#undef CAPI_PPP_ON_RAW_DEVICE
+#endif /* CONFIG_PPP */
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/devfs_fs_kernel.h>
-
#include "capiutil.h"
#include "capicmd.h"
-#include "capidev.h"
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#include "capifs.h"
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+#include <linux/slab.h>
+
+static char *revision = "$Revision: 1.30 $";
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
+#undef _DEBUG_REFCOUNT /* alloc/free and open/close debug */
+#undef _DEBUG_TTYFUNCS /* call to tty_driver */
+#undef _DEBUG_DATAFLOW /* data flow */
+
/* -------- driver information -------------------------------------- */
int capi_major = 68; /* allocated */
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+int capi_rawmajor = 190;
+int capi_ttymajor = 191;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
MODULE_PARM(capi_major, "i");
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+MODULE_PARM(capi_rawmajor, "i");
+MODULE_PARM(capi_ttymajor, "i");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- defines ------------------------------------------------- */
+
+#define CAPINC_MAX_RECVQUEUE 10
+#define CAPINC_MAX_SENDQUEUE 10
+#define CAPI_MAX_BLKSIZE 2048
+
+/* -------- data structures ----------------------------------------- */
+
+struct capidev;
+struct capincci;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+struct capiminor;
+
+struct capiminor {
+ struct capiminor *next;
+ struct capincci *nccip;
+ unsigned int minor;
+
+ __u16 applid;
+ __u32 ncci;
+ __u16 datahandle;
+ __u16 msgid;
+
+ struct file *file;
+ struct tty_struct *tty;
+ int ttyinstop;
+ int ttyoutstop;
+ struct sk_buff *ttyskb;
+ atomic_t ttyopencount;
+
+ struct sk_buff_head inqueue;
+ int inbytes;
+ struct sk_buff_head outqueue;
+ int outbytes;
+
+ /* for raw device */
+ struct sk_buff_head recvqueue;
+ wait_queue_head_t recvwait;
+ wait_queue_head_t sendwait;
+
+ /* transmit path */
+ struct datahandle_queue {
+ struct datahandle_queue *next;
+ __u16 datahandle;
+ } *ackqueue;
+ int nack;
+
+};
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+struct capincci {
+ struct capincci *next;
+ __u32 ncci;
+ struct capidev *cdev;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *minorp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+};
+
+struct capidev {
+ struct capidev *next;
+ struct file *file;
+ __u16 applid;
+ __u16 errcode;
+ unsigned int minor;
+ unsigned userflags;
+
+ struct sk_buff_head recvqueue;
+ wait_queue_head_t recvwait;
+
+ /* Statistic */
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
+
+ struct capincci *nccis;
+};
/* -------- global variables ---------------------------------------- */
-static struct capidev capidevs[CAPI_MAXMINOR + 1];
-struct capi_interface *capifuncs;
+static struct capi_interface *capifuncs = 0;
+static struct capidev *capidev_openlist = 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+static struct capiminor *minors = 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-/* -------- function called by lower level -------------------------- */
+static kmem_cache_t *capidev_cachep = 0;
+static kmem_cache_t *capincci_cachep = 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+static kmem_cache_t *capiminor_cachep = 0;
+static kmem_cache_t *capidh_cachep = 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- datahandles --------------------------------------------- */
+
+int capincci_add_ack(struct capiminor *mp, __u16 datahandle)
+{
+ struct datahandle_queue *n, **pp;
+
+ n = (struct datahandle_queue *)
+ kmem_cache_alloc(capidh_cachep, GFP_ATOMIC);
+ if (!n) {
+ printk(KERN_ERR "capi: alloc datahandle failed\n");
+ return -1;
+ }
+ n->next = 0;
+ n->datahandle = datahandle;
+ for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
+ *pp = n;
+ mp->nack++;
+ return 0;
+}
+
+int capiminor_del_ack(struct capiminor *mp, __u16 datahandle)
+{
+ struct datahandle_queue **pp, *p;
+
+ for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->datahandle == datahandle) {
+ p = *pp;
+ *pp = (*pp)->next;
+ kmem_cache_free(capidh_cachep, p);
+ mp->nack--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void capiminor_del_all_ack(struct capiminor *mp)
+{
+ struct datahandle_queue **pp, *p;
+
+ for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
+ p = *pp;
+ *pp = (*pp)->next;
+ kmem_cache_free(capidh_cachep, p);
+ mp->nack--;
+ }
+}
+
+
+/* -------- struct capiminor ---------------------------------------- */
+
+struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci)
+{
+ struct capiminor *mp, **pp;
+ unsigned int minor = 0;
+
+ mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC);
+ if (!mp) {
+ printk(KERN_ERR "capi: can't alloc capiminor\n");
+ return 0;
+ }
+ MOD_INC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ memset(mp, 0, sizeof(struct capiminor));
+ mp->applid = applid;
+ mp->ncci = ncci;
+ mp->msgid = 0;
+ atomic_set(&mp->ttyopencount,0);
+
+ skb_queue_head_init(&mp->inqueue);
+ skb_queue_head_init(&mp->outqueue);
+
+ skb_queue_head_init(&mp->recvqueue);
+ init_waitqueue_head(&mp->recvwait);
+ init_waitqueue_head(&mp->sendwait);
+
+ for (pp = &minors; *pp; pp = &(*pp)->next) {
+ if ((*pp)->minor < minor)
+ continue;
+ if ((*pp)->minor > minor)
+ break;
+ minor++;
+ }
+ mp->minor = minor;
+ mp->next = *pp;
+ *pp = mp;
+ return mp;
+}
+
+void capiminor_free(struct capiminor *mp)
+{
+ struct capiminor **pp;
+ struct sk_buff *skb;
+
+ pp = &minors;
+ while (*pp) {
+ if (*pp == mp) {
+ *pp = (*pp)->next;
+ if (mp->ttyskb) kfree_skb(mp->ttyskb);
+ mp->ttyskb = 0;
+ while ((skb = skb_dequeue(&mp->recvqueue)) != 0)
+ kfree_skb(skb);
+ while ((skb = skb_dequeue(&mp->inqueue)) != 0)
+ kfree_skb(skb);
+ while ((skb = skb_dequeue(&mp->outqueue)) != 0)
+ kfree_skb(skb);
+ capiminor_del_all_ack(mp);
+ kmem_cache_free(capiminor_cachep, mp);
+ MOD_DEC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ return;
+ } else {
+ pp = &(*pp)->next;
+ }
+ }
+}
+
+struct capiminor *capiminor_find(unsigned int minor)
+{
+ struct capiminor *p;
+ for (p = minors; p && p->minor != minor; p = p->next)
+ ;
+ return p;
+}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- struct capincci ----------------------------------------- */
+
+static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci)
+{
+ struct capincci *np, **pp;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp = 0;
+ kdev_t kdev;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+ np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC);
+ if (!np)
+ return 0;
+ memset(np, 0, sizeof(struct capincci));
+ np->ncci = ncci;
+ np->cdev = cdev;
+ for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
+ ;
+ *pp = np;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ mp = 0;
+ if (cdev->userflags & CAPIFLAG_HIGHJACKING)
+ mp = np->minorp = capiminor_alloc(cdev->applid, ncci);
+ if (mp) {
+ mp->nccip = np;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "set mp->nccip\n");
+#endif
+#ifdef CONFIG_ISDN_CAPIFS
+ kdev = MKDEV(capi_rawmajor, mp->minor);
+ capifs_new_ncci('r', mp->minor, kdev);
+ kdev = MKDEV(capi_ttymajor, mp->minor);
+ capifs_new_ncci(0, mp->minor, kdev);
+#endif
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return np;
+}
+
+static void capincci_free(struct capidev *cdev, __u32 ncci)
+{
+ struct capincci *np, **pp;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+ pp=&cdev->nccis;
+ while (*pp) {
+ np = *pp;
+ if (ncci == 0xffffffff || np->ncci == ncci) {
+ *pp = (*pp)->next;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if ((mp = np->minorp) != 0) {
+#ifdef CONFIG_ISDN_CAPIFS
+ capifs_free_ncci('r', mp->minor);
+ capifs_free_ncci(0, mp->minor);
+#endif
+ if (mp->tty) {
+ mp->nccip = 0;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "reset mp->nccip\n");
+#endif
+ tty_hangup(mp->tty);
+ } else if (mp->file) {
+ mp->nccip = 0;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "reset mp->nccip\n");
+#endif
+ wake_up_interruptible(&mp->recvwait);
+ wake_up_interruptible(&mp->sendwait);
+ } else {
+ capiminor_free(mp);
+ }
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ kmem_cache_free(capincci_cachep, np);
+ if (*pp == 0) return;
+ } else {
+ pp = &(*pp)->next;
+ }
+ }
+}
+
+struct capincci *capincci_find(struct capidev *cdev, __u32 ncci)
+{
+ struct capincci *p;
+
+ for (p=cdev->nccis; p ; p = p->next) {
+ if (p->ncci == ncci)
+ break;
+ }
+ return p;
+}
+
+/* -------- struct capidev ------------------------------------------ */
-static void capi_signal(__u16 applid, __u32 minor)
+static struct capidev *capidev_alloc(struct file *file)
{
struct capidev *cdev;
+ struct capidev **pp;
+
+ cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
+ if (!cdev)
+ return 0;
+ memset(cdev, 0, sizeof(struct capidev));
+ cdev->file = file;
+ cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ skb_queue_head_init(&cdev->recvqueue);
+ init_waitqueue_head(&cdev->recvwait);
+ pp=&capidev_openlist;
+ while (*pp) pp = &(*pp)->next;
+ *pp = cdev;
+ return cdev;
+}
+
+static void capidev_free(struct capidev *cdev)
+{
+ struct capidev **pp;
+ struct sk_buff *skb;
+
+ if (cdev->applid)
+ (*capifuncs->capi_release) (cdev->applid);
+ cdev->applid = 0;
+
+ while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
+ kfree_skb(skb);
+ }
+
+ pp=&capidev_openlist;
+ while (*pp && *pp != cdev) pp = &(*pp)->next;
+ if (*pp)
+ *pp = cdev->next;
+
+ kmem_cache_free(capidev_cachep, cdev);
+}
+
+static struct capidev *capidev_find(__u16 applid)
+{
+ struct capidev *p;
+ for (p=capidev_openlist; p; p = p->next) {
+ if (p->applid == applid)
+ break;
+ }
+ return p;
+}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- handle data queue --------------------------------------- */
+
+struct sk_buff *
+gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+ nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
+ if (nskb) {
+ __u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
+ unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
+ capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
+ capimsg_setu16(s, 2, mp->applid);
+ capimsg_setu8 (s, 4, CAPI_DATA_B3);
+ capimsg_setu8 (s, 5, CAPI_RESP);
+ capimsg_setu16(s, 6, mp->msgid++);
+ capimsg_setu32(s, 8, mp->ncci);
+ capimsg_setu16(s, 12, datahandle);
+ }
+ return nskb;
+}
+
+int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+ unsigned int datalen;
+ __u16 errcode, datahandle;
+
+ datalen = skb->len - CAPIMSG_LEN(skb->data);
+ if (mp->tty) {
+ if (mp->tty->ldisc.receive_buf == 0) {
+ printk(KERN_ERR "capi: ldisc has no receive_buf function\n");
+ return -1;
+ }
+ if (mp->ttyinstop) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: recv tty throttled\n");
+#endif
+ return -1;
+ }
+ if (mp->tty->ldisc.receive_room &&
+ mp->tty->ldisc.receive_room(mp->tty) < datalen) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: no room in tty\n");
+#endif
+ return -1;
+ }
+ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+ printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+ return -1;
+ }
+ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+ errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+ errcode);
+ kfree_skb(nskb);
+ return -1;
+ }
+ (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
+ datahandle, skb->len);
+#endif
+ mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len);
+ return 0;
+
+ } else if (mp->file) {
+ if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: no room in raw queue\n");
+#endif
+ return -1;
+ }
+ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+ printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+ return -1;
+ }
+ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+ errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
+ if (errcode != CAPI_NOERROR) {
+ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+ errcode);
+ kfree_skb(nskb);
+ return -1;
+ }
+ (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n",
+ datahandle, skb->len);
+#endif
+ skb_queue_tail(&mp->recvqueue, skb);
+ wake_up_interruptible(&mp->recvwait);
+ return 0;
+ }
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: currently no receiver\n");
+#endif
+ return -1;
+}
+
+void handle_minor_recv(struct capiminor *mp)
+{
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
+ unsigned int len = skb->len;
+ mp->inbytes -= len;
+ if (handle_recv_skb(mp, skb) < 0) {
+ skb_queue_head(&mp->inqueue, skb);
+ mp->inbytes += len;
+ return;
+ }
+ }
+}
+
+int handle_minor_send(struct capiminor *mp)
+{
+ struct sk_buff *skb;
+ __u16 len;
+ int count = 0;
+ __u16 errcode;
+ __u16 datahandle;
+
+ if (mp->tty && mp->ttyoutstop) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+ printk(KERN_DEBUG "capi: send: tty stopped\n");
+#endif
+ return 0;
+ }
+
+ while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
+ datahandle = mp->datahandle;
+ len = (__u16)skb->len;
+ skb_push(skb, CAPI_DATA_B3_REQ_LEN);
+ memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+ capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+ capimsg_setu16(skb->data, 2, mp->applid);
+ capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
+ capimsg_setu8 (skb->data, 5, CAPI_REQ);
+ capimsg_setu16(skb->data, 6, mp->msgid++);
+ capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
+ capimsg_setu32(skb->data, 12, (__u32) skb->data); /* Data32 */
+ capimsg_setu16(skb->data, 16, len); /* Data length */
+ capimsg_setu16(skb->data, 18, datahandle);
+ capimsg_setu16(skb->data, 20, 0); /* Flags */
+
+ if (capincci_add_ack(mp, datahandle) < 0) {
+ skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
+ skb_queue_head(&mp->outqueue, skb);
+ return count;
+ }
+ errcode = (*capifuncs->capi_put_message) (mp->applid, skb);
+ if (errcode == CAPI_NOERROR) {
+ mp->datahandle++;
+ count++;
+ mp->outbytes -= len;
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
+ datahandle, len);
+#endif
+ continue;
+ }
+ capiminor_del_ack(mp, datahandle);
+
+ if (errcode == CAPI_SENDQUEUEFULL) {
+ skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
+ skb_queue_head(&mp->outqueue, skb);
+ break;
+ }
+
+ /* ups, drop packet */
+ printk(KERN_ERR "capi: put_message = %x\n", errcode);
+ mp->outbytes -= len;
+ kfree_skb(skb);
+ }
+ if (count)
+ wake_up_interruptible(&mp->sendwait);
+ return count;
+}
+
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+/* -------- function called by lower level -------------------------- */
+
+static void capi_signal(__u16 applid, void *param)
+{
+ struct capidev *cdev = (struct capidev *)param;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+ __u16 datahandle;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ struct capincci *np;
struct sk_buff *skb = 0;
+ __u32 ncci;
- if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
- printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
+ (void) (*capifuncs->capi_get_message) (applid, &skb);
+ if (!skb) {
+ printk(KERN_ERR "BUG: capi_signal: no skb\n");
return;
}
- cdev = &capidevs[minor];
- (void) (*capifuncs->capi_get_message) (applid, &skb);
- if (skb) {
- skb_queue_tail(&cdev->recv_queue, skb);
- wake_up_interruptible(&cdev->recv_wait);
+
+ if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+ return;
+ }
+ ncci = CAPIMSG_CONTROL(skb->data);
+ for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
+ ;
+ if (!np) {
+ printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+ return;
+ }
+#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ mp = np->minorp;
+ if (!mp) {
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
+ return;
+ }
+
+
+ if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+
+ datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
+ datahandle, skb->len-CAPIMSG_LEN(skb->data));
+#endif
+ skb_queue_tail(&mp->inqueue, skb);
+ mp->inbytes += skb->len;
+ handle_minor_recv(mp);
+
+ } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
+
+ datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n",
+ datahandle,
+ CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
+#endif
+ kfree_skb(skb);
+ (void)capiminor_del_ack(mp, datahandle);
+ if (mp->tty) {
+ if (mp->tty->ldisc.write_wakeup)
+ mp->tty->ldisc.write_wakeup(mp->tty);
+ } else {
+ wake_up_interruptible(&mp->sendwait);
+ }
+ (void)handle_minor_send(mp);
+
} else {
- printk(KERN_ERR "BUG: capi_signal: no skb\n");
+ /* ups, let capi application handle it :-) */
+ skb_queue_tail(&cdev->recvqueue, skb);
+ wake_up_interruptible(&cdev->recvwait);
}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
}
-/* -------- file_operations ----------------------------------------- */
+/* -------- file_operations for capidev ----------------------------- */
static long long capi_llseek(struct file *file,
long long offset, int origin)
@@ -182,29 +857,25 @@ static long long capi_llseek(struct file *file,
static ssize_t capi_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
int retval;
size_t copied;
- if (ppos != &file->f_pos)
+ if (ppos != &file->f_pos)
return -ESPIPE;
- if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ if (!cdev->applid)
return -ENODEV;
- cdev = &capidevs[minor];
-
- if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
+ if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
for (;;) {
- interruptible_sleep_on(&cdev->recv_wait);
- if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+ interruptible_sleep_on(&cdev->recvwait);
+ if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
break;
if (signal_pending(current))
break;
@@ -213,20 +884,22 @@ static ssize_t capi_read(struct file *file, char *buf,
return -ERESTARTNOHAND;
}
if (skb->len > count) {
- skb_queue_head(&cdev->recv_queue, skb);
+ skb_queue_head(&cdev->recvqueue, skb);
return -EMSGSIZE;
}
retval = copy_to_user(buf, skb->data, skb->len);
if (retval) {
- skb_queue_head(&cdev->recv_queue, skb);
+ skb_queue_head(&cdev->recvqueue, skb);
return retval;
}
copied = skb->len;
- if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
- && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) {
cdev->nrecvdatapkt++;
- else cdev->nrecvctlpkt++;
+ } else {
+ cdev->nrecvctlpkt++;
+ }
+
kfree_skb(skb);
return copied;
@@ -235,41 +908,34 @@ static ssize_t capi_read(struct file *file, char *buf,
static ssize_t capi_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
- struct inode *inode = file->f_dentry->d_inode;
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
int retval;
- __u8 cmd;
- __u8 subcmd;
__u16 mlen;
- if (ppos != &file->f_pos)
+ if (ppos != &file->f_pos)
return -ESPIPE;
- if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ if (!cdev->applid)
return -ENODEV;
- cdev = &capidevs[minor];
-
skb = alloc_skb(count, GFP_USER);
if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
kfree_skb(skb);
return retval;
}
- cmd = CAPIMSG_COMMAND(skb->data);
- subcmd = CAPIMSG_SUBCOMMAND(skb->data);
mlen = CAPIMSG_LEN(skb->data);
- if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
- __u16 dlen = CAPIMSG_DATALEN(skb->data);
- if (mlen + dlen != count) {
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
+ if (mlen + CAPIMSG_DATALEN(skb->data) != count) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ } else {
+ if (mlen != count) {
kfree_skb(skb);
return -EINVAL;
}
- } else if (mlen != count) {
- kfree_skb(skb);
- return -EINVAL;
}
CAPIMSG_SETAPPID(skb->data, cdev->applid);
@@ -279,26 +945,26 @@ static ssize_t capi_write(struct file *file, const char *buf,
kfree_skb(skb);
return -EIO;
}
- if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ)
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
cdev->nsentdatapkt++;
- else cdev->nsentctlpkt++;
+ } else {
+ cdev->nsentctlpkt++;
+ }
return count;
}
static unsigned int
capi_poll(struct file *file, poll_table * wait)
{
+ struct capidev *cdev = (struct capidev *)file->private_data;
unsigned int mask = 0;
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct capidev *cdev;
- if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ if (!cdev->applid)
return POLLERR;
- cdev = &capidevs[minor];
- poll_wait(file, &(cdev->recv_wait), wait);
+ poll_wait(file, &(cdev->recvwait), wait);
mask = POLLOUT | POLLWRNORM;
- if (!skb_queue_empty(&cdev->recv_queue))
+ if (!skb_queue_empty(&cdev->recvqueue))
mask |= POLLIN | POLLRDNORM;
return mask;
}
@@ -306,36 +972,28 @@ capi_poll(struct file *file, poll_table * wait)
static int capi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ struct capidev *cdev = (struct capidev *)file->private_data;
capi_ioctl_struct data;
- int retval;
-
-
- if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
- return -ENODEV;
-
- cdev = &capidevs[minor];
+ int retval = -EINVAL;
switch (cmd) {
case CAPI_REGISTER:
{
- if (!minor)
- return -EINVAL;
retval = copy_from_user((void *) &data.rparams,
(void *) arg, sizeof(struct capi_register_params));
if (retval)
return -EFAULT;
- if (cdev->is_registered)
+ if (cdev->applid)
return -EEXIST;
cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
&cdev->applid);
- if (cdev->errcode)
+ if (cdev->errcode) {
+ cdev->applid = 0;
return -EIO;
- (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
- cdev->is_registered = 1;
+ }
+ (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev);
}
- return 0;
+ return (int)cdev->applid;
case CAPI_GET_VERSION:
{
@@ -441,8 +1099,6 @@ static int capi_ioctl(struct inode *inode, struct file *file,
case CAPI_MANUFACTURER_CMD:
{
struct capi_manufacturer_cmd mcmd;
- if (minor)
- return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
retval = copy_from_user((void *) &mcmd, (void *) arg,
@@ -452,102 +1108,721 @@ static int capi_ioctl(struct inode *inode, struct file *file,
return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
}
return 0;
+
+ case CAPI_SET_FLAGS:
+ case CAPI_CLR_FLAGS:
+ {
+ unsigned userflags;
+ retval = copy_from_user((void *) &userflags,
+ (void *) arg,
+ sizeof(userflags));
+ if (retval)
+ return -EFAULT;
+ if (cmd == CAPI_SET_FLAGS)
+ cdev->userflags |= userflags;
+ else
+ cdev->userflags &= ~userflags;
+ }
+ return 0;
+
+ case CAPI_GET_FLAGS:
+ {
+ retval = copy_to_user((void *) arg,
+ (void *) &cdev->userflags,
+ sizeof(cdev->userflags));
+ if (retval)
+ return -EFAULT;
+ }
+ return 0;
+
+ case CAPI_NCCI_OPENCOUNT:
+ {
+ struct capincci *nccip;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ unsigned ncci;
+ int count = 0;
+ retval = copy_from_user((void *) &ncci,
+ (void *) arg,
+ sizeof(ncci));
+ if (retval)
+ return -EFAULT;
+ nccip = capincci_find(cdev, (__u32) ncci);
+ if (!nccip)
+ return 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if ((mp = nccip->minorp) != 0) {
+ count += atomic_read(&mp->ttyopencount);
+ if (mp->file)
+ count++;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return count;
+ }
+ return 0;
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ case CAPI_NCCI_GETUNIT:
+ {
+ struct capincci *nccip;
+ struct capiminor *mp;
+ unsigned ncci;
+ retval = copy_from_user((void *) &ncci,
+ (void *) arg,
+ sizeof(ncci));
+ if (retval)
+ return -EFAULT;
+ nccip = capincci_find(cdev, (__u32) ncci);
+ if (!nccip || (mp = nccip->minorp) == 0)
+ return -ESRCH;
+ return mp->minor;
+ }
+ return 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
}
return -EINVAL;
}
static int capi_open(struct inode *inode, struct file *file)
{
- unsigned int minor = MINOR(inode->i_rdev);
+ if (file->private_data)
+ return -EEXIST;
+
+ if ((file->private_data = capidev_alloc(file)) == 0)
+ return -ENOMEM;
+
+ MOD_INC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ return 0;
+}
+
+static int capi_release(struct inode *inode, struct file *file)
+{
+ struct capidev *cdev = (struct capidev *)file->private_data;
+
+ capincci_free(cdev, 0xffffffff);
+ capidev_free(cdev);
+
+ MOD_DEC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ return 0;
+}
+
+static struct file_operations capi_fops =
+{
+ llseek: capi_llseek,
+ read: capi_read,
+ write: capi_write,
+ poll: capi_poll,
+ ioctl: capi_ioctl,
+ open: capi_open,
+ release: capi_release,
+};
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- file_operations for capincci ---------------------------- */
- if (minor >= CAPI_MAXMINOR)
+int capinc_raw_open(struct inode *inode, struct file *file)
+{
+ struct capiminor *mp;
+
+ if (file->private_data)
+ return -EEXIST;
+ if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+ return -ENXIO;
+ if (mp->nccip == 0)
return -ENXIO;
+ if (mp->file)
+ return -EBUSY;
- if (minor) {
- if (capidevs[minor].is_open)
- return -EEXIST;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
- capidevs[minor].is_open = 1;
- skb_queue_head_init(&capidevs[minor].recv_queue);
- MOD_INC_USE_COUNT;
- capidevs[minor].nopen++;
+ mp->datahandle = 0;
+ mp->file = file;
+ file->private_data = (void *)mp;
+ handle_minor_recv(mp);
+ return 0;
+}
- } else {
- capidevs[minor].is_open++;
- MOD_INC_USE_COUNT;
+long long capinc_raw_llseek(struct file *file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+ssize_t capinc_raw_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ struct sk_buff *skb;
+ int retval;
+ size_t copied = 0;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (!mp || !mp->nccip)
+ return -EINVAL;
+
+ if ((skb = skb_dequeue(&mp->recvqueue)) == 0) {
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ for (;;) {
+ interruptible_sleep_on(&mp->recvwait);
+ if (mp->nccip == 0)
+ return 0;
+ if ((skb = skb_dequeue(&mp->recvqueue)) != 0)
+ break;
+ if (signal_pending(current))
+ break;
+ }
+ if (skb == 0)
+ return -ERESTARTNOHAND;
}
+ do {
+ if (count < skb->len) {
+ retval = copy_to_user(buf, skb->data, count);
+ if (retval) {
+ skb_queue_head(&mp->recvqueue, skb);
+ return retval;
+ }
+ skb_pull(skb, count);
+ skb_queue_head(&mp->recvqueue, skb);
+ copied += count;
+ return copied;
+ } else {
+ retval = copy_to_user(buf, skb->data, skb->len);
+ if (retval) {
+ skb_queue_head(&mp->recvqueue, skb);
+ return copied;
+ }
+ copied += skb->len;
+ count -= skb->len;
+ buf += skb->len;
+ kfree_skb(skb);
+ }
+ } while ((skb = skb_dequeue(&mp->recvqueue)) != 0);
+
+ return copied;
+}
+
+ssize_t capinc_raw_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ struct sk_buff *skb;
+ int retval;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (!mp || !mp->nccip)
+ return -EINVAL;
+
+ skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER);
+
+ skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+ if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
+ kfree_skb(skb);
+ return retval;
+ }
+
+ while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ interruptible_sleep_on(&mp->sendwait);
+ if (mp->nccip == 0) {
+ kfree_skb(skb);
+ return -EIO;
+ }
+ if (signal_pending(current))
+ return -ERESTARTNOHAND;
+ }
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ return count;
+}
+
+unsigned int
+capinc_raw_poll(struct file *file, poll_table * wait)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ unsigned int mask = 0;
+
+ if (!mp || !mp->nccip)
+ return POLLERR|POLLHUP;
+ poll_wait(file, &(mp->recvwait), wait);
+ if (!skb_queue_empty(&mp->recvqueue))
+ mask |= POLLIN | POLLRDNORM;
+ poll_wait(file, &(mp->sendwait), wait);
+ if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE)
+ mask = POLLOUT | POLLWRNORM;
+ return mask;
+}
+
+int capinc_raw_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+ if (!mp || !mp->nccip)
+ return -EINVAL;
+
+ switch (cmd) {
+ }
+ return -EINVAL;
+}
+
+int
+capinc_raw_release(struct inode *inode, struct file *file)
+{
+ struct capiminor *mp = (struct capiminor *)file->private_data;
+
+ if (mp) {
+ mp->file = 0;
+ if (mp->nccip == 0)
+ capiminor_free(mp);
+ }
+
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
return 0;
}
-static int
-capi_release(struct inode *inode, struct file *file)
+struct file_operations capinc_raw_fops =
{
- unsigned int minor = MINOR(inode->i_rdev);
- struct capidev *cdev;
+ capinc_raw_llseek,
+ capinc_raw_read,
+ capinc_raw_write,
+ NULL, /* capi_readdir */
+ capinc_raw_poll,
+ capinc_raw_ioctl,
+ NULL, /* capi_mmap */
+ capinc_raw_open,
+ NULL, /* capi_flush */
+ capinc_raw_release,
+ NULL, /* capi_fsync */
+ NULL, /* capi_fasync */
+};
+
+/* -------- tty_operations for capincci ----------------------------- */
+
+int capinc_tty_open(struct tty_struct * tty, struct file * file)
+{
+ struct capiminor *mp;
+
+ if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+ return -ENXIO;
+ if (mp->nccip == 0)
+ return -ENXIO;
+ if (mp->file)
+ return -EBUSY;
+
+ skb_queue_head_init(&mp->recvqueue);
+ init_waitqueue_head(&mp->recvwait);
+ init_waitqueue_head(&mp->sendwait);
+ tty->driver_data = (void *)mp;
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(THIS_MODULE));
+#endif
+ if (atomic_read(&mp->ttyopencount) == 0)
+ mp->tty = tty;
+ atomic_inc(&mp->ttyopencount);
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
+#endif
+ handle_minor_recv(mp);
+ return 0;
+}
+
+void capinc_tty_close(struct tty_struct * tty, struct file * file)
+{
+ struct capiminor *mp;
+
+ mp = (struct capiminor *)tty->driver_data;
+ if (mp) {
+ if (atomic_dec_and_test(&mp->ttyopencount)) {
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_close lastclose\n");
+#endif
+ tty->driver_data = (void *)0;
+ mp->tty = 0;
+ }
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
+#endif
+ if (mp->nccip == 0)
+ capiminor_free(mp);
+ }
+
+#ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capinc_tty_close\n");
+#endif
+}
+
+int capinc_tty_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
+ int retval;
- if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
- printk(KERN_ERR "capi20: release minor %d ???\n", minor);
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n",
+ from_user, count);
+#endif
+
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
+#endif
return 0;
}
- cdev = &capidevs[minor];
- if (minor) {
-
- if (cdev->is_registered)
- (*capifuncs->capi_release) (cdev->applid);
+ skb = mp->ttyskb;
+ if (skb) {
+ mp->ttyskb = 0;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ }
- cdev->is_registered = 0;
- cdev->applid = 0;
+ skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
+ return -ENOMEM;
+ }
- while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) {
+ skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+ if (from_user) {
+ if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
kfree_skb(skb);
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval);
+#endif
+ return retval;
}
- cdev->is_open = 0;
} else {
- cdev->is_open--;
+ memcpy(skb_put(skb, count), buf, count);
}
- MOD_DEC_USE_COUNT;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ (void)handle_minor_recv(mp);
+ return count;
+}
+
+void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
+#endif
+
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
+#endif
+ return;
+ }
+
+ skb = mp->ttyskb;
+ if (skb) {
+ if (skb_tailroom(skb) > 0) {
+ *(skb_put(skb, 1)) = ch;
+ return;
+ }
+ mp->ttyskb = 0;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ }
+ skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC);
+ if (skb) {
+ skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+ *(skb_put(skb, 1)) = ch;
+ mp->ttyskb = skb;
+ } else {
+ printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+ }
+}
+
+void capinc_tty_flush_chars(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_chars\n");
+#endif
+
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
+#endif
+ return;
+ }
+
+ skb = mp->ttyskb;
+ if (skb) {
+ mp->ttyskb = 0;
+ skb_queue_tail(&mp->outqueue, skb);
+ mp->outbytes += skb->len;
+ (void)handle_minor_send(mp);
+ }
+ (void)handle_minor_recv(mp);
+}
+
+int capinc_tty_write_room(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ int room;
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
+#endif
+ return 0;
+ }
+ room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
+ room *= CAPI_MAX_BLKSIZE;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);
+#endif
+ return room;
+}
+
+int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
+#endif
+ return 0;
+ }
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
+ mp->outbytes, mp->nack,
+ skb_queue_len(&mp->outqueue),
+ skb_queue_len(&mp->inqueue));
+#endif
+ return mp->outbytes;
+}
+
+int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_set_termios\n");
+#endif
+}
+
+void capinc_tty_throttle(struct tty_struct * tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_throttle\n");
+#endif
+ if (mp)
+ mp->ttyinstop = 1;
+}
+
+void capinc_tty_unthrottle(struct tty_struct * tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_unthrottle\n");
+#endif
+ if (mp) {
+ mp->ttyinstop = 0;
+ handle_minor_recv(mp);
+ }
+}
+
+void capinc_tty_stop(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_stop\n");
+#endif
+ if (mp) {
+ mp->ttyoutstop = 1;
+ }
+}
+
+void capinc_tty_start(struct tty_struct *tty)
+{
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_start\n");
+#endif
+ if (mp) {
+ mp->ttyoutstop = 0;
+ (void)handle_minor_send(mp);
+ }
+}
+
+void capinc_tty_hangup(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_hangup\n");
+#endif
+}
+
+void capinc_tty_break_ctl(struct tty_struct *tty, int state)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
+#endif
+}
+
+void capinc_tty_flush_buffer(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
+#endif
+}
+
+void capinc_tty_set_ldisc(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
+#endif
+}
+
+void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+#ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
+#endif
+}
+
+int capinc_tty_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
return 0;
}
-static struct file_operations capi_fops =
+int capinc_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
{
- llseek: capi_llseek,
- read: capi_read,
- write: capi_write,
- poll: capi_poll,
- ioctl: capi_ioctl,
- open: capi_open,
- release: capi_release,
-};
+ return 0;
+}
+
+#define CAPINC_NR_PORTS 256
+static struct tty_driver capinc_tty_driver;
+static int capinc_tty_refcount;
+static struct tty_struct *capinc_tty_table[CAPINC_NR_PORTS];
+static struct termios *capinc_tty_termios[CAPINC_NR_PORTS];
+static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS];
+
+int capinc_tty_init(void)
+{
+ struct tty_driver *drv = &capinc_tty_driver;
+
+ /* Initialize the tty_driver structure */
+
+ memset(drv, 0, sizeof(struct tty_driver));
+ drv->magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+ drv->driver_name = "capi_nc";
+#endif
+ drv->name = "capi/%d";
+ drv->major = capi_ttymajor;
+ drv->minor_start = 0;
+ drv->num = CAPINC_NR_PORTS;
+ drv->type = TTY_DRIVER_TYPE_SERIAL;
+ drv->subtype = SERIAL_TYPE_NORMAL;
+ drv->init_termios = tty_std_termios;
+ drv->init_termios.c_iflag = ICRNL;
+ drv->init_termios.c_oflag = OPOST | ONLCR;
+ drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ drv->init_termios.c_lflag = 0;
+ drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS;
+ drv->refcount = &capinc_tty_refcount;
+ drv->table = capinc_tty_table;
+ drv->termios = capinc_tty_termios;
+ drv->termios_locked = capinc_tty_termios_locked;
+
+ drv->open = capinc_tty_open;
+ drv->close = capinc_tty_close;
+ drv->write = capinc_tty_write;
+ drv->put_char = capinc_tty_put_char;
+ drv->flush_chars = capinc_tty_flush_chars;
+ drv->write_room = capinc_tty_write_room;
+ drv->chars_in_buffer = capinc_tty_chars_in_buffer;
+ drv->ioctl = capinc_tty_ioctl;
+ drv->set_termios = capinc_tty_set_termios;
+ drv->throttle = capinc_tty_throttle;
+ drv->unthrottle = capinc_tty_unthrottle;
+ drv->stop = capinc_tty_stop;
+ drv->start = capinc_tty_start;
+ drv->hangup = capinc_tty_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+ drv->break_ctl = capinc_tty_break_ctl;
+#endif
+ drv->flush_buffer = capinc_tty_flush_buffer;
+ drv->set_ldisc = capinc_tty_set_ldisc;
+#if (LINUX_VERSION_CODE >= 131343)
+ drv->send_xchar = capinc_tty_send_xchar;
+ drv->read_proc = capinc_tty_read_proc;
+#endif
+ if (tty_register_driver(drv)) {
+ printk(KERN_ERR "Couldn't register capi_nc driver\n");
+ return -1;
+ }
+ return 0;
+}
-/* -------- /proc functions ----------------------------------- */
+void capinc_tty_exit(void)
+{
+ struct tty_driver *drv = &capinc_tty_driver;
+ int retval;
+ if ((retval = tty_unregister_driver(drv)))
+ printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);
+}
+
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- /proc functions ----------------------------------------- */
/*
* /proc/capi/capi20:
- * minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
+ * minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
*/
static int proc_capidev_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- struct capidev *cp;
- int i;
+ struct capidev *cdev;
int len = 0;
off_t begin = 0;
- for (i=0; i < CAPI_MAXMINOR; i++) {
- cp = &capidevs[i+1];
- if (cp->nopen == 0) continue;
- len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n",
- i+1,
- cp->nopen,
- cp->nrecvctlpkt,
- cp->nrecvdatapkt,
- cp->nsentctlpkt,
- cp->nsentdatapkt);
+ for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+ len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n",
+ cdev->minor,
+ cdev->applid,
+ cdev->nrecvctlpkt,
+ cdev->nrecvdatapkt,
+ cdev->nsentctlpkt,
+ cdev->nsentdatapkt);
if (len+begin > off+count)
goto endloop;
if (len+begin < off) {
@@ -556,7 +1831,46 @@ static int proc_capidev_read_proc(char *page, char **start, off_t off,
}
}
endloop:
- if (i >= CAPI_MAXMINOR)
+ if (cdev == 0)
+ *eof = 1;
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * /proc/capi/capi20ncci:
+ * applid ncci
+ */
+static int proc_capincci_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct capidev *cdev;
+ struct capincci *np;
+ int len = 0;
+ off_t begin = 0;
+
+ for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+ for (np=cdev->nccis; np; np = np->next) {
+ len += sprintf(page+len, "%d 0x%x%s\n",
+ cdev->applid,
+ np->ncci,
+#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
+ "");
+#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ np->minorp && np->minorp->file ? " open" : "");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ if (len+begin > off+count)
+ goto endloop;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ }
+endloop:
+ if (cdev == 0)
*eof = 1;
if (off >= len+begin)
return 0;
@@ -573,6 +1887,7 @@ static struct procfsentries {
} procfsentries[] = {
/* { "capi", S_IFDIR, 0 }, */
{ "capi/capi20", 0 , proc_capidev_read_proc },
+ { "capi/capi20ncci", 0 , proc_capincci_read_proc },
};
static void proc_init(void)
@@ -600,78 +1915,226 @@ static void proc_exit(void)
}
}
}
+
/* -------- init function and module interface ---------------------- */
+
+static void alloc_exit(void)
+{
+ if (capidev_cachep) {
+ (void)kmem_cache_destroy(capidev_cachep);
+ capidev_cachep = 0;
+ }
+ if (capincci_cachep) {
+ (void)kmem_cache_destroy(capincci_cachep);
+ capincci_cachep = 0;
+ }
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if (capidh_cachep) {
+ (void)kmem_cache_destroy(capidh_cachep);
+ capidh_cachep = 0;
+ }
+ if (capiminor_cachep) {
+ (void)kmem_cache_destroy(capiminor_cachep);
+ capiminor_cachep = 0;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+}
+
+static int alloc_init(void)
+{
+ capidev_cachep = kmem_cache_create("capi20_dev",
+ sizeof(struct capidev),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capidev_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+
+ capincci_cachep = kmem_cache_create("capi20_ncci",
+ sizeof(struct capincci),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capincci_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ capidh_cachep = kmem_cache_create("capi20_dh",
+ sizeof(struct datahandle_queue),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capidh_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+ capiminor_cachep = kmem_cache_create("capi20_minor",
+ sizeof(struct capiminor),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!capiminor_cachep) {
+ alloc_exit();
+ return -ENOMEM;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return 0;
+}
+
+static void lower_callback(unsigned int cmd, __u32 contr, void *data)
+{
+ struct capi_ncciinfo *np;
+ struct capidev *cdev;
+
+ switch (cmd) {
+ case KCI_CONTRUP:
+ printk(KERN_INFO "capi: controller %hu up\n", contr);
+ break;
+ case KCI_CONTRDOWN:
+ printk(KERN_INFO "capi: controller %hu down\n", contr);
+ break;
+ case KCI_NCCIUP:
+ np = (struct capi_ncciinfo *)data;
+ if ((cdev = capidev_find(np->applid)) == 0)
+ return;
+ (void)capincci_alloc(cdev, np->ncci);
+ break;
+ case KCI_NCCIDOWN:
+ np = (struct capi_ncciinfo *)data;
+ if ((cdev = capidev_find(np->applid)) == 0)
+ return;
+ (void)capincci_free(cdev, np->ncci);
+ break;
+ }
+}
+
#ifdef MODULE
#define capi_init init_module
#endif
static struct capi_interface_user cuser = {
"capi20",
- 0,
+ lower_callback,
};
+static char rev[10];
+
int capi_init(void)
{
- int j;
-
- memset(capidevs, 0, sizeof(capidevs));
- for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) {
- init_waitqueue_head(&capidevs[j].recv_wait);
- }
+ char *p;
+
+ MOD_INC_USE_COUNT;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 2);
+ p = strchr(rev, '$');
+ *(p-1) = 0;
+ } else
+ strcpy(rev, "???");
if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) {
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if (devfs_register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) {
+ devfs_unregister_chrdev(capi_major, "capi20");
+ printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor);
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+ devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS,
+ DEVFS_FL_DEFAULT,
+ capi_rawmajor, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ &capinc_raw_fops, NULL);
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
&capi_fops, NULL);
- devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT,
- capi_major, 1,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
- &capi_fops, NULL);
- devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT,
- capi_major, 11,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
- &capi_fops, NULL);
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
+
+ MOD_DEC_USE_COUNT;
devfs_unregister_chrdev(capi_major, "capi20");
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
capi_major, 0,
DEVFS_SPECIAL_CHR, 0));
- for (j = 0; j < 10; j++) {
- char devname[32];
+ return -EIO;
+ }
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ if (capinc_tty_init() < 0) {
+ (void) detach_capi_interface(&cuser);
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- sprintf(devname, "isdn/capi20.0%i", j);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0));
- sprintf (devname, "isdn/capi20.1%i", j);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0));
+ if (alloc_init() < 0) {
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ unsigned int j;
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ for (j = 0; j < CAPINC_NR_PORTS; j++) {
+ char devname[32];
+ sprintf(devname, "capi/r%u", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
}
- return -EIO;
+ capinc_tty_exit();
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ (void) detach_capi_interface(&cuser);
+ devfs_unregister_chrdev(capi_major, "capi20");
+ devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
+ capi_major, 0,
+ DEVFS_SPECIAL_CHR, 0));
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
}
+
(void)proc_init();
+
+ printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n",
+ rev, capi_major);
+
+ MOD_DEC_USE_COUNT;
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
- int i;
- char devname[32];
-
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ unsigned int j;
+#endif
+ alloc_exit();
(void)proc_exit();
+
devfs_unregister_chrdev(capi_major, "capi20");
devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0));
- for (i = 0; i < 10; i++) {
- sprintf (devname, "isdn/capi20.0%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0));
- sprintf (devname, "isdn/capi20.1%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0));
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ capinc_tty_exit();
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ for (j = 0; j < CAPINC_NR_PORTS; j++) {
+ char devname[32];
+ sprintf(devname, "capi/r%u", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
}
+#endif
(void) detach_capi_interface(&cuser);
+ printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev);
}
#endif
diff --git a/drivers/isdn/avmb1/capicmd.h b/drivers/isdn/avmb1/capicmd.h
index 104ef824f..970365f7a 100644
--- a/drivers/isdn/avmb1/capicmd.h
+++ b/drivers/isdn/avmb1/capicmd.h
@@ -1,11 +1,22 @@
/*
- * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ * $Id: capicmd.h,v 1.2 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capicmd.h,v $
+ * Revision 1.2 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.1 1997/03/04 21:50:30 calle
* Frirst version in isdn4linux
*
@@ -20,6 +31,10 @@
#ifndef __CAPICMD_H__
#define __CAPICMD_H__
+#define CAPI_MSG_BASELEN 8
+#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2)
+#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2)
+
/*----- CAPI commands -----*/
#define CAPI_ALERT 0x01
#define CAPI_CONNECT 0x02
diff --git a/drivers/isdn/avmb1/capidev.h b/drivers/isdn/avmb1/capidev.h
index 96e37c1f4..6f1d9a42a 100644
--- a/drivers/isdn/avmb1/capidev.h
+++ b/drivers/isdn/avmb1/capidev.h
@@ -1,11 +1,22 @@
/*
- * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $
+ * $Id: capidev.h,v 1.5 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 Interface for Linux
*
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidev.h,v $
+ * Revision 1.5 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.4 1999/07/01 15:26:32 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
@@ -40,18 +51,18 @@
*/
struct capidev {
- int is_open;
- int is_registered;
- __u16 applid;
+ struct capidev *next;
+ struct file *file;
+ __u16 applid;
+ __u16 errcode;
+ unsigned int minor;
+
struct sk_buff_head recv_queue;
wait_queue_head_t recv_wait;
- __u16 errcode;
+
/* Statistic */
- unsigned long nopen;
- unsigned long nrecvctlpkt;
- unsigned long nrecvdatapkt;
- unsigned long nsentctlpkt;
- unsigned long nsentdatapkt;
+ unsigned long nrecvctlpkt;
+ unsigned long nrecvdatapkt;
+ unsigned long nsentctlpkt;
+ unsigned long nsentdatapkt;
};
-
-#define CAPI_MAXMINOR CAPI_MAXAPPL
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 79bb370d1..d35c21d77 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,22 @@
/*
- * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $
+ * $Id: capidrv.c,v 1.30 2000/03/03 15:50:42 calle Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.30 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.29 1999/12/06 17:13:06 calle
* Added controller watchdog.
*
@@ -171,7 +182,7 @@
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.29 $";
+static char *revision = "$Revision: 1.30 $";
int debugmode = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -440,25 +451,33 @@ static inline __u8 cip2si2(__u16 cipval)
static inline capidrv_contr *findcontrbydriverid(int driverid)
{
capidrv_contr *p = global.contr_list;
+ long flags;
+ save_flags(flags);
+ cli();
while (p) {
if (p->myid == driverid)
- return p;
+ break;
p = p->next;
}
- return (capidrv_contr *) 0;
+ restore_flags(flags);
+ return p;
}
static capidrv_contr *findcontrbynumber(__u32 contr)
{
capidrv_contr *p = global.contr_list;
+ long flags;
+ save_flags(flags);
+ cli();
while (p) {
if (p->contrnr == contr)
- return p;
+ break;
p = p->next;
}
- return (capidrv_contr *) 0;
+ restore_flags(flags);
+ return p;
}
@@ -1501,7 +1520,7 @@ static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
static _cmsg s_cmsg;
-static void capidrv_signal(__u16 applid, __u32 dummy)
+static void capidrv_signal(__u16 applid, void *dummy)
{
struct sk_buff *skb = 0;
@@ -2218,14 +2237,18 @@ static void listentimerfunc(unsigned long x)
static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
{
capidrv_contr *card;
+ long flags;
isdn_ctrl cmd;
char id[20];
int i;
+ MOD_INC_USE_COUNT;
+
sprintf(id, "capidrv-%d", contr);
if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
printk(KERN_WARNING
"capidrv: (%s) Could not allocate contr-struct.\n", id);
+ MOD_DEC_USE_COUNT;
return -1;
}
memset(card, 0, sizeof(capidrv_contr));
@@ -2238,6 +2261,7 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
printk(KERN_WARNING
"capidrv: (%s) Could not allocate bchan-structs.\n", id);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -1;
}
card->interface.channels = profp->nbchannel;
@@ -2258,29 +2282,35 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
ISDN_FEATURE_P_UNKNOWN;
card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
- card->next = global.contr_list;
- global.contr_list = card;
- global.ncontr++;
+
+
card->q931_read = card->q931_buf;
card->q931_write = card->q931_buf;
card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
if (!register_isdn(&card->interface)) {
- global.contr_list = global.contr_list->next;
printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
kfree(card->bchans);
kfree(card);
+ MOD_DEC_USE_COUNT;
return -1;
}
card->myid = card->interface.channels;
+ save_flags(flags);
+ cli();
+ card->next = global.contr_list;
+ global.contr_list = card;
+ global.ncontr++;
+ restore_flags(flags);
+
memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
for (i = 0; i < card->nbchan; i++) {
card->bchans[i].contr = card;
}
- cmd.driver = card->myid;
cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
card->interface.statcallb(&cmd);
card->cipmask = 0x1FFF03FF; /* any */
@@ -2304,30 +2334,41 @@ static int capidrv_delcontr(__u16 contr)
{
capidrv_contr **pp, *card;
isdn_ctrl cmd;
+ long flags;
int i;
+ save_flags(flags);
+ cli();
for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
if ((*pp)->contrnr == contr)
break;
}
if (!*pp) {
+ restore_flags(flags);
printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
return -1;
}
card = *pp;
+ *pp = (*pp)->next;
+ global.ncontr--;
+ restore_flags(flags);
if (debugmode)
printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
card->contrnr, card->myid);
- cmd.command = ISDN_STAT_UNLOAD;
+ cmd.command = ISDN_STAT_STOP;
cmd.driver = card->myid;
card->interface.statcallb(&cmd);
- *pp = (*pp)->next;
- global.ncontr--;
-
for (i = 0; i < card->nbchan; i++) {
+
+ cmd.command = ISDN_STAT_DISCH;
+ cmd.driver = card->myid;
+ cmd.arg = i;
+ cmd.parm.num[0] = 0;
+ card->interface.statcallb(&cmd);
+
if (card->bchans[i].nccip)
free_ncci(card, card->bchans[i].nccip);
if (card->bchans[i].plcip)
@@ -2338,10 +2379,16 @@ static int capidrv_delcontr(__u16 contr)
kfree(card->bchans);
del_timer(&card->listentimer);
- printk(KERN_INFO "%s: now down.\n", card->name);
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
kfree(card);
+ printk(KERN_INFO "%s: now down.\n", card->name);
+
+ MOD_DEC_USE_COUNT;
+
return 0;
}
@@ -2438,10 +2485,14 @@ int capidrv_init(void)
__u32 ncontr, contr;
__u16 errcode;
+ MOD_INC_USE_COUNT;
+
capifuncs = attach_capi_interface(&cuser);
- if (!capifuncs)
+ if (!capifuncs) {
+ MOD_DEC_USE_COUNT;
return -EIO;
+ }
if ((p = strchr(revision, ':'))) {
strcpy(rev, p + 1);
@@ -2456,6 +2507,7 @@ int capidrv_init(void)
errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
if (errcode) {
detach_capi_interface(&cuser);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -2463,6 +2515,7 @@ int capidrv_init(void)
if (errcode != CAPI_NOERROR) {
(void) (*capifuncs->capi_release) (global.appid);
detach_capi_interface(&cuser);
+ MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -2477,6 +2530,9 @@ int capidrv_init(void)
}
proc_init();
+ printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev);
+ MOD_DEC_USE_COUNT;
+
return 0;
}
@@ -2484,6 +2540,7 @@ int capidrv_init(void)
void cleanup_module(void)
{
capidrv_contr *card, *next;
+ long flags;
char rev[10];
char *p;
@@ -2498,8 +2555,15 @@ void cleanup_module(void)
for (card = global.contr_list; card; card = next) {
next = card->next;
disable_dchannel_trace(card);
+ }
+
+ save_flags(flags);
+ cli();
+ for (card = global.contr_list; card; card = next) {
+ next = card->next;
capidrv_delcontr(card->contrnr);
}
+ restore_flags(flags);
(void) (*capifuncs->capi_release) (global.appid);
detach_capi_interface(&cuser);
diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
new file mode 100644
index 000000000..b869e6b5c
--- /dev/null
+++ b/drivers/isdn/avmb1/capifs.c
@@ -0,0 +1,595 @@
+/*
+ * $Id: capifs.c,v 1.5 2000/03/13 17:49:52 calle Exp $
+ *
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
+ *
+ * Heavily based on devpts filesystem from H. Peter Anvin
+ *
+ * $Log: capifs.c,v $
+ * Revision 1.5 2000/03/13 17:49:52 calle
+ * make it running with 2.3.51.
+ *
+ * Revision 1.4 2000/03/08 17:06:33 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.3 2000/03/06 18:00:23 calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
+ * Revision 1.2 2000/03/06 09:17:07 calle
+ * - capifs: fileoperations now in inode (change for 2.3.49)
+ * - Config.in: Middleware extention not a tristate, uups.
+ *
+ * Revision 1.1 2000/03/03 16:48:38 calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ * It is now possible to create a connection with a CAPI2.0 applikation
+ * and than to handle the data connection from /dev/capi/ (capifs) and also
+ * using async or sync PPP on this connection.
+ * The two major device number 190 and 191 are not confirmed yet,
+ * but I want to save the code in cvs, before I go on.
+ *
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/param.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/ctype.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
+
+static char *revision = "$Revision: 1.5 $";
+
+struct capifs_ncci {
+ struct inode *inode;
+ char used;
+ char type;
+ unsigned int num;
+ kdev_t kdev;
+};
+
+struct capifs_sb_info {
+ u32 magic;
+ struct super_block *next;
+ struct super_block **back;
+ int setuid;
+ int setgid;
+ uid_t uid;
+ gid_t gid;
+ umode_t mode;
+
+ unsigned int max_ncci;
+ struct capifs_ncci *nccis;
+};
+
+#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
+#define CAPIFS_SBI_MAGIC (('C'<<24)|('A'<<16)|('P'<<8)|'I')
+
+static inline struct capifs_sb_info *SBI(struct super_block *sb)
+{
+ return (struct capifs_sb_info *)(sb->u.generic_sbp);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int capifs_root_readdir(struct file *,void *,filldir_t);
+static struct dentry *capifs_root_lookup(struct inode *,struct dentry *);
+static int capifs_revalidate(struct dentry *, int);
+
+static struct file_operations capifs_root_operations = {
+ read: generic_read_dir,
+ readdir: capifs_root_readdir,
+};
+
+struct inode_operations capifs_root_inode_operations = {
+ lookup: capifs_root_lookup,
+};
+
+struct inode_operations capifs_inode_operations;
+
+static struct dentry_operations capifs_dentry_operations = {
+ d_revalidate: capifs_revalidate,
+};
+
+/*
+ * /dev/capi/%d
+ * /dev/capi/r%d
+ */
+
+static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
+ off_t nr;
+ char numbuf[32];
+
+ nr = filp->f_pos;
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ default:
+ while (nr < sbi->max_ncci) {
+ int n = nr - 2;
+ struct capifs_ncci *np = &sbi->nccis[n];
+ if (np->inode && np->used) {
+ char *p = numbuf;
+ if (np->type) *p++ = np->type;
+ sprintf(p, "%u", np->num);
+ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+ return 0;
+ }
+ filp->f_pos = ++nr;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Revalidate is called on every cache lookup. We use it to check that
+ * the ncci really does still exist. Never revalidate negative dentries;
+ * for simplicity (fix later?)
+ */
+static int capifs_revalidate(struct dentry * dentry, int flags)
+{
+ struct capifs_sb_info *sbi;
+
+ if ( !dentry->d_inode )
+ return 0;
+
+ sbi = SBI(dentry->d_inode->i_sb);
+
+ return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode );
+}
+
+static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry)
+{
+ struct capifs_sb_info *sbi = SBI(dir->i_sb);
+ struct capifs_ncci *np;
+ unsigned int i;
+ char numbuf[32];
+ char *p, *tmp;
+ unsigned int num;
+ char type = 0;
+
+ dentry->d_inode = NULL; /* Assume failure */
+ dentry->d_op = &capifs_dentry_operations;
+
+ if (dentry->d_name.len >= sizeof(numbuf) )
+ return NULL;
+ strncpy(numbuf, dentry->d_name.name, dentry->d_name.len);
+ numbuf[dentry->d_name.len] = 0;
+ p = numbuf;
+ if (!isdigit(*p)) type = *p++;
+ tmp = p;
+ num = (unsigned int)simple_strtoul(p, &tmp, 10);
+ if (tmp == p || *tmp)
+ return NULL;
+
+ for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) {
+ if (np->used && np->num == num && np->type == type)
+ break;
+ }
+
+ if ( i >= sbi->max_ncci )
+ return NULL;
+
+ dentry->d_inode = np->inode;
+ if ( dentry->d_inode )
+ dentry->d_inode->i_count++;
+
+ d_add(dentry, dentry->d_inode);
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct super_block *mounts = NULL;
+
+static void capifs_put_super(struct super_block *sb)
+{
+ struct capifs_sb_info *sbi = SBI(sb);
+ struct inode *inode;
+ int i;
+
+ for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
+ if ( (inode = sbi->nccis[i].inode) ) {
+ if ( inode->i_count != 1 )
+ printk("capifs_put_super: badness: entry %d count %d\n",
+ i, inode->i_count);
+ inode->i_nlink--;
+ iput(inode);
+ }
+ }
+
+ *sbi->back = sbi->next;
+ if ( sbi->next )
+ SBI(sbi->next)->back = sbi->back;
+
+ kfree(sbi->nccis);
+ kfree(sbi);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void capifs_write_inode(struct inode *inode) { };
+#else
+static int capifs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+static void capifs_read_inode(struct inode *inode);
+
+static struct super_operations capifs_sops = {
+ read_inode: capifs_read_inode,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ write_inode: capifs_write_inode,
+#endif
+ put_super: capifs_put_super,
+ statfs: capifs_statfs,
+};
+
+static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
+{
+ int setuid = 0;
+ int setgid = 0;
+ uid_t uid = 0;
+ gid_t gid = 0;
+ umode_t mode = 0600;
+ unsigned int maxncci = 512;
+ char *this_char, *value;
+
+ this_char = NULL;
+ if ( options )
+ this_char = strtok(options,",");
+ for ( ; this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"uid")) {
+ if (!value || !*value)
+ return 1;
+ uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ setuid = 1;
+ }
+ else if (!strcmp(this_char,"gid")) {
+ if (!value || !*value)
+ return 1;
+ gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ setgid = 1;
+ }
+ else if (!strcmp(this_char,"mode")) {
+ if (!value || !*value)
+ return 1;
+ mode = simple_strtoul(value,&value,8);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"maxncci")) {
+ if (!value || !*value)
+ return 1;
+ maxncci = simple_strtoul(value,&value,8);
+ if (*value)
+ return 1;
+ }
+ else
+ return 1;
+ }
+ sbi->setuid = setuid;
+ sbi->setgid = setgid;
+ sbi->uid = uid;
+ sbi->gid = gid;
+ sbi->mode = mode & ~S_IFMT;
+ sbi->max_ncci = maxncci;
+
+ return 0;
+}
+
+struct super_block *capifs_read_super(struct super_block *s, void *data,
+ int silent)
+{
+ struct inode * root_inode;
+ struct dentry * root;
+ struct capifs_sb_info *sbi;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ MOD_INC_USE_COUNT;
+ lock_super(s);
+#endif
+ /* Super block already completed? */
+ if (s->s_root)
+ goto out;
+
+ sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL);
+ if ( !sbi )
+ goto fail;
+
+ memset(sbi, 0, sizeof(struct capifs_sb_info));
+ sbi->magic = CAPIFS_SBI_MAGIC;
+
+ if ( capifs_parse_options(data,sbi) ) {
+ kfree(sbi);
+ printk("capifs: called with bogus options\n");
+ goto fail;
+ }
+
+ sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL);
+ if ( !sbi->nccis ) {
+ kfree(sbi);
+ goto fail;
+ }
+ memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci);
+
+ s->u.generic_sbp = (void *) sbi;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = CAPIFS_SUPER_MAGIC;
+ s->s_op = &capifs_sops;
+ s->s_root = NULL;
+
+ /*
+ * Get the root inode and dentry, but defer checking for errors.
+ */
+ root_inode = iget(s, 1); /* inode 1 == root directory */
+ root = d_alloc_root(root_inode);
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root) {
+ if (root) dput(root);
+ else iput(root_inode);
+ goto out;
+ }
+
+ if (!root) {
+ printk("capifs: get root dentry failed\n");
+ /*
+ * iput() can block, so we clear the super block first.
+ */
+ iput(root_inode);
+ kfree(sbi->nccis);
+ kfree(sbi);
+ goto fail;
+ }
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out;
+
+ /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ s->s_root = root;
+
+ sbi->next = mounts;
+ if ( sbi->next )
+ SBI(sbi->next)->back = &(sbi->next);
+ sbi->back = &mounts;
+ mounts = s;
+
+out: /* Success ... somebody else completed the super block for us. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ unlock_super(s);
+#endif
+ return s;
+fail:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+#endif
+ return NULL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = CAPIFS_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ tmp.f_blocks = 0;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+#else
+static int capifs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ buf->f_type = CAPIFS_SUPER_MAGIC;
+ buf->f_bsize = 1024;
+ buf->f_blocks = 0;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_files = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
+}
+#endif
+
+static void capifs_read_inode(struct inode *inode)
+{
+ ino_t ino = inode->i_ino;
+ struct capifs_sb_info *sbi = SBI(inode->i_sb);
+
+ inode->i_op = NULL;
+ inode->i_mode = 0;
+ inode->i_nlink = 0;
+ inode->i_size = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
+ inode->i_uid = inode->i_gid = 0;
+
+ if ( ino == 1 ) {
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+ inode->i_op = &capifs_root_inode_operations;
+ inode->i_fop = &capifs_root_operations;
+ inode->i_nlink = 2;
+ return;
+ }
+
+ /* need dummy inode operations .... */
+ inode->i_op = &capifs_inode_operations;
+
+ ino -= 2;
+ if ( ino >= sbi->max_ncci )
+ return; /* Bogus */
+
+ init_special_inode(inode, S_IFCHR, 0);
+
+ return;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static struct file_system_type capifs_fs_type = {
+ "capifs",
+ 0,
+ capifs_read_super,
+ NULL
+};
+#else
+static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0);
+#endif
+
+void capifs_new_ncci(char type, unsigned int num, kdev_t device)
+{
+ struct super_block *sb;
+ struct capifs_sb_info *sbi;
+ struct capifs_ncci *np;
+ ino_t ino;
+
+ for ( sb = mounts ; sb ; sb = sbi->next ) {
+ sbi = SBI(sb);
+
+ for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
+ if (np->used == 0) {
+ np->used = 1;
+ np->type = type;
+ np->num = num;
+ np->kdev = device;
+ break;
+ }
+ }
+
+ if ((np->inode = iget(sb, ino+2)) != 0) {
+ struct inode *inode = np->inode;
+ inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
+ inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
+ inode->i_mode = sbi->mode | S_IFCHR;
+ inode->i_rdev = np->kdev;
+ inode->i_nlink++;
+ }
+ }
+}
+
+void capifs_free_ncci(char type, unsigned int num)
+{
+ struct super_block *sb;
+ struct capifs_sb_info *sbi;
+ struct inode *inode;
+ struct capifs_ncci *np;
+ ino_t ino;
+
+ for ( sb = mounts ; sb ; sb = sbi->next ) {
+ sbi = SBI(sb);
+
+ for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
+ if (!np->used || np->type != type || np->num != num)
+ continue;
+ if (np->inode) {
+ inode = np->inode;
+ np->used = 0;
+ inode->i_nlink--;
+ iput(inode);
+ break;
+ }
+ }
+ }
+}
+
+int __init capifs_init(void)
+{
+ char rev[10];
+ char *p;
+ int err;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, "1.0");
+
+ err = register_filesystem(&capifs_fs_type);
+ if (err)
+ return err;
+#ifdef MODULE
+ printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev);
+#else
+ printk(KERN_NOTICE "capifs: Rev%s: started\n", rev);
+#endif
+ return 0;
+}
+
+void capifs_exit(void)
+{
+ unregister_filesystem(&capifs_fs_type);
+}
+
+EXPORT_SYMBOL(capifs_new_ncci);
+EXPORT_SYMBOL(capifs_free_ncci);
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ return capifs_init();
+}
+
+void cleanup_module(void)
+{
+ capifs_exit();
+}
+
+#endif
diff --git a/drivers/isdn/avmb1/capifs.h b/drivers/isdn/avmb1/capifs.h
new file mode 100644
index 000000000..f6b8072ed
--- /dev/null
+++ b/drivers/isdn/avmb1/capifs.h
@@ -0,0 +1,25 @@
+/*
+ * $Id: capifs.h,v 1.2 2000/03/08 17:06:33 calle Exp $
+ *
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
+ *
+ * $Log: capifs.h,v $
+ * Revision 1.2 2000/03/08 17:06:33 calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.1 2000/03/03 16:48:38 calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ * It is now possible to create a connection with a CAPI2.0 applikation
+ * and than to handle the data connection from /dev/capi/ (capifs) and also
+ * using async or sync PPP on this connection.
+ * The two major device number 190 and 191 are not confirmed yet,
+ * but I want to save the code in cvs, before I go on.
+ *
+ *
+ */
+
+void capifs_new_ncci(char type, unsigned int num, kdev_t device);
+void capifs_free_ncci(char type, unsigned int num);
diff --git a/drivers/isdn/avmb1/capiutil.c b/drivers/isdn/avmb1/capiutil.c
index 3482f2a97..6f10025f5 100644
--- a/drivers/isdn/avmb1/capiutil.c
+++ b/drivers/isdn/avmb1/capiutil.c
@@ -1,5 +1,5 @@
/*
- * $Id: capiutil.c,v 1.10 1999/08/31 11:19:54 paul Exp $
+ * $Id: capiutil.c,v 1.11 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 convert capi message to capi message struct
*
@@ -7,6 +7,17 @@
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capiutil.c,v $
+ * Revision 1.11 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.10 1999/08/31 11:19:54 paul
* various spelling corrections (new checksums may be needed, Karsten!)
*
@@ -794,7 +805,7 @@ static char *pnames[] =
/*15 */ "Class",
/*16 */ "ConnectedNumber",
/*17 */ "ConnectedSubaddress",
- /*18 */ "Data",
+ /*18 */ "Data32",
/*19 */ "DataHandle",
/*1a */ "DataLength",
/*1b */ "FacilityConfirmationParameter",
@@ -892,13 +903,7 @@ static void protocol_message_2_pars(_cmsg * cmsg, int level)
cmsg->l += 2;
break;
case _CDWORD:
- if (strcmp(NAME, "Data") == 0) {
- bufprint("%-*s = ", slen, NAME);
- printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
- *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
- bufprint("\n");
- } else
- bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
+ bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
cmsg->l += 4;
break;
case _CSTRUCT:
diff --git a/drivers/isdn/avmb1/capiutil.h b/drivers/isdn/avmb1/capiutil.h
index 3825ac308..8435ede45 100644
--- a/drivers/isdn/avmb1/capiutil.h
+++ b/drivers/isdn/avmb1/capiutil.h
@@ -1,5 +1,5 @@
/*
- * $Id: capiutil.h,v 1.4 1999/09/15 08:16:03 calle Exp $
+ * $Id: capiutil.h,v 1.5 2000/03/03 15:50:42 calle Exp $
*
* CAPI 2.0 defines & types
*
@@ -7,6 +7,17 @@
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capiutil.h,v $
+ * Revision 1.5 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.4 1999/09/15 08:16:03 calle
* Implementation of 64Bit extention complete.
*
@@ -36,28 +47,47 @@
#include <asm/types.h>
-#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8))
-#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8))
-#define CAPIMSG_COMMAND(m) (m[4])
-#define CAPIMSG_SUBCOMMAND(m) (m[5])
-#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8))
+#define CAPIMSG_BASELEN 8
+#define CAPIMSG_U8(m, off) (m[off])
+#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8))
+#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
+#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0)
+#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2)
+#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4)
+#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5)
+#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5]))
+#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6)
#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
-#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
+#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8)
#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
-#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
-#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8))
-
-#define CAPIMSG_SETAPPID(m, applid) \
- do { \
- ((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
- ((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
- } while (0)
-
-#define CAPIMSG_SETLEN(m, len) \
- do { \
- ((__u8 *)m)[0] = (__u16)(len) & 0xff; \
- ((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \
- } while (0)
+#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */
+
+static inline void capimsg_setu8(void *m, int off, __u8 val)
+{
+ ((__u8 *)m)[off] = val;
+}
+
+static inline void capimsg_setu16(void *m, int off, __u16 val)
+{
+ ((__u8 *)m)[off] = val & 0xff;
+ ((__u8 *)m)[off+1] = (val >> 8) & 0xff;
+}
+
+static inline void capimsg_setu32(void *m, int off, __u32 val)
+{
+ ((__u8 *)m)[off] = val & 0xff;
+ ((__u8 *)m)[off+1] = (val >> 8) & 0xff;
+ ((__u8 *)m)[off+2] = (val >> 16) & 0xff;
+ ((__u8 *)m)[off+3] = (val >> 24) & 0xff;
+}
+
+#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len)
+#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid)
+#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd)
+#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd)
+#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid)
+#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr)
+#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len)
/*----- basic-type definitions -----*/
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index d82fbc496..d678a8ad7 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -1,11 +1,22 @@
/*
- * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $
+ * $Id: kcapi.c,v 1.13 2000/03/03 15:50:42 calle Exp $
*
* Kernel CAPI 2.0 Module
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kcapi.c,v $
+ * Revision 1.13 2000/03/03 15:50:42 calle
+ * - kernel CAPI:
+ * - Changed parameter "param" in capi_signal from __u32 to void *.
+ * - rewrote notifier handling in kcapi.c
+ * - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ * - /dev/capi20 is now a cloning device.
+ * - middleware extentions prepared.
+ * - capidrv.c
+ * - locking of list operations and module count updates.
+ *
* Revision 1.12 2000/01/28 16:45:39 calle
* new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
* will search named driver and call the add_card function if one exist.
@@ -78,6 +89,7 @@
#include <linux/tqueue.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
+#include <linux/locks.h>
#include <asm/uaccess.h>
#include "capicmd.h"
#include "capiutil.h"
@@ -86,7 +98,7 @@
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.13 $";
/* ------------------------------------------------------------- */
@@ -125,8 +137,8 @@ struct capi_appl {
__u16 applid;
capi_register_params rparam;
int releasing;
- __u32 param;
- void (*signal) (__u16 applid, __u32 param);
+ void *param;
+ void (*signal) (__u16 applid, void *param);
struct sk_buff_head recv_queue;
int nncci;
struct capi_ncci *nccilist;
@@ -137,6 +149,14 @@ struct capi_appl {
unsigned long nsentdatapkt;
};
+struct capi_notifier {
+ struct capi_notifier *next;
+ unsigned int cmd;
+ __u32 controller;
+ __u16 applid;
+ __u32 ncci;
+};
+
/* ------------------------------------------------------------- */
static struct capi_version driver_version = {2, 0, 1, 1<<4};
@@ -160,9 +180,9 @@ static struct capi_ctr cards[CAPI_MAXCONTR];
static int ncards = 0;
static struct sk_buff_head recv_queue;
static struct capi_interface_user *capi_users = 0;
+static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;
static struct capi_driver *drivers;
-static long notify_up_set = 0;
-static long notify_down_set = 0;
+static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
static struct tq_struct tq_state_notify;
static struct tq_struct tq_recv_notify;
@@ -304,6 +324,7 @@ static int proc_driver_read_proc(char *page, char **start, off_t off,
int len = 0;
off_t begin = 0;
+ spin_lock(&drivers_lock);
for (driver = drivers; driver; driver = driver->next) {
len += sprintf(page+len, "%-32s %d %s\n",
driver->name,
@@ -317,6 +338,7 @@ static int proc_driver_read_proc(char *page, char **start, off_t off,
}
}
endloop:
+ spin_unlock(&drivers_lock);
if (!driver)
*eof = 1;
if (off >= len+begin)
@@ -336,6 +358,7 @@ static int proc_users_read_proc(char *page, char **start, off_t off,
int len = 0;
off_t begin = 0;
+ spin_lock(&capi_users_lock);
for (cp = capi_users; cp ; cp = cp->next) {
len += sprintf(page+len, "%s\n", cp->name);
if (len+begin > off+count)
@@ -346,6 +369,7 @@ static int proc_users_read_proc(char *page, char **start, off_t off,
}
}
endloop:
+ spin_unlock(&capi_users_lock);
if (cp == 0)
*eof = 1;
if (off >= len+begin)
@@ -510,6 +534,161 @@ static void proc_capi_exit(void)
}
}
+/* -------- Notifier handling --------------------------------- */
+
+static struct capi_notifier_list{
+ struct capi_notifier *head;
+ struct capi_notifier *tail;
+} notifier_list;
+
+static inline void notify_enqueue(struct capi_notifier *np)
+{
+ struct capi_notifier_list *q = &notifier_list;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (q->tail) {
+ q->tail->next = np;
+ q->tail = np;
+ } else {
+ q->head = q->tail = np;
+ }
+ restore_flags(flags);
+}
+
+static inline struct capi_notifier *notify_dequeue(void)
+{
+ struct capi_notifier_list *q = &notifier_list;
+ struct capi_notifier *np = 0;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (q->head) {
+ np = q->head;
+ if ((q->head = np->next) == 0)
+ q->tail = 0;
+ np->next = 0;
+ }
+ restore_flags(flags);
+ return np;
+}
+
+static int notify_push(unsigned int cmd, __u32 controller,
+ __u16 applid, __u32 ncci)
+{
+ struct capi_notifier *np;
+
+ np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
+ if (!np)
+ return -1;
+ memset(np, 0, sizeof(struct capi_notifier));
+ np->cmd = cmd;
+ np->controller = controller;
+ np->applid = applid;
+ np->ncci = ncci;
+ notify_enqueue(np);
+ MOD_INC_USE_COUNT;
+ queue_task(&tq_state_notify, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return 0;
+}
+
+/* -------- KCI_CONTRUP --------------------------------------- */
+
+static void notify_up(__u32 contr)
+{
+ struct capi_interface_user *p;
+
+ printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
+ }
+ spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_CONTRDOWN ------------------------------------- */
+
+static void notify_down(__u32 contr)
+{
+ struct capi_interface_user *p;
+ printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_CONTRDOWN, contr, 0);
+ }
+ spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_NCCIUP ---------------------------------------- */
+
+static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci)
+{
+ struct capi_interface_user *p;
+ struct capi_ncciinfo n;
+ n.applid = applid;
+ n.ncci = ncci;
+ /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_NCCIUP, contr, &n);
+ }
+ spin_unlock(&capi_users_lock);
+};
+
+/* -------- KCI_NCCIDOWN -------------------------------------- */
+
+static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci)
+{
+ struct capi_interface_user *p;
+ struct capi_ncciinfo n;
+ n.applid = applid;
+ n.ncci = ncci;
+ /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+ if (!p->callback) continue;
+ (*p->callback) (KCI_NCCIDOWN, contr, &n);
+ }
+ spin_unlock(&capi_users_lock);
+};
+
+/* ------------------------------------------------------------ */
+
+static void inline notify_doit(struct capi_notifier *np)
+{
+ switch (np->cmd) {
+ case KCI_CONTRUP:
+ notify_up(np->controller);
+ break;
+ case KCI_CONTRDOWN:
+ notify_down(np->controller);
+ break;
+ case KCI_NCCIUP:
+ notify_ncciup(np->controller, np->applid, np->ncci);
+ break;
+ case KCI_NCCIDOWN:
+ notify_nccidown(np->controller, np->applid, np->ncci);
+ break;
+ }
+}
+
+static void notify_handler(void *dummy)
+{
+ struct capi_notifier *np;
+
+ while ((np = notify_dequeue()) != 0) {
+ notify_doit(np);
+ kfree(np);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
/* -------- NCCI Handling ------------------------------------- */
static inline void mq_init(struct capi_ncci * np)
@@ -617,6 +796,7 @@ static void controllercb_new_ncci(struct capi_ctr * card,
APPL(appl)->nncci++;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
+ notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);
}
static void controllercb_free_ncci(struct capi_ctr * card,
@@ -634,6 +814,7 @@ static void controllercb_free_ncci(struct capi_ctr * card,
kfree(np);
APPL(appl)->nncci--;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
+ notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci);
return;
}
}
@@ -734,42 +915,6 @@ error:
kfree_skb(skb);
}
-/* -------- Notifier ------------------------------------------ */
-
-static void notify_up(__u32 contr)
-{
- struct capi_interface_user *p;
-
- printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
- for (p = capi_users; p; p = p->next) {
- if (!p->callback) continue;
- (*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
- }
-}
-
-static void notify_down(__u32 contr)
-{
- struct capi_interface_user *p;
- printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
- for (p = capi_users; p; p = p->next) {
- if (!p->callback) continue;
- (*p->callback) (KCI_CONTRDOWN, contr, 0);
- }
-}
-
-static void notify_handler(void *dummy)
-{
- __u32 contr;
-
- for (contr=1; VALID_CARD(contr); contr++)
- if (test_and_clear_bit(contr, &notify_up_set))
- notify_up(contr);
- for (contr=1; VALID_CARD(contr); contr++)
- if (test_and_clear_bit(contr, &notify_down_set))
- notify_down(contr);
-}
-
-
static void controllercb_ready(struct capi_ctr * card)
{
__u16 appl;
@@ -782,11 +927,10 @@ static void controllercb_ready(struct capi_ctr * card)
card->driver->register_appl(card, appl, &APPL(appl)->rparam);
}
- set_bit(CARDNR(card), &notify_up_set);
- queue_task(&tq_state_notify, &tq_scheduler);
-
printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
CARDNR(card), card->name);
+
+ notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);
}
static void controllercb_reseted(struct capi_ctr * card)
@@ -812,6 +956,7 @@ static void controllercb_reseted(struct capi_ctr * card)
struct capi_ncci *np = *pp;
*pp = np->next;
printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
+ notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci);
kfree(np);
nextpp = pp;
} else {
@@ -819,9 +964,10 @@ static void controllercb_reseted(struct capi_ctr * card)
}
}
}
- set_bit(CARDNR(card), &notify_down_set);
- queue_task(&tq_state_notify, &tq_scheduler);
+
printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card));
+
+ notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);
}
static void controllercb_suspend_output(struct capi_ctr *card)
@@ -952,9 +1098,12 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
{
struct capi_driver **pp;
+ MOD_INC_USE_COUNT;
+ spin_lock(&drivers_lock);
for (pp = &drivers; *pp; pp = &(*pp)->next) ;
driver->next = 0;
*pp = driver;
+ spin_unlock(&drivers_lock);
printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
sprintf(driver->procfn, "capi/drivers/%s", driver->name);
driver->procent = create_proc_entry(driver->procfn, 0, 0);
@@ -974,6 +1123,7 @@ struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver)
void detach_capi_driver(struct capi_driver *driver)
{
struct capi_driver **pp;
+ spin_lock(&drivers_lock);
for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
if (*pp) {
*pp = (*pp)->next;
@@ -981,10 +1131,12 @@ void detach_capi_driver(struct capi_driver *driver)
} else {
printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
}
+ spin_unlock(&drivers_lock);
if (driver->procent) {
remove_proc_entry(driver->procfn, 0);
driver->procent = 0;
}
+ MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
@@ -1041,6 +1193,7 @@ static __u16 capi_release(__u16 applid)
if (!VALID_APPLID(applid) || APPL(applid)->releasing)
return CAPI_ILLAPPNR;
+ APPL(applid)->releasing++;
while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
kfree_skb(skb);
for (i = 0; i < CAPI_MAXCONTR; i++) {
@@ -1049,6 +1202,7 @@ static __u16 capi_release(__u16 applid)
APPL(applid)->releasing++;
cards[i].driver->release_appl(&cards[i], applid);
}
+ APPL(applid)->releasing--;
if (APPL(applid)->releasing <= 0) {
APPL(applid)->signal = 0;
APPL_MARK_FREE(applid);
@@ -1128,8 +1282,8 @@ static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
}
static __u16 capi_set_signal(__u16 applid,
- void (*signal) (__u16 applid, __u32 param),
- __u32 param)
+ void (*signal) (__u16 applid, void *param),
+ void *param)
{
if (!VALID_APPLID(applid))
return CAPI_ILLAPPNR;
@@ -1194,10 +1348,12 @@ static __u16 capi_get_profile(__u32 contr, struct capi_profile *profp)
static struct capi_driver *find_driver(char *name)
{
struct capi_driver *dp;
+ spin_lock(&drivers_lock);
for (dp = drivers; dp; dp = dp->next)
if (strcmp(dp->name, name) == 0)
- return dp;
- return 0;
+ break;
+ spin_unlock(&drivers_lock);
+ return dp;
}
#ifdef CONFIG_AVMB1_COMPAT
@@ -1272,6 +1428,10 @@ static int old_capi_manufacturer(unsigned int cmd, void *data)
card = CARD(ldef.contr);
if (card->cardstate == CARD_FREE)
return -ESRCH;
+ if (card->driver->load_firmware == 0) {
+ printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
+ return -ESRCH;
+ }
if (ldef.t4file.len <= 0) {
printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
@@ -1490,16 +1650,20 @@ struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
{
struct capi_interface_user *p;
+ MOD_INC_USE_COUNT;
+ spin_lock(&capi_users_lock);
for (p = capi_users; p; p = p->next) {
if (p == userp) {
+ spin_unlock(&capi_users_lock);
printk(KERN_ERR "kcapi: double attach from %s\n",
userp->name);
+ MOD_DEC_USE_COUNT;
return 0;
}
}
userp->next = capi_users;
capi_users = userp;
- MOD_INC_USE_COUNT;
+ spin_unlock(&capi_users_lock);
printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
return &avmb1_interface;
@@ -1509,15 +1673,18 @@ int detach_capi_interface(struct capi_interface_user *userp)
{
struct capi_interface_user **pp;
+ spin_lock(&capi_users_lock);
for (pp = &capi_users; *pp; pp = &(*pp)->next) {
if (*pp == userp) {
*pp = userp->next;
+ spin_unlock(&capi_users_lock);
userp->next = 0;
- MOD_DEC_USE_COUNT;
printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
+ MOD_DEC_USE_COUNT;
return 0;
}
}
+ spin_unlock(&capi_users_lock);
printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
return -1;
}
@@ -1623,7 +1790,6 @@ void cleanup_module(void)
strcpy(rev, "1.0");
}
- schedule(); /* execute queued tasks .... */
proc_capi_exit();
printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
}
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 5dc6924e1..f8e7b418c 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -1,5 +1,5 @@
/*
- * $Id: divert_procfs.c,v 1.6 2000/02/14 19:23:03 werner Exp $
+ * $Id: divert_procfs.c,v 1.8 2000/03/03 16:37:11 kai Exp $
*
* Filesystem handling for the diversion supplementary services.
*
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: divert_procfs.c,v $
+ * Revision 1.8 2000/03/03 16:37:11 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.7 2000/03/02 00:11:06 werner
+ *
+ * Changes related to procfs for 2.3.48
+ *
* Revision 1.6 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
@@ -302,13 +310,13 @@ isdn_divert_lseek(struct file *file, loff_t offset, int orig)
static struct file_operations isdn_fops =
{
- llseek: isdn_divert_lseek,
- read: isdn_divert_read,
- write: isdn_divert_write,
- poll: isdn_divert_poll,
- ioctl: isdn_divert_ioctl,
- open: isdn_divert_open,
- release: isdn_divert_close,
+ llseek: isdn_divert_lseek,
+ read: isdn_divert_read,
+ write: isdn_divert_write,
+ poll: isdn_divert_poll,
+ ioctl: isdn_divert_ioctl,
+ open: isdn_divert_open,
+ release: isdn_divert_close,
};
/****************************/
@@ -336,7 +344,7 @@ divert_dev_init(void)
remove_proc_entry("isdn", proc_net);
return (-1);
}
- isdn_divert_entry->proc_fops = &isdn_fops;
+ isdn_divert_entry->proc_fops = &isdn_fops;
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index eb3590069..9cef520bc 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* IDI interface
@@ -26,6 +26,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.33 2000/03/06 15:45:17 armin
+ * Fixed incomplete number handling with BRI PtP connection.
+ *
+ * Revision 1.32 2000/03/04 17:04:21 armin
+ * Fix of statemachine, B-connect before D-connect,
+ * thanks to Helmut Adams <adams@ipcon.de>
+ * Minor change in send-data packet handling.
+ *
* Revision 1.31 2000/02/22 16:26:40 armin
* Fixed membase error message.
* Fixed missing log buffer struct.
@@ -156,7 +164,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.31 $";
+char *eicon_idi_revision = "$Revision: 1.33 $";
eicon_manifbuf *manbuf;
@@ -2515,15 +2523,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
break;
case 3: /* incomplete number */
eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
- switch(ccard->type) {
- case EICON_CTYPE_MAESTRAP:
- case EICON_CTYPE_S2M:
- /* TODO (other protocols) */
- chan->fsm_state = EICON_STATE_ICALLW;
- break;
- default:
- idi_do_req(ccard, chan, HANGUP, 0);
- }
+ chan->fsm_state = EICON_STATE_ICALLW;
break;
}
break;
@@ -2560,8 +2560,10 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
/* On most incoming calls we use automatic connect */
/* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
}
- } else
- idi_hangup(ccard, chan);
+ } else {
+ if (chan->fsm_state != EICON_STATE_ACTIVE)
+ idi_hangup(ccard, chan);
+ }
break;
case CALL_CON:
eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
@@ -3012,11 +3014,13 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
if (((len - offset) > 270) &&
+ (chan->l2prot != ISDN_PROTO_L2_MODEM) &&
+ (chan->l2prot != ISDN_PROTO_L2_FAX) &&
(chan->l2prot != ISDN_PROTO_L2_TRANS)) {
reqbuf->Req = IDI_N_MDATA;
} else {
reqbuf->Req = IDI_N_DATA;
- if (ack) reqbuf->Req |= N_D_BIT;
+ /* if (ack) reqbuf->Req |= N_D_BIT; */
}
reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 4a01218c3..7c5163f82 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $
+/* $Id: callc.c,v 2.41 2000/03/17 07:07:42 kai Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -11,6 +11,9 @@
* Fritz Elfert
*
* $Log: callc.c,v $
+ * Revision 2.41 2000/03/17 07:07:42 kai
+ * fixed oops when dialing out without l3 protocol selected
+ *
* Revision 2.40 1999/12/19 12:59:56 keil
* fix leased line handling
* and cosmetics
@@ -167,7 +170,7 @@
#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
#endif /* MODULE */
-const char *lli_revision = "$Revision: 2.40 $";
+const char *lli_revision = "$Revision: 2.41 $";
extern struct IsdnCard cards[];
extern int nrcards;
@@ -349,6 +352,8 @@ lli_deliver_cause(struct Channel *chanp)
{
isdn_ctrl ic;
+ if (!chanp->proc)
+ return;
if (chanp->proc->para.cause == NO_CAUSE)
return;
ic.driver = chanp->cs->myid;
@@ -641,7 +646,8 @@ lli_disconnect_req(struct FsmInst *fi, int event, void *arg)
lli_leased_hup(fi, chanp);
} else {
FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
+ if (chanp->proc)
+ chanp->proc->para.cause = 0x10; /* Normal Call Clearing */
chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
chanp->proc);
}
@@ -656,7 +662,8 @@ lli_disconnect_reject(struct FsmInst *fi, int event, void *arg)
lli_leased_hup(fi, chanp);
} else {
FsmChangeState(fi, ST_WAIT_DRELEASE);
- chanp->proc->para.cause = 0x15; /* Call Rejected */
+ if (chanp->proc)
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
chanp->proc);
}
@@ -688,7 +695,8 @@ lli_reject_req(struct FsmInst *fi, int event, void *arg)
return;
}
#ifndef ALERT_REJECT
- chanp->proc->para.cause = 0x15; /* Call Rejected */
+ if (chanp->proc)
+ chanp->proc->para.cause = 0x15; /* Call Rejected */
chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
lli_dhup_close(fi, event, arg);
#else
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 2b0451a0a..5c36458ff 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $
+/* $Id: l3dss1.c,v 2.24 2000/03/19 15:26:35 kai Exp $
* EURO/DSS1 D-channel protocol
*
@@ -13,6 +13,9 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
+ * Revision 2.24 2000/03/19 15:26:35 kai
+ * changed keypad to use specified bearer, instead of always a-law
+ *
* Revision 2.23 2000/02/26 01:38:14 keil
* Fixes for V.110 encoding LLC from Jens Jakobsen
*
@@ -107,7 +110,7 @@
#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.23 $";
+const char *dss1_revision = "$Revision: 2.24 $";
#define EXT_BEARER_CAPS 1
@@ -1313,39 +1316,31 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
- if (!send_keypad)
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
- else { *p++ = 0x4; /* assumptions for bearer services with keypad */
- *p++ = 0x3;
- *p++ = 0x80;
- *p++ = 0x90;
- *p++ = 0xa3;
- *p++ = 0x18; /* no specific channel */
- *p++ = 0x01;
- *p++ = 0x83;
- *p++ = 0x2C; /* IE keypad */
+ switch (pc->para.setup.si1) {
+ case 1: /* Telephony */
+ *p++ = IE_BEARER;
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = IE_BEARER;
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
+
+ if (send_keypad) {
+ *p++ = IE_KEYPAD;
*p++ = strlen(teln);
while (*teln)
- *p++ = (*teln++) & 0x7F;
- }
+ *p++ = (*teln++) & 0x7F;
+ }
-
/*
* What about info2? Mapping to High-Layer-Compatibility?
*/
@@ -1394,7 +1389,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
sp++;
}
if (*msn) {
- *p++ = 0x6c;
+ *p++ = IE_CALLING_PN;
*p++ = strlen(msn) + (screen ? 2 : 1);
/* Classify as AnyPref. */
if (screen) {
@@ -1407,7 +1402,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
}
if (sub) {
*sub++ = '.';
- *p++ = 0x6d; /* Calling party subaddress */
+ *p++ = IE_CALLING_SUB;
*p++ = strlen(sub) + 2;
*p++ = 0x80; /* NSAP coded */
*p++ = 0x50; /* local IDI format */
@@ -1425,33 +1420,27 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
}
if (!send_keypad) {
- *p++ = 0x70;
- *p++ = strlen(teln) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- if (sub) {
- *sub++ = '.';
- *p++ = 0x71; /* Called party subaddress */
- *p++ = strlen(sub) + 2;
- *p++ = 0x80; /* NSAP coded */
- *p++ = 0x50; /* local IDI format */
- while (*sub)
- *p++ = *sub++ & 0x7f;
- }
+ *p++ = IE_CALLED_PN;
+ *p++ = strlen(teln) + 1;
+ /* Classify as AnyPref. */
+ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+ while (*teln)
+ *p++ = *teln++ & 0x7f;
+
+ if (sub) {
+ *sub++ = '.';
+ *p++ = IE_CALLED_SUB;
+ *p++ = strlen(sub) + 2;
+ *p++ = 0x80; /* NSAP coded */
+ *p++ = 0x50; /* local IDI format */
+ while (*sub)
+ *p++ = *sub++ & 0x7f;
+ }
}
#if EXT_BEARER_CAPS
- if (send_keypad) { /* special handling independant of si2 */
- *p++ = 0x7c;
- *p++ = 0x03;
- *p++ = 0x80;
- *p++ = 0x90;
- *p++ = 0xa3;
- } else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
-
- *p++ = 0x7c;
+ if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
+
+ *p++ = IE_LLC;
*p++ = 0x04;
*p++ = 0x88;
*p++ = 0x90;
@@ -1459,7 +1448,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
} else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
- *p++ = 0x7c;
+ *p++ = IE_LLC;
*p++ = 0x05;
*p++ = 0x88;
*p++ = 0x90;
@@ -1468,7 +1457,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
*p++ = 0x82;
} else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
- *p++ = 0x7c;
+ *p++ = IE_LLC;
*p++ = 0x06;
*p++ = 0x88;
*p++ = 0x90;
@@ -1477,18 +1466,18 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
#ifndef CONFIG_HISAX_NO_LLC
} else {
switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = 0x7c; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
+ case 1: /* Telephony */
+ *p++ = IE_LLC;
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
default:
- *p++ = 0x7c; /* BC-IE-code */
- *p++ = 0x2; /* Length */
+ *p++ = IE_LLC;
+ *p++ = 0x2; /* Length */
*p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
*p++ = 0x90; /* Circuit-Mode 64kbps */
break;
diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc
index afb83e1c8..ec21e78c7 100644
--- a/drivers/isdn/hisax/md5sums.asc
+++ b/drivers/isdn/hisax/md5sums.asc
@@ -11,9 +11,9 @@ dd3955847bbf680b41233478fe521d88 isdnl1.c
bb51bd223040b511c18f091da5ab6456 isdnl2.c
b7aa7f97b2374967a4aca7c52991142c isdnl3.c
a23fbf8879c1432b04640b8b04bdf419 tei.c
-ce248e56c2e1326012d0b25f92bbf99b callc.c
+838791b14269ec94c74ba4ae89c022e6 callc.c
bf9605b36429898f7be6630034e83230 cert.c
-6ce0a184127be1a44747e2017ed24ad9 l3dss1.c
+a30e6253837739f6f54d9dadcd42d9f2 l3dss1.c
a3a570781f828b6d59e6b231653133de l3_1tr6.c
4aeba32c4c3480d2a6b9af34600b974f elsa.c
a296edc459b508bf0346c3132815a4db diva.c
@@ -23,9 +23,9 @@ a296edc459b508bf0346c3132815a4db diva.c
Version: 2.6.3i
Charset: noconv
-iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR
-HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd
-BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS
-ZMQ1pb9W6jE=
-=CA5N
+iQCVAwUBONlcejpxHvX/mS9tAQFWYAP/WmxgwQ7W6gVnsMkUlwzE1TKGWVJdGUTC
+7WrKEtdweuzW3/7WEzjBoZgUEcpugJYK3JENby1xjh3yIHfws4HqLme1yXAmkYUK
+6LmW96HC2g4wj7PH0hvLnzTOtXDGTppU7KJibbB+ziyhBbs6SGXOD4zHrCWmT9ld
+CURhfNgftIs=
+=AA+Q
-----END PGP SIGNATURE-----
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index d3c269a04..aa6776d3b 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $
+/* $Id: q931.c,v 1.8 2000/03/21 23:53:22 kai Exp $
* q931.c code to decode ITU Q.931 call control messages
*
@@ -14,6 +14,9 @@
*
*
* $Log: q931.c,v $
+ * Revision 1.8 2000/03/21 23:53:22 kai
+ * fix backwards compatibility
+ *
* Revision 1.7 1998/11/15 23:55:17 keil
* changes from 2.0
*
@@ -201,29 +204,6 @@ struct MessageType mt_n1[] =
#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
-static struct MessageType fac_1tr6[] =
-{
- {FAC_Sperre, "Sperre"},
- {FAC_Forward1, "Forward 1"},
- {FAC_Forward2, "Forward 2"},
- {FAC_Konferenz, "Konferenz"},
- {FAC_GrabBchan, "Grab Bchannel"},
- {FAC_Reactivate, "Reactivate"},
- {FAC_Konferenz3, "Dreier Konferenz"},
- {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
- {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
- {FAC_NummernIdent, "Rufnummer-Identifizierung"},
- {FAC_GBG, "GBG"},
- {FAC_DisplayUebergeben, "Display Uebergeben"},
- {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
- {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
- {FAC_Deactivate, "Deactivate"},
- {FAC_Activate, "Activate"},
- {FAC_SPV, "SPV"},
- {FAC_Rueckwechsel, "Rueckwechsel"},
- {FAC_Umleitung, "Umleitung"}
-};
-#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType))
static int
prbits(char *dest, u_char b, int start, int len)
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index c6fe2acdd..f9ce17675 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1,4 +1,4 @@
-/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $
+/* $Id: w6692.c,v 1.4 2000/03/16 23:24:11 werner Exp $
* w6692.c Winbond W6692 specific routines
*
@@ -8,6 +8,14 @@
* This file is (c) under GNU PUBLIC LICENSE
*
* $Log: w6692.c,v $
+ * Revision 1.4 2000/03/16 23:24:11 werner
+ *
+ * Fixed an additional location
+ *
+ * Revision 1.3 2000/03/16 22:41:36 werner
+ *
+ * Tried to fix second B-channel problem (still not tested)
+ *
* Revision 1.2 2000/02/26 00:35:13 keil
* Fix skb freeing in interrupt context
*
@@ -50,7 +58,7 @@ static const PCI_ENTRY id_list[] =
extern const char *CardType[];
-const char *w6692_revision = "$Revision: 1.2 $";
+const char *w6692_revision = "$Revision: 1.4 $";
#define DBUSY_TIMER_VALUE 80
@@ -317,10 +325,13 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
{
u_char val;
u_char r;
- struct BCState *bcs = cs->bcs + bchan;
+ struct BCState *bcs = cs->bcs;
struct sk_buff *skb;
int count;
+ if (bcs->channel != bchan)
+ bcs++; /* hardware bchan must match ! */
+
val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
@@ -724,7 +735,9 @@ static void
W6692Bmode(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
- int bchan = bcs->hw.w6692.bchan;
+ int bchan = bc;
+
+ bcs->hw.w6692.bchan = bc;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "w6692 %c mode %d ichan %d",
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 20d69e32f..ac67610f7 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_procconf.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+/* $Id: hysdn_procconf.c,v 1.4 2000/03/03 16:37:12 kai Exp $
* Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_procconf.c,v $
+ * Revision 1.4 2000/03/03 16:37:12 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.3 2000/03/02 00:11:07 werner
+ *
+ * Changes related to procfs for 2.3.48
+ *
* Revision 1.2 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
@@ -40,7 +48,7 @@
#include "hysdn_defs.h"
-static char *hysdn_procconf_revision = "$Revision: 1.2 $";
+static char *hysdn_procconf_revision = "$Revision: 1.4 $";
#define INFO_OUT_LEN 80 /* length of info line including lf */
@@ -403,11 +411,11 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
/******************************************************/
static struct file_operations conf_fops =
{
- llseek: hysdn_dummy_lseek,
- read: hysdn_conf_read,
- write: hysdn_conf_write,
- open: hysdn_conf_open,
- release: hysdn_conf_close,
+ llseek: hysdn_dummy_lseek,
+ read: hysdn_conf_read,
+ write: hysdn_conf_write,
+ open: hysdn_conf_open,
+ release: hysdn_conf_close,
};
/*****************************/
@@ -438,7 +446,6 @@ hysdn_procconf_init(void)
if ((card->procconf = (void *) create_proc_entry(conf_name,
S_IFREG | S_IRUGO | S_IWUSR,
hysdn_proc_entry)) != NULL) {
-
((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
hysdn_proclog_init(card); /* init the log file entry */
}
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 4a585053a..d93b59995 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_proclog.c,v 1.2 2000/02/14 19:23:03 werner Exp $
+/* $Id: hysdn_proclog.c,v 1.4 2000/03/03 16:37:12 kai Exp $
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -20,6 +20,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hysdn_proclog.c,v $
+ * Revision 1.4 2000/03/03 16:37:12 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.3 2000/03/02 00:11:07 werner
+ *
+ * Changes related to procfs for 2.3.48
+ *
* Revision 1.2 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
@@ -40,7 +48,7 @@
#include "hysdn_defs.h"
-static char *hysdn_proclog_revision = "$Revision: 1.2 $";
+static char *hysdn_proclog_revision = "$Revision: 1.4 $";
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
@@ -420,14 +428,15 @@ hysdn_log_poll(struct file *file, poll_table * wait)
/**************************************************/
static struct file_operations log_fops =
{
- llseek: hysdn_dummy_lseek,
- read: hysdn_log_read,
- write: hysdn_log_write,
- poll: hysdn_log_poll,
- open: hysdn_log_open,
- release: hysdn_log_close,
+ llseek: hysdn_dummy_lseek,
+ read: hysdn_log_read,
+ write: hysdn_log_write,
+ poll: hysdn_log_poll,
+ open: hysdn_log_open,
+ release: hysdn_log_close,
};
+
/***********************************************************************************/
/* hysdn_proclog_init is called when the module is loaded after creating the cards */
/* conf files. */
@@ -441,10 +450,9 @@ hysdn_proclog_init(hysdn_card * card)
if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
memset(pd, 0, sizeof(struct procdata));
-
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
- pd->log->proc_fops = &log_fops; /* set new operations table */
+ pd->log->proc_fops = &log_fops;
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c
index 3599d2ada..2be90eb6f 100644
--- a/drivers/isdn/isdn_audio.c
+++ b/drivers/isdn/isdn_audio.c
@@ -292,38 +292,25 @@ static char dtmf_matrix[4][4] =
{'*', '0', '#', 'D'}
};
-
-/*
- * egcs 2.95 complain about invalid asm statement:
- * "fixed or forbidden register 2 (cx) was spilled for class CREG."
- */
-#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__)
-#if __GNUC__ == 2 && __GNUC_MINOR__ < 95
-#define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
-#endif
-#endif
-
-#ifdef ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
static inline void
isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
{
- __asm__("cld\n"
+#ifdef __i386__
+ unsigned long d0, d1, d2, d3;
+ __asm__ __volatile__(
+ "cld\n"
"1:\tlodsb\n\t"
"xlatb\n\t"
"stosb\n\t"
"loop 1b\n\t"
- : : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
- : "bx", "cx", "di", "si", "ax");
-}
-
+ : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3)
+ : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff)
+ : "memory", "ax");
#else
-static inline void
-isdn_audio_tlookup(const char *table, char *buff, unsigned long n)
-{
while (n--)
*buff++ = table[*(unsigned char *)buff];
-}
#endif
+}
void
isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index b8e9efa0f..e9c3ce50b 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $
+/* $Id: isdn_common.c,v 1.100 2000/03/03 16:37:11 kai Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.100 2000/03/03 16:37:11 kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
* Revision 1.99 2000/02/26 01:00:52 keil
* changes from 2.3.47
*
@@ -449,7 +453,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.99 $";
+static char *isdn_revision = "$Revision: 1.100 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c
index ca05f8bf3..07722dbb1 100644
--- a/drivers/isdn/isdn_concap.c
+++ b/drivers/isdn/isdn_concap.c
@@ -1,10 +1,13 @@
-/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle Exp $
+/* $Id: isdn_concap.c,v 1.7 2000/03/21 23:53:22 kai Exp $
* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
* stuff goes here. Stuff that depends only on the concap protocol goes to
* another -- protocol specific -- source file.
*
* $Log: isdn_concap.c,v $
+ * Revision 1.7 2000/03/21 23:53:22 kai
+ * fix backwards compatibility
+ *
* Revision 1.6 1999/08/22 20:26:01 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -58,15 +61,20 @@
int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
{
- int tmp;
struct net_device *ndev = concap -> net_dev;
- isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
+ isdn_net_local *lp = isdn_net_get_locked_lp(nd);
IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
+ if (!lp) {
+ IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1);
+ return 1;
+ }
lp->huptimer = 0;
- tmp=isdn_net_send_skb(ndev, lp, skb);
- IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp);
- return tmp;
+ isdn_net_writebuf_skb(lp, skb);
+ spin_unlock_bh(&lp->xmit_lock);
+ IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0);
+ return 0;
}
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index ee3af91fa..8948e43f5 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $
+/* $Id: isdn_net.c,v 1.122 2000/03/20 22:37:46 detabc Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,50 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.122 2000/03/20 22:37:46 detabc
+ * modify abc-extension to work together with the new LL.
+ * remove abc frame-counter (is obsolete now).
+ * use the new lp->super_tx_queue for internal queueing (bsd-rawip-compress).
+ * modify isdn_net_xmit() and isdn_net_write_super().
+ * -- Kai, please have a look to this two function's. Thank's.
+ *
+ * Revision 1.121 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.120 2000/03/18 16:20:25 kai
+ * cosmetics / renaming
+ *
+ * Revision 1.118 2000/03/17 18:20:46 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.117 2000/03/17 17:01:00 kai
+ * cleanup
+ *
+ * Revision 1.116 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
+ * Revision 1.115 2000/03/17 12:49:42 kai
+ * calling statcallb with ISDN_STAT_BSENT in hard-IRQ context is now
+ * officially allowed. writebuf_skb() will never be called in hard-IRQ context
+ * anymore.
+ *
+ * Revision 1.114 2000/03/16 16:37:41 kai
+ * Allow phone numbers starting with "*" as outgoing numbers for
+ * networking interface. Some PBX's need this to allow dialing internal
+ * numbers (mine, for example ;-)
+ *
+ * Revision 1.113 2000/03/16 15:46:37 kai
+ * a little bugfix and cosmetic changes
+ *
+ * Revision 1.112 2000/03/04 16:20:42 detabc
+ * copy frames before rewriting frame's saddr
+ *
+ * Revision 1.111 2000/02/28 22:28:24 he
+ * moved tx_timeout warning messages in old (2.2.x) branch where it really only
+ * indicates problems.
+ *
* Revision 1.110 2000/02/26 01:00:53 keil
* changes from 2.3.47
*
@@ -487,19 +531,6 @@
* the network layer, and therefore, it only makes sense to call netif_*
* functions on them.
*
- * The old code abused the slaves dev->start to remember the corresponding
- * master's interface state (ifup'ed or not). This does not work with SOFTNET
- * any more, because there's now dev->start anymore.
- * Instead I chose to add isdn_net_started() which gives the state of the
- * master in case of slaves.
- * I'm still not sure if this is how it's supposed to be done this way
- * because it uses netif_running(dev) which might be
- * considered private to the network layer. However, it works for now.
- * Alternative: set a flag in _open() and clear it in _close()
- *
- * I left some dead code around in #if 0 which I'm not absolutely sure about.
- * If no problems turn up, it should be removed later
- *
* --KG
*/
@@ -507,7 +538,7 @@
* Find out if the netdevice has been ifup-ed yet.
* For slaves, look at the corresponding master.
*/
-static int __inline__ isdn_net_started(isdn_net_dev *n)
+static __inline__ int isdn_net_device_started(isdn_net_dev *n)
{
isdn_net_local *lp = n->local;
struct net_device *dev;
@@ -523,7 +554,7 @@ static int __inline__ isdn_net_started(isdn_net_dev *n)
* wake up the network -> net_device queue.
* For slaves, wake the corresponding master interface.
*/
-static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
{
if (lp->master)
netif_wake_queue(lp->master);
@@ -531,6 +562,75 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
netif_wake_queue(&lp->netdev->dev);
}
+/*
+ * stop the network -> net_device queue.
+ * For slaves, stop the corresponding master interface.
+ */
+static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
+{
+ if (lp->master)
+ netif_stop_queue(lp->master);
+ else
+ netif_stop_queue(&lp->netdev->dev);
+}
+
+/*
+ * find out if the net_device which this lp belongs to (lp can be
+ * master or slave) is busy. It's busy iff all (master and slave)
+ * queues are busy
+ */
+static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
+{
+ isdn_net_local *nlp;
+ isdn_net_dev *nd;
+ unsigned long flags;
+
+ if (!isdn_net_lp_busy(lp))
+ return 0;
+
+ if (lp->master)
+ nd = ((isdn_net_local *) lp->master->priv)->netdev;
+ else
+ nd = lp->netdev;
+
+ spin_lock_irqsave(&nd->queue_lock, flags);
+ nlp = lp->next;
+ while (nlp != lp) {
+ if (!isdn_net_lp_busy(nlp)) {
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ return 0;
+ }
+ nlp = nlp->next;
+ }
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ return 1;
+}
+
+static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
+{
+ atomic_inc(&lp->frame_cnt);
+ if (isdn_net_device_busy(lp))
+ isdn_net_device_stop_queue(lp);
+}
+
+static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
+{
+ atomic_dec(&lp->frame_cnt);
+
+ if (!(isdn_net_device_busy(lp))) {
+ if (!skb_queue_empty(&lp->super_tx_queue)) {
+ queue_task(&lp->tqueue, &tq_immediate);
+ } else {
+ isdn_net_device_wake_queue(lp);
+ }
+ }
+}
+
+static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
+{
+ atomic_set(&lp->frame_cnt, 0);
+}
+
/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
* to be safe.
* For 2.3.x we push it up to 20 secs, because call establishment
@@ -546,9 +646,8 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
-static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.110 $";
+char *isdn_net_revision = "$Revision: 1.122 $";
/*
* Code for raw-networking over ISDN
@@ -660,16 +759,12 @@ static void
isdn_net_unbind_channel(isdn_net_local * lp)
{
ulong flags;
+ struct sk_buff *skb;
save_flags(flags);
cli();
- if (lp->first_skb) {
- dev_kfree_skb(lp->first_skb);
- lp->first_skb = NULL;
- }
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- lp->sav_skb = NULL;
+ while ((skb = skb_dequeue(&lp->super_tx_queue))) {
+ kfree_skb(skb);
}
if (!lp->master) { /* reset only master device */
/* Moral equivalent of dev_purge_queues():
@@ -766,6 +861,11 @@ isdn_net_autohup()
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
}
+static void isdn_net_lp_disconnected(isdn_net_local *lp)
+{
+ isdn_net_rm_from_bundle(lp);
+}
+
/*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
@@ -789,28 +889,9 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
/* A packet has successfully been sent out */
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
+ isdn_net_dec_frame_cnt(lp);
lp->stats.tx_packets++;
lp->stats.tx_bytes += c->parm.length;
- /* some HL drivers deliver
- ISDN_STAT_BSENT from hw interrupt.
- Output routines in isdn_ppp are now
- called with irq disabled such that
- dequeueing the sav_skb while another
- frame is sent will not occur.
- */
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
- struct net_device *mdev;
- if (lp->master)
- mdev = lp->master;
- else
- mdev = &lp->netdev->dev;
- if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
- lp->sav_skb = NULL;
- } else {
- return 1;
- }
- }
- isdn_net_lp_xon(lp);
}
return 1;
case ISDN_STAT_DCONN:
@@ -842,6 +923,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
#endif
+ isdn_net_lp_disconnected(lp);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
@@ -864,6 +946,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
#endif /* CONFIG_ISDN_X25 */
case ISDN_STAT_BCONN:
/* B-Channel is up */
+ isdn_net_zero_frame_cnt(lp);
switch (lp->dialstate) {
case 5:
case 6:
@@ -881,13 +964,17 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1);
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
+ if (lp->master) { /* is lp a slave? */
+ isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
+ isdn_net_add_to_bundle(nd, lp);
+ }
+ }
printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
*/
lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n",
- lp->name, lp->chargetime);
/* reset dial-timeout */
lp->dialstarted = 0;
@@ -903,13 +990,9 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
if( pops->connect_ind)
pops->connect_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
- /* Immediately send first skb to speed up arp */
- if (lp->first_skb) {
-
- if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
- lp->first_skb = NULL;
- }
- if(! lp->first_skb) isdn_net_lp_xon(lp);
+ /* ppp needs to do negotiations first */
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
+ isdn_net_device_wake_queue(lp);
return 1;
}
break;
@@ -942,20 +1025,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
}
/*
- * Check, if a number contains wildcard-characters, in which case it
- * is for incoming purposes only.
- */
-static int
-isdn_net_checkwild(char *num)
-{
- return ((strchr(num, '?')) ||
- (strchr(num, '*')) ||
- (strchr(num, '[')) ||
- (strchr(num, ']')) ||
- (strchr(num, '^')));
-}
-
-/*
* Perform dialout for net-interfaces and timeout-handling for
* D-Channel-up and B-Channel-up Messages.
* This function is initially called from within isdn_net_start_xmit() or
@@ -1033,7 +1102,7 @@ isdn_net_dial(void)
s = "dial suppressed: isdn system stopped";
else
s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(&p->dev, lp->first_skb, s);
+ isdn_net_unreachable(&p->dev, 0, s);
isdn_net_hangup(&p->dev);
break;
}
@@ -1066,7 +1135,7 @@ isdn_net_dial(void)
restore_flags(flags);
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out");
+ isdn_net_unreachable(&p->dev, 0, "dial: timed out");
isdn_net_hangup(&p->dev);
break;
}
@@ -1084,7 +1153,7 @@ isdn_net_dial(void)
if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times");
+ isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times");
}
isdn_net_hangup(&p->dev);
break;
@@ -1248,6 +1317,7 @@ isdn_net_hangup(struct net_device *d)
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
#endif
+ isdn_net_lp_disconnected(lp);
#ifdef CONFIG_ISDN_X25
/* try if there are generic encap protocol
receiver routines and signal the closure of
@@ -1360,31 +1430,83 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
}
/*
- * Generic routine to send out an skbuf.
- * If lowlevel-device does not support support skbufs, use
- * standard send-routine, else send directly.
- *
- * Return: 0 on success, !0 on failure.
+ * this function is used to send supervisory data, i.e. data which was
+ * not received from the network layer, but e.g. frames from ipppd, CCP
+ * reset frames etc.
*/
-int isdn_net_send_skb
- (struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb)
+void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
+{
+ if (in_interrupt()) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ return;
+ }
+
+ spin_lock_bh(&lp->xmit_lock);
+ if (!isdn_net_lp_busy(lp)) {
+ isdn_net_writebuf_skb(lp, skb);
+ } else {
+ skb_queue_tail(&lp->super_tx_queue, skb);
+ }
+ spin_unlock_bh(&lp->xmit_lock);
+}
+
+/*
+ * called from tq_immediate
+ */
+static void
+isdn_net_softint(void *private)
+{
+ isdn_net_local *lp = private;
+ struct sk_buff *skb;
+
+ spin_lock_bh(&lp->xmit_lock);
+ while (!isdn_net_lp_busy(lp)) {
+ skb = skb_dequeue(&lp->super_tx_queue);
+ if (!skb)
+ break;
+ isdn_net_writebuf_skb(lp, skb);
+ }
+ spin_unlock_bh(&lp->xmit_lock);
+}
+
+/*
+ * all frames sent from the (net) LL to a HL driver should go via this function
+ * it's serialized by the caller holding the lp->xmit_lock spinlock
+ */
+void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
{
int ret;
int len = skb->len; /* save len */
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
- if (ret == len) {
- lp->transcount += len;
- return 0;
+ /* before obtaining the lock the caller should have checked that
+ the lp isn't busy */
+ if (isdn_net_lp_busy(lp)) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ goto error;
}
- if (ret < 0) {
- dev_kfree_skb(skb);
- lp->stats.tx_errors++;
- return 0;
+
+ if (!(lp->flags & ISDN_NET_CONNECTED)) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ goto error;
}
- return 1;
+ ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
+ if (ret != len) {
+ /* we should never get here */
+ printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+ goto error;
+ }
+
+ lp->transcount += len;
+ isdn_net_inc_frame_cnt(lp);
+ return;
+
+ error:
+ dev_kfree_skb(skb);
+ lp->stats.tx_errors++;
+
}
+
/*
* Helper function for isdn_net_start_xmit.
* When called, the connection is already established.
@@ -1397,9 +1519,18 @@ int isdn_net_send_skb
*/
static int
-isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
+isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
{
- int ret;
+ isdn_net_dev *nd;
+ isdn_net_local *slp;
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ int retv = 0;
+
+ if (((isdn_net_local *) (ndev->priv))->master) {
+ printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+ dev_kfree_skb(skb);
+ return 0;
+ }
/* For the other encaps the header has already been built */
#ifdef CONFIG_ISDN_PPP
@@ -1407,31 +1538,27 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
return isdn_ppp_xmit(skb, ndev);
}
#endif
+
+ nd = ((isdn_net_local *) ndev->priv)->netdev;
+
+ lp = isdn_net_get_locked_lp(nd);
+ if (!lp) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name);
+ return 1;
+ }
+ /* we have our lp locked from now on */
+
/* Reset hangup-timeout */
- lp->huptimer = 0;
+ lp->huptimer = 0; // FIXME?
+ isdn_net_writebuf_skb(lp, skb);
+ spin_unlock_bh(&lp->xmit_lock);
+
+ /* the following stuff is here for backwards compatibility.
+ * in future, start-up and hangup of slaves (based on current load)
+ * should move to userspace and get based on an overall cps
+ * calculation
+ */
if (lp->cps > lp->triggercps) {
- /* Device overloaded */
-
- /*
- * Packet-delivery via round-robin over master
- * and all connected slaves.
- */
- if (lp->master)
- /* Slaves always deliver themselves */
- ret = isdn_net_send_skb(ndev, lp, skb);
- else {
- isdn_net_local *slp = (isdn_net_local *) (lp->srobin->priv);
- /* Master delivers via srobin and maintains srobin */
- if (lp->srobin == ndev)
- ret = isdn_net_send_skb(ndev, lp, skb);
- else
- ret = isdn_net_start_xmit(skb, lp->srobin);
- lp->srobin = (slp->slave) ? slp->slave : ndev;
- slp = (isdn_net_local *) (lp->srobin->priv);
- if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
- lp->srobin = ndev;
- }
- /* Slave-startup using delay-variable */
if (lp->slave) {
if (!lp->sqfull) {
/* First time overload: set timestamp only */
@@ -1439,17 +1566,24 @@ isdn_net_xmit(struct net_device *ndev, isdn_net_local * lp, struct sk_buff *skb)
lp->sqfull_stamp = jiffies;
} else {
/* subsequent overload: if slavedelay exceeded, start dialing */
- if ((jiffies - lp->sqfull_stamp) > lp->slavedelay)
- isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+ if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) {
+ slp = lp->slave->priv;
+ if (!(slp->flags & ISDN_NET_CONNECTED)) {
+ isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+ }
+ }
}
}
} else {
- /* Not overloaded, deliver locally */
- ret = isdn_net_send_skb(ndev, lp, skb);
- if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ))))
+ if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) {
lp->sqfull = 0;
+ }
+ /* this is a hack to allow auto-hangup for slaves on moderate loads */
+ nd->queue = nd->local;
}
- return ret;
+
+ return retv;
+
}
static void
@@ -1489,7 +1623,7 @@ void isdn_net_tx_timeout(struct net_device * ndev)
* actually, this may not matter at all, because ISDN hardware
* should not see transmitter hangs at all IMO
* changed KERN_DEBUG to KERN_WARNING to find out if this is
- * ever called
+ * ever called --KG
*/
}
ndev->trans_start = jiffies;
@@ -1608,19 +1742,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return 1; /* let upper layer requeue skb packet */
}
#endif
- /* remember first skb to speed up arp
- * when using encap ETHER
- */
- if (lp->first_skb) {
- printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
- dev_kfree_skb(lp->first_skb);
- lp->first_skb = NULL;
- }
- lp->first_skb = skb;
/* Initiate dialing */
restore_flags(flags);
isdn_net_dial();
- return 0;
+ isdn_net_device_stop_queue(lp);
+ return 1;
} else {
isdn_net_unreachable(ndev, skb,
"No phone number");
@@ -1633,14 +1759,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (!lp->dialstate) {
/* ISDN connection is established, try sending */
int ret;
- if (lp->first_skb) {
- if (isdn_net_xmit(ndev, lp, lp->first_skb)){
- netif_stop_queue(ndev);
- return 1;
-}
- lp->first_skb = NULL;
- }
- ret = (isdn_net_xmit(ndev, lp, skb));
+ ret = (isdn_net_xmit(ndev, skb));
if(ret) netif_stop_queue(ndev);
return ret;
} else
@@ -1754,7 +1873,6 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC);
unsigned long t = (jiffies / HZ * 1000000);
- int len;
cisco_hdr *ch;
cisco_slarp *s;
@@ -1782,9 +1900,7 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
s->rel = 0xffff;
s->t1 = t >> 16;
s->t0 = t & 0xffff;
- len = skb->len;
- if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len)
- dev_kfree_skb(skb);
+ isdn_net_write_super(lp, skb);
}
static void
@@ -2417,7 +2533,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
* Is the interface up?
* If not, reject the call actively.
*/
- if (!isdn_net_started(p)) {
+ if (!isdn_net_device_started(p)) {
restore_flags(flags);
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
lp->name);
@@ -2508,6 +2624,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
+ isdn_net_lp_disconnected(lp);
isdn_free_channel(lp->isdn_device, lp->isdn_channel,
ISDN_USAGE_NET);
}
@@ -2707,10 +2824,17 @@ isdn_net_new(char *name, struct net_device *master)
netdev->ib.last = NULL;
#endif
netdev->queue = netdev->local;
+ spin_lock_init(&netdev->queue_lock);
+
netdev->local->last = netdev->local;
netdev->local->netdev = netdev;
netdev->local->next = netdev->local;
+ memset(&netdev->local->tqueue, 0, sizeof(struct tq_struct));
+ netdev->local->tqueue.routine = isdn_net_softint;
+ netdev->local->tqueue.data = netdev->local;
+ spin_lock_init(&netdev->local->xmit_lock);
+
netdev->local->isdn_device = -1;
netdev->local->isdn_channel = -1;
netdev->local->pre_device = -1;
@@ -2718,13 +2842,11 @@ isdn_net_new(char *name, struct net_device *master)
netdev->local->exclusive = -1;
netdev->local->ppp_slot = -1;
netdev->local->pppbind = -1;
- netdev->local->sav_skb = NULL;
- netdev->local->first_skb = NULL;
+ skb_queue_head_init(&netdev->local->super_tx_queue);
netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
netdev->local->triggercps = 6000;
netdev->local->slavedelay = 10 * HZ;
- netdev->local->srobin = &netdev->dev;
netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
netdev->local->onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
@@ -2762,7 +2884,7 @@ isdn_net_newslave(char *parm)
if (n->local->master)
return NULL;
/* Master must not be started yet */
- if (isdn_net_started(n))
+ if (isdn_net_device_started(n))
return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
@@ -2805,7 +2927,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = p -> cprot;
#endif
- if (isdn_net_started(p)) {
+ if (isdn_net_device_started(p)) {
printk(KERN_WARNING "%s: cannot change encap when if is up\n",
lp->name);
return -EBUSY;
@@ -3066,8 +3188,6 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
isdn_net_dev *p = isdn_net_findif(phone->name);
isdn_net_phone *n;
- if (isdn_net_checkwild(phone->phone) && (phone->outgoing & 1))
- return -EINVAL;
if (p) {
if (!(n = (isdn_net_phone *) kmalloc(sizeof(isdn_net_phone), GFP_KERNEL)))
return -ENOMEM;
@@ -3240,7 +3360,7 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
save_flags(flags);
cli();
- if (isdn_net_started(p)) {
+ if (isdn_net_device_started(p)) {
restore_flags(flags);
return -EBUSY;
}
diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h
index bd48c592c..5012ea772 100644
--- a/drivers/isdn/isdn_net.h
+++ b/drivers/isdn/isdn_net.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $
+/* $Id: isdn_net.h,v 1.16 2000/03/21 23:53:22 kai Exp $
* header for Linux ISDN subsystem, network related functions (linklevel).
*
@@ -21,6 +21,26 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.h,v $
+ * Revision 1.16 2000/03/21 23:53:22 kai
+ * fix backwards compatibility
+ *
+ * Revision 1.15 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.14 2000/03/18 16:20:25 kai
+ * cosmetics / renaming
+ *
+ * Revision 1.13 2000/03/17 18:20:46 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.12 2000/03/17 17:01:00 kai
+ * cleanup
+ *
+ * Revision 1.11 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
* Revision 1.10 1999/08/22 20:26:06 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
@@ -124,8 +144,88 @@ extern void isdn_net_autohup(void);
extern int isdn_net_force_hangup(char *);
extern int isdn_net_force_dial(char *);
extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_send_skb(struct net_device *, isdn_net_local *,
- struct sk_buff *);
extern int isdn_net_rcv_skb(int, struct sk_buff *);
extern void isdn_net_slarp_out(void);
extern int isdn_net_dial_req(isdn_net_local *);
+extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
+extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
+
+#define ISDN_NET_MAX_QUEUE_LENGTH 2
+
+/*
+ * is this particular channel busy?
+ */
+static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
+{
+ if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * For the given net device, this will get a non-busy channel out of the
+ * corresponding bundle. The returned channel is locked.
+ */
+static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
+{
+ unsigned long flags;
+ isdn_net_local *lp;
+
+ spin_lock_irqsave(&nd->queue_lock, flags);
+ lp = nd->queue; /* get lp on top of queue */
+ spin_lock_bh(&nd->queue->xmit_lock);
+ while (isdn_net_lp_busy(nd->queue)) {
+ spin_unlock_bh(&nd->queue->xmit_lock);
+ nd->queue = nd->queue->next;
+ if (nd->queue == lp) /* not found -- should never happen */
+ return 0;
+ spin_lock_bh(&nd->queue->xmit_lock);
+ }
+ lp = nd->queue;
+
+ nd->queue = nd->queue->next;
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+ return lp;
+}
+
+/*
+ * add a channel to a bundle
+ */
+static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
+{
+ isdn_net_local *lp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nd->queue_lock, flags);
+
+ lp = nd->queue;
+ nlp->last = lp->last;
+ lp->last->next = nlp;
+ lp->last = nlp;
+ nlp->next = lp;
+ nd->queue = nlp;
+
+ spin_unlock_irqrestore(&nd->queue_lock, flags);
+}
+/*
+ * remove a channel from the bundle it belongs to
+ */
+static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
+{
+ isdn_net_local *master_lp = lp;
+ unsigned long flags;
+
+ if (lp->master)
+ master_lp = (isdn_net_local *) lp->master->priv;
+
+ spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
+ lp->last->next = lp->next;
+ lp->next->last = lp->last;
+ if (master_lp->netdev->queue == lp)
+ master_lp->netdev->queue = lp->next;
+ lp->next = lp->last = lp; /* (re)set own pointers */
+ spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+}
+
+
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 2551dc344..8a3ccce5f 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.62 2000/02/12 19:26:55 kai Exp $
+/* $Id: isdn_ppp.c,v 1.69 2000/03/19 15:27:53 kai Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -19,6 +19,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.69 2000/03/19 15:27:53 kai
+ * no known bugs left...
+ *
+ * Revision 1.67 2000/03/17 18:20:46 kai
+ * moved to frame_cnt based flow control
+ * some races still need to be fixed
+ *
+ * Revision 1.66 2000/03/17 17:01:00 kai
+ * cleanup
+ *
+ * Revision 1.65 2000/03/17 16:22:55 kai
+ * we keep track of outstanding packets (given to HL, but not confirmed yet)
+ * now, but we don't use it for flow control yet.
+ *
+ * Revision 1.64 2000/03/17 10:43:56 kai
+ * 2.3.99 contains MPPP constants which cause a warning because we
+ * redefine them in include/linux/isdn_ppp.h
+ *
+ * So from now on we use the generic PPP constants, change is backwards
+ * compatible, though
+ *
+ * Revision 1.63 2000/03/16 15:46:37 kai
+ * a little bugfix and cosmetic changes
+ *
* Revision 1.62 2000/02/12 19:26:55 kai
* adopted to latest 2.3 softnet changes.
*
@@ -263,10 +287,6 @@
*
*/
-/* TODO: right tbusy handling when using MP */
-
-#define CONFIG_ISDN_CCP 1
-
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -331,7 +351,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.62 $";
+char *isdn_ppp_revision = "$Revision: 1.69 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
@@ -366,36 +386,28 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
int
isdn_ppp_free(isdn_net_local * lp)
{
-#ifdef CONFIG_ISDN_MPP
isdn_net_local *master_lp = lp;
-#endif
unsigned long flags;
struct ippp_struct *is;
if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
return 0;
- is = ippp_table[lp->ppp_slot];
-
save_flags(flags);
cli();
+
#ifdef CONFIG_ISDN_MPP
- if (lp->master)
- master_lp = (isdn_net_local *) lp->master->priv;
-
- lp->last->next = lp->next;
- lp->next->last = lp->last;
- if (master_lp->netdev->queue == lp) {
- master_lp->netdev->queue = lp->next;
- if (lp->next == lp) { /* last link in queue? */
- master_lp->netdev->ib.bundled = 0;
- isdn_ppp_free_mpqueue(master_lp->netdev);
- isdn_ppp_free_sqqueue(master_lp->netdev);
- }
+ if (lp->next == lp) { /* last link in queue? */
+ master_lp->netdev->ib.bundled = 0;
+ isdn_ppp_free_mpqueue(master_lp->netdev);
+ isdn_ppp_free_sqqueue(master_lp->netdev);
}
- lp->next = lp->last = lp; /* (re)set own pointers */
#endif
+ isdn_net_rm_from_bundle(lp);
+
+ is = ippp_table[lp->ppp_slot];
+
if ((is->state & IPPP_CONNECT))
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
else if (is->state & IPPP_ASSIGNED)
@@ -406,6 +418,7 @@ isdn_ppp_free(isdn_net_local * lp)
is->lp = NULL; /* link is down .. set lp to NULL */
lp->ppp_slot = -1; /* is this OK ?? */
+
restore_flags(flags);
return 0;
@@ -422,9 +435,6 @@ isdn_ppp_bind(isdn_net_local * lp)
long flags;
struct ippp_struct *is;
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- return -1;
-
save_flags(flags);
cli();
@@ -1030,8 +1040,6 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
unsigned short hl;
- unsigned long flags;
- int cnt;
struct sk_buff *skb;
/*
* we need to reserve enought space in front of
@@ -1054,17 +1062,7 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
- save_flags(flags);
- cli();
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
- } else
- printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count);
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+ isdn_net_write_super(lp, skb);
}
}
return count;
@@ -1162,7 +1160,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
int sqno_end;
if(is->compflags & SC_LINK_DECOMP_ON) {
- if(proto == PPP_LINK_COMP) {
+ if(proto == PPP_COMPFRAG) {
if(is->debug & 0x10)
printk(KERN_DEBUG "received single link compressed frame\n");
skb = isdn_ppp_decompress(skb,is,NULL,proto);
@@ -1425,7 +1423,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
#endif
break;
case PPP_CCP:
- case PPP_LINK_CCP:
+ case PPP_CCPFRAG:
isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
@@ -1484,19 +1482,13 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
int
isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
{
- struct net_device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */
isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- unsigned long flags;
- if (mdev)
- mlp = (isdn_net_local *) (mdev->priv);
- else {
- mdev = netdev;
- mlp = (isdn_net_local *) (netdev->priv);
- }
+ mlp = (isdn_net_local *) (netdev->priv);
+
nd = mlp->netdev; /* get master lp */
ipts = ippp_table[mlp->ppp_slot];
@@ -1515,21 +1507,18 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
break;
default:
dev_kfree_skb(skb);
- printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol);
+ printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
+ skb->protocol);
return 0;
}
- lp = nd->queue; /* get lp on top of queue */
-
- if (lp->sav_skb) { /* find a non-busy device */
- isdn_net_local *nlp = lp->next;
- while (lp->sav_skb) {
- if (lp == nlp)
- return 1;
- nlp = nd->queue = nd->queue->next;
- }
- lp = nlp;
+ lp = isdn_net_get_locked_lp(nd);
+ if (!lp) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", lp->name);
+ return 1;
}
+ /* we have our lp locked from now on */
+
ipt = ippp_table[lp->ppp_slot];
lp->huptimer = 0;
@@ -1538,8 +1527,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
*/
/* Pull off the fake header we stuck on earlier to keep
- * the fragemntation code happy.
- */
+ * the fragmentation code happy.
+ */
skb_pull(skb,IPPP_MAX_HEADER);
if (ipt->debug & 0x4)
@@ -1612,11 +1601,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
/* we get mp_seqno from static isdn_net_local */
long mp_seqno = ipts->mp_seqno;
ipts->mp_seqno++;
- nd->queue = nd->queue->next;
if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
unsigned char *data = isdn_ppp_skb_push(&skb, 3);
if(!data)
- return 0;
+ goto unlock;
mp_seqno &= 0xfff;
data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
data[1] = mp_seqno & 0xff;
@@ -1624,7 +1612,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
} else {
unsigned char *data = isdn_ppp_skb_push(&skb, 5);
if(!data)
- return 0;
+ goto unlock;
data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
data[2] = (mp_seqno >> 8) & 0xff;
@@ -1644,20 +1632,20 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
unsigned char *data = isdn_ppp_skb_push(&skb,1);
if(!data)
- return 0;
+ goto unlock;
data[0] = proto & 0xff;
}
else {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
- return 0;
+ goto unlock;
data[0] = (proto >> 8) & 0xff;
data[1] = proto & 0xff;
}
if(!(ipt->pppcfg & SC_COMP_AC)) {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
- return 0;
+ goto unlock;
data[0] = 0xff; /* All Stations */
data[1] = 0x03; /* Unnumbered information */
}
@@ -1668,16 +1656,11 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
}
- save_flags(flags);
- cli();
- if (isdn_net_send_skb(netdev, lp, skb)) {
- if (lp->sav_skb) { /* should never happen as sav_skb are sent with disabled IRQs) */
- printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name);
- dev_kfree_skb(skb);
- } else
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+
+ isdn_net_writebuf_skb(lp, skb);
+
+ unlock:
+ spin_unlock_bh(&lp->xmit_lock);
return 0;
}
@@ -1731,28 +1714,21 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
char ifn[IFNAMSIZ + 1];
long flags;
isdn_net_dev *p;
- isdn_net_local *lp,
- *nlp;
+ isdn_net_local *lp, *nlp;
sprintf(ifn, "ippp%d", unit);
p = isdn_net_findif(ifn);
if (!p)
return -1;
- isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */
-
save_flags(flags);
cli();
+ isdn_timer_ctrl(ISDN_TIMER_IPPP, 1); /* enable timer for ippp/MP */
nlp = is->lp;
-
lp = p->queue;
+ isdn_net_add_to_bundle(p, nlp);
p->ib.bundled = 1;
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- p->queue = nlp;
ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
/* maybe also SC_CCP stuff */
@@ -1761,7 +1737,6 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
-
restore_flags(flags);
return 0;
}
@@ -1949,12 +1924,14 @@ isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
#ifdef CONFIG_ISDN_PPP_VJ
int toss = 0;
#endif
-/* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
- eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
- wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
- bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
- groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
- ja ein Paket mit B und eins mit E dazwischenpassen */
+ /* currently we just discard ancient packets.
+ To do:
+ Maybe, as long as there's no B-packet in front and sqno <= min_sqno: discard.
+ If sqno < min_sqno and there are gaps: discard (the gaps won't be filled anyway).
+ Packets with sqno > min_sqno: Larger than mp_mrru: If sum of all pktlen of pending
+ packets large than mrru: discard - packets need to be consecutive, though, if not
+ there could be an B and an E-packet in between.
+ */
struct mpqueue *ql,
*q = dev->mp_last;
@@ -2249,8 +2226,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
{
struct sk_buff *skb;
unsigned char *p;
- int count, hl;
- unsigned long flags;
+ int hl;
int cnt = 0;
isdn_net_local *lp = is->lp;
@@ -2291,26 +2267,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
printk(KERN_DEBUG "Sending CCP Frame:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
- /* Just ripped from isdn_ppp_write. Dunno whether it makes sense,
- especially dunno what the sav_skb stuff is good for. */
-
- count = skb->len;
- save_flags(flags);
- cli();
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel,
- 1, skb)) != count) {
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- printk(KERN_INFO
- "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",
- cnt, count);
- } else
- printk(KERN_INFO
- "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",
- cnt, count);
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+ isdn_net_write_super(lp, skb);
}
/* Allocate the reset state vector */
@@ -2560,14 +2517,6 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
int proto)
{
-#ifndef CONFIG_ISDN_CCP
- if(proto == PPP_COMP || proto == PPP_LINK_COMP) {
- printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- return skb;
-#else
void *stat = NULL;
struct isdn_ppp_compressor *ipc = NULL;
struct sk_buff *skb_out;
@@ -2617,7 +2566,7 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
printk(KERN_DEBUG "ippp: Decompress valid!\n");
*/
- if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) {
+ if((master && proto == PPP_COMP) || (!master && proto == PPP_COMPFRAG) ) {
/* Set up reset params for the decompressor */
memset(&rsparm, 0, sizeof(rsparm));
rsparm.data = rsdata;
@@ -2657,7 +2606,6 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
ipc->incomp(stat,skb,proto);
return skb;
}
-#endif
}
/*
@@ -2676,13 +2624,9 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
void *stat;
struct sk_buff *skb_out;
-#ifdef CONFIG_ISDN_CCP
/* we do not compress control protocols */
if(*proto < 0 || *proto > 0x3fff) {
-#else
- {
-#endif
- return skb_in;
+ return skb_in;
}
if(type) { /* type=1 => Link compression */
@@ -2883,7 +2827,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
}
proto = ((int)data[0]<<8)+data[1];
- if(proto != PPP_CCP && proto != PPP_LINK_CCP)
+ if(proto != PPP_CCP && proto != PPP_CCPFRAG)
return;
printk(KERN_DEBUG "Received CCP frame from daemon:\n");
diff --git a/drivers/isdn/isdn_v110.c b/drivers/isdn/isdn_v110.c
index a3ac19caf..22863e208 100644
--- a/drivers/isdn/isdn_v110.c
+++ b/drivers/isdn/isdn_v110.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.3 1999/10/30 09:49:28 keil Exp $
+/* $Id: isdn_v110.c,v 1.4 2000/03/16 16:34:12 kai Exp $
* Linux ISDN subsystem, V.110 related functions (linklevel).
*
@@ -19,6 +19,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_v110.c,v $
+ * Revision 1.4 2000/03/16 16:34:12 kai
+ * some translation work
+ *
+ * there shouldn't be any German comments lurking around anymore ;-)
+ *
* Revision 1.3 1999/10/30 09:49:28 keil
* Reinit of v110 structs
*
@@ -39,14 +44,15 @@
#undef ISDN_V110_DEBUG
-char *isdn_v110_revision = "$Revision: 1.3 $";
+char *isdn_v110_revision = "$Revision: 1.4 $";
#define V110_38400 255
#define V110_19200 15
#define V110_9600 3
-/* Die folgenden Daten sind fertig kodierte Matrizen, jeweils
- als online und offline matrix für 9600, 19200 und 38400
+/*
+ * The following data are precoded matrices, online and offline matrix
+ * for 9600, 19200 und 38400, respectively
*/
static unsigned char V110_OnMatrix_9600[] =
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
@@ -74,13 +80,12 @@ static unsigned char V110_OnMatrix_38400[] =
static unsigned char V110_OffMatrix_38400[] =
{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
-
-/* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um.
- Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123,
- bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge
- auf der isdn-leitung falsch herum ist.
+/*
+ * FlipBits reorders sequences of keylen bits in one byte.
+ * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
+ * and to 67452301 when keylen = 2. This is necessary because ordering on
+ * the isdn line is the the other way.
*/
-
static __inline unsigned char
FlipBits(unsigned char c, int keylen)
{
@@ -164,8 +169,9 @@ isdn_v110_close(isdn_v110_stream * v)
}
-/* ValidHeaderBytes prüft, wieviele bytes in v->decodebuf gültig sind */
-
+/*
+ * ValidHeaderBytes return the number of valid bytes in v->decodebuf
+ */
static int
ValidHeaderBytes(isdn_v110_stream * v)
{
@@ -176,8 +182,9 @@ ValidHeaderBytes(isdn_v110_stream * v)
return i;
}
-/* SyncHeader schiebt den decodebuf pointer auf den nächsten gültigen header */
-
+/*
+ * SyncHeader moves the decodebuf ptr to the next valid header
+ */
static void
SyncHeader(isdn_v110_stream * v)
{
@@ -214,68 +221,60 @@ DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf
int dbit = v->dbit;
unsigned char b = v->b;
- while (line < len) { /* sind schon alle matrizenzeilen abgearbeitet? */
- if ((line % 10) == 0) { /* die 0. zeile der matrix ist immer null ! */
- if (m[line] != 0x00) { /* nicht 0 ? dann fehler! */
+ while (line < len) { /* Are we done with all lines of the matrix? */
+ if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */
+ if (m[line] != 0x00) { /* not 0 ? -> error! */
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
+ /* returning now is not the right thing, though :-( */
#endif
-
-/*
- dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
- v->introducer = 0; v->dbit = 1; v->b = 0;
- return buflen; anzahl schon erzeugter daten zurückgeben!
- */
- }
- line++; /* sonst die nächste matrixzeile nehmen */
+ }
+ line++; /* next line of matrix */
continue;
- } else if ((line % 10) == 5) { /* in zeile 5 stehen nur e-bits ! */
- if ((m[line] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */
+ } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */
+ if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
+ /* returning now is not the right thing, though :-( */
#endif
-/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
- v->introducer = 0; v->dbit = 1; v->b = 0;
- return buflen;
- */
}
- line++; /* alles klar, nächste zeile */
+ line++; /* next line */
continue;
} else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
- introducer = (m[line] & mbit) ? 0 : 1; /* aktuelles bit der matrix */
+ introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */
next_byte:
- if (mbit > 2) { /* war es das letzte bit dieser matrixzeile ? */
- mbit >>= 1; /* nein, nimm das nächste in dieser zeile */
+ if (mbit > 2) { /* was it the last bit in this line ? */
+ mbit >>= 1; /* no -> take next */
continue;
- } /* sonst links in der nächsten zeile anfangen */
+ } /* otherwise start with leftmost bit in the next line */
mbit = 64;
line++;
continue;
- } else { /* sonst müssen wir ein datenbit setzen */
- if (m[line] & mbit) /* war das bit in der matrix gesetzt ? */
- b |= dbit; /* ja, dann setz es auch im datenbyte */
+ } else { /* otherwise we need to set a data bit */
+ if (m[line] & mbit) /* was that bit set in the matrix ? */
+ b |= dbit; /* yes -> set it in the data byte */
else
- b &= dbit - 1; /* nein, lösch bit im datenbyte */
- if (dbit < 128) /* haben wir schon ein ganzes byte voll ? */
- dbit <<= 1; /* nein, auf zum nächsten datenbit */
- else { /* ein ganzes datenbyte ist voll */
- buf[buflen++] = b; /* byte in den output buffer kopieren */
- introducer = b = 0; /* Init der Introsequenz und des datenbytes */
- dbit = 1; /* als nächstes suchen wir das nullte bit */
+ b &= dbit - 1; /* no -> clear it in the data byte */
+ if (dbit < 128) /* is that data byte done ? */
+ dbit <<= 1; /* no, got the next bit */
+ else { /* data byte is done */
+ buf[buflen++] = b; /* copy byte into the output buffer */
+ introducer = b = 0; /* init of the intro sequence and of the data byte */
+ dbit = 1; /* next we look for the 0th bit */
}
- goto next_byte; /* suche das nächste bit in der matrix */
+ goto next_byte; /* look for next bit in the matrix */
}
}
v->introducer = introducer;
v->dbit = dbit;
v->b = b;
- return buflen; /* return anzahl der bytes im output buffer */
+ return buflen; /* return number of bytes in the output buffer */
}
-/* DecodeStream erhält vom input stream V110 kodierte Daten, die zu den
- V110 frames zusammengepackt werden müssen. Die Daten können an diese
- Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
- darauf achten zu müssen, das frames usw. eingehalten werden.
+/*
+ * DecodeStream receives V.110 coded data from the input stream. It recovers the
+ * original frames.
+ * The input stream doesn't need to be framed
*/
struct sk_buff *
isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
@@ -314,8 +313,8 @@ isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
dev_kfree_skb(skb);
return NULL; /* no, try later */
}
- if (ValidHeaderBytes(v) != v->nbytes) { /* ist es ein ungültiger header ? */
- SyncHeader(v); /* nein, such einen header */
+ if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */
+ SyncHeader(v); /* no -> look for header */
goto ReSync;
}
len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
@@ -357,15 +356,15 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
int introducer = 3;
int ibit[] = {0, 1, 1};
- while ((i < len) && (line < mlen)) { /* solange noch input da ist */
- switch (line % 10) { /* in welcher matrixzeile sind wir ? */
+ while ((i < len) && (line < mlen)) { /* while we still have input data */
+ switch (line % 10) { /* in which line of the matrix are we? */
case 0:
- m[line++] = 0x00; /* zeile 0 ist immer 0 */
- mbit = 128; /* und es geht mit dem 7. bit weiter */
+ m[line++] = 0x00; /* line 0 is always 0 */
+ mbit = 128; /* go on with the 7th bit */
break;
case 5:
- m[line++] = 0xbf; /* zeile 5 ist immer 10111111 */
- mbit = 128; /* und es geht mit dem 7. bit weiter */
+ m[line++] = 0xbf; /* line 5 is always 10111111 */
+ mbit = 128; /* go on with the 7th bit */
break;
}
if (line >= mlen) {
@@ -373,41 +372,41 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
return line;
}
next_bit:
- switch (mbit) { /* ganz linkes oder rechtes bit ? */
+ switch (mbit) { /* leftmost or rightmost bit ? */
case 1:
- line++; /* ganz rechts ! dann in die nächste */
+ line++; /* rightmost -> go to next line */
if (line >= mlen) {
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
return line;
}
case 128:
- m[line] = 128; /* ganz links byte auf 1000000 setzen */
- mbit = 64; /* aktuelles bit in der matrixzeile */
+ m[line] = 128; /* leftmost -> set byte to 1000000 */
+ mbit = 64; /* current bit in the matrix line */
continue;
}
- if (introducer) { /* 110 sequenz setzen ? */
- introducer--; /* ein digit weniger setzen */
- m[line] |= ibit[introducer] ? mbit : 0; /* entsprechendes bit setzen */
- mbit >>= 1; /* bit der matrixzeile >> 1 */
- goto next_bit; /* und dort weiter machen */
- } /* else datenbits in die matrix packen! */
- m[line] |= (buf[i] & dbit) ? mbit : 0; /* datenbit in matrix setzen */
- if (dbit == 128) { /* war es das letzte datenbit ? */
- dbit = 1; /* dann mach beim nächsten weiter */
- i++; /* nächste datenbyte des input buffers */
- if (i < len) /* war es schon das letzte ? */
- introducer = 3; /* nein, schreib den introducer 110 */
- else { /* war das letzte datenbyte ! */
- m[line] |= (mbit - 1) & 0xfe; /* setz restliche bits der zeile auf 1 */
+ if (introducer) { /* set 110 sequence ? */
+ introducer--; /* set on digit less */
+ m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */
+ mbit >>= 1; /* bit of matrix line >> 1 */
+ goto next_bit; /* and go on there */
+ } /* else push data bits into the matrix! */
+ m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */
+ if (dbit == 128) { /* was it the last one? */
+ dbit = 1; /* then go on with first bit of */
+ i++; /* next byte in input buffer */
+ if (i < len) /* input buffer done ? */
+ introducer = 3; /* no, write introducer 110 */
+ else { /* input buffer done ! */
+ m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */
break;
}
- } else /* nicht das letzte datenbit */
- dbit <<= 1; /* dann gehe zum nächsten datenbit */
- mbit >>= 1; /* und setz bit der matrix weiter */
+ } else /* not the last data bit */
+ dbit <<= 1; /* then go to next data bit */
+ mbit >>= 1; /* go to next bit of matrix */
goto next_bit;
}
- /* evtl. noch restliche zeilen in der matrix generieren... */
+ /* if necessary, generate remaining lines of the matrix... */
if ((line) && ((line + 10) < mlen))
switch (++line % 10) {
case 1:
@@ -429,7 +428,7 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
case 9:
m[line++] = 0xfe;
}
- return line; /* soviele matrixzeilen sind es */
+ return line; /* that's how many lines we have */
}
/*
@@ -517,7 +516,7 @@ isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
return nskb;
}
mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
- /* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
+ /* now distribute 2 or 4 bits each to the output stream! */
rbuf = skb_put(nskb, size);
olen = 0;
sval1 = 8 - v->nbits;
diff --git a/drivers/isdn/isdn_v110.h b/drivers/isdn/isdn_v110.h
index 4bb694849..de6f9f6e1 100644
--- a/drivers/isdn/isdn_v110.h
+++ b/drivers/isdn/isdn_v110.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.h,v 1.2 1999/10/30 09:49:28 keil Exp $
+/* $Id: isdn_v110.h,v 1.3 2000/03/16 16:34:12 kai Exp $
* Linux ISDN subsystem, V.110 related functions (linklevel).
*
@@ -19,6 +19,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_v110.h,v $
+ * Revision 1.3 2000/03/16 16:34:12 kai
+ * some translation work
+ *
+ * there shouldn't be any German comments lurking around anymore ;-)
+ *
* Revision 1.2 1999/10/30 09:49:28 keil
* Reinit of v110 structs
*
@@ -29,17 +34,14 @@
#ifndef _isdn_v110_h_
#define _isdn_v110_h_
-/* isdn_v110_encode erhält len Nettodaten in buf, kodiert diese und liefert
- das Ergebnis wieder in buf. Wieviele Bytes kodiert wurden wird als
- return zurück gegeben. Diese Daten können dann 1:1 auf die Leitung
- gegeben werden.
-*/
+/*
+ * isdn_v110_encode will take raw data and encode it using V.110
+ */
extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
-/* isdn_v110_decode erhält vom input stream V110 kodierte Daten, die zu den
- V110 frames zusammengepackt werden müssen. Die Daten können an diese
- Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
- darauf achten zu müssen, das frames usw. eingehalten werden.
+/*
+ * isdn_v110_decode receives V.110 coded data from the stream and rebuilds
+ * frames from them. The source stream doesn't need to be framed.
*/
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 08c92ace9..da4e4bfe4 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -310,9 +310,11 @@ int el3_probe(struct net_device *dev)
with "nopnp=1" before, does not harm if not. */
idev->deactivate(idev);
idev->activate(idev);
- if (!idev->resource[0].start || check_region(idev->resource[0].start,16))
+ if (!idev->resource[0].start || check_region(idev->resource[0].start, EL3_IO_EXTENT))
continue;
ioaddr = idev->resource[0].start;
+ if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509 PnP"))
+ return -EBUSY;
irq = idev->irq_resource[0].start;
if (el3_debug > 3)
printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n",
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index d8a5e12af..4aeee0a2e 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -490,7 +490,7 @@ static int corkscrew_scan(struct net_device *dev)
if (inw(ioaddr + Wn0EepromData) != 0x6d50)
continue;
}
- printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
+ printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
/* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr;
@@ -533,7 +533,7 @@ no_pnp:
if (inw(ioaddr + Wn0EepromData) != 0x6d50)
continue;
}
- printk(KERN_INFO "3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n",
+ printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
irq = inw(ioaddr + 0x2002) & 15;
corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 31e8c79b8..ebaeb68ba 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -21,8 +21,6 @@
*/
-static char *version =
-"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -85,6 +83,9 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#define PCI_SUPPORT_VER2
#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+static char *version __initdata =
+"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
MODULE_PARM(debug, "i");
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 6169eb742..336a66949 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1838,7 +1838,7 @@ static void rtl8139_set_rx_mode (struct net_device *dev)
void *ioaddr = tp->mmio_addr;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
- unsigned long flags;
+ unsigned long flags=0;
DPRINTK ("ENTER\n");
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 65246369c..9ce1cf4af 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -114,8 +114,8 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
static void set_multicast_list(struct net_device *dev);
static void do_set_multicast_list(struct net_device *dev);
-/*
- * SMP and the 8390 setup.
+/**
+ * DOC: SMP and the 8390 setup.
*
* The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
* a page register that controls bank and packet buffer access. We guard
@@ -142,10 +142,14 @@ static void do_set_multicast_list(struct net_device *dev);
-/* Open/initialize the board. This routine goes all-out, setting everything
- up anew at each open, even though many of these registers should only
- need to be set once at boot.
- */
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
int ei_open(struct net_device *dev)
{
unsigned long flags;
@@ -173,7 +177,12 @@ int ei_open(struct net_device *dev)
return 0;
}
-/* Opposite of above. Only used when "ifconfig <devname> down" is done. */
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open. Only used when "ifconfig <devname> down" is done.
+ */
int ei_close(struct net_device *dev)
{
struct ei_device *ei_local = (struct ei_device *) dev->priv;
@@ -190,6 +199,14 @@ int ei_close(struct net_device *dev)
return 0;
}
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+
static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
long e8390_base = dev->base_addr;
@@ -389,8 +406,15 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-/* The typical workload of the driver:
- Handle the ether interface interrupts. */
+/**
+ * ei_interrupt -
+ * @irq:
+ * @dev_id:
+ * @regs:
+ *
+ * The typical workload of the driver:
+ * Handle the ether interface interrupts.
+ */
void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
@@ -492,7 +516,10 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
return;
}
-/*
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
* A transmitter error has happened. Most likely excess collisions (which
* is a fairly normal condition). If the error is one where the Tx will
* have been aborted, we try and send another one right away, instead of
@@ -538,8 +565,13 @@ static void ei_tx_err(struct net_device *dev)
}
}
-/* We have finished a transmit: check for errors and then trigger the next
- packet to be sent. Called with lock held */
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held
+ */
static void ei_tx_intr(struct net_device *dev)
{
@@ -625,8 +657,13 @@ static void ei_tx_intr(struct net_device *dev)
netif_wake_queue(dev);
}
-/* We have a good packet(s), get it/them out of the buffers.
- Called with lock held */
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers.
+ * Called with lock held
+ */
static void ei_receive(struct net_device *dev)
{
@@ -751,7 +788,10 @@ static void ei_receive(struct net_device *dev)
return;
}
-/*
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
* We have a receiver overrun: we have to kick the 8390 to get it started
* again. Problem is that you have to kick it exactly as NS prescribes in
* the updated datasheets, or "the NIC may act in an unpredictable manner."
@@ -900,7 +940,10 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
}
}
-/*
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
* Set or clear the multicast filter for this adaptor. May be called
* from a BH in 2.1.x. Must be called with lock held.
*/
@@ -970,7 +1013,10 @@ static void set_multicast_list(struct net_device *dev)
spin_unlock_irqrestore(&ei_local->page_lock, flags);
}
-/*
+/**
+ * ethdev_init - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
* Initialize the rest of the 8390 device structure. Do NOT __init
* this, as it is used by 8390 based modular drivers too.
*/
@@ -1006,7 +1052,11 @@ int ethdev_init(struct net_device *dev)
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
-/*
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean. non-zero value to initiate chip processing
+ *
* Must be called with lock held.
*/
@@ -1066,7 +1116,6 @@ void NS8390_init(struct net_device *dev, int startp)
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
do_set_multicast_list(dev); /* (re)load the mcast table */
}
- return;
}
/* Trigger a transmit start, assuming the length is valid.
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index b62986f83..057f2f704 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -124,9 +124,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
if [ "$CONFIG_NET_PCI" = "y" ]; then
tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
- fi
+ dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
fi
@@ -134,12 +132,12 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
tristate ' CS89x0 support' CONFIG_CS89x0
tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
- tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
+ dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
fi
- tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100
+ dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then
bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM
@@ -147,7 +145,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
fi
- tristate ' PCI NE2000 support' CONFIG_NE2K_PCI
+ dep_tristate ' PCI NE2000 support' CONFIG_NE2K_PCI $CONFIG_PCI
# tristate ' Sundance Alta support' CONFIG_ALTA
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129
@@ -166,7 +164,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
bool ' Pocket and portable adapters' CONFIG_NET_POCKET
if [ "$CONFIG_NET_POCKET" = "y" ]; then
- tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ if [ "$CONFIG_X86" = "y" ]; then
+ tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ fi
tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
fi
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index b3851ef09..91aeaced9 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3495,6 +3495,6 @@ void dfx_xmt_flush(
/*
* Local variables:
- * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 -c defxx.c"
+ * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c"
* End:
*/
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index f855d1978..2832775ae 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1099,6 +1099,12 @@ static int __devinit epic100_init_one (struct pci_dev *pdev,
struct net_device *dev;
long ioaddr;
static int card_idx = -1;
+ static int printed_version = 0;
+
+ if (!printed_version) {
+ printk (KERN_INFO "%s", version);
+ printed_version = 1;
+ }
chip_idx = ent->driver_data;
@@ -1280,13 +1286,7 @@ static struct pci_driver epic100_driver = {
static int __init epic100_init (void)
{
- printk (KERN_INFO "%s", version);
-
- if (pci_register_driver (&epic100_driver) > 0)
- return 0;
-
- pci_unregister_driver (&epic100_driver);
- return -ENODEV;
+ return pci_module_init (&epic100_driver);
}
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index bf001d83d..03944f066 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -941,10 +941,14 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_task_execute(self, __irport_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
break;
case SIOCSDONGLE: /* Set dongle */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
/* Initialize dongle */
dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
if (!dongle)
@@ -965,12 +969,16 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
NULL);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = irport_is_receiving(self);
break;
case SIOCSDTRRTS:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
break;
default:
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index 931ae9c4c..1fd3acda9 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Dec 9 21:18:38 1997
- * Modified at: Fri Jan 14 21:02:27 2000
+ * Modified at: Sat Mar 11 07:43:30 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -962,10 +962,14 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_task_execute(self, irtty_change_speed, NULL, NULL,
(void *) irq->ifr_baudrate);
break;
case SIOCSDONGLE: /* Set dongle */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
/* Initialize dongle */
dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
if (!dongle)
@@ -986,15 +990,21 @@ static int irtty_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
NULL);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
irq->ifr_receiving = irtty_is_receiving(self);
break;
case SIOCSDTRRTS:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
break;
case SIOCSMODE:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irtty_set_mode(dev, irq->ifr_mode);
break;
default:
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 2dd149bf1..df9c63621 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1947,9 +1947,13 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
nsc_ircc_change_speed(self, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index 951b08d8f..387208e2f 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -603,11 +603,15 @@ static int toshoboe_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
/* toshoboe_setbaud(self, irq->ifr_baudrate); */
/* Just change speed once - inserted by Paul Bristow */
self->new_speed = irq->ifr_baudrate;
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 239120e51..2456e012d 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -1332,9 +1332,13 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
w83977af_change_speed(self, irq->ifr_baudrate);
break;
case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
irda_device_set_media_busy(self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index f6929905e..743812346 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -71,28 +71,55 @@ enum {
STOP_PG_0x60=0x100,
};
-/* This will eventually be converted to the standard PCI probe table. */
+
+enum ne2k_pci_chipsets {
+ CH_RealTek_RTL_8029 = 0,
+ CH_Winbond_89C940,
+ CH_Compex_RL2000,
+ CH_KTI_ET32P2,
+ CH_NetVin_NV5000SC,
+ CH_Via_86C926,
+ CH_SureCom_NE34,
+ CH_Winbond_W89C940F,
+ CH_Holtek_HT80232,
+ CH_Holtek_HT80229,
+};
+
static struct {
- unsigned short vendor, dev_id;
char *name;
int flags;
-}
-pci_clone_list[] __initdata = {
- {0x10ec, 0x8029, "RealTek RTL-8029", 0},
- {0x1050, 0x0940, "Winbond 89C940", 0},
- {0x11f6, 0x1401, "Compex RL2000", 0},
- {0x8e2e, 0x3000, "KTI ET32P2", 0},
- {0x4a14, 0x5000, "NetVin NV5000SC", 0},
- {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
- {0x10bd, 0x0e34, "SureCom NE34", 0},
- {0x1050, 0x5a5a, "Winbond W89C940F", 0},
- {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
- {0x12c3, 0x5598, "Holtek HT80229",
- ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
+} pci_clone_list[] __devinitdata = {
+ {"RealTek RTL-8029", 0},
+ {"Winbond 89C940", 0},
+ {"Compex RL2000", 0},
+ {"KTI ET32P2", 0},
+ {"NetVin NV5000SC", 0},
+ {"Via 86C926", ONLY_16BIT_IO},
+ {"SureCom NE34", 0},
+ {"Winbond W89C940F", 0},
+ {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
+ {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
{0,}
};
+
+static struct pci_device_id ne2k_pci_tbl[] __devinitdata = {
+ { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
+ { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
+ { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
+ { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 },
+ { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC },
+ { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 },
+ { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 },
+ { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F },
+ { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 },
+ { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl);
+
+
/* ---- No user-serviceable parts below ---- */
#define NE_BASE (dev->base_addr)
@@ -104,8 +131,6 @@ pci_clone_list[] __initdata = {
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
-static int ne2k_pci_probe(void);
-static struct net_device *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx);
static int ne2k_pci_open(struct net_device *dev);
static int ne2k_pci_close(struct net_device *dev);
@@ -122,47 +147,11 @@ static void ne2k_pci_block_output(struct net_device *dev, const int count,
/* No room in the standard 8390 structure for extra info we need. */
struct ne2k_pci_card {
- struct ne2k_pci_card *next;
struct net_device *dev;
struct pci_dev *pci_dev;
};
-/* A list of all installed devices, for removing the driver module. */
-static struct ne2k_pci_card *ne2k_card_list = NULL;
-static int __init ne2k_pci_init_module(void)
-{
- /* We must emit version information. */
- if (debug)
- printk(KERN_INFO "%s", version);
- if (ne2k_pci_probe()) {
- printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
- return -ENODEV;
- }
- lock_8390_module();
- return 0;
-}
-
-static void __exit ne2k_pci_cleanup_module(void)
-{
- struct net_device *dev;
- struct ne2k_pci_card *this_card;
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (ne2k_card_list) {
- dev = ne2k_card_list->dev;
- unregister_netdev(dev);
- release_region(dev->base_addr, NE_IO_EXTENT);
- kfree(dev);
- this_card = ne2k_card_list;
- ne2k_card_list = ne2k_card_list->next;
- kfree(this_card);
- }
- unlock_8390_module();
-}
-
-module_init(ne2k_pci_init_module);
-module_exit(ne2k_pci_cleanup_module);
/*
NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
@@ -177,96 +166,42 @@ module_exit(ne2k_pci_cleanup_module);
in the 'dev' and 'ei_status' structures.
*/
-#ifdef HAVE_DEVLIST
-struct netdev_entry netcard_drv =
-{"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0};
-#endif
-static int __init ne2k_pci_probe(void)
+static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- struct pci_dev *pdev = NULL;
- int cards_found = 0;
- int i;
struct net_device *dev;
+ int i, irq, reg0, start_page, stop_page;
+ unsigned char SA_prom[32];
+ int chip_idx = ent->driver_data;
+ static unsigned version_printed = 0;
+ long ioaddr;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
- if ( ! pci_present())
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
+
+ if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
+ printk (KERN_ERR "ne2k-pci: no I/O resource at PCI BAR #0\n");
return -ENODEV;
-
- while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) {
- int pci_irq_line;
- u16 pci_command, new_command;
- unsigned long pci_ioaddr;
-
- /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */
- for (i = 0; pci_clone_list[i].vendor != 0; i++)
- if (pci_clone_list[i].vendor == pdev->vendor
- && pci_clone_list[i].dev_id == pdev->device)
- break;
- if (pci_clone_list[i].vendor == 0)
- continue;
-
- pci_ioaddr = pdev->resource[0].start;
- pci_irq_line = pdev->irq;
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-
- /* Avoid already found cards from previous calls */
- if (check_region(pci_ioaddr, NE_IO_EXTENT))
- continue;
-
- {
- static unsigned version_printed = 0;
- if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
- }
-
- /* Activate the card: fix for brain-damaged Win98 BIOSes. */
- new_command = pci_command | PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " NE2k clone! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-#ifndef __sparc__
- if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS)
- printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k"
- " card to IRQ %d, which is unlikely to work!.\n"
- KERN_WARNING " You should use the PCI BIOS setup to assign"
- " a valid IRQ line.\n", pci_irq_line);
-#endif
- printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#lx, IRQ %d.\n",
- pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
- dev = ne2k_pci_probe1(pci_ioaddr, pci_irq_line, i);
- if (dev == 0) {
- /* Should not happen. */
- printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#lx failed.\n",
- pci_ioaddr);
- continue;
- } else {
- struct ne2k_pci_card *ne2k_card =
- kmalloc(sizeof(struct ne2k_pci_card), GFP_KERNEL);
- ne2k_card->next = ne2k_card_list;
- ne2k_card_list = ne2k_card;
- ne2k_card->dev = dev;
- ne2k_card->pci_dev = pdev;
- }
-
- cards_found++;
}
-
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx)
-{
- struct net_device *dev;
- int i;
- unsigned char SA_prom[32];
- int start_page, stop_page;
- int reg0 = inb(ioaddr);
-
+
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR "ne2k-pci: cannot enable device\n");
+ return -EIO;
+ }
+
+ if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
+ printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n",
+ NE_IO_EXTENT, ioaddr);
+ return -EBUSY;
+ }
+
+ reg0 = inb(ioaddr);
if (reg0 == 0xFF)
- return 0;
+ goto err_out_free_res;
/* Do a preliminary verification that we have a 8390. */
{
@@ -279,12 +214,16 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
if (inb(ioaddr + EN0_COUNTER0) != 0) {
outb(reg0, ioaddr);
outb(regd, ioaddr + 0x0d); /* Restore the old values. */
- return 0;
+ goto err_out_free_res;
}
}
dev = init_etherdev(NULL, 0);
-
+ if (!dev) {
+ printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n");
+ goto err_out_free_res;
+ }
+
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
unsigned long reset_start_time = jiffies;
@@ -298,14 +237,15 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
/* Limit wait: '2' avoids jiffy roll-over. */
if (jiffies - reset_start_time > 2) {
printk("ne2k-pci: Card failure (no reset ack).\n");
- return 0;
+ goto err_out_free_netdev;
}
outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
}
if (load_8390_module("ne2k-pci.c")) {
- return 0;
+ printk (KERN_ERR "ne2k-pci: cannot load 8390 module\n");
+ goto err_out_free_netdev;
}
/* Read the 16 bytes of station address PROM.
@@ -355,12 +295,10 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
- printk ("%s: unable to get memory for dev->priv.\n", dev->name);
- return 0;
+ printk (KERN_ERR "%s: unable to get memory for dev->priv.\n", dev->name);
+ goto err_out_free_netdev;
}
- request_region(ioaddr, NE_IO_EXTENT, dev->name);
-
printk("%s: %s found at %#lx, IRQ %d, ",
dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
for(i = 0; i < 6; i++) {
@@ -387,16 +325,26 @@ static struct net_device __init *ne2k_pci_probe1(long ioaddr, int irq, int chip_
dev->open = &ne2k_pci_open;
dev->stop = &ne2k_pci_close;
NS8390_init(dev, 0);
- return dev;
+ return 0;
+
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+err_out_free_res:
+ release_region (ioaddr, NE_IO_EXTENT);
+ return -ENODEV;
+
}
static int
ne2k_pci_open(struct net_device *dev)
{
- if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev))
+ MOD_INC_USE_COUNT;
+ if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
return -EAGAIN;
+ }
ei_open(dev);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -589,6 +537,58 @@ ne2k_pci_block_output(struct net_device *dev, int count,
return;
}
+
+static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+
+ if (!dev) {
+ printk (KERN_ERR "bug! ne2k_pci_remove_one called w/o net_device\n");
+ return;
+ }
+
+ unregister_netdev (dev);
+ release_region (dev->base_addr, NE_IO_EXTENT);
+ kfree (dev);
+}
+
+
+static struct pci_driver ne2k_driver = {
+ name: "ne2k-pci",
+ probe: ne2k_pci_init_one,
+ remove: ne2k_pci_remove_one,
+ id_table: ne2k_pci_tbl,
+};
+
+
+static int __init ne2k_pci_init(void)
+{
+ int rc;
+
+ MOD_INC_USE_COUNT;
+ lock_8390_module();
+
+ rc = pci_module_init (&ne2k_driver);
+
+ /* XXX should this test CONFIG_HOTPLUG like pci_module_init? */
+ if (rc <= 0)
+ unlock_8390_module();
+
+ MOD_DEC_USE_COUNT;
+
+ return rc;
+}
+
+
+static void __exit ne2k_pci_cleanup(void)
+{
+ pci_unregister_driver (&ne2k_driver);
+ unlock_8390_module();
+}
+
+module_init(ne2k_pci_init);
+module_exit(ne2k_pci_cleanup);
+
/*
* Local variables:
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
index f2976e562..214341b53 100644
--- a/drivers/net/net_init.c
+++ b/drivers/net/net_init.c
@@ -1,4 +1,4 @@
-/* netdrv_init.c: Initialization for network devices. */
+/* net_init.c: Initialization for network devices. */
/*
Written 1993,1994,1995 by Donald Becker.
@@ -27,6 +27,8 @@
08/11/99 - Alan Cox: Got fed up of the mess in this file and cleaned it
up. We now share common code and have regularised name
allocation setups. Abolished the 16 card limits.
+ 03/19/2000 - jgarzik and Urban Widmark: init_etherdev 32-byte align
+
*/
#include <linux/config.h>
@@ -139,14 +141,22 @@ static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv, c
return dev;
}
-/* Fill in the fields of the device structure with ethernet-generic values.
-
- If no device structure is passed, a new one is constructed, complete with
- a SIZEOF_PRIVATE private data area.
-
- If an empty string area is passed as dev->name, or a new structure is made,
- a new name string is constructed. The passed string area should be 8 bytes
- long.
+/**
+ * init_etherdev - Register ethernet device
+ * @dev: An ethernet device structure to be filled in, or %NULL if a new
+ * struct should be allocated.
+ * @sizeof_priv: Size of additional driver-private structure to be allocated
+ * for this ethernet device
+ *
+ * Fill in the fields of the device structure with ethernet-generic values.
+ *
+ * If no device structure is passed, a new one is constructed, complete with
+ * a private data area of size @sizeof_priv. A 32-byte (not bit)
+ * alignment is enforced for this private data area.
+ *
+ * If an empty string area is passed as dev->name, or a new structure is made,
+ * a new name string is constructed. The passed string area should be 8 bytes
+ * long.
*/
struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv)
diff --git a/drivers/net/pcmcia/3c575_cb.c b/drivers/net/pcmcia/3c575_cb.c
index e98e1eda8..bff7bc9ed 100644
--- a/drivers/net/pcmcia/3c575_cb.c
+++ b/drivers/net/pcmcia/3c575_cb.c
@@ -12,10 +12,16 @@
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Linux Kernel Additions:
+
+ LK1.1.2 (March 19, 2000)
+ * New PCI interface (jgarzik)
+
*/
static char *version =
-"3c59x.c:v0.99L 5/28/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c575_cb.c:v0.99L+LK1.1.2 3/19/2000 Donald Becker and others http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -64,6 +70,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -85,9 +92,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(compaq_ioaddr, "i");
-MODULE_PARM(compaq_irq, "i");
-MODULE_PARM(compaq_device_id, "i");
/* Operational parameter that usually are not changed. */
@@ -103,6 +107,10 @@ MODULE_PARM(compaq_device_id, "i");
code size of a per-interface flag is not worthwhile. */
static char mii_preamble_required = 0;
+#define PFX "3c575_cb: "
+
+
+
/*
Theory of Operation
@@ -186,76 +194,134 @@ enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int drv_flags, io_size;
- struct net_device *(*probe1)(struct pci_dev *pdev, struct net_device *dev,
- long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
- struct net_device *dev, long ioaddr,
- int irq, int dev_id, int card_idx);
-static struct pci_id_info pci_tbl[] = {
- {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100baseTx", 0x10B7, 0x5950, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100baseT4", 0x10B7, 0x5951, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3c595 Vortex 100base-MII", 0x10B7, 0x5952, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
- {"3Com Vortex", 0x10B7, 0x5900, 0xff00,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Boomerang 10baseT", 0x10B7, 0x9000, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
- {"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c900B-FL Cyclone 10base-FL", 0x10B7, 0x900A, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c905 Boomerang 100baseTx", 0x10B7, 0x9050, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3c905 Boomerang 100baseT4", 0x10B7, 0x9051, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
- {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
- {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c905C Tornado", 0x10B7, 0x9200, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
- {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFE575CT Cyclone CardBus", 0x10B7, 0x5257, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3CCFEM656 Cyclone CardBus", 0x10B7, 0x6562, 0xffff,
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
- 128, vortex_probe1},
- {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
- {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00,
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+
+
+enum vortex_chips {
+ CH_3C590 = 0,
+ CH_3C595_1,
+ CH_3C595_2,
+ CH_3C595_3,
+ CH_VORTEX,
+ CH_3C900_1,
+ CH_3C900_2,
+ CH_3C900_3,
+ CH_3C900B_FL,
+ CH_3C905_1,
+ CH_3C905_2,
+ CH_3C905B_1,
+ CH_3C905B_2,
+ CH_3C905B_FX,
+ CH_3C905C,
+ CH_3C980,
+ CH_3CSOHO100_TX,
+ CH_3C555,
+ CH_3C575_1,
+ CH_3CCFE575,
+ CH_3CCFE575CT,
+ CH_3CCFE656,
+ CH_3CCFEM656,
+ CH_3C575_2,
+ CH_BOOMERANG,
+};
+
+
+/* note: this array directly indexed by above enums, and MUST
+ * be kept in sync with both the enums above, and the PCI device
+ * table below
+ */
+static struct vortex_chip_info {
+ const char *name;
+ int flags;
+ int drv_flags;
+ int io_size;
+} vortex_info_tbl[] = {
+ {"3c590 Vortex 10Mbps",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3c595 Vortex 100baseTx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3c595 Vortex 100baseT4",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3c595 Vortex 100base-MII",
+ PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ {"3Com Vortex",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"3c900 Boomerang 10baseT",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"3c900 Boomerang 10Mbps Combo",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {"3c900 Cyclone 10Mbps Combo",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c900B-FL Cyclone 10base-FL",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c905 Boomerang 100baseTx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3c905 Boomerang 100baseT4",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3c905B Cyclone 100baseTx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c905B Cyclone 10/100/BNC",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+ {"3c905B-FX Cyclone 100baseFx",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c905C Tornado",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c980 Cyclone",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3cSOHO100-TX Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c555 Laptop Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ {"3c575 Boomerang CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3CCFE575 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3CCFE575CT Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3CCFE656 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3CCFEM656 Cyclone CardBus",
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, },
+ {"3c575 series CardBus (unknown version)",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
+ {"3Com Boomerang (unknown version)",
+ PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
+ {0,}, /* 0 terminated list. */
+};
+
+
+static struct pci_device_id vortex_pci_tbl[] __devinit = {
+ { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
+ { 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
+ { 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
+ { 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
+ { 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VORTEX },
+ { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
+ { 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
+ { 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
+ { 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
+ { 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
+ { 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
+ { 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
+ { 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
+ { 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
+ { 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
+ { 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
+ { 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
+ { 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
+ { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
+ { 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
+ { 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
+ { 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
+ { 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
+ { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_2 },
+ { 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_BOOMERANG },
{0,}, /* 0 terminated list. */
};
+MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
+
/* Operational definitions.
These are not used by other compilation units and thus are not
@@ -400,7 +466,7 @@ struct vortex_private {
/* The addresses of transmit- and receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
struct sk_buff* tx_skbuff[TX_RING_SIZE];
- struct net_device *next_module;
+ struct net_device *next_module; /* NULL if PCI device */
void *priv_addr;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
@@ -463,9 +529,8 @@ static struct media_table {
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
-#ifndef CARDBUS
-static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]);
-#endif
+static int vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq,
+ int chip_idx, int card_idx);
static void vortex_up(struct net_device *dev);
static void vortex_down(struct net_device *dev);
static int vortex_open(struct net_device *dev);
@@ -484,7 +549,6 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void vortex_tx_timeout(struct net_device *dev);
-static void acpi_wake(struct pci_dev *pdev);
static void acpi_set_WOL(struct net_device *dev);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
@@ -492,280 +556,181 @@ static void acpi_set_WOL(struct net_device *dev);
#define MAX_UNITS 8
static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-/* A list of all installed Vortex devices, for removing the driver module. */
-static struct net_device *root_vortex_dev = NULL;
-#ifdef MODULE
-#ifndef CARDBUS
-/* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
-#ifdef CARDBUS
+/* A list of all installed Vortex EISA devices, for removing the driver module. */
+static struct net_device *root_vortex_eisa_dev = NULL;
-#include <pcmcia/driver_ops.h>
+static int vortex_cards_found = 0;
-static void vortex_reap(void)
-{
- struct net_device **devp, **next;
- printk(KERN_DEBUG "vortex_reap()\n");
- for (devp = &root_vortex_dev; *devp; devp = next) {
- struct vortex_private *vp = (*devp)->priv;
- next = &vp->next_module;
- if (vp->open || !vp->reap) continue;
- unregister_netdev(*devp);
- if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
- kfree(*devp);
- kfree(vp->priv_addr);
- *devp = *next; next = devp;
- }
-}
-static dev_node_t *vortex_attach(dev_locator_t *loc)
-{
- u16 dev_id, vendor_id;
- u32 io;
- u8 irq;
- struct net_device *dev;
- int chip_idx;
- struct pci_dev *pdev;
- vortex_reap();
- if (loc->bus != LOC_PCI) return NULL;
- pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
- if (!pdev) return NULL;
- io = pci_resource_start (pdev, 0);
- irq = pdev->irq;
- vendor_id = pdev->vendor;
- dev_id = pdev->device;
- printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
- pdev->bus->number, pdev->devfn, dev_id);
- if (io == 0 || irq == 0) {
- printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
- "assigned an %s.\n" KERN_ERR " It will not be activated.\n",
- io == 0 ? "I/O address" : "IRQ");
- return NULL;
- }
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor_id == pci_tbl[chip_idx].vendor_id
- && (dev_id & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) { /* Compiled out! */
- printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
- "vortex_attach().\n", vendor_id, dev_id);
- return NULL;
- }
- dev = vortex_probe1(pdev, NULL, io, irq, chip_idx, MAX_UNITS+1);
- if (dev) {
- dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- strcpy(node->dev_name, dev->name);
- node->major = node->minor = 0;
- node->next = NULL;
- MOD_INC_USE_COUNT;
- return node;
- }
- return NULL;
-}
-static void vortex_detach(dev_node_t *node)
+static void vortex_suspend (struct pci_dev *pdev)
{
- struct net_device *dev, *next;
- printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name);
- for (dev = root_vortex_dev; dev; dev = next) {
- next = ((struct vortex_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
- if (dev && dev->priv) {
- struct vortex_private *vp = dev->priv;
- if (vp->open) vortex_down(dev);
- vp->reap = 1;
- kfree(node);
- MOD_DEC_USE_COUNT;
- }
-}
+ struct net_device *dev = pdev->driver_data;
+
+ printk(KERN_DEBUG "vortex_suspend(%s)\n", dev->name);
-static void vortex_suspend(dev_node_t *node)
-{
- struct net_device *dev, *next;
- printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name);
- for (dev = root_vortex_dev; dev; dev = next) {
- next = ((struct vortex_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
if (dev && dev->priv) {
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- if (vp->open) vortex_down(dev);
+ if (vp->open) {
+ netif_device_detach(dev);
+ vortex_down(dev);
+ }
}
}
-static void vortex_resume(dev_node_t *node)
+
+static void vortex_resume (struct pci_dev *pdev)
{
- struct net_device *dev, *next;
- printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name);
- for (dev = root_vortex_dev; dev; dev = next) {
- next = ((struct vortex_private *)dev->priv)->next_module;
- if (strcmp(dev->name, node->dev_name) == 0) break;
- }
+ struct net_device *dev = pdev->driver_data;
+
+ printk(KERN_DEBUG "vortex_resume(%s)\n", dev->name);
+
if (dev && dev->priv) {
struct vortex_private *vp = (struct vortex_private *)dev->priv;
- if (vp->open) vortex_up(dev);
+ if (vp->open) {
+ vortex_up(dev);
+ netif_device_attach(dev);
+ }
}
}
-struct driver_operations vortex_ops = {
- "3c575_cb", vortex_attach, vortex_suspend, vortex_resume, vortex_detach
-};
-#endif /* Cardbus support */
-
-int init_module(void)
+/* returns count found (>= 0), or negative on error */
+static int __init vortex_eisa_init (void)
{
- if (vortex_debug)
- printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
- register_driver(&vortex_ops);
- return 0;
-#else
- return vortex_scan(0, pci_tbl);
-#endif
-}
-
-#else
-int tc59x_probe(struct net_device *dev)
-{
- static int did_version = -1;
- if (++did_version <= 0)
- printk(KERN_INFO "%s", version);
- return vortex_scan(dev, pci_tbl);
-}
-#endif /* not MODULE */
-
-#ifndef CARDBUS
-static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[])
-{
- int cards_found = 0;
+ long ioaddr;
+ int rc;
+ int orig_cards_found = vortex_cards_found;
- /* Allow an EISA-only driver. */
- struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
- ioaddr = pdev->base_address[0] & ~3;
- irq = pdev->irq;
- }
+ /* Now check all slots of the EISA bus. */
+ if (!EISA_bus)
+ return 0;
- if (ioaddr == 0) {
- printk(KERN_WARNING " A 3Com network adapter has been found, "
- "however it has not been assigned an I/O address.\n"
- " You may need to power-cycle the machine for this "
- "device to work!\n");
- continue;
- }
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
+ int device_id;
- /* Activate the card. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the device "
- "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }
+ if (request_region(ioaddr, VORTEX_TOTAL_SIZE, "vortex") == NULL)
+ continue;
- dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq,
- chip_idx, cards_found);
-
- if (dev) {
- /* Get and check the latency values. On the 3c590 series
- the latency timer must be set to the maximum value to avoid
- data corruption that occurs when the timer expires during
- a transfer -- a bug in the Vortex chip only. */
- u8 pci_latency;
- u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
-
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < new_latency) {
- printk(KERN_INFO "%s: Overriding PCI latency"
- " timer (CFLT) setting of %d, new value is %d.\n",
- dev->name, pci_latency, new_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, new_latency);
- }
- dev = 0;
- cards_found++;
- }
+ /* Check the standard EISA ID register for an encoded '3Com'. */
+ if (inw(ioaddr + 0xC80) != 0x6d50) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ continue;
}
- }
- /* Now check all slots of the EISA bus. */
- if (EISA_bus) {
- static long ioaddr = 0x1000;
- for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
- int device_id;
- if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
- continue;
- /* Check the standard EISA ID register for an encoded '3Com'. */
- if (inw(ioaddr + 0xC80) != 0x6d50)
- continue;
- /* Check for a product that we support, 3c59{2,7} any rev. */
- device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
- if ((device_id & 0xFF00) != 0x5900)
- continue;
- vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
- 4, cards_found);
- dev = 0;
- cards_found++;
+ /* Check for a product that we support, 3c59{2,7} any rev. */
+ device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+ if ((device_id & 0xFF00) != 0x5900) {
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+ continue;
}
- }
-#ifdef MODULE
- /* Special code to work-around the Compaq PCI BIOS32 problem. */
- if (compaq_ioaddr) {
- vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,
- compaq_device_id, cards_found++);
- dev = 0;
+ rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
+ 4, /* XXX is 4 correct eisa idx? */
+ vortex_cards_found);
+ if (rc == 0)
+ vortex_cards_found++;
+ else
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
}
-#endif
- return cards_found ? 0 : -ENODEV;
+ return vortex_cards_found - orig_cards_found;
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int __devinit vortex_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ rc = vortex_probe1 (pdev, pci_resource_start (pdev, 0), pdev->irq,
+ ent->driver_data, vortex_cards_found);
+ if (rc == 0)
+ vortex_cards_found++;
+
+ return rc;
}
-#endif /* ! Cardbus */
-static struct net_device *vortex_probe1(struct pci_dev *pdev,
- struct net_device *dev, long ioaddr,
- int irq, int chip_idx, int card_idx)
+
+/* NOTE: pdev can be NULL, for the case of an EISA driver */
+static int __devinit vortex_probe1(struct pci_dev *pdev,
+ long ioaddr, int irq,
+ int chip_idx, int card_idx)
{
struct vortex_private *vp;
int option;
unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
+ struct net_device *dev;
+ static int printed_version = 0;
+
+ if (!printed_version) {
+ printk (KERN_INFO "%s", version);
+ printed_version = 1;
+ }
- dev = init_etherdev(dev, 0);
-
- printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
- dev->name, pci_tbl[chip_idx].name, ioaddr);
-
+ dev = init_etherdev(NULL, sizeof(*vp));
+ if (!dev) {
+ printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
+ return -ENOMEM;
+ }
+
+ printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
+ dev->name,
+ pdev ? "PCI" : "EISA",
+ vortex_info_tbl[chip_idx].name,
+ ioaddr);
+
+ /* private struct aligned and zeroed by init_etherdev */
+ vp = dev->priv;
+ vp->priv_addr = vp;
dev->base_addr = ioaddr;
dev->irq = irq;
dev->mtu = mtu;
- /* Make certain the descriptor lists are aligned. */
- {
- void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
- vp = (void *)(((long)mem + 15) & ~15);
- memset(vp, 0, sizeof(*vp));
- vp->priv_addr = mem;
+ /* module list only for EISA devices */
+ if (pdev == NULL) {
+ vp->next_module = root_vortex_eisa_dev;
+ root_vortex_eisa_dev = dev;
}
- dev->priv = vp;
+
+ /* PCI-only startup logic */
+ if (pdev) {
+ /* EISA resources already marked, so only PCI needs to do this here */
+ if (!request_region (ioaddr, vortex_info_tbl[chip_idx].io_size,
+ dev->name)) {
+ printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
+ dev->name, vortex_info_tbl[chip_idx].io_size, ioaddr);
+ kfree (dev);
+ return -EBUSY;
+ }
+
+ /* wake up and enable device */
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR "%s: Cannot enable device, aborting\n", dev->name);
+ release_region (ioaddr, vortex_info_tbl[chip_idx].io_size);
+ kfree (dev);
+ return -EIO;
+ }
- vp->next_module = root_vortex_dev;
- root_vortex_dev = dev;
+ /* enable bus-mastering if necessary */
+ if (vortex_info_tbl[chip_idx].flags & PCI_USES_MASTER)
+ pci_set_master (pdev);
+ }
vp->lock = SPIN_LOCK_UNLOCKED;
vp->chip_id = chip_idx;
vp->pdev = pdev;
+ /* if we are a PCI driver, we store info in pdev->driver_data
+ * instead of a module list */
+ if (pdev)
+ pdev->driver_data = dev;
+
/* The lower four bits are the media type. */
if (dev->mem_start)
option = dev->mem_start;
@@ -793,7 +758,7 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
EL3WINDOW(0);
for (i = 0; i < 0x40; i++) {
int timer;
-#ifdef CARDBUS
+#if 1 /* ifdef CARDBUS */
outw(0x230 + i, ioaddr + Wn0EepromCmd);
#else
outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
@@ -835,7 +800,7 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
dev->irq);
#endif
- if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+ if (pdev && vortex_info_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
u32 fn_st_addr; /* Cardbus function status space */
fn_st_addr = pci_resource_start (pdev, 2);
if (fn_st_addr)
@@ -922,9 +887,6 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
}
- /* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
/* The 3c59x-specific entries in the device structure. */
dev->open = &vortex_open;
dev->hard_start_xmit = &vortex_start_xmit;
@@ -932,10 +894,10 @@ static struct net_device *vortex_probe1(struct pci_dev *pdev,
dev->get_stats = &vortex_get_stats;
dev->do_ioctl = &vortex_ioctl;
dev->set_multicast_list = &set_rx_mode;
- dev->tx_timeout = vortex_tx_timeout;
+ dev->tx_timeout = &vortex_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- return dev;
+ return 0;
}
static void wait_for_completion(struct net_device *dev, int cmd)
@@ -956,11 +918,13 @@ vortex_up(struct net_device *dev)
long ioaddr = dev->base_addr;
struct vortex_private *vp = (struct vortex_private *)dev->priv;
union wn3_config config;
- int i;
-
- /* Should be if(HAS_ACPI) */
- acpi_wake(vp->pdev);
+ int i, device_id;
+ if (vp->pdev)
+ device_id = vp->pdev->device;
+ else
+ device_id = 0x5900; /* EISA */
+
/* Before initializing select the active media port. */
EL3WINDOW(3);
config.i = inl(ioaddr + Wn3_Config);
@@ -972,7 +936,7 @@ vortex_up(struct net_device *dev)
media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
} else if (vp->autoselect) {
- if (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY)
+ if (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY)
dev->if_port = XCVR_NWAY;
else {
/* Find first available media type, starting with 100baseTx. */
@@ -995,7 +959,7 @@ vortex_up(struct net_device *dev)
vp->full_duplex = vp->force_fd;
config.u.xcvr = dev->if_port;
- if ( ! (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+ if ( ! (vortex_info_tbl[vp->chip_id].drv_flags & HAS_NWAY))
outl(config.i, ioaddr + Wn3_Config);
if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
@@ -1045,12 +1009,11 @@ vortex_up(struct net_device *dev)
if (vp->cb_fn_base) {
u_short n = inw(ioaddr + Wn2_ResetOptions);
/* Inverted LED polarity */
- if (pci_tbl[vp->chip_id].device_id != 0x5257)
+ if (device_id != 0x5257)
n |= 0x0010;
/* Inverted polarity of MII power bit */
- if ((pci_tbl[vp->chip_id].device_id == 0x6560) ||
- (pci_tbl[vp->chip_id].device_id == 0x6562) ||
- (pci_tbl[vp->chip_id].device_id == 0x5257))
+ if ((device_id == 0x6560) || (device_id == 0x6562) ||
+ (device_id == 0x5257))
n |= 0x4000;
outw(n, ioaddr + Wn2_ResetOptions);
}
@@ -2088,66 +2051,107 @@ static void acpi_set_WOL(struct net_device *dev)
/* Change the power state to D3; RxEnable doesn't take effect. */
pci_write_config_word(vp->pdev, 0xe0, 0x8103);
}
-/* Change from D3 (sleep) to D0 (active).
- Problem: The Cyclone forgets all PCI config info during the transition! */
-static void acpi_wake(struct pci_dev *pdev)
+
+
+static void __devexit vortex_remove_one (struct pci_dev *pdev)
{
- u32 base0, base1, romaddr;
- u16 pci_command, pwr_command;
- u8 pci_latency, pci_cacheline, irq;
+ struct net_device *dev = pdev->driver_data;
+ struct vortex_private *vp;
- pci_read_config_word(pdev, 0xe0, &pwr_command);
- if ((pwr_command & 3) == 0)
+ if (!dev)
return;
- pci_read_config_word( pdev, PCI_COMMAND, &pci_command);
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base0);
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &base1);
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr);
- pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency);
- pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline);
- pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq);
-
- pci_write_config_word( pdev, 0xe0, 0x0000);
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, base0);
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, base1);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr);
- pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq);
- pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency);
- pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline);
- pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5);
+
+ vp = (void *)(dev->priv);
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ unregister_netdev(dev);
+ outw(TotalReset, dev->base_addr + EL3_CMD);
+ release_region(dev->base_addr, vortex_info_tbl[vp->chip_id].io_size);
+ kfree(dev);
}
-#ifdef MODULE
-void cleanup_module(void)
+
+static struct pci_driver vortex_driver = {
+ name: "3c575_cb",
+ probe: vortex_init_one,
+ remove: vortex_remove_one,
+ suspend: vortex_suspend,
+ resume: vortex_resume,
+ id_table: vortex_pci_tbl,
+};
+
+
+static int vortex_have_pci = 0;
+static int vortex_have_eisa = 0;
+
+
+static int __init vortex_init (void)
{
- struct net_device *next_dev;
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&vortex_driver);
+ if (rc < 0)
+ goto out;
+ if (rc > 0)
+ vortex_have_pci = 1;
+
+ rc = vortex_eisa_init ();
+ if (rc < 0)
+ goto out;
+ if (rc > 0)
+ vortex_have_eisa = 1;
+
+out:
+ MOD_DEC_USE_COUNT;
+ return rc;
+}
-#ifdef CARDBUS
- unregister_driver(&vortex_ops);
- vortex_reap();
-#endif
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_vortex_dev) {
- struct vortex_private *vp=(void *)(root_vortex_dev->priv);
- next_dev = vp->next_module;
- unregister_netdev(root_vortex_dev);
- outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
- release_region(root_vortex_dev->base_addr,
- pci_tbl[vp->chip_id].io_size);
- kfree(root_vortex_dev);
- kfree(vp->priv_addr);
- root_vortex_dev = next_dev;
+static void __exit vortex_eisa_cleanup (void)
+{
+ struct net_device *dev, *tmp;
+ struct vortex_private *vp;
+ long ioaddr;
+
+ dev = root_vortex_eisa_dev;
+
+ while (dev) {
+ vp = dev->priv;
+ ioaddr = dev->base_addr;
+
+ unregister_netdev (dev);
+ outw (TotalReset, ioaddr + EL3_CMD);
+ release_region (ioaddr, VORTEX_TOTAL_SIZE);
+
+ tmp = dev;
+ dev = vp->next_module;
+
+ kfree (tmp);
}
}
-#endif /* MODULE */
+
+static void __exit vortex_cleanup (void)
+{
+ if (vortex_have_pci)
+ pci_unregister_driver (&vortex_driver);
+ if (vortex_have_eisa)
+ vortex_eisa_cleanup ();
+}
+
+
+module_init(vortex_init);
+module_exit(vortex_cleanup);
+
+
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c"
+ * cardbus-compile-command: "gcc -DCONFIG_HOTPLUG -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c575_cb.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 534a4bdbd..936abfed8 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -18,6 +18,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
if [ "$CONFIG_CARDBUS" = "y" ]; then
dep_tristate ' 3Com 3c575 CardBus support' CONFIG_PCMCIA_3C575 m
+ tristate ' Xircom Tulip-like CardBus support' CONFIG_PCMCIA_XIRTULIP
fi
bool 'Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile
index 5d0d36f4a..65938d96d 100644
--- a/drivers/net/pcmcia/Makefile
+++ b/drivers/net/pcmcia/Makefile
@@ -19,8 +19,6 @@ obj- :=
# Things that need to export symbols
export-objs := ray_cs.o
-CFLAGS_3c575_cb.o = -DCARDBUS -DMODULE
-
# 16-bit client drivers
obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
@@ -39,6 +37,7 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o
# Cardbus client drivers
obj-$(CONFIG_PCMCIA_3C575) += 3c575_cb.o
+obj-$(CONFIG_PCMCIA_XIRTULIP) += xircom_tulip_cb.o
O_OBJS := $(filter-out $(export-objs), $(obj-y))
OX_OBJS := $(filter $(export-objs), $(obj-y))
diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c
new file mode 100644
index 000000000..c1cb7629f
--- /dev/null
+++ b/drivers/net/pcmcia/xircom_tulip_cb.c
@@ -0,0 +1,3153 @@
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
+/*
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ This driver is for the Digital "Tulip" Ethernet adapter interface.
+ It should work with most DEC 21*4*-based chips/ethercards, as well as
+ with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
+
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Support and updates available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+*/
+
+#define SMP_CHECK
+#define CARDBUS 1
+static const char version[] = "xircom_tulip_cb.c:v0.91 4/14/99 becker@cesdis.gsfc.nasa.gov (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n";
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
+
+/* The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+ "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
+/* Keep the ring sizes a power of two for efficiency.
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/*
+ Set the bus performance register.
+ Typical: Set 16 longword cache alignment, no burst limit.
+ Cache alignment bits 15:14 Burst length 13:8
+ 0000 No alignment 0x00000000 unlimited 0800 8 longwords
+ 4000 8 longwords 0100 1 longword 1000 16 longwords
+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
+ C000 32 longwords 0400 4 longwords
+ Warning: many older 486 systems are broken and require setting 0x00A04800
+ 8 longword cache alignment, 8 longword burst.
+ ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__powerpc__)
+static int csr0 = 0x01B00000 | 0x8000;
+#elif defined(__sparc__)
+static int csr0 = 0x01B00080 | 0x8000;
+#elif defined(__i386__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+ to support a pre-NWay full-duplex signaling mechanism using short frames.
+ No one knows what it should be, but if left at its default value some
+ 10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC 0x6969
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
+ This is only in the support-all-kernels source code. */
+
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+#define RUN_AT(x) (jiffies + (x))
+
+#define tulip_debug debug
+#ifdef TULIP_DEBUG
+static int tulip_debug = TULIP_DEBUG;
+#else
+static int tulip_debug = 1;
+#endif
+
+/*
+ Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI. Supported members of the family
+are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported.
+
+These chips are used on at least 140 unique PCI board designs. The great
+number of chips and board designs supported is the reason for the
+driver size and complexity. Almost of the increasing complexity is in the
+board configuration and media selection code. There is very little
+increasing in the operational critical path length.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+
+Some boards have EEPROMs tables with default media entry. The factory default
+is usually "autoselect". This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers. When an incoming frame is less than
+RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
+copied to the new skbuff. When the incoming frame is larger, the skbuff is
+passed directly up the protocol stack and replaced by a newly allocated
+skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames. For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information). For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data. A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control. One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag. The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.) After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
+
+IVb. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840A.html
+http://www.asix.com.tw/pmac.htm
+http://www.admtek.com.tw/
+
+IVc. Errata
+
+The old DEC databooks were light on details.
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written. Hmmm, now how is that possible?
+
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below. Some boards do not have EEPROM
+media tables and need to be patched up. Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
+
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them. The MII transceiver status is polled using an kernel timer.
+
+*/
+
+/* This table use during operation for capabilities and media timer. */
+
+static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
+static void comet_timer(unsigned long data);
+
+enum tbl_flag {
+ HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+ HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+ HAS_NWAY143=0x40, /* Uses 21143-like internal NWay. */
+};
+static struct tulip_chip_table {
+ char *chip_name;
+ int io_size;
+ int valid_intrs; /* CSR7 interrupt enable settings */
+ int flags;
+ void (*media_timer)(unsigned long data);
+} tulip_tbl[] = {
+ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+ { "Digital DS21143 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer },
+ { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+ HAS_MII, pnic_timer },
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+ { "Lite-On PNIC-II", 256, 0x0001ebef,
+ HAS_MII | HAS_NWAY143, pnic_timer },
+ { "ADMtek Comet", 256, 0x0001abef,
+ MC_HASH_ONLY, comet_timer },
+ { "Compex 9881 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Xircom Cardbus Adapter (DEC 21143 compatible mode)", 128, 0x0801fbff,
+ HAS_MII | HAS_ACPI, tulip_timer },
+ {0},
+};
+/* This matches the table above. Note 21142 == 21143. */
+enum chips {
+ DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+ LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
+ X3201_3,
+};
+
+/* A full-duplex map for media types. */
+enum MediaIs {
+ MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+ MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
+static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
+static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+/* Offsets to the Command and Status Registers, "CSRs". All accesses
+ must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+ CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+ CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+ CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+ TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+ NormalIntr=0x10000, AbnormalIntr=0x8000,
+ RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+ TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
+};
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct tulip_rx_desc {
+ s32 status;
+ s32 length;
+ u32 buffer1, buffer2;
+};
+
+struct tulip_tx_desc {
+ s32 status;
+ s32 length;
+ u32 buffer1, buffer2; /* We use only buffer 1. */
+};
+
+enum desc_status_bits {
+ DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+
+/* Ring-wrap flag in length field, use for last ring entry.
+ 0x01000000 means chain on buffer2 address,
+ 0x02000000 means use the ring start address in CSR2/3.
+ Note: Some work-alike chips do not function correctly in chained mode.
+ The ASIX chip works only in chained mode.
+ Thus we indicates ring mode, but always write the 'next' field for
+ chained mode as well.
+*/
+#define DESC_RING_WRAP 0x02000000
+
+#ifdef CARDBUS
+#define EEPROM_ADDRLEN (chip_rev == 65 ? 8 : 6)
+#else
+#define EEPROM_ADDRLEN 6
+#endif
+#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
+
+struct medialeaf {
+ u8 type;
+ u8 media;
+ unsigned char *leafdata;
+};
+
+struct mediatable {
+ u16 defaultmedia;
+ u8 leafcount, csr12dir; /* General purpose pin directions. */
+ unsigned has_mii:1, has_nonmii:1, has_reset:6;
+ u32 csr15dir, csr15val; /* 21143 NWay setting. */
+ struct medialeaf mleaf[0];
+};
+
+struct mediainfo {
+ struct mediainfo *next;
+ int info_type;
+ int index;
+ unsigned char *info;
+};
+
+struct tulip_private {
+ char devname[8]; /* Used only for kernel debugging. */
+ const char *product_name;
+ struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+ struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff* tx_skbuff[TX_RING_SIZE];
+#ifdef CARDBUS
+ /* The X3201-3 requires double word aligned tx bufs */
+ struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
+#endif
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ char *rx_buffs; /* Address of temporary Rx buffers. */
+ u8 setup_buf[96*sizeof(u16) + 7];
+ u16 *setup_frame; /* Pseudo-Tx frame to init address table. */
+ int chip_id;
+ int revision;
+ struct net_device_stats stats;
+ struct timer_list timer; /* Media selection timer. */
+ int interrupt; /* In-interrupt flag. */
+ unsigned int cur_rx, cur_tx; /* The next free ring entry */
+ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int full_duplex_lock:1;
+ unsigned int fake_addr:1; /* Multiport board faked address. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int media2:4; /* Secondary monitored media port. */
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
+ unsigned int open:1;
+ unsigned int csr0; /* CSR0 setting. */
+ unsigned int csr6; /* Current CSR6 control settings. */
+ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
+ u16 to_advertise; /* NWay capabilities advertised. */
+ u16 lpar; /* 21143 Link partner ability. */
+ u16 advertising[4];
+ signed char phys[4], mii_cnt; /* MII device addresses. */
+ struct mediatable *mtable;
+ int cur_index; /* Current media index. */
+ int saved_if_port;
+ struct pci_dev *pdev;
+ spinlock_t lock;
+ int pad0, pad1; /* Used for 8-byte alignment */
+};
+
+static void parse_eeprom(struct net_device *dev);
+static int read_eeprom(long ioaddr, int location, int addr_len);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static void select_media(struct net_device *dev, int startup);
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
+static int tulip_open(struct net_device *dev);
+static void tulip_timer(unsigned long data);
+static void t21142_start_nway(struct net_device *dev);
+static void tulip_tx_timeout(struct net_device *dev);
+static void tulip_init_ring(struct net_device *dev);
+static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int tulip_rx(struct net_device *dev);
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_close(struct net_device *dev);
+static struct net_device_stats *tulip_get_stats(struct net_device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif
+static void set_rx_mode(struct net_device *dev);
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+ manipulated. Keith Owens <kaos@ocs.com.au>. */
+
+static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx)
+{
+ const int strict_bits = 0x0060e202;
+ int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+ long flags;
+ save_flags(flags);
+ cli();
+ if (chip_idx != X3201_3) {
+ outl(newcsr6, ioaddr + CSR6);
+ restore_flags(flags);
+ return;
+ }
+ newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
+ /* read 0 on the Xircom cards */
+ newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
+ currcsr6 = inl(ioaddr + CSR6);
+ if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+ ((currcsr6 & ~0x2002) == 0)) {
+ outl(newcsr6, ioaddr + CSR6); /* safe */
+ restore_flags(flags);
+ return;
+ }
+ /* make sure the transmitter and receiver are stopped first */
+ currcsr6 &= ~0x2002;
+ while (1) {
+ csr5 = inl(ioaddr + CSR5);
+ if (csr5 == 0xffffffff)
+ break; /* cannot read csr5, card removed? */
+ csr5_22_20 = csr5 & 0x700000;
+ csr5_19_17 = csr5 & 0x0e0000;
+ if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+ (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+ break; /* both are stopped or suspended */
+ if (!--attempts) {
+ printk(KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
+ "csr5=0x%08x\n", csr5);
+ outl(newcsr6, ioaddr + CSR6); /* unsafe but do it anyway */
+ restore_flags(flags);
+ return;
+ }
+ outl(currcsr6, ioaddr + CSR6);
+ udelay(1);
+ }
+ /* now it is safe to change csr6 */
+ outl(newcsr6, ioaddr + CSR6);
+ restore_flags(flags);
+}
+
+static struct net_device *tulip_probe1(struct pci_dev *pdev,
+ struct net_device *dev, long ioaddr, int irq,
+ int chip_idx, int board_idx)
+{
+ static int did_version = 0; /* Already printed version info. */
+ struct tulip_private *tp;
+ /* See note below on the multiport cards. */
+ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+ static int last_irq = 0;
+ static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
+ u8 chip_rev;
+ int i;
+ unsigned short sum;
+
+ if (tulip_debug > 0 && did_version++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ dev = init_etherdev(dev, 0);
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
+ /* Bring the 21143 out of sleep mode.
+ Caution: Snooze mode does not work with some boards! */
+ if (tulip_tbl[chip_idx].flags & HAS_ACPI)
+ pci_write_config_dword(pdev, 0x40, 0x00000000);
+
+ printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+ dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+
+ /* Stop the chip's Tx and Rx processes. */
+ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx);
+ /* Clear the missed-packet counter. */
+ (volatile int)inl(ioaddr + CSR8);
+
+ if (chip_idx == DC21041) {
+ if (inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_idx = DC21040;
+ } else {
+ printk(" 21041 mode,");
+ }
+ }
+
+ /* The station address ROM is read byte serially. The register must
+ be polled, waiting for the value to be read bit serially from the
+ EEPROM.
+ */
+ sum = 0;
+ if (chip_idx == DC21040) {
+ outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
+ for (i = 0; i < 6; i++) {
+ int value, boguscnt = 100000;
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ dev->dev_addr[i] = value;
+ sum += value & 0xff;
+ }
+ } else if (chip_idx == LC82C168) {
+ for (i = 0; i < 3; i++) {
+ int value, boguscnt = 100000;
+ outl(0x600 | i, ioaddr + 0x98);
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+ sum += value & 0xffff;
+ }
+ } else if (chip_idx == COMET) {
+ /* No need to read the EEPROM. */
+ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+ put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+ for (i = 0; i < 6; i ++)
+ sum += dev->dev_addr[i];
+ } else if (chip_idx == X3201_3) {
+ /* Xircom has its address stored in the CIS
+ * we access it through the boot rom interface for now
+ * this might not work, as the CIS is not parsed but I
+ * (danilo) use the offset I found on my card's CIS !!!
+ *
+ * Doug Ledford: I changed this routine around so that it
+ * walks the CIS memory space, parsing the config items, and
+ * finds the proper lan_node_id tuple and uses the data
+ * stored there.
+ */
+ unsigned char j, tuple, link, data_id, data_count;
+ outl(1<<12, ioaddr + CSR9); /* enable boot rom access */
+ for (i = 0x100; i < 0x1f7; i += link+2) {
+ outl(i, ioaddr + CSR10);
+ tuple = inl(ioaddr + CSR9) & 0xff;
+ outl(i + 1, ioaddr + CSR10);
+ link = inl(ioaddr + CSR9) & 0xff;
+ outl(i + 2, ioaddr + CSR10);
+ data_id = inl(ioaddr + CSR9) & 0xff;
+ outl(i + 3, ioaddr + CSR10);
+ data_count = inl(ioaddr + CSR9) & 0xff;
+ if ( (tuple == 0x22) &&
+ (data_id == 0x04) && (data_count == 0x06) ) {
+ /*
+ * This is it. We have the data we want.
+ */
+ for (j = 0; j < 6; j++) {
+ outl(i + j + 4, ioaddr + CSR10);
+ dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff;
+ }
+ break;
+ } else if (link == 0) {
+ break;
+ }
+ }
+ sum = 1; // to make check below fail!
+ } else { /* Must be a new chip, with a serial EEPROM interface. */
+ /* We read the whole EEPROM, and sort it out later. DEC has a
+ specification _Digital Semiconductor 21X4 Serial ROM Format_
+ but early vendor boards just put the address in the first six
+ EEPROM locations. */
+ unsigned char ee_data[EEPROM_SIZE];
+ int sa_offset = 0;
+
+ for (i = 0; i < sizeof(ee_data)/2; i++)
+ ((u16 *)ee_data)[i] =
+ le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
+
+ /* Detect the simple EEPROM format by the duplicated station addr. */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ sa_offset = 20;
+ if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
+ sa_offset = 2; /* Grrr, damn Matrox boards. */
+ multiport_cnt = 4;
+ }
+ for (i = 0; i < 6; i ++) {
+ dev->dev_addr[i] = ee_data[i + sa_offset];
+ sum += ee_data[i + sa_offset];
+ }
+ }
+ /* Lite-On boards have the address byte-swapped. */
+ if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0)
+ && dev->dev_addr[1] == 0x00)
+ for (i = 0; i < 6; i+=2) {
+ char tmp = dev->dev_addr[i];
+ dev->dev_addr[i] = dev->dev_addr[i+1];
+ dev->dev_addr[i+1] = tmp;
+ }
+ /* On the Zynx 315 Etherarray and other multiport boards only the
+ first Tulip has an EEPROM.
+ The addresses of the subsequent ports are derived from the first.
+ Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+ that here as well. */
+ if (sum == 0 || sum == 6*0xff) {
+ printk(" EEPROM not present,");
+ for (i = 0; i < 5; i++)
+ dev->dev_addr[i] = last_phys_addr[i];
+ dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386__) /* Patch up x86 BIOS bug. */
+ if (last_irq)
+ irq = last_irq;
+#endif
+ }
+
+ for (i = 0; i < 6; i++)
+ printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
+ printk(", IRQ %d.\n", irq);
+ last_irq = irq;
+
+ /* We do a request_region() only to register /proc/ioports info. */
+ /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+ request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ /* Make certain the data structures are quadword aligned. */
+ tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
+ memset(tp, 0, sizeof(*tp));
+ dev->priv = tp;
+
+ tp->lock = SPIN_LOCK_UNLOCKED;
+ tp->pdev = pdev;
+ tp->chip_id = chip_idx;
+ tp->revision = chip_rev;
+ tp->csr0 = csr0;
+ tp->setup_frame = (u16 *)(((unsigned long)tp->setup_buf + 7) & ~7);
+
+ /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+ And the ASIX must have a burst limit or horrible things happen. */
+ if ( (chip_idx == DC21143 && chip_rev == 65) ||
+ (chip_idx == X3201_3) )
+ tp->csr0 &= ~0x01000000;
+ else if (chip_idx == AX88140)
+ tp->csr0 |= 0x2000;
+
+#ifdef TULIP_FULL_DUPLEX
+ tp->full_duplex = 1;
+ tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+ tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+ tp->medialock = 1;
+#endif
+
+ /* The lower four bits are the media type. */
+ if (board_idx >= 0 && board_idx < MAX_UNITS) {
+ tp->default_port = options[board_idx] & 15;
+ if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+ tp->full_duplex = 1;
+ if (mtu[board_idx] > 0)
+ dev->mtu = mtu[board_idx];
+ }
+ if (dev->mem_start)
+ tp->default_port = dev->mem_start;
+ if (tp->default_port) {
+ tp->medialock = 1;
+ if (media_cap[tp->default_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ }
+ if (tp->full_duplex)
+ tp->full_duplex_lock = 1;
+
+ /* This is logically part of probe1(), but too complex to write inline. */
+ if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE)
+ parse_eeprom(dev);
+
+ if (media_cap[tp->default_port] & MediaIsMII) {
+ u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+ tp->to_advertise = media2advert[tp->default_port - 9];
+ } else
+ tp->to_advertise = 0x03e1;
+
+ if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) ||
+ (tp->mtable && tp->mtable->has_mii) ||
+ ( ! tp->mtable && (tulip_tbl[chip_idx].flags & HAS_MII))) {
+ int phy, phy_idx;
+ if (tp->mtable && tp->mtable->has_mii) {
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == 11) {
+ tp->cur_index = i;
+ tp->saved_if_port = dev->if_port;
+ select_media(dev, 1);
+ dev->if_port = tp->saved_if_port;
+ break;
+ }
+ }
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later,
+ but takes much time. */
+ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+ phy++) {
+ int mii_status = mdio_read(dev, phy, 1);
+ if ((mii_status & 0x8301) == 0x8001 ||
+ ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
+ int mii_reg0 = mdio_read(dev, phy, 0);
+ int mii_advert = mdio_read(dev, phy, 4);
+ int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+ tp->phys[phy_idx] = phy;
+ tp->advertising[phy_idx++] = reg4;
+ printk(KERN_INFO "%s: MII transceiver #%d "
+ "config %4.4x status %4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_reg0, mii_status, mii_advert);
+ /* Fixup for DLink with miswired PHY. */
+ if (mii_advert != reg4) {
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
+ " previously advertising %4.4x.\n",
+ dev->name, reg4, phy, mii_advert);
+ mdio_write(dev, phy, 4, reg4);
+ }
+ /* Enable autonegotiation: some boards default to off. */
+ mdio_write(dev, phy, 0, mii_reg0 |
+ (tp->full_duplex ? 0x1100 : 0x1000) |
+ (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+ }
+ }
+ tp->mii_cnt = phy_idx;
+ if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
+ printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+ dev->name);
+ tp->phys[0] = 1;
+ }
+ }
+
+ /* The Tulip-specific entries in the device structure. */
+ dev->open = &tulip_open;
+ dev->hard_start_xmit = &tulip_start_xmit;
+ dev->stop = &tulip_close;
+ dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &private_ioctl;
+#endif
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_rx_mode;
+#endif
+ dev->tx_timeout = tulip_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /* Reset the xcvr interface and turn on heartbeat. */
+ switch (chip_idx) {
+ case DC21041:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+ outl_CSR6(inl(ioaddr + CSR6) | 0x0200, ioaddr, chip_idx);
+ outl(0x0000EF05, ioaddr + CSR13);
+ break;
+ case DC21040:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0x00000004, ioaddr + CSR13);
+ break;
+ case DC21140: default:
+ if (tp->mtable)
+ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+ break;
+ case DC21142:
+ case PNIC2:
+ if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) {
+ outl_CSR6(0x82020000, ioaddr, chip_idx);
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl_CSR6(0x820E0000, ioaddr, chip_idx);
+ } else {
+ outl_CSR6(0x82420200, ioaddr, chip_idx);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ }
+ break;
+ case X3201_3:
+ outl(0x0008, ioaddr + CSR15);
+ udelay(5); /* The delays are Xircom recommended to give the
+ * chipset time to reset the actual hardware
+ * on the PCMCIA card
+ */
+ outl(0xa8050000, ioaddr + CSR15);
+ udelay(5);
+ outl(0xa00f0000, ioaddr + CSR15);
+ udelay(5);
+ outl_CSR6(0x32000200, ioaddr, chip_idx);
+ break;
+ case LC82C168:
+ if ( ! tp->mii_cnt) {
+ outl_CSR6(0x00420000, ioaddr, chip_idx);
+ outl(0x30, ioaddr + CSR12);
+ outl(0x0001F078, ioaddr + 0xB8);
+ outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+ }
+ break;
+ case MX98713: case COMPEX9881:
+ outl_CSR6(0x00000000, ioaddr, chip_idx);
+ outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+ outl(0x00000001, ioaddr + CSR13);
+ break;
+ case MX98715: case MX98725:
+ outl_CSR6(0x01a80000, ioaddr, chip_idx);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00001000, ioaddr + CSR12);
+ break;
+ case COMET:
+ /* No initialization necessary. */
+ break;
+ }
+
+ return dev;
+}
+
+/* Serial EEPROM section. */
+/* The main routine to parse the very complicated SROM structure.
+ Search www.digital.com for "21X4 SROM" to get details.
+ This code is very complex, and will require changes to support
+ additional cards, so I'll be verbose about what is going on.
+ */
+
+/* Known cards that have old-style EEPROMs. */
+static struct fixups {
+ char *name;
+ unsigned char addr0, addr1, addr2;
+ u16 newtable[32]; /* Max length below. */
+} eeprom_fixups[] = {
+ {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+ 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+ {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0903, 0x006D, /* 100baseTx */ }},
+ {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+ 0x0107, 0x8021, /* 100baseFx */
+ 0x0108, 0x8021, /* 100baseFx-FD */
+ 0x0103, 0x006D, /* 100baseTx */ }},
+ {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
+ 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }},
+ {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F,
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ }},
+ {0, 0, 0, 0, {}}};
+
+static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+
+#if defined(__i386__) /* AKA get_unaligned() */
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
+static void parse_eeprom(struct net_device *dev)
+{
+ /* The last media info list parsed, for multiport boards. */
+ static struct mediatable *last_mediatable = NULL;
+ static unsigned char *last_ee_data = NULL;
+ static int controller_index = 0;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ unsigned char *ee_data = tp->eeprom;
+ int i;
+#ifdef CARDBUS
+ int chip_rev = tp->revision;
+#endif
+
+ tp->mtable = 0;
+ for (i = 0; i < EEPROM_SIZE/2; i++)
+ ((u16 *)ee_data)[i] =
+ le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
+
+ /* Detect an old-style (SA only) EEPROM layout:
+ memcmp(eedata, eedata+16, 8). */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ break;
+ if (i >= 8) {
+ if (ee_data[0] == 0xff) {
+ if (last_mediatable) {
+ controller_index++;
+ printk(KERN_INFO "%s: Controller %d of multiport board.\n",
+ dev->name, controller_index);
+ tp->mtable = last_mediatable;
+ ee_data = last_ee_data;
+ goto subsequent_board;
+ } else
+ printk(KERN_INFO "%s: Missing EEPROM, this interface may "
+ "not work correctly!\n",
+ dev->name);
+ return;
+ }
+ /* Do a fix-up based on the vendor half of the station address prefix. */
+ for (i = 0; eeprom_fixups[i].name; i++) {
+ if (dev->dev_addr[0] == eeprom_fixups[i].addr0
+ && dev->dev_addr[1] == eeprom_fixups[i].addr1
+ && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
+ if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
+ i++; /* An Accton EN1207, not an outlaw Maxtech. */
+ memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+ sizeof(eeprom_fixups[i].newtable));
+ printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
+ " substitute media control info.\n",
+ dev->name, eeprom_fixups[i].name);
+ break;
+ }
+ }
+ if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+ printk(KERN_INFO "%s: Old style EEPROM with no media selection "
+ "information.\n",
+ dev->name);
+ return;
+ }
+ }
+
+ controller_index = 0;
+ if (ee_data[19] > 1) { /* Multiport board. */
+ last_ee_data = ee_data;
+ }
+subsequent_board:
+
+ if (ee_data[27] == 0) { /* No valid media table. */
+ } else if (tp->chip_id == DC21041) {
+ unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
+ short media;
+ int count;
+
+ media = get_u16(p);
+ p += 2;
+ count = *p++;
+
+ printk(KERN_INFO "%s:21041 Media information at %d, default media "
+ "%4.4x (%s).\n", dev->name, ee_data[27], media,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ unsigned char media_code = *p++;
+ u16 csrvals[3];
+ int idx;
+ for (idx = 0; idx < 3; idx++) {
+ csrvals[idx] = get_u16(p);
+ p += 2;
+ }
+ if (media_code & 0x40) {
+ printk(KERN_INFO "%s: 21041 media %2.2x (%s),"
+ " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+ dev->name, media_code & 15, medianame[media_code & 15],
+ csrvals[0], csrvals[1], csrvals[2]);
+ } else
+ printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
+ dev->name, media_code & 15, medianame[media_code & 15]);
+ }
+ } else {
+ unsigned char *p = (void *)ee_data + ee_data[27];
+ unsigned char csr12dir = 0;
+ int count;
+ struct mediatable *mtable;
+ u16 media = get_u16(p);
+
+ p += 2;
+ if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
+ csr12dir = *p++;
+ count = *p++;
+ mtable = (struct mediatable *)
+ kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
+ GFP_KERNEL);
+ if (mtable == NULL)
+ return; /* Horrible, impossible failure. */
+ last_mediatable = tp->mtable = mtable;
+ mtable->defaultmedia = media;
+ mtable->leafcount = count;
+ mtable->csr12dir = csr12dir;
+ mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+ mtable->csr15dir = mtable->csr15val = 0;
+
+ printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ struct medialeaf *leaf = &mtable->mleaf[i];
+
+ if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+ leaf->type = 0;
+ leaf->media = p[0] & 0x3f;
+ leaf->leafdata = p;
+ if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */
+ mtable->has_mii = 1;
+ p += 4;
+ } else {
+ leaf->type = p[1];
+ if (p[1] == 0x05) {
+ mtable->has_reset = i;
+ leaf->media = p[2] & 0x0f;
+ } else if (p[1] & 1) {
+ mtable->has_mii = 1;
+ leaf->media = 11;
+ } else {
+ mtable->has_nonmii = 1;
+ leaf->media = p[2] & 0x0f;
+ if (p[1] == 2) {
+ if (leaf->media == 0) {
+ mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
+ mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
+ } else if (leaf->media == 0x40) {
+ u32 base15 = get_unaligned((u16*)&p[7]);
+ mtable->csr15dir =
+ (get_unaligned((u16*)&p[9])<<16) + base15;
+ mtable->csr15val =
+ (get_unaligned((u16*)&p[11])<<16) + base15;
+ }
+ }
+ }
+ leaf->leafdata = p + 2;
+ p += (p[0] & 0x3f) + 1;
+ }
+ if (tulip_debug > 1 && leaf->media == 11) {
+ unsigned char *bp = leaf->leafdata;
+ printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
+ "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
+ dev->name, bp[0], bp[1], bp[1 + bp[1]*2],
+ bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+ }
+ printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
+ "by a %s (%d) block.\n",
+ dev->name, i, medianame[leaf->media], leaf->media,
+ block_name[leaf->type], leaf->type);
+ }
+ }
+}
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
+#define EE_CS 0x01 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+ We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay() inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5 << addr_len)
+#define EE_READ_CMD (6 << addr_len)
+#define EE_ERASE_CMD (7 << addr_len)
+
+static int read_eeprom(long ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned short retval = 0;
+ long ee_addr = ioaddr + CSR9;
+ int read_cmd = location | EE_READ_CMD;
+
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ outl(EE_ENB, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outl(EE_ENB | dataval, ee_addr);
+ eeprom_delay();
+ outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ }
+ outl(EE_ENB, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outl(EE_ENB, ee_addr);
+ eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ return retval;
+}
+
+/* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+ MDIO protocol. See the MII specifications or DP83840A data sheet
+ for details. */
+
+/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+ MDIO protocol. It is just different enough from the EEPROM protocol
+ to not share code. The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int retval = 0;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ int i = 1000;
+ outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ while (--i > 0)
+ if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+ return retval & 0xffff;
+ return 0xffff;
+ }
+
+ if (tp->chip_id == COMET) {
+ if (phy_id == 1) {
+ if (location < 7)
+ return inl(ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ return inl(ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ return inl(ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return 0xffff;
+ }
+
+ /* Establish sync by sending at least 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ int i = 1000;
+ outl(cmd, ioaddr + 0xA0);
+ do
+ if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+ break;
+ while (--i > 0);
+ return;
+ }
+
+ if (tp->chip_id == COMET) {
+ if (phy_id != 1)
+ return;
+ if (location < 7)
+ outl(value, ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ outl(value, ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+ return;
+ }
+
+ /* Establish sync by sending 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return;
+}
+
+static void
+tulip_up(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int i;
+
+ /* On some chip revs we must set the MII/SYM port before the reset!? */
+ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
+ outl_CSR6(0x00040000, ioaddr, tp->chip_id);
+
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ outl(0x00000001, ioaddr + CSR0);
+
+ /* Deassert reset. */
+ outl(tp->csr0, ioaddr + CSR0);
+ udelay(2);
+
+ if (tulip_tbl[tp->chip_id].flags & HAS_ACPI)
+ pci_write_config_dword(tp->pdev, 0x40, 0x00000000);
+
+ /* Clear the tx ring */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ tp->tx_skbuff[i] = 0;
+ tp->tx_ring[i].status = 0x00000000;
+ }
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
+
+ if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) {
+ u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+ u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+ if (tp->chip_id == AX88140) {
+ outl(0, ioaddr + CSR13);
+ outl(addr_low, ioaddr + CSR14);
+ outl(1, ioaddr + CSR13);
+ outl(addr_high, ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) {
+ outl(addr_low, ioaddr + 0xA4);
+ outl(addr_high, ioaddr + 0xA8);
+ outl(0, ioaddr + 0xAC);
+ outl(0, ioaddr + 0xB0);
+ }
+ } else if (tp->chip_id != X3201_3) {
+ /* This is set_rx_mode(), but without starting the transmitter. */
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u16 *setup_frm = &tp->setup_frame[15*6];
+
+ /* 21140 bug: you must add the broadcast address. */
+ memset(tp->setup_frame, 0xff, 96*sizeof(u16));
+ /* Fill the final entry of the table with our physical address. */
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ /* Put the setup frame on the Tx list. */
+ tp->tx_ring[0].length = 0x08000000 | 192;
+ tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
+ tp->tx_ring[0].status = DescOwned;
+
+ tp->cur_tx++;
+ } else { /* X3201_3 */
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u16 *setup_frm = &tp->setup_frame[0*6];
+
+ /* fill the table with the broadcast address */
+ memset(tp->setup_frame, 0xff, 96*sizeof(u16));
+ /* re-fill the first 14 table entries with our address */
+ for(i=0; i<14; i++) {
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+
+ /* Put the setup frame on the Tx list. */
+ tp->tx_ring[0].length = 0x08000000 | 192;
+ /* Lie about the address of our setup frame to make the */
+ /* chip happy */
+ tp->tx_ring[0].buffer1 = (virt_to_bus(tp->setup_frame) + 4);
+ tp->tx_ring[0].status = DescOwned;
+
+ tp->cur_tx++;
+ }
+ outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+ outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+ tp->saved_if_port = dev->if_port;
+ if (dev->if_port == 0)
+ dev->if_port = tp->default_port;
+ if (tp->chip_id == DC21041 && dev->if_port > 4)
+ /* Invalid: Select initial TP, autosense, autonegotiate. */
+ dev->if_port = 4;
+
+ /* Allow selecting a default media. */
+ i = 0;
+ if (tp->mtable == NULL)
+ goto media_picked;
+ if (dev->if_port) {
+ int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
+ (dev->if_port == 12 ? 0 : dev->if_port);
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using user-specified media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ goto media_picked;
+ }
+ }
+ if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+ int looking_for = tp->mtable->defaultmedia & 15;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+ dev->name, medianame[looking_for]);
+ goto media_picked;
+ }
+ }
+ /* Start sensing first non-full-duplex media. */
+ for (i = tp->mtable->leafcount - 1;
+ (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
+ ;
+media_picked:
+
+ tp->csr6 = 0;
+ tp->cur_index = i;
+ if (dev->if_port == 0 && tp->chip_id == DC21142) {
+ if (tp->mii_cnt) {
+ select_media(dev, 1);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Using MII transceiver %d, status "
+ "%4.4x.\n",
+ dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
+ outl_CSR6(0x82020000, ioaddr, tp->chip_id);
+ tp->csr6 = 0x820E0000;
+ dev->if_port = 11;
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ } else
+ t21142_start_nway(dev);
+ } else if ((tp->chip_id == LC82C168 || tp->chip_id == PNIC2)
+ && tp->mii_cnt && ! tp->medialock) {
+ dev->if_port = 11;
+ tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0001, ioaddr + CSR15);
+ } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
+ && ! tp->medialock) {
+ dev->if_port = 0;
+ tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+ /* Provided by BOLO, Macronix - 12/10/1998. */
+ dev->if_port = 0;
+ tp->csr6 = 0x01880200;
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+ } else if (tp->chip_id == DC21143 &&
+ media_cap[dev->if_port] & MediaIsMII) {
+ /* We must reset the media CSRs when we force-select MII mode. */
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ } else if (tp->chip_id == X3201_3) {
+ outl(0x0008, ioaddr + CSR15);
+ udelay(5);
+ outl(0xa8050000, ioaddr + CSR15);
+ udelay(5);
+ outl(0xa00f0000, ioaddr + CSR15);
+ udelay(5);
+ tp->csr6 = 0x32400000;
+ } else if (tp->chip_id == COMET) {
+ dev->if_port = 0;
+ tp->csr6 = 0x00040000;
+ } else
+ select_media(dev, 1);
+
+ /* Start the chip's Tx to process setup frame. */
+ outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id);
+
+ /* Enable interrupts by setting the interrupt mask. */
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ outl(0, ioaddr + CSR2); /* Rx poll demand */
+
+ netif_start_queue (dev);
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+ dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+ inl(ioaddr + CSR6));
+ }
+ /* Set the timer to switch to check for link beat and perhaps switch
+ to an alternate media type. */
+ init_timer(&tp->timer);
+ tp->timer.expires = RUN_AT(5*HZ);
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+ add_timer(&tp->timer);
+}
+
+static int
+tulip_open(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
+ return -EAGAIN;
+
+ tulip_init_ring(dev);
+
+ tulip_up(dev);
+ tp->open = 1;
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+/* Set up the transceiver control registers for the selected media type. */
+static void select_media(struct net_device *dev, int startup)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ struct mediatable *mtable = tp->mtable;
+ u32 new_csr6;
+ int i;
+
+ if (mtable) {
+ struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+ unsigned char *p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: /* 21140 non-MII xcvr. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+ " with control setting %2.2x.\n",
+ dev->name, p[1]);
+ dev->if_port = p[0];
+ if (startup)
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ outl(p[1], ioaddr + CSR12);
+ new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+ break;
+ case 2: case 4: {
+ u16 setup[5];
+ u32 csr13val, csr14val, csr15dir, csr15val;
+ for (i = 0; i < 5; i++)
+ setup[i] = get_u16(&p[i*2 + 1]);
+
+ dev->if_port = p[0] & 15;
+ if (media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+
+ if (startup && mtable->has_reset) {
+ struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+ unsigned char *rst = rleaf->leafdata;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
+ dev->name);
+ for (i = 0; i < rst[0]; i++)
+ outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
+ "%4.4x/%4.4x.\n",
+ dev->name, medianame[dev->if_port], setup[0], setup[1]);
+ if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
+ csr13val = setup[0];
+ csr14val = setup[1];
+ csr15dir = (setup[3]<<16) | setup[2];
+ csr15val = (setup[4]<<16) | setup[2];
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ outl(csr13val, ioaddr + CSR13);
+ } else {
+ csr13val = 1;
+ csr14val = 0x0003FF7F;
+ csr15dir = (setup[0]<<16) | 0x0008;
+ csr15val = (setup[1]<<16) | 0x0008;
+ if (dev->if_port <= 4)
+ csr14val = t21142_csr14[dev->if_port];
+ if (startup) {
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ }
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ if (startup) outl(csr13val, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
+ dev->name, csr15dir, csr15val);
+ if (mleaf->type == 4)
+ new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+ else
+ new_csr6 = 0x82420000;
+ break;
+ }
+ case 1: case 3: {
+ int phy_num = p[0];
+ int init_length = p[1];
+ u16 *misc_info;
+ u16 to_advertise;
+
+ dev->if_port = 11;
+ new_csr6 = 0x020E0000;
+ if (mleaf->type == 3) { /* 21142 */
+ u16 *init_sequence = (u16*)(p+2);
+ u16 *reset_sequence = &((u16*)(p+3))[init_length];
+ int reset_length = p[2 + init_length*2];
+ misc_info = reset_sequence + reset_length;
+ if (startup)
+ for (i = 0; i < reset_length; i++)
+ outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+ for (i = 0; i < init_length; i++)
+ outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+ } else {
+ u8 *init_sequence = p + 2;
+ u8 *reset_sequence = p + 3 + init_length;
+ int reset_length = p[2 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (startup) {
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ for (i = 0; i < reset_length; i++)
+ outl(reset_sequence[i], ioaddr + CSR12);
+ }
+ for (i = 0; i < init_length; i++)
+ outl(init_sequence[i], ioaddr + CSR12);
+ }
+ to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+ tp->advertising[phy_num] = to_advertise;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
+ dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+ /* Bogus: put in by a committee? */
+ mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
+ break;
+ }
+ default:
+ printk(KERN_DEBUG "%s: Invalid media table selection %d.\n",
+ dev->name, mleaf->type);
+ new_csr6 = 0x020E0000;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12) & 0xff);
+ } else if (tp->chip_id == DC21041) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
+ dev->name, medianame[dev->if_port & 15],
+ inl(ioaddr + CSR12) & 0xffff);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ new_csr6 = 0x80020000;
+ } else if (tp->chip_id == LC82C168 || tp->chip_id == PNIC2) {
+ if (startup && ! tp->medialock)
+ dev->if_port = tp->mii_cnt ? 11 : 0;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
+ " media %s.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
+ medianame[dev->if_port]);
+ if (tp->mii_cnt) {
+ new_csr6 = 0x810C0000;
+ outl(0x0001, ioaddr + CSR15);
+ outl(0x0201B07A, ioaddr + 0xB8);
+ } else if (startup) {
+ /* Start with 10mbps to do autonegotiation. */
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x0001B078, ioaddr + 0xB8);
+ outl(0x0201B078, ioaddr + 0xB8);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ if (startup)
+ outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */
+ else
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ } else if (tp->chip_id == DC21040) { /* 21040 */
+ /* Turn on the xcvr interface. */
+ int csr12 = inl(ioaddr + CSR12);
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ if (media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ new_csr6 = 0x20000;
+ /* Set the full duplux match frame. */
+ outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ if (t21040_csr13[dev->if_port] & 8) {
+ outl(0x0705, ioaddr + CSR14);
+ outl(0x0006, ioaddr + CSR15);
+ } else {
+ outl(0xffff, ioaddr + CSR14);
+ outl(0x0000, ioaddr + CSR15);
+ }
+ outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
+ } else if (tp->chip_id == X3201_3) { /* Xircom */
+ if (tp->default_port == 0)
+ dev->if_port = tp->mii_cnt ? 11 : 3;
+/* Someone is on crack, the Xircom only does MII, no Fx */
+/* if (media_cap[dev->if_port] & MediaIsMII) {
+ new_csr6 = 0x020E0000;
+ } else if (media_cap[dev->if_port] & MediaIsFx) {
+ new_csr6 = 0x028600000;
+ } else
+ new_csr6 = 0x038600000;*/
+ new_csr6 = 0x324c0000;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Xircom CardBus Adapter: "
+ "%s transceiver, CSR12 %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12));
+ } else { /* Unknown chip type with no media table. */
+ if (tp->default_port == 0)
+ dev->if_port = tp->mii_cnt ? 11 : 3;
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ new_csr6 = 0x020E0000;
+ } else if (media_cap[dev->if_port] & MediaIsFx) {
+ new_csr6 = 0x028600000;
+ } else
+ new_csr6 = 0x038600000;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No media description table, assuming "
+ "%s transceiver, CSR12 %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12));
+ }
+
+ tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+ return;
+}
+
+/*
+ Check the MII negotiated duplex, and change the CSR6 setting if
+ required.
+ Return 0 if everything is OK.
+ Return < 0 if the transceiver is missing or has no link beat.
+ */
+static int check_duplex(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int mii_reg1, mii_reg5, negotiated, duplex;
+
+ if (tp->full_duplex_lock)
+ return 0;
+ mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+ mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+ "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+ if (mii_reg1 == 0xffff)
+ return -2;
+ if ((mii_reg1 & 0x0004) == 0) {
+ int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+ if ((new_reg1 & 0x0004) == 0) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: No link beat on the MII interface,"
+ " status %4.4x.\n", dev->name, new_reg1);
+ return -1;
+ }
+ }
+ negotiated = mii_reg5 & tp->advertising[0];
+ duplex = ((negotiated & 0x0300) == 0x0100
+ || (negotiated & 0x00C0) == 0x0040);
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ if (tp->full_duplex) tp->csr6 |= 0x0200;
+ else tp->csr6 &= ~0x0200;
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ if (tulip_debug > 0)
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+ "#%d link partner capability of %4.4x.\n",
+ dev->name, tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ }
+ return 0;
+}
+
+static void tulip_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u32 csr12 = inl(ioaddr + CSR12);
+ int next_tick = 2*HZ;
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x "
+ "SIA %8.8x %8.8x %8.8x %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6),
+ csr12, inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ }
+ switch (tp->chip_id) {
+ case DC21040:
+ if (!tp->medialock && csr12 & 0x0002) { /* Network error */
+ printk(KERN_INFO "%s: No link beat found.\n",
+ dev->name);
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ select_media(dev, 0);
+ dev->trans_start = jiffies;
+ }
+ break;
+ case DC21041:
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
+ dev->name, csr12);
+ switch (dev->if_port) {
+ case 0: case 3: case 4:
+ if (csr12 & 0x0004) { /*LnkFail */
+ /* 10baseT is dead. Check for activity on alternate port. */
+ tp->mediasense = 1;
+ if (csr12 & 0x0200)
+ dev->if_port = 2;
+ else
+ dev->if_port = 1;
+ printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
+ dev->name, medianame[dev->if_port]);
+ outl(0, ioaddr + CSR13); /* Reset */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ next_tick = 10*HZ; /* 2.4 sec. */
+ } else
+ next_tick = 30*HZ;
+ break;
+ case 1: /* 10base2 */
+ case 2: /* AUI */
+ if (csr12 & 0x0100) {
+ next_tick = (30*HZ); /* 30 sec. */
+ tp->mediasense = 0;
+ } else if ((csr12 & 0x0004) == 0) {
+ printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
+ dev->name);
+ dev->if_port = 0;
+ select_media(dev, 0);
+ next_tick = (24*HZ)/10; /* 2.4 sec. */
+ } else if (tp->mediasense || (csr12 & 0x0002)) {
+ dev->if_port = 3 - dev->if_port; /* Swap ports. */
+ select_media(dev, 0);
+ next_tick = 20*HZ;
+ } else {
+ next_tick = 20*HZ;
+ }
+ break;
+ }
+ break;
+ case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
+ struct medialeaf *mleaf;
+ unsigned char *p;
+ if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
+ /* Not much that can be done.
+ Assume this a generic MII or SYM transceiver. */
+ next_tick = 60*HZ;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+ "CSR12 0x%2.2x.\n",
+ dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+ break;
+ }
+ mleaf = &tp->mtable->mleaf[tp->cur_index];
+ p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: case 4: {
+ /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */
+ int offset = mleaf->type == 4 ? 5 : 2;
+ s8 bitnum = p[offset];
+ if (p[offset+1] & 0x80) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG"%s: Transceiver monitor tick "
+ "CSR12=%#2.2x, no media sense.\n",
+ dev->name, csr12);
+ if (mleaf->type == 4) {
+ if (mleaf->media == 3 && (csr12 & 0x02))
+ goto select_next_media;
+ }
+ break;
+ }
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+ " bit %d is %d, expecting %d.\n",
+ dev->name, csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
+ /* Check that the specified bit has the proper value. */
+ if ((bitnum < 0) !=
+ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+ medianame[mleaf->media]);
+ if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
+ goto actually_mii;
+ break;
+ }
+ if (tp->medialock)
+ break;
+ select_next_media:
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+ if (media_cap[dev->if_port] & MediaIsFD)
+ goto select_next_media; /* Skip FD entries. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No link beat on media %s,"
+ " trying transceiver type %s.\n",
+ dev->name, medianame[mleaf->media & 15],
+ medianame[tp->mtable->mleaf[tp->cur_index].media]);
+ select_media(dev, 0);
+ /* Restart the transmit process. */
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ next_tick = (24*HZ)/10;
+ break;
+ }
+ case 1: case 3: /* 21140, 21142 MII */
+ actually_mii:
+ check_duplex(dev);
+ next_tick = 60*HZ;
+ break;
+ case 2: /* 21142 serial block has no link beat. */
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+ of available transceivers. */
+static void t21142_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = 0;
+
+ if ((tulip_debug > 2) && !(media_cap[dev->if_port] & MediaIsMII))
+ printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
+ dev->name, csr12, medianame[dev->if_port]);
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ check_duplex(dev);
+ next_tick = 60*HZ;
+ } else if (tp->nwayset) {
+ /* Don't screw up a negotiated session! */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ } else if (tp->medialock) {
+ ;
+ } else if (dev->if_port == 3) {
+ if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
+ "trying NWay.\n", dev->name, csr12);
+ t21142_start_nway(dev);
+ next_tick = 3*HZ;
+ }
+ } else if (((csr12 & 0x7000) != 0x5000)
+ && tp->chip_id != X3201_3) {
+ /* Negotiation failed. Search media types. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
+ dev->name, csr12);
+ if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ new_csr6 = 0x82420000;
+ dev->if_port = 0;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ } else {
+ /* Select 100mbps port to check for link beat. */
+ new_csr6 = 0x83860000;
+ dev->if_port = 3;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outw(8, ioaddr + CSR15);
+ outl(1, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+ tp->csr6 &= 0x00D5;
+ tp->csr6 |= new_csr6;
+ outl(0x0301, ioaddr + CSR12);
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ next_tick = 3*HZ;
+ }
+ if (tp->cur_tx - tp->dirty_tx > 0 &&
+ jiffies - dev->trans_start > TX_TIMEOUT) {
+ printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n",
+ dev->name, tp->cur_tx, tp->dirty_tx);
+ tulip_tx_timeout(dev);
+ }
+
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void t21142_start_nway(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr14 = ((tp->to_advertise & 0x0180) << 9) |
+ ((tp->to_advertise&0x0020)<<1) | 0xffbf;
+
+ dev->if_port = 0;
+ tp->nway = tp->mediasense = 1;
+ tp->nwayset = tp->lpar = 0;
+ if (debug > 1)
+ printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
+ dev->name, csr14);
+ outl(0x0001, ioaddr + CSR13);
+ outl(csr14, ioaddr + CSR14);
+ tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+ outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
+ if (tp->mtable && tp->mtable->csr15dir) {
+ outl(tp->mtable->csr15dir, ioaddr + CSR15);
+ outl(tp->mtable->csr15val, ioaddr + CSR15);
+ } else
+ outw(0x0008, ioaddr + CSR15);
+ outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
+}
+
+static void t21142_lnk_change(struct net_device *dev, int csr5)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
+ "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
+
+ /* If NWay finished and we have a negotiated partner capability. */
+ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
+ int setup_done = 0;
+ tp->lpar = csr12 >> 16;
+ tp->nwayset = 1;
+ if (csr12 & 0x01000000) dev->if_port = 5;
+ else if (csr12 & 0x00800000) dev->if_port = 3;
+ else if (csr12 & 0x00400000) dev->if_port = 4;
+ else if (csr12 & 0x00200000) dev->if_port = 0;
+ else {
+ tp->nwayset = 0;
+ if ( ! (csr12 & 2)) dev->if_port = 3;
+ else if ( ! (csr12 & 4)) dev->if_port = 0;
+ }
+ tp->full_duplex = (media_cap[tp->default_port] & MediaAlwaysFD) ? 1:0;
+
+ if (tulip_debug > 1) {
+ if (tp->nwayset)
+ printk(KERN_INFO "%s: Switching to %s based on link partner "
+ "advertisement %4.4x.\n",
+ dev->name, medianame[dev->if_port], tp->lpar);
+ else
+ printk(KERN_INFO "%s: Switching to %s based on link beat "
+ "status of %4.4x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ }
+
+ if (tp->mtable) {
+ int i;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == dev->if_port) {
+ tp->cur_index = i;
+ select_media(dev, 0);
+ setup_done = 1;
+ break;
+ }
+ }
+ if ( ! setup_done) {
+ tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
+ if (tp->full_duplex)
+ tp->csr6 |= 0x0200;
+ outw(0x0000, ioaddr + CSR13);
+ outw(0x0000, ioaddr + CSR14);
+ }
+ outl_CSR6(tp->csr6 | 0x0000, ioaddr, tp->chip_id);
+ if (debug > 2)
+ printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5));
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ } else if ((tp->nwayset && (csr5 & 0x08000000)
+ && (dev->if_port == 3 || dev->if_port == 5)
+ && (csr12 & 2) == 2) ||
+ (tp->nway && (csr5 & (TPLnkFail)))) {
+ /* Link blew? Maybe restart NWay. */
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
+ dev->name, medianame[dev->if_port],
+ (csr12 & 2) ? "failed" : "good");
+ if ((csr12 & 2) && ! tp->medialock) {
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ }
+ } else if (dev->if_port == 0 || dev->if_port == 4) {
+ if ((csr12 & 4) == 0)
+ printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
+ dev->name);
+ } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
+ dev->name);
+ dev->if_port = 0;
+ } else if (tp->nwayset) {
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
+ dev->name, medianame[dev->if_port], tp->csr6);
+ } else { /* 100mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
+ dev->name);
+ dev->if_port = 3;
+ tp->csr6 = 0x83860000;
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outl(0x0301, ioaddr + CSR12);
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+}
+
+static void mxic_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 3) {
+ printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+ inl(ioaddr + CSR12));
+ }
+ if (next_tick) {
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+ }
+}
+
+static void pnic_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = tp->csr6 & ~0x40C40200;
+
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC negotiated capability %8.8x, "
+ "CSR5 %8.8x.\n",
+ dev->name, negotiated, inl(ioaddr + CSR5));
+
+ if (negotiated & 0x0380) /* 10 vs 100mbps */
+ new_csr6 |= 0x810E0000;
+ else
+ new_csr6 |= 0x814E0000;
+ if (((negotiated & 0x0300) == 0x0100) /* Duplex */
+ || (negotiated & 0x00C0) == 0x0040
+ || tp->full_duplex_lock) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x0200;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC MII PHY status %4.4x, Link "
+ "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
+ dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
+ tp->csr6, inl(ioaddr + CSR6));
+ } else {
+ int phy_reg = inl(ioaddr + 0xB8);
+ int csr5 = inl(ioaddr + CSR5);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC PHY status %8.8x, CSR5 %8.8x.\n",
+ dev->name, phy_reg, csr5);
+
+ if (phy_reg & 0x04000000) { /* Remote link fault */
+ /*outl(0x0201F078, ioaddr + 0xB8);*/
+ next_tick = 3*HZ;
+ }
+ if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+ "CSR5 %8.8x, PHY %3.3x.\n",
+ dev->name, medianame[dev->if_port], csr12,
+ inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+ if (tp->medialock) {
+ } else if (dev->if_port == 0) {
+ dev->if_port = 3;
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ dev->if_port = 0;
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ new_csr6 |= (tp->csr6 & 0xfdff);
+ next_tick = 3*HZ;
+ } else
+ new_csr6 = tp->csr6;
+ if (tp->full_duplex_lock || (phy_reg & 0x30000000) != 0) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x00000200;
+ }
+ }
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); /* Restart Tx */
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ dev->trans_start = jiffies;
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
+ "CSR6 %8.8x.\n",
+ dev->name, tp->full_duplex ? "full" : "half", new_csr6);
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void comet_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
+ "%4.4x.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void tulip_tx_timeout(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ } else if (tp->chip_id == DC21040) {
+ if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ printk(KERN_INFO "%s: transmit timed out, switching to "
+ "%s.\n",
+ dev->name, medianame[dev->if_port]);
+ select_media(dev, 0);
+ }
+ dev->trans_start = jiffies;
+ return;
+ } else if (tp->chip_id == DC21041) {
+ int csr12 = inl(ioaddr + CSR12);
+
+ printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+ "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), csr12,
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+ tp->mediasense = 1;
+ if ( ! tp->medialock) {
+ if (dev->if_port == 1 || dev->if_port == 2)
+ if (csr12 & 0x0004) {
+ dev->if_port = 2 - dev->if_port;
+ } else
+ dev->if_port = 0;
+ else
+ dev->if_port = 1;
+ select_media(dev, 0);
+ }
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+ || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ if ( ! tp->medialock && tp->mtable) {
+ do
+ --tp->cur_index;
+ while (tp->cur_index >= 0
+ && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
+ & MediaIsFD));
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ select_media(dev, 0);
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+ "media.\n", dev->name, medianame[dev->if_port]);
+ }
+ } else {
+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+ "%8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+ dev->if_port = 0;
+ }
+
+#if defined(way_too_many_messages)
+ if (tulip_debug > 3) {
+ int i;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+ int j;
+ printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x "
+ "%2.2x %2.2x %2.2x.\n",
+ i, (unsigned int)tp->rx_ring[i].status,
+ (unsigned int)tp->rx_ring[i].length,
+ (unsigned int)tp->rx_ring[i].buffer1,
+ (unsigned int)tp->rx_ring[i].buffer2,
+ buf[0], buf[1], buf[2]);
+ for (j = 0; buf[j] != 0xee && j < 1600; j++)
+ if (j < 100) printk(" %2.2x", buf[j]);
+ printk(" j=%d.\n", j);
+ }
+ printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+ printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+ printk("\n");
+ }
+#endif
+
+ /* Stop and restart the chip's Tx processes . */
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+ tp->stats.tx_errors++;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void tulip_init_ring(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+
+ tp->tx_full = 0;
+ tp->cur_rx = tp->cur_tx = 0;
+ tp->dirty_rx = tp->dirty_tx = 0;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ tp->rx_ring[i].status = 0x00000000;
+ tp->rx_ring[i].length = PKT_BUF_SZ;
+ tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
+ tp->rx_skbuff[i] = NULL;
+ }
+ /* Mark the last entry as wrapping the ring. */
+ tp->rx_ring[i-1].length = PKT_BUF_SZ | DESC_RING_WRAP;
+ tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ /* Note the receive buffer must be longword aligned.
+ dev_alloc_skb() provides 16 byte alignment. But do *not*
+ use skb_reserve() to align the IP header! */
+ struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+ tp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[i].status = DescOwned; /* Owned by Tulip chip */
+ tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+ }
+ tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+ /* The Tx buffer descriptor is filled in as needed, but we
+ do need to clear the ownership bit. */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ tp->tx_skbuff[i] = 0;
+ tp->tx_ring[i].status = 0x00000000;
+ tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
+#ifdef CARDBUS
+ if (tp->chip_id == X3201_3)
+ tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
+#endif CARDBUS
+ }
+ tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
+}
+
+static int
+tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry;
+ u32 flag;
+
+ /* Caution: the write order is important here, set the base address
+ with the "ownership" bits last. */
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % TX_RING_SIZE;
+
+ tp->tx_skbuff[entry] = skb;
+#ifdef CARDBUS
+ if (tp->chip_id == X3201_3) {
+ memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
+ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
+ } else
+#endif
+ tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+
+ if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+ flag = 0x60000000; /* No interrupt */
+ } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+ flag = 0xe0000000; /* Tx-done intr. */
+ } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+ flag = 0x60000000; /* No Tx-done intr. */
+ } else {
+ /* Leave room for set_rx_mode() to fill entries. */
+ flag = 0xe0000000; /* Tx-done intr. */
+ tp->tx_full = 1;
+ }
+ if (entry == TX_RING_SIZE-1)
+ flag |= 0xe0000000 | DESC_RING_WRAP;
+
+ tp->tx_ring[entry].length = skb->len | flag;
+ tp->tx_ring[entry].status = DescOwned; /* Pass ownership to the chip. */
+ tp->cur_tx++;
+ if (tp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
+
+ /* Trigger an immediate transmit demand. */
+ outl(0, dev->base_addr + CSR1);
+
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr5, work_budget = max_interrupt_work;
+
+ spin_lock (&tp->lock);
+
+ do {
+ csr5 = inl(ioaddr + CSR5);
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
+ dev->name, csr5, inl(dev->base_addr + CSR5));
+
+ if (csr5 == 0xffffffff)
+ break; /* all bits set, assume PCMCIA card removed */
+
+ if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+ break;
+
+ if (csr5 & (RxIntr | RxNoBuf))
+ work_budget -= tulip_rx(dev);
+
+ if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+ unsigned int dirty_tx;
+
+ for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+ dirty_tx++) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ int status = tp->tx_ring[entry].status;
+
+ if (status < 0)
+ break; /* It still hasn't been Txed */
+ /* Check for Rx filter setup frames. */
+ if (tp->tx_skbuff[entry] == NULL)
+ continue;
+
+ if (status & 0x8000) {
+ /* There was an major error, log it. */
+#ifndef final_version
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, status);
+#endif
+ tp->stats.tx_errors++;
+ if (status & 0x4104) tp->stats.tx_aborted_errors++;
+ if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+ if (status & 0x0200) tp->stats.tx_window_errors++;
+ if (status & 0x0002) tp->stats.tx_fifo_errors++;
+ if ((status & 0x0080) && tp->full_duplex == 0)
+ tp->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+ if (status & 0x0100) tp->stats.collisions16++;
+#endif
+ } else {
+#ifdef ETHER_STATS
+ if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+ tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+ tp->stats.collisions += (status >> 3) & 15;
+ tp->stats.tx_packets++;
+ }
+
+ /* Free the original skb. */
+ dev_kfree_skb_irq(tp->tx_skbuff[entry]);
+ tp->tx_skbuff[entry] = 0;
+ }
+
+#ifndef final_version
+ if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
+ printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+ dirty_tx += TX_RING_SIZE;
+ }
+#endif
+
+ if (tp->tx_full &&
+ tp->cur_tx - dirty_tx < TX_RING_SIZE - 2)
+ /* The ring is no longer full */
+ tp->tx_full = 0;
+
+ if (tp->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
+
+ tp->dirty_tx = dirty_tx;
+ if (csr5 & TxDied) {
+ if (tulip_debug > 2)
+ printk(KERN_WARNING "%s: The transmitter stopped."
+ " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+ dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ }
+
+ /* Log errors. */
+ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
+ if (csr5 == 0xffffffff)
+ break;
+ if (csr5 & TxJabber) tp->stats.tx_errors++;
+ if (csr5 & TxFIFOUnderflow) {
+ if ((tp->csr6 & 0xC000) != 0xC000)
+ tp->csr6 += 0x4000; /* Bump up the Tx threshold */
+ else
+ tp->csr6 |= 0x00200000; /* Store-n-forward. */
+ /* Restart the transmit process. */
+ outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ if (csr5 & RxDied) { /* Missed a Rx frame. */
+ tp->stats.rx_errors++;
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+ }
+ if (csr5 & TimerInt) {
+ if (tulip_debug > 2)
+ printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+ dev->name, csr5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+ }
+ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
+ if ( tp->chip_id == DC21142)
+ t21142_lnk_change(dev, csr5);
+ }
+ /* Clear all error sources, included undocumented ones! */
+ outl(0x0800f7ba, ioaddr + CSR5);
+ }
+ if (--work_budget < 0) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Too much work during an interrupt, "
+ "csr5=0x%8.8x.\n", dev->name, csr5);
+ /* Acknowledge all interrupt sources. */
+ outl(0x8001ffff, ioaddr + CSR5);
+#ifdef notdef
+ /* Clear all but standard interrupt sources. */
+ outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#endif
+ break;
+ }
+ } while (1);
+
+ if (tulip_debug > 3)
+ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
+ spin_unlock (&tp->lock);
+}
+
+static int
+tulip_rx(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry = tp->cur_rx % RX_RING_SIZE;
+ int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+ int work_done = 0;
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+ tp->rx_ring[entry].status);
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while (tp->rx_ring[entry].status >= 0) {
+ s32 status = tp->rx_ring[entry].status;
+
+ if (tulip_debug > 5)
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+ tp->rx_ring[entry].status);
+ if (--rx_work_limit < 0)
+ break;
+ if ((status & 0x38008300) != 0x0300) {
+ if ((status & 0x38000300) != 0x0300) {
+ /* Ingore earlier buffers. */
+ if ((status & 0xffff) != 0x7fff) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Oversized Ethernet frame "
+ "spanned multiple buffers, status %8.8x!\n",
+ dev->name, status);
+ tp->stats.rx_length_errors++;
+ }
+ } else if (status & RxDescFatalErr) {
+ /* There was a fatal error. */
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+ dev->name, status);
+ tp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x0890) tp->stats.rx_length_errors++;
+ if (status & 0x0004) tp->stats.rx_frame_errors++;
+ if (status & 0x0002) tp->stats.rx_crc_errors++;
+ if (status & 0x0001) tp->stats.rx_fifo_errors++;
+ }
+ } else {
+ /* Omit the four octet CRC from the length. */
+ short pkt_len = ((status >> 16) & 0x7ff) - 4;
+ struct sk_buff *skb;
+
+#ifndef final_version
+ if (pkt_len > 1518) {
+ printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+ dev->name, pkt_len, pkt_len);
+ pkt_len = 1518;
+ tp->stats.rx_length_errors++;
+ }
+#endif
+ /* Check if the packet is long enough to accept without copying
+ to a minimally-sized skbuff. */
+ if (pkt_len < rx_copybreak
+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP header */
+#if ! defined(__alpha__)
+ eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+ pkt_len, 0);
+ skb_put(skb, pkt_len);
+#else
+ memcpy(skb_put(skb, pkt_len),
+ bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
+#endif
+ work_done++;
+ } else { /* Pass up the skb already on the Rx ring. */
+ char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
+ tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+ if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+ "do not match in tulip_rx: %p vs. %p / %p.\n",
+ dev->name, bus_to_virt(tp->rx_ring[entry].buffer1),
+ skb->head, temp);
+#endif
+ }
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ tp->stats.rx_packets++;
+ tp->stats.rx_bytes += pkt_len;
+ }
+ entry = (++tp->cur_rx) % RX_RING_SIZE;
+ }
+
+ /* Refill the Rx ring buffers. */
+ for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+ work_done++;
+ }
+ tp->rx_ring[entry].status = DescOwned;
+ }
+
+ return work_done;
+}
+
+static void
+tulip_down(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ outl(0x00000000, ioaddr + CSR7);
+ /* Stop the chip's Tx and Rx processes. */
+ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, tp->chip_id);
+ /* 21040 -- Leave the card in 10baseT state. */
+ if (tp->chip_id == DC21040)
+ outl(0x00000004, ioaddr + CSR13);
+
+ if (inl(ioaddr + CSR6) != 0xffffffff)
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+ dev->if_port = tp->saved_if_port;
+}
+
+static int
+tulip_close(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
+ netif_stop_queue(dev);
+
+ if (netif_device_present(dev))
+ tulip_down(dev);
+
+ del_timer(&tp->timer);
+
+ free_irq(dev->irq, dev);
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = tp->rx_skbuff[i];
+ tp->rx_skbuff[i] = 0;
+ tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
+ tp->rx_ring[i].length = 0;
+ tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+ if (skb) {
+ dev_kfree_skb(skb);
+ }
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (tp->tx_skbuff[i])
+ dev_kfree_skb(tp->tx_skbuff[i]);
+ tp->tx_skbuff[i] = 0;
+ }
+
+ MOD_DEC_USE_COUNT;
+ tp->open = 0;
+ return 0;
+}
+
+static struct net_device_stats *tulip_get_stats(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+
+ if (netif_device_present(dev))
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+ return &tp->stats;
+}
+
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u16 *data = (u16 *)&rq->ifr_data;
+ int phy = tp->phys[0] & 0x1f;
+ long flags;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ if (tp->mii_cnt)
+ data[0] = phy;
+ else if (tp->chip_id == DC21142) /* 21142 pseudo-MII */
+ data[0] = 32;
+ else if (tp->chip_id == PNIC2)
+ data[0] = 32;
+ else if (tp->chip_id == COMET)
+ data[0] = 1;
+ else
+ return -ENODEV;
+ return 0;
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ if (data[0] == 32 &&
+ (tp->chip_id == DC21142 || tp->chip_id == PNIC2)) {
+ int csr12 = inl(ioaddr + CSR12);
+ int csr14 = inl(ioaddr + CSR14);
+ switch (data[1]) {
+ case 0: {
+ data[3] = (csr14<<5) & 0x1000;
+ break; }
+ case 1:
+ data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+ + (csr12&0x06 ? 0x04 : 0);
+ break;
+ case 4: {
+ data[3] = ((csr14>>9)&0x0380) +
+ ((inl(ioaddr + CSR6)>>3)&0x0040) +((csr14>>1)&0x20) + 1;
+ break;
+ }
+ case 5: data[3] = csr12 >> 16; break;
+ default: data[3] = 0; break;
+ }
+ } else {
+ save_flags(flags);
+ cli();
+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+ restore_flags(flags);
+ }
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+#if defined(CAP_NET_ADMIN)
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+#else
+ if (!suser())
+ return -EPERM;
+#endif
+ if (data[0] == 32 && tp->chip_id == DC21142) {
+ if (data[1] == 5)
+ tp->to_advertise = data[2];
+ } else {
+ save_flags(flags);
+ cli();
+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ restore_flags(flags);
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return -EOPNOTSUPP;
+}
+#endif /* HAVE_PRIVATE_IOCTL */
+
+/* Set or clear the multicast filter for this adaptor.
+ Note that we only use exclusion around actually queueing the
+ new frame, not around filling tp->setup_frame. This is non-deterministic
+ when re-entered but still correct. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+ N.B. Do not use for bulk data, use a table-based routine instead.
+ This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline u32 ether_crc_le(int length, unsigned char *data)
+{
+ u32 crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+ int crc = -1;
+
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+ }
+ return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ tp->csr6 &= ~0x00D5;
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ tp->csr6 |= 0x00C0;
+ csr6 |= 0x00C0;
+ /* Unconditionally log net taps. */
+ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter well -- accept all multicasts. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) {
+ /* Some work-alikes have only a 64-entry hash filter table. */
+ /* Should verify correctness on big-endian/__powerpc__ */
+ struct dev_mc_list *mclist;
+ int i;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else {
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+ if (tp->chip_id == AX88140) {
+ outl(2, ioaddr + CSR13);
+ outl(mc_filter[0], ioaddr + CSR14);
+ outl(3, ioaddr + CSR13);
+ outl(mc_filter[1], ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+ outl(mc_filter[0], ioaddr + 0xAC);
+ outl(mc_filter[1], ioaddr + 0xB0);
+ }
+ }
+ } else {
+ u16 *eaddrs, *setup_frm = tp->setup_frame;
+ struct dev_mc_list *mclist;
+ u32 tx_flags = 0x08000000 | 192;
+ int i;
+
+ /* Note that only the low-address shortword of setup_frame is valid!
+ The values are doubled for big-endian architectures. */
+ if ((dev->mc_count > 14) || ((dev->mc_count > 6) && (tp->chip_id == X3201_3))) { /* Must use a multicast hash table. */
+ u16 hash_table[32];
+ tx_flags = 0x08400000 | 192; /* Use hash filter. */
+ memset(hash_table, 0, sizeof(hash_table));
+ set_bit(255, hash_table); /* Broadcast entry */
+ /* This should work on big-endian machines as well. */
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+ hash_table);
+ for (i = 0; i < 32; i++) {
+ *setup_frm++ = hash_table[i];
+ *setup_frm++ = hash_table[i];
+ }
+ setup_frm = &tp->setup_frame[13*6];
+ } else if(tp->chip_id != X3201_3) {
+ /* We have <= 14 addresses so we can use the wonderful
+ 16 address perfect filtering of the Tulip. */
+ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+ /* Fill the unused entries with the broadcast address. */
+ memset(setup_frm, 0xff, (15-i)*12);
+ setup_frm = &tp->setup_frame[15*6];
+ } else {
+ /* fill the first two table entries with our address */
+ eaddrs = (u16 *)dev->dev_addr;
+ for(i=0; i<2; i++) {
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+ /* Double fill each entry to accomodate chips that */
+ /* don't like to parse these correctly */
+ for (i=0, mclist=dev->mc_list; i<dev->mc_count;
+ i++, mclist=mclist->next) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ }
+ i=((i+1)*2);
+ /* Fill the unused entries with the broadcast address. */
+ memset(setup_frm, 0xff, (15-i)*12);
+ setup_frm = &tp->setup_frame[15*6];
+ }
+
+ /* Fill the final entry with our physical address. */
+ eaddrs = (u16 *)dev->dev_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ /* Now add this frame to the Tx list. */
+ if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
+ /* Same setup recently queued, we need not add it. */
+ } else {
+ unsigned long flags;
+ unsigned int entry, dummy = -1;
+
+ save_flags(flags); cli();
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+
+ if (entry != 0) {
+ /* Avoid a chip errata by prefixing a dummy entry. */
+ tp->tx_skbuff[entry] = 0;
+ tp->tx_ring[entry].length =
+ (entry == TX_RING_SIZE-1) ? DESC_RING_WRAP : 0;
+ tp->tx_ring[entry].buffer1 = 0;
+ /* race with chip, set DescOwned later */
+ dummy = entry;
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+ }
+
+ tp->tx_skbuff[entry] = 0;
+ /* Put the setup frame on the Tx list. */
+ if (entry == TX_RING_SIZE-1)
+ tx_flags |= DESC_RING_WRAP; /* Wrap ring. */
+ tp->tx_ring[entry].length = tx_flags;
+ if(tp->chip_id == X3201_3)
+ tp->tx_ring[entry].buffer1 = (virt_to_bus(tp->setup_frame) + 4);
+ else
+ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
+ tp->tx_ring[entry].status = DescOwned;
+ if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+ tp->tx_full = 1;
+ netif_stop_queue (dev);
+ }
+ if (dummy >= 0)
+ tp->tx_ring[dummy].status = DescOwned;
+ restore_flags(flags);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+ }
+ }
+ outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id);
+}
+
+static struct pci_device_id tulip_pci_table[] __devinitdata = {
+#if 0 /* these entries conflict with regular tulip driver */
+ { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
+ { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
+ { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21142 },
+ { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
+ { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
+ { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
+ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
+#endif
+ { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ {0},
+};
+
+MODULE_DEVICE_TABLE(pci, tulip_pci_table);
+
+static int __devinit tulip_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct net_device *dev;
+ static int board_idx = 0;
+
+ printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
+
+ pci_enable_device (pdev);
+ pci_set_master (pdev);
+ dev = tulip_probe1(pdev, NULL,
+ pci_resource_start (pdev, 0), pdev->irq,
+ id->driver_data, board_idx++);
+ if (dev) {
+ pdev->driver_data = dev;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static void tulip_suspend(struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ printk(KERN_INFO "tulip_suspend(%s)\n", dev->name);
+ if (tp->open) tulip_down(dev);
+}
+
+static void tulip_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ printk(KERN_INFO "tulip_resume(%s)\n", dev->name);
+ if (tp->open) tulip_up(dev);
+}
+
+static void __devexit tulip_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+ printk(KERN_INFO "tulip_detach(%s)\n", dev->name);
+ unregister_netdev(dev);
+ kfree(dev);
+ kfree(tp);
+}
+
+static struct pci_driver tulip_ops = {
+ name: "tulip_cb",
+ id_table: tulip_pci_table,
+ probe: tulip_pci_probe,
+ remove: tulip_remove,
+ suspend: tulip_suspend,
+ resume: tulip_resume
+};
+
+static int __init tulip_init(void)
+{
+ pci_register_driver(&tulip_ops);
+ return 0;
+}
+
+static __exit void tulip_exit(void)
+{
+ pci_unregister_driver(&tulip_ops);
+}
+
+module_init(tulip_init)
+module_exit(tulip_exit)
+
+
+/*
+ * Local variables:
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 64fafa17f..6508c56c2 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -1325,7 +1325,7 @@ static void __exit plip_cleanup_module (void)
static int parport_ptr = 0;
-static void __init plip_setup(char *str)
+static int __init plip_setup(char *str)
{
int ints[4];
@@ -1350,6 +1350,7 @@ static void __init plip_setup(char *str)
ints[1]);
}
}
+ return 1;
}
__setup("plip=", plip_setup);
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 8e8236e92..8ad1a2a16 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1650,6 +1650,6 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/*
* Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
* End:
*/
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 213905c3a..c7cb98318 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.c,v 1.16 2000/03/26 22:57:54 ralf Exp $
+/* $Id: sgiseeq.c,v 1.17 2000/03/27 23:02:57 ralf Exp $
*
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
@@ -32,6 +32,7 @@
#include <linux/skbuff.h>
#include <asm/sgi/sgihpc.h>
+#include <asm/sgi/sgint23.h>
#include <asm/sgialib.h>
#include "sgiseeq.h"
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index c3a552b43..41e15ff36 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -485,20 +485,24 @@ static void shaper_cache_update(struct hh_cache *hh, struct net_device *dev,
static int shaper_neigh_setup(struct neighbour *n)
{
+#ifdef CONFIG_INET
if (n->nud_state == NUD_NONE) {
n->ops = &arp_broken_ops;
n->output = n->ops->output;
}
+#endif
return 0;
}
static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
{
+#ifdef CONFIG_INET
if (p->tbl->family == AF_INET) {
p->neigh_setup = shaper_neigh_setup;
p->ucast_probes = 0;
p->mcast_probes = 0;
}
+#endif
return 0;
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index de0856020..5036b01af 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -12,10 +12,16 @@
Support and updates available at
http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html
+
+ LK1.1.1 (jgarzik):
+ - Use PCI driver interface
+ - Fix MOD_xxx races
+ - softnet fixups
+
*/
static const char *versionA =
-"starfire.c:v0.12 5/28/99 Written by Donald Becker\n",
+"starfire.c:v0.12+LK1.1.1 3/19/2000 Written by Donald Becker and others\n",
*versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n";
/* A few user-configurable values. These may be modified when a driver
@@ -26,7 +32,6 @@ static int interrupt_mitigation = 0x0;
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
static int mtu = 0;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
The Starfire has a 512 element hash table based on the Ethernet CRC. */
@@ -62,6 +67,9 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+#define PFX "starfire: "
+
+
#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
#warning You must compile this file with the correct options!
#warning See the last lines of the source file.
@@ -94,7 +102,6 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(min_pci_latency, "i");
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
@@ -196,38 +203,33 @@ enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int io_size;
- struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-static struct net_device *starfire_probe1(struct pci_dev *pdev, int pci_bus,
- int pci_devfn, long ioaddr,
- int irq, int chp_idx, int fnd_cnt);
#if 0
#define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */
#endif
#define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */
-static struct pci_id_info pci_tbl[] = {
- { "Adaptec Starfire 6915",
- 0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1},
- {0,}, /* 0 terminated list. */
+
+enum chipset {
+ CH_6915 = 0,
};
-/* A chip capabilities table, matching the entries in pci_tbl[] above. */
+static struct pci_device_id starfire_pci_tbl[] __devinitdata = {
+ { 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
+
+
+/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
enum chip_capability_flags {CanHaveMII=1, };
-struct chip_info {
+static struct chip_info {
char *chip_name;
int io_size;
int flags;
- void (*media_timer)(unsigned long data);
-} static skel_netdrv_tbl[] = {
- {"Adaptec Starfire 6915", 128, CanHaveMII, 0, },
+} netdrv_tbl[] = {
+ { "Adaptec Starfire 6915", 128, CanHaveMII },
};
@@ -322,8 +324,6 @@ struct netdev_private {
struct starfire_tx_desc *tx_ring;
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
- struct net_device *next_module; /* Link for devices of this type. */
- const char *product_name;
/* The addresses of rx/tx-in-place skbuffs. */
struct ring_info rx_info[RX_RING_SIZE];
struct ring_info tx_info[TX_RING_SIZE];
@@ -340,7 +340,6 @@ struct netdev_private {
/* Frequently used values: keep some adjacent for cache effect. */
int chip_id;
struct pci_dev *pdev;
- unsigned char pci_bus, pci_devfn;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
@@ -378,107 +377,62 @@ static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
-
-/* A list of our installed devices, for removing the driver module. */
-static struct net_device *root_net_dev = NULL;
-
-/* Ideally we would detect all network cards in slot order. That would
- be best done a central PCI probe dispatch, which wouldn't work
- well when dynamically adding drivers. So instead we detect just the
- cards we know about in slot order. */
-
-static int pci_etherdev_probe(struct pci_id_info pci_tbl[])
+static int __devinit starfire_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int cards_found = 0;
- int pci_index = 0;
- unsigned char pci_bus, pci_device_fn;
+ struct netdev_private *np;
+ int i, irq, option, chip_id = ent->driver_data;
struct net_device *dev;
-
- for (;pci_index < 0xff; pci_index++) {
- struct pci_dev *pdev;
- u16 vendor, device, pci_command, new_command;
- int chip_idx, irq;
- long pciaddr;
- long ioaddr;
-
- if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
- &pci_bus, &pci_device_fn)
- != PCIBIOS_SUCCESSFUL)
- break;
- pdev = pci_find_slot (pci_bus, pci_device_fn);
- if (!pdev) continue;
- vendor = pdev->vendor;
- device = pdev->device;
-
- for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
- if (vendor == pci_tbl[chip_idx].vendor_id
- && (device & pci_tbl[chip_idx].device_id_mask) ==
- pci_tbl[chip_idx].device_id)
- break;
- if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */
- continue;
-
- pciaddr = pdev->resource[0].start;
-#if defined(ADDR_64BITS) && defined(__alpha__)
- pciaddr |= ((long)pdev->base_address[1]) << 32;
-#endif
- irq = pdev->irq;
-
- if (debug > 2)
- printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
- pci_tbl[chip_idx].name, pciaddr, irq);
-
- if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) {
- if (check_region(pciaddr, pci_tbl[chip_idx].io_size))
- continue;
- ioaddr = pciaddr;
- } else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) {
- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
- pciaddr);
- continue;
- }
-
- pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
- new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled the"
- " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n",
- pci_bus, pci_device_fn, pci_command, new_command);
- pci_write_config_word(pdev, PCI_COMMAND, new_command);
- }
-
- dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr,
- irq, chip_idx, cards_found);
-
- if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
- u8 pci_latency;
- pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < min_pci_latency) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to %d clocks.\n",
- pci_latency, min_pci_latency);
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency);
- }
- }
- cards_found++;
+ static int card_idx = 0;
+ static int printed_version = 0;
+ long ioaddr;
+ int io_size = netdrv_tbl[chip_id].io_size;
+
+ ioaddr = pci_resource_start (pdev, 0);
+ if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
+ printk (KERN_ERR PFX "no PCI MEM resources, aborting\n");
+ return -ENODEV;
+ }
+
+ dev = init_etherdev(NULL, sizeof(*np));
+ if (!dev) {
+ printk (KERN_ERR PFX "cannot alloc etherdev, aborting\n");
+ return -ENOMEM;
+ }
+
+ irq = pdev->irq;
+
+ if (request_mem_region (ioaddr, io_size, dev->name) == NULL) {
+ printk (KERN_ERR PFX "resource 0x%x @ 0x%lx busy, aborting\n",
+ io_size, ioaddr);
+ goto err_out_free_netdev;
+ }
+
+ if (pci_enable_device (pdev)) {
+ printk (KERN_ERR PFX "cannot enable PCI device, aborting\n");
+ goto err_out_free_res;
+ }
+
+ ioaddr = (long) ioremap (ioaddr, io_size);
+ if (!ioaddr) {
+ printk (KERN_ERR PFX "cannot remap 0x%x @ 0x%lx, aborting\n",
+ io_size, ioaddr);
+ goto err_out_free_res;
}
- return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *
-starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_id, int card_idx)
-{
- struct netdev_private *np;
- int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
- struct net_device *dev = init_etherdev(NULL, 0);
-
- if (!dev)
- return NULL;
+ pci_set_master (pdev);
+
+ option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+ card_idx++;
+
+ if (!printed_version) {
+ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printed_version = 1;
+ }
- printk(KERN_INFO "%s: %s at 0x%lx, ",
- dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
+ printk (KERN_INFO "%s: %s at 0x%lx, ",
+ dev->name, netdrv_tbl[chip_id].chip_name, ioaddr);
/* Serial EEPROM reads are hidden by the hardware. */
for (i = 0; i < 6; i++)
@@ -500,18 +454,13 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
dev->base_addr = ioaddr;
dev->irq = irq;
- /* Make certain the descriptor lists are aligned. */
- np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 15) & ~15);
- memset(np, 0, sizeof(*np));
- dev->priv = np;
-
- np->next_module = root_net_dev;
- root_net_dev = dev;
+ /* private struct aligned and zeroed by init_etherdev */
+ np = dev->priv;
np->pdev = pdev;
- np->pci_bus = pci_bus;
- np->pci_devfn = pci_devfn;
np->chip_id = chip_id;
+
+ pdev->driver_data = dev;
if (dev->mem_start)
option = dev->mem_start;
@@ -533,7 +482,7 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
/* The chip-specific entries in the device structure. */
dev->open = &netdev_open;
dev->hard_start_xmit = &start_tx;
- dev->tx_timeout = tx_timeout;
+ dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->stop = &netdev_close;
dev->get_stats = &get_stats;
@@ -543,7 +492,7 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
if (mtu)
dev->mtu = mtu;
- if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) {
+ if (netdrv_tbl[np->chip_id].flags & CanHaveMII) {
int phy, phy_idx = 0;
for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
int mii_status = mdio_read(dev, phy, 1);
@@ -558,7 +507,14 @@ starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, i
np->mii_cnt = phy_idx;
}
- return dev;
+ return 0;
+
+err_out_free_res:
+ release_mem_region (ioaddr, io_size);
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+ return -ENODEV;
}
@@ -590,10 +546,13 @@ static int netdev_open(struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
+ MOD_INC_USE_COUNT;
/* Do we need to reset the chip??? */
- if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
- return -EAGAIN;
+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
/* Disable the Rx and Tx, and reset the chip. */
writel(0, ioaddr + GenCtrl);
@@ -624,11 +583,10 @@ static int netdev_open(struct net_device *dev)
if (np->rx_ring)
pci_free_consistent(np->pdev, PAGE_SIZE,
np->rx_ring, np->rx_ring_dma);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
- MOD_INC_USE_COUNT;
-
init_ring(dev);
/* Set the size of the Rx buffers. */
writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl);
@@ -691,6 +649,8 @@ static int netdev_open(struct net_device *dev)
/* Enable the Rx and Tx units. */
writel(0x000F, ioaddr + GenCtrl);
+ netif_start_queue(dev);
+
if (debug > 2)
printk(KERN_DEBUG "%s: Done netdev_open().\n",
dev->name);
@@ -762,6 +722,7 @@ static void netdev_timer(unsigned long data)
add_timer(&np->timer);
}
+
static void tx_timeout(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -783,15 +744,16 @@ static void tx_timeout(struct net_device *dev)
}
#endif
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
+ /* Perhaps we should reinitialize the hardware here. */
+ dev->if_port = 0;
+
+ /* Stop and restart the chip's Tx processes . */
+ /* XXX todo */
- /* Trigger an immediate transmit demand. */
+ /* Trigger an immediate transmit demand. */
+ /* XXX todo */
- netif_wake_queue(dev);
- np->stats.tx_errors++;
- return;
+ np->stats.tx_errors++;
}
@@ -849,8 +811,6 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
struct netdev_private *np = (struct netdev_private *)dev->priv;
unsigned entry;
- netif_stop_queue(dev);
-
/* Caution: the write order is important here, set the field
with the "ownership" bits last. */
@@ -883,10 +843,10 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
/* Update the producer index. */
writel(++entry, dev->base_addr + TxProducerIdx);
- if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1)
+ if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
np->tx_full = 1;
- if (! np->tx_full)
- netif_start_queue(dev);
+ netif_stop_queue(dev);
+ }
dev->trans_start = jiffies;
if (debug > 4) {
@@ -1347,56 +1307,69 @@ static int netdev_close(struct net_device *dev)
return 0;
}
-static int __init starfire_init_module (void)
+
+static void __devexit starfire_remove_one (struct pci_dev *pdev)
{
- if (debug) /* Emit version even if no cards detected. */
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-#ifdef CARDBUS
- register_driver(&etherdev_ops);
- return 0;
-#else
- if (pci_etherdev_probe(pci_tbl)) {
- printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n");
- return -ENODEV;
+ struct net_device *dev = pdev->driver_data;
+ struct netdev_private *np;
+
+ if (!dev) {
+ printk (KERN_WARNING "bug: removing starfire pci dev without driver\n");
+ return;
}
- return 0;
-#endif
+
+ np = dev->priv;
+
+ unregister_netdev(dev);
+ iounmap((char *)dev->base_addr);
+
+ if (np->tx_done_q)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->tx_done_q, np->tx_done_q_dma);
+ if (np->rx_done_q)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->rx_done_q, np->rx_done_q_dma);
+ if (np->tx_ring)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->tx_ring, np->tx_ring_dma);
+ if (np->rx_ring)
+ pci_free_consistent(np->pdev, PAGE_SIZE,
+ np->rx_ring, np->rx_ring_dma);
+
+ kfree(dev);
}
-static void __exit starfire_cleanup_module (void)
+
+static struct pci_driver starfire_driver = {
+ name: "starfire",
+ probe: starfire_init_one,
+ remove: starfire_remove_one,
+ id_table: starfire_pci_tbl,
+};
+
+
+static int __init starfire_init (void)
{
- struct net_device *next_dev;
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&starfire_driver);
+
+ MOD_DEC_USE_COUNT;
+
+ return rc;
+}
-#ifdef CARDBUS
- unregister_driver(&etherdev_ops);
-#endif
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_net_dev) {
- struct netdev_private *np =
- (struct netdev_private *)root_net_dev->priv;
- next_dev = np->next_module;
- unregister_netdev(root_net_dev);
- iounmap((char *)root_net_dev->base_addr);
- if (np->tx_done_q)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->tx_done_q, np->tx_done_q_dma);
- if (np->rx_done_q)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->rx_done_q, np->rx_done_q_dma);
- if (np->tx_ring)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->tx_ring, np->tx_ring_dma);
- if (np->rx_ring)
- pci_free_consistent(np->pdev, PAGE_SIZE,
- np->rx_ring, np->rx_ring_dma);
- kfree(root_net_dev);
- root_net_dev = next_dev;
- }
+static void __exit starfire_cleanup (void)
+{
+ pci_unregister_driver (&starfire_driver);
}
-module_init(starfire_init_module);
-module_exit(starfire_cleanup_module);
+
+module_init(starfire_init);
+module_exit(starfire_cleanup);
/*
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index a699391da..5c466ecf0 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -66,6 +66,12 @@
* network cleanup in 2.3.43pre7 (Tigran & myself)
* - Minor stuff.
*
+ * v1.5 March 22, 2000 - Fixed another timer bug that would hang the driver
+ * if no cable/link were present.
+ * - Cosmetic changes.
+ * - TODO: Port completely to new PCI/DMA API
+ * Auto-Neg fallback.
+ *
*******************************************************************************/
@@ -106,7 +112,7 @@ static int bbuf = 0;
static u8 *TLanPadBuffer;
static char TLanSignature[] = "TLAN";
static int TLanVersionMajor = 1;
-static int TLanVersionMinor = 4;
+static int TLanVersionMinor = 5;
static TLanAdapterEntry TLanAdapterList[] __initdata = {
@@ -430,7 +436,8 @@ static int __init tlan_probe(void)
}
- printk(KERN_INFO "TLAN: %d device(s) installed\n", TLanDevicesInstalled);
+ printk(KERN_INFO "TLAN: %d device%s installed\n",
+ TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s");
return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV);
}
@@ -839,8 +846,10 @@ static int TLan_Close(struct net_device *dev)
TLan_ReadAndClearStats( dev, TLAN_RECORD );
outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
- if ( priv->timer.function != NULL )
+ if ( priv->timer.function != NULL ) {
del_timer( &priv->timer );
+ priv->timer.function = NULL;
+ }
free_irq( dev->irq, dev );
TLan_FreeLists( dev );
TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name );
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index e0a339bfa..1714d34d1 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -58,6 +58,7 @@
* First release to the public
* 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing
* malloc free checks, reviewed code. <alan@redhat.com>
+ * 03/13/00 - Added spinlocks for smp
*
* To Do:
*
@@ -105,6 +106,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -121,7 +123,7 @@
* Official releases will only have an a.b.c version number format.
*/
-static char *version = "LanStreamer.c v0.1.0 12/10/99 - Mike Sullivan";
+static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan";
static char *open_maj_error[] = {
"No error", "Lobe Media Test", "Physical Insertion",
@@ -210,7 +212,7 @@ static int __init streamer_scan(struct net_device *dev)
/* Check to see if io has been allocated, if so, we've already done this card,
so continue on the card discovery loop */
- if (check_region(pci_device->resource[0].start, STREAMER_IO_SPACE))
+ if (check_region(pci_device->resource[0].start & (~3), STREAMER_IO_SPACE))
{
card_no++;
continue;
@@ -223,6 +225,8 @@ static int __init streamer_scan(struct net_device *dev)
break;
}
memset(streamer_priv, 0, sizeof(struct streamer_private));
+ init_waitqueue_head(&streamer_priv->srb_wait);
+ init_waitqueue_head(&streamer_priv->trb_wait);
#ifndef MODULE
dev = init_trdev(dev, 0);
if(dev==NULL)
@@ -238,11 +242,11 @@ static int __init streamer_scan(struct net_device *dev)
pci_device, dev, dev->priv);
#endif
dev->irq = pci_device->irq;
- dev->base_addr = pci_device->resource[0].start;
+ dev->base_addr = pci_device->resource[0].start & (~3);
dev->init = &streamer_init;
+ streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name;
streamer_priv->streamer_mmio = ioremap(pci_device->resource[1].start, 256);
- init_waitqueue_head(&streamer_priv->srb_wait);
- init_waitqueue_head(&streamer_priv->trb_wait);
+
if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000))
streamer_priv->pkt_buf_sz = PKT_BUF_SZ;
else
@@ -250,7 +254,6 @@ static int __init streamer_scan(struct net_device *dev)
streamer_priv->streamer_ring_speed = ringspeed[card_no];
streamer_priv->streamer_message_level = message_level[card_no];
- streamer_priv->streamer_multicast_set = 0;
if (streamer_init(dev) == -1) {
unregister_netdevice(dev);
@@ -274,7 +277,7 @@ static int __init streamer_scan(struct net_device *dev)
}
-static int __init streamer_init(struct net_device *dev)
+static int streamer_reset(struct net_device *dev)
{
struct streamer_private *streamer_priv;
__u8 *streamer_mmio;
@@ -286,12 +289,6 @@ static int __init streamer_init(struct net_device *dev)
streamer_priv = (struct streamer_private *) dev->priv;
streamer_mmio = streamer_priv->streamer_mmio;
- printk("%s \n", version);
- printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n",
- dev->name, (unsigned int) dev->base_addr,
- streamer_priv->streamer_mmio, dev->irq);
-
- request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer");
writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
t = jiffies;
/* Hold soft reset bit for a while */
@@ -330,11 +327,16 @@ static int __init streamer_init(struct net_device *dev)
printk(KERN_INFO "%s: skb allocation for diagnostics failed...proceeding\n",
dev->name);
} else {
- streamer_priv->streamer_rx_ring[0].forward = 0;
- streamer_priv->streamer_rx_ring[0].status = 0;
- streamer_priv->streamer_rx_ring[0].buffer = virt_to_bus(skb->data);
- streamer_priv->streamer_rx_ring[0].framelen_buflen = 512; /* streamer_priv->pkt_buf_sz; */
- writel(virt_to_bus(&streamer_priv->streamer_rx_ring[0]), streamer_mmio + RXBDA);
+ struct streamer_rx_desc *rx_ring;
+ u8 *data;
+
+ rx_ring=(struct streamer_rx_desc *)skb->data;
+ data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc);
+ rx_ring->forward=0;
+ rx_ring->status=0;
+ rx_ring->buffer=virt_to_bus(data);
+ rx_ring->framelen_buflen=512;
+ writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA);
}
#if STREAMER_DEBUG
@@ -382,7 +384,7 @@ static int __init streamer_init(struct net_device *dev)
writew(readw(streamer_mmio + LAPWWO) + 6, streamer_mmio + LAPA);
if (readw(streamer_mmio + LAPD)) {
printk(KERN_INFO "tokenring card intialization failed. errorcode : %x\n",
- readw(streamer_mmio + LAPD));
+ ntohs(readw(streamer_mmio + LAPD)));
release_region(dev->base_addr, STREAMER_IO_SPACE);
return -1;
}
@@ -398,17 +400,14 @@ static int __init streamer_init(struct net_device *dev)
#endif
/* setup uaa area for access with LAPD */
- writew(uaa_addr, streamer_mmio + LAPA);
-
- /* setup uaa area for access with LAPD */
{
int i;
__u16 addr;
writew(uaa_addr, streamer_mmio + LAPA);
for (i = 0; i < 6; i += 2) {
- addr = readw(streamer_mmio + LAPDINC);
- dev->dev_addr[i] = addr & 0xff;
- dev->dev_addr[i + 1] = (addr >> 8) & 0xff;
+ addr=ntohs(readw(streamer_mmio+LAPDINC));
+ dev->dev_addr[i]= (addr >> 8) & 0xff;
+ dev->dev_addr[i+1]= addr & 0xff;
}
#if STREAMER_DEBUG
printk("Adapter address: ");
@@ -421,6 +420,32 @@ static int __init streamer_init(struct net_device *dev)
return 0;
}
+static int __init streamer_init(struct net_device *dev)
+{
+ struct streamer_private *streamer_priv;
+ __u8 *streamer_mmio;
+ int rc;
+
+ streamer_priv=(struct streamer_private *)dev->priv;
+ streamer_mmio=streamer_priv->streamer_mmio;
+
+ spin_lock_init(&streamer_priv->streamer_lock);
+
+ printk("%s \n", version);
+ printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
+ streamer_priv->streamer_card_name,
+ (unsigned int) dev->base_addr,
+ streamer_priv->streamer_mmio,
+ dev->irq);
+
+ request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer");
+
+ rc=streamer_reset(dev);
+ return rc;
+}
+
+
+
static int streamer_open(struct net_device *dev)
{
struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
@@ -430,7 +455,11 @@ static int streamer_open(struct net_device *dev)
int i, open_finished = 1;
__u16 srb_word;
__u16 srb_open;
+ int rc;
+ if (readw(streamer_mmio+BMCTL_SUM) & BMCTL_RX_ENABLED) {
+ rc=streamer_reset(dev);
+ }
if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) {
return -EAGAIN;
@@ -461,23 +490,27 @@ static int streamer_open(struct net_device *dev)
writew(0, streamer_mmio + LAPDINC);
}
- writew(readw(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
- writew(SRB_OPEN_ADAPTER, streamer_mmio + LAPDINC); /* open */
+ writew(readw(streamer_mmio+LAPWWO),streamer_mmio+LAPA);
+ writew(htons(SRB_OPEN_ADAPTER<<8),streamer_mmio+LAPDINC) ; /* open */
+ writew(htons(STREAMER_CLEAR_RET_CODE<<8),streamer_mmio+LAPDINC);
writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
writew(readw(streamer_mmio + LAPWWO) + 8, streamer_mmio + LAPA);
#if STREAMER_NETWORK_MONITOR
/* If Network Monitor, instruct card to copy MAC frames through the ARB */
- writew(ntohs(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */
+ writew(htons(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), streamer_mmio + LAPDINC); /* offset 8 word contains open options */
#else
- writew(ntohs(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */
+ writew(htons(OPEN_ADAPTER_ENABLE_FDX), streamer_mmio + LAPDINC); /* Offset 8 word contains Open.Options */
#endif
if (streamer_priv->streamer_laa[0]) {
writew(readw(streamer_mmio + LAPWWO) + 12, streamer_mmio + LAPA);
- writew(((__u16 *) (streamer_priv->streamer_laa))[0], streamer_mmio + LAPDINC); /* offset 12 word */
- writew(((__u16 *) (streamer_priv->streamer_laa))[2], streamer_mmio + LAPDINC); /* offset 14 word */
- writew(((__u16 *) (streamer_priv->streamer_laa))[4], streamer_mmio + LAPDINC); /* offset 16 word */
+ writew(htons((streamer_priv->streamer_laa[0] << 8) |
+ streamer_priv->streamer_laa[1]),streamer_mmio+LAPDINC);
+ writew(htons((streamer_priv->streamer_laa[2] << 8) |
+ streamer_priv->streamer_laa[3]),streamer_mmio+LAPDINC);
+ writew(htons((streamer_priv->streamer_laa[4] << 8) |
+ streamer_priv->streamer_laa[5]),streamer_mmio+LAPDINC);
memcpy(dev->dev_addr, streamer_priv->streamer_laa, dev->addr_len);
}
@@ -526,7 +559,7 @@ static int streamer_open(struct net_device *dev)
* timed out.
*/
writew(srb_open + 2, streamer_mmio + LAPA);
- srb_word = readw(streamer_mmio + LAPD) & 0xFF;
+ srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF;
if (srb_word == STREAMER_CLEAR_RET_CODE) {
printk(KERN_WARNING "%s: Adapter Open time out or error.\n",
dev->name);
@@ -574,7 +607,7 @@ static int streamer_open(struct net_device *dev)
} while (!(open_finished)); /* Will only loop if ring speed mismatch re-open attempted && autosense is on */
writew(srb_open + 18, streamer_mmio + LAPA);
- srb_word = readw(streamer_mmio + LAPD) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8;
if (srb_word & (1 << 3))
if (streamer_priv->streamer_message_level)
printk(KERN_INFO "%s: Opened in FDX Mode\n", dev->name);
@@ -604,6 +637,14 @@ static int streamer_open(struct net_device *dev)
writew(~BMCTL_RX_DIS, streamer_mmio + BMCTL_RUM);
/* setup rx descriptors */
+ streamer_priv->streamer_rx_ring=
+ kmalloc( sizeof(struct streamer_rx_desc)*
+ STREAMER_RX_RING_SIZE,GFP_KERNEL);
+ if (!streamer_priv->streamer_rx_ring) {
+ printk(KERN_WARNING "%s ALLOC of streamer rx ring FAILED!!\n",dev->name);
+ return -EIO;
+ }
+
for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
struct sk_buff *skb;
@@ -638,6 +679,13 @@ static int streamer_open(struct net_device *dev)
/* setup tx ring */
+ streamer_priv->streamer_tx_ring=kmalloc(sizeof(struct streamer_tx_desc)*
+ STREAMER_TX_RING_SIZE,GFP_KERNEL);
+ if (!streamer_priv->streamer_tx_ring) {
+ printk(KERN_WARNING "%s ALLOC of streamer_tx_ring FAILED\n",dev->name);
+ return -EIO;
+ }
+
writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM); /* Enables TX channel 2 */
for (i = 0; i < STREAMER_TX_RING_SIZE; i++) {
streamer_priv->streamer_tx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_tx_ring[i + 1]);
@@ -776,7 +824,7 @@ static void streamer_rx(struct net_device *dev)
memcpy(skb_put(skb, length),bus_to_virt(rx_desc->buffer), length); /* copy this fragment */
streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0;
streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz;
- streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = virt_to_bus(skb->data);
+
/* give descriptor back to the adapter */
writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]), streamer_mmio + RXLBDA);
@@ -828,10 +876,14 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
misr = readw(streamer_mmio + MISR_RUM);
writew(~misr, streamer_mmio + MISR_RUM);
- if (!sisr) { /* Interrupt isn't for us */
+ if (!sisr)
+ { /* Interrupt isn't for us */
+ writew(~misr,streamer_mmio+MISR_RUM);
return;
}
+ spin_lock(&streamer_priv->streamer_lock);
+
if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY))
|| (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) {
if (sisr & SISR_SRB_REPLY) {
@@ -868,9 +920,9 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n",
dev->name, readw(streamer_mmio + LAPDINC),
- readw(streamer_mmio + LAPDINC),
- readw(streamer_mmio + LAPDINC),
- readw(streamer_mmio + LAPDINC));
+ ntohs(readw(streamer_mmio + LAPDINC)),
+ ntohs(readw(streamer_mmio + LAPDINC)),
+ ntohs(readw(streamer_mmio + LAPDINC)));
free_irq(dev->irq, dev);
}
@@ -907,17 +959,19 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} /* One if the interrupts we want */
writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+ spin_unlock(&streamer_priv->streamer_lock) ;
}
-
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct streamer_private *streamer_priv =
(struct streamer_private *) dev->priv;
__u8 *streamer_mmio = streamer_priv->streamer_mmio;
+ unsigned long flags ;
+ spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
netif_stop_queue(dev);
-
+
if (streamer_priv->free_tx_ring_entries) {
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
@@ -941,9 +995,11 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
- netif_start_queue(dev);
+ netif_wake_queue(dev);
+ spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
return 0;
} else {
+ spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
return 1;
}
}
@@ -957,9 +1013,10 @@ static int streamer_close(struct net_device *dev)
unsigned long flags;
int i;
+ netif_stop_queue(dev);
writew(streamer_priv->srb, streamer_mmio + LAPA);
- writew(SRB_CLOSE_ADAPTER, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
+ writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
save_flags(flags);
cli();
@@ -987,7 +1044,9 @@ static int streamer_close(struct net_device *dev)
streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
- dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]);
+ if (streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]) {
+ dev_kfree_skb(streamer_priv->rx_ring_skb[streamer_priv->rx_ring_last_received]);
+ }
streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
}
@@ -1003,11 +1062,10 @@ static int streamer_close(struct net_device *dev)
writew(streamer_priv->srb, streamer_mmio + LAPA);
printk("srb): ");
for (i = 0; i < 2; i++) {
- printk("%x ", htons(readw(streamer_mmio + LAPDINC)));
+ printk("%x ", ntohs(readw(streamer_mmio + LAPDINC)));
}
printk("\n");
#endif
- netif_stop_queue(dev);
free_irq(dev->irq, dev);
MOD_DEC_USE_COUNT;
@@ -1019,9 +1077,10 @@ static void streamer_set_rx_mode(struct net_device *dev)
struct streamer_private *streamer_priv =
(struct streamer_private *) dev->priv;
__u8 *streamer_mmio = streamer_priv->streamer_mmio;
- __u8 options = 0, set_mc_list = 0;
- __u16 ata1, ata2;
+ __u8 options = 0;
struct dev_mc_list *dmi;
+ unsigned char dev_mc_address[5];
+ int i;
writel(streamer_priv->srb, streamer_mmio + LAPA);
options = streamer_priv->streamer_copy_all_options;
@@ -1031,23 +1090,17 @@ static void streamer_set_rx_mode(struct net_device *dev)
else
options &= ~(3 << 5);
- if (dev->mc_count) {
- set_mc_list = 1;
- }
-
/* Only issue the srb if there is a change in options */
if ((options ^ streamer_priv->streamer_copy_all_options))
{
/* Now to issue the srb command to alter the copy.all.options */
-
- writew(SRB_MODIFY_RECEIVE_OPTIONS,
- streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
- writew(streamer_priv->streamer_receive_options | (options << 8), streamer_mmio + LAPDINC);
- writew(0x414a, streamer_mmio + LAPDINC);
- writew(0x454d, streamer_mmio + LAPDINC);
- writew(0x2053, streamer_mmio + LAPDINC);
+ writew(htons(SRB_MODIFY_RECEIVE_OPTIONS << 8), streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
+ writew(htons((streamer_priv->streamer_receive_options << 8) | options),streamer_mmio+LAPDINC);
+ writew(htons(0x4a41),streamer_mmio+LAPDINC);
+ writew(htons(0x4d45),streamer_mmio+LAPDINC);
+ writew(htons(0x5320),streamer_mmio+LAPDINC);
writew(0x2020, streamer_mmio + LAPDINC);
streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */
@@ -1058,54 +1111,25 @@ static void streamer_set_rx_mode(struct net_device *dev)
return;
}
- if (set_mc_list ^ streamer_priv->streamer_multicast_set)
- { /* Multicast options have changed */
- dmi = dev->mc_list;
-
- writel(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA);
- ata1 = readw(streamer_mmio + LAPDINC);
- ata2 = readw(streamer_mmio + LAPD);
-
- writel(streamer_priv->srb, streamer_mmio + LAPA);
-
- if (set_mc_list)
- {
- /* Turn multicast on */
-
- /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
- * We do this with a set functional address mask.
- */
-
- if (!(ata1 & 0x0400)) { /* need to set functional mask */
- writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
- writew(0, streamer_mmio + LAPDINC);
- writew(ata1 | 0x0400, streamer_mmio + LAPDINC);
- writew(ata2, streamer_mmio + LAPD);
-
- streamer_priv->srb_queued = 2;
- writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
-
- streamer_priv->streamer_multicast_set = 1;
- }
-
- } else { /* Turn multicast off */
-
- if ((ata1 & 0x0400)) { /* Hmmm, need to reset the functional mask */
- writew(SRB_SET_FUNC_ADDRESS, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
- writew(0, streamer_mmio + LAPDINC);
- writew(ata1 & ~0x0400, streamer_mmio + LAPDINC);
- writew(ata2, streamer_mmio + LAPD);
-
- streamer_priv->srb_queued = 2;
- writel(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
-
- streamer_priv->streamer_multicast_set = 0;
- }
- }
-
+ /* Set the functional addresses we need for multicast */
+ writel(streamer_priv->srb,streamer_mmio+LAPA);
+ dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
+
+ for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next)
+ {
+ dev_mc_address[0] |= dmi->dmi_addr[2] ;
+ dev_mc_address[1] |= dmi->dmi_addr[3] ;
+ dev_mc_address[2] |= dmi->dmi_addr[4] ;
+ dev_mc_address[3] |= dmi->dmi_addr[5] ;
}
+
+ writew(htons(SRB_SET_FUNC_ADDRESS << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
+ writew(0,streamer_mmio+LAPDINC);
+ writew(htons( (dev_mc_address[0] << 8) | dev_mc_address[1]),streamer_mmio+LAPDINC);
+ writew(htons( (dev_mc_address[2] << 8) | dev_mc_address[3]),streamer_mmio+LAPDINC);
+ streamer_priv->srb_queued = 2 ;
+ writel(LISR_SRB_CMD,streamer_mmio+LISR_SUM);
}
static void streamer_srb_bh(struct net_device *dev)
@@ -1115,7 +1139,7 @@ static void streamer_srb_bh(struct net_device *dev)
__u16 srb_word;
writew(streamer_priv->srb, streamer_mmio + LAPA);
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
@@ -1125,7 +1149,8 @@ static void streamer_srb_bh(struct net_device *dev)
*/
case SRB_MODIFY_RECEIVE_OPTIONS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
+
switch (srb_word) {
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name);
@@ -1147,11 +1172,10 @@ static void streamer_srb_bh(struct net_device *dev)
/* SRB_SET_GROUP_ADDRESS - Multicast group setting
*/
case SRB_SET_GROUP_ADDRESS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
- streamer_priv->streamer_multicast_set = 1;
- break;
+ break;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name);
break;
@@ -1176,11 +1200,10 @@ static void streamer_srb_bh(struct net_device *dev)
/* SRB_RESET_GROUP_ADDRESS - Remove a multicast address from group list
*/
case SRB_RESET_GROUP_ADDRESS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
- streamer_priv->streamer_multicast_set = 0;
- break;
+ break;
case 0x01:
printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name);
break;
@@ -1200,7 +1223,7 @@ static void streamer_srb_bh(struct net_device *dev)
*/
case SRB_SET_FUNC_ADDRESS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
if (streamer_priv->streamer_message_level)
@@ -1221,7 +1244,7 @@ static void streamer_srb_bh(struct net_device *dev)
*/
case SRB_READ_LOG:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
{
@@ -1250,7 +1273,7 @@ static void streamer_srb_bh(struct net_device *dev)
/* SRB_READ_SR_COUNTERS - Read and reset the source routing bridge related counters */
case SRB_READ_SR_COUNTERS:
- srb_word = readw(streamer_mmio + LAPDINC) & 0xFF;
+ srb_word=ntohs(readw(streamer_mmio+LAPDINC)) >> 8;
switch (srb_word) {
case 0x00:
if (streamer_priv->streamer_message_level)
@@ -1285,9 +1308,10 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr)
struct sockaddr *saddr = addr;
struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
- if (netif_running(dev)) {
+ if (netif_running(dev))
+ {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name);
- return -EBUSY;
+ return -EIO;
}
memcpy(streamer_priv->streamer_laa, saddr->sa_data, dev->addr_len);
@@ -1324,12 +1348,12 @@ static void streamer_arb_cmd(struct net_device *dev)
#endif
writew(streamer_priv->arb, streamer_mmio + LAPA);
- arb_word = readw(streamer_mmio + LAPD) & 0xFF;
-
+ arb_word=ntohs(readw(streamer_mmio+LAPD)) >> 8;
+
if (arb_word == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
writew(streamer_priv->arb + 6, streamer_mmio + LAPA);
streamer_priv->mac_rx_buffer = buff_off = ntohs(readw(streamer_mmio + LAPDINC));
- header_len = readw(streamer_mmio + LAPDINC) & 0xff; /* 802.5 Token-Ring Header Length */
+ header_len=ntohs(readw(streamer_mmio+LAPDINC)) >> 8; /* 802.5 Token-Ring Header Length */
frame_len = ntohs(readw(streamer_mmio + LAPDINC));
#if STREAMER_DEBUG
@@ -1340,7 +1364,7 @@ static void streamer_arb_cmd(struct net_device *dev)
__u16 len;
writew(ntohs(buff_off), streamer_mmio + LAPA); /*setup window to frame data */
- next = ntohs(readw(streamer_mmio + LAPDINC));
+ next = htons(readw(streamer_mmio + LAPDINC));
status =
ntohs(readw(streamer_mmio + LAPDINC)) & 0xff;
len = ntohs(readw(streamer_mmio + LAPDINC));
@@ -1364,7 +1388,7 @@ static void streamer_arb_cmd(struct net_device *dev)
int i;
__u16 rx_word;
- writew(ntohs(buff_off), streamer_mmio + LAPA); /* setup window to frame data */
+ writew(htons(buff_off), streamer_mmio + LAPA); /* setup window to frame data */
next_ptr = ntohs(readw(streamer_mmio + LAPDINC));
readw(streamer_mmio + LAPDINC); /* read thru status word */
buffer_len = ntohs(readw(streamer_mmio + LAPDINC));
@@ -1374,9 +1398,9 @@ static void streamer_arb_cmd(struct net_device *dev)
i = 0;
while (i < buffer_len) {
- rx_word = readw(streamer_mmio + LAPDINC);
- frame_data[i] = rx_word & 0xff;
- frame_data[i + 1] = (rx_word >> 8) & 0xff;
+ rx_word=ntohs(readw(streamer_mmio+LAPDINC));
+ frame_data[i]=rx_word >> 8;
+ frame_data[i+1]=rx_word & 0xff;
i += 2;
}
@@ -1420,10 +1444,10 @@ static void streamer_arb_cmd(struct net_device *dev)
writew(streamer_priv->asb, streamer_mmio + LAPA);
- writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */
+ writew(htons(ASB_RECEIVE_DATA << 8), streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
writew(0, streamer_mmio + LAPDINC);
- writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
+ writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM);
@@ -1433,12 +1457,13 @@ static void streamer_arb_cmd(struct net_device *dev)
} else if (arb_word == ARB_LAN_CHANGE_STATUS) { /* Lan.change.status */
writew(streamer_priv->arb + 6, streamer_mmio + LAPA);
lan_status = ntohs(readw(streamer_mmio + LAPDINC));
- fdx_prot_error = readw(streamer_mmio + LAPD) & 0xFF;
-
+ fdx_prot_error = ntohs(readw(streamer_mmio+LAPD)) >> 8;
+
/* Issue ARB Free */
writew(LISR_ARB_FREE, streamer_priv->streamer_mmio + LISR_SUM);
- lan_status_diff = streamer_priv->streamer_lan_status ^ lan_status;
+ lan_status_diff = (streamer_priv->streamer_lan_status ^ lan_status) &
+ lan_status;
if (lan_status_diff & (LSC_LWF | LSC_ARW | LSC_FPE | LSC_RR))
{
@@ -1489,8 +1514,8 @@ static void streamer_arb_cmd(struct net_device *dev)
/* Issue READ.LOG command */
writew(streamer_priv->srb, streamer_mmio + LAPA);
- writew(SRB_READ_LOG, streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC);
+ writew(htons(SRB_READ_LOG << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
writew(0, streamer_mmio + LAPDINC);
streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */
@@ -1503,10 +1528,10 @@ static void streamer_arb_cmd(struct net_device *dev)
/* Issue a READ.SR.COUNTERS */
writew(streamer_priv->srb, streamer_mmio + LAPA);
- writew(SRB_READ_SR_COUNTERS,
- streamer_mmio + LAPDINC);
- writew(STREAMER_CLEAR_RET_CODE,
- streamer_mmio + LAPDINC);
+ writew(htons(SRB_READ_SR_COUNTERS << 8),
+ streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8),
+ streamer_mmio+LAPDINC);
streamer_priv->srb_queued = 2; /* Can't sleep, use srb_bh */
writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
@@ -1528,10 +1553,10 @@ static void streamer_asb_bh(struct net_device *dev)
/* Dropped through the first time */
writew(streamer_priv->asb, streamer_mmio + LAPA);
- writew(ASB_RECEIVE_DATA, streamer_mmio + LAPDINC); /* Receive data */
- writew(STREAMER_CLEAR_RET_CODE, streamer_mmio + LAPDINC); /* Necessary ?? */
+ writew(htons(ASB_RECEIVE_DATA << 8),streamer_mmio+LAPDINC);
+ writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
writew(0, streamer_mmio + LAPDINC);
- writew(ntohs(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
+ writew(htons(streamer_priv->mac_rx_buffer), streamer_mmio + LAPD);
writel(LISR_ASB_REPLY | LISR_ASB_FREE_REQ, streamer_priv->streamer_mmio + LISR_SUM);
streamer_priv->asb_queued = 2;
@@ -1542,7 +1567,7 @@ static void streamer_asb_bh(struct net_device *dev)
if (streamer_priv->asb_queued == 2) {
__u8 rc;
writew(streamer_priv->asb + 2, streamer_mmio + LAPA);
- rc = readw(streamer_mmio + LAPD) & 0xff;
+ rc=ntohs(readw(streamer_mmio+LAPD)) >> 8;
switch (rc) {
case 0x01:
printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
@@ -1594,7 +1619,7 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset,
off_t pos = 0;
int size;
- struct net_device *dev;
+ struct device *dev;
size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n");
@@ -1607,8 +1632,8 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset,
for (dev = dev_base; dev != NULL; dev = dev->next)
{
- if (dev->base_addr == (pci_device->base_address[0] & (~3)))
- { /* Yep, a Streamer device */
+ if (dev->base_addr == pci_device->resource[0].start)
+ { /* Yep, a Streamer device */
size = sprintf_info(buffer + len, dev);
len += size;
pos = begin + len;
@@ -1644,17 +1669,17 @@ static int sprintf_info(char *buffer, struct net_device *dev)
for (i = 0; i < 14; i += 2) {
__u16 io_word;
__u8 *datap = (__u8 *) & sat;
- io_word = readw(streamer_mmio + LAPDINC);
- datap[size] = io_word & 0xff;
- datap[size + 1] = (io_word >> 8) & 0xff;
+ io_word=ntohs(readw(streamer_mmio+LAPDINC));
+ datap[size]=io_word >> 8;
+ datap[size+1]=io_word & 0xff;
}
writew(streamer_priv->streamer_parms_addr, streamer_mmio + LAPA);
for (i = 0; i < 68; i += 2) {
__u16 io_word;
__u8 *datap = (__u8 *) & spt;
- io_word = readw(streamer_mmio + LAPDINC);
- datap[size] = io_word & 0xff;
- datap[size + 1] = (io_word >> 8) & 0xff;
+ io_word=ntohs(readw(streamer_mmio+LAPDINC));
+ datap[size]=io_word >> 8;
+ datap[size+1]=io_word & 0xff;
}
@@ -1723,10 +1748,7 @@ int init_module(void)
#if STREAMER_NETWORK_MONITOR
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-
- ent = create_proc_entry("net/streamer_tr", 0, 0);
- ent->read_proc = &streamer_proc_info;
+ create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL);
#endif
#endif
for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++)
@@ -1758,11 +1780,17 @@ int init_module(void)
void cleanup_module(void)
{
int i;
+ struct streamer_private *streamer_priv;
for (i = 0; i < STREAMER_MAX_ADAPTERS; i++)
if (dev_streamer[i]) {
unregister_trdev(dev_streamer[i]);
release_region(dev_streamer[i]->base_addr, STREAMER_IO_SPACE);
+ streamer_priv=(struct streamer_private *)dev_streamer[i]->priv;
+ kfree_s(streamer_priv->streamer_rx_ring,
+ sizeof(struct streamer_rx_desc)*STREAMER_RX_RING_SIZE);
+ kfree_s(streamer_priv->streamer_tx_ring,
+ sizeof(struct streamer_tx_desc)*STREAMER_TX_RING_SIZE);
kfree_s(dev_streamer[i]->priv, sizeof(struct streamer_private));
kfree_s(dev_streamer[i], sizeof(struct net_device));
dev_streamer[i] = NULL;
diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h
index 7ba86dfe5..4c99f875e 100644
--- a/drivers/net/tokenring/lanstreamer.h
+++ b/drivers/net/tokenring/lanstreamer.h
@@ -132,6 +132,7 @@
#define BMCTL_TX1_DIS (1<<14)
#define BMCTL_TX2_DIS (1<<10)
#define BMCTL_RX_DIS (1<<6)
+#define BMCTL_RX_ENABLED (1<<5)
#define RXLBDA 0x90
#define RXBDA 0x94
@@ -257,6 +258,9 @@ struct streamer_private {
__u16 asb;
__u8 *streamer_mmio;
+ char *streamer_card_name;
+
+ spinlock_t streamer_lock;
volatile int srb_queued; /* True if an SRB is still posted */
wait_queue_head_t srb_wait;
@@ -264,10 +268,10 @@ struct streamer_private {
volatile int asb_queued; /* True if an ASB is posted */
volatile int trb_queued; /* True if a TRB is posted */
- wait_queue_head_t trb_wait;
+ wait_queue_head_t trb_wait;
- struct streamer_rx_desc streamer_rx_ring[STREAMER_RX_RING_SIZE];
- struct streamer_tx_desc streamer_tx_ring[STREAMER_TX_RING_SIZE];
+ struct streamer_rx_desc *streamer_rx_ring;
+ struct streamer_tx_desc *streamer_tx_ring;
struct sk_buff *tx_ring_skb[STREAMER_TX_RING_SIZE],
*rx_ring_skb[STREAMER_RX_RING_SIZE];
int tx_ring_free, tx_ring_last_status, rx_ring_last_received,
@@ -279,7 +283,6 @@ struct streamer_private {
__u16 pkt_buf_sz;
__u8 streamer_receive_options, streamer_copy_all_options,
streamer_message_level;
- __u8 streamer_multicast_set;
__u16 streamer_addr_table_addr, streamer_parms_addr;
__u16 mac_rx_buffer;
__u8 streamer_laa[6];
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 57b3aa252..f244874e4 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index b009a8a4b..27ea89232 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -15,7 +15,6 @@
#include "tulip.h"
#include <linux/init.h>
-#include <asm/io.h>
#include <asm/unaligned.h>
@@ -30,31 +29,31 @@
/* Known cards that have old-style EEPROMs. */
static struct eeprom_fixup eeprom_fixups[] __devinitdata = {
{"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
- 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+ 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
{"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
- 0x0000, 0x009E, /* 10baseT */
- 0x0004, 0x009E, /* 10baseT-FD */
- 0x0903, 0x006D, /* 100baseTx */
- 0x0905, 0x006D, /* 100baseTx-FD */ }},
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0903, 0x006D, /* 100baseTx */
+ 0x0905, 0x006D, /* 100baseTx-FD */ }},
{"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
- 0x0107, 0x8021, /* 100baseFx */
- 0x0108, 0x8021, /* 100baseFx-FD */
- 0x0100, 0x009E, /* 10baseT */
- 0x0104, 0x009E, /* 10baseT-FD */
- 0x0103, 0x006D, /* 100baseTx */
- 0x0105, 0x006D, /* 100baseTx-FD */ }},
+ 0x0107, 0x8021, /* 100baseFx */
+ 0x0108, 0x8021, /* 100baseFx-FD */
+ 0x0100, 0x009E, /* 10baseT */
+ 0x0104, 0x009E, /* 10baseT-FD */
+ 0x0103, 0x006D, /* 100baseTx */
+ 0x0105, 0x006D, /* 100baseTx-FD */ }},
{"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
- 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
- 0x0000, 0x009E, /* 10baseT */
- 0x0004, 0x009E, /* 10baseT-FD */
- 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
- 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+ 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+ 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
{"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
- 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
- 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
- 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
- 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
- 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
}},
{"NetWinder", 0x00, 0x10, 0x57,
/* Default media = MII
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 12b7af968..0a48a27f0 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
@@ -211,9 +210,12 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
if (status < 0)
break; /* It still has not been Txed */
+
/* Check for Rx filter setup frames. */
if (tp->tx_buffers[entry].skb == NULL) {
- pci_unmap_single(tp->pdev,
+ /* test because dummy frames not mapped */
+ if (tp->tx_buffers[entry].mapping)
+ pci_unmap_single(tp->pdev,
tp->tx_buffers[entry].mapping,
sizeof(tp->setup_frame),
PCI_DMA_TODEVICE);
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index 1d4c3b2e4..e704c6c7d 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index 445d4a440..2f408684f 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include "tulip.h"
-#include <asm/io.h>
void pnic_do_nway(struct net_device *dev)
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index 796fdd136..0a40abb48 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -14,7 +14,6 @@
*/
#include "tulip.h"
-#include <asm/io.h>
void tulip_timer(unsigned long data)
@@ -87,7 +86,11 @@ void tulip_timer(unsigned long data)
break;
}
break;
- case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
+ case DC21140:
+ case DC21142:
+ case MX98713:
+ case COMPEX9881:
+ default: {
struct medialeaf *mleaf;
unsigned char *p;
if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 8196723ae..22260591f 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -17,7 +17,7 @@
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
-
+#include <asm/io.h>
struct tulip_chip_table {
char *chip_name;
@@ -36,8 +36,10 @@ enum tbl_flag {
HAS_ACPI = 0x10,
MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */
HAS_PNICNWAY = 0x80,
- HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */
- HAS_8023X = 0x100,
+ HAS_NWAY = 0x40, /* Uses internal NWay xcvr. */
+ HAS_INTR_MITIGATION = 0x100,
+ IS_ASIX = 0x200,
+ HAS_8023X = 0x400,
};
@@ -58,7 +60,6 @@ enum chips {
COMET,
COMPEX9881,
I21145,
- X3201_3,
};
@@ -137,6 +138,17 @@ enum desc_status_bits {
};
+enum t21041_csr13_bits {
+ csr13_eng = (0xEF0<<4), /* for eng. purposes only, hardcode at EF0h */
+ csr13_aui = (1<<3), /* clear to force 10bT, set to force AUI/BNC */
+ csr13_cac = (1<<2), /* CSR13/14/15 autoconfiguration */
+ csr13_srl = (1<<0), /* When reset, resets all SIA functions, machines */
+
+ csr13_mask_auibnc = (csr13_eng | csr13_aui | csr13_cac | csr13_srl),
+ csr13_mask_10bt = (csr13_eng | csr13_cac | csr13_srl),
+};
+
+
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority.
@@ -334,7 +346,14 @@ extern u8 t21040_csr13[];
extern u16 t21041_csr13[];
extern u16 t21041_csr14[];
extern u16 t21041_csr15[];
-void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6);
+
+
+extern inline void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
+{
+ long ioaddr = tp->base_addr;
+
+ outl (newcsr6, ioaddr + CSR6);
+}
#endif /* __NET_TULIP_H__ */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 6881093ea..196dcf7f6 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -19,7 +19,7 @@
*/
-static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n";
+static const char version[] = "Linux Tulip driver version 0.9.4.2 (Mar 21, 2000)\n";
#include <linux/module.h>
#include "tulip.h"
@@ -27,7 +27,6 @@ static const char version[] = "Linux Tulip driver version 0.9.4 (Feb 28, 2000)\n
#include <linux/init.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-#include <asm/io.h>
#include <asm/unaligned.h>
@@ -92,9 +91,6 @@ static int csr0 = 0x00A00000 | 0x4800;
#define TX_TIMEOUT (4*HZ)
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-
MODULE_AUTHOR("The Linux Kernel Team");
MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
MODULE_PARM(tulip_debug, "i");
@@ -123,12 +119,13 @@ int tulip_debug = 1;
struct tulip_chip_table tulip_tbl[] = {
{ "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
- { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebef,
+ HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer },
{ "Digital DS21140 Tulip", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
{ "Digital DS21143 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
- t21142_timer },
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
+ | HAS_INTR_MITIGATION, t21142_timer },
{ "Lite-On 82c168 PNIC", 256, 0x0001ebef,
HAS_MII | HAS_PNICNWAY, pnic_timer },
{ "Macronix 98713 PMAC", 128, 0x0001ebef,
@@ -138,18 +135,15 @@ struct tulip_chip_table tulip_tbl[] = {
{ "Macronix 98725 PMAC", 256, 0x0001ebef,
HAS_MEDIA_TABLE, mxic_timer },
{ "ASIX AX88140", 128, 0x0001fbff,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer },
{ "Lite-On PNIC-II", 256, 0x0801fbff,
- HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
+ HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer },
{ "ADMtek Comet", 256, 0x0001abef,
MC_HASH_ONLY, comet_timer },
{ "Compex 9881 PMAC", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
{ "Intel DS21145 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
- t21142_timer },
- { "Xircom tulip work-alike", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY,
t21142_timer },
{0},
};
@@ -163,16 +157,20 @@ static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
{ 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
{ 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
{ 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
- { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+/* { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },*/
{ 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
{ 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
{ 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
- { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
{0},
};
-MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
+MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
/* A full-duplex map for media types. */
@@ -181,7 +179,13 @@ const char tulip_media_cap[] =
u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
-u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+u16 t21041_csr13[] = {
+ csr13_mask_10bt, /* 10-T */
+ csr13_mask_auibnc, /* 10-2 */
+ csr13_mask_auibnc, /* AUI */
+ csr13_mask_10bt, /* 10-T */
+ csr13_mask_10bt, /* 10T-FD */
+};
u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
@@ -198,54 +202,6 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
-/* The Xircom cards are picky about when certain bits in CSR6 can be
- manipulated. Keith Owens <kaos@ocs.com.au>. */
-
-void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
-{
- long ioaddr = tp->base_addr;
- const int strict_bits = 0x0060e202;
- int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
-
- /* common path */
- if (tp->chip_id != X3201_3) {
- outl (newcsr6, ioaddr + CSR6);
- return;
- }
-
- newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
- /* read 0 on the Xircom cards */
- newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
- currcsr6 = inl (ioaddr + CSR6);
- if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
- ((currcsr6 & ~0x2002) == 0))
- goto out_write;
-
- /* make sure the transmitter and receiver are stopped first */
- currcsr6 &= ~0x2002;
- while (1) {
- csr5 = inl (ioaddr + CSR5);
- if (csr5 == 0xffffffff)
- break; /* cannot read csr5, card removed? */
- csr5_22_20 = csr5 & 0x700000;
- csr5_19_17 = csr5 & 0x0e0000;
- if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
- (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
- break; /* both are stopped or suspended */
- if (!--attempts) {
- printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts,"
- "csr5=0x%08x\n", csr5);
- goto out_write;
- }
- outl (currcsr6, ioaddr + CSR6);
- udelay (1);
- }
-
-out_write:
- /* now it is safe to change csr6 */
- outl (newcsr6, ioaddr + CSR6);
-}
-
static void tulip_up(struct net_device *dev)
{
@@ -264,11 +220,13 @@ static void tulip_up(struct net_device *dev)
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
outl(0x00000001, ioaddr + CSR0);
+ udelay(100);
/* Deassert reset.
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
outl(tp->csr0, ioaddr + CSR0);
+ udelay(100);
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
@@ -561,7 +519,6 @@ static void tulip_tx_timeout(struct net_device *dev)
out:
dev->trans_start = jiffies;
- netif_start_queue (dev);
spin_unlock_irqrestore (&tp->lock, flags);
}
@@ -786,14 +743,14 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
if (tp->mii_cnt)
data[0] = phy;
- else if (tp->flags & HAS_NWAY143)
+ else if (tp->flags & HAS_NWAY)
data[0] = 32;
else if (tp->chip_id == COMET)
data[0] = 1;
else
return -ENODEV;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
int csr12 = inl(ioaddr + CSR12);
int csr14 = inl(ioaddr + CSR14);
switch (data[1]) {
@@ -821,7 +778,7 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ if (data[0] == 32 && (tp->flags & HAS_NWAY)) {
if (data[1] == 5)
tp->to_advertise = data[2];
} else {
@@ -1108,9 +1065,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
/* Clear the missed-packet counter. */
(volatile int)inl(ioaddr + CSR8);
- if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) {
- printk(" 21040 compatible mode,");
- chip_idx = DC21040;
+ if (chip_idx == DC21041) {
+ if (inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_idx = DC21040;
+ } else {
+ printk(" 21041 mode,");
+ }
}
/* The station address ROM is read byte serially. The register must
@@ -1307,7 +1268,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->do_ioctl = private_ioctl;
dev->set_multicast_list = set_rx_mode;
- if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041)
+ if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041)
tp->link_change = t21142_lnk_change;
else if (tp->flags & HAS_PNICNWAY)
tp->link_change = pnic_lnk_change;
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 4c52f055c..a9988e77b 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -27,16 +27,19 @@
LK1.1.1:
- Justin Guyett: softnet and locking fixes
- Jeff Garzik: use PCI interface
-
-*/
-static const char *versionA =
-"via-rhine.c:v1.01-LK1.1.1 3/2/2000 Written by Donald Becker\n";
-static const char *versionB =
-" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
+ LK1.1.2:
+ - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
+
+ LK1.1.3:
+ - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c code)
+ update "Theory of Operation" with softnet/locking changes
+ - Dave Miller: PCI DMA and endian fixups
+ - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
+*/
/* A few user-configurable values. These may be modified when a driver
- module is loaded.*/
+ module is loaded. */
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
static int max_interrupt_work = 20;
@@ -58,6 +61,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
The Rhine has a 64 element 8390-like hash table. */
static const int multicast_filter_limit = 32;
+
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for compile efficiency.
@@ -68,12 +72,21 @@ static const int multicast_filter_limit = 32;
#define TX_RING_SIZE 8
#define RX_RING_SIZE 16
+
/* Operational parameters that usually are not changed. */
+
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (2*HZ)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error See the last lines of the source file for the proper compile-command.
+#endif
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -91,15 +104,20 @@ static const int multicast_filter_limit = 32;
#include <asm/bitops.h>
#include <asm/io.h>
-/* This driver was written to use PCI memory space, however some x86
- motherboards only configure I/O space accesses correctly. */
-#if defined(__i386__) && !defined(VIA_USE_MEMORY)
-#define VIA_USE_IO
-#endif
-#if defined(__alpha__)
-#define VIA_USE_IO
-#endif
-#ifdef VIA_USE_IO
+static const char *versionA __devinitdata =
+"via-rhine.c:v1.03a-LK1.1.3 3/23/2000 Written by Donald Becker\n";
+static const char *versionB __devinitdata =
+" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
+
+
+
+/* This driver was written to use PCI memory space, however most versions
+ of the Rhine only work correctly with I/O space accesses. */
+#if defined(VIA_USE_MEMORY)
+#warning Many adapters using the VIA Rhine chip are not configured to work
+#warning with PCI memory space accesses.
+#else
+#define USE_IO
#undef readb
#undef readw
#undef readl
@@ -114,9 +132,6 @@ static const int multicast_filter_limit = 32;
#define writel outl
#endif
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-
#define RUN_AT(x) (jiffies + (x))
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
@@ -186,18 +201,17 @@ IIId. Synchronization
The driver runs as two independent, single-threaded flows of control. One
is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag. The other thread is the interrupt handler, which is single
-threaded by the hardware and interrupt handling software.
+dev->priv->lock spinlock. The other thread is the interrupt handler, which
+is single threaded by the hardware and interrupt handling software.
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'lp->tx_full' flag.
+The send packet thread has partial control over the Tx ring. It locks the
+dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring
+is not available it stops the transmit queue by calling netif_stop_queue.
The interrupt handler has exclusive control over the Rx ring and records stats
from the Tx ring. After reaping the stats, it marks the Tx queue entry as
-empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-clears both the tx_full and tbusy flags.
+empty by incrementing the dirty_tx mark. If at least half of the entries in
+the Rx ring are available the transmit queue is woken up if it was stopped.
IV. Notes
@@ -231,57 +245,49 @@ enum pci_flags_bit {
};
enum via_rhine_chips {
- vt86c100a = 0,
- vt3043,
+ VT86C100A = 0,
+ VT3043,
};
struct via_rhine_chip_info {
const char *name;
- u16 flags;
+ u16 pci_flags;
int io_size;
+ int drv_flags;
};
+enum chip_capability_flags {CanHaveMII=1, };
+
+#if defined(VIA_USE_MEMORY)
+#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
+#else
+#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0)
+#endif
+
/* directly indexed by enum via_rhine_chips, above */
static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata =
{
- {"VIA VT86C100A Rhine-II",
- PCI_USES_MEM | PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
- 128,},
- {"VIA VT3043 Rhine",
- PCI_USES_IO | PCI_USES_MEM | PCI_USES_MASTER,
- 128,},
+ { "VIA VT86C100A Rhine-II", RHINE_IOTYPE, 128, CanHaveMII },
+ { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII }
};
static struct pci_device_id via_rhine_pci_tbl[] __devinitdata =
{
- {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt86c100a},
- {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt3043},
+ {0x1106, 0x6100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A},
+ {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT3043},
{0,}, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl);
-
-/* A chip capabilities table, matching the entries in pci_tbl[] above. */
-enum chip_capability_flags {CanHaveMII=1, };
-struct chip_info {
- int io_size;
- int flags;
-} static cap_tbl[] = {
- {128, CanHaveMII, },
- {128, CanHaveMII, },
-};
-
-
-/* Offsets to the device registers.
-*/
+/* Offsets to the device registers. */
enum register_offsets {
StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
IntrStatus=0x0C, IntrEnable=0x0E,
MulticastFilter0=0x10, MulticastFilter1=0x14,
RxRingPtr=0x18, TxRingPtr=0x1C,
- MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E,
+ MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72,
Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E,
};
@@ -295,21 +301,19 @@ enum intr_status_bits {
IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
IntrTxAborted=0x2000, IntrLinkChange=0x4000,
IntrRxWakeUp=0x8000,
- IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260,
+ IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
};
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
- u16 rx_status;
- u16 rx_length;
+ s32 rx_status;
u32 desc_length;
u32 addr;
u32 next_desc;
};
struct tx_desc {
- u16 tx_status;
- u16 tx_own;
+ s32 tx_status;
u32 desc_length;
u32 addr;
u32 next_desc;
@@ -317,9 +321,11 @@ struct tx_desc {
/* Bits in *_desc.status */
enum rx_status_bits {
- RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};
+ RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
+};
+
enum desc_status_bits {
- DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000,
+ DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
};
/* Bits in ChipCmd. */
@@ -331,32 +337,42 @@ enum chip_cmd_bits {
};
struct netdev_private {
- /* Descriptor rings first for alignment. */
- struct rx_desc rx_ring[RX_RING_SIZE];
- struct tx_desc tx_ring[TX_RING_SIZE];
+ /* Descriptor rings */
+ struct rx_desc *rx_ring;
+ struct tx_desc *tx_ring;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+
/* The addresses of receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ dma_addr_t rx_skbuff_dma[RX_RING_SIZE];
+
/* The saved address of a sent-in-place packet/buffer, for later free(). */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ dma_addr_t tx_skbuff_dma[TX_RING_SIZE];
unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
+
+ struct pci_dev *pdev;
struct net_device_stats stats;
struct timer_list timer; /* Media monitoring timer. */
spinlock_t lock;
+
/* Frequently used values: keep some adjacent for cache effect. */
int chip_id;
struct rx_desc *rx_head_desc;
- unsigned short int cur_rx, dirty_rx; /* Producer/consumer ring indices */
- unsigned short int cur_tx, dirty_tx;
+ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
+ unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
u16 chip_cmd; /* Current setting for ChipCmd */
unsigned int tx_full:1; /* The Tx queue is full. */
+
/* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev->if_port value. */
u8 tx_thresh, rx_thresh;
+
/* MII transceiver section. */
int mii_cnt; /* MII device addresses. */
u16 advertising; /* NWay media advertisement */
@@ -393,6 +409,9 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
static int did_version = 0;
long ioaddr;
int io_size;
+ int pci_flags;
+ void *ring;
+ dma_addr_t ring_dma;
/* print version once and once only */
if (! did_version++) {
@@ -403,44 +422,67 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
card_idx++;
option = card_idx < MAX_UNITS ? options[card_idx] : 0;
io_size = via_rhine_chip_info[chip_id].io_size;
+ pci_flags = via_rhine_chip_info[chip_id].pci_flags;
+
+ /* this should always be supported */
+ if (!pci_dma_supported(pdev, 0xffffffff)) {
+ printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");
+ goto err_out;
+ }
+
+ /* sanity check */
+ if ((pci_resource_len (pdev, 0) < io_size) ||
+ (pci_resource_len (pdev, 1) < io_size)) {
+ printk (KERN_ERR "Insufficient PCI resources, aborting\n");
+ goto err_out;
+ }
+ /* allocate pci dma space for rx and tx descriptor rings */
+ ring = pci_alloc_consistent(pdev,
+ RX_RING_SIZE * sizeof(struct rx_desc) +
+ TX_RING_SIZE * sizeof(struct tx_desc),
+ &ring_dma);
+ if (!ring) {
+ printk(KERN_ERR "Could not allocate DMA memory.\n");
+ goto err_out;
+ }
-#ifdef VIA_USE_IO
- ioaddr = pci_resource_start (pdev, 0);
-#else
- ioaddr = pci_resource_start (pdev, 1);
-#endif
+ ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1);
if (pci_enable_device (pdev)) {
printk (KERN_ERR "unable to init PCI device (card #%d)\n",
card_idx);
- goto err_out;
+ goto err_out_free_dma;
}
- if (via_rhine_chip_info[chip_id].flags & PCI_USES_MASTER)
+ if (pci_flags & PCI_USES_MASTER)
pci_set_master (pdev);
dev = init_etherdev(NULL, sizeof(*np));
if (dev == NULL) {
printk (KERN_ERR "init_ethernet failed for card #%d\n",
card_idx);
- goto err_out;
+ goto err_out_free_dma;
}
- if (!request_region(pci_resource_start (pdev, 0), io_size, dev->name)) {
+ /* request all PIO and MMIO regions just to make sure
+ * noone else attempts to use any portion of our I/O space */
+ if (!request_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0), dev->name)) {
printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n",
dev->name, io_size,
pci_resource_start (pdev, 0));
goto err_out_free_netdev;
}
- if (!request_mem_region(pci_resource_start (pdev, 1), io_size, dev->name)) {
+ if (!request_mem_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1), dev->name)) {
printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n",
dev->name, io_size,
pci_resource_start (pdev, 1));
goto err_out_free_pio;
}
-#ifndef VIA_USE_IO
+#ifndef USE_IO
ioaddr = (long) ioremap (ioaddr, io_size);
if (!ioaddr) {
printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n",
@@ -469,6 +511,11 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
np = dev->priv;
spin_lock_init (&np->lock);
np->chip_id = chip_id;
+ np->pdev = pdev;
+ np->rx_ring = ring;
+ np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
+ np->rx_ring_dma = ring_dma;
+ np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
if (dev->mem_start)
option = dev->mem_start;
@@ -499,7 +546,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
pdev->driver_data = dev;
- if (cap_tbl[np->chip_id].flags & CanHaveMII) {
+ if (via_rhine_chip_info[chip_id].drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
np->phys[0] = 1; /* Standard for this chip. */
for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
@@ -518,18 +565,25 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
return 0;
-#ifndef VIA_USE_IO
+#ifndef USE_IO
/* note this is ifdef'd because the ioremap is ifdef'd...
* so additional exit conditions above this must move
* release_mem_region outside of the ifdef */
err_out_free_mmio:
- release_mem_region(pci_resource_start (pdev, 1), io_size, dev->name));
+ release_mem_region(pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
#endif
err_out_free_pio:
- release_region(pci_resource_start (pdev, 0), io_size);
+ release_region(pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
err_out_free_netdev:
unregister_netdev (dev);
kfree (dev);
+err_out_free_dma:
+ pci_free_consistent(pdev,
+ RX_RING_SIZE * sizeof(struct rx_desc) +
+ TX_RING_SIZE * sizeof(struct tx_desc),
+ ring, ring_dma);
err_out:
return -ENODEV;
}
@@ -557,9 +611,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum)
static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
long ioaddr = dev->base_addr;
int boguscnt = 1024;
+ if (phy_id == np->phys[0] && regnum == 4)
+ np->advertising = value;
/* Wait for a previous command to complete. */
while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)
;
@@ -578,32 +635,34 @@ static int via_rhine_open(struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
+ MOD_INC_USE_COUNT;
+
/* Reset the chip. */
writew(CmdReset, ioaddr + ChipCmd);
- if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev))
- return -EAGAIN;
+ if (request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
if (debug > 1)
printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
dev->name, dev->irq);
- MOD_INC_USE_COUNT;
-
via_rhine_init_ring(dev);
- writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
- writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
+ writel(np->rx_ring_dma, ioaddr + RxRingPtr);
+ writel(np->tx_ring_dma, ioaddr + TxRingPtr);
for (i = 0; i < 6; i++)
writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */
- writew(0x0006, ioaddr + PCIConfig); /* Tune configuration??? */
+ writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
/* Configure the FIFO thresholds. */
writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */
np->tx_thresh = 0x20;
- np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */
+ np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */
if (dev->if_port == 0)
dev->if_port = np->default_port;
@@ -666,6 +725,7 @@ static void via_rhine_check_duplex(struct net_device *dev)
}
}
+
static void via_rhine_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
@@ -677,12 +737,14 @@ static void via_rhine_timer(unsigned long data)
printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
dev->name, readw(ioaddr + IntrStatus));
}
+
via_rhine_check_duplex(dev);
np->timer.expires = RUN_AT(next_tick);
add_timer(&np->timer);
}
+
static void via_rhine_tx_timeout (struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *) dev->priv;
@@ -693,16 +755,17 @@ static void via_rhine_tx_timeout (struct net_device *dev)
dev->name, readw (ioaddr + IntrStatus),
mdio_read (dev, np->phys[0], 1));
- /* Perhaps we should reinitialize the hardware here. */
+ /* XXX Perhaps we should reinitialize the hardware here. */
dev->if_port = 0;
+
/* Stop and restart the chip's Tx processes . */
+ /* XXX to do */
/* Trigger an immediate transmit demand. */
+ /* XXX to do */
dev->trans_start = jiffies;
np->stats.tx_errors++;
-
- netif_start_queue (dev);
}
@@ -720,13 +783,13 @@ static void via_rhine_init_ring(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].rx_length = 0;
- np->rx_ring[i].desc_length = np->rx_buf_sz;
- np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
+ np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+ np->rx_ring[i].next_desc =
+ cpu_to_le32(np->rx_ring_dma + sizeof(struct rx_desc)*(i+1));
np->rx_skbuff[i] = 0;
}
/* Mark the last entry as wrapping the ring. */
- np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
+ np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma);
/* Fill in the Rx buffers. */
for (i = 0; i < RX_RING_SIZE; i++) {
@@ -734,20 +797,25 @@ static void via_rhine_init_ring(struct net_device *dev)
np->rx_skbuff[i] = skb;
if (skb == NULL)
break;
- skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[i].addr = virt_to_bus(skb->tail);
- np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].rx_length = DescOwn;
+ skb->dev = dev; /* Mark as being used by this device. */
+
+ np->rx_skbuff_dma[i] =
+ pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+
+ np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
+ np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
}
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_skbuff[i] = 0;
- np->tx_ring[i].tx_own = 0;
- np->tx_ring[i].desc_length = 0x00e08000;
- np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);
+ np->tx_ring[i].tx_status = 0;
+ np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+ np->tx_ring[i].next_desc =
+ cpu_to_le32(np->tx_ring_dma + sizeof(struct tx_desc)*(i+1));
np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
}
- np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);
+ np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
return;
}
@@ -771,16 +839,24 @@ static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
if ((long)skb->data & 3) { /* Must use alignment buffer. */
if (np->tx_buf[entry] == NULL &&
- (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL)
+ (np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL) {
+ spin_unlock_irqrestore (&np->lock, flags);
return 1;
+ }
memcpy(np->tx_buf[entry], skb->data, skb->len);
- np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]);
- } else
- np->tx_ring[entry].addr = virt_to_bus(skb->data);
+ np->tx_skbuff_dma[entry] =
+ pci_map_single(np->pdev, np->tx_buf[entry], skb->len,
+ PCI_DMA_TODEVICE);
+ } else {
+ np->tx_skbuff_dma[entry] =
+ pci_map_single(np->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ }
+ np->tx_ring[entry].addr = cpu_to_le32(np->tx_skbuff_dma[entry]);
- np->tx_ring[entry].desc_length = 0x00E08000 |
- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
- np->tx_ring[entry].tx_own = DescOwn;
+ np->tx_ring[entry].desc_length =
+ cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+ np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
np->cur_tx++;
@@ -848,7 +924,7 @@ static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs
}
/* This routine is logically part of the interrupt handler, but isolated
- for clarity and better register allocation. */
+ for clarity. */
static void via_rhine_tx(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
@@ -858,15 +934,15 @@ static void via_rhine_tx(struct net_device *dev)
/* if tx_full is set, they're all dirty, not clean */
while (np->dirty_tx != np->cur_tx) {
- if (np->tx_ring[entry].tx_own) /* transmit request pending */
+ txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
+ if (txstatus & DescOwn)
break;
- txstatus = np->tx_ring[entry].tx_status;
if (debug > 6)
- printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
+ printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
entry, txstatus);
if (txstatus & 0x8000) {
if (debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
dev->name, txstatus);
np->stats.tx_errors++;
if (txstatus & 0x0400) np->stats.tx_carrier_errors++;
@@ -877,12 +953,15 @@ static void via_rhine_tx(struct net_device *dev)
/* Transmitter restarted in 'abnormal' handler. */
} else {
np->stats.collisions += (txstatus >> 3) & 15;
- np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
+ np->stats.tx_bytes += le32_to_cpu(np->tx_ring[entry].desc_length) & 0x7ff;
np->stats.tx_packets++;
- }
- /* Free the original skb. */
- dev_kfree_skb_irq(np->tx_skbuff[entry]);
- np->tx_skbuff[entry] = NULL;
+ }
+ /* Free the original skb. */
+ pci_unmap_single(np->pdev,
+ le32_to_cpu(np->tx_ring[entry].addr),
+ np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(np->tx_skbuff[entry]);
+ np->tx_skbuff[entry] = NULL;
entry = (++np->dirty_tx) % TX_RING_SIZE;
}
if ((np->cur_tx - np->dirty_tx) <= TX_RING_SIZE/2)
@@ -896,33 +975,32 @@ static void via_rhine_tx(struct net_device *dev)
static void via_rhine_rx(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
- int entry = (np->dirty_rx = np->cur_rx) % RX_RING_SIZE;
- int boguscnt = RX_RING_SIZE;
+ int entry = np->cur_rx % RX_RING_SIZE;
+ int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
if (debug > 4) {
- printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %4.4x.\n",
- entry, np->rx_head_desc->rx_length);
+ printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %8.8x.\n",
+ entry, le32_to_cpu(np->rx_head_desc->rx_status));
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
- while ( ! (np->rx_head_desc->rx_length & DescOwn)) {
+ while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
struct rx_desc *desc = np->rx_head_desc;
- int data_size = desc->rx_length;
- u16 desc_status = desc->rx_status;
+ u32 desc_status = le32_to_cpu(desc->rx_status);
+ int data_size = desc_status >> 16;
if (debug > 4)
- printk(KERN_DEBUG " via_rhine_rx() status is %4.4x.\n",
+ printk(KERN_DEBUG " via_rhine_rx() status is %8.8x.\n",
desc_status);
if (--boguscnt < 0)
break;
if ( (desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
if ((desc_status & RxWholePkt) != RxWholePkt) {
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, entry %#x length %d status %4.4x!\n",
+ "multiple buffers, entry %#x length %d status %8.8x!\n",
dev->name, entry, data_size, desc_status);
printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",
- dev->name, np->rx_head_desc,
- &np->rx_ring[entry]);
+ dev->name, np->rx_head_desc, &np->rx_ring[entry]);
np->stats.rx_length_errors++;
} else if (desc_status & RxErr) {
/* There was a error. */
@@ -942,25 +1020,35 @@ static void via_rhine_rx(struct net_device *dev)
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
- if (pkt_len < rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ if (pkt_len < rx_copybreak &&
+ (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
+ pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry],
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */
- eth_copy_and_sum(skb, bus_to_virt(desc->addr),
- pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
skb_put(skb, pkt_len);
#else
- memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len);
+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
+ pkt_len);
#endif
} else {
- skb_put(skb = np->rx_skbuff[entry], pkt_len);
+ skb = np->rx_skbuff[entry];
+ if (skb == NULL) {
+ printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",
+ dev->name);
+ break;
+ }
np->rx_skbuff[entry] = NULL;
+ skb_put(skb, pkt_len);
+ pci_unmap_single(np->pdev, np->rx_skbuff_dma[entry],
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
}
skb->protocol = eth_type_trans(skb, dev);
- np->stats.rx_bytes+=skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
+ np->stats.rx_bytes += skb->len;
np->stats.rx_packets++;
}
entry = (++np->cur_rx) % RX_RING_SIZE;
@@ -968,19 +1056,21 @@ static void via_rhine_rx(struct net_device *dev)
}
/* Refill the Rx ring buffers. */
- while (np->dirty_rx != np->cur_rx) {
+ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
struct sk_buff *skb;
- entry = np->dirty_rx++ % RX_RING_SIZE;
+ entry = np->dirty_rx % RX_RING_SIZE;
if (np->rx_skbuff[entry] == NULL) {
skb = dev_alloc_skb(np->rx_buf_sz);
np->rx_skbuff[entry] = skb;
if (skb == NULL)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[entry].addr = virt_to_bus(skb->tail);
+ np->rx_skbuff_dma[entry] =
+ pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ np->rx_ring[entry].addr = cpu_to_le32(np->rx_skbuff_dma[entry]);
}
- np->rx_ring[entry].rx_status = 0;
- np->rx_ring[entry].rx_length = DescOwn;
+ np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
}
/* Pre-emptively restart Rx engine. */
@@ -1020,7 +1110,8 @@ static void via_rhine_error(struct net_device *dev, int intr_status)
printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
"threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
}
- if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug > 1) {
+ if ((intr_status & ~( IntrLinkChange | IntrStatsMax |
+ IntrTxAbort | IntrTxAborted)) && debug > 1) {
printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
dev->name, intr_status);
/* Recovery for other fault sources not known. */
@@ -1076,6 +1167,8 @@ static void via_rhine_set_rx_mode(struct net_device *dev)
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
+ writel(0xffffffff, ioaddr + MulticastFilter0);
+ writel(0xffffffff, ioaddr + MulticastFilter1);
rx_mode = 0x0C;
} else {
struct dev_mc_list *mclist;
@@ -1083,12 +1176,11 @@ static void via_rhine_set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26,
- mc_filter);
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
}
writel(mc_filter[0], ioaddr + MulticastFilter0);
writel(mc_filter[1], ioaddr + MulticastFilter1);
- rx_mode = 0x08;
+ rx_mode = 0x0C;
}
writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
}
@@ -1138,13 +1230,17 @@ static int via_rhine_close(struct net_device *dev)
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
- np->rx_ring[i].rx_length = 0;
- np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
+ np->rx_ring[i].rx_status = 0;
+ np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
if (np->rx_skbuff[i]) {
+ pci_unmap_single(np->pdev,
+ np->rx_skbuff_dma[i],
+ np->rx_buf_sz, PCI_DMA_FROMDEVICE);
dev_kfree_skb(np->rx_skbuff[i]);
}
np->rx_skbuff[i] = 0;
}
+
for (i = 0; i < TX_RING_SIZE; i++) {
if (np->tx_skbuff[i])
dev_kfree_skb(np->tx_skbuff[i]);
@@ -1165,14 +1261,19 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
unregister_netdev(dev);
release_region(pci_resource_start (pdev, 0),
- via_rhine_chip_info[np->chip_id].io_size);
+ pci_resource_len (pdev, 0));
release_mem_region(pci_resource_start (pdev, 1),
- via_rhine_chip_info[np->chip_id].io_size);
+ pci_resource_len (pdev, 1));
-#ifndef VIA_USE_IO
+#ifndef USE_IO
iounmap((char *)(dev->base_addr));
#endif
+ pci_free_consistent(pdev,
+ RX_RING_SIZE * sizeof(struct rx_desc) +
+ TX_RING_SIZE * sizeof(struct tx_desc),
+ np->rx_ring, np->rx_ring_dma);
+
kfree(dev);
}
@@ -1187,7 +1288,15 @@ static struct pci_driver via_rhine_driver = {
static int __init via_rhine_init (void)
{
- return pci_module_init (&via_rhine_driver);
+ int rc;
+
+ MOD_INC_USE_COUNT;
+
+ rc = pci_module_init (&via_rhine_driver);
+
+ MOD_DEC_USE_COUNT;
+
+ return rc;
}
diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
index e0a6f5e8f..4ffe0730f 100644
--- a/drivers/net/wan/Config.in
+++ b/drivers/net/wan/Config.in
@@ -55,9 +55,11 @@ if [ "$CONFIG_WAN" = "y" ]; then
if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1
bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC
- bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
+ fi
bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP
- bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index d2bb93c74..e8bd316e6 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,12 @@
+2000-03-22 Tim Waugh <twaugh@redhat.com>
+
+ * init.c (parport_setup): Fix return value.
+
+2000-03-21 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (parport_pc_pci_probe): Fix return value; call
+ pci_enable_device.
+
2000-03-16 Tim Waugh <twaugh@redhat.com>
* parport_pc.c (parport_ECP_supported): This seems to trigger on
diff --git a/drivers/parport/init.c b/drivers/parport/init.c
index a43d59dbe..8ad352774 100644
--- a/drivers/parport/init.c
+++ b/drivers/parport/init.c
@@ -49,13 +49,13 @@ static int __init parport_setup (char *str)
if (!str || !*str || (*str == '0' && !*(str+1))) {
/* Disable parport if "parport=0" in cmdline */
io[0] = PARPORT_DISABLE;
- return 0;
+ return 1;
}
if (!strncmp (str, "auto", 4)) {
irq[0] = PARPORT_IRQ_AUTO;
dma[0] = PARPORT_DMA_AUTO;
- return 0;
+ return 1;
}
val = simple_strtoul (str, &endptr, 0);
@@ -108,7 +108,7 @@ static int __init parport_setup (char *str)
}
parport_setup_ptr++;
- return 0;
+ return 1;
}
__setup ("parport=", parport_setup);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index dbbd12864..16b5ea3fe 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2348,7 +2348,7 @@ MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
const struct pci_device_id *id)
{
- int count, n, i = id->driver_data;
+ int err, count, n, i = id->driver_data;
if (i < last_sio)
/* This is an onboard Super-IO and has already been probed */
return 0;
@@ -2356,6 +2356,9 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
/* This is a PCI card */
i -= last_sio;
count = 0;
+ if ((err = pci_enable_device (dev)) != 0)
+ return err;
+
for (n = 0; n < cards[i].numports; n++) {
int lo = cards[i].addr[n].lo;
int hi = cards[i].addr[n].hi;
@@ -2370,7 +2373,7 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
count++;
}
- return count;
+ return count == 0 ? -ENODEV : 0;
}
static struct pci_driver parport_pc_pci_driver = {
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0b6614fe1..8f523cdf4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -33,6 +33,16 @@
LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices);
+/**
+ * pci_find_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: number of PCI slot in which desired PCI device resides
+ *
+ * Given a PCI bus and slot number, the desired PCI device is
+ * located in system global list of PCI devices. If the device
+ * is found, a pointer to its data structure is returned. If no
+ * device is found, %NULL is returned.
+ */
struct pci_dev *
pci_find_slot(unsigned int bus, unsigned int devfn)
{
@@ -66,6 +76,19 @@ pci_find_subsys(unsigned int vendor, unsigned int device,
}
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all vendor ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @vendor and @device, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ *
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not null, searches continue from that point.
+ */
struct pci_dev *
pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
{
@@ -73,6 +96,18 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *
}
+/**
+ * pci_find_class - begin or continue searching for a PCI device by class
+ * @class: search for a PCI device with this class designation
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices. If a PCI device is
+ * found with a matching @class, a pointer to its device structure is
+ * returned. Otherwise, %NULL is returned.
+ *
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not null, searches continue from that point.
+ */
struct pci_dev *
pci_find_class(unsigned int class, const struct pci_dev *from)
{
@@ -122,7 +157,11 @@ pci_find_capability(struct pci_dev *dev, int cap)
}
-/*
+/**
+ * pci_find_parent_resource - return resource region of parent bus of given region
+ * @dev: PCI device structure contains resources to be searched
+ * @res: child resource record for which parent is sought
+ *
* For given resource region of given device, return the resource
* region of parent bus the given region is contained in or where
* it should be allocated from.
@@ -150,7 +189,11 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
return best;
}
-/*
+/**
+ * pci_set_power_state - Set power management state of a device.
+ * @dev: PCI device for which PM is set
+ * @new_state: new power management statement (0 == D0, 3 == D3, etc.)
+ *
* Set power management state of a device. For transitions from state D3
* it isn't as straightforward as one could assume since many devices forget
* their configuration space during wakeup. Returns old power state.
@@ -192,7 +235,10 @@ pci_set_power_state(struct pci_dev *dev, int new_state)
return old_state;
}
-/*
+/**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
* Initialize device before it's used by a driver. Ask low-level code
* to enable I/O and memory. Wake up the device if it was suspended.
* Beware, this function can fail.
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index 16c881f7d..e47662901 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -137,16 +137,32 @@
#ifdef CONFIG_CARDBUS
/*
- * Generic TI open - TI has an extension for the
+ * Generic TI init - TI has an extension for the
* INTCTL register that sets the PCI CSC interrupt.
* Make sure we set it correctly at open and init
- * time.
+ * time
+ * - open: disable the PCI CSC interrupt. This makes
+ * it possible to use the CSC interrupt to probe the
+ * ISA interrupts.
+ * - init: set the interrupt to match our PCI state.
+ * This makes us correctly get PCI CSC interrupt
+ * events.
*/
static int ti_open(pci_socket_t *socket)
{
u8 new, reg = exca_readb(socket, I365_INTCTL);
new = reg & ~I365_INTR_ENA;
+ if (new != reg)
+ exca_writeb(socket, I365_INTCTL, new);
+ return 0;
+}
+
+static int ti_intctl(pci_socket_t *socket)
+{
+ u8 new, reg = exca_readb(socket, I365_INTCTL);
+
+ new = reg & ~I365_INTR_ENA;
if (socket->cb_irq)
new |= I365_INTR_ENA;
if (new != reg)
@@ -157,7 +173,7 @@ static int ti_open(pci_socket_t *socket)
static int ti_init(pci_socket_t *socket)
{
yenta_init(socket);
- ti_open(socket);
+ ti_intctl(socket);
return 0;
}
@@ -200,7 +216,7 @@ static int ti113x_init(pci_socket_t *socket)
config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
- ti_open(socket);
+ ti_intctl(socket);
return 0;
}
@@ -237,7 +253,7 @@ static int ti1250_init(pci_socket_t *socket)
yenta_init(socket);
config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
- ti_open(socket);
+ ti_intctl(socket);
return 0;
}
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index a8b311780..294895733 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -851,22 +851,3 @@ struct pci_socket_ops yenta_operations = {
yenta_proc_setup
};
EXPORT_SYMBOL(yenta_operations);
-
-/*
- * Ricoh cardbus bridge: standard cardbus, except it needs
- * some extra init code to set timings etc.
- */
-struct pci_socket_ops ricoh_operations = {
- yenta_open,
- yenta_close,
- ricoh_init,
- yenta_suspend,
- yenta_get_status,
- yenta_get_socket,
- yenta_set_socket,
- yenta_get_io_map,
- yenta_set_io_map,
- yenta_get_mem_map,
- yenta_set_mem_map,
- yenta_proc_setup
-};
diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
index 51468e1ef..06bf94664 100644
--- a/drivers/pnp/isapnp.c
+++ b/drivers/pnp/isapnp.c
@@ -1208,6 +1208,50 @@ struct pci_dev *isapnp_find_dev(struct pci_bus *card,
return NULL;
}
+static const struct isapnp_card_id *
+isapnp_match_card(const struct isapnp_card_id *ids, struct pci_bus *card)
+{
+ int idx;
+
+ while (ids->vendor || ids->device) {
+ if ((ids->vendor == ISAPNP_ANY_ID || ids->vendor == card->vendor) &&
+ (ids->device == ISAPNP_ANY_ID || ids->device == card->device)) {
+ for (idx = 0; idx < ISAPNP_CARD_DEVS; idx++) {
+ if (ids->devs[idx].vendor == 0 &&
+ ids->devs[idx].function == 0)
+ return ids;
+ if (isapnp_find_dev(card,
+ ids->devs[idx].vendor,
+ ids->devs[idx].function,
+ NULL) == NULL)
+ goto __next;
+ }
+ return ids;
+ }
+ __next:
+ ids++;
+ }
+ return NULL;
+}
+
+int isapnp_probe_cards(const struct isapnp_card_id *ids,
+ int (*probe)(struct pci_bus *_card,
+ const struct isapnp_card_id *_id))
+{
+ struct pci_bus *card;
+ const struct isapnp_card_id *id;
+ int count = 0;
+
+ if (ids == NULL || probe == NULL)
+ return -EINVAL;
+ isapnp_for_each_card(card) {
+ id = isapnp_match_card(ids, card);
+ if (id != NULL && probe(card, id) >= 0)
+ count++;
+ }
+ return count;
+}
+
static unsigned int isapnp_dma_resource_flags(struct isapnp_dma *dma)
{
return dma->flags | IORESOURCE_DMA | IORESOURCE_AUTO;
@@ -2065,6 +2109,8 @@ static void __init isapnp_pci_init(void)
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL(isapnp_cards);
+EXPORT_SYMBOL(isapnp_devices);
EXPORT_SYMBOL(isapnp_present);
EXPORT_SYMBOL(isapnp_cfg_begin);
EXPORT_SYMBOL(isapnp_cfg_end);
@@ -2080,6 +2126,7 @@ EXPORT_SYMBOL(isapnp_activate);
EXPORT_SYMBOL(isapnp_deactivate);
EXPORT_SYMBOL(isapnp_find_card);
EXPORT_SYMBOL(isapnp_find_dev);
+EXPORT_SYMBOL(isapnp_probe_cards);
EXPORT_SYMBOL(isapnp_resource_change);
int __init isapnp_init(void)
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 08acf4f81..039994471 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.15 2000/02/09 22:33:23 davem Exp $
+/* $Id: envctrl.c,v 1.16 2000/03/22 21:29:23 ecd Exp $
* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
@@ -1002,7 +1002,6 @@ rasctrl_setup(int node)
return 0;
out:
- envctrl_stop();
return -ENODEV;
}
@@ -1381,7 +1380,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "cpu-temp-factors",
envctrl.cpu_temp_table, 256);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `cpu-temp-factors'\n");
goto out;
}
@@ -1398,7 +1397,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "cpu-fan-speeds",
envctrl.cpu_fan_speeds, 112);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `cpu-fan-speeds'\n");
goto out;
}
@@ -1415,7 +1414,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "ps-temp-factors",
envctrl.ps_temp_table, 256);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `ps-temp-factors'\n");
goto out;
}
@@ -1432,7 +1431,7 @@ envctrl_setup(int node)
} else {
err = prom_getproperty(node, "ps-fan-speeds",
envctrl.ps_fan_speeds, 112);
- if (err) {
+ if (err < 0) {
printk("envctrl: can't read `ps-fan-speeds'\n");
goto out;
}
@@ -1449,8 +1448,6 @@ envctrl_setup(int node)
out:
if (tmp)
kfree(tmp);
-
- envctrl_stop();
return err;
}
#endif /* U450_SUPPORT */
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
index 091702d15..f1641a33a 100644
--- a/drivers/sbus/char/sunmouse.c
+++ b/drivers/sbus/char/sunmouse.c
@@ -69,7 +69,6 @@ struct sun_mouse {
unsigned char prev_state; /* Previous button state */
int delta_x; /* Current delta-x */
int delta_y; /* Current delta-y */
- int present;
int ready; /* set if there if data is available */
int active; /* set if device is open */
int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */
@@ -382,8 +381,6 @@ sun_mouse_open(struct inode * inode, struct file * file)
{
if(sunmouse.active++)
return 0;
- if(!sunmouse.present)
- return -EINVAL;
sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
sunmouse.button_state = 0x80;
sunmouse.vuid_mode = VUID_NATIVE;
@@ -555,11 +552,8 @@ static struct miscdevice sun_mouse_mouse = {
SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
};
-int __init sun_mouse_init(void)
+void sun_mouse_zsinit(void)
{
- if (!sunmouse.present)
- return -ENODEV;
-
printk("Sun Mouse-Systems mouse driver version 1.00\n");
sunmouse.ready = sunmouse.active = 0;
@@ -568,11 +562,4 @@ int __init sun_mouse_init(void)
sunmouse.button_state = 0x80;
init_waitqueue_head(&sunmouse.proc_list);
sunmouse.byte = 69;
- return 0;
-}
-
-void
-sun_mouse_zsinit(void)
-{
- sunmouse.present = 1;
}
diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c
index 9719f625a..e58eb1ef7 100644
--- a/drivers/sbus/char/sunserial.c
+++ b/drivers/sbus/char/sunserial.c
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.74 1999/12/15 22:30:23 davem Exp $
+/* $Id: sunserial.c,v 1.75 2000/03/22 02:45:36 davem Exp $
* serial.c: Serial port driver infrastructure for the Sparc.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -67,6 +67,8 @@ int rs_init(void)
return err;
}
+__initcall(rs_init);
+
void __init rs_kgdb_hook(int channel)
{
rs_ops.rs_kgdb_hook(channel);
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 74644cccf..81a164066 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -738,18 +738,12 @@ sim710_u.h: sim710_d.h
sim710.o : sim710_d.h
-initio.o: ini9100u.c i91uscsi.c
- $(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o
- $(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o
+initio.o: ini9100u.o i91uscsi.o
$(LD) -r -o initio.o ini9100u.o i91uscsi.o
- rm -f ini9100u.o i91uscsi.o
a100u2w.o: inia100.o i60uscsi.o
$(LD) -r -o a100u2w.o inia100.o i60uscsi.o
-megaraid.o: megaraid.c
- $(CC) $(CFLAGS) -c megaraid.c
-
scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o \
scsi_queue.o scsi_lib.o scsi_merge.o scsi_dma.o scsi_scan.o
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 9e2f14548..eb3c22cf0 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -4186,7 +4186,7 @@ STATIC void asc_prt_hex(char *f, uchar *, int);
#endif /* ADVANSYS_DEBUG */
#ifdef ADVANSYS_ASSERT
-STATIC int interrupts_enabled(void);
+STATIC int advansys_interrupts_enabled(void);
#endif /* ADVANSYS_ASSERT */
@@ -7053,7 +7053,7 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
Scsi_Device *device;
int ret;
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %lx, done %lx\n",
(ulong) scp, (ulong) scp->scsi_done);
@@ -7182,7 +7182,7 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
}
ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
return ret;
}
@@ -7602,7 +7602,7 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
struct Scsi_Host *shp;
int i;
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %lx, qdonep %lx\n",
(ulong) asc_dvc_varp, (ulong) qdonep);
ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
@@ -7773,7 +7773,7 @@ adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
struct Scsi_Host *shp;
int i;
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %lx, scsiqp %lx\n",
(ulong) adv_dvc_varp, (ulong) scsiqp);
ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
@@ -8422,7 +8422,7 @@ asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
ASC_DBG3(3, "asc_enqueue: ascq %lx, reqp %lx, flag %d\n",
(ulong) ascq, (ulong) reqp, flag);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
tid = REQPTID(reqp);
@@ -8475,7 +8475,7 @@ asc_dequeue(asc_queue_t *ascq, int tid)
REQP reqp;
ASC_DBG2(3, "asc_dequeue: ascq %lx, tid %d\n", (ulong) ascq, tid);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
if ((reqp = ascq->q_first[tid]) != NULL) {
ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
@@ -8524,7 +8524,7 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
int i;
ASC_DBG2(3, "asc_dequeue_list: ascq %lx, tid %d\n", (ulong) ascq, tid);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
/*
@@ -8607,7 +8607,7 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
ASC_DBG2(3, "asc_rmqueue: ascq %lx, reqp %lx\n",
(ulong) ascq, (ulong) reqp);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
tid = REQPTID(reqp);
@@ -8675,7 +8675,7 @@ asc_isqueued(asc_queue_t *ascq, REQP reqp)
ASC_DBG2(3, "asc_isqueued: ascq %lx, reqp %lx\n",
(ulong) ascq, (ulong) reqp);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
tid = REQPTID(reqp);
@@ -8705,7 +8705,7 @@ asc_execute_queue(asc_queue_t *ascq)
int i;
ASC_DBG1(1, "asc_execute_queue: ascq %lx\n", (ulong) ascq);
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_ASSERT(advansys_interrupts_enabled() == ASC_FALSE);
/*
* Execute queued commands for devices attached to
* the current board in round-robin fashion.
@@ -10919,12 +10919,12 @@ asc_prt_hex(char *f, uchar *s, int l)
#ifdef ADVANSYS_ASSERT
/*
- * interrupts_enabled()
+ * advansys_interrupts_enabled()
*
* Return 1 if interrupts are enabled, otherwise return 0.
*/
STATIC int
-interrupts_enabled(void)
+advansys_interrupts_enabled(void)
{
int flags;
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index d87bf6d70..c1939a817 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1212,7 +1212,7 @@ static int option_setup(char *str) {
ints[0] = i - 1;
internal_setup(cur, ints);
- return 0;
+ return 1;
}
static void add_pci_ports(void) {
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
index 8bc0230fd..8e9c314ba 100644
--- a/drivers/scsi/qlogicisp.c
+++ b/drivers/scsi/qlogicisp.c
@@ -6,6 +6,9 @@
* Copyright 2000, Jayson C. Vantuyl <vantuyl@csc.smsu.edu>
* and Bryon W. Roche <bryon@csc.smsu.edu>
*
+ * 64-bit addressing added by Kanoj Sarcar <kanoj@sgi.com>
+ * and Leo Dagum <dagum@sgi.com>
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
@@ -18,6 +21,7 @@
*/
#include <linux/blk.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
@@ -179,7 +183,7 @@ struct {
#define REQUEST_QUEUE_WAKEUP 0x8005
#define EXECUTION_TIMEOUT_RESET 0x8006
-#ifdef CONFIG_QL_ISP_A64
+#ifdef CONFIG_QL_ISP_A64
#define IOCB_SEGS 2
#define CONTINUATION_SEGS 5
#define MAX_CONTINUATION_ENTRIES 254
@@ -500,7 +504,7 @@ static const u_char mbox_param[] = {
PACKB(0, 0), /* 0x004b */
PACKB(0, 0), /* 0x004c */
PACKB(0, 0), /* 0x004d */
- PACKB(0, 0), /* 0x004e */
+ PACKB(0, 0), /* 0x004e */
PACKB(0, 0), /* 0x004f */
PACKB(0, 0), /* 0x0050 */
PACKB(0, 0), /* 0x0051 */
@@ -907,7 +911,7 @@ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
dma_addr = sg_dma_address(sg);
ds[i].d_base = cpu_to_le32((u32) dma_addr);
#ifdef CONFIG_QL_ISP_A64
- ds[i].d_base_hi = cpu_to_le32((u32) (dma_addr>>32));
+ ds[i].d_base_hi = cpu_to_le32((u32)(dma_addr>>32));
#endif /* CONFIG_QL_ISP_A64 */
ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
++sg;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 21cb989ca..9fa8bc444 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1377,12 +1377,12 @@ int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
*/
void scsi_release_commandblocks(Scsi_Device * SDpnt)
{
- Scsi_Cmnd *SCpnt;
+ Scsi_Cmnd *SCpnt, *SCnext;
unsigned long flags;
- spin_lock_irqsave(&device_request_lock, flags);
- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
- SDpnt->device_queue = SCpnt->next;
+ spin_lock_irqsave(&device_request_lock, flags);
+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
+ SDpnt->device_queue = SCnext = SCpnt->next;
kfree((char *) SCpnt);
}
SDpnt->has_cmdblocks = 0;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8df062781..8ea85f0cd 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -5,14 +5,14 @@
History:
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including (in alphabetical
- order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
- Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and
- Eric Youngdale.
+ order) Klaus Ehrenfried, Eric Lee Green, Wolfgang Denk, Steve Hirsch,
+ Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer,
+ J"org Weule, and Eric Youngdale.
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Mon Mar 13 21:15:29 2000 by makisara@kai.makisara.local
+ Last modified: Sun Mar 19 22:06:54 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -2621,8 +2621,7 @@ static int update_partition(Scsi_Tape *STp)
return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
}
-/* Functions for reading and writing the medium partition mode page. These
- seem to work with Wangtek 6200HS and HP C1533A. */
+/* Functions for reading and writing the medium partition mode page. */
#define PART_PAGE 0x11
#define PART_PAGE_FIXED_LENGTH 8
@@ -2675,6 +2674,11 @@ static int nbr_partitions(Scsi_Tape *STp)
The following algorithm is used to accomodate both drives: if the number of
partition size fields is greater than the maximum number of additional partitions
in the mode page, the second field is used. Otherwise the first field is used.
+
+ For Seagate DDS drives the page length must be 8 when no partitions is defined
+ and 10 when 1 partition is defined (information from Eric Lee Green). This is
+ is acceptable also to some other old drives and enforced if the first partition
+ size field is used for the first additional partition size.
*/
static int partition_tape(Scsi_Tape *STp, int size)
{
@@ -2707,12 +2711,16 @@ static int partition_tape(Scsi_Tape *STp, int size)
if (size <= 0) {
bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
+ if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n",
dev));
} else {
bp[psdo] = (size >> 8) & 0xff;
bp[psdo + 1] = size & 0xff;
bp[pgo + 3] = 1;
+ if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
+ bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
DEBC(printk(ST_DEB_MSG
"st%d: Formatting tape with two partitions (1 = %d MB).\n",
dev, size));
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 379b55874..aa6706e8c 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -943,7 +943,7 @@ static int option_setup(char *str) {
ints[0] = i - 1;
internal_setup(cur, ints);
- return 0;
+ return 1;
}
int u14_34f_detect(Scsi_Host_Template *tpnt)
diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c
index 0a0e30775..ae866148b 100644
--- a/drivers/sound/ac97_codec.c
+++ b/drivers/sound/ac97_codec.c
@@ -25,7 +25,7 @@
* v0.3 Feb 22 2000 Ollie Lho
* bug fix for record mask setting
* v0.2 Feb 10 2000 Ollie Lho
- * add ac97_read_proc for /proc/driver/vnedor/ac97
+ * add ac97_read_proc for /proc/driver/{vendor}/ac97
* v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
* Isolated from trident.c to support multiple ac97 codec
*/
diff --git a/drivers/sound/awe_hw.h b/drivers/sound/awe_hw.h
index c7dde2679..7e403ad68 100644
--- a/drivers/sound/awe_hw.h
+++ b/drivers/sound/awe_hw.h
@@ -3,9 +3,9 @@
*
* Access routines and definitions for the low level driver for the
* Creative AWE32/SB32/AWE64 wave table synth.
- * version 0.4.3; Mar. 1, 1998
+ * version 0.4.4; Jan. 4, 2000
*
- * Copyright (C) 1996-1998 Takashi Iwai
+ * Copyright (C) 1996-2000 Takashi Iwai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/sound/awe_wave.c b/drivers/sound/awe_wave.c
index bedebb3b6..ac00add8f 100644
--- a/drivers/sound/awe_wave.c
+++ b/drivers/sound/awe_wave.c
@@ -2,9 +2,9 @@
* sound/awe_wave.c
*
* The low level driver for the AWE32/SB32/AWE64 wave table synth.
- * version 0.4.3; Feb. 1, 1999
+ * version 0.4.4; Jan. 4, 2000
*
- * Copyright (C) 1996-1999 Takashi Iwai
+ * Copyright (C) 1996-2000 Takashi Iwai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,9 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+#include <linux/isapnp.h>
+#endif
#include "sound_config.h"
#include "soundmodule.h"
@@ -42,9 +45,6 @@
* debug message
*/
-/* do not allocate buffer at beginning */
-#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
-
#ifdef AWE_DEBUG_ON
#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
@@ -59,56 +59,56 @@
* bank and voice record
*/
+typedef struct _sf_list sf_list;
+typedef struct _awe_voice_list awe_voice_list;
+typedef struct _awe_sample_list awe_sample_list;
+
/* soundfont record */
-typedef struct _sf_list {
- unsigned short sf_id;
- unsigned short type;
+struct _sf_list {
+ unsigned short sf_id; /* id number */
+ unsigned short type; /* lock & shared flags */
int num_info; /* current info table index */
int num_sample; /* current sample table index */
int mem_ptr; /* current word byte pointer */
- int infos;
- int samples;
+ awe_voice_list *infos, *last_infos; /* instruments */
+ awe_sample_list *samples, *last_samples; /* samples */
#ifdef AWE_ALLOW_SAMPLE_SHARING
- int shared; /* shared index */
- unsigned char name[AWE_PATCH_NAME_LEN];
+ sf_list *shared; /* shared list */
+ unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */
#endif
-} sf_list;
+ sf_list *next, *prev;
+};
-/* bank record */
-typedef struct _awe_voice_list {
- int next; /* linked list with same sf_id */
+/* instrument list */
+struct _awe_voice_list {
+ awe_voice_info v; /* instrument information */
+ sf_list *holder; /* parent sf_list of this record */
unsigned char bank, instr; /* preset number information */
char type, disabled; /* type=normal/mapped, disabled=boolean */
- awe_voice_info v; /* voice information */
- int next_instr; /* preset table list */
- int next_bank; /* preset table list */
-} awe_voice_list;
+ awe_voice_list *next; /* linked list with same sf_id */
+ awe_voice_list *next_instr; /* instrument list */
+ awe_voice_list *next_bank; /* hash table list */
+};
/* voice list type */
#define V_ST_NORMAL 0
#define V_ST_MAPPED 1
-typedef struct _awe_sample_list {
- int next; /* linked list with same sf_id */
+/* sample list */
+struct _awe_sample_list {
awe_sample_info v; /* sample information */
-} awe_sample_list;
+ sf_list *holder; /* parent sf_list of this record */
+ awe_sample_list *next; /* linked list with same sf_id */
+};
/* sample and information table */
-static int current_sf_id = 0;
-static int locked_sf_id = 0;
-static int max_sfs;
-static sf_list *sflists = NULL;
-
-#define awe_free_mem_ptr() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].mem_ptr)
-#define awe_free_info() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_info)
-#define awe_free_sample() (current_sf_id <= 0 ? 0 : sflists[current_sf_id-1].num_sample)
-
-static int max_samples;
-static awe_sample_list *samples = NULL;
-
-static int max_infos;
-static awe_voice_list *infos = NULL;
+static int current_sf_id = 0; /* current number of fonts */
+static int locked_sf_id = 0; /* locked position */
+static sf_list *sfhead = NULL, *sftail = NULL; /* linked-lists */
+#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)
+#define awe_free_info() (sftail ? sftail->num_info : 0)
+#define awe_free_sample() (sftail ? sftail->num_sample : 0)
#define AWE_MAX_PRESETS 256
#define AWE_DEFAULT_PRESET 0
@@ -119,7 +119,7 @@ static awe_voice_list *infos = NULL;
#define MAX_LAYERS AWE_MAX_VOICES
/* preset table index */
-static int preset_table[AWE_MAX_PRESETS];
+static awe_voice_list *preset_table[AWE_MAX_PRESETS];
/*
* voice table
@@ -143,8 +143,6 @@ typedef struct _awe_chan_info {
int main_vol; /* channel volume (0-127) */
int expression_vol; /* midi expression (0-127) */
int chan_press; /* channel pressure */
- int vrec; /* instrument list */
- int def_vrec; /* default instrument list */
int sustained; /* sustain status in MIDI */
FX_Rec fx; /* effects */
FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
@@ -194,9 +192,9 @@ static voice_info voices[AWE_MAX_VOICES];
static awe_chan_info channels[AWE_MAX_CHANNELS];
-/*----------------------------------------------------------------
+/*
* global variables
- *----------------------------------------------------------------*/
+ */
#ifndef AWE_DEFAULT_BASE_ADDR
#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */
@@ -206,10 +204,13 @@ static awe_chan_info channels[AWE_MAX_CHANNELS];
#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */
#endif
-#define awe_port io
-#define awe_mem_size memsize
int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static int isapnp = 1;
+#else
+static int isapnp = 0;
+#endif
MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
@@ -217,6 +218,8 @@ MODULE_PARM(io, "i");
MODULE_PARM_DESC(io, "base i/o port of Emu8000");
MODULE_PARM(memsize, "i");
MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
+MODULE_PARM(isapnp, "i");
+MODULE_PARM_DESC(isapnp, "use ISAPnP detection");
EXPORT_NO_SYMBOLS;
/* DRAM start offset */
@@ -255,7 +258,7 @@ static struct synth_info awe_info = {
0, /* perc_mode (obsolete) */
AWE_MAX_VOICES, /* nr_voices */
0, /* nr_drums (obsolete) */
- AWE_MAX_INFOS /* instr_bank_size */
+ 400 /* instr_bank_size */
};
@@ -362,8 +365,9 @@ static void awe_sustain_off(int voice, int forced);
static void awe_terminate_and_init(int voice, int forced);
/* voice search */
-static int awe_search_instr(int bank, int preset);
-static int awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist);
+static int awe_search_key(int bank, int preset, int note);
+static awe_voice_list *awe_search_instr(int bank, int preset, int note);
+static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);
static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
static void awe_alloc_one_voice(int voice, int note, int velocity);
static int awe_clear_voice(void);
@@ -373,6 +377,7 @@ static int awe_open_patch(awe_patch_info *patch, const char *addr, int count);
static int awe_close_patch(awe_patch_info *patch, const char *addr, int count);
static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count);
static int awe_load_info(awe_patch_info *patch, const char *addr, int count);
+static int awe_remove_info(awe_patch_info *patch, const char *addr, int count);
static int awe_load_data(awe_patch_info *patch, const char *addr, int count);
static int awe_replace_data(awe_patch_info *patch, const char *addr, int count);
static int awe_load_map(awe_patch_info *patch, const char *addr, int count);
@@ -381,22 +386,24 @@ static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag
#endif
/*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/
static int awe_probe_data(awe_patch_info *patch, const char *addr, int count);
-static int check_patch_opened(int type, char *name);
-static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels);
-static void add_sf_info(int rec);
-static void add_sf_sample(int rec);
-static void purge_old_list(int rec, int next);
-static void add_info_list(int rec);
+static sf_list *check_patch_opened(int type, char *name);
+static int awe_write_wave_data(const char *addr, int offset, awe_sample_list *sp, int channels);
+static int awe_create_sf(int type, char *name);
+static void awe_free_sf(sf_list *sf);
+static void add_sf_info(sf_list *sf, awe_voice_list *rec);
+static void add_sf_sample(sf_list *sf, awe_sample_list *smp);
+static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);
+static void add_info_list(awe_voice_list *rec);
static void awe_remove_samples(int sf_id);
static void rebuild_preset_list(void);
-static short awe_set_sample(awe_voice_info *vp);
-static int search_sample_index(int sf, int sample, int level);
+static short awe_set_sample(awe_voice_list *rec);
+static awe_sample_list *search_sample_index(sf_list *sf, int sample);
+static int is_identical_holder(sf_list *sf1, sf_list *sf2);
#ifdef AWE_ALLOW_SAMPLE_SHARING
-static int is_identical_id(int id1, int id2);
-static int is_identical_name(unsigned char *name, int id);
+static int is_identical_name(unsigned char *name, sf_list *p);
static int is_shared_sf(unsigned char *name);
-static int info_duplicated(awe_voice_list *rec);
+static int info_duplicated(sf_list *sf, awe_voice_list *rec);
#endif /* allow sharing */
/* lowlevel functions */
@@ -410,7 +417,7 @@ static void awe_init_fm(void);
static int awe_open_dram_for_write(int offset, int channels);
static void awe_open_dram_for_check(void);
static void awe_close_dram(void);
-static void awe_write_dram(unsigned short c);
+/*static void awe_write_dram(unsigned short c);*/
static int awe_detect_base(int addr);
static int awe_detect(void);
static void awe_check_dram(void);
@@ -483,9 +490,9 @@ static struct CtrlParmsDef {
static int ctrls[AWE_MD_END];
-/*----------------------------------------------------------------
+/*
* synth operation table
- *----------------------------------------------------------------*/
+ */
static struct synth_operations awe_operations =
{
@@ -513,39 +520,32 @@ static struct synth_operations awe_operations =
};
-/*================================================================
+/*
* General attach / unload interface
- *================================================================*/
+ */
-static int _attach_awe(void)
+static int __init _attach_awe(void)
{
if (awe_present) return 0; /* for OSS38.. called twice? */
/* check presence of AWE32 card */
if (! awe_detect()) {
- printk(KERN_WARNING "AWE32: not detected\n");
+ printk(KERN_ERR "AWE32: not detected\n");
return 0;
}
/* check AWE32 ports are available */
if (awe_check_port()) {
- printk(KERN_WARNING "AWE32: I/O area already used.\n");
+ printk(KERN_ERR "AWE32: I/O area already used.\n");
return 0;
}
/* set buffers to NULL */
- sflists = NULL;
- samples = NULL;
- infos = NULL;
-
- /* allocate sample tables */
- INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list);
- INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list);
- INIT_TABLE(infos, max_infos, AWE_MAX_INFOS, awe_voice_list);
+ sfhead = sftail = NULL;
my_dev = sound_alloc_synthdev();
if (my_dev == -1) {
- printk(KERN_WARNING "AWE32 Error: too many synthesizers\n");
+ printk(KERN_ERR "AWE32 Error: too many synthesizers\n");
return 0;
}
@@ -570,8 +570,8 @@ static int _attach_awe(void)
awe_initialize();
sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
- AWEDRV_VERSION, awe_mem_size/1024);
- printk("<SoundBlaster EMU8000 (RAM%dk)>\n", awe_mem_size/1024);
+ AWEDRV_VERSION, memsize/1024);
+ printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024);
awe_present = TRUE;
@@ -583,33 +583,18 @@ static int _attach_awe(void)
static void free_tables(void)
{
- if(sflists)
- vfree(sflists);
- sflists = NULL; max_sfs = 0;
- if (samples)
- vfree(samples);
- samples = NULL; max_samples = 0;
- if (infos)
- vfree(infos);
- infos = NULL; max_infos = 0;
-}
-
-static void *realloc_block(void *buf, int oldsize, int size)
-{
- void *ptr;
- if (oldsize == size)
- return buf;
- if ((ptr = vmalloc(size)) == NULL)
- return NULL;
- if (oldsize && size)
- memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) );
- if (buf)
- vfree(buf);
- return ptr;
+ if (sftail) {
+ sf_list *p, *prev;
+ for (p = sftail; p; p = prev) {
+ prev = p->prev;
+ awe_free_sf(p);
+ }
+ }
+ sfhead = sftail = NULL;
}
-static void _unload_awe(void)
+static void __exit _unload_awe(void)
{
if (awe_present) {
awe_reset_samples();
@@ -627,96 +612,6 @@ static void _unload_awe(void)
}
}
-/*
- * Linux PnP driver support
- */
-
-#ifdef CONFIG_PNP_DRV
-
-#include <linux/pnp.h>
-
-static int pnp = 1; /* use PnP as default */
-
-#define AWE_NUM_CHIPS 3
-static unsigned int pnp_ids[AWE_NUM_CHIPS] = {
- PNP_EISAID('C','T','L',0x0021),
- PNP_EISAID('C','T','L',0x0022),
- PNP_EISAID('C','T','L',0x0023),
-};
-static struct pnp_driver pnp_awe[AWE_NUM_CHIPS];
-static int awe_pnp_ok = 0;
-
-static void awe_pnp_config(struct pnp_device *d)
-{
- struct pnp_resource *r;
- int port[3];
- int nio = 0;
-
- port[0] = port[1] = port[2] = 0;
- for (r = d->res; r != NULL; r = r->next) {
- if (r->type == PNP_RES_IO) {
- if (nio >= 0 && nio < 3)
- port[nio] = r->start;
- nio++;
- }
- }
- setup_ports(port[0], port[1], port[2]);
- DEBUG(0,printk("AWE32: PnP setup ports: %x:%x:%x\n", port[0], port[1], port[2]));
-}
-
-static int awe_pnp_event (struct pnp_device *d, struct pnp_drv_event *e)
-{
- struct pnp_driver *drv = d->l.k.driver;
-
- switch (e->type) {
- case PNP_DRV_ALLOC:
- drv->flags |= PNP_DRV_INUSE;
- awe_pnp_ok = 1;
- awe_pnp_config(d);
- _attach_awe();
- break;
-
- case PNP_DRV_DISABLE:
- case PNP_DRV_EMERGSTOP:
- drv->flags &= ~PNP_DRV_INUSE;
- awe_pnp_ok = 0;
- _unload_awe();
- break;
-
- case PNP_DRV_CONFIG:
- if (awe_busy) return 1; /* used now */
- awe_release_region();
- awe_pnp_config(d);
- awe_request_region();
- break;
-
- case PNP_DRV_RECONFIG:
- break;
- }
- return 0;
-}
-
-static int awe_initpnp (void)
-{
- int i;
- for (i = 0; i < AWE_NUM_CHIPS; i++) {
- pnp_awe[i].id.type = PNP_HDL_ISA;
- pnp_awe[i].id.t.isa.id = pnp_ids[i];
- pnp_awe[i].id.next = NULL;
- pnp_awe[i].name = "Soundblaster AWE32/AWE64 PnP";
- pnp_awe[i].event = awe_pnp_event;
- pnp_register_driver(&pnp_awe[i], 1);
- }
- return 0;
-}
-
-static void awe_unload_pnp (void)
-{
- int i;
- for (i = 0; i < AWE_NUM_CHIPS; i++)
- pnp_unregister_driver(&pnp_awe[i]);
-}
-#endif /* PnP support */
/*
* clear sample tables
@@ -725,12 +620,8 @@ static void awe_unload_pnp (void)
static void
awe_reset_samples(void)
{
- int i;
-
/* free all bank tables */
- for (i = 0; i < AWE_MAX_PRESETS; i++)
- preset_table[i] = -1;
-
+ memset(preset_table, 0, sizeof(preset_table));
free_tables();
current_sf_id = 0;
@@ -767,7 +658,7 @@ static void setup_ports(int port1, int port2, int port3)
}
/* write 16bit data */
-static inline void
+static void
awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
{
awe_set_cmd(cmd);
@@ -775,7 +666,7 @@ awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
}
/* write 32bit data */
-static inline void
+static void
awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
{
unsigned short addr = awe_ports[port];
@@ -785,7 +676,7 @@ awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
}
/* read 16bit data */
-static inline unsigned short
+static unsigned short
awe_peek(unsigned short cmd, unsigned short port)
{
unsigned short k;
@@ -795,7 +686,7 @@ awe_peek(unsigned short cmd, unsigned short port)
}
/* read 32bit data */
-static inline unsigned int
+static unsigned int
awe_peek_dw(unsigned short cmd, unsigned short port)
{
unsigned int k1, k2;
@@ -837,14 +728,16 @@ static void awe_wait(unsigned short delay)
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
}
+/*
+static void awe_wait(unsigned short delay)
+{
+ udelay(((unsigned long)delay * 1000000L + 44099) / 44100);
+}
+*/
#endif /* wait by loop */
/* write a word data */
-static inline void
-awe_write_dram(unsigned short c)
-{
- awe_poke(AWE_SMLD, c);
-}
+#define awe_write_dram(c) awe_poke(AWE_SMLD, c)
/*
@@ -852,7 +745,7 @@ awe_write_dram(unsigned short c)
* 0x620-623, 0xA20-A23, 0xE20-E23
*/
-static int
+static int __init
awe_check_port(void)
{
if (! port_setuped) return 0;
@@ -861,7 +754,7 @@ awe_check_port(void)
check_region(awe_ports[3], 4));
}
-static void
+static void __init
awe_request_region(void)
{
if (! port_setuped) return;
@@ -870,7 +763,7 @@ awe_request_region(void)
request_region(awe_ports[3], 4, "sound driver (AWE32)");
}
-static void
+static void __exit
awe_release_region(void)
{
if (! port_setuped) return;
@@ -879,9 +772,11 @@ awe_release_region(void)
release_region(awe_ports[3], 4);
}
+
/*
- * AWE32 initialization
+ * initialization of AWE driver
*/
+
static void
awe_initialize(void)
{
@@ -935,7 +830,6 @@ awe_initialize(void)
static void
awe_init_voice_info(awe_voice_info *vp)
{
- vp->sf_id = 0; /* normal mode */
vp->sample = 0;
vp->rate_offset = 0;
@@ -1338,7 +1232,7 @@ awe_note_on(int voice)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
/* A voice sample must assigned before calling */
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
parm = (awe_voice_parm_block*)&vp->parm;
@@ -1457,15 +1351,15 @@ awe_note_on(int voice)
awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
- /* turn on envelope */
- awe_poke(AWE_DCYSUSV(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
- vp->parm.voldcysus));
/* set reverb */
temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
awe_poke_dw(AWE_PTRX(voice), temp);
awe_poke_dw(AWE_CPF(voice), ptarget << 16);
+ /* turn on envelope */
+ awe_poke(AWE_DCYSUSV(voice),
+ FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
+ vp->parm.voldcysus));
voices[voice].state = AWE_ST_ON;
@@ -1568,7 +1462,7 @@ awe_set_volume(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (!IS_PLAYING(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
@@ -1603,7 +1497,7 @@ awe_set_pan(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
/* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
@@ -1622,14 +1516,16 @@ awe_set_pan(int voice, int forced)
}
if (forced || temp != voices[voice].apan) {
voices[voice].apan = temp;
+ if (temp == 0)
+ voices[voice].aaux = 0xff;
+ else
+ voices[voice].aaux = (-temp) & 0xff;
addr = vp->loopstart - 1;
addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
AWE_FX_COARSE_LOOP_START, vp->mode);
temp = (temp<<24) | (unsigned int)addr;
awe_poke_dw(AWE_PSST(voice), temp);
DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
- if (temp == 0) voices[voice].aaux = 0xff;
- else voices[voice].aaux = (-temp)&0xff;
}
}
@@ -1644,7 +1540,7 @@ awe_fx_fmmod(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
awe_poke(AWE_FMMOD(voice),
FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
@@ -1662,7 +1558,7 @@ awe_fx_tremfrq(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
awe_poke(AWE_TREMFRQ(voice),
FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
@@ -1680,7 +1576,7 @@ awe_fx_fm2frq2(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
awe_poke(AWE_FM2FRQ2(voice),
FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
@@ -1700,7 +1596,7 @@ awe_fx_filterQ(int voice, int forced)
fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ if ((vp = voices[voice].sample) == NULL || vp->index == 0)
return;
addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
@@ -1708,12 +1604,12 @@ awe_fx_filterQ(int voice, int forced)
awe_poke_dw(AWE_CCCA(voice), addr);
}
-/*================================================================
+/*
* calculate pitch offset
- *----------------------------------------------------------------
+ *
* 0xE000 is no pitch offset at 44100Hz sample.
* Every 4096 is one octave.
- *================================================================*/
+ */
static void
awe_calc_pitch(int voice)
@@ -1726,9 +1622,9 @@ awe_calc_pitch(int voice)
/* search voice information */
if ((ap = vp->sample) == NULL)
return;
- if (ap->index < 0) {
+ if (ap->index == 0) {
DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample(ap) < 0)
+ if (awe_set_sample((awe_voice_list*)ap) == 0)
return;
}
@@ -1785,9 +1681,9 @@ awe_calc_pitch_from_freq(int voice, int freq)
/* search voice information */
if ((ap = vp->sample) == NULL)
return;
- if (ap->index < 0) {
+ if (ap->index == 0) {
DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample(ap) < 0)
+ if (awe_set_sample((awe_voice_list*)ap) == 0)
return;
}
note = freq_to_note(freq);
@@ -1806,13 +1702,13 @@ awe_calc_pitch_from_freq(int voice, int freq)
#endif /* AWE_HAS_GUS_COMPATIBILITY */
-/*================================================================
+/*
* calculate volume attenuation
- *----------------------------------------------------------------
+ *
* Voice volume is controlled by volume attenuation parameter.
* So volume becomes maximum when avol is 0 (no attenuation), and
* minimum when 255 (-96dB or silence).
- *================================================================*/
+ */
static int vol_table[128] = {
255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
@@ -1887,9 +1783,9 @@ awe_calc_volume(int voice)
return;
ap = vp->sample;
- if (ap->index < 0) {
+ if (ap->index == 0) {
DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample(ap) < 0)
+ if (awe_set_sample((awe_voice_list*)ap) == 0)
return;
}
@@ -2054,8 +1950,6 @@ static void awe_channel_init(int ch, int init_all)
cp->instr = ctrls[AWE_MD_DEF_PRESET];
cp->bank = ctrls[AWE_MD_DEF_BANK];
}
- cp->vrec = -1;
- cp->def_vrec = -1;
}
cp->bender = 0; /* zero tune skew */
@@ -2092,9 +1986,9 @@ static void awe_voice_change(int voice, fx_affect_func func)
}
-/*----------------------------------------------------------------
+/*
* device open / close
- *----------------------------------------------------------------*/
+ */
/* open device:
* reset status of all voices, and clear sample position flag
@@ -2158,13 +2052,13 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
awe_info.nr_voices = awe_max_voices;
else
awe_info.nr_voices = AWE_MAX_CHANNELS;
- memcpy((char*)arg, &awe_info + 0, sizeof(awe_info));
+ memcpy((char*)arg, &awe_info, sizeof(awe_info));
return 0;
break;
case SNDCTL_SEQ_RESETSAMPLES:
- awe_reset_samples();
awe_reset(dev);
+ awe_reset_samples();
return 0;
break;
@@ -2174,10 +2068,10 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
break;
case SNDCTL_SYNTH_MEMAVL:
- return awe_mem_size - awe_free_mem_ptr() * 2;
+ return memsize - awe_free_mem_ptr() * 2;
default:
- printk("AWE32: unsupported ioctl %d\n", cmd);
+ printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd);
return -EINVAL;
}
}
@@ -2358,18 +2252,46 @@ awe_start_note(int dev, int voice, int note, int velocity)
}
-/* search instrument from preset table with the specified bank */
+/* calculate hash key */
static int
-awe_search_instr(int bank, int preset)
+awe_search_key(int bank, int preset, int note)
{
- int i;
+ unsigned int key;
- limitvalue(preset, 0, AWE_MAX_PRESETS-1);
- for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) {
- if (infos[i].bank == bank)
- return i;
+#if 1 /* new hash table */
+ if (bank == AWE_DRUM_BANK)
+ key = preset + note + 128;
+ else
+ key = bank + preset;
+#else
+ key = preset;
+#endif
+ key %= AWE_MAX_PRESETS;
+
+ return (int)key;
+}
+
+
+/* search instrument from hash table */
+static awe_voice_list *
+awe_search_instr(int bank, int preset, int note)
+{
+ awe_voice_list *p;
+ int key, key2;
+
+ key = awe_search_key(bank, preset, note);
+ for (p = preset_table[key]; p; p = p->next_bank) {
+ if (p->instr == preset && p->bank == bank)
+ return p;
}
- return -1;
+ key2 = awe_search_key(bank, preset, 0); /* search default */
+ if (key == key2)
+ return NULL;
+ for (p = preset_table[key2]; p; p = p->next_bank) {
+ if (p->instr == preset && p->bank == bank)
+ return p;
+ }
+ return NULL;
}
@@ -2390,7 +2312,6 @@ static int
awe_set_instr(int dev, int voice, int instr_no)
{
awe_chan_info *cinfo;
- int def_bank;
if (! voice_in_range(voice))
return -EINVAL;
@@ -2399,26 +2320,8 @@ awe_set_instr(int dev, int voice, int instr_no)
return -EINVAL;
cinfo = &channels[voice];
-
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
- def_bank = AWE_DRUM_BANK; /* always search drumset */
- else
- def_bank = cinfo->bank;
-
- cinfo->vrec = -1;
- cinfo->def_vrec = -1;
- cinfo->vrec = awe_search_instr(def_bank, instr_no);
- if (def_bank == AWE_DRUM_BANK) /* search default drumset */
- cinfo->def_vrec = awe_search_instr(def_bank, ctrls[AWE_MD_DEF_DRUM]);
- else /* search default preset */
- cinfo->def_vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr_no);
-
- if (cinfo->vrec < 0 && cinfo->def_vrec < 0) {
- DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no));
- }
-
cinfo->instr = instr_no;
- DEBUG(2,printk("AWE32: [program(%d) %d/%d]\n", voice, instr_no, def_bank));
+ DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no));
return 0;
}
@@ -2576,7 +2479,7 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event)
switch (cmd) {
case _AWE_DEBUG_MODE:
ctrls[AWE_MD_DEBUG_MODE] = p1;
- printk("AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
+ printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
break;
case _AWE_REVERB_MODE:
ctrls[AWE_MD_REVERB_MODE] = p1;
@@ -2590,6 +2493,7 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event)
case _AWE_REMOVE_LAST_SAMPLES:
DEBUG(0,printk("AWE32: remove last samples\n"));
+ awe_reset(0);
if (locked_sf_id > 0)
awe_remove_samples(locked_sf_id);
break;
@@ -2772,6 +2676,8 @@ awe_controller(int dev, int voice, int ctrl_num, int value)
if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
!ctrls[AWE_MD_TOGGLE_DRUM_BANK])
break;
+ if (value < 0 || value > 255)
+ break;
cinfo->bank = value;
if (cinfo->bank == AWE_DRUM_BANK)
DRUM_CHANNEL_ON(cinfo->channel);
@@ -2920,10 +2826,10 @@ awe_bender(int dev, int voice, int value)
}
-/*----------------------------------------------------------------
+/*
* load a sound patch:
* three types of patches are accepted: AWE, GUS, and SYSEX.
- *----------------------------------------------------------------*/
+ */
static int
awe_load_patch(int dev, int format, const char *addr,
@@ -2941,20 +2847,21 @@ awe_load_patch(int dev, int format, const char *addr,
/* no system exclusive message supported yet */
return 0;
} else if (format != AWE_PATCH) {
- printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format);
+ printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format);
return -EINVAL;
}
if (count < AWE_PATCH_INFO_SIZE) {
- printk("AWE32 Error: Patch header too short\n");
+ printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
return -EINVAL;
}
- copy_from_user(((char*)&patch) + offs, addr + offs,
- AWE_PATCH_INFO_SIZE - offs);
+ if (copy_from_user(((char*)&patch) + offs, addr + offs,
+ AWE_PATCH_INFO_SIZE - offs))
+ return -EFAULT;
count -= AWE_PATCH_INFO_SIZE;
if (count < patch.len) {
- printk("AWE32: sample: Patch record too short (%d<%d)\n",
+ printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n",
count, patch.len);
return -EINVAL;
}
@@ -2987,6 +2894,9 @@ awe_load_patch(int dev, int format, const char *addr,
case AWE_PROBE_DATA:
rc = awe_probe_data(&patch, addr, count);
break;
+ case AWE_REMOVE_INFO:
+ rc = awe_remove_info(&patch, addr, count);
+ break;
case AWE_LOAD_CHORUS_FX:
rc = awe_load_chorus_fx(&patch, addr, count);
break;
@@ -2995,7 +2905,7 @@ awe_load_patch(int dev, int format, const char *addr,
break;
default:
- printk("AWE32 Error: unknown patch format type %d\n",
+ printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n",
patch.type);
rc = -EINVAL;
}
@@ -3004,7 +2914,7 @@ awe_load_patch(int dev, int format, const char *addr,
}
-/* create an sflist record */
+/* create an sf list record */
static int
awe_create_sf(int type, char *name)
{
@@ -3012,40 +2922,43 @@ awe_create_sf(int type, char *name)
/* terminate sounds */
awe_reset(0);
- if (current_sf_id >= max_sfs) {
- int newsize = max_sfs + AWE_MAX_SF_LISTS;
- sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs,
- sizeof(sf_list)*newsize);
- if (newlist == NULL)
- return 1;
- sflists = newlist;
- max_sfs = newsize;
- }
- rec = &sflists[current_sf_id];
+ rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL);
+ if (rec == NULL)
+ return 1; /* no memory */
rec->sf_id = current_sf_id + 1;
rec->type = type;
- if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0)
+ if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0)
locked_sf_id = current_sf_id + 1;
rec->num_info = awe_free_info();
rec->num_sample = awe_free_sample();
rec->mem_ptr = awe_free_mem_ptr();
- rec->infos = -1;
- rec->samples = -1;
+ rec->infos = rec->last_infos = NULL;
+ rec->samples = rec->last_samples = NULL;
+
+ /* add to linked-list */
+ rec->next = NULL;
+ rec->prev = sftail;
+ if (sftail)
+ sftail->next = rec;
+ else
+ sfhead = rec;
+ sftail = rec;
+ current_sf_id++;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- rec->shared = 0;
+ rec->shared = NULL;
if (name)
memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
else
strcpy(rec->name, "*TEMPORARY*");
- if (current_sf_id > 0 && name && (type & AWE_PAT_SHARED) != 0) {
+ if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) {
/* is the current font really a shared font? */
if (is_shared_sf(rec->name)) {
/* check if the shared font is already installed */
- int i;
- for (i = current_sf_id; i > 0; i--) {
- if (is_identical_name(rec->name, i)) {
- rec->shared = i;
+ sf_list *p;
+ for (p = rec->prev; p; p = p->prev) {
+ if (is_identical_name(rec->name, p)) {
+ rec->shared = p;
break;
}
}
@@ -3053,8 +2966,6 @@ awe_create_sf(int type, char *name)
}
#endif /* allow sharing */
- current_sf_id++;
-
return 0;
}
@@ -3065,37 +2976,31 @@ awe_create_sf(int type, char *name)
#define ASC_TO_KEY(c) ((c) - 'A' + 1)
static int is_shared_sf(unsigned char *name)
{
- static unsigned char id_head[6] = {
+ static unsigned char id_head[4] = {
ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
AWE_MAJOR_VERSION,
- AWE_MINOR_VERSION,
- AWE_TINY_VERSION,
};
- if (memcmp(name, id_head, 6) == 0)
+ if (memcmp(name, id_head, 4) == 0)
return TRUE;
return FALSE;
}
/* check if the given name matches to the existing list */
-static int is_identical_name(unsigned char *name, int sf)
+static int is_identical_name(unsigned char *name, sf_list *p)
{
- char *id = sflists[sf-1].name;
+ char *id = p->name;
if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
return TRUE;
return FALSE;
}
/* check if the given voice info exists */
-static int info_duplicated(awe_voice_list *rec)
+static int info_duplicated(sf_list *sf, awe_voice_list *rec)
{
- int j, sf_id;
- sf_list *sf;
-
/* search for all sharing lists */
- for (sf_id = rec->v.sf_id; sf_id > 0 && sf_id <= current_sf_id; sf_id = sf->shared) {
- sf = &sflists[sf_id - 1];
- for (j = sf->infos; j >= 0; j = infos[j].next) {
- awe_voice_list *p = &infos[j];
+ for (; sf; sf = sf->shared) {
+ awe_voice_list *p;
+ for (p = sf->infos; p; p = p->next) {
if (p->type == V_ST_NORMAL &&
p->bank == rec->bank &&
p->instr == rec->instr &&
@@ -3111,6 +3016,29 @@ static int info_duplicated(awe_voice_list *rec)
#endif /* AWE_ALLOW_SAMPLE_SHARING */
+/* free sf_list record */
+/* linked-list in this function is not cared */
+static void
+awe_free_sf(sf_list *sf)
+{
+ if (sf->infos) {
+ awe_voice_list *p, *next;
+ for (p = sf->infos; p; p = next) {
+ next = p->next;
+ kfree(p);
+ }
+ }
+ if (sf->samples) {
+ awe_sample_list *p, *next;
+ for (p = sf->samples; p; p = next) {
+ next = p->next;
+ kfree(p);
+ }
+ }
+ kfree(sf);
+}
+
+
/* open patch; create sf list and set opened flag */
static int
awe_open_patch(awe_patch_info *patch, const char *addr, int count)
@@ -3118,13 +3046,14 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
awe_open_parm parm;
int shared;
- copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm));
+ if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)))
+ return -EFAULT;
shared = FALSE;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (current_sf_id > 0 && (parm.type & AWE_PAT_SHARED) != 0) {
+ if (sftail && (parm.type & AWE_PAT_SHARED) != 0) {
/* is the previous font the same font? */
- if (is_identical_name(parm.name, current_sf_id)) {
+ if (is_identical_name(parm.name, sftail)) {
/* then append to the previous */
shared = TRUE;
awe_reset(0);
@@ -3135,8 +3064,8 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
#endif /* allow sharing */
if (! shared) {
if (awe_create_sf(parm.type, parm.name)) {
- printk("AWE32: can't open: failed to alloc new list\n");
- return -ENOSPC;
+ printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n");
+ return -ENOMEM;
}
}
patch_opened = TRUE;
@@ -3144,28 +3073,30 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
}
/* check if the patch is already opened */
-static int
+static sf_list *
check_patch_opened(int type, char *name)
{
if (! patch_opened) {
if (awe_create_sf(type, name)) {
- printk("AWE32: failed to alloc new list\n");
- return -ENOSPC;
+ printk(KERN_ERR "AWE32: failed to alloc new list\n");
+ return NULL;
}
patch_opened = TRUE;
- return current_sf_id;
+ return sftail;
}
- return current_sf_id;
+ return sftail;
}
/* close the patch; if no voice is loaded, remove the patch */
static int
awe_close_patch(awe_patch_info *patch, const char *addr, int count)
{
- if (patch_opened && current_sf_id > 0) {
+ if (patch_opened && sftail) {
/* if no voice is loaded, release the current patch */
- if (sflists[current_sf_id-1].infos == -1)
+ if (sftail->infos == NULL) {
+ awe_reset(0);
awe_remove_samples(current_sf_id - 1);
+ }
}
patch_opened = 0;
return 0;
@@ -3176,52 +3107,39 @@ awe_close_patch(awe_patch_info *patch, const char *addr, int count)
static int
awe_unload_patch(awe_patch_info *patch, const char *addr, int count)
{
- if (current_sf_id > 0 && current_sf_id > locked_sf_id)
+ if (current_sf_id > 0 && current_sf_id > locked_sf_id) {
+ awe_reset(0);
awe_remove_samples(current_sf_id - 1);
+ }
return 0;
}
/* allocate voice info list records */
-static int alloc_new_info(int nvoices)
+static awe_voice_list *
+alloc_new_info(void)
{
- int newsize, free_info;
awe_voice_list *newlist;
- free_info = awe_free_info();
- if (free_info + nvoices >= max_infos) {
- do {
- newsize = max_infos + AWE_MAX_INFOS;
- } while (free_info + nvoices >= newsize);
- newlist = realloc_block(infos, sizeof(awe_voice_list)*max_infos,
- sizeof(awe_voice_list)*newsize);
- if (newlist == NULL) {
- printk("AWE32: can't alloc info table\n");
- return -ENOSPC;
- }
- infos = newlist;
- max_infos = newsize;
+
+ newlist = (awe_voice_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
+ if (newlist == NULL) {
+ printk(KERN_ERR "AWE32: can't alloc info table\n");
+ return NULL;
}
- return 0;
+ return newlist;
}
/* allocate sample info list records */
-static int alloc_new_sample(void)
+static awe_sample_list *
+alloc_new_sample(void)
{
- int newsize, free_sample;
awe_sample_list *newlist;
- free_sample = awe_free_sample();
- if (free_sample >= max_samples) {
- newsize = max_samples + AWE_MAX_SAMPLES;
- newlist = realloc_block(samples,
- sizeof(awe_sample_list)*max_samples,
- sizeof(awe_sample_list)*newsize);
- if (newlist == NULL) {
- printk("AWE32: can't alloc sample table\n");
- return -ENOSPC;
- }
- samples = newlist;
- max_samples = newsize;
+
+ newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
+ if (newlist == NULL) {
+ printk(KERN_ERR "AWE32: can't alloc sample table\n");
+ return NULL;
}
- return 0;
+ return newlist;
}
/* load voice map */
@@ -3229,35 +3147,33 @@ static int
awe_load_map(awe_patch_info *patch, const char *addr, int count)
{
awe_voice_map map;
- awe_voice_list *rec;
- int p, free_info;
+ awe_voice_list *rec, *p;
+ sf_list *sf;
/* get the link info */
if (count < sizeof(map)) {
- printk("AWE32 Error: invalid patch info length\n");
+ printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
return -EINVAL;
}
- copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
+ if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
+ return -EFAULT;
/* check if the identical mapping already exists */
- p = awe_search_instr(map.map_bank, map.map_instr);
- for (; p >= 0; p = infos[p].next_instr) {
- if (p >= 0 && infos[p].type == V_ST_MAPPED &&
- infos[p].v.low == map.map_key &&
- infos[p].v.start == map.src_instr &&
- infos[p].v.end == map.src_bank &&
- infos[p].v.fixkey == map.src_key)
+ p = awe_search_instr(map.map_bank, map.map_instr, map.map_key);
+ for (; p; p = p->next_instr) {
+ if (p->type == V_ST_MAPPED &&
+ p->v.start == map.src_instr &&
+ p->v.end == map.src_bank &&
+ p->v.fixkey == map.src_key)
return 0; /* already present! */
}
- if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0)
- return -ENOSPC;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL)
+ return -ENOMEM;
- if (alloc_new_info(1) < 0)
- return -ENOSPC;
+ if ((rec = alloc_new_info()) == NULL)
+ return -ENOMEM;
- free_info = awe_free_info();
- rec = &infos[free_info];
rec->bank = map.map_bank;
rec->instr = map.map_instr;
rec->type = V_ST_MAPPED;
@@ -3270,9 +3186,8 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count)
rec->v.start = map.src_instr;
rec->v.end = map.src_bank;
rec->v.fixkey = map.src_key;
- rec->v.sf_id = current_sf_id;
- add_info_list(free_info);
- add_sf_info(free_info);
+ add_sf_info(sf, rec);
+ add_info_list(rec);
return 0;
}
@@ -3284,25 +3199,28 @@ awe_probe_info(awe_patch_info *patch, const char *addr, int count)
{
#ifdef AWE_ALLOW_SAMPLE_SHARING
awe_voice_map map;
- int p;
+ awe_voice_list *p;
if (! patch_opened)
return -EINVAL;
/* get the link info */
if (count < sizeof(map)) {
- printk("AWE32 Error: invalid patch info length\n");
+ printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
return -EINVAL;
}
- copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
+ if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
+ return -EFAULT;
/* check if the identical mapping already exists */
- p = awe_search_instr(map.src_bank, map.src_instr);
- for (; p >= 0; p = infos[p].next_instr) {
- if (p >= 0 && infos[p].type == V_ST_NORMAL &&
- is_identical_id(infos[p].v.sf_id, current_sf_id) &&
- infos[p].v.low <= map.src_key &&
- infos[p].v.high >= map.src_key)
+ if (sftail == NULL)
+ return -EINVAL;
+ p = awe_search_instr(map.src_bank, map.src_instr, map.src_key);
+ for (; p; p = p->next_instr) {
+ if (p->type == V_ST_NORMAL &&
+ is_identical_holder(p->holder, sftail) &&
+ p->v.low <= map.src_key &&
+ p->v.high >= map.src_key)
return 0; /* already present! */
}
#endif /* allow sharing */
@@ -3319,12 +3237,40 @@ awe_probe_data(awe_patch_info *patch, const char *addr, int count)
return -EINVAL;
/* search the specified sample by optarg */
- if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0)
+ if (search_sample_index(sftail, patch->optarg) != NULL)
return 0;
#endif /* allow sharing */
return -EINVAL;
}
+
+/* remove the present instrument layers */
+static int
+remove_info(sf_list *sf, int bank, int instr)
+{
+ awe_voice_list *prev, *next, *p;
+ int removed = 0;
+
+ prev = NULL;
+ for (p = sf->infos; p; prev = p, p = next) {
+ next = p->next;
+ if (p->type == V_ST_NORMAL &&
+ p->bank == bank && p->instr == instr) {
+ /* remove this layer */
+ if (prev)
+ prev->next = next;
+ else
+ sf->infos = next;
+ if (p == sf->last_infos)
+ sf->last_infos = prev;
+ sf->num_info--;
+ removed++;
+ kfree(p);
+ }
+ }
+ return removed;
+}
+
/* load voice information data */
static int
awe_load_info(awe_patch_info *patch, const char *addr, int count)
@@ -3333,125 +3279,154 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count)
awe_voice_rec_hdr hdr;
int i;
int total_size;
+ sf_list *sf;
+ awe_voice_list *rec;
if (count < AWE_VOICE_REC_SIZE) {
- printk("AWE32 Error: invalid patch info length\n");
+ printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
return -EINVAL;
}
offset = AWE_PATCH_INFO_SIZE;
- copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE);
+ if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE))
+ return -EFAULT;
offset += AWE_VOICE_REC_SIZE;
if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
- printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices);
+ printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices);
return -EINVAL;
}
total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
if (count < total_size) {
- printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
+ printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
count, hdr.nvoices);
return -EINVAL;
}
- if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
- return -ENOSPC;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
+ return -ENOMEM;
-#if 0 /* it looks like not so useful.. */
- /* check if the same preset already exists in the info list */
- for (i = sflists[current_sf_id-1].infos; i >= 0; i = infos[i].next) {
- if (infos[i].disabled) continue;
- if (infos[i].bank == hdr.bank && infos[i].instr == hdr.instr) {
- /* in exclusive mode, do skip loading this */
- if (hdr.write_mode == AWE_WR_EXCLUSIVE)
- return 0;
- /* in replace mode, disable the old data */
- else if (hdr.write_mode == AWE_WR_REPLACE)
- infos[i].disabled = TRUE;
+ switch (hdr.write_mode) {
+ case AWE_WR_EXCLUSIVE:
+ /* exclusive mode - if the instrument already exists,
+ return error */
+ for (rec = sf->infos; rec; rec = rec->next) {
+ if (rec->type == V_ST_NORMAL &&
+ rec->bank == hdr.bank &&
+ rec->instr == hdr.instr)
+ return -EINVAL;
}
+ break;
+ case AWE_WR_REPLACE:
+ /* replace mode - remoe the instrument if it already exists */
+ remove_info(sf, hdr.bank, hdr.instr);
+ break;
}
- if (hdr.write_mode == AWE_WR_REPLACE)
- rebuild_preset_list();
-#endif
-
- if (alloc_new_info(hdr.nvoices) < 0)
- return -ENOSPC;
+ /* append new layers */
for (i = 0; i < hdr.nvoices; i++) {
- int rec = awe_free_info();
+ rec = alloc_new_info();
+ if (rec == NULL)
+ return -ENOMEM;
- infos[rec].bank = hdr.bank;
- infos[rec].instr = hdr.instr;
- infos[rec].type = V_ST_NORMAL;
- infos[rec].disabled = FALSE;
+ rec->bank = hdr.bank;
+ rec->instr = hdr.instr;
+ rec->type = V_ST_NORMAL;
+ rec->disabled = FALSE;
/* copy awe_voice_info parameters */
- copy_from_user(&infos[rec].v, addr + offset, AWE_VOICE_INFO_SIZE);
+ if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) {
+ kfree(rec);
+ return -EFAULT;
+ }
offset += AWE_VOICE_INFO_SIZE;
- infos[rec].v.sf_id = current_sf_id;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (sflists[current_sf_id-1].shared) {
- if (info_duplicated(&infos[rec]))
+ if (sf && sf->shared) {
+ if (info_duplicated(sf, rec)) {
+ kfree(rec);
continue;
+ }
}
#endif /* allow sharing */
- if (infos[rec].v.mode & AWE_MODE_INIT_PARM)
- awe_init_voice_parm(&infos[rec].v.parm);
- awe_set_sample(&infos[rec].v);
+ if (rec->v.mode & AWE_MODE_INIT_PARM)
+ awe_init_voice_parm(&rec->v.parm);
+ add_sf_info(sf, rec);
+ awe_set_sample(rec);
add_info_list(rec);
- add_sf_info(rec);
}
return 0;
}
+/* remove instrument layers */
+static int
+awe_remove_info(awe_patch_info *patch, const char *addr, int count)
+{
+ unsigned char bank, instr;
+ sf_list *sf;
+
+ if (! patch_opened || (sf = sftail) == NULL) {
+ printk(KERN_WARNING "AWE32: remove_info: patch not opened\n");
+ return -EINVAL;
+ }
+
+ bank = ((unsigned short)patch->optarg >> 8) & 0xff;
+ instr = (unsigned short)patch->optarg & 0xff;
+ if (! remove_info(sf, bank, instr))
+ return -EINVAL;
+ return 0;
+}
+
+
/* load wave sample data */
static int
awe_load_data(awe_patch_info *patch, const char *addr, int count)
{
int offset, size;
- int rc, free_sample;
- awe_sample_info tmprec, *rec;
+ int rc;
+ awe_sample_info tmprec;
+ awe_sample_list *rec;
+ sf_list *sf;
- if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
- return -ENOSPC;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
+ return -ENOMEM;
size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
offset = AWE_PATCH_INFO_SIZE;
- copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE);
+ if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE))
+ return -EFAULT;
offset += AWE_SAMPLE_INFO_SIZE;
if (size != tmprec.size) {
- printk("AWE32: load: sample size differed (%d != %d)\n",
+ printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n",
tmprec.size, size);
return -EINVAL;
}
- if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) {
+ if (search_sample_index(sf, tmprec.sample) != NULL) {
#ifdef AWE_ALLOW_SAMPLE_SHARING
/* if shared sample, skip this data */
- if (sflists[current_sf_id-1].type & AWE_PAT_SHARED)
+ if (sf->type & AWE_PAT_SHARED)
return 0;
#endif /* allow sharing */
DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
return -EINVAL;
}
- if (alloc_new_sample() < 0)
- return -ENOSPC;
+ if ((rec = alloc_new_sample()) == NULL)
+ return -ENOMEM;
- free_sample = awe_free_sample();
- rec = &samples[free_sample].v;
- *rec = tmprec;
+ memcpy(&rec->v, &tmprec, sizeof(tmprec));
- if (rec->size > 0)
- if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0)
+ if (rec->v.size > 0) {
+ if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) {
+ kfree(rec);
return rc;
+ }
+ sf->mem_ptr += rc;
+ }
- rec->sf_id = current_sf_id;
-
- add_sf_sample(free_sample);
-
+ add_sf_sample(sf, rec);
return 0;
}
@@ -3462,55 +3437,57 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count)
{
int offset;
int size;
- int rc, i;
+ int rc;
int channels;
awe_sample_info cursmp;
int save_mem_ptr;
+ sf_list *sf;
+ awe_sample_list *rec;
- if (! patch_opened) {
- printk("AWE32: replace: patch not opened\n");
+ if (! patch_opened || (sf = sftail) == NULL) {
+ printk(KERN_WARNING "AWE32: replace: patch not opened\n");
return -EINVAL;
}
size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
offset = AWE_PATCH_INFO_SIZE;
- copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE);
+ if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE))
+ return -EFAULT;
offset += AWE_SAMPLE_INFO_SIZE;
if (cursmp.size == 0 || size != cursmp.size) {
- printk("AWE32: replace: illegal sample size (%d!=%d)\n",
+ printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n",
cursmp.size, size);
return -EINVAL;
}
channels = patch->optarg;
if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
- printk("AWE32: replace: illegal channels %d\n", channels);
+ printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels);
return -EINVAL;
}
- for (i = sflists[current_sf_id-1].samples;
- i >= 0; i = samples[i].next) {
- if (samples[i].v.sample == cursmp.sample)
+ for (rec = sf->samples; rec; rec = rec->next) {
+ if (rec->v.sample == cursmp.sample)
break;
}
- if (i < 0) {
- printk("AWE32: replace: cannot find existing sample data %d\n",
+ if (rec == NULL) {
+ printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n",
cursmp.sample);
return -EINVAL;
}
- if (samples[i].v.size != cursmp.size) {
- printk("AWE32: replace: exiting size differed (%d!=%d)\n",
- samples[i].v.size, cursmp.size);
+ if (rec->v.size != cursmp.size) {
+ printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n",
+ rec->v.size, cursmp.size);
return -EINVAL;
}
save_mem_ptr = awe_free_mem_ptr();
- sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start;
- memcpy(&samples[i].v, &cursmp, sizeof(cursmp));
- if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0)
+ sftail->mem_ptr = rec->v.start - awe_mem_start;
+ memcpy(&rec->v, &cursmp, sizeof(cursmp));
+ rec->v.sf_id = current_sf_id;
+ if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0)
return rc;
- sflists[current_sf_id-1].mem_ptr = save_mem_ptr;
- samples[i].v.sf_id = current_sf_id;
+ sftail->mem_ptr = save_mem_ptr;
return 0;
}
@@ -3521,28 +3498,11 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count)
static const char *readbuf_addr;
static int readbuf_offs;
static int readbuf_flags;
-#ifdef MALLOC_LOOP_DATA
-static unsigned short *readbuf_loop;
-static int readbuf_loopstart, readbuf_loopend;
-#endif
/* initialize read buffer */
static int
readbuf_init(const char *addr, int offset, awe_sample_info *sp)
{
-#ifdef MALLOC_LOOP_DATA
- readbuf_loop = NULL;
- readbuf_loopstart = sp->loopstart;
- readbuf_loopend = sp->loopend;
- if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
- int looplen = sp->loopend - sp->loopstart;
- readbuf_loop = vmalloc(looplen * 2);
- if (readbuf_loop == NULL) {
- printk("AWE32: can't malloc temp buffer\n");
- return -ENOSPC;
- }
- }
-#endif
readbuf_addr = addr;
readbuf_offs = offset;
readbuf_flags = sp->mode_flags;
@@ -3557,59 +3517,31 @@ readbuf_word(int pos)
/* read from user buffer */
if (readbuf_flags & AWE_SAMPLE_8BITS) {
unsigned char cc;
- get_user(cc, (unsigned char*)&(readbuf_addr)[readbuf_offs + pos]);
- c = cc << 8; /* convert 8bit -> 16bit */
+ get_user(cc, (unsigned char*)(readbuf_addr + readbuf_offs + pos));
+ c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */
} else {
- get_user(c, (unsigned short*)&(readbuf_addr)[readbuf_offs + pos * 2]);
+ get_user(c, (unsigned short*)(readbuf_addr + readbuf_offs + pos * 2));
}
if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
c ^= 0x8000; /* unsigned -> signed */
-#ifdef MALLOC_LOOP_DATA
- /* write on cache for reverse loop */
- if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
- if (pos >= readbuf_loopstart && pos < readbuf_loopend)
- readbuf_loop[pos - readbuf_loopstart] = c;
- }
-#endif
return c;
}
-#ifdef MALLOC_LOOP_DATA
-/* read from cache */
-static unsigned short
-readbuf_word_cache(int pos)
-{
- if (pos >= readbuf_loopstart && pos < readbuf_loopend)
- return readbuf_loop[pos - readbuf_loopstart];
- return 0;
-}
-
-static void
-readbuf_end(void)
-{
- if (readbuf_loop)
- vfree(readbuf_loop);
- readbuf_loop = NULL;
-}
-
-#else
-
#define readbuf_word_cache readbuf_word
#define readbuf_end() /**/
-#endif
-
/*----------------------------------------------------------------*/
#define BLANK_LOOP_START 8
#define BLANK_LOOP_END 40
#define BLANK_LOOP_SIZE 48
-/* loading onto memory */
+/* loading onto memory - return the actual written size */
static int
-awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels)
+awe_write_wave_data(const char *addr, int offset, awe_sample_list *list, int channels)
{
int i, truesize, dram_offset;
+ awe_sample_info *sp = &list->v;
int rc;
/* be sure loop points start < end */
@@ -3621,11 +3553,11 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann
/* compute true data size to be loaded */
truesize = sp->size;
- if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)
+ if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))
truesize += sp->loopend - sp->loopstart;
if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
truesize += BLANK_LOOP_SIZE;
- if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) {
+ if (awe_free_mem_ptr() + truesize >= memsize/2) {
DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
return -ENOSPC;
}
@@ -3686,13 +3618,12 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann
}
}
- sflists[current_sf_id-1].mem_ptr += truesize;
awe_close_dram();
/* initialize FM */
awe_init_fm();
- return 0;
+ return truesize;
}
@@ -3728,33 +3659,36 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
struct patch_info patch;
awe_voice_info *rec;
awe_sample_info *smp;
+ awe_voice_list *vrec;
+ awe_sample_list *smprec;
int sizeof_patch;
- int note, free_sample, free_info;
- int rc;
+ int note, rc;
+ sf_list *sf;
sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
if (size < sizeof_patch) {
- printk("AWE32 Error: Patch header too short\n");
+ printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
return -EINVAL;
}
- copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs);
+ if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs))
+ return -EFAULT;
size -= sizeof_patch;
if (size < patch.len) {
- printk("AWE32 Warning: Patch record too short (%d<%d)\n",
+ printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n",
size, patch.len);
return -EINVAL;
}
- if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0)
- return -ENOSPC;
- if (alloc_new_sample() < 0)
- return -ENOSPC;
- if (alloc_new_info(1))
- return -ENOSPC;
-
- free_sample = awe_free_sample();
- smp = &samples[free_sample].v;
+ if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL)
+ return -ENOMEM;
+ if ((smprec = alloc_new_sample()) == NULL)
+ return -ENOMEM;
+ if ((vrec = alloc_new_info()) == NULL) {
+ kfree(smprec);
+ return -ENOMEM;
+ }
- smp->sample = free_sample;
+ smp = &smprec->v;
+ smp->sample = sf->num_sample;
smp->start = 0;
smp->end = patch.len;
smp->loopstart = patch.loop_start;
@@ -3786,17 +3720,15 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
smp->checksum_flag = 0;
smp->checksum = 0;
- if ((rc = awe_write_wave_data(addr, sizeof_patch, smp, -1)) != 0)
+ if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0)
return rc;
-
- smp->sf_id = current_sf_id;
- add_sf_sample(free_sample);
+ sf->mem_ptr += rc;
+ add_sf_sample(sf, smprec);
/* set up voice info */
- free_info = awe_free_info();
- rec = &infos[free_info].v;
+ rec = &vrec->v;
awe_init_voice_info(rec);
- rec->sample = free_sample; /* the last sample */
+ rec->sample = sf->num_info; /* the last sample */
rec->rate_offset = calc_rate_offset(patch.base_freq);
note = freq_to_note(patch.base_note);
rec->root = note / 100;
@@ -3831,8 +3763,8 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
release += calc_gus_envelope_time
(patch.env_rate[5], patch.env_offset[4],
patch.env_offset[5]);
- rec->parm.volatkhld = (calc_parm_attack(attack) << 8) |
- calc_parm_hold(hold);
+ rec->parm.volatkhld = (calc_parm_hold(hold) << 8) |
+ calc_parm_attack(attack);
rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
calc_parm_decay(decay);
rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
@@ -3860,17 +3792,16 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
/* scale_freq, scale_factor, volume, and fractions not implemented */
/* append to the tail of the list */
- infos[free_info].bank = ctrls[AWE_MD_GUS_BANK];
- infos[free_info].instr = patch.instr_no;
- infos[free_info].disabled = FALSE;
- infos[free_info].type = V_ST_NORMAL;
- infos[free_info].v.sf_id = current_sf_id;
+ vrec->bank = ctrls[AWE_MD_GUS_BANK];
+ vrec->instr = patch.instr_no;
+ vrec->disabled = FALSE;
+ vrec->type = V_ST_NORMAL;
- add_info_list(free_info);
- add_sf_info(free_info);
+ add_sf_info(sf, vrec);
+ add_info_list(vrec);
/* set the voice index */
- awe_set_sample(rec);
+ awe_set_sample(vrec);
return 0;
}
@@ -3881,96 +3812,100 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
* sample and voice list handlers
*/
-/* append this to the sf list */
-static void add_sf_info(int rec)
+/* append this to the current sf list */
+static void add_sf_info(sf_list *sf, awe_voice_list *rec)
{
- int sf_id = infos[rec].v.sf_id;
- if (sf_id <= 0) return;
- sf_id--;
- if (sflists[sf_id].infos < 0)
- sflists[sf_id].infos = rec;
- else {
- int i, prev;
- prev = sflists[sf_id].infos;
- while ((i = infos[prev].next) >= 0)
- prev = i;
- infos[prev].next = rec;
- }
- infos[rec].next = -1;
- sflists[sf_id].num_info++;
+ if (sf == NULL)
+ return;
+ rec->holder = sf;
+ rec->v.sf_id = sf->sf_id;
+ if (sf->last_infos)
+ sf->last_infos->next = rec;
+ else
+ sf->infos = rec;
+ sf->last_infos = rec;
+ rec->next = NULL;
+ sf->num_info++;
}
/* prepend this sample to sf list */
-static void add_sf_sample(int rec)
+static void add_sf_sample(sf_list *sf, awe_sample_list *rec)
{
- int sf_id = samples[rec].v.sf_id;
- if (sf_id <= 0) return;
- sf_id--;
- samples[rec].next = sflists[sf_id].samples;
- sflists[sf_id].samples = rec;
- sflists[sf_id].num_sample++;
+ if (sf == NULL)
+ return;
+ rec->holder = sf;
+ rec->v.sf_id = sf->sf_id;
+ if (sf->last_samples)
+ sf->last_samples->next = rec;
+ else
+ sf->samples = rec;
+ sf->last_samples = rec;
+ rec->next = NULL;
+ sf->num_sample++;
}
/* purge the old records which don't belong with the same file id */
-static void purge_old_list(int rec, int next)
+static void purge_old_list(awe_voice_list *rec, awe_voice_list *next)
{
- infos[rec].next_instr = next;
- if (infos[rec].bank == AWE_DRUM_BANK) {
+ rec->next_instr = next;
+ if (rec->bank == AWE_DRUM_BANK) {
/* remove samples with the same note range */
- int cur, *prevp = &infos[rec].next_instr;
- int low = infos[rec].v.low;
- int high = infos[rec].v.high;
- for (cur = next; cur >= 0; cur = infos[cur].next_instr) {
- if (infos[cur].v.low == low &&
- infos[cur].v.high == high &&
- ! is_identical_id(infos[cur].v.sf_id, infos[rec].v.sf_id))
- *prevp = infos[cur].next_instr;
- prevp = &infos[cur].next_instr;
+ awe_voice_list *cur, *prev = rec;
+ int low = rec->v.low;
+ int high = rec->v.high;
+ for (cur = next; cur; cur = cur->next_instr) {
+ if (cur->v.low == low &&
+ cur->v.high == high &&
+ ! is_identical_holder(cur->holder, rec->holder))
+ prev->next_instr = cur->next_instr;
+ else
+ prev = cur;
}
} else {
- if (! is_identical_id(infos[next].v.sf_id, infos[rec].v.sf_id))
- infos[rec].next_instr = -1;
+ if (! is_identical_holder(next->holder, rec->holder))
+ /* remove all samples */
+ rec->next_instr = NULL;
}
}
/* prepend to top of the preset table */
-static void add_info_list(int rec)
+static void add_info_list(awe_voice_list *rec)
{
- int *prevp, cur;
- int instr;
- int bank;
+ awe_voice_list *prev, *cur;
+ int key;
- if (infos[rec].disabled)
+ if (rec->disabled)
return;
- instr = infos[rec].instr;
- bank = infos[rec].bank;
- limitvalue(instr, 0, AWE_MAX_PRESETS-1);
- prevp = &preset_table[instr];
- cur = *prevp;
- while (cur >= 0) {
+ key = awe_search_key(rec->bank, rec->instr, rec->v.low);
+ prev = NULL;
+ for (cur = preset_table[key]; cur; cur = cur->next_bank) {
/* search the first record with the same bank number */
- if (infos[cur].bank == bank) {
+ if (cur->instr == rec->instr && cur->bank == rec->bank) {
/* replace the list with the new record */
- infos[rec].next_bank = infos[cur].next_bank;
- *prevp = rec;
+ rec->next_bank = cur->next_bank;
+ if (prev)
+ prev->next_bank = rec;
+ else
+ preset_table[key] = rec;
purge_old_list(rec, cur);
return;
}
- prevp = &infos[cur].next_bank;
- cur = infos[cur].next_bank;
+ prev = cur;
}
/* this is the first bank record.. just add this */
- infos[rec].next_instr = -1;
- infos[rec].next_bank = preset_table[instr];
- preset_table[instr] = rec;
+ rec->next_instr = NULL;
+ rec->next_bank = preset_table[key];
+ preset_table[key] = rec;
}
/* remove samples later than the specified sf_id */
static void
awe_remove_samples(int sf_id)
{
+ sf_list *p, *prev;
+
if (sf_id <= 0) {
awe_reset_samples();
return;
@@ -3979,6 +3914,20 @@ awe_remove_samples(int sf_id)
if (current_sf_id <= sf_id)
return;
+ for (p = sftail; p; p = prev) {
+ if (p->sf_id <= sf_id)
+ break;
+ prev = p->prev;
+ awe_free_sf(p);
+ }
+ sftail = p;
+ if (sftail) {
+ sf_id = sftail->sf_id;
+ sftail->next = NULL;
+ } else {
+ sf_id = 0;
+ sfhead = NULL;
+ }
current_sf_id = sf_id;
if (locked_sf_id > sf_id)
locked_sf_id = sf_id;
@@ -3989,33 +3938,36 @@ awe_remove_samples(int sf_id)
/* rebuild preset search list */
static void rebuild_preset_list(void)
{
- int i, j;
+ sf_list *p;
+ awe_voice_list *rec;
- for (i = 0; i < AWE_MAX_PRESETS; i++)
- preset_table[i] = -1;
+ memset(preset_table, 0, sizeof(preset_table));
- for (i = 0; i < current_sf_id; i++) {
- for (j = sflists[i].infos; j >= 0; j = infos[j].next)
- add_info_list(j);
+ for (p = sfhead; p; p = p->next) {
+ for (rec = p->infos; rec; rec = rec->next)
+ add_info_list(rec);
}
}
/* compare the given sf_id pair */
-static int is_identical_id(int id1, int id2)
+static int is_identical_holder(sf_list *sf1, sf_list *sf2)
{
- if (id1 == id2)
- return TRUE;
- if (id1 <= 0 || id2 <= 0) /* this must not happen.. */
+ if (sf1 == NULL || sf2 == NULL)
return FALSE;
+ if (sf1 == sf2)
+ return TRUE;
#ifdef AWE_ALLOW_SAMPLE_SHARING
{
/* compare with the sharing id */
- int i;
- if (id1 < id2) { /* make sure id1 > id2 */
- int tmp; tmp = id1; id1 = id2; id2 = tmp;
+ sf_list *p;
+ int counter = 0;
+ if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */
+ sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp;
}
- for (i = sflists[id1-1].shared; i > 0 && i <= current_sf_id; i = sflists[i-1].shared) {
- if (i == id2)
+ for (p = sf1->shared; p; p = p->shared) {
+ if (counter++ > current_sf_id)
+ break; /* strange sharing loop.. quit */
+ if (p == sf2)
return TRUE;
}
}
@@ -4024,73 +3976,81 @@ static int is_identical_id(int id1, int id2)
}
/* search the sample index matching with the given sample id */
-static int search_sample_index(int sf, int sample, int level)
+static awe_sample_list *
+search_sample_index(sf_list *sf, int sample)
{
- int i;
-
- if (sf <= 0 || sf > current_sf_id)
- return -1; /* this must not happen */
-
- for (i = sflists[sf-1].samples; i >= 0; i = samples[i].next) {
- if (samples[i].v.sample == sample)
- return i;
- }
+ awe_sample_list *p;
#ifdef AWE_ALLOW_SAMPLE_SHARING
- if ((i = sflists[sf-1].shared) > 0 && i <= current_sf_id) { /* search recursively */
- if (level > current_sf_id)
- return -1; /* strange sharing loop.. quit */
- return search_sample_index(i, sample, level + 1);
+ int counter = 0;
+ while (sf) {
+ for (p = sf->samples; p; p = p->next) {
+ if (p->v.sample == sample)
+ return p;
+ }
+ sf = sf->shared;
+ if (counter++ > current_sf_id)
+ break; /* strange sharing loop.. quit */
+ }
+#else
+ if (sf) {
+ for (p = sf->samples; p; p = p->next) {
+ if (p->v.sample == sample)
+ return p;
+ }
}
#endif
- return -1;
+ return NULL;
}
/* search the specified sample */
+/* non-zero = found */
static short
-awe_set_sample(awe_voice_info *vp)
+awe_set_sample(awe_voice_list *rec)
{
- int i;
+ awe_sample_list *smp;
+ awe_voice_info *vp = &rec->v;
- vp->index = -1;
- if ((i = search_sample_index(vp->sf_id, vp->sample, 0)) < 0)
- return -1;
+ vp->index = 0;
+ if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL)
+ return 0;
/* set the actual sample offsets */
- vp->start += samples[i].v.start;
- vp->end += samples[i].v.end;
- vp->loopstart += samples[i].v.loopstart;
- vp->loopend += samples[i].v.loopend;
+ vp->start += smp->v.start;
+ vp->end += smp->v.end;
+ vp->loopstart += smp->v.loopstart;
+ vp->loopend += smp->v.loopend;
/* copy mode flags */
- vp->mode = samples[i].v.mode_flags;
- /* set index */
- vp->index = i;
+ vp->mode = smp->v.mode_flags;
+ /* set flag */
+ vp->index = 1;
- return i;
+ return 1;
}
-/*----------------------------------------------------------------
+/*
* voice allocation
- *----------------------------------------------------------------*/
+ */
/* look for all voices associated with the specified note & velocity */
static int
-awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist)
+awe_search_multi_voices(awe_voice_list *rec, int note, int velocity,
+ awe_voice_info **vlist)
{
int nvoices;
nvoices = 0;
- for (; rec >= 0; rec = infos[rec].next_instr) {
- if (note >= infos[rec].v.low &&
- note <= infos[rec].v.high &&
- velocity >= infos[rec].v.vellow &&
- velocity <= infos[rec].v.velhigh) {
- if (infos[rec].type == V_ST_MAPPED) {
+ for (; rec; rec = rec->next_instr) {
+ if (note >= rec->v.low &&
+ note <= rec->v.high &&
+ velocity >= rec->v.vellow &&
+ velocity <= rec->v.velhigh) {
+ if (rec->type == V_ST_MAPPED) {
/* mapper */
- vlist[0] = &infos[rec].v;
+ vlist[0] = &rec->v;
return -1;
}
- vlist[nvoices++] = &infos[rec].v;
+ vlist[nvoices++] = &rec->v;
if (nvoices >= AWE_MAX_VOICES)
break;
}
@@ -4103,29 +4063,45 @@ awe_search_multi_voices(int rec, int note, int velocity, awe_voice_info **vlist)
the note number if necessary.
*/
static int
-really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_info **vlist, int level)
+really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist)
{
int nvoices;
-
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- if (nvoices == 0)
- nvoices = awe_search_multi_voices(def_vrec, *note, velocity, vlist);
- if (nvoices < 0) { /* mapping */
- int preset = vlist[0]->start;
- int bank = vlist[0]->end;
- int key = vlist[0]->fixkey;
- if (level > 5) {
- printk("AWE32: too deep mapping level\n");
- return 0;
+ awe_voice_list *vrec;
+ int level = 0;
+
+ for (;;) {
+ vrec = awe_search_instr(bank, instr, *note);
+ nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+ if (nvoices == 0) {
+ if (bank == AWE_DRUM_BANK)
+ /* search default drumset */
+ vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note);
+ else
+ /* search default preset */
+ vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note);
+ nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
}
- vrec = awe_search_instr(bank, preset);
- if (bank == AWE_DRUM_BANK)
- def_vrec = awe_search_instr(bank, 0);
- else
- def_vrec = awe_search_instr(0, preset);
- if (key >= 0)
- *note = key;
- return really_alloc_voices(vrec, def_vrec, note, velocity, vlist, level+1);
+ if (nvoices == 0) {
+ if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0)
+ /* search default drumset */
+ vrec = awe_search_instr(bank, 0, *note);
+ else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0)
+ /* search default preset */
+ vrec = awe_search_instr(0, instr, *note);
+ nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
+ }
+ if (nvoices < 0) { /* mapping */
+ int key = vlist[0]->fixkey;
+ instr = vlist[0]->start;
+ bank = vlist[0]->end;
+ if (level++ > 5) {
+ printk(KERN_ERR "AWE32: too deep mapping level\n");
+ return 0;
+ }
+ if (key >= 0)
+ *note = key;
+ } else
+ break;
}
return nvoices;
@@ -4135,15 +4111,17 @@ really_alloc_voices(int vrec, int def_vrec, int *note, int velocity, awe_voice_i
static void
awe_alloc_multi_voices(int ch, int note, int velocity, int key)
{
- int i, v, nvoices;
+ int i, v, nvoices, bank;
awe_voice_info *vlist[AWE_MAX_VOICES];
- if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
- awe_set_instr(0, ch, channels[ch].instr);
+ if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch))
+ bank = AWE_DRUM_BANK; /* always search drumset */
+ else
+ bank = channels[ch].bank;
/* check the possible voices; note may be changeable if mapped */
- nvoices = really_alloc_voices(channels[ch].vrec, channels[ch].def_vrec,
- &note, velocity, vlist, 0);
+ nvoices = really_alloc_voices(bank, channels[ch].instr,
+ &note, velocity, vlist);
/* set the voices */
current_alloc_time++;
@@ -4169,78 +4147,62 @@ awe_alloc_multi_voices(int ch, int note, int velocity, int key)
}
-/* search the best voice from the specified status condition */
+/* search an empty voice.
+ if no empty voice is found, at least terminate a voice
+ */
static int
-search_best_voice(int condition)
+awe_clear_voice(void)
{
- int i, time, best;
- int vtarget = 0xffff, min_vtarget = 0xffff;
+ enum {
+ OFF=0, RELEASED, SUSTAINED, PLAYING, END
+ };
+ struct voice_candidate_t {
+ int best;
+ int time;
+ int vtarget;
+ } candidate[END];
+ int i, type, vtarget;
+
+ vtarget = 0xffff;
+ for (type = OFF; type < END; type++) {
+ candidate[type].best = -1;
+ candidate[type].time = current_alloc_time + 1;
+ candidate[type].vtarget = vtarget;
+ }
- best = -1;
- time = current_alloc_time + 1;
for (i = 0; i < awe_max_voices; i++) {
- if (! (voices[i].state & condition))
+ if (voices[i].state & AWE_ST_OFF)
+ type = OFF;
+ else if (voices[i].state & AWE_ST_RELEASED)
+ type = RELEASED;
+ else if (voices[i].state & AWE_ST_SUSTAINED)
+ type = SUSTAINED;
+ else if (voices[i].state & ~AWE_ST_MARK)
+ type = PLAYING;
+ else
continue;
#ifdef AWE_CHECK_VTARGET
/* get current volume */
vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
#endif
- if (best < 0 || vtarget < min_vtarget ||
- (vtarget == min_vtarget && voices[i].time < time)) {
- best = i;
- time = voices[i].time;
- min_vtarget = vtarget;
+ if (candidate[type].best < 0 ||
+ vtarget < candidate[type].vtarget ||
+ (vtarget == candidate[type].vtarget &&
+ voices[i].time < candidate[type].time)) {
+ candidate[type].best = i;
+ candidate[type].time = voices[i].time;
+ candidate[type].vtarget = vtarget;
}
}
- /* clear voice */
- if (best >= 0) {
- if (voices[best].state != AWE_ST_OFF)
- awe_terminate(best);
- awe_voice_init(best, TRUE);
- }
-
- return best;
-}
-/* search an empty voice.
- if no empty voice is found, at least terminate a voice
- */
-static int
-awe_clear_voice(void)
-{
- int best;
-
- /* looking for the oldest empty voice */
- if ((best = search_best_voice(AWE_ST_OFF)) >= 0)
- return best;
- if ((best = search_best_voice(AWE_ST_RELEASED)) >= 0)
- return best;
- /* looking for the oldest sustained voice */
- if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0)
- return best;
-
- if (MULTI_LAYER_MODE() && ctrls[AWE_MD_CHN_PRIOR]) {
- int ch = -1;
- int time = current_alloc_time + 1;
- int i;
- /* looking for the voices from high channel (except drum ch) */
- for (i = 0; i < awe_max_voices; i++) {
- if (IS_DRUM_CHANNEL(voices[i].ch)) continue;
- if (voices[i].ch < ch) continue;
- if (voices[i].state != AWE_ST_MARK &&
- (voices[i].ch > ch || voices[i].time < time)) {
- best = i;
- time = voices[i].time;
- ch = voices[i].ch;
- }
+ for (type = OFF; type < END; type++) {
+ if ((i = candidate[type].best) >= 0) {
+ if (voices[i].state != AWE_ST_OFF)
+ awe_terminate(i);
+ awe_voice_init(i, TRUE);
+ return i;
}
}
- if (best < 0)
- best = search_best_voice(~AWE_ST_MARK);
-
- if (best >= 0)
- return best;
-
return 0;
}
@@ -4251,16 +4213,17 @@ awe_clear_voice(void)
static void
awe_alloc_one_voice(int voice, int note, int velocity)
{
- int ch, nvoices;
+ int ch, nvoices, bank;
awe_voice_info *vlist[AWE_MAX_VOICES];
ch = voices[voice].ch;
- if (channels[ch].vrec < 0 && channels[ch].def_vrec < 0)
- awe_set_instr(0, ch, channels[ch].instr);
+ if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
+ bank = AWE_DRUM_BANK; /* always search drumset */
+ else
+ bank = voices[voice].cinfo->bank;
- nvoices = really_alloc_voices(voices[voice].cinfo->vrec,
- voices[voice].cinfo->def_vrec,
- &note, velocity, vlist, 0);
+ nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr,
+ &note, velocity, vlist);
if (nvoices > 0) {
voices[voice].time = ++current_alloc_time;
voices[voice].sample = vlist[0]; /* use the first one */
@@ -4271,9 +4234,9 @@ awe_alloc_one_voice(int voice, int note, int velocity)
}
-/*----------------------------------------------------------------
+/*
* sequencer2 functions
- *----------------------------------------------------------------*/
+ */
/* search an empty voice; used by sequencer2 */
static int
@@ -4331,14 +4294,14 @@ static struct mixer_operations awe_mixer_operations = {
awe_mixer_ioctl,
};
-static void attach_mixer(void)
+static void __init attach_mixer(void)
{
if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
mixer_devs[my_mixerdev] = &awe_mixer_operations;
}
}
-static void unload_mixer(void)
+static void __exit unload_mixer(void)
{
if (my_mixerdev >= 0)
sound_unload_mixerdev(my_mixerdev);
@@ -4352,7 +4315,7 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
if (((cmd >> 8) & 0xff) != 'M')
return -EINVAL;
- level = (int) *(int *)arg;
+ level = *(int*)arg;
level = ((level & 0xff) + (level >> 8)) / 2;
DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
@@ -4408,13 +4371,13 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
level = 0;
break;
}
- return *(int *)arg = level;
+ return *(int*)arg = level;
}
#endif /* CONFIG_AWE32_MIXER */
/*
- * initialization of AWE32
+ * initialization of Emu8000
*/
/* intiailize audio channels */
@@ -4636,7 +4599,7 @@ awe_init_fm(void)
{
#ifndef AWE_ALWAYS_INIT_FM
/* if no extended memory is on board.. */
- if (awe_mem_size <= 0)
+ if (memsize <= 0)
return;
#endif
DEBUG(3,printk("AWE32: initializing FM\n"));
@@ -4731,7 +4694,8 @@ awe_open_dram_for_write(int offset, int channels)
awe_poke_dw(AWE_CCCA(vidx[i]), 0);
voices[vidx[i]].state = AWE_ST_OFF;
}
- return -ENOSPC;
+ printk("awe: not ready to write..\n");
+ return -EPERM;
}
/* set address to write */
@@ -4784,13 +4748,13 @@ awe_close_dram(void)
}
-/*================================================================
+/*
* detect presence of AWE32 and check memory size
- *================================================================*/
+ */
/* detect emu8000 chip on the specified address; from VV's guide */
-static int
+static int __init
awe_detect_base(int addr)
{
setup_ports(addr, 0, 0);
@@ -4804,16 +4768,79 @@ awe_detect_base(int addr)
return 1;
}
-static int
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static struct {
+ unsigned short vendor;
+ unsigned short function;
+ char *name;
+} isapnp_awe_list[] __initdata = {
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), "AWE32 WaveTable"},
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), "AWE64 WaveTable"},
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), "AWE64 Gold WaveTable"},
+ {0,}
+};
+
+static struct pci_dev *idev = NULL;
+
+static int __init awe_probe_isapnp(int *port)
+{
+ int i;
+
+ for (i = 0; isapnp_awe_list[i].vendor != 0; i++) {
+ while ((idev = isapnp_find_dev(NULL,
+ isapnp_awe_list[i].vendor,
+ isapnp_awe_list[i].function,
+ idev))) {
+ if (idev->prepare(idev) < 0)
+ continue;
+ if (idev->activate(idev) < 0 ||
+ !idev->resource[0].start) {
+ idev->deactivate(idev);
+ idev->deactivate(idev);
+ continue;
+ }
+ *port = idev->resource[0].start;
+ break;
+ }
+ if (!idev)
+ continue;
+ printk(KERN_INFO "ISAPnP reports %s at i/o %#x\n",
+ isapnp_awe_list[i].name, *port);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static void __exit awe_deactivate_isapnp(void)
+{
+#if 1
+ if (idev) {
+ idev->deactivate(idev);
+ idev = NULL;
+ }
+#endif
+}
+
+#endif
+
+static int __init
awe_detect(void)
{
int base;
- if (port_setuped) /* already initialized by PnP */
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+ if (isapnp) {
+ if (awe_probe_isapnp(&io) < 0) {
+ printk(KERN_ERR "AWE32: No ISAPnP cards found\n");
+ return 0;
+ }
+ setup_ports(io, 0, 0);
return 1;
+ }
+#endif /* isapnp */
- if (awe_port) /* use default i/o port value */
- setup_ports(awe_port, 0, 0);
+ if (io) /* use default i/o port value */
+ setup_ports(io, 0, 0);
else { /* probe it */
for (base = 0x620; base <= 0x680; base += 0x20)
if (awe_detect_base(base))
@@ -4826,36 +4853,36 @@ awe_detect(void)
}
-/*================================================================
+/*
* check dram size on AWE board
- *================================================================*/
+ */
/* any three numbers you like */
#define UNIQUE_ID1 0x1234
#define UNIQUE_ID2 0x4321
#define UNIQUE_ID3 0xFFFF
-static void
+static void __init
awe_check_dram(void)
{
if (awe_present) /* already initialized */
return;
- if (awe_mem_size >= 0) { /* given by config file or module option */
- awe_mem_size *= 1024; /* convert to Kbytes */
+ if (memsize >= 0) { /* given by config file or module option */
+ memsize *= 1024; /* convert to Kbytes */
return;
}
awe_open_dram_for_check();
- awe_mem_size = 0;
+ memsize = 0;
/* set up unique two id numbers */
awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
awe_poke(AWE_SMLD, UNIQUE_ID1);
awe_poke(AWE_SMLD, UNIQUE_ID2);
- while (awe_mem_size < AWE_MAX_DRAM_SIZE) {
+ while (memsize < AWE_MAX_DRAM_SIZE) {
awe_wait(5);
/* read a data on the DRAM start address */
awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
@@ -4864,33 +4891,35 @@ awe_check_dram(void)
break;
if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
break;
- awe_mem_size += 512; /* increment 512kbytes */
+ memsize += 512; /* increment 512kbytes */
/* Write a unique data on the test address;
* if the address is out of range, the data is written on
* 0x200000(=AWE_DRAM_OFFSET). Then the two id words are
* broken by this data.
*/
- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L);
+ awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L);
awe_poke(AWE_SMLD, UNIQUE_ID3);
awe_wait(5);
/* read a data on the just written DRAM address */
- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L);
+ awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L);
awe_peek(AWE_SMLD); /* discard stale data */
if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
break;
}
awe_close_dram();
- DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", awe_mem_size));
+ DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize));
/* convert to Kbytes */
- awe_mem_size *= 1024;
+ memsize *= 1024;
}
-/*================================================================
+/*----------------------------------------------------------------*/
+
+/*
* chorus and reverb controls; from VV's guide
- *================================================================*/
+ */
/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
static char chorus_defined[AWE_CHORUS_NUMBERS];
@@ -4909,15 +4938,16 @@ static int
awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count)
{
if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
- printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg);
+ printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg);
return -EINVAL;
}
if (count < sizeof(awe_chorus_fx_rec)) {
- printk("AWE32 Error: too short chorus fx parameters\n");
+ printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n");
return -EINVAL;
}
- copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_chorus_fx_rec));
+ if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+ sizeof(awe_chorus_fx_rec)))
+ return -EFAULT;
chorus_defined[patch->optarg] = TRUE;
return 0;
}
@@ -5016,15 +5046,16 @@ static int
awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count)
{
if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
- printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg);
+ printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg);
return -EINVAL;
}
if (count < sizeof(awe_reverb_fx_rec)) {
- printk("AWE32 Error: too short reverb fx parameters\n");
+ printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n");
return -EINVAL;
}
- copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_reverb_fx_rec));
+ if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
+ sizeof(awe_reverb_fx_rec)))
+ return -EFAULT;
reverb_defined[patch->optarg] = TRUE;
return 0;
}
@@ -5047,9 +5078,9 @@ awe_update_reverb_mode(void)
awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
}
-/*================================================================
+/*
* treble/bass equalizer control
- *================================================================*/
+ */
static unsigned short bass_parm[12][3] = {
{0xD26A, 0xD36A, 0x0000}, /* -12 dB */
@@ -5113,15 +5144,17 @@ static void awe_update_equalizer(void)
}
+/*----------------------------------------------------------------*/
+
#ifdef CONFIG_AWE32_MIDIEMU
-/*================================================================
+/*
* Emu8000 MIDI Emulation
- *================================================================*/
+ */
-/*================================================================
+/*
* midi queue record
- *================================================================*/
+ */
/* queue type */
enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
@@ -5149,9 +5182,9 @@ typedef struct {
} ConvTable;
-/*================================================================
+/*
* prototypes
- *================================================================*/
+ */
static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
static void awe_midi_close(int dev);
@@ -5183,9 +5216,9 @@ static int xg_control_change(MidiStatus *st, int cmd, int val);
#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
-/*================================================================
+/*
* OSS Midi device record
- *================================================================*/
+ */
static struct midi_operations awe_midi_operations =
{
@@ -5204,7 +5237,7 @@ static struct midi_operations awe_midi_operations =
static int my_mididev = -1;
-static void attach_midiemu(void)
+static void __init attach_midiemu(void)
{
if ((my_mididev = sound_alloc_mididev()) < 0)
printk ("Sound: Too many midi devices detected\n");
@@ -5212,7 +5245,7 @@ static void attach_midiemu(void)
midi_devs[my_mididev] = &awe_midi_operations;
}
-static void unload_midiemu(void)
+static void __exit unload_midiemu(void)
{
if (my_mididev >= 0)
sound_unload_mididev(my_mididev);
@@ -5632,9 +5665,9 @@ static void midi_select_bank(MidiStatus *st, int val)
}
-/*================================================================
+/*
* RPN events
- *================================================================*/
+ */
static void midi_rpn_event(MidiStatus *st)
{
@@ -5686,10 +5719,10 @@ static void midi_detune(int chan, int coarse, int fine)
}
-/*================================================================
+/*
* system exclusive message
* GM/GS/XG macros are accepted
- *================================================================*/
+ */
static void midi_system_exclusive(MidiStatus *st)
{
@@ -5784,6 +5817,8 @@ static void midi_system_exclusive(MidiStatus *st)
}
+/*----------------------------------------------------------------*/
+
/*
* convert NRPN/control values
*/
@@ -6006,9 +6041,9 @@ static ConvTable gs_effects[] =
static int num_gs_effects = numberof(gs_effects);
-/*================================================================
+/*
* NRPN events: accept as AWE32/SC88 specific controls
- *================================================================*/
+ */
static void midi_nrpn_event(MidiStatus *st)
{
@@ -6026,9 +6061,9 @@ static void midi_nrpn_event(MidiStatus *st)
}
-/*----------------------------------------------------------------
+/*
* XG control effects; still experimental
- *----------------------------------------------------------------*/
+ */
/* cutoff: quarter semitone step, max=255 */
static unsigned short xg_cutoff(int val)
@@ -6071,45 +6106,42 @@ static int xg_control_change(MidiStatus *st, int cmd, int val)
#endif /* CONFIG_AWE32_MIDIEMU */
-/* new type interface */
-static int __init attach_awe(void)
+
+/*----------------------------------------------------------------*/
+
+/*
+ * device / lowlevel (module) interface
+ */
+
+int __init attach_awe(void)
{
-#ifdef CONFIG_PNP_DRV
- if (pnp) {
- awe_initpnp();
- if (awe_pnp_ok)
- return 0;
- }
-#endif /* pnp */
-
- _attach_awe();
-
- return 0;
-}
+ return _attach_awe() ? 0 : -ENODEV;
+}
-static void __exit unload_awe(void)
+void __exit unload_awe(void)
{
-#ifdef CONFIG_PNP_DRV
- if (pnp)
- awe_unload_pnp();
-#endif
-
_unload_awe();
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+ if (isapnp)
+ awe_deactivate_isapnp();
+#endif /* isapnp */
}
+
module_init(attach_awe);
module_exit(unload_awe);
#ifndef MODULE
static int __init setup_awe(char *str)
{
- /* io, memsize */
- int ints[3];
+ /* io, memsize, isapnp */
+ int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
io = ints[1];
memsize = ints[2];
+ isapnp = ints[3];
return 1;
}
diff --git a/drivers/sound/awe_wave.h b/drivers/sound/awe_wave.h
index 0984da765..a3aa01811 100644
--- a/drivers/sound/awe_wave.h
+++ b/drivers/sound/awe_wave.h
@@ -2,7 +2,7 @@
* sound/awe_config.h
*
* Configuration of AWE32/SB32/AWE64 wave table synth driver.
- * version 0.4.3; Mar. 1, 1998
+ * version 0.4.4; Jan. 4, 2000
*
* Copyright (C) 1996-1998 Takashi Iwai
*
@@ -68,20 +68,10 @@
/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
/*
- * maximum size of soundfont list table
+ * AWE driver version number
*/
-
-#define AWE_MAX_SF_LISTS 16
-
-/*
- * chunk size of sample and voice tables
- */
-
-#define AWE_MAX_SAMPLES 400
-#define AWE_MAX_INFOS 800
-
#define AWE_MAJOR_VERSION 0
#define AWE_MINOR_VERSION 4
-#define AWE_TINY_VERSION 3
+#define AWE_TINY_VERSION 4
#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION "0.4.3"
+#define AWEDRV_VERSION "0.4.4"
diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h
index 282e644a3..6e24d6e89 100644
--- a/drivers/sound/sb.h
+++ b/drivers/sound/sb.h
@@ -151,6 +151,7 @@ int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio);
int sb_dsp_init (struct address_info *hw_config);
void sb_dsp_unload(struct address_info *hw_config, int sbmpu);
int sb_mixer_init(sb_devc *devc);
+void sb_mixer_unload(sb_devc *devc);
void sb_mixer_set_stereo (sb_devc *devc, int mode);
void smw_mixer_init(sb_devc *devc);
void sb_dsp_midi_init (sb_devc *devc);
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index c471163ef..557a971a4 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -29,6 +29,10 @@
* 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup
* Alessandro Zummo <azummo@ita.flashnet.it>
*
+ * 13-03-2000 Added some more cards, thanks to Torsten Werner.
+ * Removed joystick and wavetable code, there are better places for them.
+ * Code cleanup plus some fixes.
+ *
*/
#include <linux/config.h>
@@ -145,10 +149,7 @@ static struct address_info cfg;
static struct address_info cfg_mpu;
struct pci_dev *sb_dev = NULL,
- *wss_dev = NULL,
- *jp_dev = NULL,
- *mpu_dev = NULL,
- *wt_dev = NULL;
+ *mpu_dev = NULL;
/*
* Note DMA2 of -1 has the right meaning in the SB16 driver as well
* as here. It will cause either an error if it is needed or a fallback
@@ -166,10 +167,9 @@ static int __initdata type = 0; /* Can set this to a specific card type */
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
static int isapnp = 1;
static int isapnpjump = 0;
-static int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be
- in the kernel tree */
+static int activated = 1;
#else
-int isapnp = 0;
+static int isapnp = 0;
#endif
MODULE_DESCRIPTION("Soundblaster driver");
@@ -187,10 +187,8 @@ MODULE_PARM(acer, "i");
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
MODULE_PARM(isapnp, "i");
MODULE_PARM(isapnpjump, "i");
-MODULE_PARM(nosbwave, "i");
MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled");
MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
-MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver.");
#endif
MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
@@ -213,12 +211,13 @@ static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev
{
int err;
+ /* Device already active? Let's use it */
+
if(dev->active)
{
- printk(KERN_INFO "sb: %s %s already in use\n", devname, resname);
- return(NULL);
+ activated = 0;
+ return(dev);
}
-
if((err = dev->activate(dev)) < 0)
{
printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err);
@@ -324,42 +323,6 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
else
printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
-
- /* @P@:Gameport
- */
-
- if((jp_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- jp_dev->prepare(jp_dev);
-
- if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev)))
- show_base("CMI8330", "gameport", &jp_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n");
-
- /* @@@0001:OPL3
- */
-
-#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
- if((wss_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- wss_dev->prepare(wss_dev);
-
- /* Let's disable IRQ and DMA for WSS device */
-
- wss_dev->irq_resource[0].flags = 0;
- wss_dev->dma_resource[0].flags = 0;
-
- if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev)))
- show_base("CMI8330", "opl3", &wss_dev->resource[1]);
- }
- else
- printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n");
-#endif
-
printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
return(sb_dev);
@@ -391,7 +354,6 @@ static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card
}
if(!sb_dev) return(NULL);
-
}
else
printk(KERN_ERR "sb: DT0197H panic: sb base not found\n");
@@ -413,169 +375,100 @@ static struct pci_dev *sb_init_diamond(struct pci_bus *bus, struct pci_dev *card
else
printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
-
- /* @P@:Gameport
- */
-
- if((jp_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- jp_dev->prepare(jp_dev);
-
- if((jp_dev = activate_dev("DT0197H", "gameport", jp_dev)))
- show_base("DT0197H", "gameport", &jp_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: DT0197H panic: gameport not found\n");
-
- /* @H@0001:OPL3
- */
-
-#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
- if((wss_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- wss_dev->prepare(wss_dev);
-
- /* Let's disable IRQ and DMA for WSS device */
-
- wss_dev->irq_resource[0].flags = 0;
- wss_dev->dma_resource[0].flags = 0;
-
- if((wss_dev = activate_dev("DT0197H", "opl3", wss_dev)))
- show_base("DT0197H", "opl3", &wss_dev->resource[0]);
- }
- else
- printk(KERN_ERR "sb: DT0197H panic: opl3 not found\n");
-#endif
-
printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner <twerner@intercomm.de>\n");
return(sb_dev);
}
-/* Specific support for awe will be dropped when:
- * a) The new awe_wawe driver with PnP support will be introduced in the kernel
- * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-)
- */
-
-static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
+static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
{
- /* CTL0042:Audio SB64
- * CTL0031:Audio SB32
- * CTL0045:Audio SB64
+ /*
+ * ALS100
+ * very similar to both ones above above
*/
- if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) ||
- (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) ||
- (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) )
+ /* @@@0001:Soundblaster.
+ */
+
+ if((sb_dev = isapnp_find_dev(bus,
+ ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
sb_dev->prepare(sb_dev);
- if((sb_dev = activate_dev("AWE", "sb", sb_dev)))
+ if((sb_dev = activate_dev("ALS100", "sb", sb_dev)))
{
hw_config->io_base = sb_dev->resource[0].start;
hw_config->irq = sb_dev->irq_resource[0].start;
- hw_config->dma = sb_dev->dma_resource[0].start;
- hw_config->dma2 = sb_dev->dma_resource[1].start;
+ hw_config->dma = sb_dev->dma_resource[1].start;
+ hw_config->dma2 = sb_dev->dma_resource[0].start;
- mpu_config->io_base = sb_dev->resource[1].start;
-
- show_base("AWE", "sb", &sb_dev->resource[0]);
- show_base("AWE", "mpu", &sb_dev->resource[1]);
- show_base("AWE", "opl3", &sb_dev->resource[2]);
+ show_base("ALS100", "sb", &sb_dev->resource[0]);
}
- else
- return(NULL);
- }
- else
- printk(KERN_ERR "sb: AWE panic: sb base not found\n");
-
-
- /* CTL7002:Game SB64
- * CTL7001:Game SB32
- */
- if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
- (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) )
- {
- jp_dev->prepare(jp_dev);
-
- if((jp_dev = activate_dev("AWE", "gameport", jp_dev)))
- show_base("AWE", "gameport", &jp_dev->resource[0]);
+ if(!sb_dev) return(NULL);
}
else
- printk(KERN_ERR "sb: AWE panic: gameport not found\n");
+ printk(KERN_ERR "sb: ALS100 panic: sb base not found\n");
-
- /* CTL0022:WaveTable SB64
- * CTL0021:WaveTable SB32
- * CTL0023:WaveTable Sb64
+ /* @X@0001:mpu
*/
- if( nosbwave == 0 &&
- ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
- ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
- ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
+ if((mpu_dev = isapnp_find_dev(bus,
+ ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
- wt_dev->prepare(wt_dev);
-
- if((wt_dev = activate_dev("AWE", "wavetable", wt_dev)))
+ mpu_dev->prepare(mpu_dev);
+
+ if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev)))
{
- show_base("AWE", "wavetable", &wt_dev->resource[0]);
- show_base("AWE", "wavetable", &wt_dev->resource[1]);
- show_base("AWE", "wavetable", &wt_dev->resource[2]);
+ show_base("ALS100", "mpu", &mpu_dev->resource[0]);
+ mpu_config->io_base = mpu_dev->resource[0].start;
}
}
else
- printk(KERN_ERR "sb: AWE panic: wavetable not found\n");
+ printk(KERN_ERR "sb: ALS100 panic: mpu not found\n");
- printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
+ printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner <twerner@intercomm.de>\n");
return(sb_dev);
}
-#define SBF_DEV 0x01
+#define SBF_DEV 0x01 /* Please notice that cards without this flag are on the top in the list */
static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
-isapnp_sb_list[] __initdata = {
+sb_isapnp_list[] __initdata = {
+ {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
+ {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" },
+ {ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_als, "ALS 100" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
{ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
{ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
- {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
- {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" },
{0}
};
-static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
+static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
{
struct pci_dev *idev = NULL;
/* You missed the init func? That's bad. */
- if(isapnp_sb_list[slot].initfunc)
+ if(sb_isapnp_list[slot].initfunc)
{
- char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name;
+ char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
printk(KERN_INFO "sb: %s detected\n", busname);
/* Initialize this baby. */
- if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config)))
+ if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, mpu_config)))
{
/* We got it. */
@@ -600,12 +493,12 @@ static int __init sb_init_isapnp(struct address_info *hw_config, struct address_
Should this be fixed? - azummo
*/
-int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config)
+int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config)
{
int i;
- /* Count entries in isapnp_sb_list */
- for (i = 0; isapnp_sb_list[i].vendor != 0; i++);
+ /* Count entries in sb_isapnp_list */
+ for (i = 0; sb_isapnp_list[i].vendor != 0; i++);
/* Check and adjust isapnpjump */
if( isapnpjump < 0 || isapnpjump > ( i - 1 ) )
@@ -614,18 +507,18 @@ int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *
isapnpjump = 0;
}
- for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
+ for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
- if(!(isapnp_sb_list[i].flags & SBF_DEV))
+ if(!(sb_isapnp_list[i].flags & SBF_DEV))
{
struct pci_bus *bus = NULL;
while ((bus = isapnp_find_card(
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
+ sb_isapnp_list[i].vendor,
+ sb_isapnp_list[i].function,
bus))) {
- if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i))
+ if(sb_isapnp_init(hw_config, mpu_config, bus, NULL, i))
return 0;
}
}
@@ -635,18 +528,18 @@ int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *
* that matches any entry marked with SBF_DEV in the table.
*/
- for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) {
+ for (i = isapnpjump; sb_isapnp_list[i].vendor != 0; i++) {
- if(isapnp_sb_list[i].flags & SBF_DEV)
+ if(sb_isapnp_list[i].flags & SBF_DEV)
{
struct pci_dev *card = NULL;
while ((card = isapnp_find_dev(NULL,
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
+ sb_isapnp_list[i].vendor,
+ sb_isapnp_list[i].function,
card))) {
- if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i))
+ if(sb_isapnp_init(hw_config, mpu_config, card->bus, card, i))
return 0;
}
}
@@ -665,7 +558,7 @@ static int __init init_sb(void)
*/
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
- if(isapnp && (sb_probe_isapnp(&cfg, &cfg_mpu) < 0) ) {
+ if(isapnp && (sb_isapnp_probe(&cfg, &cfg_mpu) < 0) ) {
printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
isapnp = 0;
}
@@ -707,11 +600,13 @@ static void __exit cleanup_sb(void)
unload_sbmpu(&cfg_mpu);
SOUND_LOCK_END;
- if(sb_dev) sb_dev->deactivate(sb_dev);
- if(jp_dev) jp_dev->deactivate(jp_dev);
- if(wt_dev) wt_dev->deactivate(wt_dev);
- if(mpu_dev) mpu_dev->deactivate(mpu_dev);
- if(wss_dev) wss_dev->deactivate(wss_dev);
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+ if(activated)
+ {
+ if(sb_dev) sb_dev->deactivate(sb_dev);
+ if(mpu_dev) mpu_dev->deactivate(mpu_dev);
+ }
+#endif
}
module_init(init_sb);
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 5fb40f46d..80c282a5d 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -908,13 +908,10 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
}
if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI))
{
- extern int sbmixnum;
-
if (devc->irq > 0)
free_irq(devc->irq, devc);
- sound_unload_mixerdev(devc->my_mixerdev);
- sbmixnum--;
+ sb_mixer_unload(devc);
/* We don't have to do this bit any more the UART401 is its own
master -- Krzysztof Halasa */
/* But we have to do it, if UART401 is not detected */
diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c
index f441be0aa..a955db7e3 100644
--- a/drivers/sound/sb_mixer.c
+++ b/drivers/sound/sb_mixer.c
@@ -740,3 +740,9 @@ int sb_mixer_init(sb_devc * devc)
sb_mixer_reset(devc);
return 1;
}
+
+void sb_mixer_unload(sb_devc *devc)
+{
+ sound_unload_mixerdev(devc->my_mixerdev);
+ sbmixnum--;
+}
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 012a27187..28ad96481 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -43,6 +43,7 @@ comment 'USB Devices'
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB m
if [ "$CONFIG_USB_STORAGE" != "n" ]; then
bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 6e9e99714..06b0a4648 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_CPIA) += cpia.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o
+obj-$(CONFIG_USB_MDC800) += mdc800.o
obj-$(CONFIG_USB_STORAGE) += usb-storage.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
diff --git a/drivers/usb/hid-debug.h b/drivers/usb/hid-debug.h
index 8aaf4be81..b72565fb9 100644
--- a/drivers/usb/hid-debug.h
+++ b/drivers/usb/hid-debug.h
@@ -105,6 +105,7 @@ static struct hid_usage_entry hid_usage_table[] = {
{0, 0x35, "Tap"},
{0, 0x39, "TabletFunctionKey"},
{0, 0x3a, "ProgramChangeKey"},
+ {0, 0x3c, "Invert"},
{0, 0x42, "TipSwitch"},
{0, 0x43, "SecondaryTipSwitch"},
{0, 0x44, "BarrelSwitch"},
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index c7bb34e4d..b8af56051 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -802,6 +802,11 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
case 0x30: /* TipPressure */
+ if (!test_bit(BTN_TOUCH, input->keybit)) {
+ device->quirks |= HID_QUIRK_NOTOUCH;
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_TOUCH, input->keybit);
+ }
usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
usage->code = ABS_PRESSURE;
clear_bit(usage->code, bit);
@@ -817,10 +822,18 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
break;
+ case 0x3c: /* Invert */
+
+ usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+ usage->code = BTN_TOOL_RUBBER;
+ clear_bit(usage->code, bit);
+ break;
+
case 0x33: /* Touch */
case 0x42: /* TipSwitch */
case 0x43: /* TipSwitch2 */
+ device->quirks &= ~HID_QUIRK_NOTOUCH;
usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
usage->code = BTN_TOUCH;
clear_bit(usage->code, bit);
@@ -930,7 +943,7 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
}
}
-static void hid_process_event(struct input_dev *input, int flags, struct hid_usage *usage, __s32 value)
+static void hid_process_event(struct input_dev *input, int *quirks, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
hid_dump_input(usage, value);
@@ -941,9 +954,30 @@ static void hid_process_event(struct input_dev *input, int flags, struct hid_usa
return;
}
+ if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
+ *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
+ return;
+ }
+
+ if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
+ if (value) {
+ input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
+ return;
+ }
+ input_event(input, usage->type, usage->code, 0);
+ input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
+ return;
+ }
+
+ if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
+ int a = field->logical_minimum;
+ int b = field->logical_maximum;
+ input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
+ }
+
input_event(input, usage->type, usage->code, value);
- if ((flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
+ if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
input_event(input, usage->type, usage->code, 0);
}
@@ -986,19 +1020,21 @@ static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u
} else {
if (value[n] == field->value[n]) continue;
}
- hid_process_event(&dev->input, field->flags, &field->usage[n], value[n]);
+ hid_process_event(&dev->input, &dev->quirks, field, &field->usage[n], value[n]);
} else {
if (field->value[n] >= min && field->value[n] <= max /* non-NULL value */
&& field->usage[field->value[n] - min].hid /* nonzero usage */
&& search(value, field->value[n], count))
- hid_process_event(&dev->input, field->flags, &field->usage[field->value[n] - min], 0);
+ hid_process_event(&dev->input, &dev->quirks, field,
+ &field->usage[field->value[n] - min], 0);
if (value[n] >= min && value[n] <= max /* non-NULL value */
&& field->usage[value[n] - min].hid /* nonzero usage */
&& search(field->value, value[n], count))
- hid_process_event(&dev->input, field->flags, &field->usage[value[n] - min], 1);
+ hid_process_event(&dev->input, &dev->quirks,
+ field, &field->usage[value[n] - min], 1);
}
}
@@ -1261,14 +1297,18 @@ static void hid_init_input(struct hid_device *hid)
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS 0x0021
+#define USB_DEVICE_ID_WACOM_INTUOS 0x0020
struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
} hid_blacklist[] = {
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
+ { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
{ 0, 0 }
};
diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h
index 4a4caf401..18e7481c2 100644
--- a/drivers/usb/hid.h
+++ b/drivers/usb/hid.h
@@ -179,6 +179,13 @@ struct hid_item {
#define HID_FEATURE_REPORT 2
/*
+ * HID device quirks.
+ */
+
+#define HID_QUIRK_INVERT 0x01
+#define HID_QUIRK_NOTOUCH 0x02
+
+/*
* This is the global enviroment of the parser. This information is
* persistent for main-items. The global enviroment can be saved and
* restored with PUSH/POP statements.
@@ -285,6 +292,7 @@ struct hid_device { /* device report descriptor */
struct urb urb; /* USB URB structure */
struct urb urbout; /* Output URB */
struct input_dev input; /* input device structure */
+ int quirks; /* Various nasty tricks the device can pull on us */
};
#define HID_GLOBAL_STACK_SIZE 4
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index 2aef212cb..7c94c185b 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -58,7 +58,8 @@ static unsigned char keybdev_mac_codes[256] =
#endif
-struct input_handler keybdev_handler;
+static struct input_handler keybdev_handler;
+static int keybdev_alt = 0;
void keybdev_ledfunc(unsigned int led)
{
@@ -93,14 +94,22 @@ void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int
handle_scancode(0x1d, down);
handle_scancode(0x45, down);
} else if (code >= 96) {
- handle_scancode(0xe0, 1);
- handle_scancode(keybdev_x86_e0s[code - 96], down);
- if (code == 99) {
+ if (code == 99 && keybdev_alt) {
+ handle_scancode(84, down);
+ } else {
handle_scancode(0xe0, 1);
- handle_scancode(0x37, down);
+ handle_scancode(keybdev_x86_e0s[code - 96], down);
+ if (code == 99) {
+ handle_scancode(0xe0, 1);
+ handle_scancode(0x37, down);
+ }
}
+ } else if (code == 84) {
+ handle_scancode(43, down);
} else handle_scancode(code, down);
+ if (code == 56 || code == 100) keybdev_alt = down;
+
#elif CONFIG_ADB_KEYBOARD
if (code < 128 && keybdev_mac_codes[code])
@@ -152,7 +161,7 @@ static void keybdev_disconnect(struct input_handle *handle)
kfree(handle);
}
-struct input_handler keybdev_handler = {
+static struct input_handler keybdev_handler = {
event: keybdev_event,
connect: keybdev_connect,
disconnect: keybdev_disconnect,
diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
new file mode 100644
index 000000000..c8063c927
--- /dev/null
+++ b/drivers/usb/mdc800.c
@@ -0,0 +1,931 @@
+/*
+ * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * USB-Kernel Driver for the Mustek MDC800 Digital Camera
+ * (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
+ *
+ *
+ * The driver brings the USB functions of the MDC800 to Linux.
+ * To use the Camera you must support the USB Protocoll of the camera
+ * to the Kernel Node.
+ * The Driver uses a misc device Node. Create it with :
+ * mknod /dev/mustek c 10 171
+ *
+ * The driver supports only one camera.
+ *
+ * version 0.7.1
+ * The Init und Exit Module Function are updated.
+ * (01/03/2000)
+ *
+ * version 0.7.0
+ * Rewrite of the driver : The driver now uses URB's. The old stuff
+ * has been removed.
+ *
+ * version 0.6.0
+ * Rewrite of this driver: The Emulation of the rs232 protocoll
+ * has been removed from the driver. A special executeCommand function
+ * for this driver is included to gphoto.
+ * The driver supports two kind of communication to bulk endpoints.
+ * Either with the dev->bus->ops->bulk... or with callback function.
+ * (09/11/1999)
+ *
+ * version 0.5.0:
+ * first Version that gets a version number. Most of the needed
+ * functions work.
+ * (20/10/1999)
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+
+#include <linux/usb.h>
+
+#define VERSION "0.7.1"
+#define RELEASE_DATE "(01/03/2000)"
+
+/* Vendor and Product Information */
+#define MDC800_VENDOR_ID 0x055f
+#define MDC800_PRODUCT_ID 0xa800
+
+/* Timeouts (msec) */
+#define TO_READ_FROM_IRQ 4000
+#define TO_GET_READY 2000
+#define TO_DOWNLOAD_GET_READY 1500
+#define TO_DOWNLOAD_GET_BUSY 1500
+#define TO_WRITE_GET_READY 3000
+#define TO_DEFAULT_COMMAND 5000
+
+/* Minor Number of the device (create with mknod /dev/mustek c 10 171) */
+#define MDC800_DEVICE_MINOR 171
+
+
+/**************************************************************************
+ Data and structs
+***************************************************************************/
+
+
+typedef enum {
+ NOT_CONNECTED, READY, WORKING, DOWNLOAD
+} mdc800_state;
+
+
+/* Data for the driver */
+struct mdc800_data
+{
+ struct usb_device * dev; // Device Data
+ mdc800_state state;
+
+ unsigned int endpoint [4];
+
+ purb_t irq_urb;
+ wait_queue_head_t irq_wait;
+ char* irq_urb_buffer;
+
+ int camera_busy; // is camera busy ?
+ int camera_request_ready; // Status to synchronize with irq
+ char camera_response [8]; // last Bytes send after busy
+
+ purb_t write_urb;
+ char* write_urb_buffer;
+ wait_queue_head_t write_wait;
+
+
+ purb_t download_urb;
+ char* download_urb_buffer;
+ wait_queue_head_t download_wait;
+ int download_left; // Bytes left to download ?
+
+
+ /* Device Data */
+ char out [64]; // Answer Buffer
+ int out_ptr; // Index to the first not readen byte
+ int out_count; // Bytes in the buffer
+
+ int open; // Camera device open ?
+ int rw_lock; // Block read <-> write
+
+ char in [8]; // Command Input Buffer
+ int in_count;
+
+ int pic_index; // Cache for the Imagesize (-1 for nothing cached )
+ int pic_len;
+};
+
+
+/* Specification of the Endpoints */
+static struct usb_endpoint_descriptor mdc800_ed [4] =
+{
+ { 0,0, 0x01, 0x02, 8, 0,0,0 },
+ { 0,0, 0x82, 0x03, 8, 0,0,0 },
+ { 0,0, 0x03, 0x02, 64, 0,0,0 },
+ { 0,0, 0x84, 0x02, 64, 0,0,0 }
+};
+
+
+/* The Variable used by the driver */
+static struct mdc800_data* mdc800=0;
+
+
+/***************************************************************************
+ The USB Part of the driver
+****************************************************************************/
+
+static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b)
+{
+ return (
+ ( a->bEndpointAddress == b->bEndpointAddress )
+ && ( a->bmAttributes == b->bmAttributes )
+ && ( a->wMaxPacketSize == b->wMaxPacketSize )
+ );
+}
+
+
+/*
+ * Checks wether the camera responds busy
+ */
+static int mdc800_isBusy (char* ch)
+{
+ int i=0;
+ while (i<8)
+ {
+ if (ch [i] != (char)0x99)
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+
+/*
+ * Checks wether the Camera is ready
+ */
+static int mdc800_isReady (char *ch)
+{
+ int i=0;
+ while (i<8)
+ {
+ if (ch [i] != (char)0xbb)
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+
+
+/*
+ * USB IRQ Handler for InputLine
+ */
+static void mdc800_usb_irq (struct urb *urb)
+{
+ int data_received=0, wake_up;
+ unsigned char* b=urb->transfer_buffer;
+ struct mdc800_data* mdc800=urb->context;
+
+ if (urb->status >= 0)
+ {
+
+ //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+ if (mdc800_isBusy (b))
+ {
+ if (!mdc800->camera_busy)
+ {
+ mdc800->camera_busy=1;
+ dbg ("gets busy");
+ }
+ }
+ else
+ {
+ if (mdc800->camera_busy && mdc800_isReady (b))
+ {
+ mdc800->camera_busy=0;
+ dbg ("gets ready");
+ }
+ }
+ if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
+ {
+ /* Store Data in camera_answer field */
+ dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+ memcpy (mdc800->camera_response,b,8);
+ data_received=1;
+ }
+ }
+ wake_up= ( mdc800->camera_request_ready > 0 )
+ &&
+ (
+ ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
+ ||
+ ((mdc800->camera_request_ready == 2) && data_received)
+ ||
+ ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
+ ||
+ (urb->status < 0)
+ );
+
+ if (wake_up)
+ {
+ mdc800->camera_request_ready=0;
+ wake_up_interruptible (&mdc800->irq_wait);
+ }
+}
+
+
+/*
+ * Waits a while until the irq responds that camera is ready
+ *
+ * mode : 0: Wait for camera gets ready
+ * 1: Wait for receiving data
+ * 2: Wait for camera gets busy
+ *
+ * msec: Time to wait
+ */
+static int mdc800_usb_waitForIRQ (int mode, int msec)
+{
+ mdc800->camera_request_ready=1+mode;
+
+ interruptible_sleep_on_timeout (&mdc800->irq_wait, msec*HZ/1000);
+
+ if (mdc800->camera_request_ready>0)
+ {
+ mdc800->camera_request_ready=0;
+ err ("timeout waiting for camera.");
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * The write_urb callback function
+ */
+static void mdc800_usb_write_notify (struct urb *urb)
+{
+ struct mdc800_data* mdc800=urb->context;
+
+ if (urb->status != 0)
+ {
+ err ("writing command fails (status=%i)", urb->status);
+ }
+ mdc800->state=READY;
+ wake_up_interruptible (&mdc800->write_wait);
+}
+
+
+/*
+ * The download_urb callback function
+ */
+static void mdc800_usb_download_notify (struct urb *urb)
+{
+ struct mdc800_data* mdc800=urb->context;
+
+ if (urb->status == 0)
+ {
+ /* Fill output buffer with these data */
+ memcpy (mdc800->out, urb->transfer_buffer, 64);
+ mdc800->out_count=64;
+ mdc800->out_ptr=0;
+ mdc800->download_left-=64;
+ if (mdc800->download_left == 0)
+ {
+ mdc800->state=READY;
+ }
+ }
+ else
+ {
+ err ("request bytes fails (status:%i)", urb->status);
+ mdc800->state=READY;
+ }
+ wake_up_interruptible (&mdc800->download_wait);
+}
+
+
+/***************************************************************************
+ Probing for the Camera
+ ***************************************************************************/
+
+static struct usb_driver mdc800_usb_driver;
+
+/*
+ * Callback to search the Mustek MDC800 on the USB Bus
+ */
+static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
+{
+ int i,j;
+ struct usb_interface_descriptor *intf_desc;
+ int irq_interval=0;
+
+ dbg ("(mdc800_usb_probe) called.");
+
+ if (mdc800->dev != 0)
+ {
+ warn ("only one Mustek MDC800 is supported.");
+ return 0;
+ }
+
+ if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
+ return 0;
+ if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
+ return 0;
+
+ if (dev->descriptor.bNumConfigurations != 1)
+ {
+ err ("probe fails -> wrong Number of Configuration");
+ return 0;
+ }
+ intf_desc=&dev->actconfig->interface[ifnum].altsetting[0];
+
+ if (
+ ( intf_desc->bInterfaceClass != 0xff )
+ || ( intf_desc->bInterfaceSubClass != 0 )
+ || ( intf_desc->bInterfaceProtocol != 0 )
+ || ( intf_desc->bNumEndpoints != 4)
+ )
+ {
+ err ("probe fails -> wrong Interface");
+ return 0;
+ }
+
+ /* Check the Endpoints */
+ for (i=0; i<4; i++)
+ {
+ mdc800->endpoint[i]=-1;
+ for (j=0; j<4; j++)
+ {
+ if (mdc800_endpoint_equals (&intf_desc->endpoint [j],&mdc800_ed [i]))
+ {
+ mdc800->endpoint[i]=intf_desc->endpoint [j].bEndpointAddress ;
+ if (i==1)
+ {
+ irq_interval=intf_desc->endpoint [j].bInterval;
+ }
+
+ continue;
+ }
+ }
+ if (mdc800->endpoint[i] == -1)
+ {
+ err ("probe fails -> Wrong Endpoints.");
+ return 0;
+ }
+ }
+
+
+ usb_driver_claim_interface (&mdc800_usb_driver, &dev->actconfig->interface[ifnum], mdc800);
+ if (usb_set_interface (dev, ifnum, 0) < 0)
+ {
+ err ("MDC800 Configuration fails.");
+ return 0;
+ }
+
+ info ("Found Mustek MDC800 on USB.");
+
+ mdc800->dev=dev;
+ mdc800->state=READY;
+
+ /* Setup URB Structs */
+ FILL_INT_URB (
+ mdc800->irq_urb,
+ mdc800->dev,
+ usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]),
+ mdc800->irq_urb_buffer,
+ 8,
+ mdc800_usb_irq,
+ mdc800,
+ irq_interval
+ );
+
+ FILL_BULK_URB (
+ mdc800->write_urb,
+ mdc800->dev,
+ usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]),
+ mdc800->write_urb_buffer,
+ 8,
+ mdc800_usb_write_notify,
+ mdc800
+ );
+
+ FILL_BULK_URB (
+ mdc800->download_urb,
+ mdc800->dev,
+ usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]),
+ mdc800->download_urb_buffer,
+ 64,
+ mdc800_usb_download_notify,
+ mdc800
+ );
+
+ return mdc800;
+}
+
+
+/*
+ * Disconnect USB device (maybe the MDC800)
+ */
+static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
+{
+ struct mdc800_data* mdc800=(struct mdc800_data*) ptr;
+
+ dbg ("(mdc800_usb_disconnect) called");
+
+ if (mdc800->state == NOT_CONNECTED)
+ return;
+
+ mdc800->state=NOT_CONNECTED;
+ mdc800->open=0;
+ mdc800->rw_lock=0;
+
+ usb_unlink_urb (mdc800->irq_urb);
+ usb_unlink_urb (mdc800->write_urb);
+ usb_unlink_urb (mdc800->download_urb);
+
+ usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]);
+
+ mdc800->dev=0;
+ info ("Mustek MDC800 disconnected from USB.");
+}
+
+
+/***************************************************************************
+ The Misc device Part (file_operations)
+****************************************************************************/
+
+/*
+ * This Function calc the Answersize for a command.
+ */
+static int mdc800_getAnswerSize (char command)
+{
+ switch ((unsigned char) command)
+ {
+ case 0x2a:
+ case 0x49:
+ case 0x51:
+ case 0x0d:
+ case 0x20:
+ case 0x07:
+ case 0x01:
+ case 0x25:
+ case 0x00:
+ return 8;
+
+ case 0x05:
+ case 0x3e:
+ return mdc800->pic_len;
+
+ case 0x09:
+ return 4096;
+
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ * Init the device: (1) alloc mem (2) Increase MOD Count ..
+ */
+static int mdc800_device_open (struct inode* inode, struct file *file)
+{
+ int retval=0;
+ if (mdc800->state == NOT_CONNECTED)
+ return -EBUSY;
+
+ if (mdc800->open)
+ return -EBUSY;
+
+ mdc800->rw_lock=0;
+ mdc800->in_count=0;
+ mdc800->out_count=0;
+ mdc800->out_ptr=0;
+ mdc800->pic_index=0;
+ mdc800->pic_len=-1;
+ mdc800->download_left=0;
+
+ mdc800->camera_busy=0;
+ mdc800->camera_request_ready=0;
+
+ retval=0;
+ if (usb_submit_urb (mdc800->irq_urb))
+ {
+ err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ return -EIO;
+ }
+
+ MOD_INC_USE_COUNT;
+ mdc800->open=1;
+
+ dbg ("Mustek MDC800 device opened.");
+ return 0;
+}
+
+
+/*
+ * Close the Camera and release Memory
+ */
+static int mdc800_device_release (struct inode* inode, struct file *file)
+{
+ int retval=0;
+ dbg ("Mustek MDC800 device closed.");
+
+ if (mdc800->open && (mdc800->state != NOT_CONNECTED))
+ {
+ mdc800->open=0;
+ usb_unlink_urb (mdc800->irq_urb);
+ usb_unlink_urb (mdc800->write_urb);
+ usb_unlink_urb (mdc800->download_urb);
+ }
+ else
+ {
+ retval=-EIO;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ return retval;
+}
+
+
+/*
+ * The Device read callback Function
+ */
+static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
+{
+ int left=len, sts=len; /* single transfer size */
+ char* ptr=buf;
+
+ if (mdc800->state == NOT_CONNECTED)
+ return -EBUSY;
+
+ if (!mdc800->open || mdc800->rw_lock)
+ return -EBUSY;
+ mdc800->rw_lock=1;
+
+ while (left)
+ {
+ if (signal_pending (current)) {
+ mdc800->rw_lock=0;
+ return -EINTR;
+ }
+
+ sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
+
+ if (sts <= 0)
+ {
+ /* Too less Data in buffer */
+ if (mdc800->state == DOWNLOAD)
+ {
+ mdc800->out_count=0;
+ mdc800->out_ptr=0;
+
+ /* Download -> Request new bytes */
+ if (usb_submit_urb (mdc800->download_urb))
+ {
+ err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return len-left;
+ }
+ interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
+ if (mdc800->download_urb->status != 0)
+ {
+ err ("requesting bytes fails (status=%i)",mdc800->download_urb->status);
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return len-left;
+ }
+ }
+ else
+ {
+ /* No more bytes -> that's an error*/
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+ }
+ else
+ {
+ /* memcpy Bytes */
+ memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts);
+ ptr+=sts;
+ left-=sts;
+ mdc800->out_ptr+=sts;
+ }
+ }
+
+ mdc800->rw_lock=0;
+ return len-left;
+}
+
+
+/*
+ * The Device write callback Function
+ * If a 8Byte Command is received, it will be send to the camera.
+ * After this the driver initiates the request for the answer or
+ * just waits until the camera becomes ready.
+ */
+static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
+{
+ int i=0;
+
+ if (mdc800->state != READY)
+ return -EBUSY;
+
+ if (!mdc800->open || mdc800->rw_lock)
+ return -EBUSY;
+ mdc800->rw_lock=1;
+
+ while (i<len)
+ {
+ if (signal_pending (current)) {
+ mdc800->rw_lock=0;
+ return -EINTR;
+ }
+
+ /* check for command start */
+ if (buf [i] == (char) 0x55)
+ {
+ mdc800->in_count=0;
+ mdc800->out_count=0;
+ mdc800->out_ptr=0;
+ mdc800->download_left=0;
+ }
+
+ /* save command byte */
+ if (mdc800->in_count < 8)
+ {
+ mdc800->in[mdc800->in_count]=buf[i];
+ mdc800->in_count++;
+ }
+ else
+ {
+ err ("Command is to long !\n");
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+
+ /* Command Buffer full ? -> send it to camera */
+ if (mdc800->in_count == 8)
+ {
+ int answersize;
+
+ mdc800_usb_waitForIRQ (0,TO_GET_READY);
+
+ answersize=mdc800_getAnswerSize (mdc800->in[1]);
+
+ mdc800->state=WORKING;
+ memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
+ if (usb_submit_urb (mdc800->write_urb))
+ {
+ err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+ mdc800->rw_lock=0;
+ mdc800->state=READY;
+ return -EIO;
+ }
+ interruptible_sleep_on_timeout (&mdc800->write_wait, TO_DEFAULT_COMMAND*HZ/1000);
+ if (mdc800->state == WORKING)
+ {
+ usb_unlink_urb (mdc800->write_urb);
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+
+ switch ((unsigned char) mdc800->in[1])
+ {
+ case 0x05: /* Download Image */
+ case 0x3e: /* Take shot in Fine Mode (WCam Mode) */
+ if (mdc800->pic_len < 0)
+ {
+ err ("call 0x07 before 0x05,0x3e");
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+ mdc800->pic_len=-1;
+
+ case 0x09: /* Download Thumbnail */
+ mdc800->download_left=answersize+64;
+ mdc800->state=DOWNLOAD;
+ mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY);
+ break;
+
+
+ default:
+ if (answersize)
+ {
+
+ if (!mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
+ {
+ err ("requesting answer from irq fails");
+ mdc800->state=READY;
+ mdc800->rw_lock=0;
+ return -EIO;
+ }
+
+ /* Write dummy data, (this is ugly but part of the USB Protokoll */
+ /* if you use endpoint 1 as bulk and not as irq */
+ memcpy (mdc800->out, mdc800->camera_response,8);
+
+ /* This is the interpreted answer */
+ memcpy (&mdc800->out[8], mdc800->camera_response,8);
+
+ mdc800->out_ptr=0;
+ mdc800->out_count=16;
+
+ /* Cache the Imagesize, if command was getImageSize */
+ if (mdc800->in [1] == (char) 0x07)
+ {
+ mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
+
+ dbg ("cached imagesize = %i",mdc800->pic_len);
+ }
+
+ }
+ else
+ {
+ if (!mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
+ {
+ err ("Command Timeout.");
+ mdc800->rw_lock=0;
+ mdc800->state=READY;
+ return -EIO;
+ }
+ }
+ mdc800->state=READY;
+ break;
+ }
+ }
+ i++;
+ }
+ mdc800->rw_lock=0;
+ return i;
+}
+
+
+/***************************************************************************
+ Init and Cleanup this driver (Structs and types)
+****************************************************************************/
+
+
+/*
+ * USB Driver Struct for this device
+ */
+static struct usb_driver mdc800_usb_driver =
+{
+ "mdc800",
+ mdc800_usb_probe,
+ mdc800_usb_disconnect,
+ { 0,0 },
+ 0,
+ 0
+};
+
+
+/* File Operations of this drivers */
+static struct file_operations mdc800_device_ops =
+{
+ 0, /* llseek */
+ mdc800_device_read,
+ mdc800_device_write,
+ 0, /* readdir */
+ 0, /* poll */
+ 0, /* ioctl, this can be used to detect USB ! */
+ 0, /* mmap */
+ mdc800_device_open,
+ 0, /* flush */
+ mdc800_device_release,
+ 0, /* async */
+ 0, /* fasync */
+ 0, /* check_media_change */
+// 0, /* revalidate */
+// 0 /* lock */
+};
+
+
+/*
+ * The Misc Device Configuration Struct
+ */
+static struct miscdevice mdc800_device =
+{
+ MDC800_DEVICE_MINOR,
+ "USB Mustek MDC800 Camera",
+ &mdc800_device_ops
+};
+
+
+/************************************************************************
+ Init and Cleanup this driver (Main Functions)
+*************************************************************************/
+
+#define try(A) if ((A) == 0) goto cleanup_on_fail;
+#define try_free_mem(A) if (A != 0) { kfree (A); A=0; }
+#define try_free_urb(A) if (A != 0) { usb_free_urb (A); A=0; }
+
+int __init usb_mdc800_init (void)
+{
+ /* Allocate Memory */
+ try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
+
+ mdc800->dev=0;
+ mdc800->open=0;
+ mdc800->state=NOT_CONNECTED;
+ memset(mdc800, 0, sizeof(struct mdc800_data));
+
+ init_waitqueue_head (&mdc800->irq_wait);
+ init_waitqueue_head (&mdc800->write_wait);
+ init_waitqueue_head (&mdc800->download_wait);
+
+ try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
+ try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
+ try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
+
+ try (mdc800->irq_urb=usb_alloc_urb (0));
+ try (mdc800->download_urb=usb_alloc_urb (0));
+ try (mdc800->write_urb=usb_alloc_urb (0));
+
+ /* Register the driver */
+ if (usb_register (&mdc800_usb_driver) < 0)
+ goto cleanup_on_fail;
+ if (misc_register (&mdc800_device) < 0)
+ goto cleanup_on_misc_register_fail;
+
+ info ("Mustek Digital Camera Driver " VERSION " (MDC800)");
+ info (RELEASE_DATE " Henning Zabel <henning@uni-paderborn.de>");
+
+ return 0;
+
+ /* Clean driver up, when something fails */
+
+cleanup_on_misc_register_fail:
+ usb_deregister (&mdc800_usb_driver);
+
+cleanup_on_fail:
+
+ if (mdc800 != 0)
+ {
+ err ("can't alloc memory!");
+
+ try_free_mem (mdc800->download_urb_buffer);
+ try_free_mem (mdc800->write_urb_buffer);
+ try_free_mem (mdc800->irq_urb_buffer);
+
+ try_free_urb (mdc800->write_urb);
+ try_free_urb (mdc800->download_urb);
+ try_free_urb (mdc800->irq_urb);
+
+ kfree (mdc800);
+ }
+ mdc800=0;
+ return -1;
+}
+
+
+void __exit usb_mdc800_cleanup (void)
+{
+ usb_deregister (&mdc800_usb_driver);
+ misc_deregister (&mdc800_device);
+
+ usb_free_urb (mdc800->irq_urb);
+ usb_free_urb (mdc800->download_urb);
+ usb_free_urb (mdc800->write_urb);
+
+ kfree (mdc800->irq_urb_buffer);
+ kfree (mdc800->write_urb_buffer);
+ kfree (mdc800->download_urb_buffer);
+
+ kfree (mdc800);
+ mdc800=0;
+}
+
+
+MODULE_AUTHOR ("Henning Zabel <henning@uni-paderborn.de>");
+MODULE_DESCRIPTION ("USB Driver for Mustek MDC800 Digital Camera");
+
+module_init (usb_mdc800_init);
+module_exit (usb_mdc800_cleanup);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 607782829..bfdc4ab3d 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -95,8 +95,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
break;
case ABS_Y:
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
- list->dy += (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
- list->oldy += list->dy * size;
+ list->dy -= (value * CONFIG_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+ list->oldy -= list->dy * size;
break;
}
break;
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 2d5de6f73..764f1c055 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -16,12 +16,9 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.3 2000/03/13 Written by Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.3.5 2000/03/21 Written by Petko Manolov (petkan@spct.net)\n";
-#define ADMTEK_VENDOR_ID 0x07a6
-#define ADMTEK_DEVICE_ID_PEGASUS 0x0986
-
#define PEGASUS_MTU 1500
#define PEGASUS_MAX_MTU 1536
#define PEGASUS_TX_TIMEOUT (HZ*5)
@@ -38,6 +35,13 @@ struct pegasus {
unsigned char ALIGN(intr_buff[8]);
};
+struct usb_eth_dev {
+ char *name;
+ __u16 vendor;
+ __u16 device;
+ void *private;
+};
+
static int loopback = 0;
static int multicast_filter_limit = 32;
@@ -46,6 +50,16 @@ MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
+static struct usb_eth_dev usb_dev_id[] = {
+ { "D-Link DSB-650TX", 0x2001, 0x4001, NULL },
+ { "Linksys USB100TX", 0x066b, 0x2203, NULL },
+ { "SMC 202 USB Ethernet", 0x0707, 0x0200, NULL },
+ { "ADMtek AN986 (Pegasus) USB Ethernet", 0x07a6, 0x0986, NULL },
+ { "Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL },
+ { NULL, 0, 0, NULL }
+};
+
+
#define pegasus_get_registers(dev, indx, size, data)\
usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ);
#define pegasus_set_registers(dev, indx, size, data)\
@@ -164,8 +178,8 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
return 4;
if ((partmedia & 0x1f) != 1) {
- err("party FAIL %x", partmedia);
- return 5;
+ warn("party FAIL %x", partmedia);
+ /* return 5; FIXME */
}
data[0] = 0xc9;
@@ -374,13 +388,25 @@ static void pegasus_set_rx_mode(struct net_device *net)
netif_wake_queue(net);
}
+static int check_device_ids( __u16 vendor, __u16 product )
+{
+ int i=0;
+
+ while ( usb_dev_id[i].name ) {
+ if ( (usb_dev_id[i].vendor == vendor) &&
+ (usb_dev_id[i].device == product) )
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
{
struct net_device *net;
struct pegasus *pegasus;
- if (dev->descriptor.idVendor != ADMTEK_VENDOR_ID ||
- dev->descriptor.idProduct != ADMTEK_DEVICE_ID_PEGASUS) {
+ if ( check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct) ) {
return NULL;
}
diff --git a/drivers/usb/serial/Makefile-keyspan_pda_fw b/drivers/usb/serial/Makefile-keyspan_pda_fw
index 219708e46..c20baf728 100644
--- a/drivers/usb/serial/Makefile-keyspan_pda_fw
+++ b/drivers/usb/serial/Makefile-keyspan_pda_fw
@@ -5,7 +5,7 @@
all: keyspan_pda_fw.h
-%.asm: %.s
+%.asm: %.S
gcc -x assembler-with-cpp -P -E -o $@ $<
%.hex: %.asm
diff --git a/drivers/usb/serial/keyspan_pda.S b/drivers/usb/serial/keyspan_pda.S
new file mode 100644
index 000000000..10c99eadd
--- /dev/null
+++ b/drivers/usb/serial/keyspan_pda.S
@@ -0,0 +1,1124 @@
+/* $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $
+ *
+ * Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
+ * the EzUSB microcontroller.
+ *
+ * (C) Copyright 2000 Brian Warner <warner@lothar.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
+ * company.
+ *
+ * This serial adapter is basically an EzUSB chip and an RS-232 line driver
+ * in a little widget that has a DB-9 on one end and a USB plug on the other.
+ * It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
+ * as a baud-rate generator. The wiring is:
+ * PC0/RxD0 <- rxd (DB9 pin 2) PC4 <- dsr pin 6
+ * PC1/TxD0 -> txd pin 3 PC5 <- ri pin 9
+ * PC2 -> rts pin 7 PC6 <- dcd pin 1
+ * PC3 <- cts pin 8 PC7 -> dtr pin 4
+ * PB1 -> line driver standby
+ *
+ * The EzUSB register constants below come from their excellent documentation
+ * and sample code (which used to be available at www.anchorchips.com, but
+ * that has now been absorbed into Cypress' site and the CD-ROM contents
+ * don't appear to be available online anymore). If we get multiple
+ * EzUSB-based drivers into the kernel, it might be useful to pull them out
+ * into a separate .h file.
+ *
+ * THEORY OF OPERATION:
+ *
+ * There are two 256-byte ring buffers, one for tx, one for rx.
+ *
+ * EP2out is pure tx data. When it appears, the data is copied into the tx
+ * ring and serial transmission is started if it wasn't already running. The
+ * "tx buffer empty" interrupt may kick off another character if the ring
+ * still has data. If the host is tx-blocked because the ring filled up,
+ * it will request a "tx unthrottle" interrupt. If sending a serial character
+ * empties the ring below the desired threshold, we set a bit that will send
+ * up the tx unthrottle message as soon as the rx buffer becomes free.
+ *
+ * EP2in (interrupt) is used to send both rx chars and rx status messages
+ * (only "tx unthrottle" at this time) back up to the host. The first byte
+ * of the rx message indicates data (0) or status msg (1). Status messages
+ * are sent before any data.
+ *
+ * Incoming serial characters are put into the rx ring by the serial
+ * interrupt, and the EP2in buffer sent if it wasn't already in transit.
+ * When the EP2in buffer returns, the interrupt prompts us to send more
+ * rx chars (or status messages) if they are pending.
+ *
+ * Device control happens through "vendor specific" control messages on EP0.
+ * All messages are destined for the "Interface" (with the index always 0,
+ * so that if their two-port device might someday use similar firmware, we
+ * can use index=1 to refer to the second port). The messages defined are:
+ *
+ * bRequest = 0 : set baud/bits/parity
+ * 1 : unused
+ * 2 : reserved for setting HW flow control (CTSRTS)
+ * 3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
+ * 4 : set break (on/off)
+ * 5 : reserved for requesting interrupts on pin state change
+ * 6 : query buffer room or chars in tx buffer
+ * 7 : request tx unthrottle interrupt
+ *
+ * The host-side driver is set to recognize the device ID values stashed in
+ * serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
+ * start it running. This firmware will use EzUSB's "renumeration" trick by
+ * simulating a bus disconnect, then reconnect with a different device ID
+ * (encoded in the desc_device descriptor below). The host driver then
+ * recognizes the new device ID and glues it to the real serial driver code.
+ *
+ * USEFUL DOCS:
+ * EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ * 8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
+ * basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
+ * use totally different registers!
+ * USB 1.1 spec: www.usb.org
+ *
+ * HOW TO BUILD:
+ * gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
+ * as31 -l keyspan_pda.asm
+ * mv keyspan_pda.obj keyspan_pda.hex
+ * perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
+ * Get as31 from <http://www.pjrc.com/tech/8051/index.html>, and hack on it
+ * a bit to make it build.
+ *
+ * THANKS:
+ * Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
+ * AnchorChips, for making such an incredibly useful little microcontroller.
+ * KeySpan, for making a handy, cheap ($40) widget that was so easy to take
+ * apart and trace with an ohmmeter.
+ *
+ * TODO:
+ * lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
+ * control. Interrupting host upon change in DCD, etc, counting transitions.
+ * Need to find a safe device id to use (the one used by the Keyspan firmware
+ * under Windows would be ideal.. can anyone figure out what it is?). Parity.
+ * More baud rates. Oh, and the string-descriptor-length silicon bug
+ * workaround should be implemented, but I'm lazy, and the consequence is
+ * that the device name strings that show up in your kernel log will have
+ * lots of trailing binary garbage in them (appears as ????). Device strings
+ * should be made more accurate.
+ *
+ * Questions, bugs, patches to Brian.
+ *
+ * -Brian Warner <warner@lothar.com>
+ *
+ */
+
+#define HIGH(x) (((x) & 0xff00) / 256)
+#define LOW(x) ((x) & 0xff)
+
+#define dpl1 0x84
+#define dph1 0x85
+#define dps 0x86
+
+;;; our bit assignments
+#define TX_RUNNING 0
+#define DO_TX_UNTHROTTLE 1
+
+ ;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
+#define STACK #0x60-1
+
+#define EXIF 0x91
+#define EIE 0xe8
+ .flag EUSB, EIE.0
+ .flag ES0, IE.4
+
+#define EP0CS #0x7fb4
+#define EP0STALLbit #0x01
+#define IN0BUF #0x7f00
+#define IN0BC #0x7fb5
+#define OUT0BUF #0x7ec0
+#define OUT0BC #0x7fc5
+#define IN2BUF #0x7e00
+#define IN2BC #0x7fb9
+#define IN2CS #0x7fb8
+#define OUT2BC #0x7fc9
+#define OUT2CS #0x7fc8
+#define OUT2BUF #0x7dc0
+#define IN4BUF #0x7d00
+#define IN4BC #0x7fbd
+#define IN4CS #0x7fbc
+#define OEB #0x7f9d
+#define OUTB #0x7f97
+#define OEC #0x7f9e
+#define OUTC #0x7f98
+#define PINSC #0x7f9b
+#define PORTCCFG #0x7f95
+#define IN07IRQ #0x7fa9
+#define OUT07IRQ #0x7faa
+#define IN07IEN #0x7fac
+#define OUT07IEN #0x7fad
+#define USBIRQ #0x7fab
+#define USBIEN #0x7fae
+#define USBBAV #0x7faf
+#define USBCS #0x7fd6
+#define SUDPTRH #0x7fd4
+#define SUDPTRL #0x7fd5
+#define SETUPDAT #0x7fe8
+
+ ;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
+
+ .org 0
+ ljmp start
+ ;; interrupt vectors
+ .org 23H
+ ljmp serial_int
+ .byte 0
+
+ .org 43H
+ ljmp USB_Jump_Table
+ .byte 0 ; filled in by the USB core
+
+;;; local variables. These are not initialized properly: do it by hand.
+ .org 30H
+rx_ring_in: .byte 0
+rx_ring_out: .byte 0
+tx_ring_in: .byte 0
+tx_ring_out: .byte 0
+tx_unthrottle_threshold: .byte 0
+
+ .org 0x100H ; wants to be on a page boundary
+USB_Jump_Table:
+ ljmp ISR_Sudav ; Setup Data Available
+ .byte 0
+ ljmp 0 ; Start of Frame
+ .byte 0
+ ljmp 0 ; Setup Data Loading
+ .byte 0
+ ljmp 0 ; Global Suspend
+ .byte 0
+ ljmp 0 ; USB Reset
+ .byte 0
+ ljmp 0 ; Reserved
+ .byte 0
+ ljmp 0 ; End Point 0 In
+ .byte 0
+ ljmp 0 ; End Point 0 Out
+ .byte 0
+ ljmp 0 ; End Point 1 In
+ .byte 0
+ ljmp 0 ; End Point 1 Out
+ .byte 0
+ ljmp ISR_Ep2in
+ .byte 0
+ ljmp ISR_Ep2out
+ .byte 0
+
+
+ .org 0x200
+
+start: mov SP,STACK-1 ; set stack
+ ;; clear local variables
+ clr a
+ mov tx_ring_in, a
+ mov tx_ring_out, a
+ mov rx_ring_in, a
+ mov rx_ring_out, a
+ mov tx_unthrottle_threshold, a
+ clr TX_RUNNING
+ clr DO_TX_UNTHROTTLE
+
+ ;; clear fifo with "fe"
+ mov r1, 0
+ mov a, #0xfe
+ mov dptr, #tx_ring
+clear_tx_ring_loop:
+ movx @dptr, a
+ inc dptr
+ djnz r1, clear_tx_ring_loop
+
+ mov a, #0xfd
+ mov dptr, #rx_ring
+clear_rx_ring_loop:
+ movx @dptr, a
+ inc dptr
+ djnz r1, clear_rx_ring_loop
+
+;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
+ ;; set OEB.1
+ mov a, #02H
+ mov dptr,OEB
+ movx @dptr,a
+ ;; clear PB1
+ mov a, #00H
+ mov dptr,OUTB
+ movx @dptr,a
+ ;; set OEC.[127]
+ mov a, #0x86
+ mov dptr,OEC
+ movx @dptr,a
+ ;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
+ mov dptr, PORTCCFG
+ mov a, #0x03
+ movx @dptr, a
+
+ ;; set up interrupts, autovectoring
+ mov dptr, USBBAV
+ movx a,@dptr
+ setb acc.0 ; AVEN bit to 0
+ movx @dptr, a
+
+ mov a,#0x01 ; enable SUDAV: setup data available (for ep0)
+ mov dptr, USBIRQ
+ movx @dptr, a ; clear SUDAVI
+ mov dptr, USBIEN
+ movx @dptr, a
+
+ mov dptr, IN07IEN
+ mov a,#0x04 ; enable IN2 int
+ movx @dptr, a
+
+ mov dptr, OUT07IEN
+ mov a,#0x04 ; enable OUT2 int
+ movx @dptr, a
+ mov dptr, OUT2BC
+ movx @dptr, a ; arm OUT2
+
+ mov a, #0x84 ; turn on RTS, DTR
+ mov dptr,OUTC
+ movx @dptr, a
+ ;; setup the serial port. 9600 8N1.
+ mov a,#01010011 ; mode 1, enable rx, clear int
+ mov SCON, a
+ ;; using timer2, in 16-bit baud-rate-generator mode
+ ;; (xtal 12MHz, internal fosc 24MHz)
+ ;; RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
+ ;; 57600: 0xFFF2.F, say 0xFFF3
+ ;; 9600: 0xFFB1.E, say 0xFFB2
+ ;; 300: 0xF63C
+#define BAUD 9600
+#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
+#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
+#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
+
+ mov T2CON, #030h ; rclk=1,tclk=1,cp=0,tr2=0(enable later)
+ mov r3, #5
+ acall set_baud
+ setb TR2
+ mov SCON, #050h
+
+#if 0
+ mov r1, #0x40
+ mov a, #0x41
+send:
+ mov SBUF, a
+ inc a
+ anl a, #0x3F
+ orl a, #0x40
+; xrl a, #0x02
+wait1:
+ jnb TI, wait1
+ clr TI
+ djnz r1, send
+;done: sjmp done
+
+#endif
+
+ setb EUSB
+ setb EA
+ setb ES0
+ ;acall dump_stat
+
+ ;; hey, what say we RENUMERATE! (TRM p.62)
+ mov a, #0
+ mov dps, a
+ mov dptr, USBCS
+ mov a, #0x02 ; DISCON=0, DISCOE=0, RENUM=1
+ movx @dptr, a
+ ;; now presence pin is floating, simulating disconnect. wait 0.5s
+ mov r1, #46
+renum_wait1:
+ mov r2, #0
+renum_wait2:
+ mov r3, #0
+renum_wait3:
+ djnz r3, renum_wait3
+ djnz r2, renum_wait2
+ djnz r1, renum_wait1 ; wait about n*(256^2) 6MHz clocks
+ mov a, #0x06 ; DISCON=0, DISCOE=1, RENUM=1
+ movx @dptr, a
+ ;; we are back online. the host device will now re-query us
+
+
+main: sjmp main
+
+
+
+ISR_Sudav:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ mov a,EXIF
+ clr acc.4
+ mov EXIF,a ; clear INT2 first
+ mov dptr, USBIRQ ; clear USB int
+ mov a,#01h
+ movx @dptr,a
+
+ ;; get request type
+ mov dptr, SETUPDAT
+ movx a, @dptr
+ mov r1, a ; r1 = bmRequestType
+ inc dptr
+ movx a, @dptr
+ mov r2, a ; r2 = bRequest
+ inc dptr
+ movx a, @dptr
+ mov r3, a ; r3 = wValueL
+ inc dptr
+ movx a, @dptr
+ mov r4, a ; r4 = wValueH
+
+ ;; main switch on bmRequest.type: standard or vendor
+ mov a, r1
+ anl a, #0x60
+ cjne a, #0x00, setup_bmreq_type_not_standard
+ ;; standard request: now main switch is on bRequest
+ ljmp setup_bmreq_is_standard
+
+setup_bmreq_type_not_standard:
+ ;; a still has bmreq&0x60
+ cjne a, #0x40, setup_bmreq_type_not_vendor
+ ;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
+ ;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
+ cjne r2, #0x00, setup_ctrl_not_00
+ ;; 00 is set baud, wValue[0] has baud rate index
+ lcall set_baud ; index in r3, carry set if error
+ jc setup_bmreq_type_not_standard__do_stall
+ ljmp setup_done_ack
+setup_bmreq_type_not_standard__do_stall:
+ ljmp setup_stall
+setup_ctrl_not_00:
+ cjne r2, #0x01, setup_ctrl_not_01
+ ;; 01 is reserved for set bits (parity). TODO
+ ljmp setup_stall
+setup_ctrl_not_01:
+ cjne r2, #0x02, setup_ctrl_not_02
+ ;; 02 is set HW flow control. TODO
+ ljmp setup_stall
+setup_ctrl_not_02:
+ cjne r2, #0x03, setup_ctrl_not_03
+ ;; 03 is control pins (RTS, DTR).
+ ljmp control_pins ; will jump to setup_done_ack,
+ ; or setup_return_one_byte
+setup_ctrl_not_03:
+ cjne r2, #0x04, setup_ctrl_not_04
+ ;; 04 is send break (really "turn break on/off"). TODO
+ cjne r3, #0x00, setup_ctrl_do_break_on
+ ;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
+ mov dptr, PORTCCFG
+ movx a, @dptr
+ orl a, #0x02
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_ctrl_do_break_on:
+ ;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
+ mov dptr, OUTC
+ movx a, @dptr
+ anl a, #0xfd ; ~0x02
+ movx @dptr, a
+ mov dptr, PORTCCFG
+ movx a, @dptr
+ anl a, #0xfd ; ~0x02
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_ctrl_not_04:
+ cjne r2, #0x05, setup_ctrl_not_05
+ ;; 05 is set desired interrupt bitmap. TODO
+ ljmp setup_stall
+setup_ctrl_not_05:
+ cjne r2, #0x06, setup_ctrl_not_06
+ ;; 06 is query room
+ cjne r3, #0x00, setup_ctrl_06_not_00
+ ;; 06, wValue[0]=0 is query write_room
+ mov a, tx_ring_out
+ setb c
+ subb a, tx_ring_in ; out-1-in = 255 - (in-out)
+ ljmp setup_return_one_byte
+setup_ctrl_06_not_00:
+ cjne r3, #0x01, setup_ctrl_06_not_01
+ ;; 06, wValue[0]=1 is query chars_in_buffer
+ mov a, tx_ring_in
+ clr c
+ subb a, tx_ring_out ; in-out
+ ljmp setup_return_one_byte
+setup_ctrl_06_not_01:
+ ljmp setup_stall
+setup_ctrl_not_06:
+ cjne r2, #0x07, setup_ctrl_not_07
+ ;; 07 is request tx unthrottle interrupt
+ mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
+ ljmp setup_done_ack
+setup_ctrl_not_07:
+ ljmp setup_stall
+
+setup_bmreq_type_not_vendor:
+ ljmp setup_stall
+
+
+setup_bmreq_is_standard:
+ cjne r2, #0x00, setup_breq_not_00
+ ;; 00: Get_Status (sub-switch on bmRequestType: device, ep, int)
+ cjne r1, #0x80, setup_Get_Status_not_device
+ ;; Get_Status(device)
+ ;; are we self-powered? no. can we do remote wakeup? no
+ ;; so return two zero bytes. This is reusable
+setup_return_two_zero_bytes:
+ mov dptr, IN0BUF
+ clr a
+ movx @dptr, a
+ inc dptr
+ movx @dptr, a
+ mov dptr, IN0BC
+ mov a, #2
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_Get_Status_not_device:
+ cjne r1, #0x82, setup_Get_Status_not_endpoint
+ ;; Get_Status(endpoint)
+ ;; must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
+ ;; for now: cheat. TODO
+ sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_endpoint:
+ cjne r1, #0x81, setup_Get_Status_not_interface
+ ;; Get_Status(interface): return two zeros
+ sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_interface:
+ ljmp setup_stall
+
+setup_breq_not_00:
+ cjne r2, #0x01, setup_breq_not_01
+ ;; 01: Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
+ cjne r3, #0x00, setup_Clear_Feature_not_stall
+ ;; Clear_Feature(stall). should clear a stall bit. TODO
+ ljmp setup_stall
+setup_Clear_Feature_not_stall:
+ cjne r3, #0x01, setup_Clear_Feature_not_rwake
+ ;; Clear_Feature(remote wakeup). ignored.
+ ljmp setup_done_ack
+setup_Clear_Feature_not_rwake:
+ ljmp setup_stall
+
+setup_breq_not_01:
+ cjne r2, #0x03, setup_breq_not_03
+ ;; 03: Set_Feature (sub-switch on wValueL: stall, remote wakeup)
+ cjne r3, #0x00, setup_Set_Feature_not_stall
+ ;; Set_Feature(stall). Should set a stall bit. TODO
+ ljmp setup_stall
+setup_Set_Feature_not_stall:
+ cjne r3, #0x01, setup_Set_Feature_not_rwake
+ ;; Set_Feature(remote wakeup). ignored.
+ ljmp setup_done_ack
+setup_Set_Feature_not_rwake:
+ ljmp setup_stall
+
+setup_breq_not_03:
+ cjne r2, #0x06, setup_breq_not_06
+ ;; 06: Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
+ cjne r4, #0x01, setup_Get_Descriptor_not_device
+ ;; Get_Descriptor(device)
+ mov dptr, SUDPTRH
+ mov a, #HIGH(desc_device)
+ movx @dptr, a
+ mov dptr, SUDPTRL
+ mov a, #LOW(desc_device)
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_Get_Descriptor_not_device:
+ cjne r4, #0x02, setup_Get_Descriptor_not_config
+ ;; Get_Descriptor(config[n])
+ cjne r3, #0x00, setup_stall; only handle n==0
+ ;; Get_Descriptor(config[0])
+ mov dptr, SUDPTRH
+ mov a, #HIGH(desc_config1)
+ movx @dptr, a
+ mov dptr, SUDPTRL
+ mov a, #LOW(desc_config1)
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_Get_Descriptor_not_config:
+ cjne r4, #0x03, setup_Get_Descriptor_not_string
+ ;; Get_Descriptor(string[wValueL])
+ ;; if (wValueL >= maxstrings) stall
+ mov a, #((desc_strings_end-desc_strings)/2)
+ clr c
+ subb a,r3 ; a=4, r3 = 0..3 . if a<=0 then stall
+ jc setup_stall
+ jz setup_stall
+ mov a, r3
+ add a, r3 ; a = 2*wValueL
+ mov dptr, #desc_strings
+ add a, dpl
+ mov dpl, a
+ mov a, #0
+ addc a, dph
+ mov dph, a ; dph = desc_strings[a]. big endian! (handy)
+ ;; it looks like my adapter uses a revision of the EZUSB that
+ ;; contains "rev D errata number 8", as hinted in the EzUSB example
+ ;; code. I cannot find an actual errata description on the Cypress
+ ;; web site, but from the example code it looks like this bug causes
+ ;; the length of string descriptors to be read incorrectly, possibly
+ ;; sending back more characters than the descriptor has. The workaround
+ ;; is to manually send out all of the data. The consequence of not
+ ;; using the workaround is that the strings gathered by the kernel
+ ;; driver are too long and are filled with trailing garbage (including
+ ;; leftover strings). Writing this out by hand is a nuisance, so for
+ ;; now I will just live with the bug.
+ movx a, @dptr
+ mov r1, a
+ inc dptr
+ movx a, @dptr
+ mov r2, a
+ mov dptr, SUDPTRH
+ mov a, r1
+ movx @dptr, a
+ mov dptr, SUDPTRL
+ mov a, r2
+ movx @dptr, a
+ ;; done
+ ljmp setup_done_ack
+
+setup_Get_Descriptor_not_string:
+ ljmp setup_stall
+
+setup_breq_not_06:
+ cjne r2, #0x08, setup_breq_not_08
+ ;; Get_Configuration. always 1. return one byte.
+ ;; this is reusable
+ mov a, #1
+setup_return_one_byte:
+ mov dptr, IN0BUF
+ movx @dptr, a
+ mov a, #1
+ mov dptr, IN0BC
+ movx @dptr, a
+ ljmp setup_done_ack
+setup_breq_not_08:
+ cjne r2, #0x09, setup_breq_not_09
+ ;; 09: Set_Configuration. ignored.
+ ljmp setup_done_ack
+setup_breq_not_09:
+ cjne r2, #0x0a, setup_breq_not_0a
+ ;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
+ ;; since we only have one interface, ignore wIndexL, return a 0
+ mov a, #0
+ ljmp setup_return_one_byte
+setup_breq_not_0a:
+ cjne r2, #0x0b, setup_breq_not_0b
+ ;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
+ ljmp setup_done_ack
+setup_breq_not_0b:
+ ljmp setup_stall
+
+
+setup_done_ack:
+ ;; now clear HSNAK
+ mov dptr, EP0CS
+ mov a, #0x02
+ movx @dptr, a
+ sjmp setup_done
+setup_stall:
+ ;; unhandled. STALL
+ ;EP0CS |= bmEPSTALL
+ mov dptr, EP0CS
+ movx a, @dptr
+ orl a, EP0STALLbit
+ movx @dptr, a
+ sjmp setup_done
+
+setup_done:
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+;;; ==============================================================
+
+set_baud: ; baud index in r3
+ ;; verify a < 10
+ mov a, r3
+ jb ACC.7, set_baud__badbaud
+ clr c
+ subb a, #10
+ jnc set_baud__badbaud
+ mov a, r3
+ rl a ; a = index*2
+ add a, #LOW(baud_table)
+ mov dpl, a
+ mov a, #HIGH(baud_table)
+ addc a, #0
+ mov dph, a
+ ;; TODO: shut down xmit/receive
+ ;; TODO: wait for current xmit char to leave
+ ;; TODO: shut down timer to avoid partial-char glitch
+ movx a,@dptr ; BAUD_HIGH
+ mov RCAP2H, a
+ mov TH2, a
+ inc dptr
+ movx a,@dptr ; BAUD_LOW
+ mov RCAP2L, a
+ mov TL2, a
+ ;; TODO: restart xmit/receive
+ ;; TODO: reenable interrupts, resume tx if pending
+ clr c ; c=0: success
+ ret
+set_baud__badbaud:
+ setb c ; c=1: failure
+ ret
+
+;;; ==================================================
+control_pins:
+ cjne r1, #0x41, control_pins_in
+control_pins_out:
+ mov a, r3 ; wValue[0] holds new bits: b7 is new DTR, b2 is new RTS
+ xrl a, #0xff ; 1 means active, 0V, +12V ?
+ anl a, #0x84
+ mov r3, a
+ mov dptr, OUTC
+ movx a, @dptr ; only change bits 7 and 2
+ anl a, #0x7b ; ~0x84
+ orl a, r3
+ movx @dptr, a ; other pins are inputs, bits ignored
+ ljmp setup_done_ack
+control_pins_in:
+ mov dptr, PINSC
+ movx a, @dptr
+ xrl a, #0xff
+ ljmp setup_return_one_byte
+
+;;; ========================================
+
+ISR_Ep2in:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ mov a,EXIF
+ clr acc.4
+ mov EXIF,a ; clear INT2 first
+ mov dptr, IN07IRQ ; clear USB int
+ mov a,#04h
+ movx @dptr,a
+
+ ;; do stuff
+ lcall start_in
+
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+ISR_Ep2out:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ mov a,EXIF
+ clr acc.4
+ mov EXIF,a ; clear INT2 first
+ mov dptr, OUT07IRQ ; clear USB int
+ mov a,#04h
+ movx @dptr,a
+
+ ;; do stuff
+
+ ;; copy data into buffer. for now, assume we will have enough space
+ mov dptr, OUT2BC ; get byte count
+ movx a,@dptr
+ mov r1, a
+ clr a
+ mov dps, a
+ mov dptr, OUT2BUF ; load DPTR0 with source
+ mov dph1, #HIGH(tx_ring) ; load DPTR1 with target
+ mov dpl1, tx_ring_in
+OUT_loop:
+ movx a,@dptr ; read
+ inc dps ; switch to DPTR1: target
+ inc dpl1 ; target = tx_ring_in+1
+ movx @dptr,a ; store
+ mov a,dpl1
+ cjne a, tx_ring_out, OUT_no_overflow
+ sjmp OUT_overflow
+OUT_no_overflow:
+ inc tx_ring_in ; tx_ring_in++
+ inc dps ; switch to DPTR0: source
+ inc dptr
+ djnz r1, OUT_loop
+ sjmp OUT_done
+OUT_overflow:
+ ;; signal overflow
+ ;; fall through
+OUT_done:
+ ;; ack
+ mov dptr,OUT2BC
+ movx @dptr,a
+
+ ;; start tx
+ acall maybe_start_tx
+ ;acall dump_stat
+
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+dump_stat:
+ ;; fill in EP4in with a debugging message:
+ ;; tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
+ ;; tx_active
+ ;; tx_ring[0..15]
+ ;; 0xfc
+ ;; rx_ring[0..15]
+ clr a
+ mov dps, a
+
+ mov dptr, IN4CS
+ movx a, @dptr
+ jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
+ mov dptr, IN4BUF
+
+ mov a, tx_ring_in
+ movx @dptr, a
+ inc dptr
+ mov a, tx_ring_out
+ movx @dptr, a
+ inc dptr
+
+ mov a, rx_ring_in
+ movx @dptr, a
+ inc dptr
+ mov a, rx_ring_out
+ movx @dptr, a
+ inc dptr
+
+ clr a
+ jnb TX_RUNNING, dump_stat__no_tx_running
+ inc a
+dump_stat__no_tx_running:
+ movx @dptr, a
+ inc dptr
+ ;; tx_ring[0..15]
+ inc dps
+ mov dptr, #tx_ring ; DPTR1: source
+ mov r1, #16
+dump_stat__tx_ring_loop:
+ movx a, @dptr
+ inc dptr
+ inc dps
+ movx @dptr, a
+ inc dptr
+ inc dps
+ djnz r1, dump_stat__tx_ring_loop
+ inc dps
+
+ mov a, #0xfc
+ movx @dptr, a
+ inc dptr
+
+ ;; rx_ring[0..15]
+ inc dps
+ mov dptr, #rx_ring ; DPTR1: source
+ mov r1, #16
+dump_stat__rx_ring_loop:
+ movx a, @dptr
+ inc dptr
+ inc dps
+ movx @dptr, a
+ inc dptr
+ inc dps
+ djnz r1, dump_stat__rx_ring_loop
+
+ ;; now send it
+ clr a
+ mov dps, a
+ mov dptr, IN4BC
+ mov a, #38
+ movx @dptr, a
+dump_stat__done:
+ ret
+
+;;; ============================================================
+
+maybe_start_tx:
+ ;; make sure the tx process is running.
+ jb TX_RUNNING, start_tx_done
+start_tx:
+ ;; is there work to be done?
+ mov a, tx_ring_in
+ cjne a,tx_ring_out, start_tx__work
+ ret ; no work
+start_tx__work:
+ ;; tx was not running. send the first character, setup the TI int
+ inc tx_ring_out ; [++tx_ring_out]
+ mov dph, #HIGH(tx_ring)
+ mov dpl, tx_ring_out
+ movx a, @dptr
+ mov sbuf, a
+ setb TX_RUNNING
+start_tx_done:
+ ;; can we unthrottle the host tx process?
+ ;; step 1: do we care?
+ mov a, #0
+ cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
+ ;; nope
+start_tx_really_done:
+ ret
+start_tx__maybe_unthrottle_tx:
+ ;; step 2: is there now room?
+ mov a, tx_ring_out
+ setb c
+ subb a, tx_ring_in
+ ;; a is now write_room. If thresh >= a, we can unthrottle
+ clr c
+ subb a, tx_unthrottle_threshold
+ jc start_tx_really_done ; nope
+ ;; yes, we can unthrottle. remove the threshold and mark a request
+ mov tx_unthrottle_threshold, #0
+ setb DO_TX_UNTHROTTLE
+ ;; prod rx, which will actually send the message when in2 becomes free
+ ljmp start_in
+
+
+serial_int:
+ push dps
+ push dpl
+ push dph
+ push dpl1
+ push dph1
+ push acc
+ jnb TI, serial_int__not_tx
+ ;; tx finished. send another character if we have one
+ clr TI ; clear int
+ clr TX_RUNNING
+ lcall start_tx
+serial_int__not_tx:
+ jnb RI, serial_int__not_rx
+ lcall get_rx_char
+ clr RI ; clear int
+serial_int__not_rx:
+ ;; return
+ pop acc
+ pop dph1
+ pop dpl1
+ pop dph
+ pop dpl
+ pop dps
+ reti
+
+get_rx_char:
+ mov dph, #HIGH(rx_ring)
+ mov dpl, rx_ring_in
+ inc dpl ; target = rx_ring_in+1
+ mov a, sbuf
+ movx @dptr, a
+ ;; check for overflow before incrementing rx_ring_in
+ mov a, dpl
+ cjne a, rx_ring_out, get_rx_char__no_overflow
+ ;; signal overflow
+ ret
+get_rx_char__no_overflow:
+ inc rx_ring_in
+ ;; kick off USB INpipe
+ acall start_in
+ ret
+
+start_in:
+ ;; check if the inpipe is already running.
+ mov dptr, IN2CS
+ movx a, @dptr
+ jb acc.1, start_in__done; int will handle it
+ jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
+ ;; see if there is any work to do. a serial interrupt might occur
+ ;; during this sequence?
+ mov a, rx_ring_in
+ cjne a, rx_ring_out, start_in__have_work
+ ret ; nope
+start_in__have_work:
+ ;; now copy as much data as possible into the pipe. 63 bytes max.
+ clr a
+ mov dps, a
+ mov dph, #HIGH(rx_ring) ; load DPTR0 with source
+ inc dps
+ mov dptr, IN2BUF ; load DPTR1 with target
+ movx @dptr, a ; in[0] signals that rest of IN is rx data
+ inc dptr
+ inc dps
+ ;; loop until we run out of data, or we have copied 64 bytes
+ mov r1, #1 ; INbuf size counter
+start_in__loop:
+ mov a, rx_ring_in
+ cjne a, rx_ring_out, start_in__still_copying
+ sjmp start_in__kick
+start_in__still_copying:
+ inc rx_ring_out
+ mov dpl, rx_ring_out
+ movx a, @dptr
+ inc dps
+ movx @dptr, a ; write into IN buffer
+ inc dptr
+ inc dps
+ inc r1
+ cjne r1, #64, start_in__loop; loop
+start_in__kick:
+ ;; either we ran out of data, or we copied 64 bytes. r1 has byte count
+ ;; kick off IN
+ mov dptr, IN2BC
+ mov a, r1
+ jz start_in__done
+ movx @dptr, a
+ ;; done
+start_in__done:
+ ;acall dump_stat
+ ret
+start_in__do_tx_unthrottle:
+ ;; special sequence: send a tx unthrottle message
+ clr DO_TX_UNTHROTTLE
+ clr a
+ mov dps, a
+ mov dptr, IN2BUF
+ mov a, #1
+ movx @dptr, a
+ inc dptr
+ mov a, #2
+ movx @dptr, a
+ mov dptr, IN2BC
+ movx @dptr, a
+ ret
+
+putchar:
+ clr TI
+ mov SBUF, a
+putchar_wait:
+ jnb TI, putchar_wait
+ clr TI
+ ret
+
+
+baud_table: ; baud_high, then baud_low
+ ;; baud[0]: 110
+ .byte BAUD_HIGH(110)
+ .byte BAUD_LOW(110)
+ ;; baud[1]: 300
+ .byte BAUD_HIGH(300)
+ .byte BAUD_LOW(300)
+ ;; baud[2]: 1200
+ .byte BAUD_HIGH(1200)
+ .byte BAUD_LOW(1200)
+ ;; baud[3]: 2400
+ .byte BAUD_HIGH(2400)
+ .byte BAUD_LOW(2400)
+ ;; baud[4]: 4800
+ .byte BAUD_HIGH(4800)
+ .byte BAUD_LOW(4800)
+ ;; baud[5]: 9600
+ .byte BAUD_HIGH(9600)
+ .byte BAUD_LOW(9600)
+ ;; baud[6]: 19200
+ .byte BAUD_HIGH(19200)
+ .byte BAUD_LOW(19200)
+ ;; baud[7]: 38400
+ .byte BAUD_HIGH(38400)
+ .byte BAUD_LOW(38400)
+ ;; baud[8]: 57600
+ .byte BAUD_HIGH(57600)
+ .byte BAUD_LOW(57600)
+ ;; baud[9]: 115200
+ .byte BAUD_HIGH(115200)
+ .byte BAUD_LOW(115200)
+
+desc_device:
+ .byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
+ .byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
+;;; The "real" device id, which must match the host driver, is that
+;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
+
+desc_config1:
+ .byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
+ .byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
+ .byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
+ .byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+
+desc_strings:
+ .word string_langids, string_mfg, string_product, string_serial
+desc_strings_end:
+
+string_langids: .byte string_langids_end-string_langids
+ .byte 3
+ .word 0
+string_langids_end:
+
+ ;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
+ ;; *that* is a pain in the ass to encode. And they are little-endian
+ ;; too. Use this perl snippet to get the bytecodes:
+ /* while (<>) {
+ @c = split(//);
+ foreach $c (@c) {
+ printf("0x%02x, 0x00, ", ord($c));
+ }
+ }
+ */
+
+string_mfg: .byte string_mfg_end-string_mfg
+ .byte 3
+; .byte "ACME usb widgets"
+ .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00
+string_mfg_end:
+
+string_product: .byte string_product_end-string_product
+ .byte 3
+; .byte "ACME USB serial widget"
+ .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00
+string_product_end:
+
+string_serial: .byte string_serial_end-string_serial
+ .byte 3
+; .byte "47"
+ .byte 0x34, 0x00, 0x37, 0x00
+string_serial_end:
+
+;;; ring buffer memory
+ ;; tx_ring_in+1 is where the next input byte will go
+ ;; [tx_ring_out] has been sent
+ ;; if tx_ring_in == tx_ring_out, theres no work to do
+ ;; there are (tx_ring_in - tx_ring_out) chars to be written
+ ;; dont let _in lap _out
+ ;; cannot inc if tx_ring_in+1 == tx_ring_out
+ ;; write [tx_ring_in+1] then tx_ring_in++
+ ;; if (tx_ring_in+1 == tx_ring_out), overflow
+ ;; else tx_ring_in++
+ ;; read/send [tx_ring_out+1], then tx_ring_out++
+
+ ;; rx_ring_in works the same way
+
+ .org 0x1000
+tx_ring:
+ .skip 0x100 ; 256 bytes
+rx_ring:
+ .skip 0x100 ; 256 bytes
+
+
+ .END
+
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 6effcc048..021754994 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -14,6 +14,16 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (03/19/2000) gkh
+ * Fixed oops that could happen when device was removed while a program
+ * was talking to the device.
+ * Removed the static urbs and now all urbs are created and destroyed
+ * dynamically.
+ * Reworked the internal interface. Now everything is based on the
+ * usb_serial_port structure instead of the larger usb_serial structure.
+ * This fixes the bug that a multiport device could not have more than
+ * one port open at one time.
+ *
* (03/17/2000) gkh
* Added config option for debugging messages.
* Added patch for keyspan pda from Brian Warner.
@@ -220,10 +230,9 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
static struct usb_driver usb_serial_driver = {
- "serial",
- usb_serial_probe,
- usb_serial_disconnect,
- { NULL, NULL }
+ name: "serial",
+ probe: usb_serial_probe,
+ disconnect: usb_serial_disconnect,
};
static int serial_refcount;
@@ -233,11 +242,50 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, };
+static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
+{
+ if (!serial) {
+ dbg("%s - serial == NULL", function);
+ return -1;
+ }
+ if (serial->magic != USB_SERIAL_MAGIC) {
+ dbg("%s - bad magic number for serial", function);
+ return -1;
+ }
+ if (!serial->type) {
+ dbg("%s - serial->type == NULL!", function);
+ return -1;
+ }
+
+ return 0;
+}
-static struct usb_serial *get_serial_by_minor (int minor)
+
+static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
{
- dbg("get_serial_by_minor %d", minor);
+ if (!port) {
+ dbg("%s - port == NULL", function);
+ return -1;
+ }
+ if (port->magic != USB_SERIAL_PORT_MAGIC) {
+ dbg("%s - bad magic number for port", function);
+ return -1;
+ }
+ if (!port->serial) {
+ dbg("%s - port->serial == NULL", function);
+ return -1;
+ }
+ if (!port->tty) {
+ dbg("%s - port->tty == NULL", function);
+ return -1;
+ }
+ return 0;
+}
+
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
return serial_table[minor];
}
@@ -267,6 +315,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
return NULL;
}
memset(serial, 0, sizeof(struct usb_serial));
+ serial->magic = USB_SERIAL_MAGIC;
serial_table[i] = serial;
*minor = i;
dbg("minor base = %d", *minor);
@@ -337,6 +386,8 @@ static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
static int serial_open (struct tty_struct *tty, struct file * filp)
{
struct usb_serial *serial;
+ struct usb_serial_port *port;
+ int portNumber;
dbg("serial_open");
@@ -346,180 +397,182 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
/* get the serial object associated with this tty pointer */
serial = get_serial_by_minor (MINOR(tty->device));
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
- }
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+ if (serial_paranoia_check (serial, "serial_open")) {
+ return -ENODEV;
}
- /* make the tty driver remember our serial object, and us it */
- tty->driver_data = serial;
- serial->tty = tty;
+ /* set up our port structure */
+ portNumber = MINOR(tty->device) - serial->minor;
+ port = &serial->port[portNumber];
+ port->number = portNumber;
+ port->serial = serial;
+ port->magic = USB_SERIAL_PORT_MAGIC;
+
+ /* make the tty driver remember our port object, and us it */
+ tty->driver_data = port;
+ port->tty = tty;
/* pass on to the driver specific version of this function if it is available */
if (serial->type->open) {
- return (serial->type->open(tty, filp));
+ return (serial->type->open(port, filp));
} else {
- return (generic_serial_open(tty, filp));
+ return (generic_open(port, filp));
}
}
static void serial_close(struct tty_struct *tty, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
dbg("serial_close");
- if (!serial) {
- dbg("serial == NULL!");
+ if (port_paranoia_check (port, "serial_close")) {
return;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_close port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_close")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not opened");
+
+ dbg("serial_close port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not opened");
return;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->close) {
- serial->type->close(tty, filp);
+ serial->type->close(port, filp);
} else {
- generic_serial_close(tty, filp);
+ generic_close(port, filp);
}
}
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- dbg("serial_write port %d, %d byte(s)", port, count);
-
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
+ dbg("serial_write");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not opened");
- return (-EINVAL);
+
+ dbg("serial_write port %d, %d byte(s)", port->number, count);
+
+ if (!port->active) {
+ dbg ("port not opened");
+ return -EINVAL;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->write) {
- return (serial->type->write(tty, from_user, buf, count));
+ return (serial->type->write(port, from_user, buf, count));
} else {
- return (generic_serial_write(tty, from_user, buf, count));
+ return (generic_write(port, from_user, buf, count));
}
}
static int serial_write_room (struct tty_struct *tty)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_write_room port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
+ dbg("serial_write_room");
+
+ if (port_paranoia_check (port, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_write")) {
+ return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
- return (-EINVAL);
+
+ dbg("serial_write_room port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -EINVAL;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->write_room) {
- return (serial->type->write_room(tty));
+ return (serial->type->write_room(port));
} else {
- return (generic_write_room(tty));
+ return (generic_write_room(port));
}
}
static int serial_chars_in_buffer (struct tty_struct *tty)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_chars_in_buffer port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
- return (-ENODEV);
+ dbg("serial_chars_in_buffer");
+
+ if (port_paranoia_check (port, "serial_chars_in_buffer")) {
+ return -ENODEV;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
- return (-ENODEV);
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_chars_in_buffer")) {
+ return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
- return (-EINVAL);
+
+ if (!port->active) {
+ dbg ("port not open");
+ return -EINVAL;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->chars_in_buffer) {
- return (serial->type->chars_in_buffer(tty));
+ return (serial->type->chars_in_buffer(port));
} else {
- return (generic_chars_in_buffer(tty));
+ return (generic_chars_in_buffer(port));
}
}
static void serial_throttle (struct tty_struct * tty)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_throttle port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
+ dbg("serial_throttle");
+
+ if (port_paranoia_check (port, "serial_throttle")) {
return;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_throttle")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_throttle port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function */
if (serial->type->throttle) {
- serial->type->throttle(tty);
- } else {
- generic_throttle(tty);
+ serial->type->throttle(port);
}
return;
@@ -528,30 +581,30 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_unthrottle port %d", port);
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
- /* do some sanity checking that we really have a device present */
- if (!serial) {
- dbg("serial == NULL!");
+ dbg("serial_unthrottle");
+
+ if (port_paranoia_check (port, "serial_unthrottle")) {
return;
}
- if (!serial->type) {
- dbg("serial->type == NULL!");
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_unthrottle")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_unthrottle port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle) {
- serial->type->unthrottle(tty);
- } else {
- generic_unthrottle(tty);
+ serial->type->unthrottle(port);
}
return;
@@ -560,70 +613,62 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
-
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
dbg("serial_ioctl");
-
- if (!serial) {
- dbg("serial == NULL!");
+
+ if (port_paranoia_check (port, "serial_ioctl")) {
return -ENODEV;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_ioctl port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_ioctl")) {
return -ENODEV;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_ioctl port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return -ENODEV;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->ioctl) {
- return (serial->type->ioctl(tty, file, cmd, arg));
+ return (serial->type->ioctl(port, file, cmd, arg));
} else {
- return (generic_ioctl (tty, file, cmd, arg));
+ return -ENOIOCTLCMD;
}
}
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
-
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
dbg("serial_set_termios");
-
- if (!serial) {
- dbg("serial == NULL!");
+
+ if (port_paranoia_check (port, "serial_set_termios")) {
return;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_set_termios port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_set_termios")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_set_termios port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function if it is available */
if (serial->type->set_termios) {
- serial->type->set_termios(tty, old);
- } else {
- generic_set_termios (tty, old);
+ serial->type->set_termios(port, old);
}
return;
@@ -632,32 +677,31 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port;
-
- if (!serial) {
- dbg("serial == NULL!");
+ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+ struct usb_serial *serial;
+
+ dbg("serial_break");
+
+ if (port_paranoia_check (port, "serial_break")) {
return;
}
- port = MINOR(tty->device) - serial->minor;
-
- dbg("serial_break port %d", port);
-
- /* do some sanity checking that we really have a device present */
- if (!serial->type) {
- dbg("serial->type == NULL!");
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "serial_break")) {
return;
}
- if (!serial->port[port].active) {
- dbg ("device not open");
+
+ dbg("serial_break port %d", port->number);
+
+ if (!port->active) {
+ dbg ("port not open");
return;
}
/* pass on to the driver specific version of this function if it is
available */
if (serial->type->break_ctl) {
- serial->type->break_ctl(tty, break_state);
+ serial->type->break_ctl(port, break_state);
}
}
@@ -666,13 +710,9 @@ static void serial_break (struct tty_struct *tty, int break_state)
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
*****************************************************************************/
-static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
-
- dbg("whiteheat_serial_open port %d", portNumber);
+ dbg("whiteheat_open port %d", port->number);
if (port->active) {
dbg ("device already open");
@@ -681,7 +721,7 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
port->active = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
/* Need to do device specific setup here (control lines, baud rate, etc.) */
@@ -691,36 +731,30 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp)
}
-static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp)
+static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
-
- dbg("whiteheat_serial_close port %d", portNumber);
+ dbg("whiteheat_close port %d", port->number);
/* Need to change the control lines here */
/* FIXME */
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
-static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios)
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = port->tty->termios->c_cflag;
- dbg("whiteheat_set_termios port %d", port);
+ dbg("whiteheat_set_termios port %d", port->number);
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("nothing to change...");
return;
}
@@ -732,12 +766,9 @@ static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_t
return;
}
-static void whiteheat_throttle (struct tty_struct * tty)
+static void whiteheat_throttle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("whiteheat_throttle port %d", port);
+ dbg("whiteheat_throttle port %d", port->number);
/* Change the control signals */
/* FIXME!!! */
@@ -746,12 +777,9 @@ static void whiteheat_throttle (struct tty_struct * tty)
}
-static void whiteheat_unthrottle (struct tty_struct * tty)
+static void whiteheat_unthrottle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("whiteheat_unthrottle port %d", port);
+ dbg("whiteheat_unthrottle port %d", port->number);
/* Change the control signals */
/* FIXME!!! */
@@ -837,13 +865,9 @@ static int whiteheat_startup (struct usb_serial *serial)
/******************************************************************************
* Handspring Visor specific driver functions
******************************************************************************/
-static int visor_serial_open (struct tty_struct *tty, struct file *filp)
+static int visor_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
-
- dbg("visor_serial_open port %d", portNumber);
+ dbg("visor_open port %d", port->number);
if (port->active) {
dbg ("device already open");
@@ -853,23 +877,22 @@ static int visor_serial_open (struct tty_struct *tty, struct file *filp)
port->active = 1;
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
return (0);
}
-static void visor_serial_close(struct tty_struct *tty, struct file * filp)
+
+static void visor_close (struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- dbg("visor_serial_close port %d", portNumber);
+ dbg("visor_close port %d", port->number);
if (!transfer_buffer) {
- err("visor_serial_close: kmalloc(%d) failed.", 0x12);
+ err("visor_close: kmalloc(%d) failed.", 0x12);
} else {
/* send a shutdown message to the device */
usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
@@ -877,33 +900,27 @@ static void visor_serial_close(struct tty_struct *tty, struct file * filp)
}
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
-static void visor_throttle (struct tty_struct * tty)
+static void visor_throttle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
- dbg("visor_throttle port %d", port);
+ dbg("visor_throttle port %d", port->number);
- usb_unlink_urb (&serial->port[port].read_urb);
+ usb_unlink_urb (port->read_urb);
return;
}
-static void visor_unthrottle (struct tty_struct * tty)
+static void visor_unthrottle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ dbg("visor_unthrottle port %d", port->number);
- dbg("visor_unthrottle port %d", port);
-
- if (usb_unlink_urb (&serial->port[port].read_urb))
+ if (usb_unlink_urb (port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
return;
@@ -988,17 +1005,15 @@ static int visor_startup (struct usb_serial *serial)
#include "ftdi_sio.h"
-static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
char buf[1]; /* Needed for the usb_control_msg I think */
- dbg("ftdi_sio_serial_open port %d", portNumber);
+ dbg("ftdi_sio_open port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg ("port already open");
return -EINVAL;
}
port->active = 1;
@@ -1069,21 +1084,19 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
}
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
return (0);
}
-static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
char buf[1];
- dbg("ftdi_sio_serial_close port %d", portNumber);
+ dbg("ftdi_sio_close port %d", port->number);
/* FIXME - might be able to do both simultaneously */
if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -1104,8 +1117,8 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
/* FIXME Should I flush the device here? - not doing it for now */
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
@@ -1116,15 +1129,13 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
B1 0
B2..7 length of message excluding byte 0
*/
-static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
const int data_offset = 1;
- dbg("ftdi_sio_serial_write port %d, %d bytes", portNumber, count);
+ dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
if (count == 0) {
dbg("write request of 0 bytes");
@@ -1133,9 +1144,9 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- unsigned char *first_byte = port->write_urb.transfer_buffer;
+ unsigned char *first_byte = port->write_urb->transfer_buffer;
- if (port->write_urb.status == -EINPROGRESS) {
+ if (port->write_urb->status == -EINPROGRESS) {
dbg ("already writing");
return 0;
}
@@ -1148,16 +1159,16 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
/* Copy in the data to send */
if (from_user) {
- copy_from_user(port->write_urb.transfer_buffer + data_offset ,
+ copy_from_user(port->write_urb->transfer_buffer + data_offset ,
buf, count - data_offset );
}
else {
- memcpy(port->write_urb.transfer_buffer + data_offset,
+ memcpy(port->write_urb->transfer_buffer + data_offset,
buf, count - data_offset );
}
/* Write the control byte at the front of the packet*/
- first_byte = port->write_urb.transfer_buffer;
+ first_byte = port->write_urb->transfer_buffer;
*first_byte = 1 | ((count-data_offset) << 2) ;
#ifdef DEBUG
@@ -1181,9 +1192,9 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
#endif
/* send the data out the bulk port */
- port->write_urb.transfer_buffer_length = count;
+ port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(&port->write_urb))
+ if (usb_submit_urb(port->write_urb))
dbg("usb_submit_urb(write bulk) failed");
dbg("write returning: %d", count - data_offset);
@@ -1197,14 +1208,24 @@ static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
static void ftdi_sio_read_bulk_callback (struct urb *urb)
{ /* ftdi_sio_serial_buld_callback */
- struct usb_serial *serial = (struct usb_serial *)urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
const int data_offset = 2;
int i;
dbg("ftdi_sio_read_bulk_callback");
+ if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+ return;
+ }
+
if (urb->status) {
dbg("nonzero read bulk status received: %d", urb->status);
return;
@@ -1227,6 +1248,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
if (urb->actual_length > data_offset) {
+ tty = port->tty;
for (i = data_offset ; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
}
@@ -1241,14 +1263,14 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
} /* ftdi_sio_serial_read_bulk_callback */
-static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios)
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
- unsigned int cflag = tty->termios->c_cflag;
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
__u16 urb_value; /* Will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
- dbg("ftdi_sio_set_termios port %d", port);
+
+ dbg("ftdi_sio_set_termios port %d", port->number);
/* FIXME - we should keep the old termios really */
/* FIXME -For this cut I don't care if the line is really changing or
@@ -1312,14 +1334,14 @@ static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_te
/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
-static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ struct usb_serial *serial = port->serial;
__u16 urb_value=0; /* Will hold the new flags */
char buf[1];
int ret, mask;
- dbg("ftdi_sio_ioctl port %d", port);
+
+ dbg("ftdi_sio_ioctl port %d", port->number);
/* Based on code from acm.c */
switch (cmd) {
@@ -1408,8 +1430,9 @@ static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned
static void keyspan_pda_rx_interrupt (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
@@ -1417,11 +1440,21 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
if (urb->status)
return;
- /* see if the message is data or a status interrupt */
+ if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ /* see if the message is data or a status interrupt */
switch (data[0]) {
case 0:
/* rest of message is rx data */
if (urb->actual_length) {
+ tty = serial->port[0].tty;
for (i = 1; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
}
@@ -1435,6 +1468,7 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
case 1: /* modemline change */
break;
case 2: /* tx unthrottle interrupt */
+ tty = serial->port[0].tty;
serial->tx_throttled = 0;
wake_up(&serial->write_wait); /* wake up writer */
wake_up(&tty->write_wait); /* them too */
@@ -1451,11 +1485,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
}
-static void keyspan_pda_rx_throttle (struct tty_struct *tty)
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
/* stop receiving characters. We just turn off the URB request, and
let chars pile up in the device. If we're doing hardware
flowcontrol, the device will signal the other end when its buffer
@@ -1463,19 +1494,16 @@ static void keyspan_pda_rx_throttle (struct tty_struct *tty)
send an XOFF, although it might make sense to foist that off
upon the device too. */
- dbg("keyspan_pda_rx_throttle port %d", port);
- usb_unlink_urb(&serial->port[port].read_urb);
+ dbg("keyspan_pda_rx_throttle port %d", port->number);
+ usb_unlink_urb(port->read_urb);
}
-static void keyspan_pda_rx_unthrottle (struct tty_struct *tty)
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
-
/* just restart the receive interrupt URB */
- dbg("keyspan_pda_rx_unthrottle port %d", port);
- if (usb_submit_urb(&serial->port[port].read_urb))
+ dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+ if (usb_submit_urb(port->read_urb))
dbg(" usb_submit_urb(read urb) failed");
return;
}
@@ -1516,9 +1544,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
}
-static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state)
+static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ struct usb_serial *serial = port->serial;
int value;
if (break_state == -1)
value = 1; /* start break */
@@ -1535,11 +1563,11 @@ static void keyspan_pda_break_ctl (struct tty_struct *tty, int break_state)
}
-static void keyspan_pda_set_termios (struct tty_struct *tty,
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
struct termios *old_termios)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
+ struct usb_serial *serial = port->serial;
+ unsigned int cflag = port->tty->termios->c_cflag;
/* cflag specifies lots of stuff: number of stop bits, parity, number
of data bits, baud. What can the device actually handle?:
@@ -1611,10 +1639,10 @@ static int keyspan_pda_set_modem_info(struct usb_serial *serial,
}
-static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file,
+static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ struct usb_serial *serial = port->serial;
int rc;
unsigned int value;
unsigned char status, mask;
@@ -1677,11 +1705,10 @@ static int keyspan_pda_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
-static int keyspan_pda_write(struct tty_struct * tty, int from_user,
+static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int port = MINOR(tty->device) - serial->minor;
+ struct usb_serial *serial = port->serial;
int request_unthrottle = 0;
int rc = 0;
DECLARE_WAITQUEUE(wait, current);
@@ -1704,7 +1731,7 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- while (serial->port[port].write_urb.status == -EINPROGRESS) {
+ while (port->write_urb->status == -EINPROGRESS) {
if (0 /* file->f_flags & O_NONBLOCK */) {
rc = -EAGAIN;
goto err;
@@ -1746,8 +1773,7 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
remove_wait_queue(&serial->write_wait, &wait);
set_current_state(TASK_RUNNING);
- count = (count > serial->port[port].bulk_out_size) ?
- serial->port[port].bulk_out_size : count;
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (count > serial->tx_room) {
unsigned char room;
/* Looks like we might overrun the Tx buffer. Ask the device
@@ -1784,17 +1810,15 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
if (count) {
/* now transfer data */
if (from_user) {
- copy_from_user(serial->port[port].write_urb.transfer_buffer,
- buf, count);
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
else {
- memcpy (serial->port[port].write_urb.transfer_buffer,
- buf, count);
+ memcpy (port->write_urb->transfer_buffer, buf, count);
}
/* send the data out the bulk port */
- serial->port[port].write_urb.transfer_buffer_length = count;
+ port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(&serial->port[port].write_urb))
+ if (usb_submit_urb(port->write_urb))
dbg(" usb_submit_urb(write bulk) failed");
}
else {
@@ -1828,11 +1852,22 @@ static int keyspan_pda_write(struct tty_struct * tty, int from_user,
static void keyspan_pda_write_bulk_callback (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+ return;
+ }
+
wake_up_interruptible(&serial->write_wait);
+ tty = port->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -1841,9 +1876,9 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
}
-static int keyspan_pda_write_room (struct tty_struct *tty)
+static int keyspan_pda_write_room (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ struct usb_serial *serial = port->serial;
/* used by n_tty.c for processing of tabs and such. Giving it our
conservative guess is probably good enough, but needs testing by
@@ -1853,9 +1888,9 @@ static int keyspan_pda_write_room (struct tty_struct *tty)
}
-static int keyspan_pda_chars_in_buffer (struct tty_struct *tty)
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
+ struct usb_serial *serial = port->serial;
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
@@ -1865,11 +1900,9 @@ static int keyspan_pda_chars_in_buffer (struct tty_struct *tty)
}
-static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp)
+static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
unsigned char room;
int rc;
@@ -1901,33 +1934,30 @@ static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp)
/* the normal serial device seems to always turn on DTR and RTS here,
so do the same */
- if (tty->termios->c_cflag & CBAUD)
+ if (port->tty->termios->c_cflag & CBAUD)
keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
else
keyspan_pda_set_modem_info(serial, 0);
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg(" usb_submit_urb(read int) failed");
return (0);
}
-static void keyspan_pda_serial_close(struct tty_struct *tty,
- struct file *filp)
+static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
/* the normal serial device seems to always shut off DTR and RTS now */
- if (tty->termios->c_cflag & HUPCL)
+ if (port->tty->termios->c_cflag & HUPCL)
keyspan_pda_set_modem_info(serial, 0);
/* shutdown our bulk reads and writes */
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
port->active = 0;
}
@@ -1971,7 +2001,7 @@ static int keyspan_pda_startup (struct usb_serial *serial)
intin = serial->port[0].interrupt_in_endpoint;
/* set up the receive interrupt urb */
- FILL_INT_URB(&serial->port[0].read_urb, serial->dev,
+ FILL_INT_URB(serial->port[0].read_urb, serial->dev,
usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
serial->port[0].interrupt_in_buffer,
intin->wMaxPacketSize,
@@ -1990,13 +2020,11 @@ static int keyspan_pda_startup (struct usb_serial *serial)
/*****************************************************************************
* generic devices specific driver functions
*****************************************************************************/
-static int generic_serial_open (struct tty_struct *tty, struct file *filp)
+static int generic_open (struct usb_serial_port *port, struct file *filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_serial_open port %d", portNumber);
+ dbg("generic_open port %d", port->number);
if (port->active) {
dbg ("device already open");
@@ -2007,7 +2035,7 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp)
/* if we have a bulk interrupt, start reading from it */
if (serial->num_bulk_in) {
/*Start reading from the device*/
- if (usb_submit_urb(&port->read_urb))
+ if (usb_submit_urb(port->read_urb))
dbg("usb_submit_urb(read bulk) failed");
}
@@ -2015,33 +2043,29 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp)
}
-static void generic_serial_close(struct tty_struct *tty, struct file * filp)
+static void generic_close (struct usb_serial_port *port, struct file * filp)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_serial_close port %d", portNumber);
+ dbg("generic_close port %d", port->number);
/* shutdown any bulk reads that might be going on */
if (serial->num_bulk_out) {
- usb_unlink_urb (&port->write_urb);
+ usb_unlink_urb (port->write_urb);
}
if (serial->num_bulk_in) {
- usb_unlink_urb (&port->read_urb);
+ usb_unlink_urb (port->read_urb);
}
port->active = 0;
}
-static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
- struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_serial_write port %d", portNumber);
+ dbg("generic_serial_write port %d", port->number);
if (count == 0) {
dbg("write request of 0 bytes");
@@ -2050,7 +2074,7 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- if (port->write_urb.status == -EINPROGRESS) {
+ if (port->write_urb->status == -EINPROGRESS) {
dbg ("already writing");
return (0);
}
@@ -2058,16 +2082,16 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (from_user) {
- copy_from_user(port->write_urb.transfer_buffer, buf, count);
+ copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
else {
- memcpy (port->write_urb.transfer_buffer, buf, count);
+ memcpy (port->write_urb->transfer_buffer, buf, count);
}
/* send the data out the bulk port */
- port->write_urb.transfer_buffer_length = count;
+ port->write_urb->transfer_buffer_length = count;
- if (usb_submit_urb(&port->write_urb))
+ if (usb_submit_urb(port->write_urb))
dbg("usb_submit_urb(write bulk) failed");
return (count);
@@ -2078,17 +2102,15 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u
}
-static int generic_write_room (struct tty_struct *tty)
+static int generic_write_room (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
int room;
- dbg("generic_write_room port %d", portNumber);
+ dbg("generic_write_room port %d", port->number);
if (serial->num_bulk_out) {
- if (port->write_urb.status == -EINPROGRESS)
+ if (port->write_urb->status == -EINPROGRESS)
room = 0;
else
room = port->bulk_out_size;
@@ -2100,16 +2122,14 @@ static int generic_write_room (struct tty_struct *tty)
}
-static int generic_chars_in_buffer (struct tty_struct *tty)
+static int generic_chars_in_buffer (struct usb_serial_port *port)
{
- struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- int portNumber = MINOR(tty->device) - serial->minor;
- struct usb_serial_port *port = &serial->port[portNumber];
+ struct usb_serial *serial = port->serial;
- dbg("generic_chars_in_buffer port %d", portNumber);
+ dbg("generic_chars_in_buffer port %d", port->number);
if (serial->num_bulk_out) {
- if (port->write_urb.status == -EINPROGRESS) {
+ if (port->write_urb->status == -EINPROGRESS) {
return (port->bulk_out_size);
}
}
@@ -2118,43 +2138,25 @@ static int generic_chars_in_buffer (struct tty_struct *tty)
}
-static void generic_throttle (struct tty_struct *tty)
-{
- /* do nothing for the generic device */
- return;
-}
-
-
-static void generic_unthrottle (struct tty_struct *tty)
-{
- /* do nothing for the generic device */
- return;
-}
-
-
-static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
- /* generic driver doesn't support any ioctls yet */
- return -ENOIOCTLCMD;
-}
-
-
-static void generic_set_termios (struct tty_struct *tty, struct termios * old)
-{
- /* generic driver doesn't really care about setting any line settings */
- return;
-}
-
-
static void generic_read_bulk_callback (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *)urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
dbg("generic_read_bulk_callback");
+ if (port_paranoia_check (port, "generic_read_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "generic_read_bulk_callback")) {
+ return;
+ }
+
if (urb->status) {
dbg("nonzero read bulk status received: %d", urb->status);
return;
@@ -2169,7 +2171,8 @@ static void generic_read_bulk_callback (struct urb *urb)
printk ("\n");
}
#endif
-
+
+ tty = port->tty;
if (urb->actual_length) {
for (i = 0; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
@@ -2187,16 +2190,27 @@ static void generic_read_bulk_callback (struct urb *urb)
static void generic_write_bulk_callback (struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *) urb->context;
- struct tty_struct *tty = serial->tty;
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
dbg("generic_write_bulk_callback");
+ if (port_paranoia_check (port, "generic_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "generic_write_bulk_callback")) {
+ return;
+ }
+
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
}
+ tty = port->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -2206,7 +2220,6 @@ static void generic_write_bulk_callback (struct urb *urb)
}
-
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
@@ -2331,6 +2344,11 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
port = &serial->port[i];
+ port->read_urb = usb_alloc_urb (0);
+ if (!port->read_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->bulk_in_buffer) {
@@ -2338,16 +2356,21 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
goto probe_error;
}
if (serial->type->read_bulk_callback) {
- FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, serial);
+ FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
} else {
- FILL_BULK_URB(&port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, serial);
+ FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
}
}
for (i = 0; i < num_bulk_out; ++i) {
port = &serial->port[i];
+ port->write_urb = usb_alloc_urb(0);
+ if (!port->write_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
if (!port->bulk_out_buffer) {
@@ -2355,25 +2378,31 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
goto probe_error;
}
if (serial->type->write_bulk_callback) {
- FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, serial);
+ FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
} else {
- FILL_BULK_URB(&port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, serial);
+ FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
+ port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
}
}
#if 0 /* use this code when WhiteHEAT is up and running */
for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ port->control_urb = usb_alloc_urb(0);
+ if (!port->control_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- serial->interrupt_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL);
- if (!serial->interrupt_in_buffer[i]) {
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
err("Couldn't allocate interrupt_in_buffer");
goto probe_error;
}
- FILL_INT_URB(&serial->control_urb[i], dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
- serial->interrupt_in_buffer[i], buffer_size, serial_control_irq,
- serial, interrupt_in_endpoint[i]->bInterval);
+ FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
+ port->interrupt_in_buffer, buffer_size, serial_control_irq,
+ port, interrupt_in_endpoint[i]->bInterval);
}
#endif
@@ -2395,15 +2424,27 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
probe_error:
if (serial) {
- for (i = 0; i < num_bulk_in; ++i)
+ for (i = 0; i < num_bulk_in; ++i) {
+ port = &serial->port[i];
+ if (port->read_urb)
+ usb_free_urb (port->read_urb);
if (serial->port[i].bulk_in_buffer[i])
kfree (serial->port[i].bulk_in_buffer);
- for (i = 0; i < num_bulk_out; ++i)
+ }
+ for (i = 0; i < num_bulk_out; ++i) {
+ port = &serial->port[i];
+ if (port->write_urb)
+ usb_free_urb (port->write_urb);
if (serial->port[i].bulk_out_buffer)
kfree (serial->port[i].bulk_out_buffer);
- for (i = 0; i < num_interrupt_in; ++i)
+ }
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ if (port->control_urb)
+ usb_free_urb (port->control_urb);
if (serial->port[i].interrupt_in_buffer)
kfree (serial->port[i].interrupt_in_buffer);
+ }
/* return the minor range that this device had */
return_serial (serial);
@@ -2422,27 +2463,33 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
int i;
if (serial) {
- /* need to stop any transfers...*/
- for (i = 0; i < serial->num_ports; ++i) {
- port = &serial->port[i];
- usb_unlink_urb (&port->write_urb);
- usb_unlink_urb (&port->read_urb);
- port->active = 0;
- }
+ for (i = 0; i < serial->num_ports; ++i)
+ serial->port[i].active = 0;
- /* free up any memory that we allocated */
for (i = 0; i < serial->num_bulk_in; ++i) {
port = &serial->port[i];
+ if (port->read_urb) {
+ usb_unlink_urb (port->read_urb);
+ usb_free_urb (port->read_urb);
+ }
if (port->bulk_in_buffer)
kfree (port->bulk_in_buffer);
}
for (i = 0; i < serial->num_bulk_out; ++i) {
port = &serial->port[i];
+ if (port->write_urb) {
+ usb_unlink_urb (port->write_urb);
+ usb_free_urb (port->write_urb);
+ }
if (port->bulk_out_buffer)
kfree (port->bulk_out_buffer);
}
for (i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
+ if (port->control_urb) {
+ usb_unlink_urb (port->control_urb);
+ usb_free_urb (port->control_urb);
+ }
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
}
@@ -2468,7 +2515,7 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
static struct tty_driver serial_tty_driver = {
magic: TTY_DRIVER_MAGIC,
driver_name: "usb",
- name: "ttyUSB",
+ name: "ttyUSB%d",
major: SERIAL_TTY_MAJOR,
minor_start: 0,
num: SERIAL_TTY_MINORS,
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 71fecb0ec..48082101a 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -52,8 +52,12 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
+#define USB_SERIAL_MAGIC 0x6702 /* magic number for usb_serial struct */
+#define USB_SERIAL_PORT_MAGIC 0x7301 /* magic number for usb_serial_port struct */
+
struct usb_serial_port {
+ int magic;
struct usb_serial *serial; /* pointer back to the owner of this port */
struct tty_struct * tty; /* the coresponding tty for this device */
unsigned char minor;
@@ -63,21 +67,21 @@ struct usb_serial_port {
struct usb_endpoint_descriptor * interrupt_in_endpoint;
__u8 interrupt_in_interval;
unsigned char * interrupt_in_buffer;
- struct urb control_urb;
+ struct urb * control_urb;
unsigned char * bulk_in_buffer;
- struct urb read_urb;
+ struct urb * read_urb;
unsigned char * bulk_out_buffer;
int bulk_out_size;
- struct urb write_urb;
+ struct urb * write_urb;
void * private; /* data private to the specific driver */
};
struct usb_serial {
+ int magic;
struct usb_device * dev;
struct usb_serial_device_type * type;
- struct tty_struct * tty; /* the coresponding tty for this device */
unsigned char minor;
unsigned char num_ports; /* the number of ports this device has */
char num_interrupt_in; /* number of interrupt in endpoints we have */
@@ -121,16 +125,16 @@ struct usb_serial_device_type {
int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
/* serial function calls */
- int (*open)(struct tty_struct * tty, struct file * filp);
- void (*close)(struct tty_struct * tty, struct file * filp);
- int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count);
- int (*write_room)(struct tty_struct *tty);
- int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct termios * old);
- void (*break_ctl)(struct tty_struct *tty, int break_state);
- int (*chars_in_buffer)(struct tty_struct *tty);
- void (*throttle)(struct tty_struct * tty);
- void (*unthrottle)(struct tty_struct * tty);
+ int (*open) (struct usb_serial_port *port, struct file * filp);
+ void (*close) (struct usb_serial_port *port, struct file * filp);
+ int (*write) (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+ int (*write_room) (struct usb_serial_port *port);
+ int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+ void (*set_termios) (struct usb_serial_port *port, struct termios * old);
+ void (*break_ctl) (struct usb_serial_port *port, int break_state);
+ int (*chars_in_buffer) (struct usb_serial_port *port);
+ void (*throttle) (struct usb_serial_port *port);
+ void (*unthrottle) (struct usb_serial_port *port);
void (*read_bulk_callback)(struct urb *urb);
void (*write_bulk_callback)(struct urb *urb);
@@ -140,15 +144,11 @@ struct usb_serial_device_type {
/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
/* need to always compile these in, as some of the other devices use these functions as their own. */
/* if a driver does not provide a function pointer, the generic function will be called. */
-static int generic_serial_open (struct tty_struct *tty, struct file *filp);
-static void generic_serial_close (struct tty_struct *tty, struct file *filp);
-static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
-static int generic_write_room (struct tty_struct *tty);
-static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
-static void generic_set_termios (struct tty_struct *tty, struct termios * old);
-static int generic_chars_in_buffer (struct tty_struct *tty);
-static void generic_throttle (struct tty_struct *tty);
-static void generic_unthrottle (struct tty_struct *tty);
+static int generic_open (struct usb_serial_port *port, struct file *filp);
+static void generic_close (struct usb_serial_port *port, struct file *filp);
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int generic_write_room (struct usb_serial_port *port);
+static int generic_chars_in_buffer (struct usb_serial_port *port);
static void generic_read_bulk_callback (struct urb *urb);
static void generic_write_bulk_callback (struct urb *urb);
@@ -172,11 +172,11 @@ static struct usb_serial_device_type generic_device = {
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
-static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp);
-static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp);
-static void whiteheat_set_termios (struct tty_struct *tty, struct termios * old);
-static void whiteheat_throttle (struct tty_struct *tty);
-static void whiteheat_unthrottle (struct tty_struct *tty);
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp);
+static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
+static void whiteheat_throttle (struct usb_serial_port *port);
+static void whiteheat_unthrottle (struct usb_serial_port *port);
static int whiteheat_startup (struct usb_serial *serial);
/* All of the device info needed for the Connect Tech WhiteHEAT */
@@ -193,6 +193,7 @@ static struct usb_serial_device_type whiteheat_fake_device = {
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
startup: whiteheat_startup
};
static struct usb_serial_device_type whiteheat_device = {
@@ -206,8 +207,8 @@ static struct usb_serial_device_type whiteheat_device = {
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
num_ports: 4,
- open: whiteheat_serial_open,
- close: whiteheat_serial_close,
+ open: whiteheat_open,
+ close: whiteheat_close,
throttle: whiteheat_throttle,
unthrottle: whiteheat_unthrottle,
set_termios: whiteheat_set_termios,
@@ -269,11 +270,11 @@ struct visor_connection_info {
/* function prototypes for a handspring visor */
-static int visor_serial_open (struct tty_struct *tty, struct file *filp);
-static void visor_serial_close (struct tty_struct *tty, struct file *filp);
-static void visor_throttle (struct tty_struct *tty);
-static void visor_unthrottle (struct tty_struct *tty);
-static int visor_startup (struct usb_serial *serial);
+static int visor_open (struct usb_serial_port *port, struct file *filp);
+static void visor_close (struct usb_serial_port *port, struct file *filp);
+static void visor_throttle (struct usb_serial_port *port);
+static void visor_unthrottle (struct usb_serial_port *port);
+static int visor_startup (struct usb_serial *serial);
/* All of the device info needed for the Handspring Visor */
static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
@@ -289,8 +290,8 @@ static struct usb_serial_device_type handspring_device = {
num_bulk_in: 2,
num_bulk_out: 2,
num_ports: 2,
- open: visor_serial_open,
- close: visor_serial_close,
+ open: visor_open,
+ close: visor_close,
throttle: visor_throttle,
unthrottle: visor_unthrottle,
startup: visor_startup,
@@ -300,12 +301,12 @@ static struct usb_serial_device_type handspring_device = {
#ifdef CONFIG_USB_SERIAL_FTDI_SIO
/* function prototypes for a FTDI serial converter */
-static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp);
-static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp);
-static int ftdi_sio_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp);
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp);
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static void ftdi_sio_read_bulk_callback (struct urb *urb);
-static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios * old);
-static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old);
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
/* All of the device info needed for the FTDI SIO serial converter */
static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
@@ -321,9 +322,10 @@ static struct usb_serial_device_type ftdi_sio_device = {
num_bulk_in: 1,
num_bulk_out: 1,
num_ports: 1,
- open: ftdi_sio_serial_open,
- close: ftdi_sio_serial_close,
- write: ftdi_sio_serial_write,
+ open: ftdi_sio_open,
+ close: ftdi_sio_close,
+ write: ftdi_sio_write,
+ ioctl: ftdi_sio_ioctl,
read_bulk_callback: ftdi_sio_read_bulk_callback,
set_termios: ftdi_sio_set_termios
};
@@ -332,28 +334,28 @@ static struct usb_serial_device_type ftdi_sio_device = {
#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA
/* function prototypes for a Keyspan PDA serial converter */
-static int keyspan_pda_serial_open (struct tty_struct *tty,
+static int keyspan_pda_open (struct usb_serial_port *port,
struct file *filp);
-static void keyspan_pda_serial_close (struct tty_struct *tty,
+static void keyspan_pda_close (struct usb_serial_port *port,
struct file *filp);
static int keyspan_pda_startup (struct usb_serial *serial);
-static void keyspan_pda_rx_throttle (struct tty_struct *tty);
-static void keyspan_pda_rx_unthrottle (struct tty_struct *tty);
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port);
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port);
static int keyspan_pda_setbaud (struct usb_serial *serial, int baud);
-static int keyspan_pda_write_room (struct tty_struct *tty);
-static int keyspan_pda_write (struct tty_struct *tty,
+static int keyspan_pda_write_room (struct usb_serial_port *port);
+static int keyspan_pda_write (struct usb_serial_port *port,
int from_user,
const unsigned char *buf,
int count);
static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int keyspan_pda_chars_in_buffer (struct tty_struct *tty);
-static int keyspan_pda_ioctl (struct tty_struct *tty,
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
+static int keyspan_pda_ioctl (struct usb_serial_port *port,
struct file *file,
unsigned int cmd,
unsigned long arg);
-static void keyspan_pda_set_termios (struct tty_struct *tty,
+static void keyspan_pda_set_termios (struct usb_serial_port *port,
struct termios *old);
-static void keyspan_pda_break_ctl (struct tty_struct *tty,
+static void keyspan_pda_break_ctl (struct usb_serial_port *port,
int break_state);
static int keyspan_pda_fake_startup (struct usb_serial *serial);
@@ -385,8 +387,8 @@ static struct usb_serial_device_type keyspan_pda_device = {
num_bulk_in: 0,
num_bulk_out: 1,
num_ports: 1,
- open: keyspan_pda_serial_open,
- close: keyspan_pda_serial_close,
+ open: keyspan_pda_open,
+ close: keyspan_pda_close,
write: keyspan_pda_write,
write_room: keyspan_pda_write_room,
write_bulk_callback: keyspan_pda_write_bulk_callback,
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index f5e67acec..9927b5382 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -1315,8 +1315,8 @@ static __u8 root_hub_dev_des[] =
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1617,7 +1617,13 @@ static int rh_submit_urb(urb_t *urb)
memcpy (data, root_hub_config_des, len);
OK(len);
case 0x03: /* string descriptors */
- stat = -EPIPE;
+ len = usb_root_hub_string (wValue & 0xff,
+ uhci->io_addr, "UHCI",
+ data, wLength);
+ if (len > 0) {
+ OK (min (leni, len));
+ } else
+ stat = -EPIPE;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
@@ -1985,6 +1991,15 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign
{
int retval;
struct uhci *uhci;
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+ io_addr, bufp);
uhci = alloc_uhci(io_addr, io_size);
if (!uhci)
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 78ae0a0ea..b134107da 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -262,8 +262,14 @@ static int sohci_submit_urb (urb_t * urb)
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
+ /* a request to the virtual root hub */
if (usb_pipedevice (pipe) == ohci->rh.devnum)
- return rh_submit_urb (urb); /* a request to the virtual root hub */
+ return rh_submit_urb (urb);
+
+ /* when controller's hung, permit only hub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled)
+ return -ESHUTDOWN;
/* every endpoint has a ed, locate and fill it */
if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
@@ -333,10 +339,11 @@ static int sohci_submit_urb (urb_t * urb)
(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
}
- td_submit_urb (urb); /* fill the TDs and link it to the ed */
-
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
ep_link (ohci, ed);
+
+ td_submit_urb (urb); /* fill the TDs and link it to the ed */
+
spin_unlock_irqrestore (&usb_ed_lock, flags);
urb->status = USB_ST_URB_PENDING;
@@ -1122,8 +1129,8 @@ static __u8 root_hub_dev_des[] =
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1222,13 +1229,16 @@ static void rh_int_timer_do (unsigned long ptr)
urb_t * urb = (urb_t *) ptr;
ohci_t * ohci = urb->dev->bus->hcpriv;
+
+ if (ohci->disabled)
+ return;
if(ohci->rh.send) {
len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
if (len > 0) {
urb->actual_length = len;
#ifdef DEBUG
- urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+ urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
#endif
if (urb->complete) urb->complete (urb);
}
@@ -1379,27 +1389,49 @@ static int rh_submit_urb (urb_t * urb)
len = min (leni, min (sizeof (root_hub_config_des), wLength));
data_buf = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
+ len = usb_root_hub_string (wValue & 0xff,
+ (int) ohci->regs, "OHCI",
+ data, wLength);
+ if (len > 0) {
+ data_buf = data;
+ OK (min (leni, len));
+ }
+ // else fallthrough
default:
status = TD_CC_STALL;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
- *(__u8 *) (data_buf+1) = 0x29;
- put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)),
- (__u32 *) (data_buf + 2));
- *(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */
-
- len = min (leni, min(*(__u8 *) data_buf, wLength));
- *(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */
- if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */
- *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff;
- *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16;
- } else {
- put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)),
- (__u32 *) (data_buf + 7));
+ {
+ __u32 temp = readl (&ohci->regs->roothub.a);
+
+ data_buf [0] = 9; // min length;
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = readl (&ohci->regs->roothub.b);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min (leni, min (data_buf [0], wLength));
+ OK (len);
}
- OK (len);
case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
@@ -1413,7 +1445,8 @@ static int rh_submit_urb (urb_t * urb)
dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
len = min(len, leni);
- memcpy (data, data_buf, len);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
urb->actual_length = len;
urb->status = cc_to_error [status];
@@ -1472,6 +1505,7 @@ static void hc_reset (ohci_t * ohci)
}
udelay (1);
}
+ ohci->disabled = 0;
}
/*-------------------------------------------------------------------------*/
@@ -1502,7 +1536,7 @@ static int hc_start (ohci_t * ohci)
writel (0x628, &ohci->regs->lsthresh);
/* Choose the interrupts we care about now, others later on demand */
- mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
writel (mask, &ohci->regs->intrenable);
@@ -1550,6 +1584,11 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller disabled");
+ }
+
if (ints & OHCI_INTR_WDH) {
writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci));
@@ -1650,16 +1689,24 @@ static void hc_release_ohci (ohci_t * ohci)
static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
{
ohci_t * ohci;
- dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
+ (unsigned long) mem_base, bufp);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
return -ENOMEM;
}
-
+
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-
+
hc_reset (ohci);
writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index 6098f0b39..e854e0c1d 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -212,31 +212,53 @@ struct ohci_regs {
} roothub;
} __attribute((aligned(32)));
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
/*
- * cmdstatus register */
-#define OHCI_CLF 0x02
-#define OHCI_BLF 0x04
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
/*
- * Interrupt register masks
+ * HcCommandStatus (cmdstatus) register masks
*/
-#define OHCI_INTR_SO (1)
-#define OHCI_INTR_WDH (1 << 1)
-#define OHCI_INTR_SF (1 << 2)
-#define OHCI_INTR_RD (1 << 3)
-#define OHCI_INTR_UE (1 << 4)
-#define OHCI_INTR_FNO (1 << 5)
-#define OHCI_INTR_RHSC (1 << 6)
-#define OHCI_INTR_OC (1 << 30)
-#define OHCI_INTR_MIE (1 << 31)
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
/*
- * Control register masks
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
*/
-#define OHCI_USB_RESET 0
-#define OHCI_USB_RESUME (1 << 6)
-#define OHCI_USB_OPER (2 << 6)
-#define OHCI_USB_SUSPEND (3 << 6)
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
/* Virtual Root HUB */
@@ -248,6 +270,9 @@ struct virt_root_hub {
int interval;
struct timer_list rh_int_timer;
};
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
/* destination of request */
#define RH_INTERFACE 0x01
@@ -261,8 +286,8 @@ struct virt_root_hub {
#define RH_GET_STATUS 0x0080
#define RH_CLEAR_FEATURE 0x0100
#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
#define RH_SET_DESCRIPTOR 0x0700
#define RH_GET_CONFIGURATION 0x0880
#define RH_SET_CONFIGURATION 0x0900
@@ -282,6 +307,7 @@ struct virt_root_hub {
#define RH_PORT_RESET 0x04
#define RH_PORT_POWER 0x08
#define RH_PORT_LOW_SPEED 0x09
+
#define RH_C_PORT_CONNECTION 0x10
#define RH_C_PORT_ENABLE 0x11
#define RH_C_PORT_SUSPEND 0x12
@@ -298,29 +324,44 @@ struct virt_root_hub {
#define RH_ACK 0x01
#define RH_REQ_ERR -1
#define RH_NACK 0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
-/* Root-Hub Register info */
-
-#define RH_PS_CCS 0x00000001
-#define RH_PS_PES 0x00000002
-#define RH_PS_PSS 0x00000004
-#define RH_PS_POCI 0x00000008
-#define RH_PS_PRS 0x00000010
-#define RH_PS_PPS 0x00000100
-#define RH_PS_LSDA 0x00000200
-#define RH_PS_CSC 0x00010000
-#define RH_PS_PESC 0x00020000
-#define RH_PS_PSSC 0x00040000
-#define RH_PS_OCIC 0x00080000
-#define RH_PS_PRSC 0x00100000
-
-/* Root hub status bits */
-#define RH_HS_LPS 0x00000001
-#define RH_HS_OCI 0x00000002
-#define RH_HS_DRWE 0x00008000
-#define RH_HS_LPSC 0x00010000
-#define RH_HS_OCIC 0x00020000
-#define RH_HS_CRWE 0x80000000
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
#define min(a,b) (((a)<(b))?(a):(b))
@@ -347,23 +388,25 @@ typedef struct
typedef struct ohci {
- struct ohci_hcca hcca; /* hcca */
+ struct ohci_hcca hcca; /* hcca */
int irq;
- struct ohci_regs * regs; /* OHCI controller's memory */
- struct list_head ohci_hcd_list; /* list of all ohci_hcd */
+ int disabled; /* e.g. got a UE, we're hung */
+
+ struct ohci_regs * regs; /* OHCI controller's memory */
+ struct list_head ohci_hcd_list; /* list of all ohci_hcd */
struct ohci * next; // chain of uhci device contexts
struct list_head urb_list; // list of all pending urbs
spinlock_t urb_list_lock; // lock to keep consistency
- int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load ballancing)*/
+ int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/
ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */
ed_t * ed_bulktail; /* last endpoint of bulk list */
ed_t * ed_controltail; /* last endpoint of control list */
ed_t * ed_isotail; /* last endpoint of iso list */
int intrstatus;
- __u32 hc_control; /* copy of the hc control reg */
+ __u32 hc_control; /* copy of the hc control reg */
struct usb_bus * bus;
struct usb_device * dev[128];
struct virt_root_hub rh;
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index 0cac2ef13..d1b77c8f5 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -3,20 +3,19 @@
* (c) 1999 Michael Gee (michael@linuxspecific.com)
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
- * Further reference:
- * This driver is based on the 'USB Mass Storage Class' document. This
- * describes in detail the protocol used to communicate with such
- * devices. Clearly, the designers had SCSI and ATAPI commands in mind
- * when they created this document. The commands are all very similar
- * to commands in the SCSI-II and ATAPI specifications.
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
*
- * It is important to note that in a number of cases this class exhibits
- * class-specific exemptions from the USB specification. Notably the
- * usage of NAK, STALL and ACK differs from the norm, in that they are
- * used to communicate wait, failed and OK on commands.
- * Also, for certain devices, the interrupt endpoint is used to convey
- * status of a command.
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
*
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
*/
#include <linux/module.h>
@@ -40,7 +39,6 @@
#include "usb-storage.h"
#include "usb-storage-debug.h"
-
/*
* This is the size of the structure Scsi_Host_Template. We create
* an instance of this structure in this file and this is a check
@@ -75,34 +73,47 @@ typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
typedef int (*trans_reset)(struct us_data*);
typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
+/* we allocate one of these for every device that we remember */
struct us_data {
struct us_data *next; /* next device */
struct usb_device *pusb_dev; /* this usb_device */
unsigned int flags; /* from filter initially */
+
+ /* information about the device -- only good if device is attached */
__u8 ifnum; /* interface number */
__u8 ep_in; /* in endpoint */
__u8 ep_out; /* out ....... */
__u8 ep_int; /* interrupt . */
- __u8 subclass; /* as in overview */
- __u8 protocol; /* .............. */
- trans_cmnd transport; /* protocol specific do cmd */
- trans_reset transport_reset; /* .......... device reset */
+ __u8 subclass;
+ __u8 protocol;
+
+ /* function pointers for this device */
+ trans_cmnd transport; /* transport function */
+ trans_reset transport_reset; /* transport device reset */
proto_cmnd proto_handler; /* protocol handler */
+
+ /* SCSI interfaces */
GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */
Scsi_Host_Template htmplt; /* own host template */
int host_number; /* to find us */
int host_no; /* allocated by scsi */
Scsi_Cmnd *srb; /* current srb */
+
+ /* thread information */
Scsi_Cmnd *queue_srb; /* the single queue slot */
int action; /* what to do */
+ int pid; /* control thread */
+
+ /* interrupt info for CBI devices */
struct semaphore ip_waitq; /* for CBI interrupts */
__u16 ip_data; /* interrupt data */
int ip_wanted; /* needed */
- int pid; /* control thread */
- struct semaphore *notify; /* wait for thread to begin */
void *irq_handle; /* for USB int requests */
unsigned int irqpipe; /* pipe for release_irq */
+
+ /* mutual exclusion structures */
+ struct semaphore notify; /* wait for thread to begin */
struct semaphore sleeper; /* to sleep on */
struct semaphore queue_exclusion; /* to protect data structs */
};
@@ -116,6 +127,7 @@ struct us_data {
#define US_ACT_DEVICE_RESET 3
#define US_ACT_BUS_RESET 4
#define US_ACT_HOST_RESET 5
+#define US_ACT_EXIT 6
/* The list of structures and the protective lock for them */
static struct us_data *us_list;
@@ -254,11 +266,6 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
case MODE_SENSE:
return srb->cmnd[4];
- /* FIXME: this needs to come out when the other
- * fix is in place */
- case READ_CAPACITY:
- return 8;
-
/* FIXME: these should be removed and tested */
case LOG_SENSE:
case MODE_SENSE_10:
@@ -791,9 +798,8 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
us->ifnum, srb->cmnd, srb->cmd_len, HZ*5);
/* check the return code for the command */
+ US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
if (result < 0) {
- US_DEBUGP("Call to usb_control_msg() returned %d\n", result);
-
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
@@ -820,15 +826,10 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* STATUS STAGE */
- /* go to sleep until we get this interrup */
- /* FIXME: this should be changed to use a timeout -- or let the
- * device reset routine up() this for us to unjam us
- */
+ /* go to sleep until we get this interrupt */
down(&(us->ip_waitq));
- /* FIXME: currently this code is unreachable, but the idea is
- * necessary. See above comment.
- */
+ /* if we were woken up by a reset instead of the actual interrupt */
if (us->ip_wanted) {
US_DEBUGP("Did not get interrupt on CBI\n");
us->ip_wanted = 0;
@@ -837,8 +838,9 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
- /* UFI gives us ASC and ASCQ, like a request sense */
- /* REQUEST_SENSE and INQUIRY don't affect the sense data, so we
+ /* UFI gives us ASC and ASCQ, like a request sense
+ *
+ * REQUEST_SENSE and INQUIRY don't affect the sense data, so we
* ignore the information for those commands
*/
if (us->subclass == US_SC_UFI) {
@@ -1114,29 +1116,27 @@ static int us_detect(struct SHT *sht)
static int us_release(struct Scsi_Host *psh)
{
struct us_data *us = (struct us_data *)psh->hostdata[0];
- struct us_data *prev;
unsigned long flags;
+ int result;
+ /* lock the data structures */
+ spin_lock_irqsave(&us_list_spinlock, flags);
+
+ US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
+
+ /* release the interrupt handler, if necessary */
if (us->irq_handle) {
- usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
+ US_DEBUGP("-- releasing irq\n");
+ result = usb_release_irq(us->pusb_dev, us->irq_handle,
+ us->irqpipe);
+ US_DEBUGP("-- usb_release_irq() returned %d\n", result);
us->irq_handle = NULL;
}
- /* FIXME: release the interface claim here? */
-
- /* FIXME: we need to move this elsewhere --
- * the remove function only gets called to remove the module
- */
- spin_lock_irqsave(&us_list_spinlock, flags);
- if (us_list == us)
- us_list = us->next;
- else {
- prev = us_list;
- while (prev->next != us)
- prev = prev->next;
- prev->next = us->next;
- }
+ /* lock the data structures */
spin_unlock_irqrestore(&us_list_spinlock, flags);
+
+ /* we always have a successful release */
return 0;
}
@@ -1153,7 +1153,7 @@ static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
{
struct us_data *us = (struct us_data *)srb->host->hostdata[0];
- US_DEBUGP("Command wakeup\n");
+ US_DEBUGP("us_queuecommand() called\n");
srb->host_scribble = (unsigned char *)us;
/* get exclusive access to the structures we want */
@@ -1180,9 +1180,11 @@ static int us_abort( Scsi_Cmnd *srb )
/* FIXME: this doesn't do anything right now */
static int us_bus_reset( Scsi_Cmnd *srb )
{
- // struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
US_DEBUGP("Bus reset requested\n");
+ if (us->ip_wanted)
+ up(&(us->ip_waitq));
// us->transport_reset(us);
return SUCCESS;
}
@@ -1364,12 +1366,9 @@ static int usb_stor_control_thread(void * __us)
unlock_kernel();
- up(us->notify);
+ up(&(us->notify));
for(;;) {
- siginfo_t info;
- int unsigned long signr;
-
US_DEBUGP("*** thread sleeping.\n");
down(&(us->sleeper));
down(&(us->queue_exclusion));
@@ -1378,7 +1377,7 @@ static int usb_stor_control_thread(void * __us)
/* take the command off the queue */
action = us->action;
us->action = 0;
- us->srb = us-> queue_srb;
+ us->srb = us->queue_srb;
/* release the queue lock as fast as possible */
up(&(us->queue_exclusion));
@@ -1433,7 +1432,8 @@ static int usb_stor_control_thread(void * __us)
us->proto_handler(us->srb, us);
}
- US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result);
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
+ us->srb->result);
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
@@ -1452,19 +1452,12 @@ static int usb_stor_control_thread(void * __us)
} /* end switch on action */
- /* FIXME: we ignore TERM and KILL... is this right? */
- if (signal_pending(current)) {
- /* sending SIGUSR1 makes us print out some info */
- spin_lock_irq(&current->sigmask_lock);
- signr = dequeue_signal(&current->blocked, &info);
- spin_unlock_irq(&current->sigmask_lock);
- } /* if (singal_pending(current)) */
+ /* exit if we get a signal to exit */
+ if (action == US_ACT_EXIT)
+ break;
} /* for (;;) */
- // MOD_DEC_USE_COUNT;
-
printk("usb_stor_control_thread exiting\n");
-
return 0;
}
@@ -1495,14 +1488,12 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* FIXME: this isn't quite right... */
/* We make an exception for the shuttle E-USB */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- protocol = US_PR_CB;
- subclass = US_SC_8070; /* an assumption */
- } else if (dev->descriptor.bDeviceClass != 0 ||
- altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
- altsetting->bInterfaceSubClass < US_SC_MIN ||
- altsetting->bInterfaceSubClass > US_SC_MAX) {
+ if (!(dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) &&
+ !(dev->descriptor.bDeviceClass == 0 &&
+ altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ altsetting->bInterfaceSubClass >= US_SC_MIN &&
+ altsetting->bInterfaceSubClass <= US_SC_MAX)) {
/* if it's not a mass storage, we go no further */
return NULL;
}
@@ -1510,7 +1501,43 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
+ /* Determine subclass and protocol, or copy from the interface */
+ /* FIXME: this isn't quite right */
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ protocol = US_PR_CB;
+ subclass = US_SC_8070; /* an assumption */
+ } else {
+ subclass = altsetting->bInterfaceSubClass;
+ protocol = altsetting->bInterfaceProtocol;
+ }
+
+ /* shuttle E-USB */
+ /* FIXME: all we should need to do here is determine the protocol */
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ __u8 qstat[2];
+
+ result = usb_control_msg(ss->pusb_dev,
+ usb_rcvctrlpipe(dev,0),
+ 1, 0xC0,
+ 0, ss->ifnum,
+ qstat, 2, HZ*5);
+ US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
+ CBI_irq, 255, (void *)ss,
+ &ss->irq_handle);
+ if (result < 0)
+ return NULL;
+
+ /* FIXME: what is this?? */
+ down(&(ss->ip_waitq));
+ }
+
/*
+ * Find the endpoints we need
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
@@ -1519,6 +1546,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* is it an BULK endpoint? */
if ((altsetting->endpoint[i].bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ /* BULK in or out? */
if (altsetting->endpoint[i].bEndpointAddress &
USB_DIR_IN)
ep_in = altsetting->endpoint[i].bEndpointAddress &
@@ -1542,36 +1570,14 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
US_DEBUGP("Result from usb_set_interface is %d\n", result);
if (result == -EPIPE) {
+ US_DEBUGP("-- clearing stall on control interface\n");
usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
+ US_DEBUGP("-- unknown error. rejecting device\n");
return NULL;
}
- /* shuttle E-USB */
- /* FIXME: all we should need to do here is determine the protocol */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- __u8 qstat[2];
-
- result = usb_control_msg(ss->pusb_dev,
- usb_rcvctrlpipe(dev,0),
- 1, 0xC0,
- 0, ss->ifnum,
- qstat, 2, HZ*5);
- US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
- init_MUTEX_LOCKED(&(ss->ip_waitq));
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255, (void *)ss,
- &ss->irq_handle);
- if (result < 0)
- return NULL;
-
- /* FIXME: what is this?? */
- down(&(ss->ip_waitq));
- }
-
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Problems with device\n");
@@ -1638,8 +1644,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("Allocating IRQ for CBI transport\n");
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255,
- (void *)ss, &ss->irq_handle);
+ CBI_irq, 255, (void *)ss,
+ &(ss->irq_handle));
US_DEBUGP("usb_request_irq returned %d\n", result);
}
} else {
@@ -1656,23 +1662,12 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Initialize the mutexes only when the struct is new */
init_MUTEX_LOCKED(&(ss->sleeper));
+ init_MUTEX_LOCKED(&(ss->notify));
init_MUTEX(&(ss->queue_exclusion));
- /*
- * If we've allready determined the subclass and protocol,
- * use that. Otherwise, use the interface ones. This
- * allows us to support devices which are compliant but
- * don't announce it. Note that this information is
- * maintained in the us_data struct so we only have to do
- * this for new devices.
- */
- if (subclass) {
- ss->subclass = subclass;
- ss->protocol = protocol;
- } else {
- ss->subclass = altsetting->bInterfaceSubClass;
- ss->protocol = altsetting->bInterfaceProtocol;
- }
+ /* copy over the subclass and protocol data */
+ ss->subclass = subclass;
+ ss->protocol = protocol;
/* copy over the endpoint data */
ss->ep_in = ep_in;
@@ -1762,9 +1757,9 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
US_DEBUGP("Allocating IRQ for CBI transport\n");
ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255,
- (void *)ss, &ss->irq_handle);
- US_DEBUGP("usb_request_irq returned %d", result);
+ CBI_irq, 255, (void *)ss,
+ &(ss->irq_handle));
+ US_DEBUGP("usb_request_irq returned %d\n", result);
}
/*
@@ -1786,23 +1781,18 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
(struct us_data *)ss->htmplt.proc_dir = ss;
/* start up our thread */
- {
- DECLARE_MUTEX_LOCKED(sem);
-
- ss->notify = &sem;
- ss->pid = kernel_thread(usb_stor_control_thread, ss,
- CLONE_FS | CLONE_FILES |
- CLONE_SIGHAND);
- if (ss->pid < 0) {
- printk(KERN_WARNING USB_STORAGE
- "Unable to start control thread\n");
- kfree(ss);
- return NULL;
- }
-
- /* wait for it to start */
- down(&sem);
+ ss->pid = kernel_thread(usb_stor_control_thread, ss,
+ CLONE_FS | CLONE_FILES |
+ CLONE_SIGHAND);
+ if (ss->pid < 0) {
+ printk(KERN_WARNING USB_STORAGE
+ "Unable to start control thread\n");
+ kfree(ss);
+ return NULL;
}
+
+ /* wait for it to start */
+ down(&(ss->notify));
/* now register - our detect function will be called */
ss->htmplt.module = &__this_module;
@@ -1829,18 +1819,26 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
static void storage_disconnect(struct usb_device *dev, void *ptr)
{
struct us_data *ss = ptr;
+ int result;
- if (!ss)
+ US_DEBUGP("storage_disconnect() called\n");
+
+ /* this is the odd case -- we disconnected but weren't using it */
+ if (!ss) {
+ US_DEBUGP("-- device was not in use\n");
return;
-
- /* FIXME: we need mututal exclusion and resource freeing here */
+ }
/* release the IRQ, if we have one */
if (ss->irq_handle) {
- usb_release_irq(ss->pusb_dev, ss->irq_handle, ss->irqpipe);
+ US_DEBUGP("-- releasing irq handle\n");
+ result = usb_release_irq(ss->pusb_dev, ss->irq_handle,
+ ss->irqpipe);
+ US_DEBUGP("-- usb_release_irq() returned %d\n", result);
ss->irq_handle = NULL;
}
+ /* mark the device as gone */
ss->pusb_dev = NULL;
}
@@ -1851,11 +1849,16 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
int __init usb_stor_init(void)
{
+ /*
+ * Check to see if the host template is a different size from
+ * what we're expected -- people have updated this in the past
+ * and forgotten about this driver.
+ */
if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) {
- printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ;
- printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n",
+ printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE bad\n");
+ printk(KERN_ERR
+ "usb-storage: expected %d bytes, got %d bytes\n",
SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ;
-
return -1 ;
}
@@ -1863,6 +1866,7 @@ int __init usb_stor_init(void)
if (usb_register(&storage_driver) < 0)
return -1;
+ /* we're all set */
printk(KERN_INFO "USB Mass Storage support registered.\n");
return 0;
}
@@ -1870,17 +1874,35 @@ int __init usb_stor_init(void)
void __exit usb_stor_exit(void)
{
static struct us_data *ptr;
-
+ static struct us_data *next;
+ unsigned long flags;
+
+ /*
+ * deregister the driver -- this eliminates races with probes and
+ * disconnects
+ */
+ usb_deregister(&storage_driver) ;
+
+ /* lock access to the data structures */
+ spin_lock_irqsave(&us_list_spinlock, flags);
+
/* unregister all the virtual hosts */
for (ptr = us_list; ptr != NULL; ptr = ptr->next)
- scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
-
- /* free up the data structures */
-
+ scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
+
/* kill the threads */
+ /* FIXME: we can do this by sending them a signal to die */
- /* deregister the driver */
- usb_deregister(&storage_driver) ;
+ /* free up the data structures */
+ /* FIXME: we need to eliminate the host structure also */
+ while (ptr) {
+ next = ptr->next;
+ kfree(ptr);
+ ptr = next;
+ }
+
+ /* unlock the data structures */
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
}
module_init(usb_stor_init) ;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 5dbde2959..f77296d7f 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -1002,8 +1002,11 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
urb_priv = urb->hcpriv;
switch (usb_pipetype (urb->pipe)) {
- case PIPE_ISOCHRONOUS:
+
case PIPE_INTERRUPT:
+ usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+ case PIPE_ISOCHRONOUS:
uhci_clean_iso_step1(s, urb_priv);
uhci_wait_ms(1);
uhci_clean_iso_step2(s, urb_priv);
@@ -1131,8 +1134,10 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
urb_priv = (urb_priv_t*)urb->hcpriv;
switch (usb_pipetype (urb->pipe)) {
- case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
+ usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+ case PIPE_ISOCHRONOUS:
uhci_clean_iso_step1 (s, urb_priv);
break;
@@ -1617,8 +1622,8 @@ _static __u8 root_hub_dev_des[] =
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1915,8 +1920,14 @@ _static int rh_submit_urb (urb_t *urb)
len = min (leni, min (sizeof (root_hub_config_des), wLength));
memcpy (data, root_hub_config_des, len);
OK (len);
- case (0x03): /*string descriptors */
- stat = -EPIPE;
+ case (0x03): /* string descriptors */
+ len = usb_root_hub_string (wValue & 0xff,
+ uhci->io_addr, "UHCI",
+ data, wLength);
+ if (len > 0) {
+ OK (min (leni, len));
+ } else
+ stat = -EPIPE;
}
break;
@@ -2597,6 +2608,15 @@ _static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_add
uhci_t *s;
struct usb_bus *bus;
struct pm_dev *pmdev;
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+ io_addr, bufp);
s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
if (!s)
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index df8fe9b38..9b2d38b6f 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1184,6 +1184,54 @@ void usb_init_root_hub(struct usb_device *dev)
dev->actconfig = NULL;
}
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+ int retval;
+
+ for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+ *utf++ = *ascii++ & 0x7f;
+ *utf++ = 0;
+ }
+ return retval;
+}
+
+/*
+ * root_hub_string is used by each host controller's root hub code,
+ * so that they're identified consistently throughout the system.
+ */
+int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+ char buf [20];
+
+ // assert (len > (2 * (sizeof (buf) + 1)));
+ // assert (strlen (type) ~== 4);
+
+ // language ids
+ if (id == 0) {
+ *data++ = 4; *data++ = 3; /* 4 bytes data */
+ *data++ = 0; *data++ = 0; /* some language id */
+ return 4;
+
+ // serial number
+ } else if (id == 1) {
+ sprintf (buf, "%x", serial);
+
+ // product description
+ } else if (id == 2) {
+ sprintf (buf, "USB %s Root Hub", type);
+
+ // id 3 == vendor description
+
+ // unsupported IDs --> "stall"
+ } else
+ return 0;
+
+ data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+ data [1] = 3;
+ return data [0];
+}
+
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs.
@@ -1824,6 +1872,7 @@ EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_init_root_hub);
+EXPORT_SYMBOL(usb_root_hub_string);
EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
diff --git a/drivers/usb/wacom.c b/drivers/usb/wacom.c
index 6dc9ab480..cb77f0717 100644
--- a/drivers/usb/wacom.c
+++ b/drivers/usb/wacom.c
@@ -1,5 +1,5 @@
/*
- * wacom.c Version 0.4
+ * wacom.c Version 0.5
*
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
@@ -14,8 +14,10 @@
* v0.1 (vp) - Initial release
* v0.2 (aba) - Support for all buttons / combinations
* v0.3 (vp) - Support for Intuos added
- * v0.4 (sm) - Support for more Intuos models, menustrip,
- * relative mode, proximity.
+ * v0.4 (sm) - Support for more Intuos models, menustrip
+ * relative mode, proximity.
+ * v0.5 (vp) - Big cleanup, nifty features removed,
+ * they belong in userspace
*/
/*
@@ -50,16 +52,14 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
/*
* Wacom Graphire packet:
*
- * The input report:
- *
* byte 0: report ID (2)
- * byte 1: bit7 mouse/pen/rubber near
- * bit5-6 0 - pen, 1 - rubber, 2 - mouse
- * bit4 1 ?
- * bit3 0 ?
- * bit2 mouse middle button / pen button2
- * bit1 mouse right button / pen button1
- * bit0 mouse left button / pen tip / rubber
+ * byte 1: bit7 pointer in range
+ * bit5-6 pointer type 0 - pen, 1 - rubber, 2 - mouse
+ * bit4 1 ?
+ * bit3 0 ?
+ * bit2 mouse middle button / pen button2
+ * bit1 mouse right button / pen button1
+ * bit0 mouse left button / touch
* byte 2: X low bits
* byte 3: X high bits
* byte 4: Y low bits
@@ -69,115 +69,58 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
*
* There are also two single-byte feature reports (2 and 3).
*
- * Resolution:
- * X: 0 - 10206
- * Y: 0 - 7422
- *
- * (0,0) is upper left corner
- *
- * Wacom Intuos Status packet:
+ * Wacom Intuos status packet:
*
- * byte 0: report ID (2)
- * byte 1: bit7 1 (Sync Byte)
- * bit6 Pointer Near
- * bit5 0 - first proximity report
- * bit4 0 ?
- * bit3 0 ?
- * bit2 pen button2
- * bit1 pen button1
- * bit0 0 ?
- * byte 2: X high bits
- * byte 3: X low bits
- * byte 4: Y high bits
- * byte 5: Y low bits
- * byte 6: bits 0-7: pressure (bits 2-9)
- * byte 7: bits 6-7: pressure (bits 0-1)
- * byte 7: bits 0-5: X tilt (bits 1-6)
- * byte 8: bit 7: X tilt (bit 0)
- * byte 8: bits 0-6: Y tilt (bits 0-6)
- * byte 9: bits 4-7: Proximity
+ * byte 0: report ID (2)
+ * byte 1: bit7 1 - sync bit
+ * bit6 pointer in range
+ * bit5 pointer type report
+ * bit4 0 ?
+ * bit3 0 ?
+ * bit2 pen button2
+ * bit1 pen button1
+ * bit0 0 ?
+ * byte 2: X high bits
+ * byte 3: X low bits
+ * byte 4: Y high bits
+ * byte 5: Y low bits
+ * byte 6: bits 0-7: pressure (bits 2-9)
+ * byte 7: bits 6-7: pressure (bits 0-1)
+ * byte 7: bits 0-5: X tilt (bits 1-6)
+ * byte 8: bit 7: X tilt (bit 0)
+ * byte 8: bits 0-6: Y tilt (bits 0-6)
+ * byte 9: bits 4-7: distance
*/
-#define USB_VENDOR_ID_WACOM 0x056a
-#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS45 0x0020 /* Guess */
-#define USB_DEVICE_ID_WACOM_INTUOS68 0x0021
-#define USB_DEVICE_ID_WACOM_INTUOS912 0x0022 /* Guess */
-#define USB_DEVICE_ID_WACOM_INTUOS1212 0x0023
-#define USB_DEVICE_ID_WACOM_INTUOS1218 0x0024 /* Guess */
-
-#define USB_TOOL_ID_WACOM_PEN 0x0022
-#define USB_TOOL_ID_WACOM_ERASER 0x00fa
-#define USB_TOOL_ID_WACOM_STROKE_PEN 0x0032
-#define USB_TOOL_ID_WACOM_INKING_PEN 0x0012
-#define USB_TOOL_ID_WACOM_AIRBRUSH 0x0112
-#define USB_TOOL_ID_WACOM_MOUSE4D 0x0094
-#define USB_TOOL_ID_WACOM_LENS_CURSOR 0x0096
-
-#define INTUOS_PEN_MODE_ABS 0x00
-#define INTUOS_PEN_MODE_REL 0x01
-#define INTUOS_PEN_MODE_QUICKPOINT 0x02
-
-#define INTUOS_PRESSURE_MODE_SOFT 0x00
-#define INTUOS_PRESSURE_MODE_MED 0x01
-#define INTUOS_PRESSURE_MODE_FIRM 0x02
-
-#define INTUOS_MENUSTRIP_Y_ZONE 1400
-#define INTUOS_MENUSTRIP_BTN_YMIN 270
-#define INTUOS_MENUSTRIP_BTN_YMAX 1070
-#define INTUOS_MENUSTRIP_F1_XMIN 40
-#define INTUOS_MENUSTRIP_F7_XMIN 8340
-#define INTUOS_MENUSTRIP_F12_XMIN 15300
-
-#define INTUOS_MENUSTRIP_BTN_WIDTH 1300
-
-#define INTUOS_MENUSTRIP_F7_IX_OFFSET 6 /* offset into wacom_fkeys */
-#define INTUOS_MENUSTRIP_F12_IX_OFFSET 11
+#define USB_VENDOR_ID_WACOM 0x056a
+
+struct wacom_features {
+ char *name;
+ int idProduct;
+ int pktlen;
+ int x_max;
+ int y_max;
+ int pressure_max;
+ int distance_max;
+ void (*irq)(struct urb *urb);
+ unsigned long evbit;
+ unsigned long relbit;
+ unsigned long absbit;
+ unsigned long btnbit;
+ unsigned long digibit;
+};
struct wacom {
- signed char data[10];
+ signed char data[10];
struct input_dev dev;
struct urb irq;
-
- int last_x, last_y;
- unsigned int tool, device;
- unsigned int ymax, menustrip_touch;
- unsigned int pen_mode;
- unsigned int pressure_mode;
+ struct wacom_features *features;
+ int tool;
};
-static int wacom_fkeys[16] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4,
- KEY_F5, KEY_F6, KEY_F7, KEY_F8,
- KEY_F9, KEY_F10, KEY_F11, KEY_F12,
- KEY_F13, KEY_F14, KEY_F15, KEY_F16};
-
-#define INTUOS_EXTENTS_MAX_X 0x00
-#define INTUOS_EXTENTS_MAX_Y 0x01
-#define INTUOS_EXTENTS_HAS_F7 0x02
-#define INTUOS_EXTENTS_HAS_F12 0x03
-#define INTUOS_EXTENTS_PEN_MODE 0x04
-#define INTUOS_EXTENTS_HAS_QUICKPOINT 0x05
-#define INTUOS_EXTENTS_HAS_PRESSURE_MODE 0x06
-#define INTUOS_EXTENTS_PRESSURE_MODE 0x07
-
-#define WACOM_TRUE 1
-#define WACOM_FALSE 0
-
-static int intuos_extents[5][8] = {
- { 12700, 10360, WACOM_FALSE, WACOM_FALSE, 8340, WACOM_FALSE, WACOM_FALSE, 0}, /* Intuos 4x5 */
- { 20320, 15040, WACOM_TRUE, WACOM_FALSE, 15300, WACOM_FALSE, WACOM_TRUE, 18360}, /* Intuos 6x8 */
- { 30480, 23060, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 9x12 */
- { 30480, 30480, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 12x12 */
- { 47720, 30480, WACOM_TRUE, WACOM_TRUE, 29260, WACOM_TRUE, WACOM_TRUE, 33620}}; /* Intuos 12x18 */
-
-static char intuos_names[5][12] = {
- {"Intuos 4x5 "}, {"Intuos 6x8 "},
- {"Intuos 9x12 "}, {"Intuos 12x12"},
- {"Intuos 12x18"}};
-
static void wacom_graphire_irq(struct urb *urb)
{
- struct wacom *wacom = urb->context;
+ struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
@@ -186,285 +129,135 @@ static void wacom_graphire_irq(struct urb *urb)
if (data[0] != 2)
dbg("received unknown report #%d", data[0]);
- if ( data[1] & 0x80 ) {
- input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
- input_report_abs(dev, ABS_Y, 7422 - (data[4] | ((__u32)data[5] << 8)));
+ if ( data[1] & 0x80 ) {
+ input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
+ input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8));
}
switch ((data[1] >> 5) & 3) {
- case 0: /* Pen */
- input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80);
- input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
- break;
-
- case 1: /* Rubber */
- input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
- input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
- break;
-
- case 2: /* Mouse */
- input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24);
- input_report_btn(dev, BTN_LEFT, data[1] & 0x01);
- input_report_btn(dev, BTN_RIGHT, data[1] & 0x02);
- input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04);
- input_report_abs(dev, ABS_DISTANCE, data[7]);
- input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
- break;
- }
-}
+ case 0: /* Pen */
+ input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80);
+ break;
-static void intuos_menustrip( unsigned int x, unsigned int y, struct wacom *wacom )
-{
- struct input_dev *dev = &wacom->dev;
- unsigned int local_x = x;
- unsigned int local_y = y - ( wacom->ymax - INTUOS_MENUSTRIP_Y_ZONE );
- unsigned int fkey_index ;
-
- /* Ensure we are in the vertical strip for the buttons */
- if ( (local_y > INTUOS_MENUSTRIP_BTN_YMIN) && (local_y < INTUOS_MENUSTRIP_BTN_YMAX) ) {
-
- /* Handle Pressure Mode */
- if ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_PRESSURE_MODE] ) {
- int pressure_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PRESSURE_MODE])
- / INTUOS_MENUSTRIP_BTN_WIDTH );
- if ( ( pressure_mode >= INTUOS_PRESSURE_MODE_SOFT ) &&
- ( pressure_mode <= INTUOS_PRESSURE_MODE_FIRM ) ) {
- wacom->pressure_mode = pressure_mode;
- return;
- }
- }
-
- /* Handle Pen Mode */
- {
- int pen_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PEN_MODE])
- / INTUOS_MENUSTRIP_BTN_WIDTH );
- if ( ( pen_mode == INTUOS_PEN_MODE_ABS ) ||
- ( pen_mode == INTUOS_PEN_MODE_REL ) ||
- ( ( pen_mode == INTUOS_PEN_MODE_QUICKPOINT ) &&
- ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_QUICKPOINT] ) ) ) {
- wacom->pen_mode = pen_mode;
- return;
- }
- }
-
- /* Handle Function Keys */
- if ( local_x > INTUOS_MENUSTRIP_F12_XMIN ) {
- fkey_index = INTUOS_MENUSTRIP_F12_IX_OFFSET
- + ( (local_x - INTUOS_MENUSTRIP_F12_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
- fkey_index = ( fkey_index > 16 ) ? 16 : fkey_index; /* Ensure in range */
- }
- else if ( local_x > INTUOS_MENUSTRIP_F7_XMIN ) {
- fkey_index = INTUOS_MENUSTRIP_F7_IX_OFFSET
- + ( (local_x - INTUOS_MENUSTRIP_F7_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
- fkey_index = ( fkey_index > 11 ) ? 11 : fkey_index;
- }
- else {
- fkey_index = ( (local_x - INTUOS_MENUSTRIP_F1_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
- fkey_index = ( fkey_index > 6 ) ? 6 : fkey_index;
- }
- input_report_key(dev, wacom_fkeys[fkey_index], 1);
- input_report_key(dev, wacom_fkeys[fkey_index], 0);
+ case 1: /* Rubber */
+ input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
+ break;
- return;
+ case 2: /* Mouse */
+ input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24);
+ input_report_btn(dev, BTN_LEFT, data[1] & 0x01);
+ input_report_btn(dev, BTN_RIGHT, data[1] & 0x02);
+ input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04);
+ input_report_abs(dev, ABS_DISTANCE, data[7]);
+ input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+ return;
}
+
+ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+
+ input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
+ input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
}
-
+
static void wacom_intuos_irq(struct urb *urb)
{
- struct wacom *wacom = urb->context;
+ struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
unsigned int t;
- int x, y;
if (urb->status) return;
if (data[0] != 2)
dbg("received unknown report #%d", data[0]);
- if ( ((data[1] >> 5) & 0x3) == 0x2 ) /* First record, feature report */
- {
- wacom->tool = (((char)data[2] << 4) | (char)data[3] >> 4) & 0xff ;
- /* Report tool type */
- switch ( wacom->tool ) {
- case USB_TOOL_ID_WACOM_PEN:
- input_report_btn(dev, BTN_TOOL_PEN, 1);
- break;
- case USB_TOOL_ID_WACOM_ERASER:
- input_report_btn(dev, BTN_TOOL_RUBBER, 1);
- break;
- case USB_TOOL_ID_WACOM_STROKE_PEN:
- input_report_btn(dev, BTN_TOOL_BRUSH, 1);
- break;
- case USB_TOOL_ID_WACOM_INKING_PEN:
- input_report_btn(dev, BTN_TOOL_PENCIL, 1);
- break;
- case USB_TOOL_ID_WACOM_AIRBRUSH:
- input_report_btn(dev, BTN_TOOL_AIRBRUSH, 1);
- break;
- case USB_TOOL_ID_WACOM_MOUSE4D:
- case USB_TOOL_ID_WACOM_LENS_CURSOR:
- input_report_btn(dev, BTN_TOOL_MOUSE, 1);
- break;
- default:
- break;
- }
- return;
- }
-
- if ( ( data[1] | data[2] | data[3] | data[4] | data[5] | data[6]
- | data[7] | data[8] | data[9] ) == 0x80 ) { /* exit report */
- switch ( wacom->tool ) {
- case USB_TOOL_ID_WACOM_PEN:
- input_report_btn(dev, BTN_TOOL_PEN, 0);
- break;
- case USB_TOOL_ID_WACOM_ERASER:
- input_report_btn(dev, BTN_TOOL_RUBBER, 0);
- break;
- case USB_TOOL_ID_WACOM_STROKE_PEN:
- input_report_btn(dev, BTN_TOOL_BRUSH, 0);
- break;
- case USB_TOOL_ID_WACOM_INKING_PEN:
- input_report_btn(dev, BTN_TOOL_PENCIL, 0);
- break;
- case USB_TOOL_ID_WACOM_AIRBRUSH:
- input_report_btn(dev, BTN_TOOL_AIRBRUSH, 0);
- break;
- case USB_TOOL_ID_WACOM_MOUSE4D:
- case USB_TOOL_ID_WACOM_LENS_CURSOR:
- input_report_btn(dev, BTN_TOOL_MOUSE, 0);
- break;
- default:
- break;
+ if (((data[1] >> 5) & 0x3) == 0x2) { /* Enter report */
+
+ switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
+ case 0x012: wacom->tool = BTN_TOOL_PENCIL; break; /* Inking pen */
+ case 0x022: wacom->tool = BTN_TOOL_PEN; break; /* Pen */
+ case 0x032: wacom->tool = BTN_TOOL_BRUSH; break; /* Stroke pen */
+ case 0x094: wacom->tool = BTN_TOOL_MOUSE; break; /* Mouse 4D */
+ case 0x096: wacom->tool = BTN_TOOL_LENS; break; /* Lens cursor */
+ case 0x0fa: wacom->tool = BTN_TOOL_RUBBER; break; /* Eraser */
+ case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH; break; /* Airbrush */
+ default: wacom->tool = BTN_TOOL_PEN; break; /* Unknown tool */
}
+ input_report_btn(dev, wacom->tool, 1);
return;
}
- x = (((unsigned int) data[2]) << 8) | data[3] ;
- y = wacom->dev.absmax[ABS_Y] - ((((unsigned int) data[4]) << 8) | data[5]);
-
- t = (((unsigned int) data[6]) << 2) | ((data[7] & 0xC0) >> 6);
-
- /* Handle touch near menustrip */
- if ( y > ( wacom->dev.absmax[ABS_Y] - INTUOS_MENUSTRIP_Y_ZONE ) ) {
- if ( t > 10 ) /* Touch */
- wacom->menustrip_touch = 1;
- if ( (wacom->menustrip_touch) && (t <= 10) ) { /* Pen Up */
- intuos_menustrip( x, y, wacom );
- wacom->menustrip_touch = 0;
- }
+ if ((data[1] | data[2] | data[3] | data[4] | data[5] |
+ data[6] | data[7] | data[8] | data[9]) == 0x80) { /* Exit report */
+ input_report_btn(dev, wacom->tool, 0);
return;
}
- else
- wacom->menustrip_touch = 0;
-
- switch ( wacom->pen_mode ) {
- case INTUOS_PEN_MODE_ABS:
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
- break;
- case INTUOS_PEN_MODE_REL:
- input_report_rel(dev, REL_X, ( x - wacom->last_x) / 8 );
- input_report_rel(dev, REL_Y, - ( y - wacom->last_y) / 8 );
- break;
- default: break;
- }
-
- wacom->last_x = x;
- wacom->last_y = y;
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
-
- input_report_btn(dev, BTN_TOUCH, t > 10);
- input_report_abs(dev, ABS_PRESSURE, t);
-
- input_report_abs(dev, ABS_DISTANCE, ( data[9] & 0xf0 ) >> 4 );
-
- input_report_abs(dev, ABS_TILT_X, ((((unsigned int) data[7]) & 0x3f) << 1) | ((data[8] & 0x80) >> 7));
+ input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
+ input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
+ input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+ input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
+ input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+ input_report_btn(dev, BTN_STYLUS, data[1] & 2);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 4);
+ input_report_btn(dev, BTN_TOUCH, t > 10);
}
+#define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
+
+struct wacom_features wacom_features[] = {
+ { "Graphire", 0x10, 8, 10206, 7422, 511, 32, wacom_graphire_irq,
+ BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE), 0 },
+ { "Intuos 4x5", 0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 6x8", 0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 9x12", 0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { "Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
+ 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ { NULL , 0 }
+};
+
static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_endpoint_descriptor *endpoint;
struct wacom *wacom;
- char *name;
+ int i;
- if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM ||
- (dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_GRAPHIRE &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS45 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS68 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS912 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1212 &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1218))
- return NULL;
+ if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM) return NULL;
+ for (i = 0; wacom_features[i].idProduct && wacom_features[i].idProduct != dev->descriptor.idProduct; i++);
+ if (!wacom_features[i].idProduct) return NULL;
endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
memset(wacom, 0, sizeof(struct wacom));
- if ( dev->descriptor.idProduct == USB_DEVICE_ID_WACOM_GRAPHIRE ) {
- wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
- wacom->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
- wacom->dev.relbit[0] |= BIT(REL_WHEEL);
- wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
-
- wacom->dev.absmax[ABS_X] = 10206;
- wacom->dev.absmax[ABS_Y] = 7422;
- wacom->dev.absmax[ABS_PRESSURE] = 511;
- wacom->dev.absmax[ABS_DISTANCE] = 32;
-
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, 8, wacom_graphire_irq, wacom, endpoint->bInterval);
-
- name = "Graphire";
- }
- else { /* Intuos */
-
- wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
- wacom->dev.keybit[LONG(KEY_F1)] |= BIT(KEY_F1) | BIT(KEY_F2) | BIT(KEY_F3) | BIT(KEY_F4) | BIT(KEY_F5);
- wacom->dev.keybit[LONG(KEY_F6)] |= BIT(KEY_F6) | BIT(KEY_F7) | BIT(KEY_F8);
- wacom->dev.keybit[LONG(KEY_F9)] |= BIT(KEY_F9) | BIT(KEY_F10) | BIT(KEY_F11) | BIT(KEY_F12);
- wacom->dev.keybit[LONG(KEY_F13)] |= BIT(KEY_F13) | BIT(KEY_F14) | BIT(KEY_F15) | BIT(KEY_F16);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_BRUSH);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_MOUSE);
- wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
- wacom->dev.absbit[0] |= BIT(ABS_TILT_X) | BIT(ABS_TILT_Y);
- wacom->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
-
- wacom->dev.absmax[ABS_PRESSURE] = 1023;
- wacom->dev.absmax[ABS_DISTANCE] = 15;
- wacom->dev.absmax[ABS_TILT_X] = 127;
- wacom->dev.absmax[ABS_TILT_Y] = 127;
-
- wacom->device = dev->descriptor.idProduct - USB_DEVICE_ID_WACOM_INTUOS45;
+ wacom->features = wacom_features + i;
- wacom->dev.absmax[ABS_X] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_X];
- wacom->dev.absmax[ABS_Y] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y];
+ wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit;
+ wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | wacom->features->absbit;
+ wacom->dev.relbit[0] |= wacom->features->relbit;
+ wacom->dev.keybit[LONG(BTN_LEFT)] |= wacom->features->btnbit;
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) |
+ BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit;
- wacom->ymax = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y];
- wacom->pen_mode = INTUOS_PEN_MODE_ABS;
- wacom->pressure_mode = INTUOS_PRESSURE_MODE_SOFT;
+ wacom->dev.absmax[ABS_X] = wacom->features->x_max;
+ wacom->dev.absmax[ABS_Y] = wacom->features->y_max;
+ wacom->dev.absmax[ABS_PRESSURE] = wacom->features->pressure_max;
+ wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max;
+ wacom->dev.absmax[ABS_TILT_X] = 127;
+ wacom->dev.absmax[ABS_TILT_Y] = 127;
- name = intuos_names[wacom->device];
-
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, 10, wacom_intuos_irq, wacom, endpoint->bInterval);
-
- }
+ FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
if (usb_submit_urb(&wacom->irq)) {
kfree(wacom);
@@ -473,7 +266,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
input_register_device(&wacom->dev);
- printk(KERN_INFO "input%d: Wacom %s\n", wacom->dev.number, name);
+ printk(KERN_INFO "input%d: Wacom %s on usb%d\n", wacom->dev.number, wacom->features->name, dev->devnum);
return wacom;
}
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 12918c1b5..49125330f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -16,7 +16,8 @@ M_OBJS :=
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o fbcon-afb.o fbcon-ilbm.o \
+export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
+ fbcon-afb.o fbcon-ilbm.o \
fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
@@ -46,6 +47,7 @@ obj-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
obj-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o fbmon.o
+obj-$(CONFIG_FB_COMPAT_XPMAC) += macmodes.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_AMIGA) += amifb.o
@@ -64,9 +66,9 @@ obj-$(CONFIG_FB_CYBER) += cyberfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
-obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o
+obj-$(CONFIG_FB_MAC) += macfb.o
obj-$(CONFIG_FB_HP300) += hpfb.o
-obj-$(CONFIG_FB_OF) += offb.o macmodes.o
+obj-$(CONFIG_FB_OF) += offb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
obj-$(CONFIG_FB_CLGEN) += clgenfb.o fbgen.o
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 97df72fd2..a0518c009 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1765,37 +1765,11 @@ default_chipset:
fb_info.flags = FBINFO_FLAG_DEFAULT;
memset(&var, 0, sizeof(var));
-#ifdef MODULE
- var.xres = ami_modedb[defmode].xres;
- var.yres = ami_modedb[defmode].yres;
- var.xres_virtual = ami_modedb[defmode].xres;
- var.yres_virtual = ami_modedb[defmode].yres;
- var.xoffset = 0;
- var.yoffset = 0;
- var.bits_per_pixel = 4;
- var.activate |= FB_ACTIVATE_TEST;
- var.pixclock = ami_modedb[defmode].pixclock;
- var.left_margin = ami_modedb[defmode].left_margin;
- var.right_margin = ami_modedb[defmode].right_margin;
- var.upper_margin = ami_modedb[defmode].upper_margin;
- var.lower_margin = ami_modedb[defmode].lower_margin;
- var.hsync_len = ami_modedb[defmode].hsync_len;
- var.vsync_len = ami_modedb[defmode].vsync_len;
- var.sync = ami_modedb[defmode].sync;
- var.vmode = ami_modedb[defmode].vmode;
- err = fb_info.fbops->fb_set_var(&var, -1, &fb_info);
- var.activate &= ~FB_ACTIVATE_TEST;
- if (err) {
- err = -EINVAL;
- goto amifb_error;
- }
-#else
if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
err = -EINVAL;
goto amifb_error;
}
-#endif
round_down_bpp = 0;
chipptr = chipalloc(videomemorysize+
diff --git a/drivers/video/cgthreefb.c b/drivers/video/cgthreefb.c
index 5e4d45a9e..9cec20abf 100644
--- a/drivers/video/cgthreefb.c
+++ b/drivers/video/cgthreefb.c
@@ -1,4 +1,4 @@
-/* $Id: cgthreefb.c,v 1.8 1999/11/19 09:57:08 davem Exp $
+/* $Id: cgthreefb.c,v 1.9 2000/03/19 04:20:44 anton Exp $
* cgthreefb.c: CGthree frame buffer driver
*
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -114,9 +114,9 @@ static void cg3_blank (struct fb_info_sbusfb *fb)
u8 tmp;
spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.cg3.regs->control);
+ tmp = sbus_readb(&fb->s.cg3.regs->control);
tmp &= ~CG3_CR_ENABLE_VIDEO;
- sbus_writel(tmp, &fb->s.cg3.regs->control);
+ sbus_writeb(tmp, &fb->s.cg3.regs->control);
spin_unlock_irqrestore(&fb->lock, flags);
}
@@ -126,9 +126,9 @@ static void cg3_unblank (struct fb_info_sbusfb *fb)
u8 tmp;
spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.cg3.regs->control);
+ tmp = sbus_readb(&fb->s.cg3.regs->control);
tmp |= CG3_CR_ENABLE_VIDEO;
- sbus_writel(tmp, &fb->s.cg3.regs->control);
+ sbus_writeb(tmp, &fb->s.cg3.regs->control);
spin_unlock_irqrestore(&fb->lock, flags);
}
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index e71f36e50..98bcf32d8 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -3,15 +3,22 @@
*
* Copyright (C) 1998 Geert Uytterhoeven
*
+ * 2000 - Removal of OpenFirmware dependencies by:
+ * - Ani Joshi
+ * - Brad Douglas <brad@neruo.com>
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
-#include <linux/tty.h>
+#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/string.h>
+#include <asm/vc_ioctl.h>
+
+#include <video/fbcon.h>
#include <video/macmodes.h>
@@ -181,6 +188,107 @@ static const struct monitor_map {
{ -1, VMODE_640_480_60 }, /* catch-all, must be last */
};
+struct fb_info *console_fb_info = NULL;
+struct vc_mode display_info;
+static u16 palette_red[16];
+static u16 palette_green[16];
+static u16 palette_blue[16];
+static struct fb_cmap palette_cmap = {
+ 0, 16, palette_red, palette_green, palette_blue, NULL
+};
+
+
+int console_getmode(struct vc_mode *);
+int console_setmode(struct vc_mode *, int);
+int console_setcmap(int, unsigned char *, unsigned char *, unsigned char *);
+int console_powermode(int);
+int mac_var_to_vmode(const struct fb_var_screeninfo *, int *, int *);
+
+
+int console_getmode(struct vc_mode *mode)
+{
+ *mode = display_info;
+ return 0;
+}
+
+
+int console_setmode(struct vc_mode *mode, int doit)
+{
+ struct fb_var_screeninfo var;
+ int cmode, err;
+
+ if (!console_fb_info)
+ return -EOPNOTSUPP;
+
+ switch(mode->depth) {
+ case 0:
+ case 8:
+ cmode = CMODE_8;
+ break;
+ case 16:
+ cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ cmode = CMODE_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((err = mac_vmode_to_var(mode->mode, cmode, &var)))
+ return err;
+
+ var.activate = FB_ACTIVATE_TEST;
+ err = console_fb_info->fbops->fb_set_var(&var, fg_console,
+ console_fb_info);
+ if (err || !doit)
+ return err;
+ else {
+ int unit;
+
+ var.activate = FB_ACTIVATE_NOW;
+ for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
+ if (fb_display[unit].conp &&
+ (GET_FB_IDX(console_fb_info->node) == con2fb_map[unit]))
+ console_fb_info->fbops->fb_set_var(&var, unit,
+ console_fb_info);
+ }
+
+ return 0;
+}
+
+
+int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
+ unsigned char *blue)
+{
+ int i, j, n = 0, err;
+
+ if (!console_fb_info)
+ return -EOPNOTSUPP;
+
+ for (i = 0; i < n_entries; i += n) {
+ n = n_entries - i;
+ if (n > 16)
+ n = 16;
+ palette_cmap.start = 1;
+ palette_cmap.len = n;
+
+ for (j = 0; j < n; j++) {
+ palette_cmap.red[j] = (red[i+j] << 8) | red[i+j];
+ palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
+ palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j];
+ }
+ err = console_fb_info->fbops->fb_set_cmap(&palette_cmap, 1,
+ fg_console,
+ console_fb_info);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
/*
* Convert a MacOS vmode/cmode pair to a frame buffer video mode structure
@@ -255,6 +363,17 @@ int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var)
}
+int console_powermode(int mode)
+{
+ if (mode == VC_POWERMODE_INQUIRY)
+ return 0;
+ if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+ return -EINVAL;
+ /* Not Supported */
+ return -ENXIO;
+}
+
+
/*
* Convert a frame buffer video mode structure to a MacOS vmode/cmode pair
*/
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 404c646f5..e33b8fdd7 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -8,6 +8,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/console_struct.h>
@@ -253,7 +254,7 @@ static int __init my_atoi(const char *name)
}
}
-static int __init PROC_CONSOLE(const struct fb_info *info)
+static int PROC_CONSOLE(const struct fb_info *info)
{
int fgc;
@@ -275,8 +276,8 @@ static int __init PROC_CONSOLE(const struct fb_info *info)
return MINOR(current->tty->device) - 1;
}
-static int __init try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
- const struct fb_videomode *mode, unsigned int bpp)
+int __fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const struct fb_videomode *mode, unsigned int bpp)
{
int err;
@@ -391,20 +392,22 @@ done:
if ((name_matches(db[j], name, namelen) ||
(res_specified && res_matches(db[j], xres, yres))) &&
(!i || db[j].refresh == refresh) &&
- try_mode(var, info, &db[j], bpp))
+ __fb_try_mode(var, info, &db[j], bpp))
return 2-i;
}
}
DPRINTK("Trying default video mode\n");
- if (try_mode(var, info, default_mode, default_bpp))
+ if (__fb_try_mode(var, info, default_mode, default_bpp))
return 3;
DPRINTK("Trying all modes\n");
for (i = 0; i < dbsize; i++)
- if (try_mode(var, info, &db[i], default_bpp))
+ if (__fb_try_mode(var, info, &db[i], default_bpp))
return 4;
DPRINTK("No valid mode found\n");
return 0;
}
+
+EXPORT_SYMBOL(__fb_try_mode);
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index f734c4f9f..d3a609d35 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -94,15 +94,6 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, int con, struct fb_info *info);
-#ifdef CONFIG_FB_COMPAT_XPMAC
-int console_getmode(struct vc_mode *);
-int console_setmode(struct vc_mode *, int);
-int console_setcmap(int, unsigned char *, unsigned char *, unsigned char *);
-int console_powermode(int);
-struct fb_info *console_fb_info = NULL;
-struct vc_mode display_info;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
-
extern boot_infos_t *boot_infos;
static int offb_init_driver(struct device_node *);
@@ -898,103 +889,3 @@ static void do_install_cmap(int con, struct fb_info *info)
fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info);
}
}
-
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-
- /*
- * Backward compatibility mode for Xpmac
- */
-
-int console_getmode(struct vc_mode *mode)
-{
- *mode = display_info;
- return 0;
-}
-
-int console_setmode(struct vc_mode *mode, int doit)
-{
- struct fb_var_screeninfo var;
- int cmode, err;
-
- if (!console_fb_info)
- return -EOPNOTSUPP;
- switch (mode->depth) {
- case 8:
- case 0: /* default */
- cmode = CMODE_8;
- break;
- case 16:
- cmode = CMODE_16;
- break;
- case 24:
- case 32:
- cmode = CMODE_32;
- break;
- default:
- return -EINVAL;
- }
- if ((err = mac_vmode_to_var(mode->mode, cmode, &var)))
- return err;
- var.activate = FB_ACTIVATE_TEST;
- err = console_fb_info->fbops->fb_set_var(&var, fg_console,
- console_fb_info);
- if (err || !doit)
- return err;
- else {
- int unit;
- var.activate = FB_ACTIVATE_NOW;
- for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
- if (fb_display[unit].conp &&
- (GET_FB_IDX(console_fb_info->node) == con2fb_map[unit]))
- console_fb_info->fbops->fb_set_var(&var, unit,
- console_fb_info);
- }
- return 0;
-}
-
-static u16 palette_red[16];
-static u16 palette_green[16];
-static u16 palette_blue[16];
-
-static struct fb_cmap palette_cmap = {
- 0, 16, palette_red, palette_green, palette_blue, NULL
-};
-
-int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
- unsigned char *blue)
-{
- int i, j, n, err;
-
- if (!console_fb_info)
- return -EOPNOTSUPP;
- for (i = 0; i < n_entries; i += n) {
- n = n_entries-i;
- if (n > 16)
- n = 16;
- palette_cmap.start = i;
- palette_cmap.len = n;
- for (j = 0; j < n; j++) {
- palette_cmap.red[j] = (red[i+j] << 8) | red[i+j];
- palette_cmap.green[j] = (green[i+j] << 8) | green[i+j];
- palette_cmap.blue[j] = (blue[i+j] << 8) | blue[i+j];
- }
- err = console_fb_info->fbops->fb_set_cmap(&palette_cmap, 1, fg_console,
- console_fb_info);
- if (err)
- return err;
- }
- return 0;
-}
-
-int console_powermode(int mode)
-{
- if (mode == VC_POWERMODE_INQUIRY)
- return 0;
- if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
- return -EINVAL;
- /* Not supported */
- return -ENXIO;
-}
-
-#endif /* CONFIG_FB_COMPAT_XPMAC */
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 82c916d8a..eef60b04e 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -521,7 +521,7 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
rinfo->base1_region_size = pci_resource_len (pd, 1);
assert (rinfo->base0_region_size >= 0x00800000); /* from GGI */
- assert (rinfo->base0_region_size >= 0x01000000); /* from GGI */
+ assert (rinfo->base1_region_size >= 0x01000000); /* from GGI */
rinfo->ctrl_base_phys = rinfo->pd->resource[0].start;
rinfo->fb_base_phys = rinfo->pd->resource[1].start;