summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/base/node.c2
-rw-r--r--drivers/cdrom/aztcd.c2
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/dtlk.c2
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c2
-rw-r--r--drivers/char/random.c1
-rw-r--r--drivers/char/tlclk.c36
-rw-r--r--drivers/char/tty_io.c26
-rw-r--r--drivers/hwmon/hdaps.c14
-rw-r--r--drivers/isdn/gigaset/Kconfig4
-rw-r--r--drivers/isdn/gigaset/asyncdata.c132
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c870
-rw-r--r--drivers/isdn/gigaset/common.c505
-rw-r--r--drivers/isdn/gigaset/ev-layer.c667
-rw-r--r--drivers/isdn/gigaset/gigaset.h600
-rw-r--r--drivers/isdn/gigaset/i4l.c231
-rw-r--r--drivers/isdn/gigaset/interface.c235
-rw-r--r--drivers/isdn/gigaset/isocdata.c139
-rw-r--r--drivers/isdn/gigaset/proc.c51
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c455
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c20
-rw-r--r--drivers/leds/Kconfig27
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-s3c24xx.c163
-rw-r--r--drivers/md/Kconfig11
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/bt8xx/Makefile2
-rw-r--r--drivers/media/video/cx25840/Makefile2
-rw-r--r--drivers/media/video/cx88/Makefile6
-rw-r--r--drivers/media/video/em28xx/Makefile2
-rw-r--r--drivers/media/video/saa7134/Makefile6
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c3
-rw-r--r--drivers/mmc/Kconfig18
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/at91_mci.c988
-rw-r--r--drivers/mmc/imxmmc.c1096
-rw-r--r--drivers/mmc/imxmmc.h67
-rw-r--r--drivers/mtd/devices/Kconfig13
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/blkmtd.c819
-rw-r--r--drivers/net/b44.c64
-rw-r--r--drivers/net/bnx2.c2
-rw-r--r--drivers/net/chelsio/Makefile2
-rw-r--r--drivers/net/hydra.h177
-rw-r--r--drivers/net/irda/irda-usb.c363
-rw-r--r--drivers/net/irda/irda-usb.h43
-rw-r--r--drivers/net/irda/smsc-ircc2.c311
-rw-r--r--drivers/net/ixgb/ixgb_main.c13
-rw-r--r--drivers/net/mv643xx_eth.c19
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/netconsole.c1
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/skge.c2
-rw-r--r--drivers/net/sky2.c6
-rw-r--r--drivers/net/sky2.h2
-rw-r--r--drivers/net/starfire.c2
-rw-r--r--drivers/net/tg3.c100
-rw-r--r--drivers/net/tg3.h3
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/via-rhine.c7
-rw-r--r--drivers/net/wan/Kconfig97
-rw-r--r--drivers/net/wan/Makefile13
-rw-r--r--drivers/net/wan/sdla_chdlc.c4428
-rw-r--r--drivers/net/wan/sdla_fr.c5061
-rw-r--r--drivers/net/wan/sdla_ft1.c345
-rw-r--r--drivers/net/wan/sdla_ppp.c3430
-rw-r--r--drivers/net/wan/sdla_x25.c5497
-rw-r--r--drivers/net/wan/sdladrv.c2314
-rw-r--r--drivers/net/wan/sdlamain.c1346
-rw-r--r--drivers/net/wan/wanpipe_multppp.c2358
-rw-r--r--drivers/parport/parport_serial.c2
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c2
-rw-r--r--drivers/rtc/rtc-ds1672.c72
-rw-r--r--drivers/rtc/rtc-ep93xx.c2
-rw-r--r--drivers/rtc/rtc-m48t86.c9
-rw-r--r--drivers/rtc/rtc-pcf8563.c11
-rw-r--r--drivers/rtc/rtc-proc.c2
-rw-r--r--drivers/rtc/rtc-rs5c372.c28
-rw-r--r--drivers/rtc/rtc-sa1100.c14
-rw-r--r--drivers/rtc/rtc-test.c3
-rw-r--r--drivers/rtc/rtc-vr41xx.c (renamed from drivers/char/vr41xx_rtc.c)404
-rw-r--r--drivers/rtc/rtc-x1205.c29
-rw-r--r--drivers/s390/block/dasd.c45
-rw-r--r--drivers/s390/block/dasd_proc.c17
-rw-r--r--drivers/s390/char/keyboard.c2
-rw-r--r--drivers/s390/char/tape_block.c4
-rw-r--r--drivers/s390/char/tape_core.c10
-rw-r--r--drivers/s390/cio/blacklist.c4
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/cio_debug.h22
-rw-r--r--drivers/scsi/3w-xxxx.c3
-rw-r--r--drivers/scsi/ahci.c1
-rw-r--r--drivers/scsi/ata_piix.c1
-rw-r--r--drivers/scsi/hosts.c12
-rw-r--r--drivers/scsi/libata-core.c1
-rw-r--r--drivers/scsi/libata-scsi.c8
-rw-r--r--drivers/scsi/libata.h1
-rw-r--r--drivers/scsi/pdc_adma.c1
-rw-r--r--drivers/scsi/sata_mv.c3
-rw-r--r--drivers/scsi/sata_nv.c1
-rw-r--r--drivers/scsi/sata_promise.c1
-rw-r--r--drivers/scsi/sata_qstor.c1
-rw-r--r--drivers/scsi/sata_sil.c1
-rw-r--r--drivers/scsi/sata_sil24.c1
-rw-r--r--drivers/scsi/sata_sis.c1
-rw-r--r--drivers/scsi/sata_svw.c1
-rw-r--r--drivers/scsi/sata_sx4.c1
-rw-r--r--drivers/scsi/sata_uli.c1
-rw-r--r--drivers/scsi/sata_via.c1
-rw-r--r--drivers/scsi/sata_vsc.c1
-rw-r--r--drivers/scsi/scsi_error.c4
-rw-r--r--drivers/sn/ioc3.c5
-rw-r--r--drivers/usb/serial/option.c5
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/aty/atyfb_base.c2
-rw-r--r--drivers/video/fbmem.c5
-rw-r--r--drivers/video/vesafb.c27
122 files changed, 5438 insertions, 28593 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5cb96300eb0f..c24652d31bf9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -329,7 +329,7 @@ config ACPI_CONTAINER
config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug"
depends on ACPI
- depends on MEMORY_HOTPLUG
+ depends on MEMORY_HOTPLUG || X86_64
default n
help
This driver adds supports for ACPI Memory Hotplug. This driver
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 16c513aa4d48..c80c3aeed004 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -106,7 +106,7 @@ static ssize_t node_read_numastat(struct sys_device * dev, char * buf)
other_node = 0;
for (i = 0; i < MAX_NR_ZONES; i++) {
struct zone *z = &pg->node_zones[i];
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ for_each_online_cpu(cpu) {
struct per_cpu_pageset *ps = zone_pcp(z,cpu);
numa_hit += ps->numa_hit;
numa_miss += ps->numa_miss;
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index ce4a1ce59d6a..ec004897b634 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1763,7 +1763,7 @@ static int __init aztcd_init(void)
release_region(azt_port, 4);
}
}
- if ((azt_port_auto[i] == 0) || (i == 16)) {
+ if ((i == 16) || (azt_port_auto[i] == 0)) {
printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n");
return -EIO;
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 889cad07774e..402296670d3a 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -805,10 +805,6 @@ config S3C2410_RTC
Samsung S3C2410. This can provide periodic interrupt rates
from 1Hz to 64Hz for user programs, and wakeup from Alarm.
-config RTC_VR41XX
- tristate "NEC VR4100 series Real Time Clock Support"
- depends on CPU_VR41XX
-
config COBALT_LCD
bool "Support for Cobalt LCD"
depends on MIPS_COBALT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index a73cb4956928..f5b01c6d498e 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -67,7 +67,6 @@ obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
-obj-$(CONFIG_RTC_VR41XX) += vr41xx_rtc.o
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 927a5bbe112c..a370e7a0bad5 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -142,7 +142,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc,
if (!boardno)
boardno = readb(loc + NUMCARD_OWNER_TO_PC);
- if (!boardno && boardno > MAX_BOARD) {
+ 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;
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index a229915ce1b2..87dcaa237f07 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -490,7 +490,7 @@ for (i = 0; i < 10; i++) \
release_region(dtlk_portlist[i], DTLK_IO_EXTENT);
}
- printk(KERN_INFO "\nDoubleTalk PC - not found\n");
+ printk(KERN_INFO "DoubleTalk PC - not found\n");
return -ENODEV;
}
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 0ded046d5aa8..9f2f8fdec69a 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -941,6 +941,7 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
list_del(&msg->link);
list_add_tail(&msg->link, &msgs);
}
+ intf->waiting_events_count = 0;
}
/* Hold the events lock while doing this to preserve order. */
@@ -2916,6 +2917,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf,
copy_event_into_recv_msg(recv_msg, msg);
list_add_tail(&(recv_msg->link), &(intf->waiting_events));
+ intf->waiting_events_count++;
} else {
/* There's too many things in the queue, discard this
message. */
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 86be04b241e1..58f3512c52e1 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1584,7 +1584,6 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo
return twothirdsMD4Transform(daddr, hash);
}
-EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#endif
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 2546637a55c0..f58ad7f68267 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -327,7 +327,7 @@ static ssize_t store_received_ref_clk3a(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(received_ref_clk3a, S_IWUGO, NULL,
+static DEVICE_ATTR(received_ref_clk3a, (S_IWUSR|S_IWGRP), NULL,
store_received_ref_clk3a);
@@ -349,7 +349,7 @@ static ssize_t store_received_ref_clk3b(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(received_ref_clk3b, S_IWUGO, NULL,
+static DEVICE_ATTR(received_ref_clk3b, (S_IWUSR|S_IWGRP), NULL,
store_received_ref_clk3b);
@@ -371,7 +371,7 @@ static ssize_t store_enable_clk3b_output(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(enable_clk3b_output, S_IWUGO, NULL,
+static DEVICE_ATTR(enable_clk3b_output, (S_IWUSR|S_IWGRP), NULL,
store_enable_clk3b_output);
static ssize_t store_enable_clk3a_output(struct device *d,
@@ -392,7 +392,7 @@ static ssize_t store_enable_clk3a_output(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(enable_clk3a_output, S_IWUGO, NULL,
+static DEVICE_ATTR(enable_clk3a_output, (S_IWUSR|S_IWGRP), NULL,
store_enable_clk3a_output);
static ssize_t store_enable_clkb1_output(struct device *d,
@@ -413,7 +413,7 @@ static ssize_t store_enable_clkb1_output(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(enable_clkb1_output, S_IWUGO, NULL,
+static DEVICE_ATTR(enable_clkb1_output, (S_IWUSR|S_IWGRP), NULL,
store_enable_clkb1_output);
@@ -435,7 +435,7 @@ static ssize_t store_enable_clka1_output(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(enable_clka1_output, S_IWUGO, NULL,
+static DEVICE_ATTR(enable_clka1_output, (S_IWUSR|S_IWGRP), NULL,
store_enable_clka1_output);
static ssize_t store_enable_clkb0_output(struct device *d,
@@ -456,7 +456,7 @@ static ssize_t store_enable_clkb0_output(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(enable_clkb0_output, S_IWUGO, NULL,
+static DEVICE_ATTR(enable_clkb0_output, (S_IWUSR|S_IWGRP), NULL,
store_enable_clkb0_output);
static ssize_t store_enable_clka0_output(struct device *d,
@@ -477,7 +477,7 @@ static ssize_t store_enable_clka0_output(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(enable_clka0_output, S_IWUGO, NULL,
+static DEVICE_ATTR(enable_clka0_output, (S_IWUSR|S_IWGRP), NULL,
store_enable_clka0_output);
static ssize_t store_select_amcb2_transmit_clock(struct device *d,
@@ -519,7 +519,7 @@ static ssize_t store_select_amcb2_transmit_clock(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(select_amcb2_transmit_clock, S_IWUGO, NULL,
+static DEVICE_ATTR(select_amcb2_transmit_clock, (S_IWUSR|S_IWGRP), NULL,
store_select_amcb2_transmit_clock);
static ssize_t store_select_amcb1_transmit_clock(struct device *d,
@@ -560,7 +560,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(select_amcb1_transmit_clock, S_IWUGO, NULL,
+static DEVICE_ATTR(select_amcb1_transmit_clock, (S_IWUSR|S_IWGRP), NULL,
store_select_amcb1_transmit_clock);
static ssize_t store_select_redundant_clock(struct device *d,
@@ -581,7 +581,7 @@ static ssize_t store_select_redundant_clock(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(select_redundant_clock, S_IWUGO, NULL,
+static DEVICE_ATTR(select_redundant_clock, (S_IWUSR|S_IWGRP), NULL,
store_select_redundant_clock);
static ssize_t store_select_ref_frequency(struct device *d,
@@ -602,7 +602,7 @@ static ssize_t store_select_ref_frequency(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(select_ref_frequency, S_IWUGO, NULL,
+static DEVICE_ATTR(select_ref_frequency, (S_IWUSR|S_IWGRP), NULL,
store_select_ref_frequency);
static ssize_t store_filter_select(struct device *d,
@@ -623,7 +623,7 @@ static ssize_t store_filter_select(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(filter_select, S_IWUGO, NULL, store_filter_select);
+static DEVICE_ATTR(filter_select, (S_IWUSR|S_IWGRP), NULL, store_filter_select);
static ssize_t store_hardware_switching_mode(struct device *d,
struct device_attribute *attr, const char *buf, size_t count)
@@ -643,7 +643,7 @@ static ssize_t store_hardware_switching_mode(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(hardware_switching_mode, S_IWUGO, NULL,
+static DEVICE_ATTR(hardware_switching_mode, (S_IWUSR|S_IWGRP), NULL,
store_hardware_switching_mode);
static ssize_t store_hardware_switching(struct device *d,
@@ -664,7 +664,7 @@ static ssize_t store_hardware_switching(struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(hardware_switching, S_IWUGO, NULL,
+static DEVICE_ATTR(hardware_switching, (S_IWUSR|S_IWGRP), NULL,
store_hardware_switching);
static ssize_t store_refalign (struct device *d,
@@ -684,7 +684,7 @@ static ssize_t store_refalign (struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(refalign, S_IWUGO, NULL, store_refalign);
+static DEVICE_ATTR(refalign, (S_IWUSR|S_IWGRP), NULL, store_refalign);
static ssize_t store_mode_select (struct device *d,
struct device_attribute *attr, const char *buf, size_t count)
@@ -704,7 +704,7 @@ static ssize_t store_mode_select (struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(mode_select, S_IWUGO, NULL, store_mode_select);
+static DEVICE_ATTR(mode_select, (S_IWUSR|S_IWGRP), NULL, store_mode_select);
static ssize_t store_reset (struct device *d,
struct device_attribute *attr, const char *buf, size_t count)
@@ -724,7 +724,7 @@ static ssize_t store_reset (struct device *d,
return strnlen(buf, count);
}
-static DEVICE_ATTR(reset, S_IWUGO, NULL, store_reset);
+static DEVICE_ATTR(reset, (S_IWUSR|S_IWGRP), NULL, store_reset);
static struct attribute *tlclk_sysfs_entries[] = {
&dev_attr_current_ref.attr,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 98b126c2ded8..f70a47eadb52 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -351,10 +351,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
-
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size)
+int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
+ size_t size)
{
int copied = 0;
do {
@@ -368,17 +368,16 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, s
tb->used += space;
copied += space;
chars += space;
-/* printk("Flip insert %d.\n", space); */
}
/* There is a small chance that we need to split the data over
several buffers. If this is the case we must loop */
while (unlikely(size > copied));
return copied;
}
-
EXPORT_SYMBOL(tty_insert_flip_string);
-int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size)
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+ const unsigned char *chars, const char *flags, size_t size)
{
int copied = 0;
do {
@@ -399,9 +398,20 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *ch
while (unlikely(size > copied));
return copied;
}
-
EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
+void tty_schedule_flip(struct tty_struct *tty)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ if (tty->buf.tail != NULL) {
+ tty->buf.tail->active = 0;
+ tty->buf.tail->commit = tty->buf.tail->used;
+ }
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
/*
* Prepare a block of space in the buffer for data. Returns the length
@@ -1730,7 +1740,7 @@ static void release_dev(struct file * filp)
{
struct tty_struct *tty, *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep;
- int devpts_master, devpts;
+ int devpts;
int idx;
char buf[64];
unsigned long flags;
@@ -1747,7 +1757,6 @@ static void release_dev(struct file * filp)
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER);
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
- devpts_master = pty_master && devpts;
o_tty = tty->link;
#ifdef TTY_PARANOIA_CHECK
@@ -2185,6 +2194,7 @@ static int ptmx_open(struct inode * inode, struct file * filp)
return 0;
out1:
release_dev(filp);
+ return retval;
out:
down(&allocated_ptys_lock);
idr_remove(&allocated_ptys, index);
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 23a9e1ea8e32..1659f6c41458 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -509,12 +509,22 @@ static int hdaps_dmi_match_invert(struct dmi_system_id *id)
} \
}
+#define HDAPS_DMI_MATCH_LENOVO(model) { \
+ .ident = "Lenovo " model, \
+ .callback = hdaps_dmi_match_invert, \
+ .matches = { \
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), \
+ DMI_MATCH(DMI_PRODUCT_VERSION, model) \
+ } \
+}
+
static int __init hdaps_init(void)
{
int ret;
/* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */
struct dmi_system_id hdaps_whitelist[] = {
+ HDAPS_DMI_MATCH_NORMAL("ThinkPad H"),
HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"),
@@ -524,15 +534,17 @@ static int __init hdaps_init(void)
HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
+ HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"),
+ HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"),
{ .ident = NULL }
};
if (!dmi_check_system(hdaps_whitelist)) {
printk(KERN_WARNING "hdaps: supported laptop not found!\n");
- ret = -ENXIO;
+ ret = -ENODEV;
goto out;
}
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index 53c4fb62ed85..5b203fe21dcd 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -3,8 +3,8 @@ menu "Siemens Gigaset"
config ISDN_DRV_GIGASET
tristate "Siemens Gigaset support (isdn)"
- depends on ISDN_I4L && m
-# depends on ISDN_I4L && MODULES
+ depends on ISDN_I4L
+ select CRC_CCITT
help
Say m here if you have a Gigaset or Sinus isdn device.
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index 171f8b703d61..ce3cd77094b3 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
* Hansjoerg Lipp <hjlipp@web.de>,
- * Stefan Eilers <Eilers.Stefan@epost.de>.
+ * Stefan Eilers.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
@@ -11,10 +11,6 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: asyncdata.c,v 1.2.2.7 2005/11/13 23:05:18 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
@@ -45,7 +41,7 @@ static inline int muststuff(unsigned char c)
* number of processed bytes
*/
static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
- struct inbuf_t *inbuf)
+ struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
unsigned cbytes = cs->cbytes;
@@ -55,10 +51,11 @@ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
for (;;) {
cs->respdata[cbytes] = c;
if (c == 10 || c == 13) {
- dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
- __func__, cbytes);
+ gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
+ __func__, cbytes);
cs->cbytes = cbytes;
- gigaset_handle_modem_response(cs); /* can change cs->dle */
+ gigaset_handle_modem_response(cs); /* can change
+ cs->dle */
cbytes = 0;
if (cs->dle &&
@@ -71,7 +68,7 @@ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
if (cbytes < MAX_RESP_SIZE - 1)
cbytes++;
else
- warn("response too large");
+ dev_warn(cs->dev, "response too large\n");
}
if (!numbytes)
@@ -96,11 +93,12 @@ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
* number of processed bytes
*/
static inline int lock_loop(unsigned char *src, int numbytes,
- struct inbuf_t *inbuf)
+ struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
- gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src, 0);
+ gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
+ numbytes, src);
gigaset_if_receive(cs, src, numbytes);
return numbytes;
@@ -115,24 +113,18 @@ static inline int lock_loop(unsigned char *src, int numbytes,
* numbytes (all bytes processed) on error --FIXME
*/
static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
- struct inbuf_t *inbuf)
+ struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
struct bc_state *bcs = inbuf->bcs;
- int inputstate;
- __u16 fcs;
- struct sk_buff *skb;
+ int inputstate = bcs->inputstate;
+ __u16 fcs = bcs->fcs;
+ struct sk_buff *skb = bcs->skb;
unsigned char error;
struct sk_buff *compskb;
int startbytes = numbytes;
int l;
- IFNULLRETVAL(bcs, numbytes);
- inputstate = bcs->inputstate;
- fcs = bcs->fcs;
- skb = bcs->skb;
- IFNULLRETVAL(skb, numbytes);
-
if (unlikely(inputstate & INS_byte_stuff)) {
inputstate &= ~INS_byte_stuff;
goto byte_stuff;
@@ -156,39 +148,37 @@ byte_stuff:
c ^= PPP_TRANS;
#ifdef CONFIG_GIGASET_DEBUG
if (unlikely(!muststuff(c)))
- dbg(DEBUG_HDLC,
- "byte stuffed: 0x%02x", c);
+ gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
#endif
} else if (unlikely(c == PPP_FLAG)) {
if (unlikely(inputstate & INS_skip_frame)) {
if (!(inputstate & INS_have_data)) { /* 7E 7E */
- //dbg(DEBUG_HDLC, "(7e)7e------------------------");
#ifdef CONFIG_GIGASET_DEBUG
++bcs->emptycount;
#endif
} else
- dbg(DEBUG_HDLC,
+ gig_dbg(DEBUG_HDLC,
"7e----------------------------");
/* end of frame */
error = 1;
gigaset_rcv_error(NULL, cs, bcs);
} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
- //dbg(DEBUG_HDLC, "(7e)7e------------------------");
#ifdef CONFIG_GIGASET_DEBUG
++bcs->emptycount;
#endif
break;
} else {
- dbg(DEBUG_HDLC,
- "7e----------------------------");
+ gig_dbg(DEBUG_HDLC,
+ "7e----------------------------");
/* end of frame */
error = 0;
if (unlikely(fcs != PPP_GOODFCS)) {
- err("Packet checksum at %lu failed, "
- "packet is corrupted (%u bytes)!",
+ dev_err(cs->dev,
+ "Packet checksum at %lu failed, "
+ "packet is corrupted (%u bytes)!\n",
bcs->rcvbytes, skb->len);
compskb = NULL;
gigaset_rcv_error(compskb, cs, bcs);
@@ -202,9 +192,11 @@ byte_stuff:
skb = NULL;
inputstate |= INS_skip_frame;
if (l == 1) {
- err("invalid packet size (1)!");
+ dev_err(cs->dev,
+ "invalid packet size (1)!\n");
error = 1;
- gigaset_rcv_error(NULL, cs, bcs);
+ gigaset_rcv_error(NULL,
+ cs, bcs);
}
}
if (likely(!(error ||
@@ -227,7 +219,8 @@ byte_stuff:
} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
skb_reserve(skb, HW_HDR_LEN);
} else {
- warn("could not allocate new skb");
+ dev_warn(cs->dev,
+ "could not allocate new skb\n");
inputstate |= INS_skip_frame;
}
@@ -235,7 +228,7 @@ byte_stuff:
#ifdef CONFIG_GIGASET_DEBUG
} else if (unlikely(muststuff(c))) {
/* Should not happen. Possible after ZDLE=1<CR><LF>. */
- dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
+ gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
#endif
}
@@ -243,8 +236,8 @@ byte_stuff:
#ifdef CONFIG_GIGASET_DEBUG
if (unlikely(!(inputstate & INS_have_data))) {
- dbg(DEBUG_HDLC,
- "7e (%d x) ================", bcs->emptycount);
+ gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
+ bcs->emptycount);
bcs->emptycount = 0;
}
#endif
@@ -253,14 +246,13 @@ byte_stuff:
if (likely(!(inputstate & INS_skip_frame))) {
if (unlikely(skb->len == SBUFSIZE)) {
- warn("received packet too long");
+ dev_warn(cs->dev, "received packet too long\n");
dev_kfree_skb_any(skb);
skb = NULL;
inputstate |= INS_skip_frame;
break;
}
- *gigaset_skb_put_quick(skb, 1) = c;
- /* *__skb_put (skb, 1) = c; */
+ *__skb_put(skb, 1) = c;
fcs = crc_ccitt_byte(fcs, c);
}
@@ -289,19 +281,14 @@ byte_stuff:
* numbytes (all bytes processed) on error --FIXME
*/
static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
- struct inbuf_t *inbuf)
+ struct inbuf_t *inbuf)
{
struct cardstate *cs = inbuf->cs;
struct bc_state *bcs = inbuf->bcs;
- int inputstate;
- struct sk_buff *skb;
+ int inputstate = bcs->inputstate;
+ struct sk_buff *skb = bcs->skb;
int startbytes = numbytes;
- IFNULLRETVAL(bcs, numbytes);
- inputstate = bcs->inputstate;
- skb = bcs->skb;
- IFNULLRETVAL(skb, numbytes);
-
for (;;) {
/* add character */
inputstate |= INS_have_data;
@@ -309,13 +296,13 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
if (likely(!(inputstate & INS_skip_frame))) {
if (unlikely(skb->len == SBUFSIZE)) {
//FIXME just pass skb up and allocate a new one
- warn("received packet too long");
+ dev_warn(cs->dev, "received packet too long\n");
dev_kfree_skb_any(skb);
skb = NULL;
inputstate |= INS_skip_frame;
break;
}
- *gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c];
+ *__skb_put(skb, 1) = gigaset_invtab[c];
}
if (unlikely(!numbytes))
@@ -343,7 +330,7 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
!= NULL)) {
skb_reserve(skb, HW_HDR_LEN);
} else {
- warn("could not allocate new skb");
+ dev_warn(cs->dev, "could not allocate new skb\n");
inputstate |= INS_skip_frame;
}
}
@@ -364,13 +351,13 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
head = atomic_read(&inbuf->head);
tail = atomic_read(&inbuf->tail);
- dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+ gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head != tail) {
cs = inbuf->cs;
src = inbuf->data + head;
numbytes = (head > tail ? RBUFSIZE : tail) - head;
- dbg(DEBUG_INTR, "processing %u bytes", numbytes);
+ gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
while (numbytes) {
if (atomic_read(&cs->mstate) == MS_LOCKED) {
@@ -392,8 +379,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
if (!(inbuf->inputstate & INS_DLE_char)) {
- /* FIXME Einfach je nach Modus Funktionszeiger in cs setzen [hier+hdlc_loop]? */
- /* FIXME Spart folgendes "if" und ermoeglicht andere Protokolle */
+ /* FIXME use function pointers? */
if (inbuf->inputstate & INS_command)
procbytes = cmd_loop(c, src, numbytes, inbuf);
else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
@@ -403,13 +389,14 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
src += procbytes;
numbytes -= procbytes;
- } else { /* DLE-char */
+ } else { /* DLE char */
inbuf->inputstate &= ~INS_DLE_char;
switch (c) {
case 'X': /*begin of command*/
#ifdef CONFIG_GIGASET_DEBUG
if (inbuf->inputstate & INS_command)
- err("received <DLE> 'X' in command mode");
+ dev_err(cs->dev,
+ "received <DLE> 'X' in command mode\n");
#endif
inbuf->inputstate |=
INS_command | INS_DLE_command;
@@ -417,7 +404,8 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
case '.': /*end of command*/
#ifdef CONFIG_GIGASET_DEBUG
if (!(inbuf->inputstate & INS_command))
- err("received <DLE> '.' in hdlc mode");
+ dev_err(cs->dev,
+ "received <DLE> '.' in hdlc mode\n");
#endif
inbuf->inputstate &= cs->dle ?
~(INS_DLE_command|INS_command)
@@ -425,7 +413,9 @@ void gigaset_m10x_input(struct inbuf_t *inbuf)
break;
//case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
default:
- err("received 0x10 0x%02x!", (int) c);
+ dev_err(cs->dev,
+ "received 0x10 0x%02x!\n",
+ (int) c);
/* FIXME: reset driver?? */
}
}
@@ -444,7 +434,7 @@ nextbyte:
}
}
- dbg(DEBUG_INTR, "setting head to %u", head);
+ gig_dbg(DEBUG_INTR, "setting head to %u", head);
atomic_set(&inbuf->head, head);
}
}
@@ -479,14 +469,13 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
stuf_cnt++;
fcs = crc_ccitt_byte(fcs, *cp++);
}
- fcs ^= 0xffff; /* complement */
+ fcs ^= 0xffff; /* complement */
/* size of new buffer: original size + number of stuffing bytes
* + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
*/
hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
if (!hdlc_skb) {
- err("unable to allocate memory for HDLC encoding!");
dev_kfree_skb(skb);
return NULL;
}
@@ -508,7 +497,7 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
}
/* Finally add FCS (byte stuffed) and flag sequence */
- c = (fcs & 0x00ff); /* least significant byte first */
+ c = (fcs & 0x00ff); /* least significant byte first */
if (muststuff(c)) {
*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
c ^= PPP_TRANS;
@@ -546,7 +535,6 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
/* worst case: every byte must be stuffed */
iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
if (!iraw_skb) {
- err("unable to allocate memory for HDLC encoding!");
dev_kfree_skb(skb);
return NULL;
}
@@ -577,21 +565,23 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
*/
int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
{
- unsigned len;
-
- IFNULLRETVAL(bcs, -EFAULT);
- IFNULLRETVAL(skb, -EFAULT);
- len = skb->len;
+ unsigned len = skb->len;
+ unsigned long flags;
if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
else
skb = iraw_encode(skb, HW_HDR_LEN, 0);
- if (!skb)
+ if (!skb) {
+ err("unable to allocate memory for encoding!\n");
return -ENOMEM;
+ }
skb_queue_tail(&bcs->squeue, skb);
- tasklet_schedule(&bcs->cs->write_tasklet);
+ spin_lock_irqsave(&bcs->cs->lock, flags);
+ if (bcs->cs->connected)
+ tasklet_schedule(&bcs->cs->write_tasklet);
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
return len; /* ok so far */
}
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 31f0f07832bc..f86ed6af3aa2 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2001 by Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>,
- * Stefan Eilers <Eilers.Stefan@epost.de>.
+ * Stefan Eilers.
*
* Based on usb-gigaset.c.
*
@@ -13,10 +13,6 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: bas-gigaset.c,v 1.52.4.19 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
@@ -30,7 +26,7 @@
#include <linux/moduleparam.h>
/* Version Information */
-#define DRIVER_AUTHOR "Tilman Schmidt <tilman@imap.cc>, Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_AUTHOR "Tilman Schmidt <tilman@imap.cc>, Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers"
#define DRIVER_DESC "USB Driver for Gigaset 307x"
@@ -70,9 +66,6 @@ static struct usb_device_id gigaset_table [] = {
MODULE_DEVICE_TABLE(usb, gigaset_table);
-/* Get a minor range for your devices from the usb maintainer */
-#define USB_SKEL_MINOR_BASE 200
-
/*======================= local function prototypes =============================*/
/* This function is called if a new device is connected to the USB port. It
@@ -88,25 +81,25 @@ static void gigaset_disconnect(struct usb_interface *interface);
/*==============================================================================*/
struct bas_cardstate {
- struct usb_device *udev; /* USB device pointer */
- struct usb_interface *interface; /* interface for this device */
+ struct usb_device *udev; /* USB device pointer */
+ struct usb_interface *interface; /* interface for this device */
unsigned char minor; /* starting minor number */
- struct urb *urb_ctrl; /* control pipe default URB */
+ struct urb *urb_ctrl; /* control pipe default URB */
struct usb_ctrlrequest dr_ctrl;
struct timer_list timer_ctrl; /* control request timeout */
struct timer_list timer_atrdy; /* AT command ready timeout */
- struct urb *urb_cmd_out; /* for sending AT commands */
+ struct urb *urb_cmd_out; /* for sending AT commands */
struct usb_ctrlrequest dr_cmd_out;
int retry_cmd_out;
- struct urb *urb_cmd_in; /* for receiving AT replies */
+ struct urb *urb_cmd_in; /* for receiving AT replies */
struct usb_ctrlrequest dr_cmd_in;
struct timer_list timer_cmd_in; /* receive request timeout */
- unsigned char *rcvbuf; /* AT reply receive buffer */
+ unsigned char *rcvbuf; /* AT reply receive buffer */
- struct urb *urb_int_in; /* URB for interrupt pipe */
+ struct urb *urb_int_in; /* URB for interrupt pipe */
unsigned char int_in_buf[3];
spinlock_t lock; /* locks all following */
@@ -208,53 +201,54 @@ static inline char *usb_pipetype_str(int pipe)
* write content of URB to syslog for debugging
*/
static inline void dump_urb(enum debuglevel level, const char *tag,
- struct urb *urb)
+ struct urb *urb)
{
#ifdef CONFIG_GIGASET_DEBUG
int i;
- IFNULLRET(tag);
- dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb);
+ gig_dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb);
if (urb) {
- dbg(level,
- " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
- "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
- (unsigned long) urb->dev,
- usb_pipetype_str(urb->pipe),
- usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
- urb->status, (unsigned long) urb->hcpriv,
- urb->transfer_flags);
- dbg(level,
- " transfer_buffer=0x%08lx[%d], actual_length=%d, "
- "bandwidth=%d, setup_packet=0x%08lx,",
- (unsigned long) urb->transfer_buffer,
- urb->transfer_buffer_length, urb->actual_length,
- urb->bandwidth, (unsigned long) urb->setup_packet);
- dbg(level,
- " start_frame=%d, number_of_packets=%d, interval=%d, "
- "error_count=%d,",
- urb->start_frame, urb->number_of_packets, urb->interval,
- urb->error_count);
- dbg(level,
- " context=0x%08lx, complete=0x%08lx, iso_frame_desc[]={",
- (unsigned long) urb->context,
- (unsigned long) urb->complete);
+ gig_dbg(level,
+ " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, "
+ "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,",
+ (unsigned long) urb->dev,
+ usb_pipetype_str(urb->pipe),
+ usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->status, (unsigned long) urb->hcpriv,
+ urb->transfer_flags);
+ gig_dbg(level,
+ " transfer_buffer=0x%08lx[%d], actual_length=%d, "
+ "bandwidth=%d, setup_packet=0x%08lx,",
+ (unsigned long) urb->transfer_buffer,
+ urb->transfer_buffer_length, urb->actual_length,
+ urb->bandwidth, (unsigned long) urb->setup_packet);
+ gig_dbg(level,
+ " start_frame=%d, number_of_packets=%d, interval=%d, "
+ "error_count=%d,",
+ urb->start_frame, urb->number_of_packets, urb->interval,
+ urb->error_count);
+ gig_dbg(level,
+ " context=0x%08lx, complete=0x%08lx, "
+ "iso_frame_desc[]={",
+ (unsigned long) urb->context,
+ (unsigned long) urb->complete);
for (i = 0; i < urb->number_of_packets; i++) {
- struct usb_iso_packet_descriptor *pifd = &urb->iso_frame_desc[i];
- dbg(level,
- " {offset=%u, length=%u, actual_length=%u, "
- "status=%u}",
- pifd->offset, pifd->length, pifd->actual_length,
- pifd->status);
+ struct usb_iso_packet_descriptor *pifd
+ = &urb->iso_frame_desc[i];
+ gig_dbg(level,
+ " {offset=%u, length=%u, actual_length=%u, "
+ "status=%u}",
+ pifd->offset, pifd->length, pifd->actual_length,
+ pifd->status);
}
}
- dbg(level, "}}");
+ gig_dbg(level, "}}");
#endif
}
/* read/set modem control bits etc. (m10x only) */
static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
- unsigned new_state)
+ unsigned new_state)
{
return -EINVAL;
}
@@ -280,8 +274,8 @@ static inline void error_hangup(struct bc_state *bcs)
{
struct cardstate *cs = bcs->cs;
- dbg(DEBUG_ANY,
- "%s: scheduling HUP for channel %d", __func__, bcs->channel);
+ gig_dbg(DEBUG_ANY, "%s: scheduling HUP for channel %d",
+ __func__, bcs->channel);
if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) {
//FIXME what should we do?
@@ -301,22 +295,19 @@ static inline void error_hangup(struct bc_state *bcs)
static inline void error_reset(struct cardstate *cs)
{
//FIXME try to recover without bothering the user
- err("unrecoverable error - please disconnect the Gigaset base to reset");
+ dev_err(cs->dev,
+ "unrecoverable error - please disconnect Gigaset base to reset\n");
}
/* check_pending
* check for completion of pending control request
* parameter:
- * urb USB request block of completed request
- * urb->context = hardware specific controller state structure
+ * ucs hardware specific controller state structure
*/
static void check_pending(struct bas_cardstate *ucs)
{
unsigned long flags;
- IFNULLRET(ucs);
- IFNULLRET(cardstate);
-
spin_lock_irqsave(&ucs->lock, flags);
switch (ucs->pending) {
case 0:
@@ -336,8 +327,6 @@ static void check_pending(struct bas_cardstate *ucs)
case HD_CLOSE_ATCHANNEL:
if (!(atomic_read(&ucs->basstate) & BS_ATOPEN))
ucs->pending = 0;
- //wake_up_interruptible(cs->initwait);
- //FIXME need own wait queue?
break;
case HD_CLOSE_B1CHANNEL:
if (!(atomic_read(&ucs->basstate) & BS_B1OPEN))
@@ -354,7 +343,9 @@ static void check_pending(struct bas_cardstate *ucs)
* are handled separately and should never end up here
*/
default:
- warn("unknown pending request 0x%02x cleared", ucs->pending);
+ dev_warn(&ucs->interface->dev,
+ "unknown pending request 0x%02x cleared\n",
+ ucs->pending);
ucs->pending = 0;
}
@@ -372,27 +363,23 @@ static void check_pending(struct bas_cardstate *ucs)
static void cmd_in_timeout(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = cs->hw.bas;
unsigned long flags;
- IFNULLRET(cs);
- ucs = cs->hw.bas;
- IFNULLRET(ucs);
-
spin_lock_irqsave(&cs->lock, flags);
- if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
+ if (unlikely(!cs->connected)) {
+ gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__);
spin_unlock_irqrestore(&cs->lock, flags);
return;
}
if (!ucs->rcvbuf_size) {
- dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
+ gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
spin_unlock_irqrestore(&cs->lock, flags);
return;
}
spin_unlock_irqrestore(&cs->lock, flags);
- err("timeout reading AT response");
+ dev_err(cs->dev, "timeout reading AT response\n");
error_reset(cs); //FIXME retry?
}
@@ -412,18 +399,15 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs);
*/
static int atread_submit(struct cardstate *cs, int timeout)
{
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = cs->hw.bas;
int ret;
- IFNULLRETVAL(cs, -EINVAL);
- ucs = cs->hw.bas;
- IFNULLRETVAL(ucs, -EINVAL);
- IFNULLRETVAL(ucs->urb_cmd_in, -EINVAL);
-
- dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size);
+ gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
+ ucs->rcvbuf_size);
if (ucs->urb_cmd_in->status == -EINPROGRESS) {
- err("could not submit HD_READ_ATMESSAGE: URB busy");
+ dev_err(cs->dev,
+ "could not submit HD_READ_ATMESSAGE: URB busy\n");
return -EBUSY;
}
@@ -433,19 +417,19 @@ static int atread_submit(struct cardstate *cs, int timeout)
ucs->dr_cmd_in.wIndex = 0;
ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size);
usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev,
- usb_rcvctrlpipe(ucs->udev, 0),
- (unsigned char*) & ucs->dr_cmd_in,
- ucs->rcvbuf, ucs->rcvbuf_size,
- read_ctrl_callback, cs->inbuf);
+ usb_rcvctrlpipe(ucs->udev, 0),
+ (unsigned char*) & ucs->dr_cmd_in,
+ ucs->rcvbuf, ucs->rcvbuf_size,
+ read_ctrl_callback, cs->inbuf);
if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
- err("could not submit HD_READ_ATMESSAGE: %s",
- get_usb_statmsg(ret));
+ dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n",
+ get_usb_statmsg(ret));
return ret;
}
if (timeout > 0) {
- dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
+ gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10;
ucs->timer_cmd_in.data = (unsigned long) cs;
ucs->timer_cmd_in.function = cmd_in_timeout;
@@ -483,25 +467,14 @@ inline static void update_basstate(struct bas_cardstate *ucs,
*/
static void read_int_callback(struct urb *urb, struct pt_regs *regs)
{
- struct cardstate *cs;
- struct bas_cardstate *ucs;
+ struct cardstate *cs = urb->context;
+ struct bas_cardstate *ucs = cs->hw.bas;
struct bc_state *bcs;
unsigned long flags;
int status;
unsigned l;
int channel;
- IFNULLRET(urb);
- cs = (struct cardstate *) urb->context;
- IFNULLRET(cs);
- ucs = cs->hw.bas;
- IFNULLRET(ucs);
-
- if (unlikely(!atomic_read(&cs->connected))) {
- warn("%s: disconnected", __func__);
- return;
- }
-
switch (urb->status) {
case 0: /* success */
break;
@@ -509,11 +482,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
case -ECONNRESET: /* canceled (async) */
case -EINPROGRESS: /* pending */
/* ignore silently */
- dbg(DEBUG_USBREQ,
- "%s: %s", __func__, get_usb_statmsg(urb->status));
+ gig_dbg(DEBUG_USBREQ, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
return;
default: /* severe trouble */
- warn("interrupt read: %s", get_usb_statmsg(urb->status));
+ dev_warn(cs->dev, "interrupt read: %s\n",
+ get_usb_statmsg(urb->status));
//FIXME corrective action? resubmission always ok?
goto resubmit;
}
@@ -521,10 +495,9 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
l = (unsigned) ucs->int_in_buf[1] +
(((unsigned) ucs->int_in_buf[2]) << 8);
- dbg(DEBUG_USBREQ,
- "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", urb->actual_length,
- (int)ucs->int_in_buf[0], l,
- (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]);
+ gig_dbg(DEBUG_USBREQ, "<-------%d: 0x%02x (%u [0x%02x 0x%02x])",
+ urb->actual_length, (int)ucs->int_in_buf[0], l,
+ (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]);
channel = 0;
@@ -570,28 +543,30 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
case HD_B1_FLOW_CONTROL:
bcs = cs->bcs + channel;
atomic_add((l - BAS_NORMFRAME) * BAS_CORRFRAMES,
- &bcs->hw.bas->corrbytes);
- dbg(DEBUG_ISO,
- "Flow control (channel %d, sub %d): 0x%02x => %d",
- channel, bcs->hw.bas->numsub, l,
- atomic_read(&bcs->hw.bas->corrbytes));
+ &bcs->hw.bas->corrbytes);
+ gig_dbg(DEBUG_ISO,
+ "Flow control (channel %d, sub %d): 0x%02x => %d",
+ channel, bcs->hw.bas->numsub, l,
+ atomic_read(&bcs->hw.bas->corrbytes));
break;
case HD_RECEIVEATDATA_ACK: /* AT response ready to be received */
if (!l) {
- warn("HD_RECEIVEATDATA_ACK with length 0 ignored");
+ dev_warn(cs->dev,
+ "HD_RECEIVEATDATA_ACK with length 0 ignored\n");
break;
}
spin_lock_irqsave(&cs->lock, flags);
if (ucs->rcvbuf_size) {
spin_unlock_irqrestore(&cs->lock, flags);
- err("receive AT data overrun, %d bytes lost", l);
+ dev_err(cs->dev,
+ "receive AT data overrun, %d bytes lost\n", l);
error_reset(cs); //FIXME reschedule
break;
}
if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) {
spin_unlock_irqrestore(&cs->lock, flags);
- err("%s: out of memory, %d bytes lost", __func__, l);
+ dev_err(cs->dev, "out of memory, %d bytes lost\n", l);
error_reset(cs); //FIXME reschedule
break;
}
@@ -607,25 +582,28 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
break;
case HD_RESET_INTERRUPT_PIPE_ACK:
- dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK");
+ gig_dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK");
break;
case HD_SUSPEND_END:
- dbg(DEBUG_USBREQ, "HD_SUSPEND_END");
+ gig_dbg(DEBUG_USBREQ, "HD_SUSPEND_END");
break;
default:
- warn("unknown Gigaset signal 0x%02x (%u) ignored",
- (int) ucs->int_in_buf[0], l);
+ dev_warn(cs->dev,
+ "unknown Gigaset signal 0x%02x (%u) ignored\n",
+ (int) ucs->int_in_buf[0], l);
}
check_pending(ucs);
resubmit:
- status = usb_submit_urb(urb, SLAB_ATOMIC);
+ spin_lock_irqsave(&cs->lock, flags);
+ status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
+ spin_unlock_irqrestore(&cs->lock, flags);
if (unlikely(status)) {
- err("could not resubmit interrupt URB: %s",
- get_usb_statmsg(status));
+ dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
+ get_usb_statmsg(status));
error_reset(cs);
}
}
@@ -639,30 +617,22 @@ resubmit:
*/
static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
{
- struct cardstate *cs;
- struct bas_cardstate *ucs;
+ struct inbuf_t *inbuf = urb->context;
+ struct cardstate *cs = inbuf->cs;
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int have_data = 0;
unsigned numbytes;
unsigned long flags;
- struct inbuf_t *inbuf;
- int have_data = 0;
-
- IFNULLRET(urb);
- inbuf = (struct inbuf_t *) urb->context;
- IFNULLRET(inbuf);
- cs = inbuf->cs;
- IFNULLRET(cs);
- ucs = cs->hw.bas;
- IFNULLRET(ucs);
spin_lock_irqsave(&cs->lock, flags);
- if (!atomic_read(&cs->connected)) {
+ if (unlikely(!cs->connected)) {
warn("%s: disconnected", __func__);
spin_unlock_irqrestore(&cs->lock, flags);
return;
}
if (!ucs->rcvbuf_size) {
- warn("%s: no receive in progress", __func__);
+ dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
spin_unlock_irqrestore(&cs->lock, flags);
return;
}
@@ -673,12 +643,14 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
case 0: /* normal completion */
numbytes = urb->actual_length;
if (unlikely(numbytes == 0)) {
- warn("control read: empty block received");
+ dev_warn(cs->dev,
+ "control read: empty block received\n");
goto retry;
}
if (unlikely(numbytes != ucs->rcvbuf_size)) {
- warn("control read: received %d chars, expected %d",
- numbytes, ucs->rcvbuf_size);
+ dev_warn(cs->dev,
+ "control read: received %d chars, expected %d\n",
+ numbytes, ucs->rcvbuf_size);
if (numbytes > ucs->rcvbuf_size)
numbytes = ucs->rcvbuf_size;
}
@@ -698,23 +670,26 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
case -ECONNRESET: /* canceled (async) */
case -EINPROGRESS: /* pending */
/* no action necessary */
- dbg(DEBUG_USBREQ,
- "%s: %s", __func__, get_usb_statmsg(urb->status));
+ gig_dbg(DEBUG_USBREQ, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
break;
default: /* severe trouble */
- warn("control read: %s", get_usb_statmsg(urb->status));
+ dev_warn(cs->dev, "control read: %s\n",
+ get_usb_statmsg(urb->status));
retry:
if (ucs->retry_cmd_in++ < BAS_RETRY) {
- notice("control read: retry %d", ucs->retry_cmd_in);
+ dev_notice(cs->dev, "control read: retry %d\n",
+ ucs->retry_cmd_in);
if (atread_submit(cs, BAS_TIMEOUT) >= 0) {
/* resubmitted - bypass regular exit block */
spin_unlock_irqrestore(&cs->lock, flags);
return;
}
} else {
- err("control read: giving up after %d tries",
- ucs->retry_cmd_in);
+ dev_err(cs->dev,
+ "control read: giving up after %d tries\n",
+ ucs->retry_cmd_in);
}
error_reset(cs);
}
@@ -724,7 +699,7 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
ucs->rcvbuf_size = 0;
spin_unlock_irqrestore(&cs->lock, flags);
if (have_data) {
- dbg(DEBUG_INTR, "%s-->BH", __func__);
+ gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(cs);
}
}
@@ -743,21 +718,16 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
unsigned long flags;
int i, rc;
- IFNULLRET(urb);
- IFNULLRET(urb->context);
- IFNULLRET(cardstate);
-
/* status codes not worth bothering the tasklet with */
if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS)) {
- dbg(DEBUG_ISO,
- "%s: %s", __func__, get_usb_statmsg(urb->status));
+ urb->status == -EINPROGRESS)) {
+ gig_dbg(DEBUG_ISO, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
return;
}
- bcs = (struct bc_state *) urb->context;
+ bcs = urb->context;
ubc = bcs->hw.bas;
- IFNULLRET(ubc);
spin_lock_irqsave(&ubc->isoinlock, flags);
if (likely(ubc->isoindone == NULL)) {
@@ -777,14 +747,17 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
urb->iso_frame_desc[i].actual_length = 0;
}
if (likely(atomic_read(&ubc->running))) {
- urb->dev = bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */
+ /* urb->dev is clobbered by USB subsystem */
+ urb->dev = bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
urb->number_of_packets = BAS_NUMFRAMES;
- dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__);
+ gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit",
+ __func__);
rc = usb_submit_urb(urb, SLAB_ATOMIC);
if (unlikely(rc != 0)) {
- err("could not resubmit isochronous read URB: %s",
- get_usb_statmsg(rc));
+ dev_err(bcs->cs->dev,
+ "could not resubmit isochronous read "
+ "URB: %s\n", get_usb_statmsg(rc));
dump_urb(DEBUG_ISO, "isoc read", urb);
error_hangup(bcs);
}
@@ -806,23 +779,17 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
struct bas_bc_state *ubc;
unsigned long flags;
- IFNULLRET(urb);
- IFNULLRET(urb->context);
- IFNULLRET(cardstate);
-
/* status codes not worth bothering the tasklet with */
if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
- urb->status == -EINPROGRESS)) {
- dbg(DEBUG_ISO,
- "%s: %s", __func__, get_usb_statmsg(urb->status));
+ urb->status == -EINPROGRESS)) {
+ gig_dbg(DEBUG_ISO, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
return;
}
/* pass URB context to tasklet */
- ucx = (struct isow_urbctx_t *) urb->context;
- IFNULLRET(ucx->bcs);
+ ucx = urb->context;
ubc = ucx->bcs->hw.bas;
- IFNULLRET(ubc);
spin_lock_irqsave(&ubc->isooutlock, flags);
ubc->isooutovfl = ubc->isooutdone;
@@ -841,15 +808,11 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
*/
static int starturbs(struct bc_state *bcs)
{
+ struct bas_bc_state *ubc = bcs->hw.bas;
struct urb *urb;
- struct bas_bc_state *ubc;
int j, k;
int rc;
- IFNULLRETVAL(bcs, -EFAULT);
- ubc = bcs->hw.bas;
- IFNULLRETVAL(ubc, -EFAULT);
-
/* initialize L2 reception */
if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
bcs->inputstate |= INS_flag_hunt;
@@ -859,7 +822,7 @@ static int starturbs(struct bc_state *bcs)
for (k = 0; k < BAS_INURBS; k++) {
urb = ubc->isoinurbs[k];
if (!urb) {
- err("isoinurbs[%d]==NULL", k);
+ dev_err(bcs->cs->dev, "isoinurbs[%d]==NULL\n", k);
rc = -EFAULT;
goto error;
}
@@ -882,8 +845,9 @@ static int starturbs(struct bc_state *bcs)
dump_urb(DEBUG_ISO, "Initial isoc read", urb);
if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
- err("could not submit isochronous read URB %d: %s",
- k, get_usb_statmsg(rc));
+ dev_err(bcs->cs->dev,
+ "could not submit isochronous read URB %d: %s\n",
+ k, get_usb_statmsg(rc));
goto error;
}
}
@@ -895,7 +859,7 @@ static int starturbs(struct bc_state *bcs)
for (k = 0; k < BAS_OUTURBS; ++k) {
urb = ubc->isoouturbs[k].urb;
if (!urb) {
- err("isoouturbs[%d].urb==NULL", k);
+ dev_err(bcs->cs->dev, "isoouturbs[%d].urb==NULL\n", k);
rc = -EFAULT;
goto error;
}
@@ -922,8 +886,9 @@ static int starturbs(struct bc_state *bcs)
dump_urb(DEBUG_ISO, "Initial isoc write", urb);
rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC);
if (rc != 0) {
- err("could not submit isochronous write URB %d: %s",
- k, get_usb_statmsg(rc));
+ dev_err(bcs->cs->dev,
+ "could not submit isochronous write URB %d: %s\n",
+ k, get_usb_statmsg(rc));
goto error;
}
}
@@ -946,20 +911,20 @@ static void stopurbs(struct bas_bc_state *ubc)
{
int k, rc;
- IFNULLRET(ubc);
-
atomic_set(&ubc->running, 0);
for (k = 0; k < BAS_INURBS; ++k) {
rc = usb_unlink_urb(ubc->isoinurbs[k]);
- dbg(DEBUG_ISO, "%s: isoc input URB %d unlinked, result = %d",
- __func__, k, rc);
+ gig_dbg(DEBUG_ISO,
+ "%s: isoc input URB %d unlinked, result = %d",
+ __func__, k, rc);
}
for (k = 0; k < BAS_OUTURBS; ++k) {
rc = usb_unlink_urb(ubc->isoouturbs[k].urb);
- dbg(DEBUG_ISO, "%s: isoc output URB %d unlinked, result = %d",
- __func__, k, rc);
+ gig_dbg(DEBUG_ISO,
+ "%s: isoc output URB %d unlinked, result = %d",
+ __func__, k, rc);
}
}
@@ -977,19 +942,14 @@ static void stopurbs(struct bas_bc_state *ubc)
*/
static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
{
- struct urb *urb;
- struct bas_bc_state *ubc;
+ struct urb *urb = ucx->urb;
+ struct bas_bc_state *ubc = ucx->bcs->hw.bas;
struct usb_iso_packet_descriptor *ifd;
int corrbytes, nframe, rc;
+ unsigned long flags;
- IFNULLRETVAL(ucx, -EFAULT);
- urb = ucx->urb;
- IFNULLRETVAL(urb, -EFAULT);
- IFNULLRETVAL(ucx->bcs, -EFAULT);
- ubc = ucx->bcs->hw.bas;
- IFNULLRETVAL(ubc, -EFAULT);
-
- urb->dev = ucx->bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */
+ /* urb->dev is clobbered by USB subsystem */
+ urb->dev = ucx->bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = ubc->isooutbuf->data;
urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data);
@@ -1000,7 +960,8 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
/* compute frame length according to flow control */
ifd->length = BAS_NORMFRAME;
if ((corrbytes = atomic_read(&ubc->corrbytes)) != 0) {
- dbg(DEBUG_ISO, "%s: corrbytes=%d", __func__, corrbytes);
+ gig_dbg(DEBUG_ISO, "%s: corrbytes=%d",
+ __func__, corrbytes);
if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME)
corrbytes = BAS_HIGHFRAME - BAS_NORMFRAME;
else if (corrbytes < BAS_LOWFRAME - BAS_NORMFRAME)
@@ -1008,18 +969,21 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
ifd->length += corrbytes;
atomic_add(-corrbytes, &ubc->corrbytes);
}
- //dbg(DEBUG_ISO, "%s: frame %d length=%d", __func__, nframe, ifd->length);
/* retrieve block of data to send */
- ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf, ifd->length);
+ ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf,
+ ifd->length);
if (ifd->offset < 0) {
if (ifd->offset == -EBUSY) {
- dbg(DEBUG_ISO, "%s: buffer busy at frame %d",
- __func__, nframe);
- /* tasklet will be restarted from gigaset_send_skb() */
+ gig_dbg(DEBUG_ISO,
+ "%s: buffer busy at frame %d",
+ __func__, nframe);
+ /* tasklet will be restarted from
+ gigaset_send_skb() */
} else {
- err("%s: buffer error %d at frame %d",
- __func__, ifd->offset, nframe);
+ dev_err(ucx->bcs->cs->dev,
+ "%s: buffer error %d at frame %d\n",
+ __func__, ifd->offset, nframe);
return ifd->offset;
}
break;
@@ -1029,9 +993,14 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
ifd->actual_length = 0;
}
if ((urb->number_of_packets = nframe) > 0) {
- if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
- err("could not submit isochronous write URB: %s",
- get_usb_statmsg(rc));
+ spin_lock_irqsave(&ucx->bcs->cs->lock, flags);
+ rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
+ spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags);
+
+ if (rc) {
+ dev_err(ucx->bcs->cs->dev,
+ "could not submit isochronous write URB: %s\n",
+ get_usb_statmsg(rc));
dump_urb(DEBUG_ISO, "isoc write", urb);
return rc;
}
@@ -1048,9 +1017,9 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx)
*/
static void write_iso_tasklet(unsigned long data)
{
- struct bc_state *bcs;
- struct bas_bc_state *ubc;
- struct cardstate *cs;
+ struct bc_state *bcs = (struct bc_state *) data;
+ struct bas_bc_state *ubc = bcs->hw.bas;
+ struct cardstate *cs = bcs->cs;
struct isow_urbctx_t *done, *next, *ovfl;
struct urb *urb;
struct usb_iso_packet_descriptor *ifd;
@@ -1060,22 +1029,10 @@ static void write_iso_tasklet(unsigned long data)
struct sk_buff *skb;
int len;
- bcs = (struct bc_state *) data;
- IFNULLRET(bcs);
- ubc = bcs->hw.bas;
- IFNULLRET(ubc);
- cs = bcs->cs;
- IFNULLRET(cs);
-
/* loop while completed URBs arrive in time */
for (;;) {
- if (unlikely(!atomic_read(&cs->connected))) {
- warn("%s: disconnected", __func__);
- return;
- }
-
if (unlikely(!(atomic_read(&ubc->running)))) {
- dbg(DEBUG_ISO, "%s: not running", __func__);
+ gig_dbg(DEBUG_ISO, "%s: not running", __func__);
return;
}
@@ -1087,7 +1044,7 @@ static void write_iso_tasklet(unsigned long data)
ubc->isooutovfl = NULL;
spin_unlock_irqrestore(&ubc->isooutlock, flags);
if (ovfl) {
- err("isochronous write buffer underrun - buy a faster machine :-)");
+ dev_err(cs->dev, "isochronous write buffer underrun\n");
error_hangup(bcs);
break;
}
@@ -1110,7 +1067,8 @@ static void write_iso_tasklet(unsigned long data)
spin_unlock_irqrestore(&ubc->isooutlock, flags);
if (next) {
/* couldn't put it back */
- err("losing isochronous write URB");
+ dev_err(cs->dev,
+ "losing isochronous write URB\n");
error_hangup(bcs);
}
}
@@ -1123,22 +1081,25 @@ static void write_iso_tasklet(unsigned long data)
break;
case -EXDEV: /* inspect individual frames */
/* assumptions (for lack of documentation):
- * - actual_length bytes of the frame in error are successfully sent
+ * - actual_length bytes of the frame in error are
+ * successfully sent
* - all following frames are not sent at all
*/
- dbg(DEBUG_ISO, "%s: URB partially completed", __func__);
+ gig_dbg(DEBUG_ISO, "%s: URB partially completed",
+ __func__);
offset = done->limit; /* just in case */
for (i = 0; i < BAS_NUMFRAMES; i++) {
ifd = &urb->iso_frame_desc[i];
if (ifd->status ||
ifd->actual_length != ifd->length) {
- warn("isochronous write: frame %d: %s, "
- "only %d of %d bytes sent",
+ dev_warn(cs->dev,
+ "isochronous write: frame %d: %s, "
+ "only %d of %d bytes sent\n",
i, get_usb_statmsg(ifd->status),
ifd->actual_length, ifd->length);
offset = (ifd->offset +
- ifd->actual_length)
- % BAS_OUTBUFSIZE;
+ ifd->actual_length)
+ % BAS_OUTBUFSIZE;
break;
}
}
@@ -1148,25 +1109,26 @@ static void write_iso_tasklet(unsigned long data)
ifd = &urb->iso_frame_desc[i];
if (ifd->status != -EINPROGRESS
|| ifd->actual_length != 0) {
- warn("isochronous write: frame %d: %s, "
- "%d of %d bytes sent",
+ dev_warn(cs->dev,
+ "isochronous write: frame %d: %s, "
+ "%d of %d bytes sent\n",
i, get_usb_statmsg(ifd->status),
ifd->actual_length, ifd->length);
offset = (ifd->offset +
- ifd->actual_length)
- % BAS_OUTBUFSIZE;
+ ifd->actual_length)
+ % BAS_OUTBUFSIZE;
break;
}
}
#endif
break;
- case -EPIPE: //FIXME is this the code for "underrun"?
- err("isochronous write stalled");
+ case -EPIPE: //FIXME is this the code for "underrun"?
+ dev_err(cs->dev, "isochronous write stalled\n");
error_hangup(bcs);
break;
default: /* severe trouble */
- warn("isochronous write: %s",
- get_usb_statmsg(urb->status));
+ dev_warn(cs->dev, "isochronous write: %s\n",
+ get_usb_statmsg(urb->status));
}
/* mark the write buffer area covered by this URB as free */
@@ -1194,8 +1156,8 @@ static void write_iso_tasklet(unsigned long data)
if (gigaset_isoc_buildframe(bcs, skb->data, len) == -EAGAIN) {
/* insufficient buffer space, push back onto queue */
skb_queue_head(&bcs->squeue, skb);
- dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d",
- __func__, skb_queue_len(&bcs->squeue));
+ gig_dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d",
+ __func__, skb_queue_len(&bcs->squeue));
break;
}
skb_pull(skb, len);
@@ -1215,28 +1177,16 @@ static void write_iso_tasklet(unsigned long data)
*/
static void read_iso_tasklet(unsigned long data)
{
- struct bc_state *bcs;
- struct bas_bc_state *ubc;
- struct cardstate *cs;
+ struct bc_state *bcs = (struct bc_state *) data;
+ struct bas_bc_state *ubc = bcs->hw.bas;
+ struct cardstate *cs = bcs->cs;
struct urb *urb;
char *rcvbuf;
unsigned long flags;
int totleft, numbytes, offset, frame, rc;
- bcs = (struct bc_state *) data;
- IFNULLRET(bcs);
- ubc = bcs->hw.bas;
- IFNULLRET(ubc);
- cs = bcs->cs;
- IFNULLRET(cs);
-
/* loop while more completed URBs arrive in the meantime */
for (;;) {
- if (!atomic_read(&cs->connected)) {
- warn("%s: disconnected", __func__);
- return;
- }
-
/* retrieve URB */
spin_lock_irqsave(&ubc->isoinlock, flags);
if (!(urb = ubc->isoindone)) {
@@ -1245,38 +1195,45 @@ static void read_iso_tasklet(unsigned long data)
}
ubc->isoindone = NULL;
if (unlikely(ubc->loststatus != -EINPROGRESS)) {
- warn("isochronous read overrun, dropped URB with status: %s, %d bytes lost",
- get_usb_statmsg(ubc->loststatus), ubc->isoinlost);
+ dev_warn(cs->dev,
+ "isochronous read overrun, "
+ "dropped URB with status: %s, %d bytes lost\n",
+ get_usb_statmsg(ubc->loststatus),
+ ubc->isoinlost);
ubc->loststatus = -EINPROGRESS;
}
spin_unlock_irqrestore(&ubc->isoinlock, flags);
if (unlikely(!(atomic_read(&ubc->running)))) {
- dbg(DEBUG_ISO, "%s: channel not running, dropped URB with status: %s",
- __func__, get_usb_statmsg(urb->status));
+ gig_dbg(DEBUG_ISO,
+ "%s: channel not running, "
+ "dropped URB with status: %s",
+ __func__, get_usb_statmsg(urb->status));
return;
}
switch (urb->status) {
case 0: /* normal completion */
break;
- case -EXDEV: /* inspect individual frames (we do that anyway) */
- dbg(DEBUG_ISO, "%s: URB partially completed", __func__);
+ case -EXDEV: /* inspect individual frames
+ (we do that anyway) */
+ gig_dbg(DEBUG_ISO, "%s: URB partially completed",
+ __func__);
break;
case -ENOENT:
case -ECONNRESET:
- dbg(DEBUG_ISO, "%s: URB canceled", __func__);
+ gig_dbg(DEBUG_ISO, "%s: URB canceled", __func__);
continue; /* -> skip */
case -EINPROGRESS: /* huh? */
- dbg(DEBUG_ISO, "%s: URB still pending", __func__);
+ gig_dbg(DEBUG_ISO, "%s: URB still pending", __func__);
continue; /* -> skip */
case -EPIPE:
- err("isochronous read stalled");
+ dev_err(cs->dev, "isochronous read stalled\n");
error_hangup(bcs);
continue; /* -> skip */
default: /* severe trouble */
- warn("isochronous read: %s",
- get_usb_statmsg(urb->status));
+ dev_warn(cs->dev, "isochronous read: %s\n",
+ get_usb_statmsg(urb->status));
goto error;
}
@@ -1284,33 +1241,44 @@ static void read_iso_tasklet(unsigned long data)
totleft = urb->actual_length;
for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) {
if (unlikely(urb->iso_frame_desc[frame].status)) {
- warn("isochronous read: frame %d: %s",
- frame, get_usb_statmsg(urb->iso_frame_desc[frame].status));
+ dev_warn(cs->dev,
+ "isochronous read: frame %d: %s\n",
+ frame,
+ get_usb_statmsg(
+ urb->iso_frame_desc[frame].status));
break;
}
numbytes = urb->iso_frame_desc[frame].actual_length;
if (unlikely(numbytes > BAS_MAXFRAME)) {
- warn("isochronous read: frame %d: numbytes (%d) > BAS_MAXFRAME",
- frame, numbytes);
+ dev_warn(cs->dev,
+ "isochronous read: frame %d: "
+ "numbytes (%d) > BAS_MAXFRAME\n",
+ frame, numbytes);
break;
}
if (unlikely(numbytes > totleft)) {
- warn("isochronous read: frame %d: numbytes (%d) > totleft (%d)",
- frame, numbytes, totleft);
+ dev_warn(cs->dev,
+ "isochronous read: frame %d: "
+ "numbytes (%d) > totleft (%d)\n",
+ frame, numbytes, totleft);
break;
}
offset = urb->iso_frame_desc[frame].offset;
if (unlikely(offset + numbytes > BAS_INBUFSIZE)) {
- warn("isochronous read: frame %d: offset (%d) + numbytes (%d) > BAS_INBUFSIZE",
- frame, offset, numbytes);
+ dev_warn(cs->dev,
+ "isochronous read: frame %d: "
+ "offset (%d) + numbytes (%d) "
+ "> BAS_INBUFSIZE\n",
+ frame, offset, numbytes);
break;
}
gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs);
totleft -= numbytes;
}
if (unlikely(totleft > 0))
- warn("isochronous read: %d data bytes missing",
- totleft);
+ dev_warn(cs->dev,
+ "isochronous read: %d data bytes missing\n",
+ totleft);
error:
/* URB processed, resubmit */
@@ -1318,12 +1286,17 @@ static void read_iso_tasklet(unsigned long data)
urb->iso_frame_desc[frame].status = 0;
urb->iso_frame_desc[frame].actual_length = 0;
}
- urb->dev = bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */
+ /* urb->dev is clobbered by USB subsystem */
+ urb->dev = bcs->cs->hw.bas->udev;
urb->transfer_flags = URB_ISO_ASAP;
urb->number_of_packets = BAS_NUMFRAMES;
- if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) {
- err("could not resubmit isochronous read URB: %s",
- get_usb_statmsg(rc));
+ spin_lock_irqsave(&cs->lock, flags);
+ rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
+ spin_unlock_irqrestore(&cs->lock, flags);
+ if (rc) {
+ dev_err(cs->dev,
+ "could not resubmit isochronous read URB: %s\n",
+ get_usb_statmsg(rc));
dump_urb(DEBUG_ISO, "resubmit iso read", urb);
error_hangup(bcs);
}
@@ -1341,15 +1314,10 @@ static void read_iso_tasklet(unsigned long data)
static void req_timeout(unsigned long data)
{
struct bc_state *bcs = (struct bc_state *) data;
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = bcs->cs->hw.bas;
int pending;
unsigned long flags;
- IFNULLRET(bcs);
- IFNULLRET(bcs->cs);
- ucs = bcs->cs->hw.bas;
- IFNULLRET(ucs);
-
check_pending(ucs);
spin_lock_irqsave(&ucs->lock, flags);
@@ -1359,33 +1327,34 @@ static void req_timeout(unsigned long data)
switch (pending) {
case 0: /* no pending request */
- dbg(DEBUG_USBREQ, "%s: no request pending", __func__);
+ gig_dbg(DEBUG_USBREQ, "%s: no request pending", __func__);
break;
case HD_OPEN_ATCHANNEL:
- err("timeout opening AT channel");
+ dev_err(bcs->cs->dev, "timeout opening AT channel\n");
error_reset(bcs->cs);
break;
case HD_OPEN_B2CHANNEL:
case HD_OPEN_B1CHANNEL:
- err("timeout opening channel %d", bcs->channel + 1);
+ dev_err(bcs->cs->dev, "timeout opening channel %d\n",
+ bcs->channel + 1);
error_hangup(bcs);
break;
case HD_CLOSE_ATCHANNEL:
- err("timeout closing AT channel");
- //wake_up_interruptible(cs->initwait);
- //FIXME need own wait queue?
+ dev_err(bcs->cs->dev, "timeout closing AT channel\n");
break;
case HD_CLOSE_B2CHANNEL:
case HD_CLOSE_B1CHANNEL:
- err("timeout closing channel %d", bcs->channel + 1);
+ dev_err(bcs->cs->dev, "timeout closing channel %d\n",
+ bcs->channel + 1);
break;
default:
- warn("request 0x%02x timed out, clearing", pending);
+ dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
+ pending);
}
}
@@ -1398,18 +1367,14 @@ static void req_timeout(unsigned long data)
*/
static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
{
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = urb->context;
unsigned long flags;
- IFNULLRET(urb);
- IFNULLRET(urb->context);
- IFNULLRET(cardstate);
-
- ucs = (struct bas_cardstate *) urb->context;
spin_lock_irqsave(&ucs->lock, flags);
if (urb->status && ucs->pending) {
- err("control request 0x%02x failed: %s",
- ucs->pending, get_usb_statmsg(urb->status));
+ dev_err(&ucs->interface->dev,
+ "control request 0x%02x failed: %s\n",
+ ucs->pending, get_usb_statmsg(urb->status));
del_timer(&ucs->timer_ctrl);
ucs->pending = 0;
}
@@ -1438,28 +1403,25 @@ static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
*/
static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
{
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = bcs->cs->hw.bas;
int ret;
unsigned long flags;
- IFNULLRETVAL(bcs, -EINVAL);
- IFNULLRETVAL(bcs->cs, -EINVAL);
- ucs = bcs->cs->hw.bas;
- IFNULLRETVAL(ucs, -EINVAL);
- IFNULLRETVAL(ucs->urb_ctrl, -EINVAL);
-
- dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val);
+ gig_dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val);
spin_lock_irqsave(&ucs->lock, flags);
if (ucs->pending) {
spin_unlock_irqrestore(&ucs->lock, flags);
- err("submission of request 0x%02x failed: request 0x%02x still pending",
- req, ucs->pending);
+ dev_err(bcs->cs->dev,
+ "submission of request 0x%02x failed: "
+ "request 0x%02x still pending\n",
+ req, ucs->pending);
return -EBUSY;
}
if (ucs->urb_ctrl->status == -EINPROGRESS) {
spin_unlock_irqrestore(&ucs->lock, flags);
- err("could not submit request 0x%02x: URB busy", req);
+ dev_err(bcs->cs->dev,
+ "could not submit request 0x%02x: URB busy\n", req);
return -EBUSY;
}
@@ -1469,19 +1431,19 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
ucs->dr_ctrl.wIndex = 0;
ucs->dr_ctrl.wLength = 0;
usb_fill_control_urb(ucs->urb_ctrl, ucs->udev,
- usb_sndctrlpipe(ucs->udev, 0),
- (unsigned char*) &ucs->dr_ctrl, NULL, 0,
- write_ctrl_callback, ucs);
+ usb_sndctrlpipe(ucs->udev, 0),
+ (unsigned char*) &ucs->dr_ctrl, NULL, 0,
+ write_ctrl_callback, ucs);
if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) {
- err("could not submit request 0x%02x: %s",
- req, get_usb_statmsg(ret));
+ dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n",
+ req, get_usb_statmsg(ret));
spin_unlock_irqrestore(&ucs->lock, flags);
return ret;
}
ucs->pending = req;
if (timeout > 0) {
- dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
+ gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout);
ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10;
ucs->timer_ctrl.data = (unsigned long) bcs;
ucs->timer_ctrl.function = req_timeout;
@@ -1504,19 +1466,18 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
{
int req, ret;
- IFNULLRETVAL(bcs, -EINVAL);
-
if ((ret = starturbs(bcs)) < 0) {
- err("could not start isochronous I/O for channel %d",
- bcs->channel + 1);
+ dev_err(bcs->cs->dev,
+ "could not start isochronous I/O for channel %d\n",
+ bcs->channel + 1);
error_hangup(bcs);
return ret;
}
req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) {
- err("could not open channel %d: %s",
- bcs->channel + 1, get_usb_statmsg(ret));
+ dev_err(bcs->cs->dev, "could not open channel %d: %s\n",
+ bcs->channel + 1, get_usb_statmsg(ret));
stopurbs(bcs->hw.bas);
error_hangup(bcs);
}
@@ -1537,8 +1498,6 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
{
int req, ret;
- IFNULLRETVAL(bcs, -EINVAL);
-
if (!(atomic_read(&bcs->cs->hw.bas->basstate) &
(bcs->channel ? BS_B2OPEN : BS_B1OPEN))) {
/* channel not running: just signal common.c */
@@ -1548,8 +1507,9 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL;
if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0)
- err("could not submit HD_CLOSE_BxCHANNEL request: %s",
- get_usb_statmsg(ret));
+ dev_err(bcs->cs->dev,
+ "could not submit HD_CLOSE_BxCHANNEL request: %s\n",
+ get_usb_statmsg(ret));
return ret;
}
@@ -1564,17 +1524,13 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
*/
static void complete_cb(struct cardstate *cs)
{
- struct cmdbuf_t *cb;
-
- IFNULLRET(cs);
- cb = cs->cmdbuf;
- IFNULLRET(cb);
+ struct cmdbuf_t *cb = cs->cmdbuf;
/* unqueue completed buffer */
cs->cmdbytes -= cs->curlen;
- dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD,
- "write_command: sent %u bytes, %u left",
- cs->curlen, cs->cmdbytes);
+ gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD,
+ "write_command: sent %u bytes, %u left",
+ cs->curlen, cs->cmdbytes);
if ((cs->cmdbuf = cb->next) != NULL) {
cs->cmdbuf->prev = NULL;
cs->curlen = cs->cmdbuf->len;
@@ -1600,15 +1556,9 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len);
*/
static void write_command_callback(struct urb *urb, struct pt_regs *regs)
{
- struct cardstate *cs;
+ struct cardstate *cs = urb->context;
+ struct bas_cardstate *ucs = cs->hw.bas;
unsigned long flags;
- struct bas_cardstate *ucs;
-
- IFNULLRET(urb);
- cs = (struct cardstate *) urb->context;
- IFNULLRET(cs);
- ucs = cs->hw.bas;
- IFNULLRET(ucs);
/* check status */
switch (urb->status) {
@@ -1618,22 +1568,27 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs)
case -ECONNRESET: /* canceled (async) */
case -EINPROGRESS: /* pending */
/* ignore silently */
- dbg(DEBUG_USBREQ,
- "%s: %s", __func__, get_usb_statmsg(urb->status));
+ gig_dbg(DEBUG_USBREQ, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
return;
default: /* any failure */
if (++ucs->retry_cmd_out > BAS_RETRY) {
- warn("command write: %s, giving up after %d retries",
- get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+ dev_warn(cs->dev,
+ "command write: %s, "
+ "giving up after %d retries\n",
+ get_usb_statmsg(urb->status),
+ ucs->retry_cmd_out);
break;
}
if (cs->cmdbuf == NULL) {
- warn("command write: %s, cannot retry - cmdbuf gone",
- get_usb_statmsg(urb->status));
+ dev_warn(cs->dev,
+ "command write: %s, "
+ "cannot retry - cmdbuf gone\n",
+ get_usb_statmsg(urb->status));
break;
}
- notice("command write: %s, retry %d",
- get_usb_statmsg(urb->status), ucs->retry_cmd_out);
+ dev_notice(cs->dev, "command write: %s, retry %d\n",
+ get_usb_statmsg(urb->status), ucs->retry_cmd_out);
if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0)
/* resubmitted - bypass regular exit block */
return;
@@ -1655,13 +1610,9 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs)
static void atrdy_timeout(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
- struct bas_cardstate *ucs;
-
- IFNULLRET(cs);
- ucs = cs->hw.bas;
- IFNULLRET(ucs);
+ struct bas_cardstate *ucs = cs->hw.bas;
- warn("timeout waiting for HD_READY_SEND_ATDATA");
+ dev_warn(cs->dev, "timeout waiting for HD_READY_SEND_ATDATA\n");
/* fake the missing signal - what else can I do? */
update_basstate(ucs, BS_ATREADY, BS_ATTIMER);
@@ -1682,18 +1633,15 @@ static void atrdy_timeout(unsigned long data)
*/
static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
{
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = cs->hw.bas;
+ unsigned long flags;
int ret;
- IFNULLRETVAL(cs, -EFAULT);
- ucs = cs->hw.bas;
- IFNULLRETVAL(ucs, -EFAULT);
- IFNULLRETVAL(ucs->urb_cmd_out, -EFAULT);
-
- dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len);
+ gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len);
if (ucs->urb_cmd_out->status == -EINPROGRESS) {
- err("could not submit HD_WRITE_ATMESSAGE: URB busy");
+ dev_err(cs->dev,
+ "could not submit HD_WRITE_ATMESSAGE: URB busy\n");
return -EBUSY;
}
@@ -1707,9 +1655,13 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
(unsigned char*) &ucs->dr_cmd_out, buf, len,
write_command_callback, cs);
- if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) {
- err("could not submit HD_WRITE_ATMESSAGE: %s",
- get_usb_statmsg(ret));
+ spin_lock_irqsave(&cs->lock, flags);
+ ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV;
+ spin_unlock_irqrestore(&cs->lock, flags);
+
+ if (ret) {
+ dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n",
+ get_usb_statmsg(ret));
return ret;
}
@@ -1718,8 +1670,8 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
/* start timeout if necessary */
if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) {
- dbg(DEBUG_OUTPUT,
- "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT);
+ gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs",
+ ATRDY_TIMEOUT);
ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10;
ucs->timer_atrdy.data = (unsigned long) cs;
ucs->timer_atrdy.function = atrdy_timeout;
@@ -1740,21 +1692,17 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len)
static int start_cbsend(struct cardstate *cs)
{
struct cmdbuf_t *cb;
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = cs->hw.bas;
unsigned long flags;
int rc;
int retval = 0;
- IFNULLRETVAL(cs, -EFAULT);
- ucs = cs->hw.bas;
- IFNULLRETVAL(ucs, -EFAULT);
-
/* check if AT channel is open */
if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
- dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, "AT channel not open");
+ gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT);
if (rc < 0) {
- err("could not open AT channel");
+ dev_err(cs->dev, "could not open AT channel\n");
/* flush command queue */
spin_lock_irqsave(&cs->cmdlock, flags);
while (cs->cmdbuf != NULL)
@@ -1792,27 +1740,23 @@ static int start_cbsend(struct cardstate *cs)
* cs controller state structure
* buf command string to send
* len number of bytes to send (max. IF_WRITEBUF)
- * wake_tasklet tasklet to run when transmission is completed (NULL if none)
+ * wake_tasklet tasklet to run when transmission is completed
+ * (NULL if none)
* return value:
* number of bytes queued on success
* error code < 0 on error
*/
static int gigaset_write_cmd(struct cardstate *cs,
- const unsigned char *buf, int len,
- struct tasklet_struct *wake_tasklet)
+ const unsigned char *buf, int len,
+ struct tasklet_struct *wake_tasklet)
{
struct cmdbuf_t *cb;
unsigned long flags;
int status;
gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
- DEBUG_TRANSCMD : DEBUG_LOCKCMD,
- "CMD Transmit", len, buf, 0);
-
- if (!atomic_read(&cs->connected)) {
- err("%s: not connected", __func__);
- return -ENODEV;
- }
+ DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+ "CMD Transmit", len, buf);
if (len <= 0)
return 0; /* nothing to do */
@@ -1820,7 +1764,7 @@ static int gigaset_write_cmd(struct cardstate *cs,
if (len > IF_WRITEBUF)
len = IF_WRITEBUF;
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
- err("%s: out of memory", __func__);
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
return -ENOMEM;
}
@@ -1849,7 +1793,8 @@ static int gigaset_write_cmd(struct cardstate *cs,
/* gigaset_write_room
* tty_driver.write_room interface routine
- * return number of characters the driver will accept to be written via gigaset_write_cmd
+ * return number of characters the driver will accept to be written via
+ * gigaset_write_cmd
* parameter:
* controller state structure
* return value:
@@ -1947,7 +1892,7 @@ static int gigaset_initbcshw(struct bc_state *bcs)
return 0;
}
tasklet_init(&ubc->sent_tasklet,
- &write_iso_tasklet, (unsigned long) bcs);
+ &write_iso_tasklet, (unsigned long) bcs);
spin_lock_init(&ubc->isoinlock);
for (i = 0; i < BAS_INURBS; ++i)
@@ -1968,7 +1913,7 @@ static int gigaset_initbcshw(struct bc_state *bcs)
ubc->shared0s = 0;
ubc->stolen0s = 0;
tasklet_init(&ubc->rcvd_tasklet,
- &read_iso_tasklet, (unsigned long) bcs);
+ &read_iso_tasklet, (unsigned long) bcs);
return 1;
}
@@ -2027,57 +1972,56 @@ static int gigaset_initcshw(struct cardstate *cs)
*/
static void freeurbs(struct cardstate *cs)
{
- struct bas_cardstate *ucs;
+ struct bas_cardstate *ucs = cs->hw.bas;
struct bas_bc_state *ubc;
int i, j;
- IFNULLRET(cs);
- ucs = cs->hw.bas;
- IFNULLRET(ucs);
-
for (j = 0; j < 2; ++j) {
ubc = cs->bcs[j].hw.bas;
- IFNULLCONT(ubc);
for (i = 0; i < BAS_OUTURBS; ++i)
if (ubc->isoouturbs[i].urb) {
usb_kill_urb(ubc->isoouturbs[i].urb);
- dbg(DEBUG_INIT,
- "%s: isoc output URB %d/%d unlinked",
- __func__, j, i);
+ gig_dbg(DEBUG_INIT,
+ "%s: isoc output URB %d/%d unlinked",
+ __func__, j, i);
usb_free_urb(ubc->isoouturbs[i].urb);
ubc->isoouturbs[i].urb = NULL;
}
for (i = 0; i < BAS_INURBS; ++i)
if (ubc->isoinurbs[i]) {
usb_kill_urb(ubc->isoinurbs[i]);
- dbg(DEBUG_INIT,
- "%s: isoc input URB %d/%d unlinked",
- __func__, j, i);
+ gig_dbg(DEBUG_INIT,
+ "%s: isoc input URB %d/%d unlinked",
+ __func__, j, i);
usb_free_urb(ubc->isoinurbs[i]);
ubc->isoinurbs[i] = NULL;
}
}
if (ucs->urb_int_in) {
usb_kill_urb(ucs->urb_int_in);
- dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", __func__);
+ gig_dbg(DEBUG_INIT, "%s: interrupt input URB unlinked",
+ __func__);
usb_free_urb(ucs->urb_int_in);
ucs->urb_int_in = NULL;
}
if (ucs->urb_cmd_out) {
usb_kill_urb(ucs->urb_cmd_out);
- dbg(DEBUG_INIT, "%s: command output URB unlinked", __func__);
+ gig_dbg(DEBUG_INIT, "%s: command output URB unlinked",
+ __func__);
usb_free_urb(ucs->urb_cmd_out);
ucs->urb_cmd_out = NULL;
}
if (ucs->urb_cmd_in) {
usb_kill_urb(ucs->urb_cmd_in);
- dbg(DEBUG_INIT, "%s: command input URB unlinked", __func__);
+ gig_dbg(DEBUG_INIT, "%s: command input URB unlinked",
+ __func__);
usb_free_urb(ucs->urb_cmd_in);
ucs->urb_cmd_in = NULL;
}
if (ucs->urb_ctrl) {
usb_kill_urb(ucs->urb_ctrl);
- dbg(DEBUG_INIT, "%s: control output URB unlinked", __func__);
+ gig_dbg(DEBUG_INIT, "%s: control output URB unlinked",
+ __func__);
usb_free_urb(ucs->urb_ctrl);
ucs->urb_ctrl = NULL;
}
@@ -2099,12 +2043,10 @@ static int gigaset_probe(struct usb_interface *interface,
int i, j;
int ret;
- IFNULLRETVAL(udev, -ENODEV);
-
- dbg(DEBUG_ANY,
- "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
- __func__, le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
+ gig_dbg(DEBUG_ANY,
+ "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
+ __func__, le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
/* See if the device offered us matches what we can accept */
if ((le16_to_cpu(udev->descriptor.idVendor) != USB_GIGA_VENDOR_ID) ||
@@ -2112,20 +2054,21 @@ static int gigaset_probe(struct usb_interface *interface,
le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID &&
le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID &&
le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) {
- dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__);
+ gig_dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__);
return -ENODEV;
}
/* set required alternate setting */
hostif = interface->cur_altsetting;
if (hostif->desc.bAlternateSetting != 3) {
- dbg(DEBUG_ANY,
- "%s: wrong alternate setting %d - trying to switch",
- __func__, hostif->desc.bAlternateSetting);
+ gig_dbg(DEBUG_ANY,
+ "%s: wrong alternate setting %d - trying to switch",
+ __func__, hostif->desc.bAlternateSetting);
if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) {
- warn("usb_set_interface failed, device %d interface %d altsetting %d",
- udev->devnum, hostif->desc.bInterfaceNumber,
- hostif->desc.bAlternateSetting);
+ dev_warn(&udev->dev, "usb_set_interface failed, "
+ "device %d interface %d altsetting %d\n",
+ udev->devnum, hostif->desc.bInterfaceNumber,
+ hostif->desc.bAlternateSetting);
return -ENODEV;
}
hostif = interface->cur_altsetting;
@@ -2134,23 +2077,28 @@ static int gigaset_probe(struct usb_interface *interface,
/* Reject application specific interfaces
*/
if (hostif->desc.bInterfaceClass != 255) {
- warn("%s: bInterfaceClass == %d",
- __func__, hostif->desc.bInterfaceClass);
+ dev_warn(&udev->dev, "%s: bInterfaceClass == %d\n",
+ __func__, hostif->desc.bInterfaceClass);
return -ENODEV;
}
- info("%s: Device matched (Vendor: 0x%x, Product: 0x%x)",
- __func__, le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
+ dev_info(&udev->dev,
+ "%s: Device matched (Vendor: 0x%x, Product: 0x%x)\n",
+ __func__, le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
cs = gigaset_getunassignedcs(driver);
if (!cs) {
- err("%s: no free cardstate", __func__);
+ dev_err(&udev->dev, "no free cardstate\n");
return -ENODEV;
}
ucs = cs->hw.bas;
+
+ /* save off device structure ptrs for later use */
+ usb_get_dev(udev);
ucs->udev = udev;
ucs->interface = interface;
+ cs->dev = &interface->dev;
/* allocate URBs:
* - one for the interrupt pipe
@@ -2159,22 +2107,22 @@ static int gigaset_probe(struct usb_interface *interface,
*/
ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL);
if (!ucs->urb_int_in) {
- err("No free urbs available");
+ dev_err(cs->dev, "no free urbs available\n");
goto error;
}
ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL);
if (!ucs->urb_cmd_in) {
- err("No free urbs available");
+ dev_err(cs->dev, "no free urbs available\n");
goto error;
}
ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL);
if (!ucs->urb_cmd_out) {
- err("No free urbs available");
+ dev_err(cs->dev, "no free urbs available\n");
goto error;
}
ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL);
if (!ucs->urb_ctrl) {
- err("No free urbs available");
+ dev_err(cs->dev, "no free urbs available\n");
goto error;
}
@@ -2184,7 +2132,7 @@ static int gigaset_probe(struct usb_interface *interface,
ubc->isoouturbs[i].urb =
usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
if (!ubc->isoouturbs[i].urb) {
- err("No free urbs available");
+ dev_err(cs->dev, "no free urbs available\n");
goto error;
}
}
@@ -2192,7 +2140,7 @@ static int gigaset_probe(struct usb_interface *interface,
ubc->isoinurbs[i] =
usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL);
if (!ubc->isoinurbs[i]) {
- err("No free urbs available");
+ dev_err(cs->dev, "no free urbs available\n");
goto error;
}
}
@@ -2204,13 +2152,14 @@ static int gigaset_probe(struct usb_interface *interface,
/* Fill the interrupt urb and send it to the core */
endpoint = &hostif->endpoint[0].desc;
usb_fill_int_urb(ucs->urb_int_in, udev,
- usb_rcvintpipe(udev,
- (endpoint->bEndpointAddress) & 0x0f),
- ucs->int_in_buf, 3, read_int_callback, cs,
- endpoint->bInterval);
+ usb_rcvintpipe(udev,
+ (endpoint->bEndpointAddress) & 0x0f),
+ ucs->int_in_buf, 3, read_int_callback, cs,
+ endpoint->bInterval);
ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL);
if (ret) {
- err("could not submit interrupt URB: %s", get_usb_statmsg(ret));
+ dev_err(cs->dev, "could not submit interrupt URB: %s\n",
+ get_usb_statmsg(ret));
goto error;
}
@@ -2221,18 +2170,18 @@ static int gigaset_probe(struct usb_interface *interface,
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
atomic_set(&cs->mstate, MS_LOCKED);
- if (!gigaset_start(cs))
- goto error;
/* save address of controller structure */
usb_set_intfdata(interface, cs);
- /* set up device sysfs */
- gigaset_init_dev_sysfs(interface);
+ if (!gigaset_start(cs))
+ goto error;
+
return 0;
error:
freeurbs(cs);
+ usb_set_intfdata(interface, NULL);
gigaset_unassign(cs);
return -ENODEV;
}
@@ -2245,23 +2194,22 @@ static void gigaset_disconnect(struct usb_interface *interface)
struct cardstate *cs;
struct bas_cardstate *ucs;
- /* clear device sysfs */
- gigaset_free_dev_sysfs(interface);
-
cs = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
- IFNULLRET(cs);
ucs = cs->hw.bas;
- IFNULLRET(ucs);
- info("disconnecting GigaSet base");
+ dev_info(cs->dev, "disconnecting Gigaset base\n");
gigaset_stop(cs);
freeurbs(cs);
+ usb_set_intfdata(interface, NULL);
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
atomic_set(&ucs->basstate, 0);
+ usb_put_dev(ucs->udev);
+ ucs->interface = NULL;
+ ucs->udev = NULL;
+ cs->dev = NULL;
gigaset_unassign(cs);
}
@@ -2293,13 +2241,14 @@ static int __init bas_gigaset_init(void)
/* allocate memory for our driver state and intialize it */
if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
- GIGASET_MODULENAME, GIGASET_DEVNAME,
- GIGASET_DEVFSNAME, &gigops,
- THIS_MODULE)) == NULL)
+ GIGASET_MODULENAME, GIGASET_DEVNAME,
+ GIGASET_DEVFSNAME, &gigops,
+ THIS_MODULE)) == NULL)
goto error;
/* allocate memory for our device state and intialize it */
- cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, GIGASET_MODULENAME);
+ cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode,
+ GIGASET_MODULENAME);
if (!cardstate)
goto error;
@@ -2329,19 +2278,18 @@ error: if (cardstate)
static void __exit bas_gigaset_exit(void)
{
gigaset_blockdriver(driver); /* => probe will fail
- * => no gigaset_start any more
- */
+ * => no gigaset_start any more
+ */
gigaset_shutdown(cardstate);
/* from now on, no isdn callback should be possible */
if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) {
- dbg(DEBUG_ANY, "closing AT channel");
+ gig_dbg(DEBUG_ANY, "closing AT channel");
if (req_submit(cardstate->bcs,
- HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) {
- /* successfully submitted - wait for completion */
- //wait_event_interruptible(cs->initwait, !cs->hw.bas->pending);
- //FIXME need own wait queue? wakeup?
+ HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) {
+ /* successfully submitted */
+ //FIXME wait for completion?
}
}
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 64371995c1a9..749b3da1236e 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -1,7 +1,7 @@
/*
* Stuff used by all variants of the driver
*
- * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ * Copyright (c) 2001 by Stefan Eilers,
* Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>.
*
@@ -11,10 +11,6 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: common.c,v 1.104.4.22 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
@@ -23,7 +19,7 @@
#include <linux/moduleparam.h>
/* Version Information */
-#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
#define DRIVER_DESC "Driver for Gigaset 307x"
/* Module parameters */
@@ -32,21 +28,10 @@ EXPORT_SYMBOL_GPL(gigaset_debuglevel);
module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "debug level");
-/*======================================================================
- Prototypes of internal functions
- */
-
-//static void gigaset_process_response(int resp_code, int parameter,
-// struct at_state_t *at_state,
-// unsigned char ** pstring);
-static struct cardstate *alloc_cs(struct gigaset_driver *drv);
-static void free_cs(struct cardstate *cs);
-static void make_valid(struct cardstate *cs, unsigned mask);
-static void make_invalid(struct cardstate *cs, unsigned mask);
-
-#define VALID_MINOR 0x01
-#define VALID_ID 0x02
-#define ASSIGNED 0x04
+/* driver state flags */
+#define VALID_MINOR 0x01
+#define VALID_ID 0x02
+#define ASSIGNED 0x04
/* bitwise byte inversion table */
__u8 gigaset_invtab[256] = {
@@ -86,42 +71,40 @@ __u8 gigaset_invtab[256] = {
EXPORT_SYMBOL_GPL(gigaset_invtab);
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
- size_t len, const unsigned char *buf, int from_user)
+ size_t len, const unsigned char *buf)
{
unsigned char outbuf[80];
- unsigned char inbuf[80 - 1];
- size_t numin;
- const unsigned char *in;
+ unsigned char c;
size_t space = sizeof outbuf - 1;
unsigned char *out = outbuf;
+ size_t numin = len;
- if (!from_user) {
- in = buf;
- numin = len;
- } else {
- numin = len < sizeof inbuf ? len : sizeof inbuf;
- in = inbuf;
- if (copy_from_user(inbuf, (const unsigned char __user *) buf, numin)) {
- strncpy(inbuf, "<FAULT>", sizeof inbuf);
- numin = sizeof "<FAULT>" - 1;
+ while (numin--) {
+ c = *buf++;
+ if (c == '~' || c == '^' || c == '\\') {
+ if (!space--)
+ break;
+ *out++ = '\\';
}
- }
-
- for (; numin && space; --numin, ++in) {
- --space;
- if (*in >= 32)
- *out++ = *in;
- else {
+ if (c & 0x80) {
+ if (!space--)
+ break;
+ *out++ = '~';
+ c ^= 0x80;
+ }
+ if (c < 0x20 || c == 0x7f) {
+ if (!space--)
+ break;
*out++ = '^';
- if (space) {
- *out++ = '@' + *in;
- --space;
- }
+ c ^= 0x40;
}
+ if (!space--)
+ break;
+ *out++ = c;
}
*out = 0;
- dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
+ gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
}
EXPORT_SYMBOL_GPL(gigaset_dbg_buffer);
@@ -146,11 +129,6 @@ int gigaset_enterconfigmode(struct cardstate *cs)
{
int i, r;
- if (!atomic_read(&cs->connected)) {
- err("not connected!");
- return -1;
- }
-
cs->control_state = TIOCM_RTS; //FIXME
r = setflags(cs, TIOCM_DTR, 200);
@@ -174,7 +152,7 @@ int gigaset_enterconfigmode(struct cardstate *cs)
return 0;
error:
- err("error %d on setuartbits!\n", -r);
+ dev_err(cs->dev, "error %d on setuartbits\n", -r);
cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value?
cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR);
@@ -187,13 +165,13 @@ static int test_timeout(struct at_state_t *at_state)
return 0;
if (--at_state->timer_expires) {
- dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
- at_state, at_state->timer_expires);
+ gig_dbg(DEBUG_MCMD, "decreased timer of %p to %lu",
+ at_state, at_state->timer_expires);
return 0;
}
if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL,
- atomic_read(&at_state->timer_index), NULL)) {
+ at_state->timer_index, NULL)) {
//FIXME what should we do?
}
@@ -221,10 +199,10 @@ static void timer_tick(unsigned long data)
if (test_timeout(at_state))
timeout = 1;
- if (atomic_read(&cs->running)) {
- mod_timer(&cs->timer, jiffies + GIG_TICK);
+ if (cs->running) {
+ mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK));
if (timeout) {
- dbg(DEBUG_CMD, "scheduling timeout");
+ gig_dbg(DEBUG_CMD, "scheduling timeout");
tasklet_schedule(&cs->event_tasklet);
}
}
@@ -238,13 +216,14 @@ int gigaset_get_channel(struct bc_state *bcs)
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->use_count) {
- dbg(DEBUG_ANY, "could not allocate channel %d", bcs->channel);
+ gig_dbg(DEBUG_ANY, "could not allocate channel %d",
+ bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return 0;
}
++bcs->use_count;
bcs->busy = 1;
- dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
+ gig_dbg(DEBUG_ANY, "allocated channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return 1;
}
@@ -255,13 +234,13 @@ void gigaset_free_channel(struct bc_state *bcs)
spin_lock_irqsave(&bcs->cs->lock, flags);
if (!bcs->busy) {
- dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
+ gig_dbg(DEBUG_ANY, "could not free channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
return;
}
--bcs->use_count;
bcs->busy = 0;
- dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
+ gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
}
@@ -274,14 +253,14 @@ int gigaset_get_channels(struct cardstate *cs)
for (i = 0; i < cs->channels; ++i)
if (cs->bcs[i].use_count) {
spin_unlock_irqrestore(&cs->lock, flags);
- dbg(DEBUG_ANY, "could not allocated all channels");
+ gig_dbg(DEBUG_ANY, "could not allocate all channels");
return 0;
}
for (i = 0; i < cs->channels; ++i)
++cs->bcs[i].use_count;
spin_unlock_irqrestore(&cs->lock, flags);
- dbg(DEBUG_ANY, "allocated all channels");
+ gig_dbg(DEBUG_ANY, "allocated all channels");
return 1;
}
@@ -291,7 +270,7 @@ void gigaset_free_channels(struct cardstate *cs)
unsigned long flags;
int i;
- dbg(DEBUG_ANY, "unblocking all channels");
+ gig_dbg(DEBUG_ANY, "unblocking all channels");
spin_lock_irqsave(&cs->lock, flags);
for (i = 0; i < cs->channels; ++i)
--cs->bcs[i].use_count;
@@ -303,7 +282,7 @@ void gigaset_block_channels(struct cardstate *cs)
unsigned long flags;
int i;
- dbg(DEBUG_ANY, "blocking all channels");
+ gig_dbg(DEBUG_ANY, "blocking all channels");
spin_lock_irqsave(&cs->lock, flags);
for (i = 0; i < cs->channels; ++i)
++cs->bcs[i].use_count;
@@ -314,25 +293,27 @@ static void clear_events(struct cardstate *cs)
{
struct event_t *ev;
unsigned head, tail;
+ unsigned long flags;
- /* no locking needed (no reader/writer allowed) */
+ spin_lock_irqsave(&cs->ev_lock, flags);
- head = atomic_read(&cs->ev_head);
- tail = atomic_read(&cs->ev_tail);
+ head = cs->ev_head;
+ tail = cs->ev_tail;
while (tail != head) {
ev = cs->events + head;
kfree(ev->ptr);
-
head = (head + 1) % MAX_EVENTS;
}
- atomic_set(&cs->ev_head, tail);
+ cs->ev_head = tail;
+
+ spin_unlock_irqrestore(&cs->ev_lock, flags);
}
struct event_t *gigaset_add_event(struct cardstate *cs,
- struct at_state_t *at_state, int type,
- void *ptr, int parameter, void *arg)
+ struct at_state_t *at_state, int type,
+ void *ptr, int parameter, void *arg)
{
unsigned long flags;
unsigned next, tail;
@@ -340,9 +321,9 @@ struct event_t *gigaset_add_event(struct cardstate *cs,
spin_lock_irqsave(&cs->ev_lock, flags);
- tail = atomic_read(&cs->ev_tail);
+ tail = cs->ev_tail;
next = (tail + 1) % MAX_EVENTS;
- if (unlikely(next == atomic_read(&cs->ev_head)))
+ if (unlikely(next == cs->ev_head))
err("event queue full");
else {
event = cs->events + tail;
@@ -352,7 +333,7 @@ struct event_t *gigaset_add_event(struct cardstate *cs,
event->ptr = ptr;
event->arg = arg;
event->parameter = parameter;
- atomic_set(&cs->ev_tail, next);
+ cs->ev_tail = next;
}
spin_unlock_irqrestore(&cs->ev_lock, flags);
@@ -391,14 +372,14 @@ static void gigaset_freebcs(struct bc_state *bcs)
{
int i;
- dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
+ gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel);
if (!bcs->cs->ops->freebcshw(bcs)) {
- dbg(DEBUG_INIT, "failed");
+ gig_dbg(DEBUG_INIT, "failed");
}
- dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
+ gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel);
clear_at_state(&bcs->at_state);
- dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
+ gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel);
if (bcs->skb)
dev_kfree_skb(bcs->skb);
@@ -408,6 +389,52 @@ static void gigaset_freebcs(struct bc_state *bcs)
}
}
+static struct cardstate *alloc_cs(struct gigaset_driver *drv)
+{
+ unsigned long flags;
+ unsigned i;
+ static struct cardstate *ret = NULL;
+
+ spin_lock_irqsave(&drv->lock, flags);
+ for (i = 0; i < drv->minors; ++i) {
+ if (!(drv->flags[i] & VALID_MINOR)) {
+ drv->flags[i] = VALID_MINOR;
+ ret = drv->cs + i;
+ }
+ if (ret)
+ break;
+ }
+ spin_unlock_irqrestore(&drv->lock, flags);
+ return ret;
+}
+
+static void free_cs(struct cardstate *cs)
+{
+ unsigned long flags;
+ struct gigaset_driver *drv = cs->driver;
+ spin_lock_irqsave(&drv->lock, flags);
+ drv->flags[cs->minor_index] = 0;
+ spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+static void make_valid(struct cardstate *cs, unsigned mask)
+{
+ unsigned long flags;
+ struct gigaset_driver *drv = cs->driver;
+ spin_lock_irqsave(&drv->lock, flags);
+ drv->flags[cs->minor_index] |= mask;
+ spin_unlock_irqrestore(&drv->lock, flags);
+}
+
+static void make_invalid(struct cardstate *cs, unsigned mask)
+{
+ unsigned long flags;
+ struct gigaset_driver *drv = cs->driver;
+ spin_lock_irqsave(&drv->lock, flags);
+ drv->flags[cs->minor_index] &= ~mask;
+ spin_unlock_irqrestore(&drv->lock, flags);
+}
+
void gigaset_freecs(struct cardstate *cs)
{
int i;
@@ -416,7 +443,7 @@ void gigaset_freecs(struct cardstate *cs)
if (!cs)
return;
- down(&cs->sem);
+ mutex_lock(&cs->mutex);
if (!cs->bcs)
goto f_cs;
@@ -424,8 +451,9 @@ void gigaset_freecs(struct cardstate *cs)
goto f_bcs;
spin_lock_irqsave(&cs->lock, flags);
- atomic_set(&cs->running, 0);
- spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are not rescheduled below */
+ cs->running = 0;
+ spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are
+ not rescheduled below */
tasklet_kill(&cs->event_tasklet);
del_timer_sync(&cs->timer);
@@ -434,7 +462,7 @@ void gigaset_freecs(struct cardstate *cs)
default:
gigaset_if_free(cs);
- dbg(DEBUG_INIT, "clearing hw");
+ gig_dbg(DEBUG_INIT, "clearing hw");
cs->ops->freecshw(cs);
//FIXME cmdbuf
@@ -443,36 +471,36 @@ void gigaset_freecs(struct cardstate *cs)
case 2: /* error in initcshw */
/* Deregister from LL */
make_invalid(cs, VALID_ID);
- dbg(DEBUG_INIT, "clearing iif");
+ gig_dbg(DEBUG_INIT, "clearing iif");
gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD);
/* fall through */
case 1: /* error when regestering to LL */
- dbg(DEBUG_INIT, "clearing at_state");
+ gig_dbg(DEBUG_INIT, "clearing at_state");
clear_at_state(&cs->at_state);
dealloc_at_states(cs);
/* fall through */
case 0: /* error in one call to initbcs */
for (i = 0; i < cs->channels; ++i) {
- dbg(DEBUG_INIT, "clearing bcs[%d]", i);
+ gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i);
gigaset_freebcs(cs->bcs + i);
}
clear_events(cs);
- dbg(DEBUG_INIT, "freeing inbuf");
+ gig_dbg(DEBUG_INIT, "freeing inbuf");
kfree(cs->inbuf);
}
-f_bcs: dbg(DEBUG_INIT, "freeing bcs[]");
+f_bcs: gig_dbg(DEBUG_INIT, "freeing bcs[]");
kfree(cs->bcs);
-f_cs: dbg(DEBUG_INIT, "freeing cs");
- up(&cs->sem);
+f_cs: gig_dbg(DEBUG_INIT, "freeing cs");
+ mutex_unlock(&cs->mutex);
free_cs(cs);
}
EXPORT_SYMBOL_GPL(gigaset_freecs);
void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
- struct cardstate *cs, int cid)
+ struct cardstate *cs, int cid)
{
int i;
@@ -482,8 +510,8 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
at_state->pending_commands = 0;
at_state->timer_expires = 0;
at_state->timer_active = 0;
- atomic_set(&at_state->timer_index, 0);
- atomic_set(&at_state->seq_index, 0);
+ at_state->timer_index = 0;
+ at_state->seq_index = 0;
at_state->ConState = 0;
for (i = 0; i < STR_NUM; ++i)
at_state->str_var[i] = NULL;
@@ -501,7 +529,7 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
- struct cardstate *cs, int inputstate)
+ struct cardstate *cs, int inputstate)
/* inbuf->read must be allocated before! */
{
atomic_set(&inbuf->head, 0);
@@ -512,9 +540,50 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
inbuf->inputstate = inputstate;
}
+/* append received bytes to inbuf */
+int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
+ unsigned numbytes)
+{
+ unsigned n, head, tail, bytesleft;
+
+ gig_dbg(DEBUG_INTR, "received %u bytes", numbytes);
+
+ if (!numbytes)
+ return 0;
+
+ bytesleft = numbytes;
+ tail = atomic_read(&inbuf->tail);
+ head = atomic_read(&inbuf->head);
+ gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+
+ while (bytesleft) {
+ if (head > tail)
+ n = head - 1 - tail;
+ else if (head == 0)
+ n = (RBUFSIZE-1) - tail;
+ else
+ n = RBUFSIZE - tail;
+ if (!n) {
+ dev_err(inbuf->cs->dev,
+ "buffer overflow (%u bytes lost)", bytesleft);
+ break;
+ }
+ if (n > bytesleft)
+ n = bytesleft;
+ memcpy(inbuf->data + tail, src, n);
+ bytesleft -= n;
+ tail = (tail + n) % RBUFSIZE;
+ src += n;
+ }
+ gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
+ atomic_set(&inbuf->tail, tail);
+ return numbytes != bytesleft;
+}
+EXPORT_SYMBOL_GPL(gigaset_fill_inbuf);
+
/* Initialize the b-channel structure */
static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
- struct cardstate *cs, int channel)
+ struct cardstate *cs, int channel)
{
int i;
@@ -526,7 +595,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
bcs->trans_down = 0;
bcs->trans_up = 0;
- dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
+ gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel);
gigaset_at_init(&bcs->at_state, bcs, cs, -1);
bcs->rcvbytes = 0;
@@ -535,7 +604,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
bcs->emptycount = 0;
#endif
- dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel);
+ gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel);
bcs->fcs = PPP_INITFCS;
bcs->inputstate = 0;
if (cs->ignoreframes) {
@@ -544,7 +613,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else {
- warn("could not allocate skb");
+ dev_warn(cs->dev, "could not allocate skb\n");
bcs->inputstate |= INS_skip_frame;
}
@@ -559,14 +628,13 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
for (i = 0; i < AT_NUM; ++i)
bcs->commands[i] = NULL;
- dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel);
+ gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel);
if (cs->ops->initbcshw(bcs))
return bcs;
-//error:
- dbg(DEBUG_INIT, " failed");
+ gig_dbg(DEBUG_INIT, " failed");
- dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel);
+ gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel);
if (bcs->skb)
dev_kfree_skb(bcs->skb);
@@ -578,9 +646,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
* Calls hardware dependent gigaset_initcshw() function
* Calls B channel initialization function gigaset_initbcs() for each B channel
* parameters:
- * drv hardware driver the device belongs to
+ * drv hardware driver the device belongs to
* channels number of B channels supported by device
- * onechannel !=0: B channel data and AT commands share one communication channel
+ * onechannel !=0: B channel data and AT commands share one
+ * communication channel
* ==0: B channels have separate communication channels
* ignoreframes number of frames to ignore after setting up B channel
* cidmode !=0: start in CallID mode
@@ -593,17 +662,18 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
int cidmode, const char *modulename)
{
struct cardstate *cs = NULL;
+ unsigned long flags;
int i;
- dbg(DEBUG_INIT, "allocating cs");
+ gig_dbg(DEBUG_INIT, "allocating cs");
cs = alloc_cs(drv);
if (!cs)
goto error;
- dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
+ gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
if (!cs->bcs)
goto error;
- dbg(DEBUG_INIT, "allocating inbuf");
+ gig_dbg(DEBUG_INIT, "allocating inbuf");
cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
if (!cs->inbuf)
goto error;
@@ -613,19 +683,23 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
cs->onechannel = onechannel;
cs->ignoreframes = ignoreframes;
INIT_LIST_HEAD(&cs->temp_at_states);
- atomic_set(&cs->running, 0);
+ cs->running = 0;
init_timer(&cs->timer); /* clear next & prev */
spin_lock_init(&cs->ev_lock);
- atomic_set(&cs->ev_tail, 0);
- atomic_set(&cs->ev_head, 0);
- init_MUTEX_LOCKED(&cs->sem);
- tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs);
+ cs->ev_tail = 0;
+ cs->ev_head = 0;
+ mutex_init(&cs->mutex);
+ mutex_lock(&cs->mutex);
+
+ tasklet_init(&cs->event_tasklet, &gigaset_handle_event,
+ (unsigned long) cs);
atomic_set(&cs->commands_pending, 0);
cs->cur_at_seq = 0;
cs->gotfwver = -1;
cs->open_count = 0;
+ cs->dev = NULL;
cs->tty = NULL;
- atomic_set(&cs->cidmode, cidmode != 0);
+ cs->cidmode = cidmode != 0;
//if(onechannel) { //FIXME
cs->tabnocid = gigaset_tab_nocid_m10x;
@@ -642,50 +716,43 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
atomic_set(&cs->mstate, MS_UNINITIALIZED);
for (i = 0; i < channels; ++i) {
- dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
+ gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
if (!gigaset_initbcs(cs->bcs + i, cs, i))
goto error;
}
++cs->cs_init;
- dbg(DEBUG_INIT, "setting up at_state");
+ gig_dbg(DEBUG_INIT, "setting up at_state");
spin_lock_init(&cs->lock);
gigaset_at_init(&cs->at_state, NULL, cs, 0);
cs->dle = 0;
cs->cbytes = 0;
- dbg(DEBUG_INIT, "setting up inbuf");
+ gig_dbg(DEBUG_INIT, "setting up inbuf");
if (onechannel) { //FIXME distinction necessary?
gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command);
} else
gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command);
- atomic_set(&cs->connected, 0);
+ cs->connected = 0;
+ cs->isdn_up = 0;
- dbg(DEBUG_INIT, "setting up cmdbuf");
+ gig_dbg(DEBUG_INIT, "setting up cmdbuf");
cs->cmdbuf = cs->lastcmdbuf = NULL;
spin_lock_init(&cs->cmdlock);
cs->curlen = 0;
cs->cmdbytes = 0;
- /*
- * Tell the ISDN4Linux subsystem (the LL) that
- * a driver for a USB-Device is available !
- * If this is done, "isdnctrl" is able to bind a device for this driver even
- * if no physical usb-device is currently connected.
- * But this device will just be accessable if a physical USB device is connected
- * (via "gigaset_probe") .
- */
- dbg(DEBUG_INIT, "setting up iif");
+ gig_dbg(DEBUG_INIT, "setting up iif");
if (!gigaset_register_to_LL(cs, modulename)) {
- err("register_isdn=>error");
+ err("register_isdn failed");
goto error;
}
make_valid(cs, VALID_ID);
++cs->cs_init;
- dbg(DEBUG_INIT, "setting up hw");
+ gig_dbg(DEBUG_INIT, "setting up hw");
if (!cs->ops->initcshw(cs))
goto error;
@@ -693,27 +760,29 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
gigaset_if_init(cs);
- atomic_set(&cs->running, 1);
- cs->timer.data = (unsigned long) cs;
- cs->timer.function = timer_tick;
- cs->timer.expires = jiffies + GIG_TICK;
+ spin_lock_irqsave(&cs->lock, flags);
+ cs->running = 1;
+ spin_unlock_irqrestore(&cs->lock, flags);
+ setup_timer(&cs->timer, timer_tick, (unsigned long) cs);
+ cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
/* FIXME: can jiffies increase too much until the timer is added?
* Same problem(?) with mod_timer() in timer_tick(). */
add_timer(&cs->timer);
- dbg(DEBUG_INIT, "cs initialized!");
- up(&cs->sem);
+ gig_dbg(DEBUG_INIT, "cs initialized");
+ mutex_unlock(&cs->mutex);
return cs;
error: if (cs)
- up(&cs->sem);
- dbg(DEBUG_INIT, "failed");
+ mutex_unlock(&cs->mutex);
+ gig_dbg(DEBUG_INIT, "failed");
gigaset_freecs(cs);
return NULL;
}
EXPORT_SYMBOL_GPL(gigaset_initcs);
-/* ReInitialize the b-channel structure */ /* e.g. called on hangup, disconnect */
+/* ReInitialize the b-channel structure */
+/* e.g. called on hangup, disconnect */
void gigaset_bcs_reinit(struct bc_state *bcs)
{
struct sk_buff *skb;
@@ -723,12 +792,12 @@ void gigaset_bcs_reinit(struct bc_state *bcs)
while ((skb = skb_dequeue(&bcs->squeue)) != NULL)
dev_kfree_skb(skb);
- spin_lock_irqsave(&cs->lock, flags); //FIXME
+ spin_lock_irqsave(&cs->lock, flags);
clear_at_state(&bcs->at_state);
bcs->at_state.ConState = 0;
bcs->at_state.timer_active = 0;
bcs->at_state.timer_expires = 0;
- bcs->at_state.cid = -1; /* No CID defined */
+ bcs->at_state.cid = -1; /* No CID defined */
spin_unlock_irqrestore(&cs->lock, flags);
bcs->inputstate = 0;
@@ -803,11 +872,14 @@ static void cleanup_cs(struct cardstate *cs)
int gigaset_start(struct cardstate *cs)
{
- if (down_interruptible(&cs->sem))
+ unsigned long flags;
+
+ if (mutex_lock_interruptible(&cs->mutex))
return 0;
- //info("USB device for Gigaset 307x now attached to Dev %d", ucs->minor);
- atomic_set(&cs->connected, 1);
+ spin_lock_irqsave(&cs->lock, flags);
+ cs->connected = 1;
+ spin_unlock_irqrestore(&cs->lock, flags);
if (atomic_read(&cs->mstate) != MS_LOCKED) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
@@ -826,23 +898,26 @@ int gigaset_start(struct cardstate *cs)
goto error;
}
- dbg(DEBUG_CMD, "scheduling START");
+ gig_dbg(DEBUG_CMD, "scheduling START");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
- up(&cs->sem);
+ /* set up device sysfs */
+ gigaset_init_dev_sysfs(cs);
+
+ mutex_unlock(&cs->mutex);
return 1;
error:
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(gigaset_start);
void gigaset_shutdown(struct cardstate *cs)
{
- down(&cs->sem);
+ mutex_lock(&cs->mutex);
cs->waiting = 1;
@@ -851,11 +926,11 @@ void gigaset_shutdown(struct cardstate *cs)
goto exit;
}
- dbg(DEBUG_CMD, "scheduling SHUTDOWN");
+ gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN");
gigaset_schedule_event(cs);
if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
- warn("aborted");
+ warn("%s: aborted", __func__);
//FIXME
}
@@ -872,15 +947,13 @@ void gigaset_shutdown(struct cardstate *cs)
cleanup_cs(cs);
exit:
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
}
EXPORT_SYMBOL_GPL(gigaset_shutdown);
void gigaset_stop(struct cardstate *cs)
{
- down(&cs->sem);
-
- atomic_set(&cs->connected, 0);
+ mutex_lock(&cs->mutex);
cs->waiting = 1;
@@ -889,21 +962,21 @@ void gigaset_stop(struct cardstate *cs)
goto exit;
}
- dbg(DEBUG_CMD, "scheduling STOP");
+ gig_dbg(DEBUG_CMD, "scheduling STOP");
gigaset_schedule_event(cs);
if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
- warn("aborted");
+ warn("%s: aborted", __func__);
//FIXME
}
- /* Tell the LL that the device is not available .. */
- gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer?
+ /* clear device sysfs */
+ gigaset_free_dev_sysfs(cs);
cleanup_cs(cs);
exit:
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
}
EXPORT_SYMBOL_GPL(gigaset_stop);
@@ -947,31 +1020,25 @@ void gigaset_debugdrivers(void)
spin_lock_irqsave(&driver_lock, flags);
list_for_each_entry(drv, &drivers, list) {
- dbg(DEBUG_DRIVER, "driver %p", drv);
+ gig_dbg(DEBUG_DRIVER, "driver %p", drv);
spin_lock(&drv->lock);
for (i = 0; i < drv->minors; ++i) {
- dbg(DEBUG_DRIVER, " index %u", i);
- dbg(DEBUG_DRIVER, " flags 0x%02x", drv->flags[i]);
+ gig_dbg(DEBUG_DRIVER, " index %u", i);
+ gig_dbg(DEBUG_DRIVER, " flags 0x%02x",
+ drv->flags[i]);
cs = drv->cs + i;
- dbg(DEBUG_DRIVER, " cardstate %p", cs);
- dbg(DEBUG_DRIVER, " minor_index %u", cs->minor_index);
- dbg(DEBUG_DRIVER, " driver %p", cs->driver);
- dbg(DEBUG_DRIVER, " i4l id %d", cs->myid);
+ gig_dbg(DEBUG_DRIVER, " cardstate %p", cs);
+ gig_dbg(DEBUG_DRIVER, " minor_index %u",
+ cs->minor_index);
+ gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver);
+ gig_dbg(DEBUG_DRIVER, " i4l id %d", cs->myid);
}
spin_unlock(&drv->lock);
}
spin_unlock_irqrestore(&driver_lock, flags);
}
-EXPORT_SYMBOL_GPL(gigaset_debugdrivers);
-
-struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
-{
- if (tty->index < 0 || tty->index >= tty->driver->num)
- return NULL;
- return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
-}
-struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
+static struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
{
unsigned long flags;
static struct cardstate *ret = NULL;
@@ -994,6 +1061,13 @@ struct cardstate *gigaset_get_cs_by_minor(unsigned minor)
return ret;
}
+struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
+{
+ if (tty->index < 0 || tty->index >= tty->driver->num)
+ return NULL;
+ return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
+}
+
void gigaset_freedriver(struct gigaset_driver *drv)
{
unsigned long flags;
@@ -1014,20 +1088,20 @@ EXPORT_SYMBOL_GPL(gigaset_freedriver);
/* gigaset_initdriver
* Allocate and initialize gigaset_driver structure. Initialize interface.
* parameters:
- * minor First minor number
- * minors Number of minors this driver can handle
- * procname Name of the driver (e.g. for /proc/tty/drivers, path in /proc/driver)
- * devname Name of the device files (prefix without minor number)
- * devfsname Devfs name of the device files without %d
+ * minor First minor number
+ * minors Number of minors this driver can handle
+ * procname Name of the driver
+ * devname Name of the device files (prefix without minor number)
+ * devfsname Devfs name of the device files without %d
* return value:
- * Pointer to the gigaset_driver structure on success, NULL on failure.
+ * Pointer to the gigaset_driver structure on success, NULL on failure.
*/
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
- const char *procname,
- const char *devname,
- const char *devfsname,
- const struct gigaset_ops *ops,
- struct module *owner)
+ const char *procname,
+ const char *devname,
+ const char *devfsname,
+ const struct gigaset_ops *ops,
+ struct module *owner)
{
struct gigaset_driver *drv;
unsigned long flags;
@@ -1036,8 +1110,9 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
drv = kmalloc(sizeof *drv, GFP_KERNEL);
if (!drv)
return NULL;
+
if (!try_module_get(owner))
- return NULL;
+ goto out1;
drv->cs = NULL;
drv->have_tty = 0;
@@ -1051,10 +1126,11 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL);
if (!drv->cs)
- goto out1;
+ goto out2;
+
drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL);
if (!drv->flags)
- goto out2;
+ goto out3;
for (i = 0; i < minors; ++i) {
drv->flags[i] = 0;
@@ -1071,61 +1147,16 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
return drv;
-out2:
+out3:
kfree(drv->cs);
+out2:
+ module_put(owner);
out1:
kfree(drv);
- module_put(owner);
return NULL;
}
EXPORT_SYMBOL_GPL(gigaset_initdriver);
-static struct cardstate *alloc_cs(struct gigaset_driver *drv)
-{
- unsigned long flags;
- unsigned i;
- static struct cardstate *ret = NULL;
-
- spin_lock_irqsave(&drv->lock, flags);
- for (i = 0; i < drv->minors; ++i) {
- if (!(drv->flags[i] & VALID_MINOR)) {
- drv->flags[i] = VALID_MINOR;
- ret = drv->cs + i;
- }
- if (ret)
- break;
- }
- spin_unlock_irqrestore(&drv->lock, flags);
- return ret;
-}
-
-static void free_cs(struct cardstate *cs)
-{
- unsigned long flags;
- struct gigaset_driver *drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] = 0;
- spin_unlock_irqrestore(&drv->lock, flags);
-}
-
-static void make_valid(struct cardstate *cs, unsigned mask)
-{
- unsigned long flags;
- struct gigaset_driver *drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] |= mask;
- spin_unlock_irqrestore(&drv->lock, flags);
-}
-
-static void make_invalid(struct cardstate *cs, unsigned mask)
-{
- unsigned long flags;
- struct gigaset_driver *drv = cs->driver;
- spin_lock_irqsave(&drv->lock, flags);
- drv->flags[cs->minor_index] &= ~mask;
- spin_unlock_irqrestore(&drv->lock, flags);
-}
-
/* For drivers without fixed assignment device<->cardstate (usb) */
struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv)
{
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index fdcb80bb21c7..1ba3424a286b 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -1,7 +1,7 @@
/*
* Stuff used by all variants of the driver
*
- * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ * Copyright (c) 2001 by Stefan Eilers,
* Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>.
*
@@ -11,82 +11,78 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: ev-layer.c,v 1.4.2.18 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
/* ========================================================== */
/* bit masks for pending commands */
-#define PC_INIT 0x004
-#define PC_DLE0 0x008
-#define PC_DLE1 0x010
-#define PC_CID 0x080
-#define PC_NOCID 0x100
-#define PC_HUP 0x002
-#define PC_DIAL 0x001
-#define PC_ACCEPT 0x040
-#define PC_SHUTDOWN 0x020
-#define PC_CIDMODE 0x200
-#define PC_UMMODE 0x400
+#define PC_DIAL 0x001
+#define PC_HUP 0x002
+#define PC_INIT 0x004
+#define PC_DLE0 0x008
+#define PC_DLE1 0x010
+#define PC_SHUTDOWN 0x020
+#define PC_ACCEPT 0x040
+#define PC_CID 0x080
+#define PC_NOCID 0x100
+#define PC_CIDMODE 0x200
+#define PC_UMMODE 0x400
/* types of modem responses */
-#define RT_NOTHING 0
-#define RT_ZSAU 1
-#define RT_RING 2
-#define RT_NUMBER 3
-#define RT_STRING 4
-#define RT_HEX 5
-#define RT_ZCAU 6
+#define RT_NOTHING 0
+#define RT_ZSAU 1
+#define RT_RING 2
+#define RT_NUMBER 3
+#define RT_STRING 4
+#define RT_HEX 5
+#define RT_ZCAU 6
/* Possible ASCII responses */
-#define RSP_OK 0
-//#define RSP_BUSY 1
-//#define RSP_CONNECT 2
-#define RSP_ZGCI 3
-#define RSP_RING 4
-#define RSP_ZAOC 5
-#define RSP_ZCSTR 6
-#define RSP_ZCFGT 7
-#define RSP_ZCFG 8
-#define RSP_ZCCR 9
-#define RSP_EMPTY 10
-#define RSP_ZLOG 11
-#define RSP_ZCAU 12
-#define RSP_ZMWI 13
-#define RSP_ZABINFO 14
-#define RSP_ZSMLSTCHG 15
-#define RSP_VAR 100
-#define RSP_ZSAU (RSP_VAR + VAR_ZSAU)
-#define RSP_ZDLE (RSP_VAR + VAR_ZDLE)
-#define RSP_ZVLS (RSP_VAR + VAR_ZVLS)
-#define RSP_ZCTP (RSP_VAR + VAR_ZCTP)
-#define RSP_STR (RSP_VAR + VAR_NUM)
-#define RSP_NMBR (RSP_STR + STR_NMBR)
-#define RSP_ZCPN (RSP_STR + STR_ZCPN)
-#define RSP_ZCON (RSP_STR + STR_ZCON)
-#define RSP_ZBC (RSP_STR + STR_ZBC)
-#define RSP_ZHLC (RSP_STR + STR_ZHLC)
-#define RSP_ERROR -1 /* ERROR */
-#define RSP_WRONG_CID -2 /* unknown cid in cmd */
-//#define RSP_EMPTY -3
-#define RSP_UNKNOWN -4 /* unknown response */
-#define RSP_FAIL -5 /* internal error */
-#define RSP_INVAL -6 /* invalid response */
-
-#define RSP_NONE -19
-#define RSP_STRING -20
-#define RSP_NULL -21
-//#define RSP_RETRYFAIL -22
-//#define RSP_RETRY -23
-//#define RSP_SKIP -24
-#define RSP_INIT -27
-#define RSP_ANY -26
-#define RSP_LAST -28
-#define RSP_NODEV -9
+#define RSP_OK 0
+//#define RSP_BUSY 1
+//#define RSP_CONNECT 2
+#define RSP_ZGCI 3
+#define RSP_RING 4
+#define RSP_ZAOC 5
+#define RSP_ZCSTR 6
+#define RSP_ZCFGT 7
+#define RSP_ZCFG 8
+#define RSP_ZCCR 9
+#define RSP_EMPTY 10
+#define RSP_ZLOG 11
+#define RSP_ZCAU 12
+#define RSP_ZMWI 13
+#define RSP_ZABINFO 14
+#define RSP_ZSMLSTCHG 15
+#define RSP_VAR 100
+#define RSP_ZSAU (RSP_VAR + VAR_ZSAU)
+#define RSP_ZDLE (RSP_VAR + VAR_ZDLE)
+#define RSP_ZVLS (RSP_VAR + VAR_ZVLS)
+#define RSP_ZCTP (RSP_VAR + VAR_ZCTP)
+#define RSP_STR (RSP_VAR + VAR_NUM)
+#define RSP_NMBR (RSP_STR + STR_NMBR)
+#define RSP_ZCPN (RSP_STR + STR_ZCPN)
+#define RSP_ZCON (RSP_STR + STR_ZCON)
+#define RSP_ZBC (RSP_STR + STR_ZBC)
+#define RSP_ZHLC (RSP_STR + STR_ZHLC)
+#define RSP_ERROR -1 /* ERROR */
+#define RSP_WRONG_CID -2 /* unknown cid in cmd */
+//#define RSP_EMPTY -3
+#define RSP_UNKNOWN -4 /* unknown response */
+#define RSP_FAIL -5 /* internal error */
+#define RSP_INVAL -6 /* invalid response */
+
+#define RSP_NONE -19
+#define RSP_STRING -20
+#define RSP_NULL -21
+//#define RSP_RETRYFAIL -22
+//#define RSP_RETRY -23
+//#define RSP_SKIP -24
+#define RSP_INIT -27
+#define RSP_ANY -26
+#define RSP_LAST -28
+#define RSP_NODEV -9
/* actions for process_response */
#define ACT_NOTHING 0
@@ -112,7 +108,7 @@
#define ACT_DISCONNECT 20
#define ACT_CONNECT 21
#define ACT_REMOTEREJECT 22
-#define ACT_CONNTIMEOUT 23
+#define ACT_CONNTIMEOUT 23
#define ACT_REMOTEHUP 24
#define ACT_ABORTHUP 25
#define ACT_ICALL 26
@@ -127,40 +123,40 @@
#define ACT_ERROR 35
#define ACT_ABORTCID 36
#define ACT_ZCAU 37
-#define ACT_NOTIFY_BC_DOWN 38
-#define ACT_NOTIFY_BC_UP 39
-#define ACT_DIAL 40
-#define ACT_ACCEPT 41
-#define ACT_PROTO_L2 42
-#define ACT_HUP 43
-#define ACT_IF_LOCK 44
-#define ACT_START 45
-#define ACT_STOP 46
-#define ACT_FAKEDLE0 47
-#define ACT_FAKEHUP 48
-#define ACT_FAKESDOWN 49
-#define ACT_SHUTDOWN 50
-#define ACT_PROC_CIDMODE 51
-#define ACT_UMODESET 52
-#define ACT_FAILUMODE 53
-#define ACT_CMODESET 54
-#define ACT_FAILCMODE 55
-#define ACT_IF_VER 56
+#define ACT_NOTIFY_BC_DOWN 38
+#define ACT_NOTIFY_BC_UP 39
+#define ACT_DIAL 40
+#define ACT_ACCEPT 41
+#define ACT_PROTO_L2 42
+#define ACT_HUP 43
+#define ACT_IF_LOCK 44
+#define ACT_START 45
+#define ACT_STOP 46
+#define ACT_FAKEDLE0 47
+#define ACT_FAKEHUP 48
+#define ACT_FAKESDOWN 49
+#define ACT_SHUTDOWN 50
+#define ACT_PROC_CIDMODE 51
+#define ACT_UMODESET 52
+#define ACT_FAILUMODE 53
+#define ACT_CMODESET 54
+#define ACT_FAILCMODE 55
+#define ACT_IF_VER 56
#define ACT_CMD 100
/* at command sequences */
-#define SEQ_NONE 0
-#define SEQ_INIT 100
-#define SEQ_DLE0 200
-#define SEQ_DLE1 250
-#define SEQ_CID 300
-#define SEQ_NOCID 350
-#define SEQ_HUP 400
-#define SEQ_DIAL 600
-#define SEQ_ACCEPT 720
-#define SEQ_SHUTDOWN 500
-#define SEQ_CIDMODE 10
-#define SEQ_UMMODE 11
+#define SEQ_NONE 0
+#define SEQ_INIT 100
+#define SEQ_DLE0 200
+#define SEQ_DLE1 250
+#define SEQ_CID 300
+#define SEQ_NOCID 350
+#define SEQ_HUP 400
+#define SEQ_DIAL 600
+#define SEQ_ACCEPT 720
+#define SEQ_SHUTDOWN 500
+#define SEQ_CIDMODE 10
+#define SEQ_UMMODE 11
// 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring
@@ -175,7 +171,7 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */
// {ACT_TIMEOUT}},
{RSP_INIT, -1, -1,SEQ_INIT, 100, INIT_TIMEOUT,
- {ACT_TIMEOUT}}, /* wait until device is ready */
+ {ACT_TIMEOUT}}, /* wait until device is ready */
{EV_TIMEOUT, 100,100, -1, 101, 3, {0}, "Z\r"}, /* device in transparent mode? try to initialize it. */
{RSP_OK, 101,103, -1, 120, 5, {ACT_GETSTRING}, "+GMR\r"}, /* get version */
@@ -190,8 +186,8 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */
{RSP_ERROR, 108,108, -1, 0, 0, {ACT_FAILINIT}},
{EV_TIMEOUT, 108,108, -1, 105, 2, {ACT_SETDLE0,
- ACT_HUPMODEM,
- ACT_TIMEOUT}}, /* still timeout => connection in unimodem mode? */
+ ACT_HUPMODEM,
+ ACT_TIMEOUT}}, /* still timeout => connection in unimodem mode? */
{EV_TIMEOUT, 105,105, -1, 103, 5, {0}, "Z\r"},
{RSP_ERROR, 102,102, -1, 107, 5, {0}, "^GETPRE\r"}, /* ERROR on ATZ => maybe in config mode? */
@@ -393,7 +389,7 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */
#if 0
-static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen uebernehmen
+static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME
{
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
@@ -401,7 +397,7 @@ static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen ueberne
{RSP_LAST,0,0,0,0,0,0}
};
-static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen uebernehmen
+static struct reply_t tab_cid[] = /* no dle mode */ //FIXME
{
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
@@ -412,30 +408,30 @@ static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen ueberneh
static struct resp_type_t resp_type[]=
{
- /*{"", RSP_EMPTY, RT_NOTHING},*/
- {"OK", RSP_OK, RT_NOTHING},
- {"ERROR", RSP_ERROR, RT_NOTHING},
- {"ZSAU", RSP_ZSAU, RT_ZSAU},
- {"ZCAU", RSP_ZCAU, RT_ZCAU},
- {"RING", RSP_RING, RT_RING},
- {"ZGCI", RSP_ZGCI, RT_NUMBER},
- {"ZVLS", RSP_ZVLS, RT_NUMBER},
- {"ZCTP", RSP_ZCTP, RT_NUMBER},
- {"ZDLE", RSP_ZDLE, RT_NUMBER},
- {"ZCFGT", RSP_ZCFGT, RT_NUMBER},
- {"ZCCR", RSP_ZCCR, RT_NUMBER},
- {"ZMWI", RSP_ZMWI, RT_NUMBER},
- {"ZHLC", RSP_ZHLC, RT_STRING},
- {"ZBC", RSP_ZBC, RT_STRING},
- {"NMBR", RSP_NMBR, RT_STRING},
- {"ZCPN", RSP_ZCPN, RT_STRING},
- {"ZCON", RSP_ZCON, RT_STRING},
- {"ZAOC", RSP_ZAOC, RT_STRING},
- {"ZCSTR", RSP_ZCSTR, RT_STRING},
- {"ZCFG", RSP_ZCFG, RT_HEX},
- {"ZLOG", RSP_ZLOG, RT_NOTHING},
- {"ZABINFO", RSP_ZABINFO, RT_NOTHING},
- {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING},
+ /*{"", RSP_EMPTY, RT_NOTHING},*/
+ {"OK", RSP_OK, RT_NOTHING},
+ {"ERROR", RSP_ERROR, RT_NOTHING},
+ {"ZSAU", RSP_ZSAU, RT_ZSAU},
+ {"ZCAU", RSP_ZCAU, RT_ZCAU},
+ {"RING", RSP_RING, RT_RING},
+ {"ZGCI", RSP_ZGCI, RT_NUMBER},
+ {"ZVLS", RSP_ZVLS, RT_NUMBER},
+ {"ZCTP", RSP_ZCTP, RT_NUMBER},
+ {"ZDLE", RSP_ZDLE, RT_NUMBER},
+ {"ZCFGT", RSP_ZCFGT, RT_NUMBER},
+ {"ZCCR", RSP_ZCCR, RT_NUMBER},
+ {"ZMWI", RSP_ZMWI, RT_NUMBER},
+ {"ZHLC", RSP_ZHLC, RT_STRING},
+ {"ZBC", RSP_ZBC, RT_STRING},
+ {"NMBR", RSP_NMBR, RT_STRING},
+ {"ZCPN", RSP_ZCPN, RT_STRING},
+ {"ZCON", RSP_ZCON, RT_STRING},
+ {"ZAOC", RSP_ZAOC, RT_STRING},
+ {"ZCSTR", RSP_ZCSTR, RT_STRING},
+ {"ZCFG", RSP_ZCFG, RT_HEX},
+ {"ZLOG", RSP_ZLOG, RT_NOTHING},
+ {"ZABINFO", RSP_ZABINFO, RT_NOTHING},
+ {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING},
{NULL,0,0}
};
@@ -446,9 +442,7 @@ static int isdn_getnum(char *p)
{
int v = -1;
- IFNULLRETVAL(p, -1);
-
- dbg(DEBUG_TRANSCMD, "string: %s", p);
+ gig_dbg(DEBUG_TRANSCMD, "string: %s", p);
while (*p >= '0' && *p <= '9')
v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0');
@@ -465,9 +459,7 @@ static int isdn_gethex(char *p)
int v = 0;
int c;
- IFNULLRETVAL(p, -1);
-
- dbg(DEBUG_TRANSCMD, "string: %s", p);
+ gig_dbg(DEBUG_TRANSCMD, "string: %s", p);
if (!*p)
return -1;
@@ -490,14 +482,6 @@ static int isdn_gethex(char *p)
return v;
}
-static inline void new_index(atomic_t *index, int max)
-{
- if (atomic_read(index) == max) //FIXME race?
- atomic_set(index, 0);
- else
- atomic_inc(index);
-}
-
/* retrieve CID from parsed response
* returns 0 if no CID, -1 if invalid CID, or CID value 1..65535
*/
@@ -536,16 +520,14 @@ void gigaset_handle_modem_response(struct cardstate *cs)
int cid;
int rawstring;
- IFNULLRET(cs);
-
len = cs->cbytes;
if (!len) {
/* ignore additional LFs/CRs (M10x config mode or cx100) */
- dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
+ gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]);
return;
}
cs->respdata[len] = 0;
- dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata);
+ gig_dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata);
argv[0] = cs->respdata;
params = 1;
if (cs->at_state.getstring) {
@@ -561,7 +543,8 @@ void gigaset_handle_modem_response(struct cardstate *cs)
case ',':
case '=':
if (params > MAX_REC_PARAMS) {
- warn("too many parameters in response");
+ dev_warn(cs->dev,
+ "too many parameters in response\n");
/* need last parameter (might be CID) */
params--;
}
@@ -572,33 +555,33 @@ void gigaset_handle_modem_response(struct cardstate *cs)
cid = params > 1 ? cid_of_response(argv[params-1]) : 0;
if (cid < 0) {
gigaset_add_event(cs, &cs->at_state, RSP_INVAL,
- NULL, 0, NULL);
+ NULL, 0, NULL);
return;
}
for (j = 1; j < params; ++j)
argv[j][-1] = 0;
- dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]);
+ gig_dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]);
if (cid) {
--params;
- dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]);
+ gig_dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]);
}
- dbg(DEBUG_TRANSCMD, "available params: %d", params - 1);
+ gig_dbg(DEBUG_TRANSCMD, "available params: %d", params - 1);
for (j = 1; j < params; j++)
- dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]);
+ gig_dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]);
}
spin_lock_irqsave(&cs->ev_lock, flags);
- head = atomic_read(&cs->ev_head);
- tail = atomic_read(&cs->ev_tail);
+ head = cs->ev_head;
+ tail = cs->ev_tail;
abort = 1;
curarg = 0;
while (curarg < params) {
next = (tail + 1) % MAX_EVENTS;
if (unlikely(next == head)) {
- err("event queue full");
+ dev_err(cs->dev, "event queue full\n");
break;
}
@@ -619,8 +602,9 @@ void gigaset_handle_modem_response(struct cardstate *cs)
if (!rt->response) {
event->type = RSP_UNKNOWN;
- warn("unknown modem response: %s",
- argv[curarg]);
+ dev_warn(cs->dev,
+ "unknown modem response: %s\n",
+ argv[curarg]);
break;
}
@@ -636,7 +620,8 @@ void gigaset_handle_modem_response(struct cardstate *cs)
break;
case RT_RING:
if (!cid) {
- err("received RING without CID!");
+ dev_err(cs->dev,
+ "received RING without CID!\n");
event->type = RSP_INVAL;
abort = 1;
} else {
@@ -664,27 +649,25 @@ void gigaset_handle_modem_response(struct cardstate *cs)
event->parameter = ZSAU_DISCONNECT_REQ;
else {
event->parameter = ZSAU_UNKNOWN;
- warn("%s: unknown parameter %s after ZSAU",
- __func__, argv[curarg]);
+ dev_warn(cs->dev,
+ "%s: unknown parameter %s after ZSAU\n",
+ __func__, argv[curarg]);
}
++curarg;
break;
case RT_STRING:
if (curarg < params) {
- len = strlen(argv[curarg]) + 1;
- event->ptr = kmalloc(len, GFP_ATOMIC);
- if (event->ptr)
- memcpy(event->ptr, argv[curarg], len);
- else
- err("no memory for string!");
+ event->ptr = kstrdup(argv[curarg], GFP_ATOMIC);
+ if (!event->ptr)
+ dev_err(cs->dev, "out of memory\n");
++curarg;
}
#ifdef CONFIG_GIGASET_DEBUG
if (!event->ptr)
- dbg(DEBUG_CMD, "string==NULL");
+ gig_dbg(DEBUG_CMD, "string==NULL");
else
- dbg(DEBUG_CMD,
- "string==%s", (char *) event->ptr);
+ gig_dbg(DEBUG_CMD, "string==%s",
+ (char *) event->ptr);
#endif
break;
case RT_ZCAU:
@@ -694,7 +677,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
j = isdn_gethex(argv[curarg + 1]);
if (i >= 0 && i < 256 && j >= 0 && j < 256)
event->parameter = (unsigned) i << 8
- | j;
+ | j;
curarg += 2;
} else
curarg = params - 1;
@@ -712,7 +695,7 @@ void gigaset_handle_modem_response(struct cardstate *cs)
} else
event->parameter = -1;
#ifdef CONFIG_GIGASET_DEBUG
- dbg(DEBUG_CMD, "parameter==%d", event->parameter);
+ gig_dbg(DEBUG_CMD, "parameter==%d", event->parameter);
#endif
break;
}
@@ -724,12 +707,13 @@ void gigaset_handle_modem_response(struct cardstate *cs)
break;
}
- atomic_set(&cs->ev_tail, tail);
+ cs->ev_tail = tail;
spin_unlock_irqrestore(&cs->ev_lock, flags);
if (curarg != params)
- dbg(DEBUG_ANY, "invalid number of processed parameters: %d/%d",
- curarg, params);
+ gig_dbg(DEBUG_ANY,
+ "invalid number of processed parameters: %d/%d",
+ curarg, params);
}
EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
@@ -739,23 +723,19 @@ EXPORT_SYMBOL_GPL(gigaset_handle_modem_response);
static void disconnect(struct at_state_t **at_state_p)
{
unsigned long flags;
- struct bc_state *bcs;
- struct cardstate *cs;
+ struct bc_state *bcs = (*at_state_p)->bcs;
+ struct cardstate *cs = (*at_state_p)->cs;
- IFNULLRET(at_state_p);
- IFNULLRET(*at_state_p);
- bcs = (*at_state_p)->bcs;
- cs = (*at_state_p)->cs;
- IFNULLRET(cs);
-
- new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX);
+ spin_lock_irqsave(&cs->lock, flags);
+ ++(*at_state_p)->seq_index;
/* revert to selected idle mode */
- if (!atomic_read(&cs->cidmode)) {
+ if (!cs->cidmode) {
cs->at_state.pending_commands |= PC_UMMODE;
atomic_set(&cs->commands_pending, 1); //FIXME
- dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+ gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
+ spin_unlock_irqrestore(&cs->lock, flags);
if (bcs) {
/* B channel assigned: invoke hardware specific handler */
@@ -777,7 +757,7 @@ static void disconnect(struct at_state_t **at_state_p)
* The structure should be freed by calling disconnect() after use.
*/
static inline struct at_state_t *get_free_channel(struct cardstate *cs,
- int cid)
+ int cid)
/* cids: >0: siemens-cid
0: without cid
-1: no cid assigned yet
@@ -826,7 +806,7 @@ static void init_failed(struct cardstate *cs, int mode)
static void schedule_init(struct cardstate *cs, int state)
{
if (cs->at_state.pending_commands & PC_INIT) {
- dbg(DEBUG_CMD, "not scheduling PC_INIT again");
+ gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again");
return;
}
atomic_set(&cs->mstate, state);
@@ -834,52 +814,56 @@ static void schedule_init(struct cardstate *cs, int state)
gigaset_block_channels(cs);
cs->at_state.pending_commands |= PC_INIT;
atomic_set(&cs->commands_pending, 1);
- dbg(DEBUG_CMD, "Scheduling PC_INIT");
+ gig_dbg(DEBUG_CMD, "Scheduling PC_INIT");
}
-/* Add "AT" to a command, add the cid, dle encode it, send the result to the hardware. */
+/* Add "AT" to a command, add the cid, dle encode it, send the result to the
+ hardware. */
static void send_command(struct cardstate *cs, const char *cmd, int cid,
- int dle, gfp_t kmallocflags)
+ int dle, gfp_t kmallocflags)
{
size_t cmdlen, buflen;
char *cmdpos, *cmdbuf, *cmdtail;
cmdlen = strlen(cmd);
buflen = 11 + cmdlen;
+ if (unlikely(buflen <= cmdlen)) {
+ dev_err(cs->dev, "integer overflow in buflen\n");
+ return;
+ }
- if (likely(buflen > cmdlen)) {
- cmdbuf = kmalloc(buflen, kmallocflags);
- if (likely(cmdbuf != NULL)) {
- cmdpos = cmdbuf + 9;
- cmdtail = cmdpos + cmdlen;
- memcpy(cmdpos, cmd, cmdlen);
-
- if (cid > 0 && cid <= 65535) {
- do {
- *--cmdpos = '0' + cid % 10;
- cid /= 10;
- ++cmdlen;
- } while (cid);
- }
+ cmdbuf = kmalloc(buflen, kmallocflags);
+ if (unlikely(!cmdbuf)) {
+ dev_err(cs->dev, "out of memory\n");
+ return;
+ }
- cmdlen += 2;
- *--cmdpos = 'T';
- *--cmdpos = 'A';
+ cmdpos = cmdbuf + 9;
+ cmdtail = cmdpos + cmdlen;
+ memcpy(cmdpos, cmd, cmdlen);
- if (dle) {
- cmdlen += 4;
- *--cmdpos = '(';
- *--cmdpos = 0x10;
- *cmdtail++ = 0x10;
- *cmdtail++ = ')';
- }
+ if (cid > 0 && cid <= 65535) {
+ do {
+ *--cmdpos = '0' + cid % 10;
+ cid /= 10;
+ ++cmdlen;
+ } while (cid);
+ }
- cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
- kfree(cmdbuf);
- } else
- err("no memory for command buffer");
- } else
- err("overflow in buflen");
+ cmdlen += 2;
+ *--cmdpos = 'T';
+ *--cmdpos = 'A';
+
+ if (dle) {
+ cmdlen += 4;
+ *--cmdpos = '(';
+ *--cmdpos = 0x10;
+ *cmdtail++ = 0x10;
+ *cmdtail++ = ')';
+ }
+
+ cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL);
+ kfree(cmdbuf);
}
static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
@@ -910,9 +894,6 @@ static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid)
static void bchannel_down(struct bc_state *bcs)
{
- IFNULLRET(bcs);
- IFNULLRET(bcs->cs);
-
if (bcs->chstate & CHS_B_UP) {
bcs->chstate &= ~CHS_B_UP;
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP);
@@ -930,16 +911,15 @@ static void bchannel_down(struct bc_state *bcs)
static void bchannel_up(struct bc_state *bcs)
{
- IFNULLRET(bcs);
-
if (!(bcs->chstate & CHS_D_UP)) {
- notice("%s: D channel not up", __func__);
+ dev_notice(bcs->cs->dev, "%s: D channel not up\n", __func__);
bcs->chstate |= CHS_D_UP;
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
}
if (bcs->chstate & CHS_B_UP) {
- notice("%s: B channel already up", __func__);
+ dev_notice(bcs->cs->dev, "%s: B channel already up\n",
+ __func__);
return;
}
@@ -947,17 +927,21 @@ static void bchannel_up(struct bc_state *bcs)
gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN);
}
-static void start_dial(struct at_state_t *at_state, void *data, int seq_index)
+static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index)
{
struct bc_state *bcs = at_state->bcs;
struct cardstate *cs = at_state->cs;
int retval;
+ unsigned long flags;
bcs->chstate |= CHS_NOTIFY_LL;
- //atomic_set(&bcs->status, BCS_INIT);
- if (atomic_read(&at_state->seq_index) != seq_index)
+ spin_lock_irqsave(&cs->lock, flags);
+ if (at_state->seq_index != seq_index) {
+ spin_unlock_irqrestore(&cs->lock, flags);
goto error;
+ }
+ spin_unlock_irqrestore(&cs->lock, flags);
retval = gigaset_isdn_setup_dial(at_state, data);
if (retval != 0)
@@ -965,20 +949,14 @@ static void start_dial(struct at_state_t *at_state, void *data, int seq_index)
at_state->pending_commands |= PC_CID;
- dbg(DEBUG_CMD, "Scheduling PC_CID");
-//#ifdef GIG_MAYINITONDIAL
-// if (atomic_read(&cs->MState) == MS_UNKNOWN) {
-// cs->at_state.pending_commands |= PC_INIT;
-// dbg(DEBUG_CMD, "Scheduling PC_INIT");
-// }
-//#endif
- atomic_set(&cs->commands_pending, 1); //FIXME
+ gig_dbg(DEBUG_CMD, "Scheduling PC_CID");
+ atomic_set(&cs->commands_pending, 1);
return;
error:
at_state->pending_commands |= PC_NOCID;
- dbg(DEBUG_CMD, "Scheduling PC_NOCID");
- atomic_set(&cs->commands_pending, 1); //FIXME
+ gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID");
+ atomic_set(&cs->commands_pending, 1);
return;
}
@@ -991,13 +969,13 @@ static void start_accept(struct at_state_t *at_state)
if (retval == 0) {
at_state->pending_commands |= PC_ACCEPT;
- dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
- atomic_set(&cs->commands_pending, 1); //FIXME
+ gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT");
+ atomic_set(&cs->commands_pending, 1);
} else {
//FIXME
at_state->pending_commands |= PC_HUP;
- dbg(DEBUG_CMD, "Scheduling PC_HUP");
- atomic_set(&cs->commands_pending, 1); //FIXME
+ gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
+ atomic_set(&cs->commands_pending, 1);
}
}
@@ -1008,9 +986,10 @@ static void do_start(struct cardstate *cs)
if (atomic_read(&cs->mstate) != MS_LOCKED)
schedule_init(cs, MS_INIT);
+ cs->isdn_up = 1;
gigaset_i4l_cmd(cs, ISDN_STAT_RUN);
- // FIXME: not in locked mode
- // FIXME 2: only after init sequence
+ // FIXME: not in locked mode
+ // FIXME 2: only after init sequence
cs->waiting = 0;
wake_up(&cs->waitqueue);
@@ -1023,6 +1002,12 @@ static void finish_shutdown(struct cardstate *cs)
atomic_set(&cs->mode, M_UNKNOWN);
}
+ /* Tell the LL that the device is not available .. */
+ if (cs->isdn_up) {
+ cs->isdn_up = 0;
+ gigaset_i4l_cmd(cs, ISDN_STAT_STOP);
+ }
+
/* The rest is done by cleanup_cs () in user mode. */
cs->cmd_result = -ENODEV;
@@ -1037,15 +1022,20 @@ static void do_shutdown(struct cardstate *cs)
if (atomic_read(&cs->mstate) == MS_READY) {
atomic_set(&cs->mstate, MS_SHUTDOWN);
cs->at_state.pending_commands |= PC_SHUTDOWN;
- atomic_set(&cs->commands_pending, 1); //FIXME
- dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); //FIXME
- //gigaset_schedule_event(cs); //FIXME
+ atomic_set(&cs->commands_pending, 1);
+ gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN");
} else
finish_shutdown(cs);
}
static void do_stop(struct cardstate *cs)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cs->lock, flags);
+ cs->connected = 0;
+ spin_unlock_irqrestore(&cs->lock, flags);
+
do_shutdown(cs);
}
@@ -1069,9 +1059,11 @@ static int reinit_and_retry(struct cardstate *cs, int channel)
return 0;
if (channel < 0)
- warn("Could not enter cid mode. Reinit device and try again.");
+ dev_warn(cs->dev,
+ "Could not enter cid mode. Reinit device and try again.\n");
else {
- warn("Could not get a call id. Reinit device and try again.");
+ dev_warn(cs->dev,
+ "Could not get a call id. Reinit device and try again.\n");
cs->bcs[channel].at_state.pending_commands |= PC_CID;
}
schedule_init(cs, MS_INIT);
@@ -1079,7 +1071,7 @@ static int reinit_and_retry(struct cardstate *cs, int channel)
}
static int at_state_invalid(struct cardstate *cs,
- struct at_state_t *test_ptr)
+ struct at_state_t *test_ptr)
{
unsigned long flags;
unsigned channel;
@@ -1116,7 +1108,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs,
case ICALL_ACCEPT:
break;
default:
- err("internal error: disposition=%d", retval);
+ dev_err(cs->dev, "internal error: disposition=%d\n", retval);
/* --v-- fall through --v-- */
case ICALL_IGNORE:
case ICALL_REJECT:
@@ -1160,7 +1152,6 @@ static int do_lock(struct cardstate *cs)
mode = atomic_read(&cs->mode);
atomic_set(&cs->mstate, MS_LOCKED);
atomic_set(&cs->mode, M_UNKNOWN);
- //FIXME reset card state / at states / bcs states
return mode;
}
@@ -1173,8 +1164,7 @@ static int do_unlock(struct cardstate *cs)
atomic_set(&cs->mstate, MS_UNINITIALIZED);
atomic_set(&cs->mode, M_UNKNOWN);
gigaset_free_channels(cs);
- //FIXME reset card state / at states / bcs states
- if (atomic_read(&cs->connected))
+ if (cs->connected)
schedule_init(cs, MS_INIT);
return 0;
@@ -1203,21 +1193,23 @@ static void do_action(int action, struct cardstate *cs,
at_state->waiting = 1;
break;
case ACT_INIT:
- //FIXME setup everything
cs->at_state.pending_commands &= ~PC_INIT;
cs->cur_at_seq = SEQ_NONE;
atomic_set(&cs->mode, M_UNIMODEM);
- if (!atomic_read(&cs->cidmode)) {
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!cs->cidmode) {
+ spin_unlock_irqrestore(&cs->lock, flags);
gigaset_free_channels(cs);
atomic_set(&cs->mstate, MS_READY);
break;
}
+ spin_unlock_irqrestore(&cs->lock, flags);
cs->at_state.pending_commands |= PC_CIDMODE;
- atomic_set(&cs->commands_pending, 1); //FIXME
- dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+ atomic_set(&cs->commands_pending, 1);
+ gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
break;
case ACT_FAILINIT:
- warn("Could not initialize the device.");
+ dev_warn(cs->dev, "Could not initialize the device.\n");
cs->dle = 0;
init_failed(cs, M_UNKNOWN);
cs->cur_at_seq = SEQ_NONE;
@@ -1273,8 +1265,8 @@ static void do_action(int action, struct cardstate *cs,
/* get fresh AT state structure for new CID */
at_state2 = get_free_channel(cs, ev->parameter);
if (!at_state2) {
- warn("RING ignored: "
- "could not allocate channel structure");
+ dev_warn(cs->dev,
+ "RING ignored: could not allocate channel structure\n");
break;
}
@@ -1302,7 +1294,7 @@ static void do_action(int action, struct cardstate *cs,
at_state = *p_at_state;
break;
case ACT_FAILSDOWN:
- warn("Could not shut down the device.");
+ dev_warn(cs->dev, "Could not shut down the device.\n");
/* fall through */
case ACT_FAKESDOWN:
case ACT_SDOWN:
@@ -1355,7 +1347,7 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_ABORTHUP:
cs->cur_at_seq = SEQ_NONE;
- warn("Could not hang up.");
+ dev_warn(cs->dev, "Could not hang up.\n");
at_state->cid = -1;
if (bcs && cs->onechannel)
at_state->pending_commands |= PC_DLE0;
@@ -1367,14 +1359,15 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_FAILDLE0:
cs->cur_at_seq = SEQ_NONE;
- warn("Could not leave DLE mode.");
+ dev_warn(cs->dev, "Could not leave DLE mode.\n");
at_state2 = &cs->bcs[cs->curchannel].at_state;
disconnect(&at_state2);
schedule_init(cs, MS_RECOVER);
break;
case ACT_FAILDLE1:
cs->cur_at_seq = SEQ_NONE;
- warn("Could not enter DLE mode. Try to hang up.");
+ dev_warn(cs->dev,
+ "Could not enter DLE mode. Trying to hang up.\n");
channel = cs->curchannel;
cs->bcs[channel].at_state.pending_commands |= PC_HUP;
atomic_set(&cs->commands_pending, 1);
@@ -1395,7 +1388,8 @@ static void do_action(int action, struct cardstate *cs,
cs->cur_at_seq = SEQ_NONE;
channel = cs->curchannel;
if (!reinit_and_retry(cs, channel)) {
- warn("Could not get a call id. Dialing not possible");
+ dev_warn(cs->dev,
+ "Could not get a call ID. Cannot dial.\n");
at_state2 = &cs->bcs[channel].at_state;
disconnect(&at_state2);
}
@@ -1428,7 +1422,8 @@ static void do_action(int action, struct cardstate *cs,
at_state->pending_commands |= PC_HUP;
atomic_set(&cs->commands_pending, 1);
break;
- case ACT_GETSTRING: /* warning: RING, ZDLE, ... are not handled properly any more */
+ case ACT_GETSTRING: /* warning: RING, ZDLE, ...
+ are not handled properly anymore */
at_state->getstring = 1;
break;
case ACT_SETVER:
@@ -1469,16 +1464,16 @@ static void do_action(int action, struct cardstate *cs,
case ACT_GOTVER:
if (cs->gotfwver == 0) {
cs->gotfwver = 1;
- dbg(DEBUG_ANY,
- "firmware version %02d.%03d.%02d.%02d",
- cs->fwver[0], cs->fwver[1],
- cs->fwver[2], cs->fwver[3]);
+ gig_dbg(DEBUG_ANY,
+ "firmware version %02d.%03d.%02d.%02d",
+ cs->fwver[0], cs->fwver[1],
+ cs->fwver[2], cs->fwver[3]);
break;
}
/* fall through */
case ACT_FAILVER:
cs->gotfwver = -1;
- err("could not read firmware version.");
+ dev_err(cs->dev, "could not read firmware version.\n");
break;
#ifdef CONFIG_GIGASET_DEBUG
case ACT_ERROR:
@@ -1496,16 +1491,16 @@ static void do_action(int action, struct cardstate *cs,
break;
#endif
case ACT_DEBUG:
- dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d",
+ gig_dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d",
__func__, ev->type, at_state->ConState);
break;
case ACT_WARN:
- warn("%s: resp_code %d in ConState %d!",
- __func__, ev->type, at_state->ConState);
+ dev_warn(cs->dev, "%s: resp_code %d in ConState %d!\n",
+ __func__, ev->type, at_state->ConState);
break;
case ACT_ZCAU:
- warn("cause code %04x in connection state %d.",
- ev->parameter, at_state->ConState);
+ dev_warn(cs->dev, "cause code %04x in connection state %d.\n",
+ ev->parameter, at_state->ConState);
break;
/* events from the LL */
@@ -1516,14 +1511,14 @@ static void do_action(int action, struct cardstate *cs,
start_accept(at_state);
break;
case ACT_PROTO_L2:
- dbg(DEBUG_CMD,
- "set protocol to %u", (unsigned) ev->parameter);
+ gig_dbg(DEBUG_CMD, "set protocol to %u",
+ (unsigned) ev->parameter);
at_state->bcs->proto2 = ev->parameter;
break;
case ACT_HUP:
at_state->pending_commands |= PC_HUP;
- atomic_set(&cs->commands_pending, 1); //FIXME
- dbg(DEBUG_CMD, "Scheduling PC_HUP");
+ atomic_set(&cs->commands_pending, 1);
+ gig_dbg(DEBUG_CMD, "Scheduling PC_HUP");
break;
/* hotplug events */
@@ -1555,17 +1550,19 @@ static void do_action(int action, struct cardstate *cs,
/* events from the proc file system */ // FIXME without ACT_xxxx?
case ACT_PROC_CIDMODE:
- if (ev->parameter != atomic_read(&cs->cidmode)) {
- atomic_set(&cs->cidmode, ev->parameter);
+ spin_lock_irqsave(&cs->lock, flags);
+ if (ev->parameter != cs->cidmode) {
+ cs->cidmode = ev->parameter;
if (ev->parameter) {
cs->at_state.pending_commands |= PC_CIDMODE;
- dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+ gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
} else {
cs->at_state.pending_commands |= PC_UMMODE;
- dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
+ gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE");
}
atomic_set(&cs->commands_pending, 1);
}
+ spin_unlock_irqrestore(&cs->lock, flags);
cs->waiting = 0;
wake_up(&cs->waitqueue);
break;
@@ -1590,7 +1587,7 @@ static void do_action(int action, struct cardstate *cs,
*p_resp_code = RSP_NULL;
}
} else
- err("%s: action==%d!", __func__, action);
+ dev_err(cs->dev, "%s: action==%d!\n", __func__, action);
}
}
@@ -1609,47 +1606,46 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
int curact;
unsigned long flags;
- IFNULLRET(cs);
- IFNULLRET(ev);
-
if (ev->cid >= 0) {
at_state = at_state_from_cid(cs, ev->cid);
if (!at_state) {
gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID,
- NULL, 0, NULL);
+ NULL, 0, NULL);
return;
}
} else {
at_state = ev->at_state;
if (at_state_invalid(cs, at_state)) {
- dbg(DEBUG_ANY,
- "event for invalid at_state %p", at_state);
+ gig_dbg(DEBUG_ANY, "event for invalid at_state %p",
+ at_state);
return;
}
}
- dbg(DEBUG_CMD,
- "connection state %d, event %d", at_state->ConState, ev->type);
+ gig_dbg(DEBUG_CMD, "connection state %d, event %d",
+ at_state->ConState, ev->type);
bcs = at_state->bcs;
sendcid = at_state->cid;
/* Setting the pointer to the dial array */
rep = at_state->replystruct;
- IFNULLRET(rep);
+ spin_lock_irqsave(&cs->lock, flags);
if (ev->type == EV_TIMEOUT) {
- if (ev->parameter != atomic_read(&at_state->timer_index)
+ if (ev->parameter != at_state->timer_index
|| !at_state->timer_active) {
ev->type = RSP_NONE; /* old timeout */
- dbg(DEBUG_ANY, "old timeout");
+ gig_dbg(DEBUG_ANY, "old timeout");
} else if (!at_state->waiting)
- dbg(DEBUG_ANY, "timeout occured");
+ gig_dbg(DEBUG_ANY, "timeout occurred");
else
- dbg(DEBUG_ANY, "stopped waiting");
+ gig_dbg(DEBUG_ANY, "stopped waiting");
}
+ spin_unlock_irqrestore(&cs->lock, flags);
- /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] or at_state->str_var[STR_XXXX], set it */
+ /* if the response belongs to a variable in at_state->int_var[VAR_XXXX]
+ or at_state->str_var[STR_XXXX], set it */
if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) {
index = ev->type - RSP_VAR;
at_state->int_var[index] = ev->parameter;
@@ -1657,20 +1653,22 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
index = ev->type - RSP_STR;
kfree(at_state->str_var[index]);
at_state->str_var[index] = ev->ptr;
- ev->ptr = NULL; /* prevent process_events() from deallocating ptr */
+ ev->ptr = NULL; /* prevent process_events() from
+ deallocating ptr */
}
if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING)
at_state->getstring = 0;
- /* Search row in dial array which matches modem response and current constate */
+ /* Search row in dial array which matches modem response and current
+ constate */
for (;; rep++) {
rcode = rep->resp_code;
- /* dbg (DEBUG_ANY, "rcode %d", rcode); */
if (rcode == RSP_LAST) {
/* found nothing...*/
- warn("%s: rcode=RSP_LAST: resp_code %d in ConState %d!",
- __func__, ev->type, at_state->ConState);
+ dev_warn(cs->dev, "%s: rcode=RSP_LAST: "
+ "resp_code %d in ConState %d!\n",
+ __func__, ev->type, at_state->ConState);
return;
}
if ((rcode == RSP_ANY || rcode == ev->type)
@@ -1706,14 +1704,14 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
} else {
/* Send command to modem if not NULL... */
if (p_command/*rep->command*/) {
- if (atomic_read(&cs->connected))
+ if (cs->connected)
send_command(cs, p_command,
- sendcid, cs->dle,
- GFP_ATOMIC);
+ sendcid, cs->dle,
+ GFP_ATOMIC);
else
gigaset_add_event(cs, at_state,
- RSP_NODEV,
- NULL, 0, NULL);
+ RSP_NODEV,
+ NULL, 0, NULL);
}
spin_lock_irqsave(&cs->lock, flags);
@@ -1723,8 +1721,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev)
} else if (rep->timeout > 0) { /* new timeout */
at_state->timer_expires = rep->timeout * 10;
at_state->timer_active = 1;
- new_index(&at_state->timer_index,
- MAX_TIMER_INDEX);
+ ++at_state->timer_index;
}
spin_unlock_irqrestore(&cs->lock, flags);
}
@@ -1744,17 +1741,16 @@ static void process_command_flags(struct cardstate *cs)
struct bc_state *bcs;
int i;
int sequence;
-
- IFNULLRET(cs);
+ unsigned long flags;
atomic_set(&cs->commands_pending, 0);
if (cs->cur_at_seq) {
- dbg(DEBUG_CMD, "not searching scheduled commands: busy");
+ gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy");
return;
}
- dbg(DEBUG_CMD, "searching scheduled commands");
+ gig_dbg(DEBUG_CMD, "searching scheduled commands");
sequence = SEQ_NONE;
@@ -1795,8 +1791,9 @@ static void process_command_flags(struct cardstate *cs)
}
/* only switch back to unimodem mode, if no commands are pending and no channels are up */
+ spin_lock_irqsave(&cs->lock, flags);
if (cs->at_state.pending_commands == PC_UMMODE
- && !atomic_read(&cs->cidmode)
+ && !cs->cidmode
&& list_empty(&cs->temp_at_states)
&& atomic_read(&cs->mode) == M_CID) {
sequence = SEQ_UMMODE;
@@ -1810,6 +1807,7 @@ static void process_command_flags(struct cardstate *cs)
}
}
}
+ spin_unlock_irqrestore(&cs->lock, flags);
cs->at_state.pending_commands &= ~PC_UMMODE;
if (sequence != SEQ_NONE) {
schedule_sequence(cs, at_state, sequence);
@@ -1865,11 +1863,7 @@ static void process_command_flags(struct cardstate *cs)
if (cs->at_state.pending_commands & PC_CIDMODE) {
cs->at_state.pending_commands &= ~PC_CIDMODE;
if (atomic_read(&cs->mode) == M_UNIMODEM) {
-#if 0
- cs->retry_count = 2;
-#else
cs->retry_count = 1;
-#endif
schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE);
return;
}
@@ -1897,7 +1891,7 @@ static void process_command_flags(struct cardstate *cs)
switch (atomic_read(&cs->mode)) {
case M_UNIMODEM:
cs->at_state.pending_commands |= PC_CIDMODE;
- dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
+ gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE");
atomic_set(&cs->commands_pending, 1);
return;
#ifdef GIG_MAYINITONDIAL
@@ -1926,18 +1920,21 @@ static void process_events(struct cardstate *cs)
int i;
int check_flags = 0;
int was_busy;
+ unsigned long flags;
- /* no locking needed (only one reader) */
- head = atomic_read(&cs->ev_head);
+ spin_lock_irqsave(&cs->ev_lock, flags);
+ head = cs->ev_head;
for (i = 0; i < 2 * MAX_EVENTS; ++i) {
- tail = atomic_read(&cs->ev_tail);
+ tail = cs->ev_tail;
if (tail == head) {
if (!check_flags && !atomic_read(&cs->commands_pending))
break;
check_flags = 0;
+ spin_unlock_irqrestore(&cs->ev_lock, flags);
process_command_flags(cs);
- tail = atomic_read(&cs->ev_tail);
+ spin_lock_irqsave(&cs->ev_lock, flags);
+ tail = cs->ev_tail;
if (tail == head) {
if (!atomic_read(&cs->commands_pending))
break;
@@ -1947,18 +1944,23 @@ static void process_events(struct cardstate *cs)
ev = cs->events + head;
was_busy = cs->cur_at_seq != SEQ_NONE;
+ spin_unlock_irqrestore(&cs->ev_lock, flags);
process_event(cs, ev);
+ spin_lock_irqsave(&cs->ev_lock, flags);
kfree(ev->ptr);
ev->ptr = NULL;
if (was_busy && cs->cur_at_seq == SEQ_NONE)
check_flags = 1;
head = (head + 1) % MAX_EVENTS;
- atomic_set(&cs->ev_head, head);
+ cs->ev_head = head;
}
+ spin_unlock_irqrestore(&cs->ev_lock, flags);
+
if (i == 2 * MAX_EVENTS) {
- err("infinite loop in process_events; aborting.");
+ dev_err(cs->dev,
+ "infinite loop in process_events; aborting.\n");
}
}
@@ -1970,12 +1972,9 @@ void gigaset_handle_event(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
- IFNULLRET(cs);
- IFNULLRET(cs->inbuf);
-
/* handle incoming data on control/common channel */
if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) {
- dbg(DEBUG_INTR, "processing new data");
+ gig_dbg(DEBUG_INTR, "processing new data");
cs->ops->handle_input(cs->inbuf);
}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 729edcdb6dac..9d21ba8757b0 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -1,11 +1,16 @@
-/* Siemens Gigaset 307x driver
+/*
+ * Siemens Gigaset 307x driver
* Common header file for all connection variants
*
- * Written by Stefan Eilers <Eilers.Stefan@epost.de>
+ * Written by Stefan Eilers
* and Hansjoerg Lipp <hjlipp@web.de>
*
- * Version: $Id: gigaset.h,v 1.97.4.26 2006/02/04 18:28:16 hjlipp Exp $
- * ===========================================================================
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ * =====================================================================
*/
#ifndef GIGASET_H
@@ -15,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/types.h>
-#include <asm/atomic.h>
#include <linux/spinlock.h>
#include <linux/isdnif.h>
#include <linux/usb.h>
@@ -27,21 +31,22 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/list.h>
+#include <asm/atomic.h>
#define GIG_VERSION {0,5,0,0}
#define GIG_COMPAT {0,4,0,0}
-#define MAX_REC_PARAMS 10 /* Max. number of params in response string */
-#define MAX_RESP_SIZE 512 /* Max. size of a response string */
-#define HW_HDR_LEN 2 /* Header size used to store ack info */
+#define MAX_REC_PARAMS 10 /* Max. number of params in response string */
+#define MAX_RESP_SIZE 512 /* Max. size of a response string */
+#define HW_HDR_LEN 2 /* Header size used to store ack info */
-#define MAX_EVENTS 64 /* size of event queue */
+#define MAX_EVENTS 64 /* size of event queue */
#define RBUFSIZE 8192
-#define SBUFSIZE 4096 /* sk_buff payload size */
+#define SBUFSIZE 4096 /* sk_buff payload size */
-#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */
-#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */
+#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */
+#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */
/* compile time options */
#define GIG_MAJOR 0
@@ -50,10 +55,7 @@
#define GIG_RETRYCID
#define GIG_X75
-#define MAX_TIMER_INDEX 1000
-#define MAX_SEQ_INDEX 1000
-
-#define GIG_TICK (HZ / 10)
+#define GIG_TICK 100 /* in milliseconds */
/* timeout values (unit: 1 sec) */
#define INIT_TIMEOUT 1
@@ -67,74 +69,89 @@
#define MAXACT 3
-#define IFNULL(a) if (unlikely(!(a)))
-#define IFNULLRET(a) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return; }
-#define IFNULLRETVAL(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return (b); }
-#define IFNULLCONT(a) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); continue; }
-#define IFNULLGOTO(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); goto b; }
-
extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */
-/* any combination of these can be given with the 'debug=' parameter to insmod, e.g.
- * 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and DEBUG_INTR. */
+/* any combination of these can be given with the 'debug=' parameter to insmod,
+ * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and
+ * DEBUG_INTR.
+ */
enum debuglevel { /* up to 24 bits (atomic_t) */
DEBUG_REG = 0x0002, /* serial port I/O register operations */
DEBUG_OPEN = 0x0004, /* open/close serial port */
DEBUG_INTR = 0x0008, /* interrupt processing */
- DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on interrupt
- requests, not available as run-time option */
+ DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on
+ interrupt requests, not available as
+ run-time option */
DEBUG_CMD = 0x00020, /* sent/received LL commands */
DEBUG_STREAM = 0x00040, /* application data stream I/O events */
DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */
DEBUG_LLDATA = 0x00100, /* sent/received LL data */
- DEBUG_INTR_0 = 0x00200, /* serial port output interrupt processing */
+ DEBUG_INTR_0 = 0x00200, /* serial port interrupt processing */
DEBUG_DRIVER = 0x00400, /* driver structure */
DEBUG_HDLC = 0x00800, /* M10x HDLC processing */
DEBUG_WRITE = 0x01000, /* M105 data write */
- DEBUG_TRANSCMD = 0x02000, /*AT-COMMANDS+RESPONSES*/
- DEBUG_MCMD = 0x04000, /*COMMANDS THAT ARE SENT VERY OFTEN*/
- DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data structures */
+ DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */
+ DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */
+ DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data
+ structures */
DEBUG_LOCK = 0x10000, /* semaphore operations */
DEBUG_OUTPUT = 0x20000, /* output to device */
- DEBUG_ISO = 0x40000, /* isochronous transfers */
+ DEBUG_ISO = 0x40000, /* isochronous transfers */
DEBUG_IF = 0x80000, /* character device operations */
- DEBUG_USBREQ = 0x100000, /* USB communication (except payload data) */
- DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when MS_LOCKED */
+ DEBUG_USBREQ = 0x100000, /* USB communication (except payload
+ data) */
+ DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when
+ MS_LOCKED */
- DEBUG_ANY = 0x3fffff, /* print message if any of the others is activated */
+ DEBUG_ANY = 0x3fffff, /* print message if any of the others is
+ activated */
};
-#ifdef CONFIG_GIGASET_DEBUG
-#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
-//#define DEBUG_DEFAULT (DEBUG_LOCK | DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUF_IF | DEBUG_DRIVER | DEBUG_OUTPUT | DEBUG_INTR)
-#else
-#define DEBUG_DEFAULT 0
+/* missing from linux/device.h ... */
+#ifndef dev_notice
+#define dev_notice(dev, format, arg...) \
+ dev_printk(KERN_NOTICE , dev , format , ## arg)
#endif
-/* redefine syslog macros to prepend module name instead of entire source path */
-/* The space before the comma in ", ##" is needed by gcc 2.95 */
+/* Kernel message macros for situations where dev_printk and friends cannot be
+ * used for lack of reliable access to a device structure.
+ * linux/usb.h already contains these but in an obsolete form which clutters
+ * the log needlessly, and according to the USB maintainer those should be
+ * removed rather than fixed anyway.
+ */
+#undef err
#undef info
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
-
-#undef notice
-#define notice(format, arg...) printk(KERN_NOTICE "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
-
#undef warn
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+#undef notice
-#undef err
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg)
+#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
+#define notice(format, arg...) printk(KERN_NOTICE KBUILD_MODNAME ": " \
+ format "\n" , ## arg)
-#undef dbg
#ifdef CONFIG_GIGASET_DEBUG
-#define dbg(level, format, arg...) do { if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \
- printk(KERN_DEBUG "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg); } while (0)
+
+#define gig_dbg(level, format, arg...) \
+ do { \
+ if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \
+ printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \
+ ## arg); \
+ } while (0)
+#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ)
+
#else
-#define dbg(level, format, arg...) do {} while (0)
+
+#define gig_dbg(level, format, arg...) do {} while (0)
+#define DEBUG_DEFAULT 0
+
#endif
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
- size_t len, const unsigned char *buf, int from_user);
+ size_t len, const unsigned char *buf);
/* connection state */
#define ZSAU_NONE 0
@@ -148,13 +165,14 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define ZSAU_UNKNOWN -1
/* USB control transfer requests */
-#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
-#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
+#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
+#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT)
/* int-in-events 3070 */
#define HD_B1_FLOW_CONTROL 0x80
#define HD_B2_FLOW_CONTROL 0x81
-#define HD_RECEIVEATDATA_ACK (0x35) // 3070 // att: HD_RECEIVE>>AT<<DATA_ACK
+#define HD_RECEIVEATDATA_ACK (0x35) // 3070
+ // att: HD_RECEIVE>>AT<<DATA_ACK
#define HD_READY_SEND_ATDATA (0x36) // 3070
#define HD_OPEN_ATCHANNEL_ACK (0x37) // 3070
#define HD_CLOSE_ATCHANNEL_ACK (0x38) // 3070
@@ -181,17 +199,18 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define HD_CLOSE_ATCHANNEL (0x29) // 3070
/* USB frames for isochronous transfer */
-#define BAS_FRAMETIME 1 /* number of milliseconds between frames */
-#define BAS_NUMFRAMES 8 /* number of frames per URB */
-#define BAS_MAXFRAME 16 /* allocated bytes per frame */
-#define BAS_NORMFRAME 8 /* send size without flow control */
-#define BAS_HIGHFRAME 10 /* " " with positive flow control */
-#define BAS_LOWFRAME 5 /* " " with negative flow control */
-#define BAS_CORRFRAMES 4 /* flow control multiplicator */
-
-#define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isochronous input buffer per URB */
-#define BAS_OUTBUFSIZE 4096 /* size of common isochronous output buffer */
-#define BAS_OUTBUFPAD BAS_MAXFRAME /* size of pad area for isochronous output buffer */
+#define BAS_FRAMETIME 1 /* number of milliseconds between frames */
+#define BAS_NUMFRAMES 8 /* number of frames per URB */
+#define BAS_MAXFRAME 16 /* allocated bytes per frame */
+#define BAS_NORMFRAME 8 /* send size without flow control */
+#define BAS_HIGHFRAME 10 /* " " with positive flow control */
+#define BAS_LOWFRAME 5 /* " " with negative flow control */
+#define BAS_CORRFRAMES 4 /* flow control multiplicator */
+
+#define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES)
+ /* size of isoc in buf per URB */
+#define BAS_OUTBUFSIZE 4096 /* size of common isoc out buffer */
+#define BAS_OUTBUFPAD BAS_MAXFRAME /* size of pad area for isoc out buf */
#define BAS_INURBS 3
#define BAS_OUTURBS 3
@@ -207,40 +226,40 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define AT_NUM 7
/* variables in struct at_state_t */
-#define VAR_ZSAU 0
-#define VAR_ZDLE 1
-#define VAR_ZVLS 2
-#define VAR_ZCTP 3
-#define VAR_NUM 4
-
-#define STR_NMBR 0
-#define STR_ZCPN 1
-#define STR_ZCON 2
-#define STR_ZBC 3
-#define STR_ZHLC 4
-#define STR_NUM 5
-
-#define EV_TIMEOUT -105
-#define EV_IF_VER -106
-#define EV_PROC_CIDMODE -107
-#define EV_SHUTDOWN -108
-#define EV_START -110
-#define EV_STOP -111
-#define EV_IF_LOCK -112
-#define EV_PROTO_L2 -113
-#define EV_ACCEPT -114
-#define EV_DIAL -115
-#define EV_HUP -116
-#define EV_BC_OPEN -117
-#define EV_BC_CLOSED -118
+#define VAR_ZSAU 0
+#define VAR_ZDLE 1
+#define VAR_ZVLS 2
+#define VAR_ZCTP 3
+#define VAR_NUM 4
+
+#define STR_NMBR 0
+#define STR_ZCPN 1
+#define STR_ZCON 2
+#define STR_ZBC 3
+#define STR_ZHLC 4
+#define STR_NUM 5
+
+#define EV_TIMEOUT -105
+#define EV_IF_VER -106
+#define EV_PROC_CIDMODE -107
+#define EV_SHUTDOWN -108
+#define EV_START -110
+#define EV_STOP -111
+#define EV_IF_LOCK -112
+#define EV_PROTO_L2 -113
+#define EV_ACCEPT -114
+#define EV_DIAL -115
+#define EV_HUP -116
+#define EV_BC_OPEN -117
+#define EV_BC_CLOSED -118
/* input state */
-#define INS_command 0x0001
-#define INS_DLE_char 0x0002
-#define INS_byte_stuff 0x0004
-#define INS_have_data 0x0008
-#define INS_skip_frame 0x0010
-#define INS_DLE_command 0x0020
+#define INS_command 0x0001
+#define INS_DLE_char 0x0002
+#define INS_byte_stuff 0x0004
+#define INS_have_data 0x0008
+#define INS_skip_frame 0x0010
+#define INS_DLE_command 0x0020
#define INS_flag_hunt 0x0040
/* channel state */
@@ -248,27 +267,27 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
#define CHS_B_UP 0x02
#define CHS_NOTIFY_LL 0x04
-#define ICALL_REJECT 0
-#define ICALL_ACCEPT 1
-#define ICALL_IGNORE 2
+#define ICALL_REJECT 0
+#define ICALL_ACCEPT 1
+#define ICALL_IGNORE 2
/* device state */
-#define MS_UNINITIALIZED 0
-#define MS_INIT 1
-#define MS_LOCKED 2
-#define MS_SHUTDOWN 3
-#define MS_RECOVER 4
-#define MS_READY 5
+#define MS_UNINITIALIZED 0
+#define MS_INIT 1
+#define MS_LOCKED 2
+#define MS_SHUTDOWN 3
+#define MS_RECOVER 4
+#define MS_READY 5
/* mode */
-#define M_UNKNOWN 0
-#define M_CONFIG 1
-#define M_UNIMODEM 2
-#define M_CID 3
+#define M_UNKNOWN 0
+#define M_CONFIG 1
+#define M_UNIMODEM 2
+#define M_CID 3
/* start mode */
-#define SM_LOCKED 0
-#define SM_ISDN 1 /* default */
+#define SM_LOCKED 0
+#define SM_ISDN 1 /* default */
struct gigaset_ops;
struct gigaset_driver;
@@ -283,27 +302,26 @@ struct ser_bc_state;
struct bas_bc_state;
struct reply_t {
- int resp_code; /* RSP_XXXX */
- int min_ConState; /* <0 => ignore */
- int max_ConState; /* <0 => ignore */
- int parameter; /* e.g. ZSAU_XXXX <0: ignore*/
- int new_ConState; /* <0 => ignore */
- int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/
- int action[MAXACT]; /* ACT_XXXX */
- char *command; /* NULL==none */
+ int resp_code; /* RSP_XXXX */
+ int min_ConState; /* <0 => ignore */
+ int max_ConState; /* <0 => ignore */
+ int parameter; /* e.g. ZSAU_XXXX <0: ignore*/
+ int new_ConState; /* <0 => ignore */
+ int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/
+ int action[MAXACT]; /* ACT_XXXX */
+ char *command; /* NULL==none */
};
extern struct reply_t gigaset_tab_cid_m10x[];
extern struct reply_t gigaset_tab_nocid_m10x[];
struct inbuf_t {
- unsigned char *rcvbuf; /* usb-gigaset receive buffer */
+ unsigned char *rcvbuf; /* usb-gigaset receive buffer */
struct bc_state *bcs;
- struct cardstate *cs;
- int inputstate;
-
- atomic_t head, tail;
- unsigned char data[RBUFSIZE];
+ struct cardstate *cs;
+ int inputstate;
+ atomic_t head, tail;
+ unsigned char data[RBUFSIZE];
};
/* isochronous write buffer structure
@@ -319,16 +337,9 @@ struct inbuf_t {
* if writesem <= 0, data[write..read-1] is currently being written to
* - idle contains the byte value to repeat when the end of valid data is
* reached; if nextread==write (buffer contains no data to send), either the
- * BAS_OUTBUFPAD bytes immediately before data[write] (if write>=BAS_OUTBUFPAD)
- * or those of the pad area (if write<BAS_OUTBUFPAD) are also filled with that
- * value
- * - optionally, the following statistics on the buffer's usage can be collected:
- * maxfill: maximum number of bytes occupied
- * idlefills: number of times a frame of idle bytes is prepared
- * emptygets: number of times the buffer was empty when a data frame was requested
- * backtoback: number of times two data packets were entered into the buffer
- * without intervening idle flags
- * nakedback: set if no idle flags have been inserted since the last data packet
+ * BAS_OUTBUFPAD bytes immediately before data[write] (if
+ * write>=BAS_OUTBUFPAD) or those of the pad area (if write<BAS_OUTBUFPAD)
+ * are also filled with that value
*/
struct isowbuf_t {
atomic_t read;
@@ -358,34 +369,28 @@ struct isow_urbctx_t {
* it is currently assigned a B channel
*/
struct at_state_t {
- struct list_head list;
- int waiting;
- int getstring;
- atomic_t timer_index;
+ struct list_head list;
+ int waiting;
+ int getstring;
+ unsigned timer_index;
unsigned long timer_expires;
int timer_active;
- unsigned int ConState; /* State of connection */
- struct reply_t *replystruct;
- int cid;
- int int_var[VAR_NUM]; /* see VAR_XXXX */
- char *str_var[STR_NUM]; /* see STR_XXXX */
- unsigned pending_commands; /* see PC_XXXX */
- atomic_t seq_index;
-
- struct cardstate *cs;
- struct bc_state *bcs;
+ unsigned int ConState; /* State of connection */
+ struct reply_t *replystruct;
+ int cid;
+ int int_var[VAR_NUM]; /* see VAR_XXXX */
+ char *str_var[STR_NUM]; /* see STR_XXXX */
+ unsigned pending_commands; /* see PC_XXXX */
+ unsigned seq_index;
+
+ struct cardstate *cs;
+ struct bc_state *bcs;
};
struct resp_type_t {
unsigned char *response;
- int resp_code; /* RSP_XXXX */
- int type; /* RT_XXXX */
-};
-
-struct prot_skb {
- atomic_t empty;
- struct semaphore *sem;
- struct sk_buff *skb;
+ int resp_code; /* RSP_XXXX */
+ int type; /* RT_XXXX */
};
struct event_t {
@@ -398,29 +403,29 @@ struct event_t {
/* This buffer holds all information about the used B-Channel */
struct bc_state {
- struct sk_buff *tx_skb; /* Current transfer buffer to modem */
- struct sk_buff_head squeue; /* B-Channel send Queue */
+ struct sk_buff *tx_skb; /* Current transfer buffer to modem */
+ struct sk_buff_head squeue; /* B-Channel send Queue */
/* Variables for debugging .. */
- int corrupted; /* Counter for corrupted packages */
- int trans_down; /* Counter of packages (downstream) */
- int trans_up; /* Counter of packages (upstream) */
+ int corrupted; /* Counter for corrupted packages */
+ int trans_down; /* Counter of packages (downstream) */
+ int trans_up; /* Counter of packages (upstream) */
struct at_state_t at_state;
unsigned long rcvbytes;
__u16 fcs;
struct sk_buff *skb;
- int inputstate; /* see INS_XXXX */
+ int inputstate; /* see INS_XXXX */
int channel;
struct cardstate *cs;
- unsigned chstate; /* bitmap (CHS_*) */
+ unsigned chstate; /* bitmap (CHS_*) */
int ignore;
- unsigned proto2; /* Layer 2 protocol (ISDN_PROTO_L2_*) */
- char *commands[AT_NUM]; /* see AT_XXXX */
+ unsigned proto2; /* Layer 2 protocol (ISDN_PROTO_L2_*) */
+ char *commands[AT_NUM]; /* see AT_XXXX */
#ifdef CONFIG_GIGASET_DEBUG
int emptycount;
@@ -428,37 +433,39 @@ struct bc_state {
int busy;
int use_count;
- /* hardware drivers */
+ /* private data of hardware drivers */
union {
- struct ser_bc_state *ser; /* private data of serial hardware driver */
- struct usb_bc_state *usb; /* private data of usb hardware driver */
- struct bas_bc_state *bas;
+ struct ser_bc_state *ser; /* serial hardware driver */
+ struct usb_bc_state *usb; /* usb hardware driver (m105) */
+ struct bas_bc_state *bas; /* usb hardware driver (base) */
} hw;
};
struct cardstate {
struct gigaset_driver *driver;
unsigned minor_index;
+ struct device *dev;
const struct gigaset_ops *ops;
/* Stuff to handle communication */
- //wait_queue_head_t initwait;
wait_queue_head_t waitqueue;
int waiting;
- atomic_t mode; /* see M_XXXX */
- atomic_t mstate; /* Modem state: see MS_XXXX */
- /* only changed by the event layer */
+ atomic_t mode; /* see M_XXXX */
+ atomic_t mstate; /* Modem state: see MS_XXXX */
+ /* only changed by the event layer */
int cmd_result;
int channels;
- struct bc_state *bcs; /* Array of struct bc_state */
+ struct bc_state *bcs; /* Array of struct bc_state */
- int onechannel; /* data and commands transmitted in one stream (M10x) */
+ int onechannel; /* data and commands transmitted in one
+ stream (M10x) */
spinlock_t lock;
- struct at_state_t at_state; /* at_state_t for cid == 0 */
- struct list_head temp_at_states; /* list of temporary "struct at_state_t"s without B channel */
+ struct at_state_t at_state; /* at_state_t for cid == 0 */
+ struct list_head temp_at_states;/* list of temporary "struct
+ at_state_t"s without B channel */
struct inbuf_t *inbuf;
@@ -474,58 +481,69 @@ struct cardstate {
unsigned fwver[4];
int gotfwver;
- atomic_t running; /* !=0 if events are handled */
- atomic_t connected; /* !=0 if hardware is connected */
+ unsigned running; /* !=0 if events are handled */
+ unsigned connected; /* !=0 if hardware is connected */
+ unsigned isdn_up; /* !=0 after ISDN_STAT_RUN */
- atomic_t cidmode;
+ unsigned cidmode;
- int myid; /* id for communication with LL */
+ int myid; /* id for communication with LL */
isdn_if iif;
struct reply_t *tabnocid;
struct reply_t *tabcid;
int cs_init;
- int ignoreframes; /* frames to ignore after setting up the B channel */
- struct semaphore sem; /* locks this structure: */
- /* connected is not changed, */
- /* hardware_up is not changed, */
- /* MState is not changed to or from MS_LOCKED */
+ int ignoreframes; /* frames to ignore after setting up the
+ B channel */
+ struct mutex mutex; /* locks this structure:
+ * connected is not changed,
+ * hardware_up is not changed,
+ * MState is not changed to or from
+ * MS_LOCKED */
struct timer_list timer;
int retry_count;
- int dle; /* !=0 if modem commands/responses are dle encoded */
- int cur_at_seq; /* sequence of AT commands being processed */
- int curchannel; /* channel, those commands are meant for */
- atomic_t commands_pending; /* flag(s) in xxx.commands_pending have been set */
- struct tasklet_struct event_tasklet; /* tasklet for serializing AT commands. Scheduled
- * -> for modem reponses (and incomming data for M10x)
- * -> on timeout
- * -> after setting bits in xxx.at_state.pending_command
- * (e.g. command from LL) */
- struct tasklet_struct write_tasklet; /* tasklet for serial output
- * (not used in base driver) */
+ int dle; /* !=0 if modem commands/responses are
+ dle encoded */
+ int cur_at_seq; /* sequence of AT commands being
+ processed */
+ int curchannel; /* channel those commands are meant
+ for */
+ atomic_t commands_pending; /* flag(s) in xxx.commands_pending have
+ been set */
+ struct tasklet_struct event_tasklet;
+ /* tasklet for serializing AT commands.
+ * Scheduled
+ * -> for modem reponses (and
+ * incoming data for M10x)
+ * -> on timeout
+ * -> after setting bits in
+ * xxx.at_state.pending_command
+ * (e.g. command from LL) */
+ struct tasklet_struct write_tasklet;
+ /* tasklet for serial output
+ * (not used in base driver) */
/* event queue */
struct event_t events[MAX_EVENTS];
- atomic_t ev_tail, ev_head;
+ unsigned ev_tail, ev_head;
spinlock_t ev_lock;
/* current modem response */
unsigned char respdata[MAX_RESP_SIZE];
unsigned cbytes;
- /* hardware drivers */
+ /* private data of hardware drivers */
union {
- struct usb_cardstate *usb; /* private data of USB hardware driver */
- struct ser_cardstate *ser; /* private data of serial hardware driver */
- struct bas_cardstate *bas; /* private data of base hardware driver */
+ struct usb_cardstate *usb; /* USB hardware driver (m105) */
+ struct ser_cardstate *ser; /* serial hardware driver */
+ struct bas_cardstate *bas; /* USB hardware driver (base) */
} hw;
};
struct gigaset_driver {
struct list_head list;
- spinlock_t lock; /* locks minor tables and blocked */
- //struct semaphore sem; /* locks this structure */
+ spinlock_t lock; /* locks minor tables and blocked */
struct tty_driver *tty;
unsigned have_tty;
unsigned minor;
@@ -553,37 +571,42 @@ struct bas_bc_state {
struct isow_urbctx_t isoouturbs[BAS_OUTURBS];
struct isow_urbctx_t *isooutdone, *isooutfree, *isooutovfl;
struct isowbuf_t *isooutbuf;
- unsigned numsub; /* submitted URB counter (for diagnostic messages only) */
+ unsigned numsub; /* submitted URB counter
+ (for diagnostic messages only) */
struct tasklet_struct sent_tasklet;
/* isochronous input state */
spinlock_t isoinlock;
struct urb *isoinurbs[BAS_INURBS];
unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS];
- struct urb *isoindone; /* completed isoc read URB */
- int loststatus; /* status of dropped URB */
- unsigned isoinlost; /* number of bytes lost */
- /* state of bit unstuffing algorithm (in addition to BC_state.inputstate) */
- unsigned seqlen; /* number of '1' bits not yet unstuffed */
- unsigned inbyte, inbits; /* collected bits for next byte */
+ struct urb *isoindone; /* completed isoc read URB */
+ int loststatus; /* status of dropped URB */
+ unsigned isoinlost; /* number of bytes lost */
+ /* state of bit unstuffing algorithm
+ (in addition to BC_state.inputstate) */
+ unsigned seqlen; /* number of '1' bits not yet
+ unstuffed */
+ unsigned inbyte, inbits; /* collected bits for next byte */
/* statistics */
- unsigned goodbytes; /* bytes correctly received */
- unsigned alignerrs; /* frames with incomplete byte at end */
- unsigned fcserrs; /* FCS errors */
- unsigned frameerrs; /* framing errors */
- unsigned giants; /* long frames */
- unsigned runts; /* short frames */
- unsigned aborts; /* HDLC aborts */
- unsigned shared0s; /* '0' bits shared between flags */
- unsigned stolen0s; /* '0' stuff bits also serving as leading flag bits */
+ unsigned goodbytes; /* bytes correctly received */
+ unsigned alignerrs; /* frames with incomplete byte at end */
+ unsigned fcserrs; /* FCS errors */
+ unsigned frameerrs; /* framing errors */
+ unsigned giants; /* long frames */
+ unsigned runts; /* short frames */
+ unsigned aborts; /* HDLC aborts */
+ unsigned shared0s; /* '0' bits shared between flags */
+ unsigned stolen0s; /* '0' stuff bits also serving as
+ leading flag bits */
struct tasklet_struct rcvd_tasklet;
};
struct gigaset_ops {
- /* Called from ev-layer.c/interface.c for sending AT commands to the device */
+ /* Called from ev-layer.c/interface.c for sending AT commands to the
+ device */
int (*write_cmd)(struct cardstate *cs,
- const unsigned char *buf, int len,
- struct tasklet_struct *wake_tasklet);
+ const unsigned char *buf, int len,
+ struct tasklet_struct *wake_tasklet);
/* Called from interface.c for additional device control */
int (*write_room)(struct cardstate *cs);
@@ -604,7 +627,8 @@ struct gigaset_ops {
/* Called by gigaset_freecs() for freeing bcs->hw.xxx */
int (*freebcshw)(struct bc_state *bcs);
- /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting bcs->hw.xxx */
+ /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting
+ bcs->hw.xxx */
void (*reinitbcshw)(struct bc_state *bcs);
/* Called by gigaset_initcs() for setting up cs->hw.xxx */
@@ -613,13 +637,10 @@ struct gigaset_ops {
/* Called by gigaset_freecs() for freeing cs->hw.xxx */
void (*freecshw)(struct cardstate *cs);
- ///* Called by gigaset_stop() for killing URBs, shutting down the device, ...
- // hardwareup: ==0: don't try to shut down the device, hardware is really not accessible
- // !=0: hardware still up */
- //void (*stophw)(struct cardstate *cs, int hardwareup);
-
- /* Called from common.c/interface.c for additional serial port control */
- int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, unsigned new_state);
+ /* Called from common.c/interface.c for additional serial port
+ control */
+ int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state,
+ unsigned new_state);
int (*baud_rate)(struct cardstate *cs, unsigned cflag);
int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag);
@@ -639,7 +660,7 @@ struct gigaset_ops {
* <DLE_FLAG>: 0x10
* <EVENT>: ((a-z)* | (A-Z)* | (0-10)*)+
*/
-#define DLE_FLAG 0x10
+#define DLE_FLAG 0x10
/* ===========================================================================
* Functions implemented in asyncdata.c
@@ -667,7 +688,8 @@ void gigaset_isoc_input(struct inbuf_t *inbuf);
/* Called from bas-gigaset.c to process a block of data
* received through the isochronous channel */
-void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs);
+void gigaset_isoc_receive(unsigned char *src, unsigned count,
+ struct bc_state *bcs);
/* Called from bas-gigaset.c to put a block of data
* into the isochronous output buffer */
@@ -703,7 +725,7 @@ static inline void gigaset_isdn_rcv_err(struct bc_state *bcs)
isdn_ctrl response;
/* error -> LL */
- dbg(DEBUG_CMD, "sending L1ERR");
+ gig_dbg(DEBUG_CMD, "sending L1ERR");
response.driver = bcs->cs->myid;
response.command = ISDN_STAT_L1ERR;
response.arg = bcs->channel;
@@ -727,8 +749,8 @@ void gigaset_handle_modem_response(struct cardstate *cs);
*/
/* initialize sysfs for device */
-void gigaset_init_dev_sysfs(struct usb_interface *interface);
-void gigaset_free_dev_sysfs(struct usb_interface *interface);
+void gigaset_init_dev_sysfs(struct cardstate *cs);
+void gigaset_free_dev_sysfs(struct cardstate *cs);
/* ===========================================================================
* Functions implemented in common.c/gigaset.h
@@ -736,7 +758,7 @@ void gigaset_free_dev_sysfs(struct usb_interface *interface);
void gigaset_bcs_reinit(struct bc_state *bcs);
void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs,
- struct cardstate *cs, int cid);
+ struct cardstate *cs, int cid);
int gigaset_get_channel(struct bc_state *bcs);
void gigaset_free_channel(struct bc_state *bcs);
int gigaset_get_channels(struct cardstate *cs);
@@ -745,16 +767,15 @@ void gigaset_block_channels(struct cardstate *cs);
/* Allocate and initialize driver structure. */
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
- const char *procname,
- const char *devname,
- const char *devfsname,
- const struct gigaset_ops *ops,
- struct module *owner);
+ const char *procname,
+ const char *devname,
+ const char *devfsname,
+ const struct gigaset_ops *ops,
+ struct module *owner);
/* Deallocate driver structure. */
void gigaset_freedriver(struct gigaset_driver *drv);
void gigaset_debugdrivers(void);
-struct cardstate *gigaset_get_cs_by_minor(unsigned minor);
struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty);
struct cardstate *gigaset_get_cs_by_id(int id);
@@ -763,7 +784,8 @@ struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv);
void gigaset_unassign(struct cardstate *cs);
void gigaset_blockdriver(struct gigaset_driver *drv);
-/* Allocate and initialize card state. Calls hardware dependent gigaset_init[b]cs(). */
+/* Allocate and initialize card state. Calls hardware dependent
+ gigaset_init[b]cs(). */
struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
int onechannel, int ignoreframes,
int cidmode, const char *modulename);
@@ -788,8 +810,8 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb);
* ptr must be kmalloc()ed (and not be freed by the caller).
*/
struct event_t *gigaset_add_event(struct cardstate *cs,
- struct at_state_t *at_state, int type,
- void *ptr, int parameter, void *arg);
+ struct at_state_t *at_state, int type,
+ void *ptr, int parameter, void *arg);
/* Called on CONFIG1 command from frontend. */
int gigaset_enterconfigmode(struct cardstate *cs); //0: success <0: errorcode
@@ -799,7 +821,7 @@ static inline void gigaset_schedule_event(struct cardstate *cs)
{
unsigned long flags;
spin_lock_irqsave(&cs->lock, flags);
- if (atomic_read(&cs->running))
+ if (cs->running)
tasklet_schedule(&cs->event_tasklet);
spin_unlock_irqrestore(&cs->lock, flags);
}
@@ -810,7 +832,7 @@ static inline void gigaset_bchannel_down(struct bc_state *bcs)
{
gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL);
- dbg(DEBUG_CMD, "scheduling BC_CLOSED");
+ gig_dbg(DEBUG_CMD, "scheduling BC_CLOSED");
gigaset_schedule_event(bcs->cs);
}
@@ -820,36 +842,19 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs)
{
gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL);
- dbg(DEBUG_CMD, "scheduling BC_OPEN");
+ gig_dbg(DEBUG_CMD, "scheduling BC_OPEN");
gigaset_schedule_event(bcs->cs);
}
/* handling routines for sk_buff */
/* ============================= */
-/* private version of __skb_put()
- * append 'len' bytes to the content of 'skb', already knowing that the
- * existing buffer can accomodate them
- * returns a pointer to the location where the new bytes should be copied to
- * This function does not take any locks so it must be called with the
- * appropriate locks held only.
- */
-static inline unsigned char *gigaset_skb_put_quick(struct sk_buff *skb,
- unsigned int len)
-{
- unsigned char *tmp = skb->tail;
- /*SKB_LINEAR_ASSERT(skb);*/ /* not needed here */
- skb->tail += len;
- skb->len += len;
- return tmp;
-}
-
/* pass received skb to LL
* Warning: skb must not be accessed anymore!
*/
static inline void gigaset_rcv_skb(struct sk_buff *skb,
- struct cardstate *cs,
- struct bc_state *bcs)
+ struct cardstate *cs,
+ struct bc_state *bcs)
{
cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb);
bcs->trans_down++;
@@ -859,8 +864,8 @@ static inline void gigaset_rcv_skb(struct sk_buff *skb,
* Warning: skb must not be accessed anymore!
*/
static inline void gigaset_rcv_error(struct sk_buff *procskb,
- struct cardstate *cs,
- struct bc_state *bcs)
+ struct cardstate *cs,
+ struct bc_state *bcs)
{
if (procskb)
dev_kfree_skb(procskb);
@@ -877,46 +882,9 @@ static inline void gigaset_rcv_error(struct sk_buff *procskb,
/* bitwise byte inversion table */
extern __u8 gigaset_invtab[]; /* in common.c */
-
/* append received bytes to inbuf */
-static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf,
- const unsigned char *src,
- unsigned numbytes)
-{
- unsigned n, head, tail, bytesleft;
-
- dbg(DEBUG_INTR, "received %u bytes", numbytes);
-
- if (!numbytes)
- return 0;
-
- bytesleft = numbytes;
- tail = atomic_read(&inbuf->tail);
- head = atomic_read(&inbuf->head);
- dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
-
- while (bytesleft) {
- if (head > tail)
- n = head - 1 - tail;
- else if (head == 0)
- n = (RBUFSIZE-1) - tail;
- else
- n = RBUFSIZE - tail;
- if (!n) {
- err("buffer overflow (%u bytes lost)", bytesleft);
- break;
- }
- if (n > bytesleft)
- n = bytesleft;
- memcpy(inbuf->data + tail, src, n);
- bytesleft -= n;
- tail = (tail + n) % RBUFSIZE;
- src += n;
- }
- dbg(DEBUG_INTR, "setting tail to %u", tail);
- atomic_set(&inbuf->tail, tail);
- return numbytes != bytesleft;
-}
+int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
+ unsigned numbytes);
/* ===========================================================================
* Functions implemented in interface.c
@@ -924,7 +892,7 @@ static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf,
/* initialize interface */
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
- const char *devname, const char *devfsname);
+ const char *devname, const char *devfsname);
/* release interface */
void gigaset_if_freedriver(struct gigaset_driver *drv);
/* add minor */
@@ -933,6 +901,6 @@ void gigaset_if_init(struct cardstate *cs);
void gigaset_if_free(struct cardstate *cs);
/* device received data */
void gigaset_if_receive(struct cardstate *cs,
- unsigned char *buffer, size_t len);
+ unsigned char *buffer, size_t len);
#endif
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 731a675f21b0..0815dbfb8291 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -1,9 +1,9 @@
/*
* Stuff used by all variants of the driver
*
- * Copyright (c) 2001 by Stefan Eilers (Eilers.Stefan@epost.de),
- * Hansjoerg Lipp (hjlipp@web.de),
- * Tilman Schmidt (tilman@imap.cc).
+ * Copyright (c) 2001 by Stefan Eilers,
+ * Hansjoerg Lipp <hjlipp@web.de>,
+ * Tilman Schmidt <tilman@imap.cc>.
*
* =====================================================================
* This program is free software; you can redistribute it and/or
@@ -11,15 +11,11 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: i4l.c,v 1.3.2.9 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
-/* == Handling of I4L IO ============================================================================*/
+/* == Handling of I4L IO =====================================================*/
/* writebuf_from_LL
* called by LL to transmit data on an open channel
@@ -29,14 +25,16 @@
* parameters:
* driverID driver ID as assigned by LL
* channel channel number
- * ack if != 0 LL wants to be notified on completion via statcallb(ISDN_STAT_BSENT)
+ * ack if != 0 LL wants to be notified on completion via
+ * statcallb(ISDN_STAT_BSENT)
* skb skb containing data to send
* return value:
* number of accepted bytes
* 0 if temporarily unable to accept data (out of buffer space)
* <0 on error (eg. -EINVAL)
*/
-static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *skb)
+static int writebuf_from_LL(int driverID, int channel, int ack,
+ struct sk_buff *skb)
{
struct cardstate *cs;
struct bc_state *bcs;
@@ -54,31 +52,28 @@ static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *
bcs = &cs->bcs[channel];
len = skb->len;
- dbg(DEBUG_LLDATA,
- "Receiving data from LL (id: %d, channel: %d, ack: %d, size: %d)",
- driverID, channel, ack, len);
+ gig_dbg(DEBUG_LLDATA,
+ "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
+ driverID, channel, ack, len);
if (!len) {
if (ack)
- warn("not ACKing empty packet from LL");
+ notice("%s: not ACKing empty packet", __func__);
return 0;
}
if (len > MAX_BUF_SIZE) {
- err("%s: packet too large (%d bytes)", __func__, channel);
+ err("%s: packet too large (%d bytes)", __func__, len);
return -EINVAL;
}
- if (!atomic_read(&cs->connected))
- return -ENODEV;
-
skblen = ack ? len : 0;
skb->head[0] = skblen & 0xff;
skb->head[1] = skblen >> 8;
- dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", len, skblen,
- (unsigned) skb->head[0], (unsigned) skb->head[1]);
+ gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x",
+ len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
/* pass to device-specific module */
- return cs->ops->send_skb(bcs, skb);
+ return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly
}
void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
@@ -89,14 +84,14 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
++bcs->trans_up;
if (skb->len)
- warn("%s: skb->len==%d", __func__, skb->len);
+ dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
+ __func__, skb->len);
len = (unsigned char) skb->head[0] |
(unsigned) (unsigned char) skb->head[1] << 8;
if (len) {
- dbg(DEBUG_MCMD,
- "Acknowledge sending to LL (id: %d, channel: %d size: %u)",
- bcs->cs->myid, bcs->channel, len);
+ gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
+ bcs->cs->myid, bcs->channel, len);
response.driver = bcs->cs->myid;
response.command = ISDN_STAT_BSENT;
@@ -119,15 +114,12 @@ static int command_from_LL(isdn_ctrl *cntrl)
struct bc_state *bcs;
int retval = 0;
struct setup_parm *sp;
+ unsigned param;
+ unsigned long flags;
- //dbg(DEBUG_ANY, "Gigaset_HW: Receiving command");
gigaset_debugdrivers();
- /* Terminate this call if no device is present. Bt if the command is "ISDN_CMD_LOCK" or
- * "ISDN_CMD_UNLOCK" then execute it due to the fact that they are device independent !
- */
- //FIXME "remove test for &connected"
- if ((!cs || !atomic_read(&cs->connected))) {
+ if (!cs) {
warn("LL tried to access unknown device with nr. %d",
cntrl->driver);
return -ENODEV;
@@ -135,29 +127,30 @@ static int command_from_LL(isdn_ctrl *cntrl)
switch (cntrl->command) {
case ISDN_CMD_IOCTL:
-
- dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver:%d,arg: %ld)",
- cntrl->driver, cntrl->arg);
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver: %d, arg: %ld)",
+ cntrl->driver, cntrl->arg);
warn("ISDN_CMD_IOCTL is not supported.");
return -EINVAL;
case ISDN_CMD_DIAL:
- dbg(DEBUG_ANY, "ISDN_CMD_DIAL (driver: %d, channel: %ld, "
- "phone: %s,ownmsn: %s, si1: %d, si2: %d)",
- cntrl->driver, cntrl->arg,
- cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
- cntrl->parm.setup.si1, cntrl->parm.setup.si2);
+ gig_dbg(DEBUG_ANY,
+ "ISDN_CMD_DIAL (driver: %d, ch: %ld, "
+ "phone: %s, ownmsn: %s, si1: %d, si2: %d)",
+ cntrl->driver, cntrl->arg,
+ cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
+ cntrl->parm.setup.si1, cntrl->parm.setup.si2);
if (cntrl->arg >= cs->channels) {
- err("invalid channel (%d)", (int) cntrl->arg);
+ err("ISDN_CMD_DIAL: invalid channel (%d)",
+ (int) cntrl->arg);
return -EINVAL;
}
bcs = cs->bcs + cntrl->arg;
if (!gigaset_get_channel(bcs)) {
- err("channel not free");
+ err("ISDN_CMD_DIAL: channel not free");
return -EBUSY;
}
@@ -169,42 +162,46 @@ static int command_from_LL(isdn_ctrl *cntrl)
}
*sp = cntrl->parm.setup;
- if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
- atomic_read(&bcs->at_state.seq_index),
- NULL)) {
+ spin_lock_irqsave(&cs->lock, flags);
+ param = bcs->at_state.seq_index;
+ spin_unlock_irqrestore(&cs->lock, flags);
+
+ if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param,
+ NULL)) {
//FIXME what should we do?
kfree(sp);
gigaset_free_channel(bcs);
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling DIAL");
+ gig_dbg(DEBUG_CMD, "scheduling DIAL");
gigaset_schedule_event(cs);
break;
case ISDN_CMD_ACCEPTD: //FIXME
- dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
if (cntrl->arg >= cs->channels) {
- err("invalid channel (%d)", (int) cntrl->arg);
+ err("ISDN_CMD_ACCEPTD: invalid channel (%d)",
+ (int) cntrl->arg);
return -EINVAL;
}
if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
- EV_ACCEPT, NULL, 0, NULL)) {
+ EV_ACCEPT, NULL, 0, NULL)) {
//FIXME what should we do?
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling ACCEPT");
+ gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
gigaset_schedule_event(cs);
break;
case ISDN_CMD_ACCEPTB:
- dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
break;
case ISDN_CMD_HANGUP:
- dbg(DEBUG_ANY,
- "ISDN_CMD_HANGUP (channel: %d)", (int) cntrl->arg);
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_HANGUP (ch: %d)",
+ (int) cntrl->arg);
if (cntrl->arg >= cs->channels) {
err("ISDN_CMD_HANGUP: invalid channel (%u)",
@@ -213,66 +210,68 @@ static int command_from_LL(isdn_ctrl *cntrl)
}
if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
- EV_HUP, NULL, 0, NULL)) {
+ EV_HUP, NULL, 0, NULL)) {
//FIXME what should we do?
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling HUP");
+ gig_dbg(DEBUG_CMD, "scheduling HUP");
gigaset_schedule_event(cs);
break;
- case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME
- dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
+ case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
break;
- case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME
- dbg(DEBUG_ANY,
- "ISDN_CMD_SETEAZ (id:%d, channel: %ld, number: %s)",
- cntrl->driver, cntrl->arg, cntrl->parm.num);
+ case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME
+ gig_dbg(DEBUG_ANY,
+ "ISDN_CMD_SETEAZ (id: %d, ch: %ld, number: %s)",
+ cntrl->driver, cntrl->arg, cntrl->parm.num);
break;
- case ISDN_CMD_SETL2: /* Set L2 to given protocol */
- dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (Channel: %ld, Proto: %lx)",
- cntrl->arg & 0xff, (cntrl->arg >> 8));
+ case ISDN_CMD_SETL2: /* Set L2 to given protocol */
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (ch: %ld, proto: %lx)",
+ cntrl->arg & 0xff, (cntrl->arg >> 8));
if ((cntrl->arg & 0xff) >= cs->channels) {
- err("invalid channel (%u)",
+ err("ISDN_CMD_SETL2: invalid channel (%u)",
(unsigned) cntrl->arg & 0xff);
return -EINVAL;
}
if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state,
- EV_PROTO_L2, NULL, cntrl->arg >> 8,
- NULL)) {
+ EV_PROTO_L2, NULL, cntrl->arg >> 8,
+ NULL)) {
//FIXME what should we do?
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling PROTO_L2");
+ gig_dbg(DEBUG_CMD, "scheduling PROTO_L2");
gigaset_schedule_event(cs);
break;
- case ISDN_CMD_SETL3: /* Set L3 to given protocol */
- dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (Channel: %ld, Proto: %lx)",
- cntrl->arg & 0xff, (cntrl->arg >> 8));
+ case ISDN_CMD_SETL3: /* Set L3 to given protocol */
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (ch: %ld, proto: %lx)",
+ cntrl->arg & 0xff, (cntrl->arg >> 8));
if ((cntrl->arg & 0xff) >= cs->channels) {
- err("invalid channel (%u)",
+ err("ISDN_CMD_SETL3: invalid channel (%u)",
(unsigned) cntrl->arg & 0xff);
return -EINVAL;
}
if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
- err("invalid protocol %lu", cntrl->arg >> 8);
+ err("ISDN_CMD_SETL3: invalid protocol %lu",
+ cntrl->arg >> 8);
return -EINVAL;
}
break;
case ISDN_CMD_PROCEED:
- dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
break;
case ISDN_CMD_ALERT:
- dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
if (cntrl->arg >= cs->channels) {
- err("invalid channel (%d)", (int) cntrl->arg);
+ err("ISDN_CMD_ALERT: invalid channel (%d)",
+ (int) cntrl->arg);
return -EINVAL;
}
//bcs = cs->bcs + cntrl->arg;
@@ -280,32 +279,31 @@ static int command_from_LL(isdn_ctrl *cntrl)
// FIXME
break;
case ISDN_CMD_REDIR:
- dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
break;
case ISDN_CMD_PROT_IO:
- dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
break;
case ISDN_CMD_FAXCMD:
- dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
break;
case ISDN_CMD_GETL2:
- dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
break;
case ISDN_CMD_GETL3:
- dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
break;
case ISDN_CMD_GETEAZ:
- dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
break;
case ISDN_CMD_SETSIL:
- dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
break;
case ISDN_CMD_GETSIL:
- dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
+ gig_dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
break;
default:
- err("unknown command %d from LL",
- cntrl->command);
+ err("unknown command %d from LL", cntrl->command);
return -EINVAL;
}
@@ -350,7 +348,8 @@ int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break;
default:
- err("invalid protocol: %u", bcs->proto2);
+ dev_err(bcs->cs->dev, "%s: invalid L2 protocol: %u\n",
+ __func__, bcs->proto2);
return -EINVAL;
}
@@ -378,7 +377,7 @@ int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
bcs->commands[i] = NULL;
if (length[i] &&
!(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
- err("out of memory");
+ dev_err(bcs->cs->dev, "out of memory\n");
return -ENOMEM;
}
}
@@ -396,10 +395,14 @@ int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
}
if (bcs->commands[AT_MSN])
- snprintf(bcs->commands[AT_MSN], length[AT_MSN], "^SMSN=%s\r", sp->eazmsn);
- snprintf(bcs->commands[AT_BC ], length[AT_BC ], "^SBC=%s\r", bc);
- snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
- snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned)bcs->channel + 1);
+ snprintf(bcs->commands[AT_MSN], length[AT_MSN],
+ "^SMSN=%s\r", sp->eazmsn);
+ snprintf(bcs->commands[AT_BC ], length[AT_BC ],
+ "^SBC=%s\r", bc);
+ snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
+ "^SBPR=%u\r", proto);
+ snprintf(bcs->commands[AT_ISO ], length[AT_ISO ],
+ "^SISO=%u\r", (unsigned)bcs->channel + 1);
return 0;
}
@@ -419,7 +422,8 @@ int gigaset_isdn_setup_accept(struct at_state_t *at_state)
proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
break;
default:
- err("invalid protocol: %u", bcs->proto2);
+ dev_err(at_state->cs->dev, "%s: invalid protocol: %u\n",
+ __func__, bcs->proto2);
return -EINVAL;
}
@@ -436,13 +440,15 @@ int gigaset_isdn_setup_accept(struct at_state_t *at_state)
bcs->commands[i] = NULL;
if (length[i] &&
!(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
- err("out of memory");
+ dev_err(at_state->cs->dev, "out of memory\n");
return -ENOMEM;
}
}
- snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
- snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned) bcs->channel + 1);
+ snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
+ "^SBPR=%u\r", proto);
+ snprintf(bcs->commands[AT_ISO ], length[AT_ISO ],
+ "^SISO=%u\r", (unsigned) bcs->channel + 1);
return 0;
}
@@ -473,7 +479,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
response.parm.setup.si1 = 1;
response.parm.setup.si2 = 2;
} else {
- warn("RING ignored - unsupported BC %s",
+ dev_warn(cs->dev, "RING ignored - unsupported BC %s\n",
at_state->str_var[STR_ZBC]);
return ICALL_IGNORE;
}
@@ -491,18 +497,17 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
response.parm.setup.eazmsn[0] = 0;
if (!bcs) {
- notice("no channel for incoming call");
- dbg(DEBUG_CMD, "Sending ICALLW");
+ dev_notice(cs->dev, "no channel for incoming call\n");
response.command = ISDN_STAT_ICALLW;
response.arg = 0; //FIXME
} else {
- dbg(DEBUG_CMD, "Sending ICALL");
+ gig_dbg(DEBUG_CMD, "Sending ICALL");
response.command = ISDN_STAT_ICALL;
response.arg = bcs->channel; //FIXME
}
response.driver = cs->myid;
retval = cs->iif.statcallb(&response);
- dbg(DEBUG_CMD, "Response: %d", retval);
+ gig_dbg(DEBUG_CMD, "Response: %d", retval);
switch (retval) {
case 0: /* no takers */
return ICALL_IGNORE;
@@ -512,7 +517,8 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
case 2: /* reject */
return ICALL_REJECT;
case 3: /* incomplete */
- warn("LL requested unsupported feature: Incomplete Number");
+ dev_warn(cs->dev,
+ "LL requested unsupported feature: Incomplete Number\n");
return ICALL_IGNORE;
case 4: /* proceeding */
/* Gigaset will send ALERTING anyway.
@@ -520,10 +526,11 @@ int gigaset_isdn_icall(struct at_state_t *at_state)
*/
return ICALL_ACCEPT;
case 5: /* deflect */
- warn("LL requested unsupported feature: Call Deflection");
+ dev_warn(cs->dev,
+ "LL requested unsupported feature: Call Deflection\n");
return ICALL_IGNORE;
default:
- err("LL error %d on ICALL", retval);
+ dev_err(cs->dev, "LL error %d on ICALL\n", retval);
return ICALL_IGNORE;
}
}
@@ -533,7 +540,7 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
{
isdn_if *iif = &cs->iif;
- dbg(DEBUG_ANY, "Register driver capabilities to LL");
+ gig_dbg(DEBUG_ANY, "Register driver capabilities to LL");
//iif->id[sizeof(iif->id) - 1]=0;
//strncpy(iif->id, isdnid, sizeof(iif->id) - 1);
@@ -542,26 +549,26 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
return -ENOMEM; //FIXME EINVAL/...??
iif->owner = THIS_MODULE;
- iif->channels = cs->channels; /* I am supporting just one channel *//* I was supporting...*/
+ iif->channels = cs->channels;
iif->maxbufsize = MAX_BUF_SIZE;
- iif->features = ISDN_FEATURE_L2_TRANS | /* Our device is very advanced, therefore */
+ iif->features = ISDN_FEATURE_L2_TRANS |
ISDN_FEATURE_L2_HDLC |
#ifdef GIG_X75
ISDN_FEATURE_L2_X75I |
#endif
ISDN_FEATURE_L3_TRANS |
ISDN_FEATURE_P_EURO;
- iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */
+ iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */
iif->command = command_from_LL;
iif->writebuf_skb = writebuf_from_LL;
- iif->writecmd = NULL; /* Don't support isdnctrl */
- iif->readstat = NULL; /* Don't support isdnctrl */
- iif->rcvcallb_skb = NULL; /* Will be set by LL */
- iif->statcallb = NULL; /* Will be set by LL */
+ iif->writecmd = NULL; /* Don't support isdnctrl */
+ iif->readstat = NULL; /* Don't support isdnctrl */
+ iif->rcvcallb_skb = NULL; /* Will be set by LL */
+ iif->statcallb = NULL; /* Will be set by LL */
if (!register_isdn(iif))
return 0;
- cs->myid = iif->channels; /* Set my device id */
+ cs->myid = iif->channels; /* Set my device id */
return 1;
}
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 3a81d9c65141..08e4c4eea14d 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -9,8 +9,6 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * Version: $Id: interface.c,v 1.14.4.15 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
@@ -24,7 +22,7 @@ static int if_lock(struct cardstate *cs, int *arg)
{
int cmd = *arg;
- dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
+ gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
if (cmd > 1)
return -EINVAL;
@@ -35,7 +33,7 @@ static int if_lock(struct cardstate *cs, int *arg)
}
if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
- && atomic_read(&cs->connected)) {
+ && cs->connected) {
cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
cs->ops->baud_rate(cs, B115200);
cs->ops->set_line_ctrl(cs, CS8);
@@ -44,12 +42,12 @@ static int if_lock(struct cardstate *cs, int *arg)
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
- NULL, cmd, NULL)) {
+ NULL, cmd, NULL)) {
cs->waiting = 0;
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling IF_LOCK");
+ gig_dbg(DEBUG_CMD, "scheduling IF_LOCK");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
@@ -68,7 +66,7 @@ static int if_version(struct cardstate *cs, unsigned arg[4])
static const unsigned compat[4] = GIG_COMPAT;
unsigned cmd = arg[0];
- dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
+ gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
switch (cmd) {
case GIGVER_DRIVER:
@@ -80,12 +78,12 @@ static int if_version(struct cardstate *cs, unsigned arg[4])
case GIGVER_FWBASE:
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
- NULL, 0, arg)) {
+ NULL, 0, arg)) {
cs->waiting = 0;
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling IF_VER");
+ gig_dbg(DEBUG_CMD, "scheduling IF_VER");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
@@ -101,7 +99,7 @@ static int if_version(struct cardstate *cs, unsigned arg[4])
static int if_config(struct cardstate *cs, int *arg)
{
- dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
+ gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
if (*arg != 1)
return -EINVAL;
@@ -109,6 +107,11 @@ static int if_config(struct cardstate *cs, int *arg)
if (atomic_read(&cs->mstate) != MS_LOCKED)
return -EBUSY;
+ if (!cs->connected) {
+ err("not connected!");
+ return -ENODEV;
+ }
+
*arg = 0;
return gigaset_enterconfigmode(cs);
}
@@ -119,7 +122,7 @@ static int if_config(struct cardstate *cs, int *arg)
static int if_open(struct tty_struct *tty, struct file *filp);
static void if_close(struct tty_struct *tty, struct file *filp);
static int if_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
+ unsigned int cmd, unsigned long arg);
static int if_write_room(struct tty_struct *tty);
static int if_chars_in_buffer(struct tty_struct *tty);
static void if_throttle(struct tty_struct *tty);
@@ -127,9 +130,9 @@ static void if_unthrottle(struct tty_struct *tty);
static void if_set_termios(struct tty_struct *tty, struct termios *old);
static int if_tiocmget(struct tty_struct *tty, struct file *file);
static int if_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear);
+ unsigned int set, unsigned int clear);
static int if_write(struct tty_struct *tty,
- const unsigned char *buf, int count);
+ const unsigned char *buf, int count);
static struct tty_operations if_ops = {
.open = if_open,
@@ -153,8 +156,8 @@ static int if_open(struct tty_struct *tty, struct file *filp)
struct cardstate *cs;
unsigned long flags;
- dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index,
- __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%d+%d: %s()",
+ tty->driver->minor_start, tty->index, __func__);
tty->driver_data = NULL;
@@ -162,7 +165,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
if (!cs)
return -ENODEV;
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
tty->driver_data = cs;
@@ -173,10 +176,9 @@ static int if_open(struct tty_struct *tty, struct file *filp)
cs->tty = tty;
spin_unlock_irqrestore(&cs->lock, flags);
tty->low_latency = 1; //FIXME test
- //FIXME
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return 0;
}
@@ -187,30 +189,29 @@ static void if_close(struct tty_struct *tty, struct file *filp)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- down(&cs->sem);
+ mutex_lock(&cs->mutex);
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else {
if (!--cs->open_count) {
spin_lock_irqsave(&cs->lock, flags);
cs->tty = NULL;
spin_unlock_irqrestore(&cs->lock, flags);
- //FIXME
}
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
}
static int if_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
struct cardstate *cs;
int retval = -ENODEV;
@@ -220,17 +221,17 @@ static int if_ioctl(struct tty_struct *tty, struct file *file,
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return -ENODEV;
}
- dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __FUNCTION__, cmd);
+ gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else {
retval = 0;
switch (cmd) {
@@ -250,37 +251,40 @@ static int if_ioctl(struct tty_struct *tty, struct file *file,
break;
case GIGASET_BRKCHARS:
//FIXME test if MS_LOCKED
- gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
- 6, (const unsigned char *) arg, 1);
- if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_ANY, "can't communicate with unplugged device");
+ if (!cs->connected) {
+ gig_dbg(DEBUG_ANY,
+ "can't communicate with unplugged device");
retval = -ENODEV;
break;
}
retval = copy_from_user(&buf,
- (const unsigned char __user *) arg, 6)
- ? -EFAULT : 0;
- if (retval >= 0)
+ (const unsigned char __user *) arg, 6)
+ ? -EFAULT : 0;
+ if (retval >= 0) {
+ gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
+ 6, (const unsigned char *) arg);
retval = cs->ops->brkchars(cs, buf);
+ }
break;
case GIGASET_VERSION:
- retval = copy_from_user(version, (unsigned __user *) arg,
- sizeof version) ? -EFAULT : 0;
+ retval = copy_from_user(version,
+ (unsigned __user *) arg, sizeof version)
+ ? -EFAULT : 0;
if (retval >= 0)
retval = if_version(cs, version);
if (retval >= 0)
- retval = copy_to_user((unsigned __user *) arg, version,
- sizeof version)
- ? -EFAULT : 0;
+ retval = copy_to_user((unsigned __user *) arg,
+ version, sizeof version)
+ ? -EFAULT : 0;
break;
- default:
- dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
- __FUNCTION__, cmd);
+ default:
+ gig_dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
+ __func__, cmd);
retval = -ENOIOCTLCMD;
}
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return retval;
}
@@ -292,25 +296,25 @@ static int if_tiocmget(struct tty_struct *tty, struct file *file)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return -ENODEV;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
// FIXME read from device?
retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return retval;
}
static int if_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
struct cardstate *cs;
int retval;
@@ -318,18 +322,18 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return -ENODEV;
}
- dbg(DEBUG_IF,
- "%u: %s(0x%x, 0x%x)", cs->minor_index, __FUNCTION__, set, clear);
+ gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
+ cs->minor_index, __func__, set, clear);
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
- if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_ANY, "can't communicate with unplugged device");
+ if (!cs->connected) {
+ gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
retval = -ENODEV;
} else {
mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
@@ -337,7 +341,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
cs->control_state = mc;
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return retval;
}
@@ -349,29 +353,29 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return -ENODEV;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY;
- } else if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_ANY, "can't write to unplugged device");
+ } else if (!cs->connected) {
+ gig_dbg(DEBUG_ANY, "can't write to unplugged device");
retval = -EBUSY; //FIXME
} else {
retval = cs->ops->write_cmd(cs, buf, count,
- &cs->if_wake_tasklet);
+ &cs->if_wake_tasklet);
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return retval;
}
@@ -383,27 +387,27 @@ static int if_write_room(struct tty_struct *tty)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return -ENODEV;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY; //FIXME
- } else if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_ANY, "can't write to unplugged device");
+ } else if (!cs->connected) {
+ gig_dbg(DEBUG_ANY, "can't write to unplugged device");
retval = -EBUSY; //FIXME
} else
retval = cs->ops->write_room(cs);
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return retval;
}
@@ -415,27 +419,27 @@ static int if_chars_in_buffer(struct tty_struct *tty)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return -ENODEV;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else if (atomic_read(&cs->mstate) != MS_LOCKED) {
warn("can't write to unlocked device");
retval = -EBUSY;
- } else if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_ANY, "can't write to unplugged device");
+ } else if (!cs->connected) {
+ gig_dbg(DEBUG_ANY, "can't write to unplugged device");
retval = -EBUSY; //FIXME
} else
retval = cs->ops->chars_in_buffer(cs);
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return retval;
}
@@ -446,21 +450,21 @@ static void if_throttle(struct tty_struct *tty)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- down(&cs->sem);
+ mutex_lock(&cs->mutex);
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else {
//FIXME
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
}
static void if_unthrottle(struct tty_struct *tty)
@@ -469,21 +473,21 @@ static void if_unthrottle(struct tty_struct *tty)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- down(&cs->sem);
+ mutex_lock(&cs->mutex);
if (!cs->open_count)
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
else {
//FIXME
}
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
}
static void if_set_termios(struct tty_struct *tty, struct termios *old)
@@ -496,21 +500,21 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
cs = (struct cardstate *) tty->driver_data;
if (!cs) {
- err("cs==NULL in %s", __FUNCTION__);
+ err("cs==NULL in %s", __func__);
return;
}
- dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
+ gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
- down(&cs->sem);
+ mutex_lock(&cs->mutex);
if (!cs->open_count) {
- warn("%s: device not opened", __FUNCTION__);
+ warn("%s: device not opened", __func__);
goto out;
}
- if (!atomic_read(&cs->connected)) {
- dbg(DEBUG_ANY, "can't communicate with unplugged device");
+ if (!cs->connected) {
+ gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
goto out;
}
@@ -518,8 +522,8 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
iflag = tty->termios->c_iflag;
cflag = tty->termios->c_cflag;
old_cflag = old ? old->c_cflag : cflag; //FIXME?
- dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index,
- iflag, cflag, old_cflag);
+ gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
+ cs->minor_index, iflag, cflag, old_cflag);
/* get a local copy of the current port settings */
control_state = cs->control_state;
@@ -531,14 +535,15 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
* Premature optimization is the root of all evil.
*/
- /* reassert DTR and (maybe) RTS on transition from B0 */
+ /* reassert DTR and (maybe) RTS on transition from B0 */
if ((old_cflag & CBAUD) == B0) {
new_state = control_state | TIOCM_DTR;
/* don't set RTS if using hardware flow control */
if (!(old_cflag & CRTSCTS))
new_state |= TIOCM_RTS;
- dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index,
- (new_state & TIOCM_RTS) ? " only" : "/RTS");
+ gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
+ cs->minor_index,
+ (new_state & TIOCM_RTS) ? " only" : "/RTS");
cs->ops->set_modem_ctrl(cs, control_state, new_state);
control_state = new_state;
}
@@ -547,7 +552,7 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
if ((cflag & CBAUD) == B0) {
/* Drop RTS and DTR */
- dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
+ gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
cs->ops->set_modem_ctrl(cs, control_state, new_state);
control_state = new_state;
@@ -567,15 +572,17 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
* Just do what we have seen with SniffUSB on Win98.
*/
/* Drop DTR/RTS if no flow control otherwise assert */
- dbg(DEBUG_IF, "%u: control_state %x", cs->minor_index, control_state);
+ gig_dbg(DEBUG_IF, "%u: control_state %x",
+ cs->minor_index, control_state);
new_state = control_state;
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
new_state |= TIOCM_DTR | TIOCM_RTS;
else
new_state &= ~(TIOCM_DTR | TIOCM_RTS);
if (new_state != control_state) {
- dbg(DEBUG_IF, "%u: new_state %x", cs->minor_index, new_state);
- gigaset_set_modem_ctrl(cs, control_state, new_state); // FIXME: mct_u232.c sets the old state here. is this a bug?
+ gig_dbg(DEBUG_IF, "%u: new_state %x",
+ cs->minor_index, new_state);
+ gigaset_set_modem_ctrl(cs, control_state, new_state);
control_state = new_state;
}
#endif
@@ -584,7 +591,7 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old)
cs->control_state = control_state;
out:
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
}
@@ -600,7 +607,7 @@ static void if_wake(unsigned long data)
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup) {
- dbg(DEBUG_IF, "write wakeup call");
+ gig_dbg(DEBUG_IF, "write wakeup call");
tty->ldisc.write_wakeup(tty);
}
@@ -635,14 +642,14 @@ void gigaset_if_free(struct cardstate *cs)
}
void gigaset_if_receive(struct cardstate *cs,
- unsigned char *buffer, size_t len)
+ unsigned char *buffer, size_t len)
{
unsigned long flags;
struct tty_struct *tty;
spin_lock_irqsave(&cs->lock, flags);
if ((tty = cs->tty) == NULL)
- dbg(DEBUG_ANY, "receive on closed device");
+ gig_dbg(DEBUG_ANY, "receive on closed device");
else {
tty_buffer_request_room(tty, len);
tty_insert_flip_string(tty, buffer, len);
@@ -655,13 +662,13 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive);
/* gigaset_if_initdriver
* Initialize tty interface.
* parameters:
- * drv Driver
- * procname Name of the driver (e.g. for /proc/tty/drivers)
- * devname Name of the device files (prefix without minor number)
- * devfsname Devfs name of the device files without %d
+ * drv Driver
+ * procname Name of the driver (e.g. for /proc/tty/drivers)
+ * devname Name of the device files (prefix without minor number)
+ * devfsname Devfs name of the device files without %d
*/
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
- const char *devname, const char *devfsname)
+ const char *devname, const char *devfsname)
{
unsigned minors = drv->minors;
int ret;
@@ -696,7 +703,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
warn("failed to register tty driver (error %d)", ret);
goto error;
}
- dbg(DEBUG_IF, "tty driver initialized");
+ gig_dbg(DEBUG_IF, "tty driver initialized");
drv->have_tty = 1;
return;
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index 5744eb91b315..45f017ed6e8c 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -10,10 +10,6 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: isocdata.c,v 1.2.2.5 2005/11/13 23:05:19 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
@@ -87,14 +83,14 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
{
if (!atomic_dec_and_test(&iwb->writesem)) {
atomic_inc(&iwb->writesem);
- dbg(DEBUG_ISO,
- "%s: couldn't acquire iso write semaphore", __func__);
+ gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore",
+ __func__);
return 0;
}
#ifdef CONFIG_GIGASET_DEBUG
- dbg(DEBUG_ISO,
- "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
- __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
+ gig_dbg(DEBUG_ISO,
+ "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
+ __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
#endif
return 1;
}
@@ -147,7 +143,7 @@ static inline void isowbuf_putflag(struct isowbuf_t *iwb)
/* recover the idle flag byte */
write = atomic_read(&iwb->write);
iwb->idle = iwb->data[write];
- dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
+ gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
/* mask extraneous bits in buffer */
iwb->data[write] &= (1 << iwb->wbits) - 1;
}
@@ -166,15 +162,14 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
read = atomic_read(&iwb->nextread);
write = atomic_read(&iwb->write);
if (likely(read == write)) {
- //dbg(DEBUG_STREAM, "%s: send buffer empty", __func__);
/* return idle frame */
return read < BAS_OUTBUFPAD ?
- BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
+ BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
}
limit = read + size;
- dbg(DEBUG_STREAM,
- "%s: read=%d write=%d limit=%d", __func__, read, write, limit);
+ gig_dbg(DEBUG_STREAM, "%s: read=%d write=%d limit=%d",
+ __func__, read, write, limit);
#ifdef CONFIG_GIGASET_DEBUG
if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
err("invalid size %d", size);
@@ -196,11 +191,12 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
return -EBUSY;
/* write position could have changed */
if (limit >= (write = atomic_read(&iwb->write))) {
- pbyte = iwb->data[write]; /* save partial byte */
+ pbyte = iwb->data[write]; /* save
+ partial byte */
limit = write + BAS_OUTBUFPAD;
- dbg(DEBUG_STREAM,
- "%s: filling %d->%d with %02x",
- __func__, write, limit, iwb->idle);
+ gig_dbg(DEBUG_STREAM,
+ "%s: filling %d->%d with %02x",
+ __func__, write, limit, iwb->idle);
if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE)
memset(iwb->data + write, iwb->idle,
BAS_OUTBUFPAD);
@@ -211,9 +207,11 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
- write);
limit = 0;
}
- dbg(DEBUG_STREAM, "%s: restoring %02x at %d",
- __func__, pbyte, limit);
- iwb->data[limit] = pbyte; /* restore partial byte */
+ gig_dbg(DEBUG_STREAM,
+ "%s: restoring %02x at %d",
+ __func__, pbyte, limit);
+ iwb->data[limit] = pbyte; /* restore
+ partial byte */
atomic_set(&iwb->write, limit);
}
isowbuf_donewrite(iwb);
@@ -242,19 +240,17 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
* write hex bytes to syslog for debugging
*/
static inline void dump_bytes(enum debuglevel level, const char *tag,
- unsigned char *bytes, int count)
+ unsigned char *bytes, int count)
{
#ifdef CONFIG_GIGASET_DEBUG
unsigned char c;
static char dbgline[3 * 32 + 1];
static const char hexdigit[] = "0123456789abcdef";
int i = 0;
- IFNULLRET(tag);
- IFNULLRET(bytes);
while (count-- > 0) {
if (i > sizeof(dbgline) - 4) {
dbgline[i] = '\0';
- dbg(level, "%s:%s", tag, dbgline);
+ gig_dbg(level, "%s:%s", tag, dbgline);
i = 0;
}
c = *bytes++;
@@ -264,7 +260,7 @@ static inline void dump_bytes(enum debuglevel level, const char *tag,
dbgline[i++] = hexdigit[c & 0x0f];
}
dbgline[i] = '\0';
- dbg(level, "%s:%s", tag, dbgline);
+ gig_dbg(level, "%s:%s", tag, dbgline);
#endif
}
@@ -380,7 +376,7 @@ static u16 stufftab[5 * 256] = {
*/
static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
- int ones)
+ int ones)
{
u16 stuff;
int shiftinc, newones;
@@ -422,7 +418,7 @@ static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
*/
static inline int hdlc_buildframe(struct isowbuf_t *iwb,
- unsigned char *in, int count)
+ unsigned char *in, int count)
{
int ones;
u16 fcs;
@@ -431,8 +427,8 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb,
if (isowbuf_freebytes(iwb) < count + count / 5 + 6 ||
!isowbuf_startwrite(iwb)) {
- dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
- __func__, isowbuf_freebytes(iwb));
+ gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
+ __func__, isowbuf_freebytes(iwb));
return -EAGAIN;
}
@@ -484,11 +480,11 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
if (isowbuf_freebytes(iwb) < count ||
!isowbuf_startwrite(iwb)) {
- dbg(DEBUG_ISO, "can't put %d bytes", count);
+ gig_dbg(DEBUG_ISO, "can't put %d bytes", count);
return -EAGAIN;
}
- dbg(DEBUG_STREAM, "put %d bytes", count);
+ gig_dbg(DEBUG_STREAM, "put %d bytes", count);
write = atomic_read(&iwb->write);
do {
c = gigaset_invtab[*in++];
@@ -508,11 +504,13 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
switch (bcs->proto2) {
case ISDN_PROTO_L2_HDLC:
result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
- dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", __func__, len, result);
+ gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d",
+ __func__, len, result);
break;
default: /* assume transparent */
result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len);
- dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", __func__, len, result);
+ gig_dbg(DEBUG_ISO, "%s: %d bytes trans -> %d",
+ __func__, len, result);
}
return result;
}
@@ -528,13 +526,13 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)
return;
}
if (unlikely(bcs->skb->len == SBUFSIZE)) {
- warn("received oversized packet discarded");
+ dev_warn(bcs->cs->dev, "received oversized packet discarded\n");
bcs->hw.bas->giants++;
dev_kfree_skb_any(bcs->skb);
bcs->skb = NULL;
return;
}
- *gigaset_skb_put_quick(bcs->skb, 1) = c;
+ *__skb_put(bcs->skb, 1) = c;
}
/* hdlc_flush
@@ -549,7 +547,7 @@ static inline void hdlc_flush(struct bc_state *bcs)
if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else
- err("could not allocate skb");
+ dev_err(bcs->cs->dev, "could not allocate skb\n");
}
/* reset packet state */
@@ -571,23 +569,25 @@ static inline void hdlc_done(struct bc_state *bcs)
if ((procskb = bcs->skb) == NULL) {
/* previous error */
- dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
+ gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
gigaset_rcv_error(NULL, bcs->cs, bcs);
} else if (procskb->len < 2) {
- notice("received short frame (%d octets)", procskb->len);
+ dev_notice(bcs->cs->dev, "received short frame (%d octets)\n",
+ procskb->len);
bcs->hw.bas->runts++;
gigaset_rcv_error(procskb, bcs->cs, bcs);
} else if (bcs->fcs != PPP_GOODFCS) {
- notice("frame check error (0x%04x)", bcs->fcs);
+ dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n",
+ bcs->fcs);
bcs->hw.bas->fcserrs++;
gigaset_rcv_error(procskb, bcs->cs, bcs);
} else {
procskb->len -= 2; /* subtract FCS */
procskb->tail -= 2;
- dbg(DEBUG_ISO,
- "%s: good frame (%d octets)", __func__, procskb->len);
+ gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)",
+ __func__, procskb->len);
dump_bytes(DEBUG_STREAM,
- "rcv data", procskb->data, procskb->len);
+ "rcv data", procskb->data, procskb->len);
bcs->hw.bas->goodbytes += procskb->len;
gigaset_rcv_skb(procskb, bcs->cs, bcs);
}
@@ -595,7 +595,7 @@ static inline void hdlc_done(struct bc_state *bcs)
if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else
- err("could not allocate skb");
+ dev_err(bcs->cs->dev, "could not allocate skb\n");
bcs->fcs = PPP_INITFCS;
}
@@ -610,14 +610,14 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
return;
}
- notice("received partial byte (%d bits)", inbits);
+ dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);
bcs->hw.bas->alignerrs++;
gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else
- err("could not allocate skb");
+ dev_err(bcs->cs->dev, "could not allocate skb\n");
bcs->fcs = PPP_INITFCS;
}
@@ -659,16 +659,12 @@ static unsigned char bitcounts[256] = {
* bcs receiving B channel structure
*/
static inline void hdlc_unpack(unsigned char *src, unsigned count,
- struct bc_state *bcs)
+ struct bc_state *bcs)
{
- struct bas_bc_state *ubc;
+ struct bas_bc_state *ubc = bcs->hw.bas;
int inputstate;
unsigned seqlen, inbyte, inbits;
- IFNULLRET(bcs);
- ubc = bcs->hw.bas;
- IFNULLRET(ubc);
-
/* load previous state:
* inputstate = set of flag bits:
* - INS_flag_hunt: no complete opening flag received since connection setup or last abort
@@ -856,7 +852,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count,
* bcs receiving B channel structure
*/
static inline void trans_receive(unsigned char *src, unsigned count,
- struct bc_state *bcs)
+ struct bc_state *bcs)
{
struct sk_buff *skb;
int dobytes;
@@ -870,7 +866,7 @@ static inline void trans_receive(unsigned char *src, unsigned count,
if (unlikely((skb = bcs->skb) == NULL)) {
bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
if (!skb) {
- err("could not allocate skb");
+ dev_err(bcs->cs->dev, "could not allocate skb\n");
return;
}
skb_reserve(skb, HW_HDR_LEN);
@@ -888,7 +884,8 @@ static inline void trans_receive(unsigned char *src, unsigned count,
gigaset_rcv_skb(skb, bcs->cs, bcs);
bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
if (!skb) {
- err("could not allocate skb");
+ dev_err(bcs->cs->dev,
+ "could not allocate skb\n");
return;
}
skb_reserve(bcs->skb, HW_HDR_LEN);
@@ -921,8 +918,8 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
case '\r':
case '\n':
/* end of line */
- dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
- __func__, cbytes);
+ gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
+ __func__, cbytes);
cs->cbytes = cbytes;
gigaset_handle_modem_response(cs);
cbytes = 0;
@@ -932,7 +929,7 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
if (cbytes < MAX_RESP_SIZE - 1)
cbytes++;
else
- warn("response too large");
+ dev_warn(cs->dev, "response too large\n");
}
}
@@ -951,27 +948,27 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
head = atomic_read(&inbuf->head);
while (head != (tail = atomic_read(&inbuf->tail))) {
- dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
+ gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
if (head > tail)
tail = RBUFSIZE;
src = inbuf->data + head;
numbytes = tail - head;
- dbg(DEBUG_INTR, "processing %u bytes", numbytes);
+ gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
if (atomic_read(&cs->mstate) == MS_LOCKED) {
gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
- numbytes, src, 0);
+ numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes);
} else {
gigaset_dbg_buffer(DEBUG_CMD, "received response",
- numbytes, src, 0);
+ numbytes, src);
cmd_loop(src, numbytes, inbuf);
}
head += numbytes;
if (head == RBUFSIZE)
head = 0;
- dbg(DEBUG_INTR, "setting head to %u", head);
+ gig_dbg(DEBUG_INTR, "setting head to %u", head);
atomic_set(&inbuf->head, head);
}
}
@@ -992,18 +989,18 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
*/
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
{
- int len;
-
- IFNULLRETVAL(bcs, -EFAULT);
- IFNULLRETVAL(skb, -EFAULT);
- len = skb->len;
+ int len = skb->len;
+ unsigned long flags;
skb_queue_tail(&bcs->squeue, skb);
- dbg(DEBUG_ISO,
- "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue));
+ gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
+ __func__, skb_queue_len(&bcs->squeue));
/* tasklet submits URB if necessary */
- tasklet_schedule(&bcs->hw.bas->sent_tasklet);
+ spin_lock_irqsave(&bcs->cs->lock, flags);
+ if (bcs->cs->connected)
+ tasklet_schedule(&bcs->hw.bas->sent_tasklet);
+ spin_unlock_irqrestore(&bcs->cs->lock, flags);
return len; /* ok so far */
}
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c
index c6915fa2be6c..d267a636b53c 100644
--- a/drivers/isdn/gigaset/proc.c
+++ b/drivers/isdn/gigaset/proc.c
@@ -1,7 +1,7 @@
/*
* Stuff used by all variants of the driver
*
- * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>,
+ * Copyright (c) 2001 by Stefan Eilers,
* Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>.
*
@@ -11,26 +11,29 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: proc.c,v 1.5.2.13 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
#include <linux/ctype.h>
-static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct cardstate *cs = usb_get_intfdata(intf);
- return sprintf(buf, "%d\n", atomic_read(&cs->cidmode)); // FIXME use scnprintf for 13607 bit architectures (if PAGE_SIZE==4096)
+ int ret;
+ unsigned long flags;
+ struct cardstate *cs = dev_get_drvdata(dev);
+
+ spin_lock_irqsave(&cs->lock, flags);
+ ret = sprintf(buf, "%u\n", cs->cidmode);
+ spin_unlock_irqrestore(&cs->lock, flags);
+
+ return ret;
}
-static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct cardstate *cs = usb_get_intfdata(intf);
+ struct cardstate *cs = dev_get_drvdata(dev);
long int value;
char *end;
@@ -41,23 +44,23 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, co
if (value < 0 || value > 1)
return -EINVAL;
- if (down_interruptible(&cs->sem))
+ if (mutex_lock_interruptible(&cs->mutex))
return -ERESTARTSYS; // FIXME -EINTR?
cs->waiting = 1;
if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE,
- NULL, value, NULL)) {
+ NULL, value, NULL)) {
cs->waiting = 0;
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return -ENOMEM;
}
- dbg(DEBUG_CMD, "scheduling PROC_CIDMODE");
+ gig_dbg(DEBUG_CMD, "scheduling PROC_CIDMODE");
gigaset_schedule_event(cs);
wait_event(cs->waitqueue, !cs->waiting);
- up(&cs->sem);
+ mutex_unlock(&cs->mutex);
return count;
}
@@ -65,17 +68,15 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, co
static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode);
/* free sysfs for device */
-void gigaset_free_dev_sysfs(struct usb_interface *interface)
+void gigaset_free_dev_sysfs(struct cardstate *cs)
{
- dbg(DEBUG_INIT, "removing sysfs entries");
- device_remove_file(&interface->dev, &dev_attr_cidmode);
+ gig_dbg(DEBUG_INIT, "removing sysfs entries");
+ device_remove_file(cs->dev, &dev_attr_cidmode);
}
-EXPORT_SYMBOL_GPL(gigaset_free_dev_sysfs);
/* initialize sysfs for device */
-void gigaset_init_dev_sysfs(struct usb_interface *interface)
+void gigaset_init_dev_sysfs(struct cardstate *cs)
{
- dbg(DEBUG_INIT, "setting up sysfs");
- device_create_file(&interface->dev, &dev_attr_cidmode);
+ gig_dbg(DEBUG_INIT, "setting up sysfs");
+ device_create_file(cs->dev, &dev_attr_cidmode);
}
-EXPORT_SYMBOL_GPL(gigaset_init_dev_sysfs);
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 323fc7349dec..bfb73fd5077e 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -1,7 +1,7 @@
/*
* USB driver for Gigaset 307x directly or using M105 Data.
*
- * Copyright (c) 2001 by Stefan Eilers <Eilers.Stefan@epost.de>
+ * Copyright (c) 2001 by Stefan Eilers
* and Hansjoerg Lipp <hjlipp@web.de>.
*
* This driver was derived from the USB skeleton driver by
@@ -13,10 +13,6 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* =====================================================================
- * ToDo: ...
- * =====================================================================
- * Version: $Id: usb-gigaset.c,v 1.85.4.18 2006/02/04 18:28:16 hjlipp Exp $
- * =====================================================================
*/
#include "gigaset.h"
@@ -29,7 +25,7 @@
#include <linux/moduleparam.h>
/* Version Information */
-#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers <Eilers.Stefan@epost.de>"
+#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers"
#define DRIVER_DESC "USB Driver for Gigaset 307x using M105"
/* Module parameters */
@@ -62,10 +58,6 @@ static struct usb_device_id gigaset_table [] = {
MODULE_DEVICE_TABLE(usb, gigaset_table);
-/* Get a minor range for your devices from the usb maintainer */
-#define USB_SKEL_MINOR_BASE 200
-
-
/*
* Control requests (empty fields: 00)
*
@@ -114,7 +106,7 @@ MODULE_DEVICE_TABLE(usb, gigaset_table);
*/
static int gigaset_probe(struct usb_interface *interface,
- const struct usb_device_id *id);
+ const struct usb_device_id *id);
static void gigaset_disconnect(struct usb_interface *interface);
static struct gigaset_driver *driver = NULL;
@@ -122,29 +114,29 @@ static struct cardstate *cardstate = NULL;
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver gigaset_usb_driver = {
- .name = GIGASET_MODULENAME,
- .probe = gigaset_probe,
- .disconnect = gigaset_disconnect,
- .id_table = gigaset_table,
+ .name = GIGASET_MODULENAME,
+ .probe = gigaset_probe,
+ .disconnect = gigaset_disconnect,
+ .id_table = gigaset_table,
};
struct usb_cardstate {
- struct usb_device *udev; /* save off the usb device pointer */
- struct usb_interface *interface; /* the interface for this device */
- atomic_t busy; /* bulk output in progress */
-
- /* Output buffer for commands (M105: and data)*/
- unsigned char *bulk_out_buffer; /* the buffer to send data */
- int bulk_out_size; /* the size of the send buffer */
- __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
- struct urb *bulk_out_urb; /* the urb used to transmit data */
-
- /* Input buffer for command responses (M105: and data)*/
- int rcvbuf_size; /* the size of the receive buffer */
- struct urb *read_urb; /* the urb used to receive data */
- __u8 int_in_endpointAddr; /* the address of the bulk in endpoint */
-
- char bchars[6]; /* req. 0x19 */
+ struct usb_device *udev; /* usb device pointer */
+ struct usb_interface *interface; /* interface for this device */
+ atomic_t busy; /* bulk output in progress */
+
+ /* Output buffer */
+ unsigned char *bulk_out_buffer;
+ int bulk_out_size;
+ __u8 bulk_out_endpointAddr;
+ struct urb *bulk_out_urb;
+
+ /* Input buffer */
+ int rcvbuf_size;
+ struct urb *read_urb;
+ __u8 int_in_endpointAddr;
+
+ char bchars[6]; /* for request 0x19 */
};
struct usb_bc_state {};
@@ -157,19 +149,20 @@ static inline unsigned tiocm_to_gigaset(unsigned state)
#ifdef CONFIG_GIGASET_UNDOCREQ
/* WARNING: EXPERIMENTAL! */
static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
- unsigned new_state)
+ unsigned new_state)
{
+ struct usb_device *udev = cs->hw.usb->udev;
unsigned mask, val;
int r;
mask = tiocm_to_gigaset(old_state ^ new_state);
val = tiocm_to_gigaset(new_state);
- dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask);
- r = usb_control_msg(cs->hw.usb->udev,
- usb_sndctrlpipe(cs->hw.usb->udev, 0), 7, 0x41,
- (val & 0xff) | ((mask & 0xff) << 8), 0,
- NULL, 0, 2000 /*timeout??*/); // don't use this in an interrupt/BH
+ gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask);
+ // don't use this in an interrupt/BH
+ r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41,
+ (val & 0xff) | ((mask & 0xff) << 8), 0,
+ NULL, 0, 2000 /* timeout? */);
if (r < 0)
return r;
//..
@@ -178,30 +171,29 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
static int set_value(struct cardstate *cs, u8 req, u16 val)
{
+ struct usb_device *udev = cs->hw.usb->udev;
int r, r2;
- dbg(DEBUG_USBREQ, "request %02x (%04x)", (unsigned)req, (unsigned)val);
- r = usb_control_msg(cs->hw.usb->udev,
- usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x12, 0x41,
- 0xf /*?*/, 0,
- NULL, 0, 2000 /*?*/); /* no idea, what this does */
+ gig_dbg(DEBUG_USBREQ, "request %02x (%04x)",
+ (unsigned)req, (unsigned)val);
+ r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x12, 0x41,
+ 0xf /*?*/, 0, NULL, 0, 2000 /*?*/);
+ /* no idea what this does */
if (r < 0) {
- err("error %d on request 0x12", -r);
+ dev_err(&udev->dev, "error %d on request 0x12\n", -r);
return r;
}
- r = usb_control_msg(cs->hw.usb->udev,
- usb_sndctrlpipe(cs->hw.usb->udev, 0), req, 0x41,
- val, 0,
- NULL, 0, 2000 /*?*/);
+ r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), req, 0x41,
+ val, 0, NULL, 0, 2000 /*?*/);
if (r < 0)
- err("error %d on request 0x%02x", -r, (unsigned)req);
+ dev_err(&udev->dev, "error %d on request 0x%02x\n",
+ -r, (unsigned)req);
- r2 = usb_control_msg(cs->hw.usb->udev,
- usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41,
- 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/);
+ r2 = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41,
+ 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/);
if (r2 < 0)
- err("error %d on request 0x19", -r2);
+ dev_err(&udev->dev, "error %d on request 0x19\n", -r2);
return r < 0 ? r : (r2 < 0 ? r2 : 0);
}
@@ -229,8 +221,8 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
case B115200: rate = 115200; break;
default:
rate = 9600;
- err("unsupported baudrate request 0x%x,"
- " using default of B9600", cflag);
+ dev_err(cs->dev, "unsupported baudrate request 0x%x,"
+ " using default of B9600\n", cflag);
}
val = 0x383fff / rate + 1;
@@ -259,7 +251,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
case CS8:
val |= 8 << 8; break;
default:
- err("CSIZE was not CS5-CS8, using default of 8");
+ dev_err(cs->dev, "CSIZE was not CS5-CS8, using default of 8\n");
val |= 8 << 8;
break;
}
@@ -277,7 +269,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
#else
static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
- unsigned new_state)
+ unsigned new_state)
{
return -EINVAL;
}
@@ -309,15 +301,12 @@ static int gigaset_close_bchannel(struct bc_state *bcs)
return 0;
}
-//void send_ack_to_LL(void *data);
static int write_modem(struct cardstate *cs);
static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb);
-/* Handling of send queue. If there is already a skb opened, put data to
- * the transfer buffer by calling "write_modem". Otherwise take a new skb out of the queue.
- * This function will be called by the ISR via "transmit_chars" (USB: B-Channel Bulk callback handler
- * via immediate task queue) or by writebuf_from_LL if the LL wants to transmit data.
+/* Write tasklet handler: Continue sending current skb, or send command, or
+ * start sending an skb from the send queue.
*/
static void gigaset_modem_fill(unsigned long data)
{
@@ -327,10 +316,10 @@ static void gigaset_modem_fill(unsigned long data)
unsigned long flags;
int again;
- dbg(DEBUG_OUTPUT, "modem_fill");
+ gig_dbg(DEBUG_OUTPUT, "modem_fill");
if (atomic_read(&cs->hw.usb->busy)) {
- dbg(DEBUG_OUTPUT, "modem_fill: busy");
+ gig_dbg(DEBUG_OUTPUT, "modem_fill: busy");
return;
}
@@ -341,26 +330,27 @@ static void gigaset_modem_fill(unsigned long data)
cb = cs->cmdbuf;
spin_unlock_irqrestore(&cs->cmdlock, flags);
if (cb) { /* commands to send? */
- dbg(DEBUG_OUTPUT, "modem_fill: cb");
+ gig_dbg(DEBUG_OUTPUT, "modem_fill: cb");
if (send_cb(cs, cb) < 0) {
- dbg(DEBUG_OUTPUT,
- "modem_fill: send_cb failed");
- again = 1; /* no callback will be called! */
+ gig_dbg(DEBUG_OUTPUT,
+ "modem_fill: send_cb failed");
+ again = 1; /* no callback will be
+ called! */
}
} else { /* skbs to send? */
bcs->tx_skb = skb_dequeue(&bcs->squeue);
if (bcs->tx_skb)
- dbg(DEBUG_INTR,
- "Dequeued skb (Adr: %lx)!",
- (unsigned long) bcs->tx_skb);
+ gig_dbg(DEBUG_INTR,
+ "Dequeued skb (Adr: %lx)!",
+ (unsigned long) bcs->tx_skb);
}
}
if (bcs->tx_skb) {
- dbg(DEBUG_OUTPUT, "modem_fill: tx_skb");
+ gig_dbg(DEBUG_OUTPUT, "modem_fill: tx_skb");
if (write_modem(cs) < 0) {
- dbg(DEBUG_OUTPUT,
- "modem_fill: write_modem failed");
+ gig_dbg(DEBUG_OUTPUT,
+ "modem_fill: write_modem failed");
// FIXME should we tell the LL?
again = 1; /* no callback will be called! */
}
@@ -371,88 +361,85 @@ static void gigaset_modem_fill(unsigned long data)
/**
* gigaset_read_int_callback
*
- * It is called if the data was received from the device. This is almost similiar to
- * the interrupt service routine in the serial device.
+ * It is called if the data was received from the device.
*/
static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
{
+ struct inbuf_t *inbuf = urb->context;
+ struct cardstate *cs = inbuf->cs;
int resubmit = 0;
int r;
- struct cardstate *cs;
unsigned numbytes;
unsigned char *src;
- //unsigned long flags;
- struct inbuf_t *inbuf;
-
- IFNULLRET(urb);
- inbuf = (struct inbuf_t *) urb->context;
- IFNULLRET(inbuf);
- //spin_lock_irqsave(&inbuf->lock, flags);
- cs = inbuf->cs;
- IFNULLGOTO(cs, exit);
- IFNULLGOTO(cardstate, exit);
-
- if (!atomic_read(&cs->connected)) {
- err("%s: disconnected", __func__);
- goto exit;
- }
+ unsigned long flags;
if (!urb->status) {
+ if (!cs->connected) {
+ err("%s: disconnected", __func__); /* should never happen */
+ return;
+ }
+
numbytes = urb->actual_length;
if (numbytes) {
src = inbuf->rcvbuf;
if (unlikely(*src))
- warn("%s: There was no leading 0, but 0x%02x!",
- __func__, (unsigned) *src);
+ dev_warn(cs->dev,
+ "%s: There was no leading 0, but 0x%02x!\n",
+ __func__, (unsigned) *src);
++src; /* skip leading 0x00 */
--numbytes;
if (gigaset_fill_inbuf(inbuf, src, numbytes)) {
- dbg(DEBUG_INTR, "%s-->BH", __func__);
+ gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(inbuf->cs);
}
} else
- dbg(DEBUG_INTR, "Received zero block length");
+ gig_dbg(DEBUG_INTR, "Received zero block length");
resubmit = 1;
} else {
/* The urb might have been killed. */
- dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
- __func__, urb->status);
- if (urb->status != -ENOENT) /* not killed */
+ gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d",
+ __func__, urb->status);
+ if (urb->status != -ENOENT) { /* not killed */
+ if (!cs->connected) {
+ err("%s: disconnected", __func__); /* should never happen */
+ return;
+ }
resubmit = 1;
+ }
}
-exit:
- //spin_unlock_irqrestore(&inbuf->lock, flags);
+
if (resubmit) {
- r = usb_submit_urb(urb, SLAB_ATOMIC);
+ spin_lock_irqsave(&cs->lock, flags);
+ r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV;
+ spin_unlock_irqrestore(&cs->lock, flags);
if (r)
- err("error %d when resubmitting urb.", -r);
+ dev_err(cs->dev, "error %d when resubmitting urb.\n",
+ -r);
}
}
-/* This callback routine is called when data was transmitted to a B-Channel.
- * Therefore it has to check if there is still data to transmit. This
- * happens by calling modem_fill via task queue.
- *
- */
+/* This callback routine is called when data was transmitted to the device. */
static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
- struct cardstate *cs = (struct cardstate *) urb->context;
+ struct cardstate *cs = urb->context;
+ unsigned long flags;
- IFNULLRET(cs);
-#ifdef CONFIG_GIGASET_DEBUG
- if (!atomic_read(&cs->connected)) {
- err("%s:not connected", __func__);
- return;
- }
-#endif
if (urb->status)
- err("bulk transfer failed (status %d)", -urb->status); /* That's all we can do. Communication problems
- are handeled by timeouts or network protocols */
+ dev_err(cs->dev, "bulk transfer failed (status %d)\n",
+ -urb->status);
+ /* That's all we can do. Communication problems
+ are handled by timeouts or network protocols. */
- atomic_set(&cs->hw.usb->busy, 0);
- tasklet_schedule(&cs->write_tasklet);
+ spin_lock_irqsave(&cs->lock, flags);
+ if (!cs->connected) {
+ err("%s: not connected", __func__);
+ } else {
+ atomic_set(&cs->hw.usb->busy, 0);
+ tasklet_schedule(&cs->write_tasklet);
+ }
+ spin_unlock_irqrestore(&cs->lock, flags);
}
static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
@@ -469,8 +456,8 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
spin_lock_irqsave(&cs->cmdlock, flags);
cs->cmdbytes -= cs->curlen;
- dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left",
- cs->curlen, cs->cmdbytes);
+ gig_dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left",
+ cs->curlen, cs->cmdbytes);
cs->cmdbuf = cb = cb->next;
if (cb) {
cb->prev = NULL;
@@ -487,52 +474,51 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb)
}
if (cb) {
count = min(cb->len, ucs->bulk_out_size);
+ gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
+
usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
- usb_sndbulkpipe(ucs->udev,
- ucs->bulk_out_endpointAddr & 0x0f),
- cb->buf + cb->offset, count,
- gigaset_write_bulk_callback, cs);
+ usb_sndbulkpipe(ucs->udev,
+ ucs->bulk_out_endpointAddr & 0x0f),
+ cb->buf + cb->offset, count,
+ gigaset_write_bulk_callback, cs);
cb->offset += count;
cb->len -= count;
atomic_set(&ucs->busy, 1);
- dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count);
- status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+ spin_lock_irqsave(&cs->lock, flags);
+ status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV;
+ spin_unlock_irqrestore(&cs->lock, flags);
+
if (status) {
atomic_set(&ucs->busy, 0);
- err("could not submit urb (error %d).",
+ err("could not submit urb (error %d)\n",
-status);
- cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */
+ cb->len = 0; /* skip urb => remove cb+wakeup
+ in next loop cycle */
}
}
- } while (cb && status); /* bei Fehler naechster Befehl //FIXME: ist das OK? */
+ } while (cb && status); /* next command on error */
return status;
}
-/* Write string into transbuf and send it to modem.
- */
+/* Send command to device. */
static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
- int len, struct tasklet_struct *wake_tasklet)
+ int len, struct tasklet_struct *wake_tasklet)
{
struct cmdbuf_t *cb;
unsigned long flags;
gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
- DEBUG_TRANSCMD : DEBUG_LOCKCMD,
- "CMD Transmit", len, buf, 0);
-
- if (!atomic_read(&cs->connected)) {
- err("%s: not connected", __func__);
- return -ENODEV;
- }
+ DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+ "CMD Transmit", len, buf);
if (len <= 0)
return 0;
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
- err("%s: out of memory", __func__);
+ dev_err(cs->dev, "%s: out of memory\n", __func__);
return -ENOMEM;
}
@@ -554,7 +540,10 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
cs->lastcmdbuf = cb;
spin_unlock_irqrestore(&cs->cmdlock, flags);
- tasklet_schedule(&cs->write_tasklet);
+ spin_lock_irqsave(&cs->lock, flags);
+ if (cs->connected)
+ tasklet_schedule(&cs->write_tasklet);
+ spin_unlock_irqrestore(&cs->lock, flags);
return len;
}
@@ -578,11 +567,12 @@ static int gigaset_chars_in_buffer(struct cardstate *cs)
static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
{
#ifdef CONFIG_GIGASET_UNDOCREQ
- gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf, 0);
+ struct usb_device *udev = cs->hw.usb->udev;
+
+ gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf);
memcpy(cs->hw.usb->bchars, buf, 6);
- return usb_control_msg(cs->hw.usb->udev,
- usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41,
- 0, 0, &buf, 6, 2000);
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41,
+ 0, 0, &buf, 6, 2000);
#else
return -EINVAL;
#endif
@@ -604,7 +594,6 @@ static int gigaset_initbcshw(struct bc_state *bcs)
if (!bcs->hw.usb)
return 0;
- //bcs->hw.usb->trans_flg = READY_TO_TRNSMIT; /* B-Channel ready to transmit */
return 1;
}
@@ -614,7 +603,6 @@ static void gigaset_reinitbcshw(struct bc_state *bcs)
static void gigaset_freecshw(struct cardstate *cs)
{
- //FIXME
tasklet_kill(&cs->write_tasklet);
kfree(cs->hw.usb);
}
@@ -639,33 +627,21 @@ static int gigaset_initcshw(struct cardstate *cs)
//ucs->urb_cmd_out = NULL;
ucs->read_urb = NULL;
tasklet_init(&cs->write_tasklet,
- &gigaset_modem_fill, (unsigned long) cs);
+ &gigaset_modem_fill, (unsigned long) cs);
return 1;
}
-/* Writes the data of the current open skb into the modem.
- * We have to protect against multiple calls until the
- * callback handler () is called , due to the fact that we
- * are just allowed to send data once to an endpoint. Therefore
- * we using "trans_flg" to synchonize ...
- */
+/* Send data from current skb to the device. */
static int write_modem(struct cardstate *cs)
{
- int ret;
+ int ret = 0;
int count;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct usb_cardstate *ucs = cs->hw.usb;
- //unsigned long flags;
-
- IFNULLRETVAL(bcs->tx_skb, -EINVAL);
-
- dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
+ unsigned long flags;
- ret = -ENODEV;
- IFNULLGOTO(ucs->bulk_out_buffer, error);
- IFNULLGOTO(ucs->bulk_out_urb, error);
- ret = 0;
+ gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len);
if (!bcs->tx_skb->len) {
dev_kfree_skb_any(bcs->tx_skb);
@@ -679,40 +655,42 @@ static int write_modem(struct cardstate *cs)
count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
skb_pull(bcs->tx_skb, count);
-
- usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
- usb_sndbulkpipe(ucs->udev,
- ucs->bulk_out_endpointAddr & 0x0f),
- ucs->bulk_out_buffer, count,
- gigaset_write_bulk_callback, cs);
atomic_set(&ucs->busy, 1);
- dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
+ gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
+
+ spin_lock_irqsave(&cs->lock, flags);
+ if (cs->connected) {
+ usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev,
+ usb_sndbulkpipe(ucs->udev,
+ ucs->bulk_out_endpointAddr & 0x0f),
+ ucs->bulk_out_buffer, count,
+ gigaset_write_bulk_callback, cs);
+ ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
+ } else {
+ ret = -ENODEV;
+ }
+ spin_unlock_irqrestore(&cs->lock, flags);
- ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC);
if (ret) {
- err("could not submit urb (error %d).", -ret);
+ err("could not submit urb (error %d)\n", -ret);
atomic_set(&ucs->busy, 0);
}
+
if (!bcs->tx_skb->len) {
/* skb sent completely */
gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0?
- dbg(DEBUG_INTR,
- "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb);
+ gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!",
+ (unsigned long) bcs->tx_skb);
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
return ret;
-error:
- dev_kfree_skb_any(bcs->tx_skb);
- bcs->tx_skb = NULL;
- return ret;
-
}
static int gigaset_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
+ const struct usb_device_id *id)
{
int retval;
struct usb_device *udev = interface_to_usbdev(interface);
@@ -720,16 +698,14 @@ static int gigaset_probe(struct usb_interface *interface,
struct usb_host_interface *hostif;
struct cardstate *cs = NULL;
struct usb_cardstate *ucs = NULL;
- //struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *endpoint;
- //isdn_ctrl command;
int buffer_size;
int alt;
- //unsigned long flags;
- info("%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
- __func__, le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
+ gig_dbg(DEBUG_ANY,
+ "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)",
+ __func__, le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
retval = -ENODEV; //FIXME
@@ -744,7 +720,7 @@ static int gigaset_probe(struct usb_interface *interface,
ifnum = hostif->desc.bInterfaceNumber; // FIXME ?
if (alt != 0 || ifnum != 0) {
- warn("ifnum %d, alt %d", ifnum, alt);
+ dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt);
return -ENODEV;
}
@@ -752,42 +728,29 @@ static int gigaset_probe(struct usb_interface *interface,
*
*/
if (hostif->desc.bInterfaceClass != 255) {
- info("%s: Device matched, but iface_desc[%d]->bInterfaceClass==%d !",
- __func__, ifnum, hostif->desc.bInterfaceClass);
+ dev_info(&udev->dev,
+ "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n",
+ __func__, ifnum, hostif->desc.bInterfaceClass);
return -ENODEV;
}
- info("%s: Device matched ... !", __func__);
+ dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
cs = gigaset_getunassignedcs(driver);
if (!cs) {
- warn("No free cardstate!");
+ dev_warn(&udev->dev, "no free cardstate\n");
return -ENODEV;
}
ucs = cs->hw.usb;
-#if 0
- if (usb_set_configuration(udev, udev->config[0].desc.bConfigurationValue) < 0) {
- warn("set_configuration failed");
- goto error;
- }
-
-
- if (usb_set_interface(udev, ifnum/*==0*/, alt/*==0*/) < 0) {
- warn("usb_set_interface failed, device %d interface %d altsetting %d",
- udev->devnum, ifnum, alt);
- goto error;
- }
-#endif
+ /* save off device structure ptrs for later use */
+ usb_get_dev(udev);
+ ucs->udev = udev;
+ ucs->interface = interface;
+ cs->dev = &interface->dev;
- /* set up the endpoint information */
- /* check out the endpoints */
- /* We will get 2 endpoints: One for sending commands to the device (bulk out) and one to
- * poll messages from the device(int in).
- * Therefore we will have an almost similiar situation as with our serial port handler.
- * If an connection will be established, we will have to create data in/out pipes
- * dynamically...
- */
+ /* save address of controller structure */
+ usb_set_intfdata(interface, cs); // dev_set_drvdata(&interface->dev, cs);
endpoint = &hostif->endpoint[0].desc;
@@ -796,14 +759,14 @@ static int gigaset_probe(struct usb_interface *interface,
ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress;
ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!ucs->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
+ dev_err(cs->dev, "Couldn't allocate bulk_out_buffer\n");
retval = -ENOMEM;
goto error;
}
ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL);
if (!ucs->bulk_out_urb) {
- err("Couldn't allocate bulk_out_buffer");
+ dev_err(cs->dev, "Couldn't allocate bulk_out_urb\n");
retval = -ENOMEM;
goto error;
}
@@ -811,12 +774,10 @@ static int gigaset_probe(struct usb_interface *interface,
endpoint = &hostif->endpoint[1].desc;
atomic_set(&ucs->busy, 0);
- ucs->udev = udev;
- ucs->interface = interface;
ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL);
if (!ucs->read_urb) {
- err("No free urbs available");
+ dev_err(cs->dev, "No free urbs available\n");
retval = -ENOMEM;
goto error;
}
@@ -825,38 +786,33 @@ static int gigaset_probe(struct usb_interface *interface,
ucs->int_in_endpointAddr = endpoint->bEndpointAddress;
cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL);
if (!cs->inbuf[0].rcvbuf) {
- err("Couldn't allocate rcvbuf");
+ dev_err(cs->dev, "Couldn't allocate rcvbuf\n");
retval = -ENOMEM;
goto error;
}
/* Fill the interrupt urb and send it to the core */
usb_fill_int_urb(ucs->read_urb, udev,
- usb_rcvintpipe(udev,
- endpoint->bEndpointAddress & 0x0f),
- cs->inbuf[0].rcvbuf, buffer_size,
- gigaset_read_int_callback,
- cs->inbuf + 0, endpoint->bInterval);
+ usb_rcvintpipe(udev,
+ endpoint->bEndpointAddress & 0x0f),
+ cs->inbuf[0].rcvbuf, buffer_size,
+ gigaset_read_int_callback,
+ cs->inbuf + 0, endpoint->bInterval);
retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL);
if (retval) {
- err("Could not submit URB!");
+ dev_err(cs->dev, "Could not submit URB (error %d)\n", -retval);
goto error;
}
/* tell common part that the device is ready */
if (startmode == SM_LOCKED)
atomic_set(&cs->mstate, MS_LOCKED);
+
if (!gigaset_start(cs)) {
tasklet_kill(&cs->write_tasklet);
retval = -ENODEV; //FIXME
goto error;
}
-
- /* save address of controller structure */
- usb_set_intfdata(interface, cs);
-
- /* set up device sysfs */
- gigaset_init_dev_sysfs(interface);
return 0;
error:
@@ -868,48 +824,45 @@ error:
kfree(cs->inbuf[0].rcvbuf);
if (ucs->read_urb != NULL)
usb_free_urb(ucs->read_urb);
+ usb_set_intfdata(interface, NULL);
ucs->read_urb = ucs->bulk_out_urb = NULL;
cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL;
+ usb_put_dev(ucs->udev);
+ ucs->udev = NULL;
+ ucs->interface = NULL;
gigaset_unassign(cs);
return retval;
}
-/**
- * skel_disconnect
- */
static void gigaset_disconnect(struct usb_interface *interface)
{
struct cardstate *cs;
struct usb_cardstate *ucs;
cs = usb_get_intfdata(interface);
-
- /* clear device sysfs */
- gigaset_free_dev_sysfs(interface);
-
- usb_set_intfdata(interface, NULL);
ucs = cs->hw.usb;
usb_kill_urb(ucs->read_urb);
- //info("GigaSet USB device #%d will be disconnected", minor);
gigaset_stop(cs);
+ usb_set_intfdata(interface, NULL);
tasklet_kill(&cs->write_tasklet);
- usb_kill_urb(ucs->bulk_out_urb); /* FIXME: nur, wenn noetig */
- //usb_kill_urb(ucs->urb_cmd_out); /* FIXME: nur, wenn noetig */
+ usb_kill_urb(ucs->bulk_out_urb); /* FIXME: only if active? */
kfree(ucs->bulk_out_buffer);
if (ucs->bulk_out_urb != NULL)
usb_free_urb(ucs->bulk_out_urb);
- //if(ucs->urb_cmd_out != NULL)
- // usb_free_urb(ucs->urb_cmd_out);
kfree(cs->inbuf[0].rcvbuf);
if (ucs->read_urb != NULL)
usb_free_urb(ucs->read_urb);
- ucs->read_urb = ucs->bulk_out_urb/*=ucs->urb_cmd_out*/=NULL;
+ ucs->read_urb = ucs->bulk_out_urb = NULL;
cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL;
+ usb_put_dev(ucs->udev);
+ ucs->interface = NULL;
+ ucs->udev = NULL;
+ cs->dev = NULL;
gigaset_unassign(cs);
}
@@ -942,9 +895,9 @@ static int __init usb_gigaset_init(void)
/* allocate memory for our driver state and intialize it */
if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
- GIGASET_MODULENAME, GIGASET_DEVNAME,
- GIGASET_DEVFSNAME, &ops,
- THIS_MODULE)) == NULL)
+ GIGASET_MODULENAME, GIGASET_DEVNAME,
+ GIGASET_DEVFSNAME, &ops,
+ THIS_MODULE)) == NULL)
goto error;
/* allocate memory for our device state and intialize it */
@@ -981,8 +934,8 @@ error: if (cardstate)
static void __exit usb_gigaset_exit(void)
{
gigaset_blockdriver(driver); /* => probe will fail
- * => no gigaset_start any more
- */
+ * => no gigaset_start any more
+ */
gigaset_shutdown(cardstate);
/* from now on, no isdn callback should be possible */
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index a0927d1b7a0c..918742271c79 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -109,7 +109,7 @@ isdn_ppp_free(isdn_net_local * lp)
{
struct ippp_struct *is;
- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
__FUNCTION__, lp->ppp_slot);
return 0;
@@ -126,7 +126,7 @@ isdn_ppp_free(isdn_net_local * lp)
lp->netdev->pb->ref_ct--;
spin_unlock(&lp->netdev->pb->lock);
#endif /* CONFIG_ISDN_MPP */
- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
__FUNCTION__, lp->ppp_slot);
return 0;
@@ -279,7 +279,7 @@ isdn_ppp_open(int min, struct file *file)
int slot;
struct ippp_struct *is;
- if (min < 0 || min > ISDN_MAX_CHANNELS)
+ if (min < 0 || min >= ISDN_MAX_CHANNELS)
return -ENODEV;
slot = isdn_ppp_get_slot();
@@ -1042,7 +1042,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
if (lp->master) { // FIXME?
mlp = (isdn_net_local *) lp->master->priv;
slot = mlp->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
lp->ppp_slot);
goto drop_packet;
@@ -1264,7 +1264,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
/* we have our lp locked from now on */
slot = lp->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
lp->ppp_slot);
kfree_skb(skb);
@@ -1603,7 +1603,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
mp = net_dev->pb;
stats = &mp->stats;
slot = lp->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
__FUNCTION__, lp->ppp_slot);
stats->frame_drops++;
@@ -1640,7 +1640,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
is->last_link_seqno = minseq = newseq;
for (lpq = net_dev->queue;;) {
slot = lpq->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
__FUNCTION__, lpq->ppp_slot);
} else {
@@ -2648,7 +2648,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
lp->ppp_slot);
- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
__FUNCTION__, lp->ppp_slot);
return;
@@ -2658,7 +2658,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
if(lp->master) {
int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
__FUNCTION__, slot);
return;
@@ -2845,7 +2845,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
if (lp->master) {
slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
__FUNCTION__, slot);
return;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 2c4f20b7f021..3f5b64794542 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -14,13 +14,7 @@ config LEDS_CLASS
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
-config LEDS_TRIGGERS
- bool "LED Trigger support"
- depends NEW_LEDS
- help
- This option enables trigger support for the leds class.
- These triggers allow kernel events to drive the LEDs and can
- be configured via sysfs. If unsure, say Y.
+comment "LED drivers"
config LEDS_CORGI
tristate "LED Support for the Sharp SL-C7x0 series"
@@ -59,6 +53,23 @@ config LEDS_TOSA
This option enables support for the LEDs on Sharp Zaurus
SL-6000 series.
+config LEDS_S3C24XX
+ tristate "LED Support for Samsung S3C24XX GPIO LEDs"
+ depends on LEDS_CLASS && ARCH_S3C2410
+ help
+ This option enables support for LEDs connected to GPIO lines
+ on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440.
+
+comment "LED Triggers"
+
+config LEDS_TRIGGERS
+ bool "LED Trigger support"
+ depends NEW_LEDS
+ help
+ This option enables trigger support for the leds class.
+ These triggers allow kernel events to drive the LEDs and can
+ be configured via sysfs. If unsure, say Y.
+
config LEDS_TRIGGER_TIMER
tristate "LED Timer Trigger"
depends LEDS_TRIGGERS
@@ -67,7 +78,7 @@ config LEDS_TRIGGER_TIMER
via sysfs. If unsure, say Y.
config LEDS_TRIGGER_IDE_DISK
- bool "LED Timer Trigger"
+ bool "LED IDE Disk Trigger"
depends LEDS_TRIGGERS && BLK_DEV_IDEDISK
help
This allows LEDs to be controlled by IDE disk activity.
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 40699d3cabbf..40f042633bf5 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o
obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o
obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o
+obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
new file mode 100644
index 000000000000..650cf72dc675
--- /dev/null
+++ b/drivers/leds/leds-s3c24xx.c
@@ -0,0 +1,163 @@
+/* drivers/leds/leds-s3c24xx.c
+ *
+ * (c) 2006 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX - LEDs GPIO driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/leds-gpio.h>
+
+/* our context */
+
+struct s3c24xx_gpio_led {
+ struct led_classdev cdev;
+ struct s3c24xx_led_platdata *pdata;
+};
+
+static inline struct s3c24xx_gpio_led *pdev_to_gpio(struct platform_device *dev)
+{
+ return platform_get_drvdata(dev);
+}
+
+static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev)
+{
+ return container_of(led_cdev, struct s3c24xx_gpio_led, cdev);
+}
+
+static void s3c24xx_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct s3c24xx_gpio_led *led = to_gpio(led_cdev);
+ struct s3c24xx_led_platdata *pd = led->pdata;
+
+ /* there will be a sort delay between setting the output and
+ * going from output to input when using tristate. */
+
+ s3c2410_gpio_setpin(pd->gpio, (value ? 1 : 0) ^
+ (pd->flags & S3C24XX_LEDF_ACTLOW));
+
+ if (pd->flags & S3C24XX_LEDF_TRISTATE)
+ s3c2410_gpio_cfgpin(pd->gpio,
+ value ? S3C2410_GPIO_OUTPUT : S3C2410_GPIO_INPUT);
+
+}
+
+static int s3c24xx_led_remove(struct platform_device *dev)
+{
+ struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
+
+ led_classdev_unregister(&led->cdev);
+ kfree(led);
+
+ return 0;
+}
+
+static int s3c24xx_led_probe(struct platform_device *dev)
+{
+ struct s3c24xx_led_platdata *pdata = dev->dev.platform_data;
+ struct s3c24xx_gpio_led *led;
+ int ret;
+
+ led = kzalloc(sizeof(struct s3c24xx_gpio_led), GFP_KERNEL);
+ if (led == NULL) {
+ dev_err(&dev->dev, "No memory for device\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(dev, led);
+
+ led->cdev.brightness_set = s3c24xx_led_set;
+ led->cdev.default_trigger = pdata->def_trigger;
+ led->cdev.name = pdata->name;
+
+ led->pdata = pdata;
+
+ /* no point in having a pull-up if we are always driving */
+
+ if (pdata->flags & S3C24XX_LEDF_TRISTATE) {
+ s3c2410_gpio_setpin(pdata->gpio, 0);
+ s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_INPUT);
+ } else {
+ s3c2410_gpio_pullup(pdata->gpio, 0);
+ s3c2410_gpio_setpin(pdata->gpio, 0);
+ s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_OUTPUT);
+ }
+
+ /* register our new led device */
+
+ ret = led_classdev_register(&dev->dev, &led->cdev);
+ if (ret < 0) {
+ dev_err(&dev->dev, "led_classdev_register failed\n");
+ goto exit_err1;
+ }
+
+ return 0;
+
+ exit_err1:
+ kfree(led);
+ return ret;
+}
+
+
+#ifdef CONFIG_PM
+static int s3c24xx_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
+
+ led_classdev_suspend(&led->cdev);
+ return 0;
+}
+
+static int s3c24xx_led_resume(struct platform_device *dev)
+{
+ struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
+
+ led_classdev_resume(&led->cdev);
+ return 0;
+}
+#else
+#define s3c24xx_led_suspend NULL
+#define s3c24xx_led_resume NULL
+#endif
+
+static struct platform_driver s3c24xx_led_driver = {
+ .probe = s3c24xx_led_probe,
+ .remove = s3c24xx_led_remove,
+ .suspend = s3c24xx_led_suspend,
+ .resume = s3c24xx_led_resume,
+ .driver = {
+ .name = "s3c24xx_led",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c24xx_led_init(void)
+{
+ return platform_driver_register(&s3c24xx_led_driver);
+}
+
+static void __exit s3c24xx_led_exit(void)
+{
+ platform_driver_unregister(&s3c24xx_led_driver);
+}
+
+module_init(s3c24xx_led_init);
+module_exit(s3c24xx_led_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C24XX LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index fd2aae150ccc..ac25a48362ac 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -139,11 +139,12 @@ config MD_RAID5_RESHAPE
is online. However it is still EXPERIMENTAL code. It should
work, but please be sure that you have backups.
- You will need a version of mdadm newer than 2.3.1. During the
- early stage of reshape there is a critical section where live data
- is being over-written. A crash during this time needs extra care
- for recovery. The newer mdadm takes a copy of the data in the
- critical section and will restore it, if necessary, after a crash.
+ You will need mdadm verion 2.4.1 or later to use this
+ feature safely. During the early stage of reshape there is
+ a critical section where live data is being over-written. A
+ crash during this time needs extra care for recovery. The
+ newer mdadm takes a copy of the data in the critical section
+ and will restore it, if necessary, after a crash.
The mdadm usage is e.g.
mdadm --grow /dev/md1 --raid-disks=6
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 4092a5e37ffc..b3ea2d63db9b 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -84,4 +84,4 @@ obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
-EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
index 94350f21cdc0..db641a36b197 100644
--- a/drivers/media/video/bt8xx/Makefile
+++ b/drivers/media/video/bt8xx/Makefile
@@ -9,4 +9,4 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
obj-$(CONFIG_VIDEO_BT848) += bttv.o
EXTRA_CFLAGS += -I$(src)/..
-EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
index 32a896c23d1e..6e8665be8954 100644
--- a/drivers/media/video/cx25840/Makefile
+++ b/drivers/media/video/cx25840/Makefile
@@ -3,4 +3,4 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
-EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 6482b9aa6a1f..0dcd09b9b727 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -8,9 +8,9 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
-EXTRA_CFLAGS += -I$(src)/..
-EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
extra-cflags-$(CONFIG_DVB_CX22702) += -DHAVE_CX22702=1
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index da457a05b0dd..826d0e340753 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -3,4 +3,4 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
-EXTRA_CFLAGS += -I$(src)/..
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index 1ba998424bbd..be7b9ee697d6 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -11,9 +11,9 @@ obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
-EXTRA_CFLAGS += -I$(src)/..
-EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
-EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index c98571c9d5a6..13de05532e0a 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -32,6 +32,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
#include "saa7134-reg.h"
#include "saa7134.h"
@@ -870,7 +871,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,pci_resource_start(pci_dev,0));
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev,0xffffffff)) {
+ if (!pci_dma_supported(pci_dev, DMA_32BIT_MASK)) {
printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
err = -EIO;
goto fail1;
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 7cc162e8978b..003b077c2324 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -91,4 +91,22 @@ config MMC_AU1X
If unsure, say N.
+config MMC_AT91RM9200
+ tristate "AT91RM9200 SD/MMC Card Interface support"
+ depends on ARCH_AT91RM9200 && MMC
+ help
+ This selects the AT91RM9200 MCI controller.
+
+ If unsure, say N.
+
+config MMC_IMX
+ tristate "Motorola i.MX Multimedia Card Interface support"
+ depends on ARCH_IMX && MMC
+ help
+ This selects the Motorola i.MX Multimedia card Interface.
+ If you have a i.MX platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index c7c34aadfc92..d2957e35cc6f 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -17,10 +17,12 @@ obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
#
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
+obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
+obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
new file mode 100644
index 000000000000..6061c2d101a0
--- /dev/null
+++ b/drivers/mmc/at91_mci.c
@@ -0,0 +1,988 @@
+/*
+ * linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver
+ *
+ * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
+ *
+ * Copyright (C) 2006 Malcolm Noyes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ This is the AT91RM9200 MCI driver that has been tested with both MMC cards
+ and SD-cards. Boards that support write protect are now supported.
+ The CCAT91SBC001 board does not support SD cards.
+
+ The three entry points are at91_mci_request, at91_mci_set_ios
+ and at91_mci_get_ro.
+
+ SET IOS
+ This configures the device to put it into the correct mode and clock speed
+ required.
+
+ MCI REQUEST
+ MCI request processes the commands sent in the mmc_request structure. This
+ can consist of a processing command and a stop command in the case of
+ multiple block transfers.
+
+ There are three main types of request, commands, reads and writes.
+
+ Commands are straight forward. The command is submitted to the controller and
+ the request function returns. When the controller generates an interrupt to indicate
+ the command is finished, the response to the command are read and the mmc_request_done
+ function called to end the request.
+
+ Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
+ controller to manage the transfers.
+
+ A read is done from the controller directly to the scatterlist passed in from the request.
+ Due to a bug in the controller, when a read is completed, all the words are byte
+ swapped in the scatterlist buffers.
+
+ The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
+
+ A write is slightly different in that the bytes to write are read from the scatterlist
+ into a dma memory buffer (this is in case the source buffer should be read only). The
+ entire write buffer is then done from this single dma memory buffer.
+
+ The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
+
+ GET RO
+ Gets the status of the write protect pin, if available.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/mmc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91rm9200_mci.h>
+#include <asm/arch/at91rm9200_pdc.h>
+
+#define DRIVER_NAME "at91_mci"
+
+#undef SUPPORT_4WIRE
+
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(fmt...) \
+ printk(fmt)
+#else
+#define DBG(fmt...) do { } while (0)
+#endif
+
+static struct clk *mci_clk;
+
+#define FL_SENT_COMMAND (1 << 0)
+#define FL_SENT_STOP (1 << 1)
+
+
+
+/*
+ * Read from a MCI register.
+ */
+static inline unsigned long at91_mci_read(unsigned int reg)
+{
+ void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
+
+ return __raw_readl(mci_base + reg);
+}
+
+/*
+ * Write to a MCI register.
+ */
+static inline void at91_mci_write(unsigned int reg, unsigned long value)
+{
+ void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
+
+ __raw_writel(value, mci_base + reg);
+}
+
+/*
+ * Low level type for this driver
+ */
+struct at91mci_host
+{
+ struct mmc_host *mmc;
+ struct mmc_command *cmd;
+ struct mmc_request *request;
+
+ struct at91_mmc_data *board;
+ int present;
+
+ /*
+ * Flag indicating when the command has been sent. This is used to
+ * work out whether or not to send the stop
+ */
+ unsigned int flags;
+ /* flag for current bus settings */
+ u32 bus_mode;
+
+ /* DMA buffer used for transmitting */
+ unsigned int* buffer;
+ dma_addr_t physical_address;
+ unsigned int total_length;
+
+ /* Latest in the scatterlist that has been enabled for transfer, but not freed */
+ int in_use_index;
+
+ /* Latest in the scatterlist that has been enabled for transfer */
+ int transfer_index;
+};
+
+/*
+ * Copy from sg to a dma block - used for transfers
+ */
+static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
+{
+ unsigned int len, i, size;
+ unsigned *dmabuf = host->buffer;
+
+ size = host->total_length;
+ len = data->sg_len;
+
+ /*
+ * Just loop through all entries. Size might not
+ * be the entire list though so make sure that
+ * we do not transfer too much.
+ */
+ for (i = 0; i < len; i++) {
+ struct scatterlist *sg;
+ int amount;
+ int index;
+ unsigned int *sgbuffer;
+
+ sg = &data->sg[i];
+
+ sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ amount = min(size, sg->length);
+ size -= amount;
+ amount /= 4;
+
+ for (index = 0; index < amount; index++)
+ *dmabuf++ = swab32(sgbuffer[index]);
+
+ kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+
+ if (size == 0)
+ break;
+ }
+
+ /*
+ * Check that we didn't get a request to transfer
+ * more data than can fit into the SG list.
+ */
+ BUG_ON(size != 0);
+}
+
+/*
+ * Prepare a dma read
+ */
+static void at91mci_pre_dma_read(struct at91mci_host *host)
+{
+ int i;
+ struct scatterlist *sg;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ DBG("pre dma read\n");
+
+ cmd = host->cmd;
+ if (!cmd) {
+ DBG("no command\n");
+ return;
+ }
+
+ data = cmd->data;
+ if (!data) {
+ DBG("no data\n");
+ return;
+ }
+
+ for (i = 0; i < 2; i++) {
+ /* nothing left to transfer */
+ if (host->transfer_index >= data->sg_len) {
+ DBG("Nothing left to transfer (index = %d)\n", host->transfer_index);
+ break;
+ }
+
+ /* Check to see if this needs filling */
+ if (i == 0) {
+ if (at91_mci_read(AT91_PDC_RCR) != 0) {
+ DBG("Transfer active in current\n");
+ continue;
+ }
+ }
+ else {
+ if (at91_mci_read(AT91_PDC_RNCR) != 0) {
+ DBG("Transfer active in next\n");
+ continue;
+ }
+ }
+
+ /* Setup the next transfer */
+ DBG("Using transfer index %d\n", host->transfer_index);
+
+ sg = &data->sg[host->transfer_index++];
+ DBG("sg = %p\n", sg);
+
+ sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
+
+ DBG("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
+
+ if (i == 0) {
+ at91_mci_write(AT91_PDC_RPR, sg->dma_address);
+ at91_mci_write(AT91_PDC_RCR, sg->length / 4);
+ }
+ else {
+ at91_mci_write(AT91_PDC_RNPR, sg->dma_address);
+ at91_mci_write(AT91_PDC_RNCR, sg->length / 4);
+ }
+ }
+
+ DBG("pre dma read done\n");
+}
+
+/*
+ * Handle after a dma read
+ */
+static void at91mci_post_dma_read(struct at91mci_host *host)
+{
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ DBG("post dma read\n");
+
+ cmd = host->cmd;
+ if (!cmd) {
+ DBG("no command\n");
+ return;
+ }
+
+ data = cmd->data;
+ if (!data) {
+ DBG("no data\n");
+ return;
+ }
+
+ while (host->in_use_index < host->transfer_index) {
+ unsigned int *buffer;
+ int index;
+ int len;
+
+ struct scatterlist *sg;
+
+ DBG("finishing index %d\n", host->in_use_index);
+
+ sg = &data->sg[host->in_use_index++];
+
+ DBG("Unmapping page %08X\n", sg->dma_address);
+
+ dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
+
+ /* Swap the contents of the buffer */
+ buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ DBG("buffer = %p, length = %d\n", buffer, sg->length);
+
+ data->bytes_xfered += sg->length;
+
+ len = sg->length / 4;
+
+ for (index = 0; index < len; index++) {
+ buffer[index] = swab32(buffer[index]);
+ }
+ kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+ flush_dcache_page(sg->page);
+ }
+
+ /* Is there another transfer to trigger? */
+ if (host->transfer_index < data->sg_len)
+ at91mci_pre_dma_read(host);
+ else {
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF);
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ }
+
+ DBG("post dma read done\n");
+}
+
+/*
+ * Handle transmitted data
+ */
+static void at91_mci_handle_transmitted(struct at91mci_host *host)
+{
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ DBG("Handling the transmit\n");
+
+ /* Disable the transfer */
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+
+ /* Now wait for cmd ready */
+ at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE);
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY);
+
+ cmd = host->cmd;
+ if (!cmd) return;
+
+ data = cmd->data;
+ if (!data) return;
+
+ data->bytes_xfered = host->total_length;
+}
+
+/*
+ * Enable the controller
+ */
+static void at91_mci_enable(void)
+{
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
+ at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF);
+ at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
+ at91_mci_write(AT91_MCI_MR, 0x834A);
+ at91_mci_write(AT91_MCI_SDCR, 0x0);
+}
+
+/*
+ * Disable the controller
+ */
+static void at91_mci_disable(void)
+{
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+}
+
+/*
+ * Send a command
+ * return the interrupts to enable
+ */
+static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+ unsigned int cmdr, mr;
+ unsigned int block_length;
+ struct mmc_data *data = cmd->data;
+
+ unsigned int blocks;
+ unsigned int ier = 0;
+
+ host->cmd = cmd;
+
+ /* Not sure if this is needed */
+#if 0
+ if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
+ DBG("Clearing timeout\n");
+ at91_mci_write(AT91_MCI_ARGR, 0);
+ at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD);
+ while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
+ /* spin */
+ DBG("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
+ }
+ }
+#endif
+ cmdr = cmd->opcode;
+
+ if (mmc_resp_type(cmd) == MMC_RSP_NONE)
+ cmdr |= AT91_MCI_RSPTYP_NONE;
+ else {
+ /* if a response is expected then allow maximum response latancy */
+ cmdr |= AT91_MCI_MAXLAT;
+ /* set 136 bit response for R2, 48 bit response otherwise */
+ if (mmc_resp_type(cmd) == MMC_RSP_R2)
+ cmdr |= AT91_MCI_RSPTYP_136;
+ else
+ cmdr |= AT91_MCI_RSPTYP_48;
+ }
+
+ if (data) {
+ block_length = 1 << data->blksz_bits;
+ blocks = data->blocks;
+
+ /* always set data start - also set direction flag for read */
+ if (data->flags & MMC_DATA_READ)
+ cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
+ else if (data->flags & MMC_DATA_WRITE)
+ cmdr |= AT91_MCI_TRCMD_START;
+
+ if (data->flags & MMC_DATA_STREAM)
+ cmdr |= AT91_MCI_TRTYP_STREAM;
+ if (data->flags & MMC_DATA_MULTI)
+ cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+ }
+ else {
+ block_length = 0;
+ blocks = 0;
+ }
+
+ if (cmd->opcode == MMC_STOP_TRANSMISSION)
+ cmdr |= AT91_MCI_TRCMD_STOP;
+
+ if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ cmdr |= AT91_MCI_OPDCMD;
+
+ /*
+ * Set the arguments and send the command
+ */
+ DBG("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
+ cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR));
+
+ if (!data) {
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
+ at91_mci_write(AT91_PDC_RPR, 0);
+ at91_mci_write(AT91_PDC_RCR, 0);
+ at91_mci_write(AT91_PDC_RNPR, 0);
+ at91_mci_write(AT91_PDC_RNCR, 0);
+ at91_mci_write(AT91_PDC_TPR, 0);
+ at91_mci_write(AT91_PDC_TCR, 0);
+ at91_mci_write(AT91_PDC_TNPR, 0);
+ at91_mci_write(AT91_PDC_TNCR, 0);
+
+ at91_mci_write(AT91_MCI_ARGR, cmd->arg);
+ at91_mci_write(AT91_MCI_CMDR, cmdr);
+ return AT91_MCI_CMDRDY;
+ }
+
+ mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
+ at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
+
+ /*
+ * Disable the PDC controller
+ */
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+
+ if (cmdr & AT91_MCI_TRCMD_START) {
+ data->bytes_xfered = 0;
+ host->transfer_index = 0;
+ host->in_use_index = 0;
+ if (cmdr & AT91_MCI_TRDIR) {
+ /*
+ * Handle a read
+ */
+ host->buffer = NULL;
+ host->total_length = 0;
+
+ at91mci_pre_dma_read(host);
+ ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
+ }
+ else {
+ /*
+ * Handle a write
+ */
+ host->total_length = block_length * blocks;
+ host->buffer = dma_alloc_coherent(NULL,
+ host->total_length,
+ &host->physical_address, GFP_KERNEL);
+
+ at91mci_sg_to_dma(host, data);
+
+ DBG("Transmitting %d bytes\n", host->total_length);
+
+ at91_mci_write(AT91_PDC_TPR, host->physical_address);
+ at91_mci_write(AT91_PDC_TCR, host->total_length / 4);
+ ier = AT91_MCI_TXBUFE;
+ }
+ }
+
+ /*
+ * Send the command and then enable the PDC - not the other way round as
+ * the data sheet says
+ */
+
+ at91_mci_write(AT91_MCI_ARGR, cmd->arg);
+ at91_mci_write(AT91_MCI_CMDR, cmdr);
+
+ if (cmdr & AT91_MCI_TRCMD_START) {
+ if (cmdr & AT91_MCI_TRDIR)
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN);
+ else
+ at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN);
+ }
+ return ier;
+}
+
+/*
+ * Wait for a command to complete
+ */
+static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+ unsigned int ier;
+
+ ier = at91_mci_send_command(host, cmd);
+
+ DBG("setting ier to %08X\n", ier);
+
+ /* Stop on errors or the required value */
+ at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier);
+}
+
+/*
+ * Process the next step in the request
+ */
+static void at91mci_process_next(struct at91mci_host *host)
+{
+ if (!(host->flags & FL_SENT_COMMAND)) {
+ host->flags |= FL_SENT_COMMAND;
+ at91mci_process_command(host, host->request->cmd);
+ }
+ else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
+ host->flags |= FL_SENT_STOP;
+ at91mci_process_command(host, host->request->stop);
+ }
+ else
+ mmc_request_done(host->mmc, host->request);
+}
+
+/*
+ * Handle a command that has been completed
+ */
+static void at91mci_completed_command(struct at91mci_host *host)
+{
+ struct mmc_command *cmd = host->cmd;
+ unsigned int status;
+
+ at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+
+ cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0));
+ cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1));
+ cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2));
+ cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3));
+
+ if (host->buffer) {
+ dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
+ host->buffer = NULL;
+ }
+
+ status = at91_mci_read(AT91_MCI_SR);
+
+ DBG("Status = %08X [%08X %08X %08X %08X]\n",
+ status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+ if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
+ AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
+ AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
+ if ((status & AT91_MCI_RCRCE) &&
+ ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
+ cmd->error = MMC_ERR_NONE;
+ }
+ else {
+ if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
+ cmd->error = MMC_ERR_TIMEOUT;
+ else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
+ cmd->error = MMC_ERR_BADCRC;
+ else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
+ cmd->error = MMC_ERR_FIFO;
+ else
+ cmd->error = MMC_ERR_FAILED;
+
+ DBG("Error detected and set to %d (cmd = %d, retries = %d)\n",
+ cmd->error, cmd->opcode, cmd->retries);
+ }
+ }
+ else
+ cmd->error = MMC_ERR_NONE;
+
+ at91mci_process_next(host);
+}
+
+/*
+ * Handle an MMC request
+ */
+static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct at91mci_host *host = mmc_priv(mmc);
+ host->request = mrq;
+ host->flags = 0;
+
+ at91mci_process_next(host);
+}
+
+/*
+ * Set the IOS
+ */
+static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ int clkdiv;
+ struct at91mci_host *host = mmc_priv(mmc);
+ unsigned long at91_master_clock = clk_get_rate(mci_clk);
+
+ DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n",
+ ios->clock, ios->bus_mode, ios->power_mode, ios->vdd);
+
+ if (host)
+ host->bus_mode = ios->bus_mode;
+ else
+ printk("MMC: No host for bus_mode\n");
+
+ if (ios->clock == 0) {
+ /* Disable the MCI controller */
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS);
+ clkdiv = 0;
+ }
+ else {
+ /* Enable the MCI controller */
+ at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
+
+ if ((at91_master_clock % (ios->clock * 2)) == 0)
+ clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
+ else
+ clkdiv = (at91_master_clock / ios->clock) / 2;
+
+ DBG("clkdiv = %d. mcck = %ld\n", clkdiv,
+ at91_master_clock / (2 * (clkdiv + 1)));
+ }
+ if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
+ DBG("MMC: Setting controller bus width to 4\n");
+ at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
+ }
+ else {
+ DBG("MMC: Setting controller bus width to 1\n");
+ at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+ }
+
+ /* Set the clock divider */
+ at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
+
+ /* maybe switch power to the card */
+ if (host && host->board->vcc_pin) {
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ at91_set_gpio_output(host->board->vcc_pin, 0);
+ break;
+ case MMC_POWER_UP:
+ case MMC_POWER_ON:
+ at91_set_gpio_output(host->board->vcc_pin, 1);
+ break;
+ }
+ }
+}
+
+/*
+ * Handle an interrupt
+ */
+static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
+{
+ struct at91mci_host *host = devid;
+ int completed = 0;
+
+ unsigned int int_status;
+
+ if (host == NULL)
+ return IRQ_HANDLED;
+
+ int_status = at91_mci_read(AT91_MCI_SR);
+ DBG("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
+ int_status & at91_mci_read(AT91_MCI_IMR));
+
+ if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000)
+ completed = 1;
+
+ int_status &= at91_mci_read(AT91_MCI_IMR);
+
+ if (int_status & AT91_MCI_UNRE)
+ DBG("MMC: Underrun error\n");
+ if (int_status & AT91_MCI_OVRE)
+ DBG("MMC: Overrun error\n");
+ if (int_status & AT91_MCI_DTOE)
+ DBG("MMC: Data timeout\n");
+ if (int_status & AT91_MCI_DCRCE)
+ DBG("MMC: CRC error in data\n");
+ if (int_status & AT91_MCI_RTOE)
+ DBG("MMC: Response timeout\n");
+ if (int_status & AT91_MCI_RENDE)
+ DBG("MMC: Response end bit error\n");
+ if (int_status & AT91_MCI_RCRCE)
+ DBG("MMC: Response CRC error\n");
+ if (int_status & AT91_MCI_RDIRE)
+ DBG("MMC: Response direction error\n");
+ if (int_status & AT91_MCI_RINDE)
+ DBG("MMC: Response index error\n");
+
+ /* Only continue processing if no errors */
+ if (!completed) {
+ if (int_status & AT91_MCI_TXBUFE) {
+ DBG("TX buffer empty\n");
+ at91_mci_handle_transmitted(host);
+ }
+
+ if (int_status & AT91_MCI_RXBUFF) {
+ DBG("RX buffer full\n");
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+ }
+
+ if (int_status & AT91_MCI_ENDTX) {
+ DBG("Transmit has ended\n");
+ }
+
+ if (int_status & AT91_MCI_ENDRX) {
+ DBG("Receive has ended\n");
+ at91mci_post_dma_read(host);
+ }
+
+ if (int_status & AT91_MCI_NOTBUSY) {
+ DBG("Card is ready\n");
+ at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
+ }
+
+ if (int_status & AT91_MCI_DTIP) {
+ DBG("Data transfer in progress\n");
+ }
+
+ if (int_status & AT91_MCI_BLKE) {
+ DBG("Block transfer has ended\n");
+ }
+
+ if (int_status & AT91_MCI_TXRDY) {
+ DBG("Ready to transmit\n");
+ }
+
+ if (int_status & AT91_MCI_RXRDY) {
+ DBG("Ready to receive\n");
+ }
+
+ if (int_status & AT91_MCI_CMDRDY) {
+ DBG("Command ready\n");
+ completed = 1;
+ }
+ }
+ at91_mci_write(AT91_MCI_IDR, int_status);
+
+ if (completed) {
+ DBG("Completed command\n");
+ at91_mci_write(AT91_MCI_IDR, 0xffffffff);
+ at91mci_completed_command(host);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs)
+{
+ struct at91mci_host *host = _host;
+ int present = !at91_get_gpio_value(irq);
+
+ /*
+ * we expect this irq on both insert and remove,
+ * and use a short delay to debounce.
+ */
+ if (present != host->present) {
+ host->present = present;
+ DBG("%s: card %s\n", mmc_hostname(host->mmc),
+ present ? "insert" : "remove");
+ if (!present) {
+ DBG("****** Resetting SD-card bus width ******\n");
+ at91_mci_write(AT91_MCI_SDCR, 0);
+ }
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+ }
+ return IRQ_HANDLED;
+}
+
+int at91_mci_get_ro(struct mmc_host *mmc)
+{
+ int read_only = 0;
+ struct at91mci_host *host = mmc_priv(mmc);
+
+ if (host->board->wp_pin) {
+ read_only = at91_get_gpio_value(host->board->wp_pin);
+ printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
+ (read_only ? "read-only" : "read-write") );
+ }
+ else {
+ printk(KERN_WARNING "%s: host does not support reading read-only "
+ "switch. Assuming write-enable.\n", mmc_hostname(mmc));
+ }
+ return read_only;
+}
+
+static struct mmc_host_ops at91_mci_ops = {
+ .request = at91_mci_request,
+ .set_ios = at91_mci_set_ios,
+ .get_ro = at91_mci_get_ro,
+};
+
+/*
+ * Probe for the device
+ */
+static int at91_mci_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct at91mci_host *host;
+ int ret;
+
+ DBG("Probe MCI devices\n");
+ at91_mci_disable();
+ at91_mci_enable();
+
+ mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
+ if (!mmc) {
+ DBG("Failed to allocate mmc host\n");
+ return -ENOMEM;
+ }
+
+ mmc->ops = &at91_mci_ops;
+ mmc->f_min = 375000;
+ mmc->f_max = 25000000;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->buffer = NULL;
+ host->bus_mode = 0;
+ host->board = pdev->dev.platform_data;
+ if (host->board->wire4) {
+#ifdef SUPPORT_4WIRE
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+#else
+ printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
+#endif
+ }
+
+ /*
+ * Get Clock
+ */
+ mci_clk = clk_get(&pdev->dev, "mci_clk");
+ if (!mci_clk) {
+ printk(KERN_ERR "AT91 MMC: no clock defined.\n");
+ return -ENODEV;
+ }
+ clk_enable(mci_clk); /* Enable the peripheral clock */
+
+ /*
+ * Allocate the MCI interrupt
+ */
+ ret = request_irq(AT91_ID_MCI, at91_mci_irq, SA_SHIRQ, DRIVER_NAME, host);
+ if (ret) {
+ DBG("Failed to request MCI interrupt\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, mmc);
+
+ /*
+ * Add host to MMC layer
+ */
+ if (host->board->det_pin)
+ host->present = !at91_get_gpio_value(host->board->det_pin);
+ else
+ host->present = -1;
+
+ mmc_add_host(mmc);
+
+ /*
+ * monitor card insertion/removal if we can
+ */
+ if (host->board->det_pin) {
+ ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
+ SA_SAMPLE_RANDOM, DRIVER_NAME, host);
+ if (ret)
+ DBG("couldn't allocate MMC detect irq\n");
+ }
+
+ DBG(KERN_INFO "Added MCI driver\n");
+
+ return 0;
+}
+
+/*
+ * Remove a device
+ */
+static int at91_mci_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct at91mci_host *host;
+
+ if (!mmc)
+ return -1;
+
+ host = mmc_priv(mmc);
+
+ if (host->present != -1) {
+ free_irq(host->board->det_pin, host);
+ cancel_delayed_work(&host->mmc->detect);
+ }
+
+ mmc_remove_host(mmc);
+ at91_mci_disable();
+ free_irq(AT91_ID_MCI, host);
+ mmc_free_host(mmc);
+
+ clk_disable(mci_clk); /* Disable the peripheral clock */
+ clk_put(mci_clk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ DBG("Removed\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc, state);
+
+ return ret;
+}
+
+static int at91_mci_resume(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_resume_host(mmc);
+
+ return ret;
+}
+#else
+#define at91_mci_suspend NULL
+#define at91_mci_resume NULL
+#endif
+
+static struct platform_driver at91_mci_driver = {
+ .probe = at91_mci_probe,
+ .remove = at91_mci_remove,
+ .suspend = at91_mci_suspend,
+ .resume = at91_mci_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_mci_init(void)
+{
+ return platform_driver_register(&at91_mci_driver);
+}
+
+static void __exit at91_mci_exit(void)
+{
+ platform_driver_unregister(&at91_mci_driver);
+}
+
+module_init(at91_mci_init);
+module_exit(at91_mci_exit);
+
+MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
+MODULE_AUTHOR("Nick Randell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
new file mode 100644
index 000000000000..ffb7f55d3467
--- /dev/null
+++ b/drivers/mmc/imxmmc.c
@@ -0,0 +1,1096 @@
+/*
+ * linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
+ *
+ * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
+ * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ * derived from pxamci.c by Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Changed to conform redesigned i.MX scatter gather DMA interface
+ *
+ * 2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Updated for 2.6.14 kernel
+ *
+ * 2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
+ * Found and corrected problems in the write path
+ *
+ * 2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * The event handling rewritten right way in softirq.
+ * Added many ugly hacks and delays to overcome SDHC
+ * deficiencies
+ *
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/protocol.h>
+#include <linux/delay.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/imx-dma.h>
+
+#include "imxmmc.h"
+
+#define DRIVER_NAME "imx-mmc"
+
+#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
+ INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
+ INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
+
+struct imxmci_host {
+ struct mmc_host *mmc;
+ spinlock_t lock;
+ struct resource *res;
+ int irq;
+ imx_dmach_t dma;
+ unsigned int clkrt;
+ unsigned int cmdat;
+ volatile unsigned int imask;
+ unsigned int power_mode;
+ unsigned int present;
+ struct imxmmc_platform_data *pdata;
+
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+
+ struct timer_list timer;
+ struct tasklet_struct tasklet;
+ unsigned int status_reg;
+ unsigned long pending_events;
+ /* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
+ u16 *data_ptr;
+ unsigned int data_cnt;
+ atomic_t stuck_timeout;
+
+ unsigned int dma_nents;
+ unsigned int dma_size;
+ unsigned int dma_dir;
+ int dma_allocated;
+
+ unsigned char actual_bus_width;
+};
+
+#define IMXMCI_PEND_IRQ_b 0
+#define IMXMCI_PEND_DMA_END_b 1
+#define IMXMCI_PEND_DMA_ERR_b 2
+#define IMXMCI_PEND_WAIT_RESP_b 3
+#define IMXMCI_PEND_DMA_DATA_b 4
+#define IMXMCI_PEND_CPU_DATA_b 5
+#define IMXMCI_PEND_CARD_XCHG_b 6
+#define IMXMCI_PEND_SET_INIT_b 7
+
+#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b)
+#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b)
+#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b)
+#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b)
+#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b)
+#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
+#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b)
+#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
+
+static void imxmci_stop_clock(struct imxmci_host *host)
+{
+ int i = 0;
+ MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
+ while(i < 0x1000) {
+ if(!(i & 0x7f))
+ MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
+
+ if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
+ /* Check twice before cut */
+ if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
+ return;
+ }
+
+ i++;
+ }
+ dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
+}
+
+static void imxmci_start_clock(struct imxmci_host *host)
+{
+ int i = 0;
+ MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
+ while(i < 0x1000) {
+ if(!(i & 0x7f))
+ MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+
+ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) {
+ /* Check twice before cut */
+ if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+ return;
+ }
+
+ i++;
+ }
+ dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
+}
+
+static void imxmci_softreset(void)
+{
+ /* reset sequence */
+ MMC_STR_STP_CLK = 0x8;
+ MMC_STR_STP_CLK = 0xD;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+ MMC_STR_STP_CLK = 0x5;
+
+ MMC_RES_TO = 0xff;
+ MMC_BLK_LEN = 512;
+ MMC_NOB = 1;
+}
+
+static int imxmci_busy_wait_for_status(struct imxmci_host *host,
+ unsigned int *pstat, unsigned int stat_mask,
+ int timeout, const char *where)
+{
+ int loops=0;
+ while(!(*pstat & stat_mask)) {
+ loops+=2;
+ if(loops >= timeout) {
+ dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
+ where, *pstat, stat_mask);
+ return -1;
+ }
+ udelay(2);
+ *pstat |= MMC_STATUS;
+ }
+ if(!loops)
+ return 0;
+
+ dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
+ loops, where, *pstat, stat_mask);
+ return loops;
+}
+
+static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
+{
+ unsigned int nob = data->blocks;
+ unsigned int blksz = 1 << data->blksz_bits;
+ unsigned int datasz = nob * blksz;
+ int i;
+
+ if (data->flags & MMC_DATA_STREAM)
+ nob = 0xffff;
+
+ host->data = data;
+ data->bytes_xfered = 0;
+
+ MMC_NOB = nob;
+ MMC_BLK_LEN = blksz;
+
+ /*
+ * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
+ * We are in big troubles for non-512 byte transfers according to note in the paragraph
+ * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
+ * The situation is even more complex in reality. The SDHC in not able to handle wll
+ * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
+ * This is required for SCR read at least.
+ */
+ if (datasz < 64) {
+ host->dma_size = datasz;
+ if (data->flags & MMC_DATA_READ) {
+ host->dma_dir = DMA_FROM_DEVICE;
+
+ /* Hack to enable read SCR */
+ if(datasz < 16) {
+ MMC_NOB = 1;
+ MMC_BLK_LEN = 16;
+ }
+ } else {
+ host->dma_dir = DMA_TO_DEVICE;
+ }
+
+ /* Convert back to virtual address */
+ host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
+ host->data_cnt = 0;
+
+ clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+ set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+ return;
+ }
+
+ if (data->flags & MMC_DATA_READ) {
+ host->dma_dir = DMA_FROM_DEVICE;
+ host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma_dir);
+
+ imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+ host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
+
+ /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
+ CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
+ } else {
+ host->dma_dir = DMA_TO_DEVICE;
+
+ host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, host->dma_dir);
+
+ imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+ host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
+
+ /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
+ CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
+ }
+
+#if 1 /* This code is there only for consistency checking and can be disabled in future */
+ host->dma_size = 0;
+ for(i=0; i<host->dma_nents; i++)
+ host->dma_size+=data->sg[i].length;
+
+ if (datasz > host->dma_size) {
+ dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
+ datasz, host->dma_size);
+ }
+#endif
+
+ host->dma_size = datasz;
+
+ wmb();
+
+ if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+ BLR(host->dma) = 0; /* burst 64 byte read / 64 bytes write */
+ else
+ BLR(host->dma) = 16; /* burst 16 byte read / 16 bytes write */
+
+ RSSR(host->dma) = DMA_REQ_SDHC;
+
+ set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+ clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+ /* start DMA engine for read, write is delayed after initial response */
+ if (host->dma_dir == DMA_FROM_DEVICE) {
+ imx_dma_enable(host->dma);
+ }
+}
+
+static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+ unsigned long flags;
+ u32 imask;
+
+ WARN_ON(host->cmd != NULL);
+ host->cmd = cmd;
+
+ if (cmd->flags & MMC_RSP_BUSY)
+ cmdat |= CMD_DAT_CONT_BUSY;
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_R1: /* short CRC, OPCODE */
+ case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
+ break;
+ case MMC_RSP_R2: /* long 136 bit + CRC */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
+ break;
+ case MMC_RSP_R3: /* short */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
+ break;
+ case MMC_RSP_R6: /* short CRC */
+ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R6;
+ break;
+ default:
+ break;
+ }
+
+ if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
+ cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
+
+ if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
+ cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
+
+ MMC_CMD = cmd->opcode;
+ MMC_ARGH = cmd->arg >> 16;
+ MMC_ARGL = cmd->arg & 0xffff;
+ MMC_CMD_DAT_CONT = cmdat;
+
+ atomic_set(&host->stuck_timeout, 0);
+ set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
+
+
+ imask = IMXMCI_INT_MASK_DEFAULT;
+ imask &= ~INT_MASK_END_CMD_RES;
+ if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
+ /*imask &= ~INT_MASK_BUF_READY;*/
+ imask &= ~INT_MASK_DATA_TRAN;
+ if ( cmdat & CMD_DAT_CONT_WRITE )
+ imask &= ~INT_MASK_WRITE_OP_DONE;
+ if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+ imask &= ~INT_MASK_BUF_READY;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->imask = imask;
+ MMC_INT_MASK = host->imask;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
+ cmd->opcode, cmd->opcode, imask);
+
+ imxmci_start_clock(host);
+}
+
+static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
+ IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
+
+ host->imask = IMXMCI_INT_MASK_DEFAULT;
+ MMC_INT_MASK = host->imask;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ host->req = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+ mmc_request_done(host->mmc, req);
+}
+
+static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
+{
+ struct mmc_data *data = host->data;
+ int data_error;
+
+ if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
+ imx_dma_disable(host->dma);
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
+ host->dma_dir);
+ }
+
+ if ( stat & STATUS_ERR_MASK ) {
+ dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
+ if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
+ data->error = MMC_ERR_BADCRC;
+ else if(stat & STATUS_TIME_OUT_READ)
+ data->error = MMC_ERR_TIMEOUT;
+ else
+ data->error = MMC_ERR_FAILED;
+ } else {
+ data->bytes_xfered = host->dma_size;
+ }
+
+ data_error = data->error;
+
+ host->data = NULL;
+
+ return data_error;
+}
+
+static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
+{
+ struct mmc_command *cmd = host->cmd;
+ int i;
+ u32 a,b,c;
+ struct mmc_data *data = host->data;
+
+ if (!cmd)
+ return 0;
+
+ host->cmd = NULL;
+
+ if (stat & STATUS_TIME_OUT_RESP) {
+ dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
+ cmd->error = MMC_ERR_TIMEOUT;
+ } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+ dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
+ cmd->error = MMC_ERR_BADCRC;
+ }
+
+ if(cmd->flags & MMC_RSP_PRESENT) {
+ if(cmd->flags & MMC_RSP_136) {
+ for (i = 0; i < 4; i++) {
+ u32 a = MMC_RES_FIFO & 0xffff;
+ u32 b = MMC_RES_FIFO & 0xffff;
+ cmd->resp[i] = a<<16 | b;
+ }
+ } else {
+ a = MMC_RES_FIFO & 0xffff;
+ b = MMC_RES_FIFO & 0xffff;
+ c = MMC_RES_FIFO & 0xffff;
+ cmd->resp[0] = a<<24 | b<<8 | c>>8;
+ }
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
+
+ if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+ if (host->req->data->flags & MMC_DATA_WRITE) {
+
+ /* Wait for FIFO to be empty before starting DMA write */
+
+ stat = MMC_STATUS;
+ if(imxmci_busy_wait_for_status(host, &stat,
+ STATUS_APPL_BUFF_FE,
+ 40, "imxmci_cmd_done DMA WR") < 0) {
+ cmd->error = MMC_ERR_FIFO;
+ imxmci_finish_data(host, stat);
+ if(host->req)
+ imxmci_finish_request(host, host->req);
+ dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
+ stat);
+ return 0;
+ }
+
+ if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+ imx_dma_enable(host->dma);
+ }
+ }
+ } else {
+ struct mmc_request *req;
+ imxmci_stop_clock(host);
+ req = host->req;
+
+ if(data)
+ imxmci_finish_data(host, stat);
+
+ if( req ) {
+ imxmci_finish_request(host, req);
+ } else {
+ dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
+ }
+ }
+
+ return 1;
+}
+
+static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
+{
+ struct mmc_data *data = host->data;
+ int data_error;
+
+ if (!data)
+ return 0;
+
+ data_error = imxmci_finish_data(host, stat);
+
+ if (host->req->stop && (data_error == MMC_ERR_NONE)) {
+ imxmci_stop_clock(host);
+ imxmci_start_cmd(host, host->req->stop, 0);
+ } else {
+ struct mmc_request *req;
+ req = host->req;
+ if( req ) {
+ imxmci_finish_request(host, req);
+ } else {
+ dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
+ }
+ }
+
+ return 1;
+}
+
+static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
+{
+ int i;
+ int burst_len;
+ int flush_len;
+ int trans_done = 0;
+ unsigned int stat = *pstat;
+
+ if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+ burst_len = 16;
+ else
+ burst_len = 64;
+
+ /* This is unfortunately required */
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
+ stat);
+
+ if(host->dma_dir == DMA_FROM_DEVICE) {
+ imxmci_busy_wait_for_status(host, &stat,
+ STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE,
+ 20, "imxmci_cpu_driven_data read");
+
+ while((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) &&
+ (host->data_cnt < host->dma_size)) {
+ if(burst_len >= host->dma_size - host->data_cnt) {
+ flush_len = burst_len;
+ burst_len = host->dma_size - host->data_cnt;
+ flush_len -= burst_len;
+ host->data_cnt = host->dma_size;
+ trans_done = 1;
+ } else {
+ flush_len = 0;
+ host->data_cnt += burst_len;
+ }
+
+ for(i = burst_len; i>=2 ; i-=2) {
+ *(host->data_ptr++) = MMC_BUFFER_ACCESS;
+ udelay(20); /* required for clocks < 8MHz*/
+ }
+
+ if(i == 1)
+ *(u8*)(host->data_ptr) = MMC_BUFFER_ACCESS;
+
+ stat = MMC_STATUS;
+
+ /* Flush extra bytes from FIFO */
+ while(flush_len >= 2){
+ flush_len -= 2;
+ i = MMC_BUFFER_ACCESS;
+ stat = MMC_STATUS;
+ stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read burst %d STATUS = 0x%x\n",
+ burst_len, stat);
+ }
+ } else {
+ imxmci_busy_wait_for_status(host, &stat,
+ STATUS_APPL_BUFF_FE,
+ 20, "imxmci_cpu_driven_data write");
+
+ while((stat & STATUS_APPL_BUFF_FE) &&
+ (host->data_cnt < host->dma_size)) {
+ if(burst_len >= host->dma_size - host->data_cnt) {
+ burst_len = host->dma_size - host->data_cnt;
+ host->data_cnt = host->dma_size;
+ trans_done = 1;
+ } else {
+ host->data_cnt += burst_len;
+ }
+
+ for(i = burst_len; i>0 ; i-=2)
+ MMC_BUFFER_ACCESS = *(host->data_ptr++);
+
+ stat = MMC_STATUS;
+
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
+ burst_len, stat);
+ }
+ }
+
+ *pstat = stat;
+
+ return trans_done;
+}
+
+static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+{
+ struct imxmci_host *host = devid;
+ uint32_t stat = MMC_STATUS;
+
+ atomic_set(&host->stuck_timeout, 0);
+ host->status_reg = stat;
+ set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
+{
+ struct imxmci_host *host = devid;
+ uint32_t stat = MMC_STATUS;
+ int handled = 1;
+
+ MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
+
+ atomic_set(&host->stuck_timeout, 0);
+ host->status_reg = stat;
+ set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+
+ return IRQ_RETVAL(handled);;
+}
+
+static void imxmci_tasklet_fnc(unsigned long data)
+{
+ struct imxmci_host *host = (struct imxmci_host *)data;
+ u32 stat;
+ unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */
+ int timeout = 0;
+
+ if(atomic_read(&host->stuck_timeout) > 4) {
+ char *what;
+ timeout = 1;
+ stat = MMC_STATUS;
+ host->status_reg = stat;
+ if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+ if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+ what = "RESP+DMA";
+ else
+ what = "RESP";
+ else
+ if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+ if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
+ what = "DATA";
+ else
+ what = "DMA";
+ else
+ what = "???";
+
+ dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
+ what, stat, MMC_INT_MASK);
+ dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
+ MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
+ dev_err(mmc_dev(host->mmc), "CMD%d, bus %d-bit, dma_size = 0x%x\n",
+ host->cmd?host->cmd->opcode:0, 1<<host->actual_bus_width, host->dma_size);
+ }
+
+ if(!host->present || timeout)
+ host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
+ STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
+
+ if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
+ clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+
+ stat = MMC_STATUS;
+ /*
+ * This is not required in theory, but there is chance to miss some flag
+ * which clears automatically by mask write, FreeScale original code keeps
+ * stat from IRQ time so do I
+ */
+ stat |= host->status_reg;
+
+ if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+ imxmci_busy_wait_for_status(host, &stat,
+ STATUS_END_CMD_RESP | STATUS_ERR_MASK,
+ 20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
+ }
+
+ if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
+ if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+ imxmci_cmd_done(host, stat);
+ if(host->data && (stat & STATUS_ERR_MASK))
+ imxmci_data_done(host, stat);
+ }
+
+ if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
+ stat |= MMC_STATUS;
+ if(imxmci_cpu_driven_data(host, &stat)){
+ if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+ imxmci_cmd_done(host, stat);
+ atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
+ &host->pending_events);
+ imxmci_data_done(host, stat);
+ }
+ }
+ }
+
+ if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
+ !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+
+ stat = MMC_STATUS;
+ /* Same as above */
+ stat |= host->status_reg;
+
+ if(host->dma_dir == DMA_TO_DEVICE) {
+ data_dir_mask = STATUS_WRITE_OP_DONE;
+ } else {
+ data_dir_mask = STATUS_DATA_TRANS_DONE;
+ }
+
+ imxmci_busy_wait_for_status(host, &stat,
+ data_dir_mask,
+ 50, "imxmci_tasklet_fnc data");
+
+ if(stat & data_dir_mask) {
+ clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+ imxmci_data_done(host, stat);
+ }
+ }
+
+ if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
+
+ if(host->cmd)
+ imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
+
+ if(host->data)
+ imxmci_data_done(host, STATUS_TIME_OUT_READ |
+ STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
+
+ if(host->req)
+ imxmci_finish_request(host, host->req);
+
+ mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+
+ }
+}
+
+static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct imxmci_host *host = mmc_priv(mmc);
+ unsigned int cmdat;
+
+ WARN_ON(host->req != NULL);
+
+ host->req = req;
+
+ cmdat = 0;
+
+ if (req->data) {
+ imxmci_setup_data(host, req->data);
+
+ cmdat |= CMD_DAT_CONT_DATA_ENABLE;
+
+ if (req->data->flags & MMC_DATA_WRITE)
+ cmdat |= CMD_DAT_CONT_WRITE;
+
+ if (req->data->flags & MMC_DATA_STREAM) {
+ cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
+ }
+ }
+
+ imxmci_start_cmd(host, req->cmd, cmdat);
+}
+
+#define CLK_RATE 19200000
+
+static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct imxmci_host *host = mmc_priv(mmc);
+ int prescaler;
+
+ dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n",
+ ios->clock, ios->power_mode, ios->vdd,
+ (ios->bus_width==MMC_BUS_WIDTH_4)?4:1);
+
+ if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
+ host->actual_bus_width = MMC_BUS_WIDTH_4;
+ imx_gpio_mode(PB11_PF_SD_DAT3);
+ }else{
+ host->actual_bus_width = MMC_BUS_WIDTH_1;
+ imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+ }
+
+ if ( host->power_mode != ios->power_mode ) {
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ break;
+ case MMC_POWER_UP:
+ set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+ break;
+ case MMC_POWER_ON:
+ break;
+ }
+ host->power_mode = ios->power_mode;
+ }
+
+ if ( ios->clock ) {
+ unsigned int clk;
+
+ /* The prescaler is 5 for PERCLK2 equal to 96MHz
+ * then 96MHz / 5 = 19.2 MHz
+ */
+ clk=imx_get_perclk2();
+ prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
+ switch(prescaler) {
+ case 0:
+ case 1: prescaler = 0;
+ break;
+ case 2: prescaler = 1;
+ break;
+ case 3: prescaler = 2;
+ break;
+ case 4: prescaler = 4;
+ break;
+ default:
+ case 5: prescaler = 5;
+ break;
+ }
+
+ dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
+ clk, prescaler);
+
+ for(clk=0; clk<8; clk++) {
+ int x;
+ x = CLK_RATE / (1<<clk);
+ if( x <= ios->clock)
+ break;
+ }
+
+ MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
+
+ imxmci_stop_clock(host);
+ MMC_CLK_RATE = (prescaler<<3) | clk;
+ imxmci_start_clock(host);
+
+ dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
+ } else {
+ imxmci_stop_clock(host);
+ }
+}
+
+static struct mmc_host_ops imxmci_ops = {
+ .request = imxmci_request,
+ .set_ios = imxmci_set_ios,
+};
+
+static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
+{
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++)
+ if (dev->resource[i].flags == mask && nr-- == 0)
+ return &dev->resource[i];
+ return NULL;
+}
+
+static int platform_device_irq(struct platform_device *dev, int nr)
+{
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++)
+ if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
+ return dev->resource[i].start;
+ return NO_IRQ;
+}
+
+static void imxmci_check_status(unsigned long data)
+{
+ struct imxmci_host *host = (struct imxmci_host *)data;
+
+ if( host->pdata->card_present() != host->present ) {
+ host->present ^= 1;
+ dev_info(mmc_dev(host->mmc), "card %s\n",
+ host->present ? "inserted" : "removed");
+
+ set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
+ test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+ atomic_inc(&host->stuck_timeout);
+ if(atomic_read(&host->stuck_timeout) > 4)
+ tasklet_schedule(&host->tasklet);
+ } else {
+ atomic_set(&host->stuck_timeout, 0);
+
+ }
+
+ mod_timer(&host->timer, jiffies + (HZ>>1));
+}
+
+static int imxmci_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct imxmci_host *host = NULL;
+ struct resource *r;
+ int ret = 0, irq;
+
+ printk(KERN_INFO "i.MX mmc driver\n");
+
+ r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_device_irq(pdev, 0);
+ if (!r || irq == NO_IRQ)
+ return -ENXIO;
+
+ r = request_mem_region(r->start, 0x100, "IMXMCI");
+ if (!r)
+ return -EBUSY;
+
+ mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mmc->ops = &imxmci_ops;
+ mmc->f_min = 150000;
+ mmc->f_max = CLK_RATE/2;
+ mmc->ocr_avail = MMC_VDD_32_33;
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ /* MMC core transfer sizes tunable parameters */
+ mmc->max_hw_segs = 64;
+ mmc->max_phys_segs = 64;
+ mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
+ mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->dma_allocated = 0;
+ host->pdata = pdev->dev.platform_data;
+
+ spin_lock_init(&host->lock);
+ host->res = r;
+ host->irq = irq;
+
+ imx_gpio_mode(PB8_PF_SD_DAT0);
+ imx_gpio_mode(PB9_PF_SD_DAT1);
+ imx_gpio_mode(PB10_PF_SD_DAT2);
+ /* Configured as GPIO with pull-up to ensure right MCC card mode */
+ /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
+ imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+ /* imx_gpio_mode(PB11_PF_SD_DAT3); */
+ imx_gpio_mode(PB12_PF_SD_CLK);
+ imx_gpio_mode(PB13_PF_SD_CMD);
+
+ imxmci_softreset();
+
+ if ( MMC_REV_NO != 0x390 ) {
+ dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
+ MMC_REV_NO);
+ goto out;
+ }
+
+ MMC_READ_TO = 0x2db4; /* recommended in data sheet */
+
+ host->imask = IMXMCI_INT_MASK_DEFAULT;
+ MMC_INT_MASK = host->imask;
+
+
+ if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){
+ dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
+ ret = -EBUSY;
+ goto out;
+ }
+ host->dma_allocated=1;
+ imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
+
+ tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
+ host->status_reg=0;
+ host->pending_events=0;
+
+ ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
+ if (ret)
+ goto out;
+
+ host->present = host->pdata->card_present();
+ init_timer(&host->timer);
+ host->timer.data = (unsigned long)host;
+ host->timer.function = imxmci_check_status;
+ add_timer(&host->timer);
+ mod_timer(&host->timer, jiffies + (HZ>>1));
+
+ platform_set_drvdata(pdev, mmc);
+
+ mmc_add_host(mmc);
+
+ return 0;
+
+out:
+ if (host) {
+ if(host->dma_allocated){
+ imx_dma_free(host->dma);
+ host->dma_allocated=0;
+ }
+ }
+ if (mmc)
+ mmc_free_host(mmc);
+ release_resource(r);
+ return ret;
+}
+
+static int imxmci_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (mmc) {
+ struct imxmci_host *host = mmc_priv(mmc);
+
+ tasklet_disable(&host->tasklet);
+
+ del_timer_sync(&host->timer);
+ mmc_remove_host(mmc);
+
+ free_irq(host->irq, host);
+ if(host->dma_allocated){
+ imx_dma_free(host->dma);
+ host->dma_allocated=0;
+ }
+
+ tasklet_kill(&host->tasklet);
+
+ release_resource(host->res);
+
+ mmc_free_host(mmc);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ int ret = 0;
+
+ if (mmc)
+ ret = mmc_suspend_host(mmc, state);
+
+ return ret;
+}
+
+static int imxmci_resume(struct platform_device *dev)
+{
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+ struct imxmci_host *host;
+ int ret = 0;
+
+ if (mmc) {
+ host = mmc_priv(mmc);
+ if(host)
+ set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+ ret = mmc_resume_host(mmc);
+ }
+
+ return ret;
+}
+#else
+#define imxmci_suspend NULL
+#define imxmci_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver imxmci_driver = {
+ .probe = imxmci_probe,
+ .remove = imxmci_remove,
+ .suspend = imxmci_suspend,
+ .resume = imxmci_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ }
+};
+
+static int __init imxmci_init(void)
+{
+ return platform_driver_register(&imxmci_driver);
+}
+
+static void __exit imxmci_exit(void)
+{
+ platform_driver_unregister(&imxmci_driver);
+}
+
+module_init(imxmci_init);
+module_exit(imxmci_exit);
+
+MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/imxmmc.h
new file mode 100644
index 000000000000..e5339e334dbb
--- /dev/null
+++ b/drivers/mmc/imxmmc.h
@@ -0,0 +1,67 @@
+
+# define __REG16(x) (*((volatile u16 *)IO_ADDRESS(x)))
+
+#define MMC_STR_STP_CLK __REG16(IMX_MMC_BASE + 0x00)
+#define MMC_STATUS __REG16(IMX_MMC_BASE + 0x04)
+#define MMC_CLK_RATE __REG16(IMX_MMC_BASE + 0x08)
+#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
+#define MMC_RES_TO __REG16(IMX_MMC_BASE + 0x10)
+#define MMC_READ_TO __REG16(IMX_MMC_BASE + 0x14)
+#define MMC_BLK_LEN __REG16(IMX_MMC_BASE + 0x18)
+#define MMC_NOB __REG16(IMX_MMC_BASE + 0x1C)
+#define MMC_REV_NO __REG16(IMX_MMC_BASE + 0x20)
+#define MMC_INT_MASK __REG16(IMX_MMC_BASE + 0x24)
+#define MMC_CMD __REG16(IMX_MMC_BASE + 0x28)
+#define MMC_ARGH __REG16(IMX_MMC_BASE + 0x2C)
+#define MMC_ARGL __REG16(IMX_MMC_BASE + 0x30)
+#define MMC_RES_FIFO __REG16(IMX_MMC_BASE + 0x34)
+#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
+#define MMC_BUFFER_ACCESS_OFS 0x38
+
+
+#define STR_STP_CLK_ENDIAN (1<<5)
+#define STR_STP_CLK_RESET (1<<3)
+#define STR_STP_CLK_ENABLE (1<<2)
+#define STR_STP_CLK_START_CLK (1<<1)
+#define STR_STP_CLK_STOP_CLK (1<<0)
+#define STATUS_CARD_PRESENCE (1<<15)
+#define STATUS_SDIO_INT_ACTIVE (1<<14)
+#define STATUS_END_CMD_RESP (1<<13)
+#define STATUS_WRITE_OP_DONE (1<<12)
+#define STATUS_DATA_TRANS_DONE (1<<11)
+#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10)
+#define STATUS_CARD_BUS_CLK_RUN (1<<8)
+#define STATUS_APPL_BUFF_FF (1<<7)
+#define STATUS_APPL_BUFF_FE (1<<6)
+#define STATUS_RESP_CRC_ERR (1<<5)
+#define STATUS_CRC_READ_ERR (1<<3)
+#define STATUS_CRC_WRITE_ERR (1<<2)
+#define STATUS_TIME_OUT_RESP (1<<1)
+#define STATUS_TIME_OUT_READ (1<<0)
+#define STATUS_ERR_MASK 0x2f
+#define CLK_RATE_PRESCALER(x) ((x) & 0x7)
+#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3)
+#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12)
+#define CMD_DAT_CONT_STOP_READWAIT (1<<11)
+#define CMD_DAT_CONT_START_READWAIT (1<<10)
+#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8)
+#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8)
+#define CMD_DAT_CONT_INIT (1<<7)
+#define CMD_DAT_CONT_BUSY (1<<6)
+#define CMD_DAT_CONT_STREAM_BLOCK (1<<5)
+#define CMD_DAT_CONT_WRITE (1<<4)
+#define CMD_DAT_CONT_DATA_ENABLE (1<<3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
+#define INT_MASK_AUTO_CARD_DETECT (1<<6)
+#define INT_MASK_DAT0_EN (1<<5)
+#define INT_MASK_SDIO (1<<4)
+#define INT_MASK_BUF_READY (1<<3)
+#define INT_MASK_END_CMD_RES (1<<2)
+#define INT_MASK_WRITE_OP_DONE (1<<1)
+#define INT_MASK_DATA_TRAN (1<<0)
+#define INT_ALL (0x7f)
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index dd628cb51e31..7fac438b5c32 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -129,8 +129,8 @@ config MTDRAM_ABS_POS
allocating space from Linux's available memory. Otherwise, leave
this set to zero. Most people will want to leave this as zero.
-config MTD_BLKMTD
- tristate "MTD emulation using block device"
+config MTD_BLOCK2MTD
+ tristate "MTD using block device"
depends on MTD
help
This driver allows a block device to appear as an MTD. It would
@@ -141,15 +141,6 @@ config MTD_BLKMTD
Testing MTD users (eg JFFS2) on large media and media that might
be removed during a write (using the floppy drive).
-config MTD_BLOCK2MTD
- tristate "MTD using block device (rewrite)"
- depends on MTD && EXPERIMENTAL
- help
- This driver is basically the same at MTD_BLKMTD above, but
- experienced some interface changes plus serious speedups. In
- the long term, it should replace MTD_BLKMTD. Right now, you
- shouldn't entrust important data to it yet.
-
comment "Disk-On-Chip Device Drivers"
config MTD_DOC2000
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 7c5ed2178380..b6573670316f 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_MTD_PMC551) += pmc551.o
obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o
obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
obj-$(CONFIG_MTD_LART) += lart.o
-obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
deleted file mode 100644
index 79f2e1f23ebd..000000000000
--- a/drivers/mtd/devices/blkmtd.c
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $
- *
- * blkmtd.c - use a block device as a fake MTD
- *
- * Author: Simon Evans <spse@secret.org.uk>
- *
- * Copyright (C) 2001,2002 Simon Evans
- *
- * Licence: GPL
- *
- * How it works:
- * The driver uses raw/io to read/write the device and the page
- * cache to cache access. Writes update the page cache with the
- * new data and mark it dirty and add the page into a BIO which
- * is then written out.
- *
- * It can be loaded Read-Only to prevent erases and writes to the
- * medium.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/blkdev.h>
-#include <linux/bio.h>
-#include <linux/pagemap.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/mount.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mutex.h>
-
-#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
-#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
-
-
-/* Default erase size in K, always make it a multiple of PAGE_SIZE */
-#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */
-#define VERSION "$Revision: 1.27 $"
-
-/* Info for the block device */
-struct blkmtd_dev {
- struct list_head list;
- struct block_device *blkdev;
- struct mtd_info mtd_info;
- struct mutex wrbuf_mutex;
-};
-
-
-/* Static info about the MTD, used in cleanup_module */
-static LIST_HEAD(blkmtd_device_list);
-
-
-static void blkmtd_sync(struct mtd_info *mtd);
-
-#define MAX_DEVICES 4
-
-/* Module parameters passed by insmod/modprobe */
-static char *device[MAX_DEVICES]; /* the block device to use */
-static int erasesz[MAX_DEVICES]; /* optional default erase size */
-static int ro[MAX_DEVICES]; /* optional read only flag */
-static int sync;
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION("Emulate an MTD using a block device");
-module_param_array(device, charp, NULL, 0);
-MODULE_PARM_DESC(device, "block device to use");
-module_param_array(erasesz, int, NULL, 0);
-MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
-module_param_array(ro, bool, NULL, 0);
-MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
-module_param(sync, bool, 0);
-MODULE_PARM_DESC(sync, "1=Synchronous writes");
-
-
-/* completion handler for BIO reads */
-static int bi_read_complete(struct bio *bio, unsigned int bytes_done, int error)
-{
- if (bio->bi_size)
- return 1;
-
- complete((struct completion*)bio->bi_private);
- return 0;
-}
-
-
-/* completion handler for BIO writes */
-static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error)
-{
- const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
- struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-
- if (bio->bi_size)
- return 1;
-
- if(!uptodate)
- err("bi_write_complete: not uptodate\n");
-
- do {
- struct page *page = bvec->bv_page;
- DEBUG(3, "Cleaning up page %ld\n", page->index);
- if (--bvec >= bio->bi_io_vec)
- prefetchw(&bvec->bv_page->flags);
-
- if (uptodate) {
- SetPageUptodate(page);
- } else {
- ClearPageUptodate(page);
- SetPageError(page);
- }
- clear_page_dirty(page);
- unlock_page(page);
- page_cache_release(page);
- } while (bvec >= bio->bi_io_vec);
-
- complete((struct completion*)bio->bi_private);
- return 0;
-}
-
-
-/* read one page from the block device */
-static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page)
-{
- struct bio *bio;
- struct completion event;
- int err = -ENOMEM;
-
- if(PageUptodate(page)) {
- DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
- unlock_page(page);
- return 0;
- }
-
- ClearPageUptodate(page);
- ClearPageError(page);
-
- bio = bio_alloc(GFP_KERNEL, 1);
- if(bio) {
- init_completion(&event);
- bio->bi_bdev = dev->blkdev;
- bio->bi_sector = page->index << (PAGE_SHIFT-9);
- bio->bi_private = &event;
- bio->bi_end_io = bi_read_complete;
- if(bio_add_page(bio, page, PAGE_SIZE, 0) == PAGE_SIZE) {
- submit_bio(READ_SYNC, bio);
- wait_for_completion(&event);
- err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
- bio_put(bio);
- }
- }
-
- if(err)
- SetPageError(page);
- else
- SetPageUptodate(page);
- flush_dcache_page(page);
- unlock_page(page);
- return err;
-}
-
-
-/* write out the current BIO and wait for it to finish */
-static int blkmtd_write_out(struct bio *bio)
-{
- struct completion event;
- int err;
-
- if(!bio->bi_vcnt) {
- bio_put(bio);
- return 0;
- }
-
- init_completion(&event);
- bio->bi_private = &event;
- bio->bi_end_io = bi_write_complete;
- submit_bio(WRITE_SYNC, bio);
- wait_for_completion(&event);
- DEBUG(3, "submit_bio completed, bi_vcnt = %d\n", bio->bi_vcnt);
- err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO;
- bio_put(bio);
- return err;
-}
-
-
-/**
- * blkmtd_add_page - add a page to the current BIO
- * @bio: bio to add to (NULL to alloc initial bio)
- * @blkdev: block device
- * @page: page to add
- * @pagecnt: pages left to add
- *
- * Adds a page to the current bio, allocating it if necessary. If it cannot be
- * added, the current bio is written out and a new one is allocated. Returns
- * the new bio to add or NULL on error
- */
-static struct bio *blkmtd_add_page(struct bio *bio, struct block_device *blkdev,
- struct page *page, int pagecnt)
-{
-
- retry:
- if(!bio) {
- bio = bio_alloc(GFP_KERNEL, pagecnt);
- if(!bio)
- return NULL;
- bio->bi_sector = page->index << (PAGE_SHIFT-9);
- bio->bi_bdev = blkdev;
- }
-
- if(bio_add_page(bio, page, PAGE_SIZE, 0) != PAGE_SIZE) {
- blkmtd_write_out(bio);
- bio = NULL;
- goto retry;
- }
- return bio;
-}
-
-
-/**
- * write_pages - write block of data to device via the page cache
- * @dev: device to write to
- * @buf: data source or NULL if erase (output is set to 0xff)
- * @to: offset into output device
- * @len: amount to data to write
- * @retlen: amount of data written
- *
- * Grab pages from the page cache and fill them with the source data.
- * Non page aligned start and end result in a readin of the page and
- * part of the page being modified. Pages are added to the bio and then written
- * out.
- */
-static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
- size_t len, size_t *retlen)
-{
- int pagenr, offset;
- size_t start_len = 0, end_len;
- int pagecnt = 0;
- int err = 0;
- struct bio *bio = NULL;
- size_t thislen = 0;
-
- pagenr = to >> PAGE_SHIFT;
- offset = to & ~PAGE_MASK;
-
- DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %zd pagenr = %d offset = %d\n",
- buf, (long)to, len, pagenr, offset);
-
- /* see if we have to do a partial write at the start */
- if(offset) {
- start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
- len -= start_len;
- }
-
- /* calculate the length of the other two regions */
- end_len = len & ~PAGE_MASK;
- len -= end_len;
-
- if(start_len)
- pagecnt++;
-
- if(len)
- pagecnt += len >> PAGE_SHIFT;
-
- if(end_len)
- pagecnt++;
-
- mutex_lock(&dev->wrbuf_mutex);
-
- DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
- start_len, len, end_len, pagecnt);
-
- if(start_len) {
- /* do partial start region */
- struct page *page;
-
- DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %zd offset = %d\n",
- pagenr, start_len, offset);
-
- BUG_ON(!buf);
- page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
- lock_page(page);
- if(PageDirty(page)) {
- err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n",
- to, start_len, len, end_len, pagenr);
- BUG();
- }
- memcpy(page_address(page)+offset, buf, start_len);
- set_page_dirty(page);
- SetPageUptodate(page);
- buf += start_len;
- thislen = start_len;
- bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
- if(!bio) {
- err = -ENOMEM;
- err("bio_add_page failed\n");
- goto write_err;
- }
- pagecnt--;
- pagenr++;
- }
-
- /* Now do the main loop to a page aligned, n page sized output */
- if(len) {
- int pagesc = len >> PAGE_SHIFT;
- DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n",
- pagenr, pagesc);
- while(pagesc) {
- struct page *page;
-
- /* see if page is in the page cache */
- DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
- page = grab_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr);
- if(PageDirty(page)) {
- BUG();
- }
- if(!page) {
- warn("write: cannot grab cache page %d", pagenr);
- err = -ENOMEM;
- goto write_err;
- }
- if(!buf) {
- memset(page_address(page), 0xff, PAGE_SIZE);
- } else {
- memcpy(page_address(page), buf, PAGE_SIZE);
- buf += PAGE_SIZE;
- }
- bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
- if(!bio) {
- err = -ENOMEM;
- err("bio_add_page failed\n");
- goto write_err;
- }
- pagenr++;
- pagecnt--;
- set_page_dirty(page);
- SetPageUptodate(page);
- pagesc--;
- thislen += PAGE_SIZE;
- }
- }
-
- if(end_len) {
- /* do the third region */
- struct page *page;
- DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %zd\n",
- pagenr, end_len);
- BUG_ON(!buf);
- page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
- lock_page(page);
- if(PageDirty(page)) {
- err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n",
- to, start_len, len, end_len, pagenr);
- BUG();
- }
- memcpy(page_address(page), buf, end_len);
- set_page_dirty(page);
- SetPageUptodate(page);
- DEBUG(3, "blkmtd: write: writing out partial end\n");
- thislen += end_len;
- bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt);
- if(!bio) {
- err = -ENOMEM;
- err("bio_add_page failed\n");
- goto write_err;
- }
- pagenr++;
- }
-
- DEBUG(3, "blkmtd: write: got %d vectors to write\n", bio->bi_vcnt);
- write_err:
- if(bio)
- blkmtd_write_out(bio);
-
- DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
- mutex_unlock(&dev->wrbuf_mutex);
-
- if(retlen)
- *retlen = thislen;
- return err;
-}
-
-
-/* erase a specified part of the device */
-static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- struct blkmtd_dev *dev = mtd->priv;
- struct mtd_erase_region_info *einfo = mtd->eraseregions;
- int numregions = mtd->numeraseregions;
- size_t from;
- u_long len;
- int err = -EIO;
- size_t retlen;
-
- instr->state = MTD_ERASING;
- from = instr->addr;
- len = instr->len;
-
- /* check erase region has valid start and length */
- DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n",
- mtd->name+9, from, len);
- while(numregions) {
- DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
- einfo->offset, einfo->erasesize, einfo->numblocks);
- if(from >= einfo->offset
- && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
- if(len == einfo->erasesize
- && ( (from - einfo->offset) % einfo->erasesize == 0))
- break;
- }
- numregions--;
- einfo++;
- }
-
- if(!numregions) {
- /* Not a valid erase block */
- err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
- instr->state = MTD_ERASE_FAILED;
- err = -EIO;
- }
-
- if(instr->state != MTD_ERASE_FAILED) {
- /* do the erase */
- DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
- err = write_pages(dev, NULL, from, len, &retlen);
- if(err || retlen != len) {
- err("erase failed err = %d", err);
- instr->state = MTD_ERASE_FAILED;
- } else {
- instr->state = MTD_ERASE_DONE;
- }
- }
-
- DEBUG(3, "blkmtd: erase: checking callback\n");
- mtd_erase_callback(instr);
- DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
- return err;
-}
-
-
-/* read a range of the data via the page cache */
-static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct blkmtd_dev *dev = mtd->priv;
- int err = 0;
- int offset;
- int pagenr, pages;
- size_t thislen = 0;
-
- DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n",
- mtd->name+9, from, len, buf);
-
- if(from > mtd->size)
- return -EINVAL;
- if(from + len > mtd->size)
- len = mtd->size - from;
-
- pagenr = from >> PAGE_SHIFT;
- offset = from - (pagenr << PAGE_SHIFT);
-
- pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
- DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
- pagenr, offset, pages);
-
- while(pages) {
- struct page *page;
- int cpylen;
-
- DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
- page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
- if(IS_ERR(page)) {
- err = -EIO;
- goto readerr;
- }
-
- cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
- if(offset+cpylen > PAGE_SIZE)
- cpylen = PAGE_SIZE-offset;
-
- memcpy(buf + thislen, page_address(page) + offset, cpylen);
- offset = 0;
- len -= cpylen;
- thislen += cpylen;
- pagenr++;
- pages--;
- if(!PageDirty(page))
- page_cache_release(page);
- }
-
- readerr:
- if(retlen)
- *retlen = thislen;
- DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", thislen, err);
- return err;
-}
-
-
-/* write data to the underlying device */
-static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct blkmtd_dev *dev = mtd->priv;
- int err;
-
- if(!len)
- return 0;
-
- DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",
- mtd->name+9, to, len, buf);
-
- if(to >= mtd->size) {
- return -ENOSPC;
- }
-
- if(to + len > mtd->size) {
- len = mtd->size - to;
- }
-
- err = write_pages(dev, buf, to, len, retlen);
- if(err > 0)
- err = 0;
- DEBUG(2, "blkmtd: write: end, err = %d\n", err);
- return err;
-}
-
-
-/* sync the device - wait until the write queue is empty */
-static void blkmtd_sync(struct mtd_info *mtd)
-{
- /* Currently all writes are synchronous */
-}
-
-
-static void free_device(struct blkmtd_dev *dev)
-{
- DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
- if(dev) {
- kfree(dev->mtd_info.eraseregions);
- kfree(dev->mtd_info.name);
- if(dev->blkdev) {
- invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
- close_bdev_excl(dev->blkdev);
- }
- kfree(dev);
- }
-}
-
-
-/* For a given size and initial erase size, calculate the number
- * and size of each erase region. Goes round the loop twice,
- * once to find out how many regions, then allocates space,
- * then round the loop again to fill it in.
- */
-static struct mtd_erase_region_info *calc_erase_regions(
- size_t erase_size, size_t total_size, int *regions)
-{
- struct mtd_erase_region_info *info = NULL;
-
- DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
- erase_size, total_size, *regions);
- /* Make any user specified erasesize be a power of 2
- and at least PAGE_SIZE */
- if(erase_size) {
- int es = erase_size;
- erase_size = 1;
- while(es != 1) {
- es >>= 1;
- erase_size <<= 1;
- }
- if(erase_size < PAGE_SIZE)
- erase_size = PAGE_SIZE;
- } else {
- erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
- }
-
- *regions = 0;
-
- do {
- int tot_size = total_size;
- int er_size = erase_size;
- int count = 0, offset = 0, regcnt = 0;
-
- while(tot_size) {
- count = tot_size / er_size;
- if(count) {
- tot_size = tot_size % er_size;
- if(info) {
- DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
- offset, er_size, count);
- (info+regcnt)->offset = offset;
- (info+regcnt)->erasesize = er_size;
- (info+regcnt)->numblocks = count;
- (*regions)++;
- }
- regcnt++;
- offset += (count * er_size);
- }
- while(er_size > tot_size)
- er_size >>= 1;
- }
- if(info == NULL) {
- info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
- if(!info)
- break;
- }
- } while(!(*regions));
- DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
- erase_size, total_size, *regions);
- return info;
-}
-
-
-static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
-{
- struct block_device *bdev;
- int mode;
- struct blkmtd_dev *dev;
-
- if(!devname)
- return NULL;
-
- /* Get a handle on the device */
-
-
-#ifdef MODULE
- mode = (readonly) ? O_RDONLY : O_RDWR;
- bdev = open_bdev_excl(devname, mode, NULL);
-#else
- mode = (readonly) ? FMODE_READ : FMODE_WRITE;
- bdev = open_by_devnum(name_to_dev_t(devname), mode);
-#endif
- if(IS_ERR(bdev)) {
- err("error: cannot open device %s", devname);
- DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
- return NULL;
- }
-
- DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
- MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-
- if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
- err("attempting to use an MTD device as a block device");
- blkdev_put(bdev);
- return NULL;
- }
-
- dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
- if(dev == NULL) {
- blkdev_put(bdev);
- return NULL;
- }
-
- memset(dev, 0, sizeof(struct blkmtd_dev));
- dev->blkdev = bdev;
- if(!readonly) {
- mutex_init(&dev->wrbuf_mutex);
- }
-
- dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
-
- /* Setup the MTD structure */
- /* make the name contain the block device in */
- dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
- if(dev->mtd_info.name == NULL)
- goto devinit_err;
-
- sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
- dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
- &dev->mtd_info.numeraseregions);
- if(dev->mtd_info.eraseregions == NULL)
- goto devinit_err;
-
- dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
- DEBUG(1, "blkmtd: init: found %d erase regions\n",
- dev->mtd_info.numeraseregions);
-
- if(readonly) {
- dev->mtd_info.type = MTD_ROM;
- dev->mtd_info.flags = MTD_CAP_ROM;
- } else {
- dev->mtd_info.type = MTD_RAM;
- dev->mtd_info.flags = MTD_CAP_RAM;
- dev->mtd_info.erase = blkmtd_erase;
- dev->mtd_info.write = blkmtd_write;
- dev->mtd_info.writev = default_mtd_writev;
- dev->mtd_info.sync = blkmtd_sync;
- }
- dev->mtd_info.read = blkmtd_read;
- dev->mtd_info.readv = default_mtd_readv;
- dev->mtd_info.priv = dev;
- dev->mtd_info.owner = THIS_MODULE;
-
- list_add(&dev->list, &blkmtd_device_list);
- if (add_mtd_device(&dev->mtd_info)) {
- /* Device didnt get added, so free the entry */
- list_del(&dev->list);
- goto devinit_err;
- } else {
- info("mtd%d: [%s] erase_size = %dKiB %s",
- dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
- dev->mtd_info.erasesize >> 10,
- readonly ? "(read-only)" : "");
- }
-
- return dev;
-
- devinit_err:
- free_device(dev);
- return NULL;
-}
-
-
-/* Cleanup and exit - sync the device and kill of the kernel thread */
-static void __devexit cleanup_blkmtd(void)
-{
- struct list_head *temp1, *temp2;
-
- /* Remove the MTD devices */
- list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
- struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
- list);
- blkmtd_sync(&dev->mtd_info);
- del_mtd_device(&dev->mtd_info);
- info("mtd%d: [%s] removed", dev->mtd_info.index,
- dev->mtd_info.name + strlen("blkmtd: "));
- list_del(&dev->list);
- free_device(dev);
- }
-}
-
-#ifndef MODULE
-
-/* Handle kernel boot params */
-
-
-static int __init param_blkmtd_device(char *str)
-{
- int i;
-
- for(i = 0; i < MAX_DEVICES; i++) {
- device[i] = str;
- DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
- strsep(&str, ",");
- }
- return 1;
-}
-
-
-static int __init param_blkmtd_erasesz(char *str)
-{
- int i;
- for(i = 0; i < MAX_DEVICES; i++) {
- char *val = strsep(&str, ",");
- if(val)
- erasesz[i] = simple_strtoul(val, NULL, 0);
- DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
- }
-
- return 1;
-}
-
-
-static int __init param_blkmtd_ro(char *str)
-{
- int i;
- for(i = 0; i < MAX_DEVICES; i++) {
- char *val = strsep(&str, ",");
- if(val)
- ro[i] = simple_strtoul(val, NULL, 0);
- DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
- }
-
- return 1;
-}
-
-
-static int __init param_blkmtd_sync(char *str)
-{
- if(str[0] == '1')
- sync = 1;
- return 1;
-}
-
-__setup("blkmtd_device=", param_blkmtd_device);
-__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
-__setup("blkmtd_ro=", param_blkmtd_ro);
-__setup("blkmtd_sync=", param_blkmtd_sync);
-
-#endif
-
-
-/* Startup */
-static int __init init_blkmtd(void)
-{
- int i;
-
- info("version " VERSION);
- /* Check args - device[0] is the bare minimum*/
- if(!device[0]) {
- err("error: missing `device' name\n");
- return -EINVAL;
- }
-
- for(i = 0; i < MAX_DEVICES; i++)
- add_device(device[i], ro[i], erasesz[i] << 10);
-
- if(list_empty(&blkmtd_device_list))
- return -EINVAL;
-
- return 0;
-}
-
-module_init(init_blkmtd);
-module_exit(cleanup_blkmtd);
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index c4e12b5cbb92..3d306681919e 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -2,6 +2,7 @@
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
* Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2006 Broadcom Corporation.
*
* Distribute under GPL.
*/
@@ -28,8 +29,8 @@
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.97"
-#define DRV_MODULE_RELDATE "Nov 30, 2005"
+#define DRV_MODULE_VERSION "1.00"
+#define DRV_MODULE_RELDATE "Apr 7, 2006"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -136,7 +137,7 @@ static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
return readl(bp->regs + reg);
}
-static inline void bw32(const struct b44 *bp,
+static inline void bw32(const struct b44 *bp,
unsigned long reg, unsigned long val)
{
writel(val, bp->regs + reg);
@@ -286,13 +287,13 @@ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
val |= ((u32) data[4]) << 8;
val |= ((u32) data[5]) << 0;
bw32(bp, B44_CAM_DATA_LO, val);
- val = (CAM_DATA_HI_VALID |
+ val = (CAM_DATA_HI_VALID |
(((u32) data[0]) << 8) |
(((u32) data[1]) << 0));
bw32(bp, B44_CAM_DATA_HI, val);
bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE |
(index << CAM_CTRL_INDEX_SHIFT)));
- b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
}
static inline void __b44_disable_ints(struct b44 *bp)
@@ -410,25 +411,18 @@ static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags)
static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
{
- u32 pause_enab = bp->flags & (B44_FLAG_TX_PAUSE |
- B44_FLAG_RX_PAUSE);
+ u32 pause_enab = 0;
- if (local & ADVERTISE_PAUSE_CAP) {
- if (local & ADVERTISE_PAUSE_ASYM) {
- if (remote & LPA_PAUSE_CAP)
- pause_enab |= (B44_FLAG_TX_PAUSE |
- B44_FLAG_RX_PAUSE);
- else if (remote & LPA_PAUSE_ASYM)
- pause_enab |= B44_FLAG_RX_PAUSE;
- } else {
- if (remote & LPA_PAUSE_CAP)
- pause_enab |= (B44_FLAG_TX_PAUSE |
- B44_FLAG_RX_PAUSE);
- }
- } else if (local & ADVERTISE_PAUSE_ASYM) {
- if ((remote & LPA_PAUSE_CAP) &&
- (remote & LPA_PAUSE_ASYM))
- pause_enab |= B44_FLAG_TX_PAUSE;
+ /* The driver supports only rx pause by default because
+ the b44 mac tx pause mechanism generates excessive
+ pause frames.
+ Use ethtool to turn on b44 tx pause if necessary.
+ */
+ if ((local & ADVERTISE_PAUSE_CAP) &&
+ (local & ADVERTISE_PAUSE_ASYM)){
+ if ((remote & LPA_PAUSE_ASYM) &&
+ !(remote & LPA_PAUSE_CAP))
+ pause_enab |= B44_FLAG_RX_PAUSE;
}
__b44_set_flow_ctrl(bp, pause_enab);
@@ -1063,7 +1057,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu)
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
-
+
return 0;
}
@@ -1381,7 +1375,7 @@ static void b44_init_hw(struct b44 *bp)
bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
bw32(bp, B44_DMARX_PTR, bp->rx_pending);
- bp->rx_prod = bp->rx_pending;
+ bp->rx_prod = bp->rx_pending;
bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
@@ -1553,9 +1547,9 @@ static void __b44_set_rx_mode(struct net_device *dev)
val |= RXCONFIG_ALLMULTI;
else
i = __b44_load_mcast(bp, dev);
-
+
for (; i < 64; i++) {
- __b44_cam_write(bp, zero, i);
+ __b44_cam_write(bp, zero, i);
}
bw32(bp, B44_RXCONFIG, val);
val = br32(bp, B44_CAM_CTRL);
@@ -1737,7 +1731,7 @@ static int b44_set_ringparam(struct net_device *dev,
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
-
+
return 0;
}
@@ -1782,7 +1776,7 @@ static int b44_set_pauseparam(struct net_device *dev,
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
-
+
return 0;
}
@@ -1898,7 +1892,7 @@ static int __devinit b44_get_invariants(struct b44 *bp)
bp->core_unit = ssb_core_unit(bp);
bp->dma_offset = SB_PCI_DMA;
- /* XXX - really required?
+ /* XXX - really required?
bp->flags |= B44_FLAG_BUGGY_TXPTR;
*/
out:
@@ -1946,7 +1940,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
"aborting.\n");
goto err_out_free_res;
}
-
+
err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
printk(KERN_ERR PFX "No usable DMA configuration, "
@@ -2041,9 +2035,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
pci_save_state(bp->pdev);
- /* Chip reset provides power to the b44 MAC & PCI cores, which
+ /* Chip reset provides power to the b44 MAC & PCI cores, which
* is necessary for MAC register access.
- */
+ */
b44_chip_reset(bp);
printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
@@ -2091,10 +2085,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
del_timer_sync(&bp->timer);
- spin_lock_irq(&bp->lock);
+ spin_lock_irq(&bp->lock);
b44_halt(bp);
- netif_carrier_off(bp->dev);
+ netif_carrier_off(bp->dev);
netif_device_detach(bp->dev);
b44_free_rings(bp);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 2671da20a496..5ca99e26660a 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -63,7 +63,7 @@
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (5*HZ)
-static char version[] __devinitdata =
+static const char version[] __devinitdata =
"Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 91e927827c43..54c78d94f48b 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_CHELSIO_T1) += cxgb.o
-EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/chelsio $(DEBUG_FLAGS)
+EXTRA_CFLAGS += -Idrivers/net/chelsio $(DEBUG_FLAGS)
cxgb-objs := cxgb2.o espi.o pm3393.o sge.o subr.o mv88x201x.o
diff --git a/drivers/net/hydra.h b/drivers/net/hydra.h
deleted file mode 100644
index 37414146258d..000000000000
--- a/drivers/net/hydra.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/* $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $ */
-
-/*
- * Copyright (c) 1994 Timo Rossi
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Timo Rossi
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * The Hydra Systems card uses the National Semiconductor
- * 8390 NIC (Network Interface Controller) chip, located
- * at card base address + 0xffe1. NIC registers are accessible
- * only at odd byte addresses, so the register offsets must
- * be multiplied by two.
- *
- * Card address PROM is located at card base + 0xffc0 (even byte addresses)
- *
- * RAM starts at the card base address, and is 16K or 64K.
- * The current Amiga NetBSD hydra driver is hardwired for 16K.
- * It seems that the RAM should be accessed as words or longwords only.
- *
- */
-
-/* adapted for Linux by Topi Kanerva 03/29/95
- with original author's permission */
-
-#define HYDRA_NIC_BASE 0xffe1
-
-/* Page0 registers */
-
-#define NIC_CR 0 /* Command register */
-#define NIC_PSTART (1*2) /* Page start (write) */
-#define NIC_PSTOP (2*2) /* Page stop (write) */
-#define NIC_BNDRY (3*2) /* Boundary pointer */
-#define NIC_TSR (4*2) /* Transmit status (read) */
-#define NIC_TPSR (4*2) /* Transmit page start (write) */
-#define NIC_NCR (5*2) /* Number of collisions, read */
-#define NIC_TBCR0 (5*2) /* Transmit byte count low (write) */
-#define NIC_FIFO (6*2) /* FIFO reg. (read) */
-#define NIC_TBCR1 (6*2) /* Transmit byte count high (write) */
-#define NIC_ISR (7*2) /* Interrupt status register */
-#define NIC_RBCR0 (0xa*2) /* Remote byte count low (write) */
-#define NIC_RBCR1 (0xb*2) /* Remote byte count high (write) */
-#define NIC_RSR (0xc*2) /* Receive status (read) */
-#define NIC_RCR (0xc*2) /* Receive config (write) */
-#define NIC_CNTR0 (0xd*2) /* Frame alignment error count (read) */
-#define NIC_TCR (0xd*2) /* Transmit config (write) */
-#define NIC_CNTR1 (0xe*2) /* CRC error counter (read) */
-#define NIC_DCR (0xe*2) /* Data config (write) */
-#define NIC_CNTR2 (0xf*2) /* missed packet counter (read) */
-#define NIC_IMR (0xf*2) /* Interrupt mask reg. (write) */
-
-/* Page1 registers */
-
-#define NIC_PAR0 (1*2) /* Physical address */
-#define NIC_PAR1 (2*2)
-#define NIC_PAR2 (3*2)
-#define NIC_PAR3 (4*2)
-#define NIC_PAR4 (5*2)
-#define NIC_PAR5 (6*2)
-#define NIC_CURR (7*2) /* Current RX ring-buffer page */
-#define NIC_MAR0 (8*2) /* Multicast address */
-#define NIC_MAR1 (9*2)
-#define NIC_MAR2 (0xa*2)
-#define NIC_MAR3 (0xb*2)
-#define NIC_MAR4 (0xc*2)
-#define NIC_MAR5 (0xd*2)
-#define NIC_MAR6 (0xe*2)
-#define NIC_MAR7 (0xf*2)
-
-/* Command register definitions */
-
-#define CR_STOP 0x01 /* Stop -- software reset command */
-#define CR_START 0x02 /* Start */
-#define CR_TXP 0x04 /* Transmit packet */
-
-#define CR_RD0 0x08 /* Remote DMA cmd */
-#define CR_RD1 0x10
-#define CR_RD2 0x20
-
-#define CR_NODMA CR_RD2
-
-#define CR_PS0 0x40 /* Page select */
-#define CR_PS1 0x80
-
-#define CR_PAGE0 0
-#define CR_PAGE1 CR_PS0
-#define CR_PAGE2 CR_PS1
-
-/* Interrupt status reg. definitions */
-
-#define ISR_PRX 0x01 /* Packet received without errors */
-#define ISR_PTX 0x02 /* Packet transmitted without errors */
-#define ISR_RXE 0x04 /* Receive error */
-#define ISR_TXE 0x08 /* Transmit error */
-#define ISR_OVW 0x10 /* Ring buffer overrun */
-#define ISR_CNT 0x20 /* Counter overflow */
-#define ISR_RDC 0x40 /* Remote DMA compile */
-#define ISR_RST 0x80 /* Reset status */
-
-/* Data config reg. definitions */
-
-#define DCR_WTS 0x01 /* Word transfer select */
-#define DCR_BOS 0x02 /* Byte order select */
-#define DCR_LAS 0x04 /* Long address select */
-#define DCR_LS 0x08 /* Loopback select */
-#define DCR_AR 0x10 /* Auto-init remote */
-#define DCR_FT0 0x20 /* FIFO threshold select */
-#define DCR_FT1 0x40
-
-/* Transmit config reg. definitions */
-
-#define TCR_CRC 0x01 /* Inhibit CRC */
-#define TCR_LB0 0x02 /* Loopback control */
-#define TCR_LB1 0x04
-#define TCR_ATD 0x08 /* Auto transmit disable */
-#define TCR_OFST 0x10 /* Collision offset enable */
-
-/* Transmit status reg. definitions */
-
-#define TSR_PTX 0x01 /* Packet transmitted */
-#define TSR_COL 0x04 /* Transmit collided */
-#define TSR_ABT 0x08 /* Transmit aborted */
-#define TSR_CRS 0x10 /* Carrier sense lost */
-#define TSR_FU 0x20 /* FIFO underrun */
-#define TSR_CDH 0x40 /* CD Heartbeat */
-#define TSR_OWC 0x80 /* Out of Window Collision */
-
-/* Receiver config register definitions */
-
-#define RCR_SEP 0x01 /* Save errored packets */
-#define RCR_AR 0x02 /* Accept runt packets */
-#define RCR_AB 0x04 /* Accept broadcast */
-#define RCR_AM 0x08 /* Accept multicast */
-#define RCR_PRO 0x10 /* Promiscuous mode */
-#define RCR_MON 0x20 /* Monitor mode */
-
-/* Receiver status register definitions */
-
-#define RSR_PRX 0x01 /* Packet received without error */
-#define RSR_CRC 0x02 /* CRC error */
-#define RSR_FAE 0x04 /* Frame alignment error */
-#define RSR_FO 0x08 /* FIFO overrun */
-#define RSR_MPA 0x10 /* Missed packet */
-#define RSR_PHY 0x20 /* Physical address */
-#define RSR_DIS 0x40 /* Received disabled */
-#define RSR_DFR 0x80 /* Deferring (jabber) */
-
-/* Hydra System card address PROM offset */
-
-#define HYDRA_ADDRPROM 0xffc0
-
-
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 6e2ec56cde0b..606243d11793 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1,7 +1,7 @@
/*****************************************************************************
*
* Filename: irda-usb.c
- * Version: 0.9b
+ * Version: 0.10
* Description: IrDA-USB Driver
* Status: Experimental
* Author: Dag Brattli <dag@brattli.net>
@@ -9,6 +9,9 @@
* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
* Copyright (C) 2001, Dag Brattli <dag@brattli.net>
* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
+ * Copyright (C) 2005, Milan Beno <beno@pobox.sk>
+ * Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua>
*
* 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
@@ -61,6 +64,7 @@
#include <linux/slab.h>
#include <linux/rtnetlink.h>
#include <linux/usb.h>
+#include <linux/firmware.h>
#include "irda-usb.h"
@@ -78,8 +82,12 @@ static struct usb_device_id dongles[] = {
{ USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
/* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */
{ USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
+ /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */
+ { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
+ { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
+ { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
.bInterfaceClass = USB_CLASS_APP_SPEC,
.bInterfaceSubClass = USB_CLASS_IRDA,
.driver_info = IUC_DEFAULT, },
@@ -99,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, dongles);
/*------------------------------------------------------------------*/
+static void irda_usb_init_qos(struct irda_usb_cb *self) ;
static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf);
static void irda_usb_disconnect(struct usb_interface *intf);
static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
@@ -141,7 +150,24 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
__u8 *header,
int force)
{
- /* Set the negotiated link speed */
+ /* Here we check if we have an STIR421x chip,
+ * and if either speed or xbofs (or both) needs
+ * to be changed.
+ */
+ if (self->capability & IUC_STIR_4210 &&
+ ((self->new_speed != -1) || (self->new_xbofs != -1))) {
+
+ /* With STIR421x, speed and xBOFs must be set at the same
+ * time, even if only one of them changes.
+ */
+ if (self->new_speed == -1)
+ self->new_speed = self->speed ;
+
+ if (self->new_xbofs == -1)
+ self->new_xbofs = self->xbofs ;
+ }
+
+ /* Set the link speed */
if (self->new_speed != -1) {
/* Hum... Ugly hack :-(
* Some device are not compliant with the spec and change
@@ -191,7 +217,11 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
*header = SPEED_4000000;
self->new_xbofs = 0;
break;
- }
+ case 16000000:
+ *header = SPEED_16000000;
+ self->new_xbofs = 0;
+ break;
+ }
} else
/* No change */
*header = 0;
@@ -235,6 +265,32 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
}
}
+/*
+* calculate turnaround time for SigmaTel header
+*/
+static __u8 get_turnaround_time(struct sk_buff *skb)
+{
+ int turnaround_time = irda_get_mtt(skb);
+
+ if ( turnaround_time == 0 )
+ return 0;
+ else if ( turnaround_time <= 10 )
+ return 1;
+ else if ( turnaround_time <= 50 )
+ return 2;
+ else if ( turnaround_time <= 100 )
+ return 3;
+ else if ( turnaround_time <= 500 )
+ return 4;
+ else if ( turnaround_time <= 1000 )
+ return 5;
+ else if ( turnaround_time <= 5000 )
+ return 6;
+ else
+ return 7;
+}
+
+
/*------------------------------------------------------------------*/
/*
* Send a command to change the speed of the dongle
@@ -262,12 +318,18 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
/* Set the new speed and xbofs in this fake frame */
irda_usb_build_header(self, frame, 1);
+ if ( self->capability & IUC_STIR_4210 ) {
+ if (frame[0] == 0) return ; // do nothing if no change
+ frame[1] = 0; // other parameters don't change here
+ frame[2] = 0;
+ }
+
/* Submit the 0 length IrDA frame to trigger new speed settings */
usb_fill_bulk_urb(urb, self->usbdev,
usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
frame, IRDA_USB_SPEED_MTU,
speed_bulk_callback, self);
- urb->transfer_buffer_length = USB_IRDA_HEADER;
+ urb->transfer_buffer_length = self->header_length;
urb->transfer_flags = 0;
/* Irq disabled -> GFP_ATOMIC */
@@ -383,16 +445,35 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
* allocation will be done lower in skb_push().
* Also, we don't use directly skb_cow(), because it require
* headroom >= 16, which force unnecessary copies - Jean II */
- if (skb_headroom(skb) < USB_IRDA_HEADER) {
+ if (skb_headroom(skb) < self->header_length) {
IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
- if (skb_cow(skb, USB_IRDA_HEADER)) {
+ if (skb_cow(skb, self->header_length)) {
IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
goto drop;
}
}
/* Change setting for next frame */
- irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
+
+ if ( self->capability & IUC_STIR_4210 ) {
+ __u8 turnaround_time;
+ __u8* frame;
+ turnaround_time = get_turnaround_time( skb );
+ frame= skb_push(skb, self->header_length);
+ irda_usb_build_header(self, frame, 0);
+ frame[2] = turnaround_time;
+ if ((skb->len != 0) &&
+ ((skb->len % 128) == 0) &&
+ ((skb->len % 512) != 0)) {
+ /* add extra byte for special SigmaTel feature */
+ frame[1] = 1;
+ skb_put(skb, 1);
+ } else {
+ frame[1] = 0;
+ }
+ } else {
+ irda_usb_build_header(self, skb_push(skb, self->header_length), 0);
+ }
/* FIXME: Make macro out of this one */
((struct irda_skb_cb *)skb->cb)->context = self;
@@ -795,7 +876,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
}
/* Check for empty frames */
- if (urb->actual_length <= USB_IRDA_HEADER) {
+ if (urb->actual_length <= self->header_length) {
IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__);
goto done;
}
@@ -816,7 +897,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);
/* Allocate a new skb */
- newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU);
+ if ( self->capability & IUC_STIR_4210 )
+ newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER);
+ else
+ newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU);
+
if (!newskb) {
self->stats.rx_dropped++;
/* We could deliver the current skb, but this would stall
@@ -845,7 +930,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
/* Set proper length on skb & remove USB-IrDA header */
skb_put(dataskb, urb->actual_length);
- skb_pull(dataskb, USB_IRDA_HEADER);
+ skb_pull(dataskb, self->header_length);
/* Ask the networking layer to queue the packet for the IrDA stack */
dataskb->dev = self->netdev;
@@ -937,6 +1022,191 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self)
return 0; /* For now */
}
+
+#define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: "
+#define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: "
+#define STIR421X_PATCH_DATA_TAG_STR "STMP"
+#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */
+#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */
+#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */
+
+/*
+ * Known firmware patches for STIR421x dongles
+ */
+static char * stir421x_patches[] = {
+ "42101001.sb",
+ "42101002.sb",
+};
+
+static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len)
+{
+ unsigned int version_offset;
+ unsigned long version_major, version_minor, version_build;
+ unsigned char * version_start;
+ int version_found = 0;
+
+ for (version_offset = 0;
+ version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG;
+ version_offset++) {
+ if (!memcmp(patch + version_offset,
+ STIR421X_PATCH_PRODUCT_VERSION_STR,
+ sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) {
+ version_found = 1;
+ version_start = patch +
+ version_offset +
+ sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1;
+ break;
+ }
+ }
+
+ /* We couldn't find a product version on this patch */
+ if (!version_found)
+ return -EINVAL;
+
+ /* Let's check if the product version is dotted */
+ if (version_start[3] != '.' ||
+ version_start[7] != '.')
+ return -EINVAL;
+
+ version_major = simple_strtoul(version_start, NULL, 10);
+ version_minor = simple_strtoul(version_start + 4, NULL, 10);
+ version_build = simple_strtoul(version_start + 8, NULL, 10);
+
+ IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n",
+ __FUNCTION__,
+ version_major, version_minor, version_build);
+
+ return (((version_major) << 12) +
+ ((version_minor) << 8) +
+ ((version_build / 10) << 4) +
+ (version_build % 10));
+
+}
+
+
+static int stir421x_upload_patch (struct irda_usb_cb *self,
+ unsigned char * patch,
+ const unsigned int patch_len)
+{
+ int retval = 0;
+ int actual_len;
+ unsigned int i = 0, download_amount = 0;
+ unsigned char * patch_chunk;
+
+ IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__);
+
+ patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL);
+ if (patch_chunk == NULL)
+ return -ENOMEM;
+
+ /* break up patch into 1023-byte sections */
+ for (i = 0; retval >= 0 && i < patch_len; i += download_amount) {
+ download_amount = patch_len - i;
+ if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE)
+ download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE;
+
+ /* download the patch section */
+ memcpy(patch_chunk, patch + i, download_amount);
+
+ retval = usb_bulk_msg (self->usbdev,
+ usb_sndbulkpipe (self->usbdev,
+ self->bulk_out_ep),
+ patch_chunk, download_amount,
+ &actual_len, msecs_to_jiffies (500));
+ IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__,
+ actual_len);
+ if (retval == 0)
+ mdelay(10);
+ }
+
+ kfree(patch_chunk);
+
+ if (i != patch_len) {
+ IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n",
+ __FUNCTION__, i, patch_len);
+ retval = -EIO;
+ }
+
+ if (retval < 0)
+ /* todo - mark device as not ready */
+ IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n",
+ __FUNCTION__, retval);
+
+ return retval;
+}
+
+
+static int stir421x_patch_device(struct irda_usb_cb *self)
+{
+ unsigned int i, patch_found = 0, data_found = 0, data_offset;
+ int patch_version, ret = 0;
+ const struct firmware *fw_entry;
+
+ for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) {
+ if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) {
+ IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]);
+ continue;
+ }
+
+ /* We found a patch from userspace */
+ patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size);
+
+ if (patch_version < 0) {
+ /* Couldn't fetch a version, let's move on to the next file */
+ IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__);
+ ret = patch_version;
+ release_firmware(fw_entry);
+ continue;
+ }
+
+ if (patch_version != self->usbdev->descriptor.bcdDevice) {
+ /* Patch version and device don't match */
+ IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n",
+ __FUNCTION__,
+ patch_version, self->usbdev->descriptor.bcdDevice);
+ ret = -EINVAL;
+ release_firmware(fw_entry);
+ continue;
+ }
+
+ /* If we're here, we've found a correct patch */
+ patch_found = 1;
+ break;
+
+ }
+
+ /* We couldn't find a valid firmware, let's leave */
+ if (!patch_found)
+ return ret;
+
+ /* The actual image starts after the "STMP" keyword */
+ for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) {
+ if (!memcmp(fw_entry->data + data_offset,
+ STIR421X_PATCH_DATA_TAG_STR,
+ sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) {
+ IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n",
+ __FUNCTION__, data_offset);
+ data_found = 1;
+ break;
+ }
+ }
+
+ /* We couldn't find "STMP" from the header */
+ if (!data_found)
+ return -EINVAL;
+
+ /* Let's upload the patch to the target */
+ ret = stir421x_upload_patch(self,
+ &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)],
+ fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)));
+
+ release_firmware(fw_entry);
+
+ return ret;
+
+}
+
+
/********************** IRDA DEVICE CALLBACKS **********************/
/*
* Main calls from the IrDA/Network subsystem.
@@ -972,6 +1242,11 @@ static int irda_usb_net_open(struct net_device *netdev)
return -1;
}
+ if(self->needspatch) {
+ IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ;
+ return -EIO ;
+ }
+
/* Initialise default speed and xbofs value
* (IrLAP will change that soon) */
self->speed = -1;
@@ -1050,7 +1325,7 @@ static int irda_usb_net_close(struct net_device *netdev)
del_timer(&self->rx_defer_timer);
/* Deallocate all the Rx path buffers (URBs and skb) */
- for (i = 0; i < IU_MAX_RX_URBS; i++) {
+ for (i = 0; i < self->max_rx_urb; i++) {
struct urb *urb = self->rx_urb[i];
struct sk_buff *skb = (struct sk_buff *) urb->context;
/* Cancel the receive command */
@@ -1426,8 +1701,22 @@ static int irda_usb_probe(struct usb_interface *intf,
spin_lock_init(&self->lock);
init_timer(&self->rx_defer_timer);
+ self->capability = id->driver_info;
+ self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ;
+
/* Create all of the needed urbs */
- for (i = 0; i < IU_MAX_RX_URBS; i++) {
+ if (self->capability & IUC_STIR_4210) {
+ self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS;
+ self->header_length = USB_IRDA_SIGMATEL_HEADER;
+ } else {
+ self->max_rx_urb = IU_MAX_RX_URBS;
+ self->header_length = USB_IRDA_HEADER;
+ }
+
+ self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *),
+ GFP_KERNEL);
+
+ for (i = 0; i < self->max_rx_urb; i++) {
self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
if (!self->rx_urb[i]) {
goto err_out_1;
@@ -1479,17 +1768,28 @@ static int irda_usb_probe(struct usb_interface *intf,
goto err_out_3;
}
+ self->usbdev = dev;
+
/* Find IrDA class descriptor */
irda_desc = irda_usb_find_class_desc(intf);
ret = -ENODEV;
if (irda_desc == NULL)
goto err_out_3;
+ if (self->needspatch) {
+ ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0),
+ 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500));
+ if (ret < 0) {
+ IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret);
+ goto err_out_3;
+ } else {
+ mdelay(10);
+ }
+ }
+
self->irda_desc = irda_desc;
self->present = 1;
self->netopen = 0;
- self->capability = id->driver_info;
- self->usbdev = dev;
self->usbintf = intf;
/* Allocate the buffer for speed changes */
@@ -1508,6 +1808,28 @@ static int irda_usb_probe(struct usb_interface *intf,
IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);
usb_set_intfdata(intf, self);
+
+ if (self->needspatch) {
+ /* Now we fetch and upload the firmware patch */
+ ret = stir421x_patch_device(self);
+ self->needspatch = (ret < 0);
+ if (ret < 0) {
+ printk("patch_device failed\n");
+ goto err_out_4;
+ }
+
+ /* replace IrDA class descriptor with what patched device is now reporting */
+ irda_desc = irda_usb_find_class_desc (self->usbintf);
+ if (irda_desc == NULL) {
+ ret = -ENODEV;
+ goto err_out_4;
+ }
+ if (self->irda_desc)
+ kfree (self->irda_desc);
+ self->irda_desc = irda_desc;
+ irda_usb_init_qos(self);
+ }
+
return 0;
err_out_4:
@@ -1518,7 +1840,7 @@ err_out_3:
err_out_2:
usb_free_urb(self->tx_urb);
err_out_1:
- for (i = 0; i < IU_MAX_RX_URBS; i++) {
+ for (i = 0; i < self->max_rx_urb; i++) {
if (self->rx_urb[i])
usb_free_urb(self->rx_urb[i]);
}
@@ -1571,7 +1893,7 @@ static void irda_usb_disconnect(struct usb_interface *intf)
/*netif_device_detach(self->netdev);*/
netif_stop_queue(self->netdev);
/* Stop all the receive URBs. Must be synchronous. */
- for (i = 0; i < IU_MAX_RX_URBS; i++)
+ for (i = 0; i < self->max_rx_urb; i++)
usb_kill_urb(self->rx_urb[i]);
/* Cancel Tx and speed URB.
* Make sure it's synchronous to avoid races. */
@@ -1586,8 +1908,9 @@ static void irda_usb_disconnect(struct usb_interface *intf)
self->usbintf = NULL;
/* Clean up our urbs */
- for (i = 0; i < IU_MAX_RX_URBS; i++)
+ for (i = 0; i < self->max_rx_urb; i++)
usb_free_urb(self->rx_urb[i]);
+ kfree(self->rx_urb);
/* Clean up Tx and speed URB */
usb_free_urb(self->tx_urb);
usb_free_urb(self->speed_urb);
@@ -1648,6 +1971,6 @@ module_exit(usb_irda_cleanup);
*/
module_param(qos_mtt_bits, int, 0);
MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver");
+MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index 4026af42dd47..d833db52cebf 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -1,7 +1,7 @@
/*****************************************************************************
*
* Filename: irda-usb.h
- * Version: 0.9b
+ * Version: 0.10
* Description: IrDA-USB Driver
* Status: Experimental
* Author: Dag Brattli <dag@brattli.net>
@@ -9,6 +9,9 @@
* Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at>
* Copyright (C) 2000, Dag Brattli <dag@brattli.net>
* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
+ * Copyright (C) 2005, Milan Beno <beno@pobox.sk>
+ * Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua>
*
* 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
@@ -31,6 +34,9 @@
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> /* struct irlap_cb */
+#define PATCH_FILE_SIZE_MAX 65536
+#define PATCH_FILE_SIZE_MIN 80
+
#define RX_COPY_THRESHOLD 200
#define IRDA_USB_MAX_MTU 2051
#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */
@@ -79,15 +85,16 @@
/* Inbound header */
#define MEDIA_BUSY 0x80
-#define SPEED_2400 0x01
-#define SPEED_9600 0x02
-#define SPEED_19200 0x03
-#define SPEED_38400 0x04
-#define SPEED_57600 0x05
-#define SPEED_115200 0x06
-#define SPEED_576000 0x07
-#define SPEED_1152000 0x08
-#define SPEED_4000000 0x09
+#define SPEED_2400 0x01
+#define SPEED_9600 0x02
+#define SPEED_19200 0x03
+#define SPEED_38400 0x04
+#define SPEED_57600 0x05
+#define SPEED_115200 0x06
+#define SPEED_576000 0x07
+#define SPEED_1152000 0x08
+#define SPEED_4000000 0x09
+#define SPEED_16000000 0x0a
/* Basic capabilities */
#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */
@@ -100,11 +107,14 @@
#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */
#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */
#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */
+#define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */
/* USB class definitions */
-#define USB_IRDA_HEADER 0x01
-#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
-#define USB_DT_IRDA 0x21
+#define USB_IRDA_HEADER 0x01
+#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */
+#define USB_DT_IRDA 0x21
+#define USB_IRDA_SIGMATEL_HEADER 0x03
+#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER)
struct irda_class_desc {
__u8 bLength;
@@ -123,6 +133,7 @@ struct irda_class_desc {
* (6.2.5, USB-IrDA class spec 1.0) */
#define IU_REQ_GET_CLASS_DESC 0x06
+#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023
struct irda_usb_cb {
struct irda_class_desc *irda_desc;
@@ -136,7 +147,8 @@ struct irda_usb_cb {
__u16 bulk_out_mtu; /* Max Tx packet size in bytes */
__u8 bulk_int_ep; /* Interrupt Endpoint assignments */
- struct urb *rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */
+ __u8 max_rx_urb;
+ struct urb **rx_urb; /* URBs used to receive data frames */
struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */
struct urb *tx_urb; /* URB used to send data frames */
struct urb *speed_urb; /* URB used to send speed commands */
@@ -157,6 +169,9 @@ struct irda_usb_cb {
__u32 speed; /* Current speed */
__s32 new_speed; /* speed we need to set */
+ __u8 header_length; /* USB-IrDA frame header size */
+ int needspatch; /* device needs firmware patch */
+
struct timer_list rx_defer_timer; /* Wait for Rx error to clear */
};
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index ec94ecdb103d..bbcfc8ec35a1 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -11,6 +11,7 @@
* Copyright (c) 2002 Daniele Peri
* All Rights Reserved.
* Copyright (c) 2002 Jean Tourrilhes
+ * Copyright (c) 2006 Linus Walleij
*
*
* Based on smc-ircc.c:
@@ -61,6 +62,9 @@
#include <linux/spinlock.h>
#include <linux/pm.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
@@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
/* Types */
+#ifdef CONFIG_PCI
+struct smsc_ircc_subsystem_configuration {
+ unsigned short vendor; /* PCI vendor ID */
+ unsigned short device; /* PCI vendor ID */
+ unsigned short subvendor; /* PCI subsystem vendor ID */
+ unsigned short subdevice; /* PCI sybsystem device ID */
+ unsigned short sir_io; /* I/O port for SIR */
+ unsigned short fir_io; /* I/O port for FIR */
+ unsigned char fir_irq; /* FIR IRQ */
+ unsigned char fir_dma; /* FIR DMA */
+ unsigned short cfg_base; /* I/O port for chip configuration */
+ int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */
+ const char *name; /* name shown as info */
+};
+#endif
+
struct smsc_transceiver {
char *name;
void (*set_for_speed)(int fir_base, u32 speed);
@@ -202,6 +222,16 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor
static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
static int __init smsc_superio_fdc(unsigned short cfg_base);
static int __init smsc_superio_lpc(unsigned short cfg_base);
+#ifdef CONFIG_PCI
+static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
+static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+ unsigned short ircc_fir,
+ unsigned short ircc_sir,
+ unsigned char ircc_dma,
+ unsigned char ircc_irq);
+#endif
/* Transceivers specific functions */
@@ -353,6 +383,13 @@ static int __init smsc_ircc_init(void)
return ret;
}
+#ifdef CONFIG_PCI
+ if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) {
+ /* Ignore errors from preconfiguration */
+ IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name);
+ }
+#endif
+
dev_count = 0;
if (ircc_fir > 0 && ircc_sir > 0) {
@@ -2285,6 +2322,280 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
return ret;
}
+/*
+ * Look for some specific subsystem setups that need
+ * pre-configuration not properly done by the BIOS (especially laptops)
+ * This code is based in part on smcinit.c, tosh1800-smcinit.c
+ * and tosh2450-smcinit.c. The table lists the device entries
+ * for ISA bridges with an LPC (Local Peripheral Configurator)
+ * that are in turn used to configure the SMSC device with default
+ * SIR and FIR I/O ports, DMA and IRQ.
+ */
+#ifdef CONFIG_PCI
+#define PCIID_VENDOR_INTEL 0x8086
+#define PCIID_VENDOR_ALI 0x10b9
+static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = {
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+ .subvendor = 0x103c,
+ .subdevice = 0x088c,
+ .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */
+ .fir_io = 0x0130,
+ .fir_irq = 0x09,
+ .fir_dma = 0x03,
+ .cfg_base = 0x004e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "HP nc8000",
+ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+ .subvendor = 0x103c,
+ .subdevice = 0x0890,
+ .sir_io = 0x02f8,
+ .fir_io = 0x0130,
+ .fir_irq = 0x09,
+ .fir_dma = 0x03,
+ .cfg_base = 0x004e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "HP nc6000",
+ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
+ .device = 0x24c0,
+ .subvendor = 0x1179,
+ .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */
+ .sir_io = 0x03f8,
+ .fir_io = 0x0130,
+ .fir_irq = 0x07,
+ .fir_dma = 0x01,
+ .cfg_base = 0x002e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "Toshiba Satellite 2450",
+ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */
+ .device = 0x248c, /* Some use 24cc? */
+ .subvendor = 0x1179,
+ .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */
+ .sir_io = 0x03f8,
+ .fir_io = 0x0130,
+ .fir_irq = 0x03,
+ .fir_dma = 0x03,
+ .cfg_base = 0x002e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "Toshiba Satellite 5100/5200, Tecra 9100",
+ },
+ {
+ .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */
+ .device = 0x1533,
+ .subvendor = 0x1179,
+ .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */
+ .sir_io = 0x02e8,
+ .fir_io = 0x02f8,
+ .fir_irq = 0x07,
+ .fir_dma = 0x03,
+ .cfg_base = 0x002e,
+ .preconfigure = preconfigure_through_ali,
+ .name = "Toshiba Satellite 1800",
+ },
+ { } // Terminator
+};
+
+
+/*
+ * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ)
+ * through the chip configuration port.
+ */
+static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf)
+{
+ unsigned short iobase = conf->cfg_base;
+ unsigned char tmpbyte;
+
+ outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state
+ outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID
+ tmpbyte = inb(iobase +1); // Read device ID
+ IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte);
+
+ /* Disable UART1 and set up SIR I/O port */
+ outb(0x24, iobase); // select CR24 - UART1 base addr
+ outb(0x00, iobase + 1); // disable UART1
+ outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr
+ outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8
+ tmpbyte = inb(iobase + 1);
+ if (tmpbyte != (conf->sir_io >> 2) ) {
+ IRDA_WARNING("ERROR: could not configure SIR ioport.\n");
+ return -ENXIO;
+ }
+
+ /* Set up FIR IRQ channel for UART2 */
+ outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select
+ tmpbyte = inb(iobase + 1);
+ tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion
+ tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK);
+ outb(tmpbyte, iobase + 1);
+ tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
+ if (tmpbyte != conf->fir_irq) {
+ IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n");
+ return -ENXIO;
+ }
+
+ /* Set up FIR I/O port */
+ outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr
+ outb((conf->fir_io >> 3), iobase + 1);
+ tmpbyte = inb(iobase + 1);
+ if (tmpbyte != (conf->fir_io >> 3) ) {
+ IRDA_WARNING("ERROR: could not configure FIR I/O port.\n");
+ return -ENXIO;
+ }
+
+ /* Set up FIR DMA channel */
+ outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select
+ outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA
+ tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK;
+ if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) {
+ IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n");
+ return -ENXIO;
+ }
+
+ outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode
+ tmpbyte = inb(iobase + 1);
+ tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA;
+ outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed
+
+ outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel
+ tmpbyte = inb(iobase + 1);
+ outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down
+
+ /* This one was not part of tosh1800 */
+ outb(0x0a, iobase); // CR0a - ecp fifo / ir mux
+ tmpbyte = inb(iobase + 1);
+ outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port
+
+ outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power
+ tmpbyte = inb(iobase + 1);
+ outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down
+
+ outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle
+ tmpbyte = inb(iobase + 1);
+ outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done
+
+ outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration
+
+ return 0;
+}
+
+/* 82801CAM registers */
+#define VID 0x00
+#define DID 0x02
+#define PIRQA_ROUT 0x60
+#define PCI_DMA_C 0x90
+#define COM_DEC 0xe0
+#define LPC_EN 0xe6
+#define GEN2_DEC 0xec
+/*
+ * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or
+ * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way!
+ */
+static int __init preconfigure_through_82801(struct pci_dev *dev,
+ struct smsc_ircc_subsystem_configuration *conf)
+{
+ unsigned short tmpword;
+ int ret;
+
+ IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n");
+ pci_write_config_byte(dev, COM_DEC, 0x10);
+
+ /* Enable LPC */
+ pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */
+ tmpword &= 0xfffd; /* mask bit 1 */
+ tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */
+ pci_write_config_word(dev, LPC_EN, tmpword);
+
+ /* Setup DMA */
+ pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */
+ pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */
+
+ /* Pre-configure chip */
+ ret = preconfigure_smsc_chip(conf);
+
+ /* Disable LPC */
+ pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */
+ tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */
+ pci_write_config_word(dev, LPC_EN, tmpword);
+ return ret;
+}
+
+static int __init preconfigure_through_ali(struct pci_dev *dev,
+ struct smsc_ircc_subsystem_configuration *conf)
+{
+ /* TODO: put in ALi 1533 configuration here. */
+ IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name);
+ return -ENODEV;
+}
+
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+ unsigned short ircc_fir,
+ unsigned short ircc_sir,
+ unsigned char ircc_dma,
+ unsigned char ircc_irq)
+{
+ struct pci_dev *dev = NULL;
+ unsigned short ss_vendor = 0x0000;
+ unsigned short ss_device = 0x0000;
+ int ret = 0;
+
+ dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+
+ while (dev != NULL) {
+ struct smsc_ircc_subsystem_configuration *conf;
+
+ /*
+ * Cache the subsystem vendor/device: some manufacturers fail to set
+ * this for all components, so we save it in case there is just
+ * 0x0000 0x0000 on the device we want to check.
+ */
+ if (dev->subsystem_vendor != 0x0000U) {
+ ss_vendor = dev->subsystem_vendor;
+ ss_device = dev->subsystem_device;
+ }
+ conf = subsystem_configurations;
+ for( ; conf->subvendor; conf++) {
+ if(conf->vendor == dev->vendor &&
+ conf->device == dev->device &&
+ conf->subvendor == ss_vendor && /* Sometimes these are cached values */
+ (conf->subdevice == ss_device || conf->subdevice == 0xffff)) {
+ struct smsc_ircc_subsystem_configuration tmpconf;
+
+ memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration));
+
+ /* Override the default values with anything passed in as parameter */
+ if (ircc_cfg != 0)
+ tmpconf.cfg_base = ircc_cfg;
+ if (ircc_fir != 0)
+ tmpconf.fir_io = ircc_fir;
+ if (ircc_sir != 0)
+ tmpconf.sir_io = ircc_sir;
+ if (ircc_dma != 0xff)
+ tmpconf.fir_dma = ircc_dma;
+ if (ircc_irq != 0xff)
+ tmpconf.fir_irq = ircc_irq;
+
+ IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name);
+ if (conf->preconfigure)
+ ret = conf->preconfigure(dev, &tmpconf);
+ else
+ ret = -ENODEV;
+ }
+ }
+ dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+ }
+
+ return ret;
+}
+#endif // CONFIG_PCI
+
/************************************************
*
* Transceivers specific functions
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index f9f77e4f5965..cfd67d812f0d 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -357,18 +357,20 @@ ixgb_probe(struct pci_dev *pdev,
if((err = pci_enable_device(pdev)))
return err;
- if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+ if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+ !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
pci_using_dac = 1;
} else {
- if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
IXGB_ERR("No usable DMA configuration, aborting\n");
- return err;
+ goto err_dma_mask;
}
pci_using_dac = 0;
}
if((err = pci_request_regions(pdev, ixgb_driver_name)))
- return err;
+ goto err_request_regions;
pci_set_master(pdev);
@@ -502,6 +504,9 @@ err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
pci_release_regions(pdev);
+err_request_regions:
+err_dma_mask:
+ pci_disable_device(pdev);
return err;
}
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 9f2661355a4a..ea62a3e7d586 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -281,10 +281,16 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev)
{
struct mv643xx_private *mp = netdev_priv(dev);
- netif_device_detach(dev);
+ if (!netif_running(dev))
+ return;
+
+ netif_stop_queue(dev);
+
eth_port_reset(mp->port_num);
eth_port_start(dev);
- netif_device_attach(dev);
+
+ if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB)
+ netif_wake_queue(dev);
}
/**
@@ -552,9 +558,9 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
#else
if (eth_int_cause & ETH_INT_CAUSE_RX)
mv643xx_eth_receive_queue(dev, INT_MAX);
+#endif
if (eth_int_cause_ext & ETH_INT_CAUSE_TX)
mv643xx_eth_free_completed_tx_descs(dev);
-#endif
/*
* If no real interrupt occured, exit.
@@ -1186,7 +1192,12 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
BUG_ON(netif_queue_stopped(dev));
BUG_ON(skb == NULL);
- BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB);
+
+ if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) {
+ printk(KERN_ERR "%s: transmit with queue full\n", dev->name);
+ netif_stop_queue(dev);
+ return 1;
+ }
if (has_tiny_unaligned_frags(skb)) {
if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 7826afbb9db9..90627756d6fa 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -238,7 +238,7 @@ static int full_duplex[MAX_UNITS];
#define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */
/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static const char version[] __devinitdata =
KERN_INFO DRV_NAME " dp8381x driver, version "
DRV_VERSION ", " DRV_RELDATE "\n"
KERN_INFO " originally by Donald Becker <becker@scyld.com>\n"
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 75b35ad760de..66e74f740261 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -87,6 +87,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
}
static struct console netconsole = {
+ .name = "netcon",
.flags = CON_ENABLED | CON_PRINTBUFFER,
.write = write_msg
};
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 56233afcb2b3..448a09488529 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1560,7 +1560,7 @@ static void ei_receive(struct net_device *dev)
static void ei_rx_overrun(struct net_device *dev)
{
- axnet_dev_t *info = (axnet_dev_t *)dev;
+ axnet_dev_t *info = PRIV(dev);
long e8390_base = dev->base_addr;
unsigned char was_txing, must_resend = 0;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 35dbf05c7f06..a70c2b0cc104 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -78,6 +78,8 @@ static const struct pci_device_id skge_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
{ PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 68f9c206a620..67b0eab16589 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -99,8 +99,6 @@ MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) },
@@ -579,8 +577,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
reg = gma_read16(hw, port, GM_PHY_ADDR);
gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
- for (i = 0; i < GM_MIB_CNT_SIZE; i++)
- gma_read16(hw, port, GM_MIB_CNT_BASE + 8 * i);
+ for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4)
+ gma_read16(hw, port, i);
gma_write16(hw, port, GM_PHY_ADDR, reg);
/* transmit control */
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 62532b4e45c5..89dd18cd12f0 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1375,7 +1375,7 @@ enum {
GM_PHY_ADDR = 0x0088, /* 16 bit r/w GPHY Address Register */
/* MIB Counters */
GM_MIB_CNT_BASE = 0x0100, /* Base Address of MIB Counters */
- GM_MIB_CNT_SIZE = 256,
+ GM_MIB_CNT_END = 0x025C, /* Last MIB counter */
};
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 45ad036733e2..9b7805be21da 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -335,7 +335,7 @@ do { \
/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static const char version[] __devinitdata =
KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n"
KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 0b5358072172..73e271e59c6a 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -497,21 +497,20 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags);
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+ if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
- /* Always leave this as zero. */
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
- spin_unlock_irqrestore(&tp->indirect_lock, flags);
-}
+ /* Always leave this as zero. */
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+ } else {
+ tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
+ tw32_f(TG3PCI_MEM_WIN_DATA, val);
-static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val)
-{
- /* If no workaround is needed, write to mem space directly */
- if (tp->write32 != tg3_write_indirect_reg32)
- tw32(NIC_SRAM_WIN_BASE + off, val);
- else
- tg3_write_mem(tp, off, val);
+ /* Always leave this as zero. */
+ tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+ }
+ spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
@@ -519,11 +518,19 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags);
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
- pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+ if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+ pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
- /* Always leave this as zero. */
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+ /* Always leave this as zero. */
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+ } else {
+ tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
+ *val = tr32(TG3PCI_MEM_WIN_DATA);
+
+ /* Always leave this as zero. */
+ tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+ }
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
@@ -1367,12 +1374,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}
}
+ tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+
/* Finally, set the new power state. */
pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
udelay(100); /* Delay after power state change */
- tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
-
return 0;
}
@@ -5828,10 +5835,14 @@ static int tg3_reset_hw(struct tg3 *tp)
GRC_MODE_NO_TX_PHDR_CSUM |
GRC_MODE_NO_RX_PHDR_CSUM);
tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
- if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM)
- tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
- if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM)
- tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
+
+ /* Pseudo-header checksum is done by hardware logic and not
+ * the offload processers, so make the chip do the pseudo-
+ * header checksums on receive. For transmit it is more
+ * convenient to do the pseudo-header checksum in software
+ * as Linux does that on transmit for us in all cases.
+ */
+ tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
tw32(GRC_MODE,
tp->grc_mode |
@@ -6535,11 +6546,11 @@ static void tg3_timer(unsigned long __opaque)
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
- tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX,
- FWCMD_NICDRV_ALIVE2);
- tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
+ FWCMD_NICDRV_ALIVE2);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */
- tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
val = tr32(GRC_RX_CPU_EVENT);
val |= (1 << 14);
tw32(GRC_RX_CPU_EVENT, val);
@@ -8034,9 +8045,13 @@ static int tg3_test_nvram(struct tg3 *tp)
for (i = 0; i < size; i++)
csum8 += buf8[i];
- if (csum8 == 0)
- return 0;
- return -EIO;
+ if (csum8 == 0) {
+ err = 0;
+ goto out;
+ }
+
+ err = -EIO;
+ goto out;
}
/* Bootstrap checksum at offset 0x10 */
@@ -9531,8 +9546,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
/* Do not even try poking around in here on Sun parts. */
- if (tp->tg3_flags2 & TG3_FLG2_SUN_570X)
+ if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+ /* All SUN chips are built-in LOMs. */
+ tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
return;
+ }
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
@@ -9630,9 +9648,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
tp->led_ctrl = LED_CTRL_MODE_PHY_2;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
- (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
+ if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)
tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
@@ -10257,6 +10273,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
}
+ if (tp->write32 == tg3_write_indirect_reg32 ||
+ ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) ||
+ (tp->tg3_flags2 & TG3_FLG2_SUN_570X))
+ tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
+
/* Get eeprom hw config before calling tg3_set_power_state().
* In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be
* determined before calling tg3_set_power_state() so that
@@ -10299,15 +10322,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
- /* Pseudo-header checksum is done by hardware logic and not
- * the offload processers, so make the chip do the pseudo-
- * header checksums on receive. For transmit it is more
- * convenient to do the pseudo-header checksum in software
- * as Linux does that on transmit for us in all cases.
- */
- tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM;
- tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM;
-
/* Derive initial jumbo mode from MTU assigned in
* ether_setup() via the alloc_etherdev() call
*/
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index c43cc3264202..8c8b987d1250 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2171,8 +2171,7 @@ struct tg3 {
#define TG3_FLAG_PCIX_MODE 0x00020000
#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000
#define TG3_FLAG_PCI_32BIT 0x00080000
-#define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000
-#define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000
+#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000
#define TG3_FLAG_SERDES_WOL_CAP 0x00400000
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index c1ce87a5f8d3..d9258d42090c 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -134,7 +134,7 @@ static const int multicast_filter_limit = 32;
#include "typhoon.h"
#include "typhoon-firmware.h"
-static char version[] __devinitdata =
+static const char version[] __devinitdata =
"typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index a9b2150909d6..6a23964c1317 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -469,7 +469,7 @@ struct rhine_private {
struct sk_buff *tx_skbuff[TX_RING_SIZE];
dma_addr_t tx_skbuff_dma[TX_RING_SIZE];
- /* Tx bounce buffers */
+ /* Tx bounce buffers (Rhine-I only) */
unsigned char *tx_buf[TX_RING_SIZE];
unsigned char *tx_bufs;
dma_addr_t tx_bufs_dma;
@@ -1043,7 +1043,8 @@ static void alloc_tbufs(struct net_device* dev)
rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
next += sizeof(struct tx_desc);
rp->tx_ring[i].next_desc = cpu_to_le32(next);
- rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ];
+ if (rp->quirks & rqRhineI)
+ rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ];
}
rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma);
@@ -1091,7 +1092,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
}
/* Called after status of force_media possibly changed */
-void rhine_set_carrier(struct mii_if_info *mii)
+static void rhine_set_carrier(struct mii_if_info *mii)
{
if (mii->force_media) {
/* autoneg is off: Link is always assumed to be up */
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 883cf7da10fc..b5328b0ff927 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -410,103 +410,6 @@ config WAN_ROUTER_DRIVERS
If unsure, say N.
-config VENDOR_SANGOMA
- tristate "Sangoma WANPIPE(tm) multiprotocol cards"
- depends on WAN_ROUTER_DRIVERS && WAN_ROUTER && (PCI || ISA) && BROKEN
- ---help---
- Driver for S514-PCI/ISA Synchronous Data Link Adapters (SDLA).
-
- WANPIPE from Sangoma Technologies Inc. <http://www.sangoma.com/>
- is a family of intelligent multiprotocol WAN adapters with data
- transfer rates up to 4Mbps. Cards support:
-
- - X.25, Frame Relay, PPP, Cisco HDLC protocols.
-
- - API for protocols like HDLC (LAPB), HDLC Streaming, X.25,
- Frame Relay and BiSync.
-
- - Ethernet Bridging over Frame Relay protocol.
-
- - MULTILINK PPP
-
- - Async PPP (Modem Dialup)
-
- The next questions will ask you about the protocols you want
- the driver to support.
-
- If you have one or more of these cards, say M to this option;
- and read <file:Documentation/networking/wan-router.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called wanpipe.
-
-config WANPIPE_CHDLC
- bool "WANPIPE Cisco HDLC support"
- depends on VENDOR_SANGOMA
- ---help---
- Connect a WANPIPE card to a leased line using the Cisco HDLC.
-
- - Supports Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards
- which allows user to build applications using the HDLC streaming API.
-
- - CHDLC Streaming MULTILINK PPP that can bind multiple WANPIPE T1
- cards into a single logical channel.
-
- Say Y and the Cisco HDLC support, HDLC streaming API and
- MULTILINK PPP will be included in the driver.
-
-config WANPIPE_FR
- bool "WANPIPE Frame Relay support"
- depends on VENDOR_SANGOMA
- help
- Connect a WANPIPE card to a Frame Relay network, or use Frame Relay
- API to develop custom applications.
-
- Contains the Ethernet Bridging over Frame Relay feature, where
- a WANPIPE frame relay link can be directly connected to the Linux
- kernel bridge. The Frame Relay option is supported on S514-PCI
- and S508-ISA cards.
-
- Say Y and the Frame Relay support will be included in the driver.
-
-config WANPIPE_X25
- bool "WANPIPE X.25 support"
- depends on VENDOR_SANGOMA
- help
- Connect a WANPIPE card to an X.25 network.
-
- Includes the X.25 API support for custom applications over the
- X.25 protocol. The X.25 option is supported on S514-PCI and
- S508-ISA cards.
-
- Say Y and the X.25 support will be included in the driver.
-
-config WANPIPE_PPP
- bool "WANPIPE PPP support"
- depends on VENDOR_SANGOMA
- help
- Connect a WANPIPE card to a leased line using Point-to-Point
- Protocol (PPP).
-
- The PPP option is supported on S514-PCI/S508-ISA cards.
-
- Say Y and the PPP support will be included in the driver.
-
-config WANPIPE_MULTPPP
- bool "WANPIPE Multi-Port PPP support"
- depends on VENDOR_SANGOMA
- help
- Connect a WANPIPE card to a leased line using Point-to-Point
- Protocol (PPP).
-
- Uses in-kernel SyncPPP protocol over the Sangoma HDLC Streaming
- adapter. In this case each Sangoma adapter port can support an
- independent PPP connection. For example, a single Quad-Port PCI
- adapter can support up to four independent PPP links. The PPP
- option is supported on S514-PCI/S508-ISA cards.
-
- Say Y and the Multi-Port PPP support will be included in the driver.
-
config CYCLADES_SYNC
tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)"
depends on WAN_ROUTER_DRIVERS && (PCI || ISA)
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index ce6c56b903e7..823c6d5ab90d 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -5,14 +5,6 @@
# Rewritten to use lists instead of if-statements.
#
-wanpipe-y := sdlamain.o sdla_ft1.o
-wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o
-wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o
-wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o
-wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o
-wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o
-wanpipe-objs := $(wanpipe-y)
-
cyclomx-y := cycx_main.o
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
cyclomx-objs := $(cyclomx-y)
@@ -43,11 +35,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/
obj-$(CONFIG_DLCI) += dlci.o
obj-$(CONFIG_SDLA) += sdla.o
-ifeq ($(CONFIG_WANPIPE_MULTPPP),y)
- obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o
-else
- obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o
-endif
obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
deleted file mode 100644
index 496d29237e92..000000000000
--- a/drivers/net/wan/sdla_chdlc.c
+++ /dev/null
@@ -1,4428 +0,0 @@
-/*****************************************************************************
-* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module.
-*
-* Authors: Nenad Corbic <ncorbic@sangoma.com>
-* Gideon Hack
-*
-* Copyright: (c) 1995-2001 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for
-* 2.4.X kernels.
-* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the
-* HDLC streaming protocol
-* Added a TTY Async serial driver over the
-* Async protocol.
-* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support
-* Nov 13, 2000 Nenad Corbic Added true interface type encoding option.
-* Tcpdump doesn't support CHDLC inteface
-* types, to fix this "true type" option will set
-* the interface type to RAW IP mode.
-* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging:
-* Deny all and specify allowed requests.
-* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the
-* latest update.
-* May 09, 2000 Nenad Corbic Option to bring down an interface
-* upon disconnect.
-* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling.
-* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing.
-* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery.
-* Feb 10, 2000 Gideon Hack Added ASYNC support.
-* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and
-* if_stats() functions.
-* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing,
-* condition between if_open and isr.
-* Jan 10, 2000 Nenad Corbic Added new socket API support.
-* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels
-* Nov 20, 1999 Nenad Corbic Fixed zero length API bug.
-* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup.
-* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing
-* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices.
-* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
-* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING).
-* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC.
-* Aug 07, 1998 David Fong Initial version.
-*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/if_arp.h> /* ARPHRD_* defines */
-
-
-#include <asm/uaccess.h>
-#include <linux/inetdevice.h>
-#include <linux/netdevice.h>
-
-#include <linux/in.h> /* sockaddr_in */
-#include <linux/inet.h>
-#include <linux/if.h>
-#include <asm/byteorder.h> /* htons(), etc. */
-#include <linux/sdlapci.h>
-#include <asm/io.h>
-
-#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */
-#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */
-
-#include <linux/if_wanpipe_common.h> /* Socket Driver common area */
-#include <linux/if_wanpipe.h>
-
-/* TTY Includes */
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-
-
-/****** Defines & Macros ****************************************************/
-
-/* reasons for enabling the timer interrupt on the adapter */
-#define TMR_INT_ENABLED_UDP 0x01
-#define TMR_INT_ENABLED_UPDATE 0x02
-#define TMR_INT_ENABLED_CONFIG 0x10
-
-#define MAX_IP_ERRORS 10
-
-#define TTY_CHDLC_MAX_MTU 2000
-#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */
-#define CHDLC_HDR_LEN 1
-
-#define CHDLC_API 0x01
-
-#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" )
-#define MAX_BH_BUFF 10
-
-//#define PRINT_DEBUG
-#ifdef PRINT_DEBUG
-#define dbg_printk(format, a...) printk(format, ## a)
-#else
-#define dbg_printk(format, a...)
-#endif
-
-/******Data Structures*****************************************************/
-
-/* This structure is placed in the private data area of the device structure.
- * The card structure used to occupy the private area but now the following
- * structure will incorporate the card structure along with CHDLC specific data
- */
-
-typedef struct chdlc_private_area
-{
- wanpipe_common_t common;
- sdla_t *card;
- int TracingEnabled; /* For enabling Tracing */
- unsigned long curr_trace_addr; /* Used for Tracing */
- unsigned long start_trace_addr;
- unsigned long end_trace_addr;
- unsigned long base_addr_trace_buffer;
- unsigned long end_addr_trace_buffer;
- unsigned short number_trace_elements;
- unsigned available_buffer_space;
- unsigned long router_start_time;
- unsigned char route_status;
- unsigned char route_removed;
- unsigned long tick_counter; /* For 5s timeout counter */
- unsigned long router_up_time;
- u32 IP_address; /* IP addressing */
- u32 IP_netmask;
- u32 ip_local;
- u32 ip_remote;
- u32 ip_local_tmp;
- u32 ip_remote_tmp;
- u8 ip_error;
- u8 config_chdlc;
- u8 config_chdlc_timeout;
- unsigned char mc; /* Mulitcast support on/off */
- unsigned short udp_pkt_lgth; /* udp packet processing */
- char udp_pkt_src;
- char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
- unsigned short timer_int_enabled;
- char update_comms_stats; /* updating comms stats */
-
- bh_data_t *bh_head; /* Circular buffer for chdlc_bh */
- unsigned long tq_working;
- volatile int bh_write;
- volatile int bh_read;
- atomic_t bh_buff_used;
-
- unsigned char interface_down;
-
- /* Polling work queue entry. Each interface
- * has its own work queue entry, which is used
- * to defer events from the interrupt */
- struct work_struct poll_work;
- struct timer_list poll_delay_timer;
-
- u8 gateway;
- u8 true_if_encoding;
- //FIXME: add driver stats as per frame relay!
-
-} chdlc_private_area_t;
-
-/* Route Status options */
-#define NO_ROUTE 0x00
-#define ADD_ROUTE 0x01
-#define ROUTE_ADDED 0x02
-#define REMOVE_ROUTE 0x03
-
-
-/* variable for keeping track of enabling/disabling FT1 monitor status */
-static int rCount = 0;
-
-/* variable for tracking how many interfaces to open for WANPIPE on the
- two ports */
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/****** Function Prototypes *************************************************/
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(struct wan_device* wandev);
-static int new_if(struct wan_device* wandev, struct net_device* dev,
- wanif_conf_t* conf);
-
-/* Network device interface */
-static int if_init(struct net_device* dev);
-static int if_open(struct net_device* dev);
-static int if_close(struct net_device* dev);
-static int if_header(struct sk_buff* skb, struct net_device* dev,
- unsigned short type, void* daddr, void* saddr,
- unsigned len);
-
-static int if_rebuild_hdr (struct sk_buff *skb);
-static struct net_device_stats* if_stats(struct net_device* dev);
-
-static int if_send(struct sk_buff* skb, struct net_device* dev);
-
-/* CHDLC Firmware interface functions */
-static int chdlc_configure (sdla_t* card, void* data);
-static int chdlc_comm_enable (sdla_t* card);
-static int chdlc_read_version (sdla_t* card, char* str);
-static int chdlc_set_intr_mode (sdla_t* card, unsigned mode);
-static int chdlc_send (sdla_t* card, void* data, unsigned len);
-static int chdlc_read_comm_err_stats (sdla_t* card);
-static int chdlc_read_op_stats (sdla_t* card);
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
-
-
-static int chdlc_disable_comm_shutdown (sdla_t *card);
-static void if_tx_timeout(struct net_device *dev);
-
-/* Miscellaneous CHDLC Functions */
-static int set_chdlc_config (sdla_t* card);
-static void init_chdlc_tx_rx_buff( sdla_t* card);
-static int process_chdlc_exception(sdla_t *card);
-static int process_global_exception(sdla_t *card);
-static int update_comms_stats(sdla_t* card,
- chdlc_private_area_t* chdlc_priv_area);
-static int configure_ip (sdla_t* card);
-static int unconfigure_ip (sdla_t* card);
-static void process_route(sdla_t *card);
-static void port_set_state (sdla_t *card, int);
-static int config_chdlc (sdla_t *card);
-static void disable_comm (sdla_t *card);
-
-static void trigger_chdlc_poll(struct net_device *dev);
-static void chdlc_poll(struct net_device *dev);
-static void chdlc_poll_delay (unsigned long dev_ptr);
-
-
-/* Miscellaneous asynchronous interface Functions */
-static int set_asy_config (sdla_t* card);
-static int asy_comm_enable (sdla_t* card);
-
-/* Interrupt handlers */
-static void wpc_isr (sdla_t* card);
-static void rx_intr (sdla_t* card);
-static void timer_intr(sdla_t *);
-
-/* Bottom half handlers */
-static void chdlc_work(struct net_device *dev);
-static int chdlc_work_cleanup(struct net_device *dev);
-static int bh_enqueue(struct net_device *dev, struct sk_buff *skb);
-
-/* Miscellaneous functions */
-static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev,
- struct sk_buff *skb);
-static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static int intr_test( sdla_t* card);
-static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
-static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area);
-static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area);
-static unsigned short calc_checksum (char *, int);
-static void s508_lock (sdla_t *card, unsigned long *smp_flags);
-static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
-
-
-static int Intr_test_counter;
-
-/* TTY Global Definitions */
-
-#define NR_PORTS 4
-#define WAN_TTY_MAJOR 226
-#define WAN_TTY_MINOR 0
-
-#define WAN_CARD(port) (tty_card_map[port])
-#define MIN_PORT 0
-#define MAX_PORT NR_PORTS-1
-
-#define CRC_LENGTH 2
-
-static int wanpipe_tty_init(sdla_t *card);
-static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int);
-static void wanpipe_tty_trigger_poll(sdla_t *card);
-
-static struct tty_driver serial_driver;
-static int tty_init_cnt=0;
-
-static struct serial_state rs_table[NR_PORTS];
-
-static char tty_driver_mode=WANOPT_TTY_SYNC;
-
-static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX",
- "CRTSCTS XONXOFF-RX","XONXOFF-TX",
- "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"};
-static char *p_decode[] = {"NONE","ODD","EVEN"};
-
-static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL};
-
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * Cisco HDLC protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup. At this
- * point adapter is completely initialized and firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
-int wpc_init (sdla_t* card, wandev_conf_t* conf)
-{
- unsigned char port_num;
- int err;
- unsigned long max_permitted_baud = 0;
- SHARED_MEMORY_INFO_STRUCT *flags;
-
- union
- {
- char str[80];
- } u;
- volatile CHDLC_MAILBOX_STRUCT* mb;
- CHDLC_MAILBOX_STRUCT* mb1;
- unsigned long timeout;
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_CHDLC) {
- printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
- return -EINVAL;
- }
-
- /* Find out which Port to use */
- if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){
- if (card->next){
-
- if (conf->comm_port != card->next->u.c.comm_port){
- card->u.c.comm_port = conf->comm_port;
- }else{
- printk(KERN_INFO "%s: ERROR - %s port used!\n",
- card->wandev.name, PORT(conf->comm_port));
- return -EINVAL;
- }
- }else{
- card->u.c.comm_port = conf->comm_port;
- }
- }else{
- printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n",
- card->wandev.name);
- return -EINVAL;
- }
-
-
- /* Initialize protocol-specific fields */
- if(card->hw.type != SDLA_S514){
-
- if (card->u.c.comm_port == WANOPT_PRI){
- card->mbox = (void *) card->hw.dpmbase;
- }else{
- card->mbox = (void *) card->hw.dpmbase +
- SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT;
- }
- }else{
- /* for a S514 adapter, set a pointer to the actual mailbox in the */
- /* allocated virtual memory area */
- if (card->u.c.comm_port == WANOPT_PRI){
- card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT;
- }else{
- card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT;
- }
- }
-
- mb = mb1 = card->mbox;
-
- if (!card->configured){
-
- /* The board will place an 'I' in the return code to indicate that it is
- ready to accept commands. We expect this to be completed in less
- than 1 second. */
-
- timeout = jiffies;
- while (mb->return_code != 'I') /* Wait 1s for board to initialize */
- if ((jiffies - timeout) > 1*HZ) break;
-
- if (mb->return_code != 'I') {
- printk(KERN_INFO
- "%s: Initialization not completed by adapter\n",
- card->devname);
- printk(KERN_INFO "Please contact Sangoma representative.\n");
- return -EIO;
- }
- }
-
- /* Read firmware version. Note that when adapter initializes, it
- * clears the mailbox, so it may appear that the first command was
- * executed successfully when in fact it was merely erased. To work
- * around this, we execute the first command twice.
- */
-
- if (chdlc_read_version(card, u.str))
- return -EIO;
-
- printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n",
- card->devname, u.str);
-
- card->isr = &wpc_isr;
- card->poll = NULL;
- card->exec = NULL;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = NULL;
- card->wandev.udp_port = conf->udp_port;
- card->disable_comm = &disable_comm;
- card->wandev.new_if_cnt = 0;
-
- /* reset the number of times the 'update()' proc has been called */
- card->u.c.update_call_count = 0;
-
- card->wandev.ttl = conf->ttl;
- card->wandev.interface = conf->interface;
-
- if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&&
- card->hw.type != SDLA_S514){
- printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n",
- card->devname, PORT(card->u.c.comm_port));
- return -EIO;
- }
-
- card->wandev.clocking = conf->clocking;
-
- port_num = card->u.c.comm_port;
-
- /* in API mode, we can configure for "receive only" buffering */
- if(card->hw.type == SDLA_S514) {
- card->u.c.receive_only = conf->receive_only;
- if(conf->receive_only) {
- printk(KERN_INFO
- "%s: Configured for 'receive only' mode\n",
- card->devname);
- }
- }
-
- /* Setup Port Bps */
-
- if(card->wandev.clocking) {
- if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
- /* For Primary Port 0 */
- max_permitted_baud =
- (card->hw.type == SDLA_S514) ?
- PRI_MAX_BAUD_RATE_S514 :
- PRI_MAX_BAUD_RATE_S508;
-
- }else if(port_num == WANOPT_SEC) {
- /* For Secondary Port 1 */
- max_permitted_baud =
- (card->hw.type == SDLA_S514) ?
- SEC_MAX_BAUD_RATE_S514 :
- SEC_MAX_BAUD_RATE_S508;
- }
-
- if(conf->bps > max_permitted_baud) {
- conf->bps = max_permitted_baud;
- printk(KERN_INFO "%s: Baud too high!\n",
- card->wandev.name);
- printk(KERN_INFO "%s: Baud rate set to %lu bps\n",
- card->wandev.name, max_permitted_baud);
- }
- card->wandev.bps = conf->bps;
- }else{
- card->wandev.bps = 0;
- }
-
- /* Setup the Port MTU */
- if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
-
- /* For Primary Port 0 */
- card->wandev.mtu =
- (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
- min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) :
- CHDLC_DFLT_DATA_LEN;
- } else if(port_num == WANOPT_SEC) {
- /* For Secondary Port 1 */
- card->wandev.mtu =
- (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
- min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) :
- CHDLC_DFLT_DATA_LEN;
- }
-
- /* Set up the interrupt status area */
- /* Read the CHDLC Configuration and obtain:
- * Ptr to shared memory infor struct
- * Use this pointer to calculate the value of card->u.c.flags !
- */
- mb1->buffer_length = 0;
- mb1->command = READ_CHDLC_CONFIGURATION;
- err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
- if(err != COMMAND_OK) {
- if(card->hw.type != SDLA_S514)
- enable_irq(card->hw.irq);
-
- chdlc_error(card, err, mb1);
- return -EIO;
- }
-
- if(card->hw.type == SDLA_S514){
- card->u.c.flags = (void *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
- ptr_shared_mem_info_struct));
- }else{
- card->u.c.flags = (void *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
- ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
- }
-
- flags = card->u.c.flags;
-
- /* This is for the ports link state */
- card->wandev.state = WAN_DUALPORT;
- card->u.c.state = WAN_DISCONNECTED;
-
-
- if (!card->wandev.piggyback){
- int err;
-
- /* Perform interrupt testing */
- err = intr_test(card);
-
- if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
- printk(KERN_INFO "%s: Interrupt test failed (%i)\n",
- card->devname, Intr_test_counter);
- printk(KERN_INFO "%s: Please choose another interrupt\n",
- card->devname);
- return -EIO;
- }
-
- printk(KERN_INFO "%s: Interrupt test passed (%i)\n",
- card->devname, Intr_test_counter);
- card->configured = 1;
- }
-
- if ((card->tty_opt=conf->tty) == WANOPT_YES){
- int err;
- card->tty_minor = conf->tty_minor;
-
- /* On ASYNC connections internal clocking
- * is mandatory */
- if ((card->u.c.async_mode = conf->tty_mode)){
- card->wandev.clocking = 1;
- }
- err=wanpipe_tty_init(card);
- if (err){
- return err;
- }
- }else{
-
-
- if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){
- printk (KERN_INFO "%s: "
- "Failed to set interrupt triggers!\n",
- card->devname);
- return -EIO;
- }
-
- /* Mask the Timer interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TIMER;
- }
-
- /* If we are using CHDLC in backup mode, this flag will
- * indicate not to look for IP addresses in config_chdlc()*/
- card->u.c.backup = conf->backup;
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics
- * This procedure is called when updating the PROC file system and returns
- * various communications statistics. These statistics are accumulated from 3
- * different locations:
- * 1) The 'if_stats' recorded for the device.
- * 2) Communication error statistics on the adapter.
- * 3) CHDLC operational statistics on the adapter.
- * The board level statistics are read during a timer interrupt. Note that we
- * read the error and operational statistics during consecitive timer ticks so
- * as to minimize the time that we are inside the interrupt handler.
- *
- */
-static int update(struct wan_device* wandev)
-{
- sdla_t* card = wandev->private;
- struct net_device* dev;
- volatile chdlc_private_area_t* chdlc_priv_area;
- SHARED_MEMORY_INFO_STRUCT *flags;
- unsigned long timeout;
-
- /* sanity checks */
- if((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
-
- if(wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- /* more sanity checks */
- if(!card->u.c.flags)
- return -ENODEV;
-
- if(test_bit(PERI_CRIT, (void*)&card->wandev.critical))
- return -EAGAIN;
-
- if((dev=card->wandev.dev) == NULL)
- return -ENODEV;
-
- if((chdlc_priv_area=dev->priv) == NULL)
- return -ENODEV;
-
- flags = card->u.c.flags;
- if(chdlc_priv_area->update_comms_stats){
- return -EAGAIN;
- }
-
- /* we will need 2 timer interrupts to complete the */
- /* reading of the statistics */
- chdlc_priv_area->update_comms_stats = 2;
- flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
- chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE;
-
- /* wait a maximum of 1 second for the statistics to be updated */
- timeout = jiffies;
- for(;;) {
- if(chdlc_priv_area->update_comms_stats == 0)
- break;
- if ((jiffies - timeout) > (1 * HZ)){
- chdlc_priv_area->update_comms_stats = 0;
- chdlc_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_UPDATE;
- return -EAGAIN;
- }
- }
-
- return 0;
-}
-
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return: 0 o.k.
- * < 0 failure (channel will not be created)
- */
-static int new_if(struct wan_device* wandev, struct net_device* dev,
- wanif_conf_t* conf)
-{
- sdla_t* card = wandev->private;
- chdlc_private_area_t* chdlc_priv_area;
-
-
- printk(KERN_INFO "%s: Configuring Interface: %s\n",
- card->devname, conf->name);
-
- if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
- printk(KERN_INFO "%s: Invalid interface name!\n",
- card->devname);
- return -EINVAL;
- }
-
- /* allocate and initialize private data */
- chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL);
-
- if(chdlc_priv_area == NULL)
- return -ENOMEM;
-
- memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t));
-
- chdlc_priv_area->card = card;
- chdlc_priv_area->common.sk = NULL;
- chdlc_priv_area->common.func = NULL;
-
- /* initialize data */
- strcpy(card->u.c.if_name, conf->name);
-
- if(card->wandev.new_if_cnt > 0) {
- kfree(chdlc_priv_area);
- return -EEXIST;
- }
-
- card->wandev.new_if_cnt++;
-
- chdlc_priv_area->TracingEnabled = 0;
- chdlc_priv_area->route_status = NO_ROUTE;
- chdlc_priv_area->route_removed = 0;
-
- card->u.c.async_mode = conf->async_mode;
-
- /* setup for asynchronous mode */
- if(conf->async_mode) {
- printk(KERN_INFO "%s: Configuring for asynchronous mode\n",
- wandev->name);
-
- if(card->u.c.comm_port == WANOPT_PRI) {
- printk(KERN_INFO
- "%s:Asynchronous mode on secondary port only\n",
- wandev->name);
- kfree(chdlc_priv_area);
- return -EINVAL;
- }
-
- if(strcmp(conf->usedby, "WANPIPE") == 0) {
- printk(KERN_INFO
- "%s: Running in WANIPE Async Mode\n", wandev->name);
- card->u.c.usedby = WANPIPE;
- }else{
- card->u.c.usedby = API;
- }
-
- if(!card->wandev.clocking) {
- printk(KERN_INFO
- "%s: Asynch. clocking must be 'Internal'\n",
- wandev->name);
- kfree(chdlc_priv_area);
- return -EINVAL;
- }
-
- if((card->wandev.bps < MIN_ASY_BAUD_RATE) ||
- (card->wandev.bps > MAX_ASY_BAUD_RATE)) {
- printk(KERN_INFO "%s: Selected baud rate is invalid.\n",
- wandev->name);
- printk(KERN_INFO "Must be between %u and %u bps.\n",
- MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE);
- kfree(chdlc_priv_area);
- return -EINVAL;
- }
-
- card->u.c.api_options = 0;
- if (conf->asy_data_trans == WANOPT_YES) {
- card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT;
- }
-
- card->u.c.protocol_options = 0;
- if (conf->rts_hs_for_receive == WANOPT_YES) {
- card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX;
- }
- if (conf->xon_xoff_hs_for_receive == WANOPT_YES) {
- card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX;
- }
- if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) {
- card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX;
- }
- if (conf->dcd_hs_for_transmit == WANOPT_YES) {
- card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX;
- }
- if (conf->cts_hs_for_transmit == WANOPT_YES) {
- card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX;
- }
-
- card->u.c.tx_bits_per_char = conf->tx_bits_per_char;
- card->u.c.rx_bits_per_char = conf->rx_bits_per_char;
- card->u.c.stop_bits = conf->stop_bits;
- card->u.c.parity = conf->parity;
- card->u.c.break_timer = conf->break_timer;
- card->u.c.inter_char_timer = conf->inter_char_timer;
- card->u.c.rx_complete_length = conf->rx_complete_length;
- card->u.c.xon_char = conf->xon_char;
-
- } else { /* setup for synchronous mode */
-
- card->u.c.protocol_options = 0;
- if (conf->ignore_dcd == WANOPT_YES){
- card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT;
- }
- if (conf->ignore_cts == WANOPT_YES){
- card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT;
- }
-
- if (conf->ignore_keepalive == WANOPT_YES) {
- card->u.c.protocol_options |=
- IGNORE_KPALV_FOR_LINK_STAT;
- card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER;
- card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER;
- card->u.c.kpalv_err = MIN_KPALV_ERR_TOL;
-
- } else { /* Do not ignore keepalives */
- card->u.c.kpalv_tx =
- ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER)
- >= 0) ?
- min_t(unsigned int, conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) :
- DEFAULT_Tx_KPALV_TIMER;
-
- card->u.c.kpalv_rx =
- ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER)
- >= 0) ?
- min_t(unsigned int, conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) :
- DEFAULT_Rx_KPALV_TIMER;
-
- card->u.c.kpalv_err =
- ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL)
- >= 0) ?
- min_t(unsigned int, conf->keepalive_err_margin,
- MAX_KPALV_ERR_TOL) :
- DEFAULT_KPALV_ERR_TOL;
- }
-
- /* Setup slarp timer to control delay between slarps */
- card->u.c.slarp_timer =
- ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ?
- min_t(unsigned int, conf->slarp_timer, MAX_SLARP_REQ_TIMER) :
- DEFAULT_SLARP_REQ_TIMER;
-
- if (conf->hdlc_streaming == WANOPT_YES) {
- printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n",
- wandev->name);
- card->u.c.protocol_options = HDLC_STREAMING_MODE;
- }
-
- if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){
- printk(KERN_INFO
- "%s: Enabling, true interface type encoding.\n",
- card->devname);
- }
-
- /* Setup wanpipe as a router (WANPIPE) or as an API */
- if( strcmp(conf->usedby, "WANPIPE") == 0) {
-
- printk(KERN_INFO "%s: Running in WANPIPE mode!\n",
- wandev->name);
- card->u.c.usedby = WANPIPE;
-
- /* Option to bring down the interface when
- * the link goes down */
- if (conf->if_down){
- set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down);
- printk(KERN_INFO
- "%s: Dynamic interface configuration enabled\n",
- card->devname);
- }
-
- } else if( strcmp(conf->usedby, "API") == 0) {
- card->u.c.usedby = API;
- printk(KERN_INFO "%s: Running in API mode !\n",
- wandev->name);
- }
- }
-
- /* Tells us that if this interface is a
- * gateway or not */
- if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){
- printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
- card->devname,card->u.c.if_name);
- }
-
- /* Get Multicast Information */
- chdlc_priv_area->mc = conf->mc;
-
- /* prepare network device data space for registration */
- strcpy(dev->name,card->u.c.if_name);
-
- dev->init = &if_init;
- dev->priv = chdlc_priv_area;
-
- /* Initialize the polling work routine */
- INIT_WORK(&chdlc_priv_area->poll_work, (void*)(void*)chdlc_poll, dev);
-
- /* Initialize the polling delay timer */
- init_timer(&chdlc_priv_area->poll_delay_timer);
- chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev;
- chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay;
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-
-/****** Network Device Interface ********************************************/
-
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration. Returning anything but zero will fail interface
- * registration.
- */
-static int if_init(struct net_device* dev)
-{
- chdlc_private_area_t* chdlc_priv_area = dev->priv;
- sdla_t* card = chdlc_priv_area->card;
- struct wan_device* wandev = &card->wandev;
-
- /* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = &if_header;
- dev->rebuild_header = &if_rebuild_hdr;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
- dev->tx_timeout = &if_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- /* Initialize media-specific parameters */
- dev->flags |= IFF_POINTOPOINT;
- dev->flags |= IFF_NOARP;
-
- /* Enable Mulitcasting if user selected */
- if (chdlc_priv_area->mc == WANOPT_YES){
- dev->flags |= IFF_MULTICAST;
- }
-
- if (chdlc_priv_area->true_if_encoding){
- dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */
- }else{
- dev->type = ARPHRD_PPP;
- }
-
- dev->mtu = card->wandev.mtu;
- /* for API usage, add the API header size to the requested MTU size */
- if(card->u.c.usedby == API) {
- dev->mtu += sizeof(api_tx_hdr_t);
- }
-
- dev->hard_header_len = CHDLC_HDR_LEN;
-
- /* Initialize hardware parameters */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
-
- /* Set transmit buffer queue length
- * If too low packets will not be retransmitted
- * by stack.
- */
- dev->tx_queue_len = 100;
- SET_MODULE_OWNER(dev);
-
- return 0;
-}
-
-/*============================================================================
- * Open network interface.
- * o enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
-static int if_open(struct net_device* dev)
-{
- chdlc_private_area_t* chdlc_priv_area = dev->priv;
- sdla_t* card = chdlc_priv_area->card;
- struct timeval tv;
- int err = 0;
-
- /* Only one open per interface is allowed */
-
- if (netif_running(dev))
- return -EBUSY;
-
- /* Initialize the work queue entry */
- chdlc_priv_area->tq_working=0;
-
- INIT_WORK(&chdlc_priv_area->common.wanpipe_work,
- (void *)(void *)chdlc_work, dev);
-
- /* Allocate and initialize BH circular buffer */
- /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */
- chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC);
- memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1)));
- atomic_set(&chdlc_priv_area->bh_buff_used, 0);
-
- do_gettimeofday(&tv);
- chdlc_priv_area->router_start_time = tv.tv_sec;
-
- netif_start_queue(dev);
-
- wanpipe_open(card);
-
- /* TTY is configured during wanpipe_set_termios
- * call, not here */
- if (card->tty_opt)
- return err;
-
- set_bit(0,&chdlc_priv_area->config_chdlc);
- chdlc_priv_area->config_chdlc_timeout=jiffies;
-
- /* Start the CHDLC configuration after 1sec delay.
- * This will give the interface initilization time
- * to finish its configuration */
- mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ);
- return err;
-}
-
-/*============================================================================
- * Close network interface.
- * o if this is the last close, then disable communications and interrupts.
- * o reset flags.
- */
-static int if_close(struct net_device* dev)
-{
- chdlc_private_area_t* chdlc_priv_area = dev->priv;
- sdla_t* card = chdlc_priv_area->card;
-
- if (chdlc_priv_area->bh_head){
- int i;
- struct sk_buff *skb;
-
- for (i=0; i<(MAX_BH_BUFF+1); i++){
- skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb;
- if (skb != NULL){
- dev_kfree_skb_any(skb);
- }
- }
- kfree(chdlc_priv_area->bh_head);
- chdlc_priv_area->bh_head=NULL;
- }
-
- netif_stop_queue(dev);
- wanpipe_close(card);
- del_timer(&chdlc_priv_area->poll_delay_timer);
- return 0;
-}
-
-static void disable_comm (sdla_t *card)
-{
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
-
- if (card->u.c.comm_enabled){
- chdlc_disable_comm_shutdown (card);
- }else{
- flags->interrupt_info_struct.interrupt_permission = 0;
- }
-
- if (!tty_init_cnt)
- return;
-
- if (card->tty_opt){
- struct serial_state * state;
- if (!(--tty_init_cnt)){
- int e1;
- serial_driver.refcount=0;
-
- if ((e1 = tty_unregister_driver(&serial_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
- e1);
- printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n",
- card->devname,WAN_TTY_MAJOR);
- }
- card->tty=NULL;
- tty_card_map[card->tty_minor]=NULL;
- state = &rs_table[card->tty_minor];
- memset(state, 0, sizeof(*state));
- }
- return;
-}
-
-
-/*============================================================================
- * Build media header.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it. If packet type is not
- * supported, set skb->protocol to 0 and discard packet later.
- *
- * Return: media header length.
- */
-static int if_header(struct sk_buff* skb, struct net_device* dev,
- unsigned short type, void* daddr, void* saddr,
- unsigned len)
-{
- skb->protocol = htons(type);
-
- return CHDLC_HDR_LEN;
-}
-
-
-/*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
-static void if_tx_timeout(struct net_device *dev)
-{
- chdlc_private_area_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
- /* If our device stays busy for at least 5 seconds then we will
- * kick start the device by making dev->tbusy = 0. We expect
- * that our device never stays busy more than 5 seconds. So this
- * is only used as a last resort.
- */
-
- ++card->wandev.stats.collisions;
-
- printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
- netif_wake_queue (dev);
-}
-
-
-
-/*============================================================================
- * Re-build media header.
- *
- * Return: 1 physical address resolved.
- * 0 physical address not resolved
- */
-static int if_rebuild_hdr (struct sk_buff *skb)
-{
- return 1;
-}
-
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- * transmit from overlapping.
- * o check link state. If link is not up, then drop the packet.
- * o execute adapter send command.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- * protocol stack and can be used for flow control with protocol layer.
- */
-static int if_send(struct sk_buff* skb, struct net_device* dev)
-{
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
- sdla_t *card = chdlc_priv_area->card;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
- int udp_type = 0;
- unsigned long smp_flags;
- int err=0;
-
- netif_stop_queue(dev);
-
- if (skb == NULL){
- /* If we get here, some higher layer thinks we've missed an
- * tx-done interrupt.
- */
- printk(KERN_INFO "%s: interface %s got kicked!\n",
- card->devname, dev->name);
-
- netif_wake_queue(dev);
- return 0;
- }
-
- if (ntohs(skb->protocol) != htons(PVC_PROT)){
-
- /* check the udp packet type */
-
- udp_type = udp_pkt_type(skb, card);
-
- if (udp_type == UDP_CPIPE_TYPE){
- if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
- chdlc_priv_area)){
- chdlc_int->interrupt_permission |=
- APP_INT_ON_TIMER;
- }
- netif_start_queue(dev);
- return 0;
- }
-
- /* check to see if the source IP address is a broadcast or */
- /* multicast IP address */
- if(chk_bcast_mcast_addr(card, dev, skb)){
- ++card->wandev.stats.tx_dropped;
- dev_kfree_skb_any(skb);
- netif_start_queue(dev);
- return 0;
- }
- }
-
- /* Lock the 508 Card: SMP is supported */
- if(card->hw.type != SDLA_S514){
- s508_lock(card,&smp_flags);
- }
-
- if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
-
- printk(KERN_INFO "%s: Critical in if_send: %lx\n",
- card->wandev.name,card->wandev.critical);
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
- goto if_send_exit_crit;
- }
-
- if(card->u.c.state != WAN_CONNECTED){
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
-
- }else if(!skb->protocol){
- ++card->wandev.stats.tx_errors;
- netif_start_queue(dev);
-
- }else {
- void* data = skb->data;
- unsigned len = skb->len;
- unsigned char attr;
-
- /* If it's an API packet pull off the API
- * header. Also check that the packet size
- * is larger than the API header
- */
- if (card->u.c.usedby == API){
- api_tx_hdr_t* api_tx_hdr;
-
- /* discard the frame if we are configured for */
- /* 'receive only' mode or if there is no data */
- if (card->u.c.receive_only ||
- (len <= sizeof(api_tx_hdr_t))) {
-
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
- goto if_send_exit_crit;
- }
-
- api_tx_hdr = (api_tx_hdr_t *)data;
- attr = api_tx_hdr->attr;
- data += sizeof(api_tx_hdr_t);
- len -= sizeof(api_tx_hdr_t);
- }
-
- if(chdlc_send(card, data, len)) {
- netif_stop_queue(dev);
- }else{
- ++card->wandev.stats.tx_packets;
- card->wandev.stats.tx_bytes += len;
-
- netif_start_queue(dev);
-
- dev->trans_start = jiffies;
- }
- }
-
-if_send_exit_crit:
-
- if (!(err=netif_queue_stopped(dev))) {
- dev_kfree_skb_any(skb);
- }else{
- chdlc_priv_area->tick_counter = jiffies;
- chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
- }
-
- clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
- if(card->hw.type != SDLA_S514){
- s508_unlock(card,&smp_flags);
- }
-
- return err;
-}
-
-
-/*============================================================================
- * Check to see if the packet to be transmitted contains a broadcast or
- * multicast source IP address.
- */
-
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
- struct sk_buff *skb)
-{
- u32 src_ip_addr;
- u32 broadcast_ip_addr = 0;
- struct in_device *in_dev;
-
- /* read the IP source address from the outgoing packet */
- src_ip_addr = *(u32 *)(skb->data + 12);
-
- /* read the IP broadcast address for the device */
- in_dev = dev->ip_ptr;
- if(in_dev != NULL) {
- struct in_ifaddr *ifa= in_dev->ifa_list;
- if(ifa != NULL)
- broadcast_ip_addr = ifa->ifa_broadcast;
- else
- return 0;
- }
-
- /* check if the IP Source Address is a Broadcast address */
- if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
- printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n",
- card->devname);
- return 1;
- }
-
- /* check if the IP Source Address is a Multicast address */
- if((ntohl(src_ip_addr) >= 0xE0000001) &&
- (ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
- printk(KERN_INFO "%s: Multicast Source Address silently discarded\n",
- card->devname);
- return 1;
- }
-
- return 0;
-}
-
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return length of reply.
- */
-static int reply_udp( unsigned char *data, unsigned int mbox_len )
-{
-
- unsigned short len, udp_length, temp, ip_length;
- unsigned long ip_temp;
- int even_bound = 0;
- chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data;
-
- /* Set length of packet */
- len = sizeof(ip_pkt_t)+
- sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- sizeof(trace_info_t)+
- mbox_len;
-
- /* fill in UDP reply */
- c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
-
- /* fill in UDP length */
- udp_length = sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- sizeof(trace_info_t)+
- mbox_len;
-
- /* put it on an even boundary */
- if ( udp_length & 0x0001 ) {
- udp_length += 1;
- len += 1;
- even_bound = 1;
- }
-
- temp = (udp_length<<8)|(udp_length>>8);
- c_udp_pkt->udp_pkt.udp_length = temp;
-
- /* swap UDP ports */
- temp = c_udp_pkt->udp_pkt.udp_src_port;
- c_udp_pkt->udp_pkt.udp_src_port =
- c_udp_pkt->udp_pkt.udp_dst_port;
- c_udp_pkt->udp_pkt.udp_dst_port = temp;
-
- /* add UDP pseudo header */
- temp = 0x1100;
- *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp;
- temp = (udp_length<<8)|(udp_length>>8);
- *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp;
-
-
- /* calculate UDP checksum */
- c_udp_pkt->udp_pkt.udp_checksum = 0;
- c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET);
-
- /* fill in IP length */
- ip_length = len;
- temp = (ip_length<<8)|(ip_length>>8);
- c_udp_pkt->ip_pkt.total_length = temp;
-
- /* swap IP addresses */
- ip_temp = c_udp_pkt->ip_pkt.ip_src_address;
- c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address;
- c_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
-
- /* fill in IP checksum */
- c_udp_pkt->ip_pkt.hdr_checksum = 0;
- c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t));
-
- return len;
-
-} /* reply_udp */
-
-unsigned short calc_checksum (char *data, int len)
-{
- unsigned short temp;
- unsigned long sum=0;
- int i;
-
- for( i = 0; i <len; i+=2 ) {
- memcpy(&temp,&data[i],2);
- sum += (unsigned long)temp;
- }
-
- while (sum >> 16 ) {
- sum = (sum & 0xffffUL) + (sum >> 16);
- }
-
- temp = (unsigned short)sum;
- temp = ~temp;
-
- if( temp == 0 )
- temp = 0xffff;
-
- return temp;
-}
-
-
-/*============================================================================
- * Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- */
-static struct net_device_stats* if_stats(struct net_device* dev)
-{
- sdla_t *my_card;
- chdlc_private_area_t* chdlc_priv_area;
-
- if ((chdlc_priv_area=dev->priv) == NULL)
- return NULL;
-
- my_card = chdlc_priv_area->card;
- return &my_card->wandev.stats;
-}
-
-
-/****** Cisco HDLC Firmware Interface Functions *******************************/
-
-/*============================================================================
- * Read firmware code version.
- * Put code version as ASCII string in str.
- */
-static int chdlc_read_version (sdla_t* card, char* str)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int len;
- char err;
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CODE_VERSION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if(err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- }
- else if (str) { /* is not null */
- len = mb->buffer_length;
- memcpy(str, mb->data, len);
- str[len] = '\0';
- }
- return (err);
-}
-
-/*-----------------------------------------------------------------------------
- * Configure CHDLC firmware.
- */
-static int chdlc_configure (sdla_t* card, void* data)
-{
- int err;
- CHDLC_MAILBOX_STRUCT *mailbox = card->mbox;
- int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT);
-
- mailbox->buffer_length = data_length;
- memcpy(mailbox->data, data, data_length);
- mailbox->command = SET_CHDLC_CONFIGURATION;
- err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT;
-
- if (err != COMMAND_OK) chdlc_error (card, err, mailbox);
-
- return err;
-}
-
-
-/*============================================================================
- * Set interrupt mode -- HDLC Version.
- */
-
-static int chdlc_set_intr_mode (sdla_t* card, unsigned mode)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- CHDLC_INT_TRIGGERS_STRUCT* int_data =
- (CHDLC_INT_TRIGGERS_STRUCT *)mb->data;
- int err;
-
- int_data->CHDLC_interrupt_triggers = mode;
- int_data->IRQ = card->hw.irq;
- int_data->interrupt_timer = 1;
-
- mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT);
- mb->command = SET_CHDLC_INTERRUPT_TRIGGERS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error (card, err, mb);
- return err;
-}
-
-
-/*===========================================================
- * chdlc_disable_comm_shutdown
- *
- * Shutdown() disables the communications. We must
- * have a sparate functions, because we must not
- * call chdlc_error() hander since the private
- * area has already been replaced */
-
-static int chdlc_disable_comm_shutdown (sdla_t *card)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- CHDLC_INT_TRIGGERS_STRUCT* int_data =
- (CHDLC_INT_TRIGGERS_STRUCT *)mb->data;
- int err;
-
- /* Disable Interrutps */
- int_data->CHDLC_interrupt_triggers = 0;
- int_data->IRQ = card->hw.irq;
- int_data->interrupt_timer = 1;
-
- mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT);
- mb->command = SET_CHDLC_INTERRUPT_TRIGGERS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- /* Disable Communications */
-
- if (card->u.c.async_mode) {
- mb->command = DISABLE_ASY_COMMUNICATIONS;
- }else{
- mb->command = DISABLE_CHDLC_COMMUNICATIONS;
- }
-
- mb->buffer_length = 0;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- card->u.c.comm_enabled = 0;
-
- return 0;
-}
-
-/*============================================================================
- * Enable communications.
- */
-
-static int chdlc_comm_enable (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = ENABLE_CHDLC_COMMUNICATIONS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card, err, mb);
- else
- card->u.c.comm_enabled = 1;
-
- return err;
-}
-
-/*============================================================================
- * Read communication error statistics.
- */
-static int chdlc_read_comm_err_stats (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = READ_COMMS_ERROR_STATS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card,err,mb);
- return err;
-}
-
-
-/*============================================================================
- * Read CHDLC operational statistics.
- */
-static int chdlc_read_op_stats (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_OPERATIONAL_STATS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card,err,mb);
- return err;
-}
-
-
-/*============================================================================
- * Update communications error and general packet statistics.
- */
-static int update_comms_stats(sdla_t* card,
- chdlc_private_area_t* chdlc_priv_area)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- COMMS_ERROR_STATS_STRUCT* err_stats;
- CHDLC_OPERATIONAL_STATS_STRUCT *op_stats;
-
- /* on the first timer interrupt, read the comms error statistics */
- if(chdlc_priv_area->update_comms_stats == 2) {
- if(chdlc_read_comm_err_stats(card))
- return 1;
- err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data;
- card->wandev.stats.rx_over_errors =
- err_stats->Rx_overrun_err_count;
- card->wandev.stats.rx_crc_errors =
- err_stats->CRC_err_count;
- card->wandev.stats.rx_frame_errors =
- err_stats->Rx_abort_count;
- card->wandev.stats.rx_fifo_errors =
- err_stats->Rx_dis_pri_bfrs_full_count;
- card->wandev.stats.rx_missed_errors =
- card->wandev.stats.rx_fifo_errors;
- card->wandev.stats.tx_aborted_errors =
- err_stats->sec_Tx_abort_count;
- }
-
- /* on the second timer interrupt, read the operational statistics */
- else {
- if(chdlc_read_op_stats(card))
- return 1;
- op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data;
- card->wandev.stats.rx_length_errors =
- (op_stats->Rx_Data_discard_short_count +
- op_stats->Rx_Data_discard_long_count);
- }
-
- return 0;
-}
-
-/*============================================================================
- * Send packet.
- * Return: 0 - o.k.
- * 1 - no transmit buffers available
- */
-static int chdlc_send (sdla_t* card, void* data, unsigned len)
-{
- CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf;
-
- if (txbuf->opp_flag)
- return 1;
-
- sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len);
-
- txbuf->frame_length = len;
- txbuf->opp_flag = 1; /* start transmission */
-
- /* Update transmit buffer control fields */
- card->u.c.txbuf = ++txbuf;
-
- if ((void*)txbuf > card->u.c.txbuf_last)
- card->u.c.txbuf = card->u.c.txbuf_base;
-
- return 0;
-}
-
-/****** Firmware Error Handler **********************************************/
-
-/*============================================================================
- * Firmware error handler.
- * This routine is called whenever firmware command returns non-zero
- * return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb)
-{
- unsigned cmd = mb->command;
-
- switch (err) {
-
- case CMD_TIMEOUT:
- printk(KERN_INFO "%s: command 0x%02X timed out!\n",
- card->devname, cmd);
- break;
-
- case S514_BOTH_PORTS_SAME_CLK_MODE:
- if(cmd == SET_CHDLC_CONFIGURATION) {
- printk(KERN_INFO
- "%s: Configure both ports for the same clock source\n",
- card->devname);
- break;
- }
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, cmd, err);
- }
-
- return 0;
-}
-
-
-/********** Bottom Half Handlers ********************************************/
-
-/* NOTE: There is no API, BH support for Kernels lower than 2.2.X.
- * DO NOT INSERT ANY CODE HERE, NOTICE THE
- * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE
- * DOING */
-
-static void chdlc_work(struct net_device * dev)
-{
- chdlc_private_area_t* chan = dev->priv;
- sdla_t *card = chan->card;
- struct sk_buff *skb;
-
- if (atomic_read(&chan->bh_buff_used) == 0){
- clear_bit(0, &chan->tq_working);
- return;
- }
-
- while (atomic_read(&chan->bh_buff_used)){
-
- skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
-
- if (skb != NULL){
-
- if (chan->common.sk == NULL || chan->common.func == NULL){
- ++card->wandev.stats.rx_dropped;
- dev_kfree_skb_any(skb);
- chdlc_work_cleanup(dev);
- continue;
- }
-
- if (chan->common.func(skb,dev,chan->common.sk) != 0){
- /* Sock full cannot send, queue us for another
- * try */
- atomic_set(&chan->common.receive_block,1);
- return;
- }else{
- chdlc_work_cleanup(dev);
- }
- }else{
- chdlc_work_cleanup(dev);
- }
- }
- clear_bit(0, &chan->tq_working);
-
- return;
-}
-
-static int chdlc_work_cleanup(struct net_device *dev)
-{
- chdlc_private_area_t* chan = dev->priv;
-
- ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
-
- if (chan->bh_read == MAX_BH_BUFF){
- chan->bh_read=0;
- }else{
- ++chan->bh_read;
- }
-
- atomic_dec(&chan->bh_buff_used);
- return 0;
-}
-
-
-
-static int bh_enqueue(struct net_device *dev, struct sk_buff *skb)
-{
- /* Check for full */
- chdlc_private_area_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
- if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){
- ++card->wandev.stats.rx_dropped;
- dev_kfree_skb_any(skb);
- return 1;
- }
-
- ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
-
- if (chan->bh_write == MAX_BH_BUFF){
- chan->bh_write=0;
- }else{
- ++chan->bh_write;
- }
-
- atomic_inc(&chan->bh_buff_used);
-
- return 0;
-}
-
-/* END OF API BH Support */
-
-
-/****** Interrupt Handlers **************************************************/
-
-/*============================================================================
- * Cisco HDLC interrupt service routine.
- */
-static void wpc_isr (sdla_t* card)
-{
- struct net_device* dev;
- SHARED_MEMORY_INFO_STRUCT* flags = NULL;
- int i;
- sdla_t *my_card;
-
-
- /* Check for which port the interrupt has been generated
- * Since Secondary Port is piggybacking on the Primary
- * the check must be done here.
- */
-
- flags = card->u.c.flags;
- if (!flags->interrupt_info_struct.interrupt_type){
- /* Check for a second port (piggybacking) */
- if ((my_card = card->next)){
- flags = my_card->u.c.flags;
- if (flags->interrupt_info_struct.interrupt_type){
- card = my_card;
- card->isr(card);
- return;
- }
- }
- }
-
- flags = card->u.c.flags;
- card->in_isr = 1;
- dev = card->wandev.dev;
-
- /* If we get an interrupt with no network device, stop the interrupts
- * and issue an error */
- if (!card->tty_opt && !dev &&
- flags->interrupt_info_struct.interrupt_type !=
- COMMAND_COMPLETE_APP_INT_PEND){
-
- goto isr_done;
- }
-
- /* if critical due to peripheral operations
- * ie. update() or getstats() then reset the interrupt and
- * wait for the board to retrigger.
- */
- if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
- printk(KERN_INFO "ISR CRIT TO PERI\n");
- goto isr_done;
- }
-
- /* On a 508 Card, if critical due to if_send
- * Major Error !!! */
- if(card->hw.type != SDLA_S514) {
- if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
- printk(KERN_INFO "%s: Critical while in ISR: %lx\n",
- card->devname, card->wandev.critical);
- card->in_isr = 0;
- flags->interrupt_info_struct.interrupt_type = 0;
- return;
- }
- }
-
- switch(flags->interrupt_info_struct.interrupt_type) {
-
- case RX_APP_INT_PEND: /* 0x01: receive interrupt */
- rx_intr(card);
- break;
-
- case TX_APP_INT_PEND: /* 0x02: transmit interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TX_FRAME;
-
- if (card->tty_opt){
- wanpipe_tty_trigger_poll(card);
- break;
- }
-
- if (dev && netif_queue_stopped(dev)){
- if (card->u.c.usedby == API){
- netif_start_queue(dev);
- wakeup_sk_bh(dev);
- }else{
- netif_wake_queue(dev);
- }
- }
- break;
-
- case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
- ++ Intr_test_counter;
- break;
-
- case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */
- process_chdlc_exception(card);
- break;
-
- case GLOBAL_EXCEP_COND_APP_INT_PEND:
- process_global_exception(card);
- break;
-
- case TIMER_APP_INT_PEND:
- timer_intr(card);
- break;
-
- default:
- printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
- card->devname,
- flags->interrupt_info_struct.interrupt_type);
- printk(KERN_INFO "Code name: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codename[i]);
- printk(KERN_INFO "\nCode version: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codeversion[i]);
- printk(KERN_INFO "\n");
- break;
- }
-
-isr_done:
-
- card->in_isr = 0;
- flags->interrupt_info_struct.interrupt_type = 0;
- return;
-}
-
-/*============================================================================
- * Receive interrupt handler.
- */
-static void rx_intr (sdla_t* card)
-{
- struct net_device *dev;
- chdlc_private_area_t *chdlc_priv_area;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb;
- struct sk_buff *skb;
- unsigned len;
- unsigned addr = rxbuf->ptr_data_bfr;
- void *buf;
- int i,udp_type;
-
- if (rxbuf->opp_flag != 0x01) {
- printk(KERN_INFO
- "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
- card->devname, (unsigned)rxbuf, rxbuf->opp_flag);
- printk(KERN_INFO "Code name: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codename[i]);
- printk(KERN_INFO "\nCode version: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codeversion[i]);
- printk(KERN_INFO "\n");
-
-
- /* Bug Fix: Mar 6 2000
- * If we get a corrupted mailbox, it measn that driver
- * is out of sync with the firmware. There is no recovery.
- * If we don't turn off all interrupts for this card
- * the machine will crash.
- */
- printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
- printk(KERN_INFO "Please contact Sangoma Technologies !\n");
- chdlc_set_intr_mode(card,0);
- return;
- }
-
- len = rxbuf->frame_length;
-
- if (card->tty_opt){
-
- if (rxbuf->error_flag){
- goto rx_exit;
- }
-
- if (len <= CRC_LENGTH){
- goto rx_exit;
- }
-
- if (!card->u.c.async_mode){
- len -= CRC_LENGTH;
- }
-
- wanpipe_tty_receive(card,addr,len);
- goto rx_exit;
- }
-
- dev = card->wandev.dev;
-
- if (!dev){
- goto rx_exit;
- }
-
- if (!netif_running(dev))
- goto rx_exit;
-
- chdlc_priv_area = dev->priv;
-
-
- /* Allocate socket buffer */
- skb = dev_alloc_skb(len);
-
- if (skb == NULL) {
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- ++card->wandev.stats.rx_dropped;
- goto rx_exit;
- }
-
- /* Copy data to the socket buffer */
- if((addr + len) > card->u.c.rx_top + 1) {
- unsigned tmp = card->u.c.rx_top - addr + 1;
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, addr, buf, tmp);
- addr = card->u.c.rx_base;
- len -= tmp;
- }
-
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, addr, buf, len);
-
- skb->protocol = htons(ETH_P_IP);
-
- card->wandev.stats.rx_packets ++;
- card->wandev.stats.rx_bytes += skb->len;
- udp_type = udp_pkt_type( skb, card );
-
- if(udp_type == UDP_CPIPE_TYPE) {
- if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK,
- card, skb, dev, chdlc_priv_area)) {
- flags->interrupt_info_struct.
- interrupt_permission |=
- APP_INT_ON_TIMER;
- }
- } else if(card->u.c.usedby == API) {
-
- api_rx_hdr_t* api_rx_hdr;
- skb_push(skb, sizeof(api_rx_hdr_t));
- api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
- api_rx_hdr->error_flag = rxbuf->error_flag;
- api_rx_hdr->time_stamp = rxbuf->time_stamp;
-
- skb->protocol = htons(PVC_PROT);
- skb->mac.raw = skb->data;
- skb->dev = dev;
- skb->pkt_type = WAN_PACKET_DATA;
-
- bh_enqueue(dev, skb);
-
- if (!test_and_set_bit(0,&chdlc_priv_area->tq_working))
- wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work);
- }else{
- /* FIXME: we should check to see if the received packet is a
- multicast packet so that we can increment the multicast
- statistic
- ++ chdlc_priv_area->if_stats.multicast;
- */
- /* Pass it up the protocol stack */
-
- skb->dev = dev;
- skb->mac.raw = skb->data;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
-
-rx_exit:
- /* Release buffer element and calculate a pointer to the next one */
- rxbuf->opp_flag = 0x00;
- card->u.c.rxmb = ++ rxbuf;
- if((void*)rxbuf > card->u.c.rxbuf_last){
- card->u.c.rxmb = card->u.c.rxbuf_base;
- }
-}
-
-/*============================================================================
- * Timer interrupt handler.
- * The timer interrupt is used for two purposes:
- * 1) Processing udp calls from 'cpipemon'.
- * 2) Reading board-level statistics for updating the proc file system.
- */
-void timer_intr(sdla_t *card)
-{
- struct net_device* dev;
- chdlc_private_area_t* chdlc_priv_area = NULL;
- SHARED_MEMORY_INFO_STRUCT* flags = NULL;
-
- if ((dev = card->wandev.dev)==NULL){
- flags = card->u.c.flags;
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TIMER;
- return;
- }
-
- chdlc_priv_area = dev->priv;
-
- if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) {
- if (!config_chdlc(card)){
- chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
- }
- }
-
- /* process a udp call if pending */
- if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) {
- process_udp_mgmt_pkt(card, dev,
- chdlc_priv_area);
- chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
- }
-
- /* read the communications statistics if required */
- if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
- update_comms_stats(card, chdlc_priv_area);
- if(!(-- chdlc_priv_area->update_comms_stats)) {
- chdlc_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_UPDATE;
- }
- }
-
- /* only disable the timer interrupt if there are no udp or statistic */
- /* updates pending */
- if(!chdlc_priv_area->timer_int_enabled) {
- flags = card->u.c.flags;
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TIMER;
- }
-}
-
-/*------------------------------------------------------------------------------
- Miscellaneous Functions
- - set_chdlc_config() used to set configuration options on the board
-------------------------------------------------------------------------------*/
-
-static int set_chdlc_config(sdla_t* card)
-{
- CHDLC_CONFIGURATION_STRUCT cfg;
-
- memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT));
-
- if(card->wandev.clocking){
- cfg.baud_rate = card->wandev.bps;
- }
-
- cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
- INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
-
- cfg.modem_config_options = 0;
- cfg.modem_status_timer = 100;
-
- cfg.CHDLC_protocol_options = card->u.c.protocol_options;
-
- if (card->tty_opt){
- cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES;
- }
-
- cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50;
- cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT |
- CHDLC_RX_DATA_BYTE_COUNT_STAT);
-
- if (card->tty_opt){
- card->wandev.mtu = TTY_CHDLC_MAX_MTU;
- }
- cfg.max_CHDLC_data_field_length = card->wandev.mtu;
- cfg.transmit_keepalive_timer = card->u.c.kpalv_tx;
- cfg.receive_keepalive_timer = card->u.c.kpalv_rx;
- cfg.keepalive_error_tolerance = card->u.c.kpalv_err;
- cfg.SLARP_request_timer = card->u.c.slarp_timer;
-
- if (cfg.SLARP_request_timer) {
- cfg.IP_address = 0;
- cfg.IP_netmask = 0;
-
- }else if (card->wandev.dev){
- struct net_device *dev = card->wandev.dev;
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
-
- struct in_device *in_dev = dev->ip_ptr;
-
- if(in_dev != NULL) {
- struct in_ifaddr *ifa = in_dev->ifa_list;
-
- if (ifa != NULL ) {
- cfg.IP_address = ntohl(ifa->ifa_local);
- cfg.IP_netmask = ntohl(ifa->ifa_mask);
- chdlc_priv_area->IP_address = ntohl(ifa->ifa_local);
- chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask);
- }
- }
-
- /* FIXME: We must re-think this message in next release
- if((cfg.IP_address & 0x000000FF) > 2) {
- printk(KERN_WARNING "\n");
- printk(KERN_WARNING " WARNING:%s configured with an\n",
- card->devname);
- printk(KERN_WARNING " invalid local IP address.\n");
- printk(KERN_WARNING " Slarp pragmatics will fail.\n");
- printk(KERN_WARNING " IP address should be of the\n");
- printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n");
- }
- */
- }
-
- return chdlc_configure(card, &cfg);
-}
-
-
-/*-----------------------------------------------------------------------------
- set_asy_config() used to set asynchronous configuration options on the board
-------------------------------------------------------------------------------*/
-
-static int set_asy_config(sdla_t* card)
-{
-
- ASY_CONFIGURATION_STRUCT cfg;
- CHDLC_MAILBOX_STRUCT *mailbox = card->mbox;
- int err;
-
- memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT));
-
- if(card->wandev.clocking)
- cfg.baud_rate = card->wandev.bps;
-
- cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
- INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
-
- cfg.modem_config_options = 0;
- cfg.asy_API_options = card->u.c.api_options;
- cfg.asy_protocol_options = card->u.c.protocol_options;
- cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char;
- cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char;
- cfg.stop_bits = card->u.c.stop_bits;
- cfg.parity = card->u.c.parity;
- cfg.break_timer = card->u.c.break_timer;
- cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer;
- cfg.asy_Rx_complete_length = card->u.c.rx_complete_length;
- cfg.XON_char = card->u.c.xon_char;
- cfg.XOFF_char = card->u.c.xoff_char;
- cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT |
- CHDLC_RX_DATA_BYTE_COUNT_STAT);
-
- mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT);
- memcpy(mailbox->data, &cfg, mailbox->buffer_length);
- mailbox->command = SET_ASY_CONFIGURATION;
- err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error (card, err, mailbox);
- return err;
-}
-
-/*============================================================================
- * Enable asynchronous communications.
- */
-
-static int asy_comm_enable (sdla_t* card)
-{
-
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = ENABLE_ASY_COMMUNICATIONS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK && card->wandev.dev)
- chdlc_error(card, err, mb);
-
- if (!err)
- card->u.c.comm_enabled = 1;
-
- return err;
-}
-
-/*============================================================================
- * Process global exception condition
- */
-static int process_global_exception(sdla_t *card)
-{
- CHDLC_MAILBOX_STRUCT* mbox = card->mbox;
- int err;
-
- mbox->buffer_length = 0;
- mbox->command = READ_GLOBAL_EXCEPTION_CONDITION;
- err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT;
-
- if(err != CMD_TIMEOUT ){
-
- switch(mbox->return_code) {
-
- case EXCEP_MODEM_STATUS_CHANGE:
-
- printk(KERN_INFO "%s: Modem status change\n",
- card->devname);
-
- switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) {
- case (DCD_HIGH):
- printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname);
- break;
- case (CTS_HIGH):
- printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname);
- break;
- case ((DCD_HIGH | CTS_HIGH)):
- printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname);
- break;
- default:
- printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname);
- break;
- }
- break;
-
- case EXCEP_TRC_DISABLED:
- printk(KERN_INFO "%s: Line trace disabled\n",
- card->devname);
- break;
-
- case EXCEP_IRQ_TIMEOUT:
- printk(KERN_INFO "%s: IRQ timeout occurred\n",
- card->devname);
- break;
-
- case 0x17:
- if (card->tty_opt){
- if (card->tty && card->tty_open){
- printk(KERN_INFO
- "%s: Modem Hangup Exception: Hanging Up!\n",
- card->devname);
- tty_hangup(card->tty);
- }
- break;
- }
-
- /* If TTY is not used just drop throught */
-
- default:
- printk(KERN_INFO "%s: Global exception %x\n",
- card->devname, mbox->return_code);
- break;
- }
- }
- return 0;
-}
-
-
-/*============================================================================
- * Process chdlc exception condition
- */
-static int process_chdlc_exception(sdla_t *card)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int err;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_EXCEPTION_CONDITION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if(err != CMD_TIMEOUT) {
-
- switch (err) {
-
- case EXCEP_LINK_ACTIVE:
- port_set_state(card, WAN_CONNECTED);
- trigger_chdlc_poll(card->wandev.dev);
- break;
-
- case EXCEP_LINK_INACTIVE_MODEM:
- port_set_state(card, WAN_DISCONNECTED);
- unconfigure_ip(card);
- trigger_chdlc_poll(card->wandev.dev);
- break;
-
- case EXCEP_LINK_INACTIVE_KPALV:
- port_set_state(card, WAN_DISCONNECTED);
- printk(KERN_INFO "%s: Keepalive timer expired.\n",
- card->devname);
- unconfigure_ip(card);
- trigger_chdlc_poll(card->wandev.dev);
- break;
-
- case EXCEP_IP_ADDRESS_DISCOVERED:
- if (configure_ip(card))
- return -1;
- break;
-
- case EXCEP_LOOPBACK_CONDITION:
- printk(KERN_INFO "%s: Loopback Condition Detected.\n",
- card->devname);
- break;
-
- case NO_CHDLC_EXCEP_COND_TO_REPORT:
- printk(KERN_INFO "%s: No exceptions reported.\n",
- card->devname);
- break;
- }
-
- }
- return 0;
-}
-
-
-/*============================================================================
- * Configure IP from SLARP negotiation
- * This adds dynamic routes when SLARP has provided valid addresses
- */
-
-static int configure_ip (sdla_t* card)
-{
- struct net_device *dev = card->wandev.dev;
- chdlc_private_area_t *chdlc_priv_area;
- char err;
-
- if (!dev)
- return 0;
-
- chdlc_priv_area = dev->priv;
-
-
- /* set to discover */
- if(card->u.c.slarp_timer != 0x00) {
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- CHDLC_CONFIGURATION_STRUCT *cfg;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CONFIGURATION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if(err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- return -1;
- }
-
- cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data;
- chdlc_priv_area->IP_address = cfg->IP_address;
- chdlc_priv_area->IP_netmask = cfg->IP_netmask;
-
- /* Set flag to add route */
- chdlc_priv_area->route_status = ADD_ROUTE;
-
- /* The idea here is to add the route in the poll routine.
- This way, we aren't in interrupt context when adding routes */
- trigger_chdlc_poll(dev);
- }
-
- return 0;
-}
-
-
-/*============================================================================
- * Un-Configure IP negotiated by SLARP
- * This removes dynamic routes when the link becomes inactive.
- */
-
-static int unconfigure_ip (sdla_t* card)
-{
- struct net_device *dev = card->wandev.dev;
- chdlc_private_area_t *chdlc_priv_area;
-
- if (!dev)
- return 0;
-
- chdlc_priv_area= dev->priv;
-
- if (chdlc_priv_area->route_status == ROUTE_ADDED) {
-
- /* Note: If this function is called, the
- * port state has been DISCONNECTED. This state
- * change will trigger a poll_disconnected
- * function, that will check for this condition.
- */
- chdlc_priv_area->route_status = REMOVE_ROUTE;
-
- }
- return 0;
-}
-
-/*============================================================================
- * Routine to add/remove routes
- * Called like a polling routine when Routes are flagged to be added/removed.
- */
-
-static void process_route (sdla_t *card)
-{
- struct net_device *dev = card->wandev.dev;
- unsigned char port_num;
- chdlc_private_area_t *chdlc_priv_area = NULL;
- u32 local_IP_addr = 0;
- u32 remote_IP_addr = 0;
- u32 IP_netmask, IP_addr;
- int err = 0;
- struct in_device *in_dev;
- mm_segment_t fs;
- struct ifreq if_info;
- struct sockaddr_in *if_data1, *if_data2;
-
- chdlc_priv_area = dev->priv;
- port_num = card->u.c.comm_port;
-
- /* Bug Fix Mar 16 2000
- * AND the IP address to the Mask before checking
- * the last two bits. */
-
- if((chdlc_priv_area->route_status == ADD_ROUTE) &&
- ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) {
-
- printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname);
-
- if(card->u.c.slarp_timer) {
- u32 addr_net = htonl(chdlc_priv_area->IP_address);
-
- printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n",
- card->devname,
- NIPQUAD(addr_net));
- printk(KERN_INFO "%s: from remote station.\n",
- card->devname);
-
- }else{
- u32 addr_net = htonl(chdlc_priv_area->IP_address);
-
- printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n",
- card->devname,
- NIPQUAD(addr_net));
- printk(KERN_INFO "%s: to remote station. Local\n",
- card->devname);
- printk(KERN_INFO "%s: IP address must be A.B.C.1\n",
- card->devname);
- printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname);
- }
-
- /* remove the route due to the IP address error condition */
- chdlc_priv_area->route_status = REMOVE_ROUTE;
- err = 1;
- }
-
- /* If we are removing a route with bad IP addressing, then use the */
- /* locally configured IP addresses */
- if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) {
-
- /* do not remove a bad route that has already been removed */
- if(chdlc_priv_area->route_removed) {
- return;
- }
-
- in_dev = dev->ip_ptr;
-
- if(in_dev != NULL) {
- struct in_ifaddr *ifa = in_dev->ifa_list;
- if (ifa != NULL ) {
- local_IP_addr = ifa->ifa_local;
- IP_netmask = ifa->ifa_mask;
- }
- }
- }else{
- /* According to Cisco HDLC, if the point-to-point address is
- A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa.
- */
- IP_netmask = ntohl(chdlc_priv_area->IP_netmask);
- remote_IP_addr = ntohl(chdlc_priv_area->IP_address);
-
-
- /* If Netmask is 255.255.255.255 the local address
- * calculation will fail. Default it back to 255.255.255.0 */
- if (IP_netmask == 0xffffffff)
- IP_netmask &= 0x00ffffff;
-
- /* Bug Fix Mar 16 2000
- * AND the Remote IP address with IP netmask, instead
- * of static netmask of 255.255.255.0 */
- local_IP_addr = (remote_IP_addr & IP_netmask) +
- (~remote_IP_addr & ntohl(0x0003));
-
- if(!card->u.c.slarp_timer) {
- IP_addr = local_IP_addr;
- local_IP_addr = remote_IP_addr;
- remote_IP_addr = IP_addr;
- }
- }
-
- fs = get_fs(); /* Save file system */
- set_fs(get_ds()); /* Get user space block */
-
- /* Setup a structure for adding/removing routes */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
-
- switch (chdlc_priv_area->route_status) {
-
- case ADD_ROUTE:
-
- if(!card->u.c.slarp_timer) {
- if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data2->sin_addr.s_addr = remote_IP_addr;
- if_data2->sin_family = AF_INET;
- err = devinet_ioctl(SIOCSIFDSTADDR, &if_info);
- } else {
- if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
- if_data1->sin_addr.s_addr = local_IP_addr;
- if_data1->sin_family = AF_INET;
- if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){
- if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data2->sin_addr.s_addr = remote_IP_addr;
- if_data2->sin_family = AF_INET;
- err = devinet_ioctl(SIOCSIFDSTADDR, &if_info);
- }
- }
-
- if(err) {
- printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n",
- card->devname, NIPQUAD(remote_IP_addr), err);
- } else {
- ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED;
- printk(KERN_INFO "%s: Dynamic route added.\n",
- card->devname);
- printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n",
- card->devname, NIPQUAD(local_IP_addr));
- printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n",
- card->devname, NIPQUAD(remote_IP_addr));
- chdlc_priv_area->route_removed = 0;
- }
- break;
-
-
- case REMOVE_ROUTE:
-
- /* Change the local ip address of the interface to 0.
- * This will also delete the destination route.
- */
- if(!card->u.c.slarp_timer) {
- if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data2->sin_addr.s_addr = 0;
- if_data2->sin_family = AF_INET;
- err = devinet_ioctl(SIOCSIFDSTADDR, &if_info);
- } else {
- if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
- if_data1->sin_addr.s_addr = 0;
- if_data1->sin_family = AF_INET;
- err = devinet_ioctl(SIOCSIFADDR,&if_info);
-
- }
- if(err) {
- printk(KERN_INFO
- "%s: Remove route %u.%u.%u.%u failed, (err %d)\n",
- card->devname, NIPQUAD(remote_IP_addr),
- err);
- } else {
- ((chdlc_private_area_t *)dev->priv)->route_status =
- NO_ROUTE;
- printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n",
- card->devname, NIPQUAD(local_IP_addr));
- chdlc_priv_area->route_removed = 1;
- }
- break;
- }
-
- set_fs(fs); /* Restore file system */
-
-}
-
-
-/*=============================================================================
- * Store a UDP management packet for later processing.
- */
-
-static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area)
-{
- int udp_pkt_stored = 0;
-
- if(!chdlc_priv_area->udp_pkt_lgth &&
- (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) {
- chdlc_priv_area->udp_pkt_lgth = skb->len;
- chdlc_priv_area->udp_pkt_src = udp_pkt_src;
- memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len);
- chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP;
- udp_pkt_stored = 1;
- }
-
- if(udp_pkt_src == UDP_PKT_FRM_STACK){
- dev_kfree_skb_any(skb);
- }else{
- dev_kfree_skb_any(skb);
- }
-
- return(udp_pkt_stored);
-}
-
-
-/*=============================================================================
- * Process UDP management packet.
- */
-
-static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area )
-{
- unsigned char *buf;
- unsigned int frames, len;
- struct sk_buff *new_skb;
- unsigned short buffer_length, real_len;
- unsigned long data_ptr;
- unsigned data_length;
- int udp_mgmt_req_valid = 1;
- CHDLC_MAILBOX_STRUCT *mb = card->mbox;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- chdlc_udp_pkt_t *chdlc_udp_pkt;
- struct timeval tv;
- int err;
- char ut_char;
-
- chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data;
-
- if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){
-
- /* Only these commands are support for remote debugging.
- * All others are not */
- switch(chdlc_udp_pkt->cblock.command) {
-
- case READ_GLOBAL_STATISTICS:
- case READ_MODEM_STATUS:
- case READ_CHDLC_LINK_STATUS:
- case CPIPE_ROUTER_UP_TIME:
- case READ_COMMS_ERROR_STATS:
- case READ_CHDLC_OPERATIONAL_STATS:
-
- /* These two commands are executed for
- * each request */
- case READ_CHDLC_CONFIGURATION:
- case READ_CHDLC_CODE_VERSION:
- udp_mgmt_req_valid = 1;
- break;
- default:
- udp_mgmt_req_valid = 0;
- break;
- }
- }
-
- if(!udp_mgmt_req_valid) {
-
- /* set length to 0 */
- chdlc_udp_pkt->cblock.buffer_length = 0;
-
- /* set return code */
- chdlc_udp_pkt->cblock.return_code = 0xCD;
-
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Warning, Illegal UDP command attempted from network: %x\n",
- card->devname,chdlc_udp_pkt->cblock.command);
- }
-
- } else {
- unsigned long trace_status_cfg_addr = 0;
- TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct;
- TRACE_STATUS_ELEMENT_STRUCT trace_element_struct;
-
- switch(chdlc_udp_pkt->cblock.command) {
-
- case CPIPE_ENABLE_TRACING:
- if (!chdlc_priv_area->TracingEnabled) {
-
- /* OPERATE_DATALINE_MONITOR */
-
- mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
- mb->command = SET_TRACE_CONFIGURATION;
-
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
- trace_config = TRACE_ACTIVE;
- /* Trace delay mode is not used because it slows
- down transfer and results in a standoff situation
- when there is a lot of data */
-
- /* Configure the Trace based on user inputs */
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |=
- chdlc_udp_pkt->data[0];
-
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
- trace_deactivation_timer = 4000;
-
-
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- card->TracingEnabled = 0;
- chdlc_udp_pkt->cblock.return_code = err;
- mb->buffer_length = 0;
- break;
- }
-
- /* Get the base address of the trace element list */
- mb->buffer_length = 0;
- mb->command = READ_TRACE_CONFIGURATION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if (err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- chdlc_priv_area->TracingEnabled = 0;
- chdlc_udp_pkt->cblock.return_code = err;
- mb->buffer_length = 0;
- break;
- }
-
- trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *)
- mb->data) -> ptr_trace_stat_el_cfg_struct;
-
- sdla_peek(&card->hw, trace_status_cfg_addr,
- &trace_cfg_struct, sizeof(trace_cfg_struct));
-
- chdlc_priv_area->start_trace_addr = trace_cfg_struct.
- base_addr_trace_status_elements;
-
- chdlc_priv_area->number_trace_elements =
- trace_cfg_struct.number_trace_status_elements;
-
- chdlc_priv_area->end_trace_addr = (unsigned long)
- ((TRACE_STATUS_ELEMENT_STRUCT *)
- chdlc_priv_area->start_trace_addr +
- (chdlc_priv_area->number_trace_elements - 1));
-
- chdlc_priv_area->base_addr_trace_buffer =
- trace_cfg_struct.base_addr_trace_buffer;
-
- chdlc_priv_area->end_addr_trace_buffer =
- trace_cfg_struct.end_addr_trace_buffer;
-
- chdlc_priv_area->curr_trace_addr =
- trace_cfg_struct.next_trace_element_to_use;
-
- chdlc_priv_area->available_buffer_space = 2000 -
- sizeof(ip_pkt_t) -
- sizeof(udp_pkt_t) -
- sizeof(wp_mgmt_t) -
- sizeof(cblock_t) -
- sizeof(trace_info_t);
- }
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- mb->buffer_length = 0;
- chdlc_priv_area->TracingEnabled = 1;
- break;
-
-
- case CPIPE_DISABLE_TRACING:
- if (chdlc_priv_area->TracingEnabled) {
-
- /* OPERATE_DATALINE_MONITOR */
- mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
- mb->command = SET_TRACE_CONFIGURATION;
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
- trace_config = TRACE_INACTIVE;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- }
-
- chdlc_priv_area->TracingEnabled = 0;
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- mb->buffer_length = 0;
- break;
-
-
- case CPIPE_GET_TRACE_INFO:
-
- if (!chdlc_priv_area->TracingEnabled) {
- chdlc_udp_pkt->cblock.return_code = 1;
- mb->buffer_length = 0;
- break;
- }
-
- chdlc_udp_pkt->trace_info.ismoredata = 0x00;
- buffer_length = 0; /* offset of packet already occupied */
-
- for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){
-
- trace_pkt_t *trace_pkt = (trace_pkt_t *)
- &chdlc_udp_pkt->data[buffer_length];
-
- sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr,
- (unsigned char *)&trace_element_struct,
- sizeof(TRACE_STATUS_ELEMENT_STRUCT));
-
- if (trace_element_struct.opp_flag == 0x00) {
- break;
- }
-
- /* get pointer to real data */
- data_ptr = trace_element_struct.ptr_data_bfr;
-
- /* See if there is actual data on the trace buffer */
- if (data_ptr){
- data_length = trace_element_struct.trace_length;
- }else{
- data_length = 0;
- chdlc_udp_pkt->trace_info.ismoredata = 0x01;
- }
-
- if( (chdlc_priv_area->available_buffer_space - buffer_length)
- < ( sizeof(trace_pkt_t) + data_length) ) {
-
- /* indicate there are more frames on board & exit */
- chdlc_udp_pkt->trace_info.ismoredata = 0x01;
- break;
- }
-
- trace_pkt->status = trace_element_struct.trace_type;
-
- trace_pkt->time_stamp =
- trace_element_struct.trace_time_stamp;
-
- trace_pkt->real_length =
- trace_element_struct.trace_length;
-
- /* see if we can fit the frame into the user buffer */
- real_len = trace_pkt->real_length;
-
- if (data_ptr == 0) {
- trace_pkt->data_avail = 0x00;
- } else {
- unsigned tmp = 0;
-
- /* get the data from circular buffer
- must check for end of buffer */
- trace_pkt->data_avail = 0x01;
-
- if ((data_ptr + real_len) >
- chdlc_priv_area->end_addr_trace_buffer + 1){
-
- tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1;
- sdla_peek(&card->hw, data_ptr,
- trace_pkt->data,tmp);
- data_ptr = chdlc_priv_area->base_addr_trace_buffer;
- }
-
- sdla_peek(&card->hw, data_ptr,
- &trace_pkt->data[tmp], real_len - tmp);
- }
-
- /* zero the opp flag to show we got the frame */
- ut_char = 0x00;
- sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1);
-
- /* now move onto the next frame */
- chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT);
-
- /* check if we went over the last address */
- if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) {
- chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr;
- }
-
- if(trace_pkt->data_avail == 0x01) {
- buffer_length += real_len - 1;
- }
-
- /* for the header */
- buffer_length += sizeof(trace_pkt_t);
-
- } /* For Loop */
-
- if (frames == chdlc_priv_area->number_trace_elements){
- chdlc_udp_pkt->trace_info.ismoredata = 0x01;
- }
- chdlc_udp_pkt->trace_info.num_frames = frames;
-
- mb->buffer_length = buffer_length;
- chdlc_udp_pkt->cblock.buffer_length = buffer_length;
-
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
-
- break;
-
-
- case CPIPE_FT1_READ_STATUS:
- ((unsigned char *)chdlc_udp_pkt->data )[0] =
- flags->FT1_info_struct.parallel_port_A_input;
-
- ((unsigned char *)chdlc_udp_pkt->data )[1] =
- flags->FT1_info_struct.parallel_port_B_input;
-
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- chdlc_udp_pkt->cblock.buffer_length = 2;
- mb->buffer_length = 2;
- break;
-
- case CPIPE_ROUTER_UP_TIME:
- do_gettimeofday( &tv );
- chdlc_priv_area->router_up_time = tv.tv_sec -
- chdlc_priv_area->router_start_time;
- *(unsigned long *)&chdlc_udp_pkt->data =
- chdlc_priv_area->router_up_time;
- mb->buffer_length = sizeof(unsigned long);
- chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long);
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- break;
-
- case FT1_MONITOR_STATUS_CTRL:
- /* Enable FT1 MONITOR STATUS */
- if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) ||
- (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) {
-
- if( rCount++ != 0 ) {
- chdlc_udp_pkt->cblock.
- return_code = COMMAND_OK;
- mb->buffer_length = 1;
- break;
- }
- }
-
- /* Disable FT1 MONITOR STATUS */
- if( chdlc_udp_pkt->data[0] == 0) {
-
- if( --rCount != 0) {
- chdlc_udp_pkt->cblock.
- return_code = COMMAND_OK;
- mb->buffer_length = 1;
- break;
- }
- }
- goto dflt_1;
-
- default:
-dflt_1:
- /* it's a board command */
- mb->command = chdlc_udp_pkt->cblock.command;
- mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length;
- if (mb->buffer_length) {
- memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt->
- data, mb->buffer_length);
- }
- /* run the command on the board */
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK) {
- break;
- }
-
- /* copy the result back to our buffer */
- memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t));
-
- if (mb->buffer_length) {
- memcpy(&chdlc_udp_pkt->data, &mb->data,
- mb->buffer_length);
- }
-
- } /* end of switch */
- } /* end of else */
-
- /* Fill UDP TTL */
- chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
-
- len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length);
-
-
- if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){
-
- /* Must check if we interrupted if_send() routine. The
- * tx buffers might be used. If so drop the packet */
- if (!test_bit(SEND_CRIT,&card->wandev.critical)) {
-
- if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) {
- ++ card->wandev.stats.tx_packets;
- card->wandev.stats.tx_bytes += len;
- }
- }
- } else {
-
- /* Pass it up the stack
- Allocate socket buffer */
- if ((new_skb = dev_alloc_skb(len)) != NULL) {
- /* copy data into new_skb */
-
- buf = skb_put(new_skb, len);
- memcpy(buf, chdlc_priv_area->udp_pkt_data, len);
-
- /* Decapsulate pkt and pass it up the protocol stack */
- new_skb->protocol = htons(ETH_P_IP);
- new_skb->dev = dev;
- new_skb->mac.raw = new_skb->data;
-
- netif_rx(new_skb);
- dev->last_rx = jiffies;
- } else {
-
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- }
- }
-
- chdlc_priv_area->udp_pkt_lgth = 0;
-
- return 0;
-}
-
-/*============================================================================
- * Initialize Receive and Transmit Buffers.
- */
-
-static void init_chdlc_tx_rx_buff( sdla_t* card)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config;
- CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config;
- char err;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CONFIGURATION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if(err != COMMAND_OK) {
- if (card->wandev.dev){
- chdlc_error(card,err,mb);
- }
- return;
- }
-
- if(card->hw.type == SDLA_S514) {
- tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Tx_stat_el_cfg_struct));
- rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Rx_stat_el_cfg_struct));
-
- /* Setup Head and Tails for buffers */
- card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
- tx_config->base_addr_Tx_status_elements);
- card->u.c.txbuf_last =
- (CHDLC_DATA_TX_STATUS_EL_STRUCT *)
- card->u.c.txbuf_base +
- (tx_config->number_Tx_status_elements - 1);
-
- card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
- rx_config->base_addr_Rx_status_elements);
- card->u.c.rxbuf_last =
- (CHDLC_DATA_RX_STATUS_EL_STRUCT *)
- card->u.c.rxbuf_base +
- (rx_config->number_Rx_status_elements - 1);
-
- /* Set up next pointer to be used */
- card->u.c.txbuf = (void *)(card->hw.dpmbase +
- tx_config->next_Tx_status_element_to_use);
- card->u.c.rxmb = (void *)(card->hw.dpmbase +
- rx_config->next_Rx_status_element_to_use);
- }
- else {
- tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
-
- rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
-
- /* Setup Head and Tails for buffers */
- card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
- (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE));
- card->u.c.txbuf_last =
- (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base
- + (tx_config->number_Tx_status_elements - 1);
- card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
- (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE));
- card->u.c.rxbuf_last =
- (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base
- + (rx_config->number_Rx_status_elements - 1);
-
- /* Set up next pointer to be used */
- card->u.c.txbuf = (void *)(card->hw.dpmbase +
- (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE));
- card->u.c.rxmb = (void *)(card->hw.dpmbase +
- (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE));
- }
-
- /* Setup Actual Buffer Start and end addresses */
- card->u.c.rx_base = rx_config->base_addr_Rx_buffer;
- card->u.c.rx_top = rx_config->end_addr_Rx_buffer;
-
-}
-
-/*=============================================================================
- * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR
- * _TEST_COUNTER times.
- */
-static int intr_test( sdla_t* card)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int err,i;
-
- Intr_test_counter = 0;
-
- err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE);
-
- if (err == CMD_OK) {
- for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CODE_VERSION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != CMD_OK)
- chdlc_error(card, err, mb);
- }
- }
- else {
- return err;
- }
-
- err = chdlc_set_intr_mode(card, 0);
-
- if (err != CMD_OK)
- return err;
-
- return 0;
-}
-
-/*==============================================================================
- * Determine what type of UDP call it is. CPIPEAB ?
- */
-static int udp_pkt_type(struct sk_buff *skb, sdla_t* card)
-{
- chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data;
-
-#ifdef _WAN_UDP_DEBUG
- printk(KERN_INFO "SIG %s = %s\n\
- UPP %x = %x\n\
- PRT %x = %x\n\
- REQ %i = %i\n\
- 36 th = %x 37th = %x\n",
- chdlc_udp_pkt->wp_mgmt.signature,
- UDPMGMT_SIGNATURE,
- chdlc_udp_pkt->udp_pkt.udp_dst_port,
- ntohs(card->wandev.udp_port),
- chdlc_udp_pkt->ip_pkt.protocol,
- UDPMGMT_UDP_PROTOCOL,
- chdlc_udp_pkt->wp_mgmt.request_reply,
- UDPMGMT_REQUEST,
- skb->data[36], skb->data[37]);
-#endif
-
- if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) &&
- (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
- (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
- (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
-
- return UDP_CPIPE_TYPE;
-
- }else{
- return UDP_INVALID_TYPE;
- }
-}
-
-/*============================================================================
- * Set PORT state.
- */
-static void port_set_state (sdla_t *card, int state)
-{
- if (card->u.c.state != state)
- {
- switch (state)
- {
- case WAN_CONNECTED:
- printk (KERN_INFO "%s: Link connected!\n",
- card->devname);
- break;
-
- case WAN_CONNECTING:
- printk (KERN_INFO "%s: Link connecting...\n",
- card->devname);
- break;
-
- case WAN_DISCONNECTED:
- printk (KERN_INFO "%s: Link disconnected!\n",
- card->devname);
- break;
- }
-
- card->wandev.state = card->u.c.state = state;
- if (card->wandev.dev){
- struct net_device *dev = card->wandev.dev;
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
- chdlc_priv_area->common.state = state;
- }
- }
-}
-
-/*===========================================================================
- * config_chdlc
- *
- * Configure the chdlc protocol and enable communications.
- *
- * The if_open() function binds this function to the poll routine.
- * Therefore, this function will run every time the chdlc interface
- * is brought up. We cannot run this function from the if_open
- * because if_open does not have access to the remote IP address.
- *
- * If the communications are not enabled, proceed to configure
- * the card and enable communications.
- *
- * If the communications are enabled, it means that the interface
- * was shutdown by ether the user or driver. In this case, we
- * have to check that the IP addresses have not changed. If
- * the IP addresses have changed, we have to reconfigure the firmware
- * and update the changed IP addresses. Otherwise, just exit.
- *
- */
-
-static int config_chdlc (sdla_t *card)
-{
- struct net_device *dev = card->wandev.dev;
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
-
- if (card->u.c.comm_enabled){
-
- /* Jun 20. 2000: NC
- * IP addresses are not used in the API mode */
-
- if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local ||
- chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) &&
- card->u.c.usedby == WANPIPE) {
-
- /* The IP addersses have changed, we must
- * stop the communications and reconfigure
- * the card. Reason: the firmware must know
- * the local and remote IP addresses. */
- disable_comm(card);
- port_set_state(card, WAN_DISCONNECTED);
- printk(KERN_INFO
- "%s: IP addresses changed!\n",
- card->devname);
- printk(KERN_INFO
- "%s: Restarting communications ...\n",
- card->devname);
- }else{
- /* IP addresses are the same and the link is up,
- * we don't have to do anything here. Therefore, exit */
- return 0;
- }
- }
-
- chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp;
- chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp;
-
-
- /* Setup the Board for asynchronous mode */
- if (card->u.c.async_mode){
-
- if (set_asy_config(card)) {
- printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n",
- card->devname);
- return 0;
- }
- }else{
- /* Setup the Board for CHDLC */
- if (set_chdlc_config(card)) {
- printk (KERN_INFO "%s: Failed CHDLC configuration!\n",
- card->devname);
- return 0;
- }
- }
-
- /* Set interrupt mode and mask */
- if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
- APP_INT_ON_GLOBAL_EXCEP_COND |
- APP_INT_ON_TX_FRAME |
- APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
- printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
- card->devname);
- return 0;
- }
-
-
- /* Mask the Transmit and Timer interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
-
- /* In TTY mode, receive interrupt will be enabled during
- * wanpipe_tty_open() operation */
- if (card->tty_opt){
- flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME;
- }
-
- /* Enable communications */
- if (card->u.c.async_mode){
- if (asy_comm_enable(card) != 0) {
- printk(KERN_INFO "%s: Failed to enable async commnunication!\n",
- card->devname);
- flags->interrupt_info_struct.interrupt_permission = 0;
- card->u.c.comm_enabled=0;
- chdlc_set_intr_mode(card,0);
- return 0;
- }
- }else{
- if (chdlc_comm_enable(card) != 0) {
- printk(KERN_INFO "%s: Failed to enable chdlc communications!\n",
- card->devname);
- flags->interrupt_info_struct.interrupt_permission = 0;
- card->u.c.comm_enabled=0;
- chdlc_set_intr_mode(card,0);
- return 0;
- }
- }
-
- /* Initialize Rx/Tx buffer control fields */
- init_chdlc_tx_rx_buff(card);
- port_set_state(card, WAN_CONNECTING);
- return 0;
-}
-
-
-/*============================================================
- * chdlc_poll
- *
- * Rationale:
- * We cannot manipulate the routing tables, or
- * ip addresses withing the interrupt. Therefore
- * we must perform such actons outside an interrupt
- * at a later time.
- *
- * Description:
- * CHDLC polling routine, responsible for
- * shutting down interfaces upon disconnect
- * and adding/removing routes.
- *
- * Usage:
- * This function is executed for each CHDLC
- * interface through a tq_schedule bottom half.
- *
- * trigger_chdlc_poll() function is used to kick
- * the chldc_poll routine.
- */
-
-static void chdlc_poll(struct net_device *dev)
-{
- chdlc_private_area_t *chdlc_priv_area;
- sdla_t *card;
- u8 check_gateway=0;
- SHARED_MEMORY_INFO_STRUCT* flags;
-
-
- if (!dev || (chdlc_priv_area=dev->priv) == NULL)
- return;
-
- card = chdlc_priv_area->card;
- flags = card->u.c.flags;
-
- /* (Re)Configuraiton is in progress, stop what you are
- * doing and get out */
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- clear_bit(POLL_CRIT,&card->wandev.critical);
- return;
- }
-
- /* if_open() function has triggered the polling routine
- * to determine the configured IP addresses. Once the
- * addresses are found, trigger the chdlc configuration */
- if (test_bit(0,&chdlc_priv_area->config_chdlc)){
-
- chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP);
- chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
-
- /* Jun 20. 2000 Bug Fix
- * Only perform this check in WANPIPE mode, since
- * IP addresses are not used in the API mode. */
-
- if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp &&
- card->u.c.slarp_timer == 0x00 &&
- !card->u.c.backup &&
- card->u.c.usedby == WANPIPE){
-
- if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){
- printk(KERN_INFO "\n%s: --- WARNING ---\n",
- card->devname);
- printk(KERN_INFO
- "%s: The local IP address is the same as the\n",
- card->devname);
- printk(KERN_INFO
- "%s: Point-to-Point IP address.\n",
- card->devname);
- printk(KERN_INFO "%s: --- WARNING ---\n\n",
- card->devname);
- }else{
- clear_bit(POLL_CRIT,&card->wandev.critical);
- chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ;
- add_timer(&chdlc_priv_area->poll_delay_timer);
- return;
- }
- }
-
- clear_bit(0,&chdlc_priv_area->config_chdlc);
- clear_bit(POLL_CRIT,&card->wandev.critical);
-
- chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
- flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
- return;
- }
- /* Dynamic interface implementation, as well as dynamic
- * routing. */
-
- switch (card->u.c.state){
-
- case WAN_DISCONNECTED:
-
- /* If the dynamic interface configuration is on, and interface
- * is up, then bring down the netowrk interface */
-
- if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) &&
- !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) &&
- card->wandev.dev->flags & IFF_UP){
-
- printk(KERN_INFO "%s: Interface %s down.\n",
- card->devname,card->wandev.dev->name);
- change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP));
- set_bit(DEV_DOWN,&chdlc_priv_area->interface_down);
- chdlc_priv_area->route_status = NO_ROUTE;
-
- }else{
- /* We need to check if the local IP address is
- * zero. If it is, we shouldn't try to remove it.
- */
-
- if (card->wandev.dev->flags & IFF_UP &&
- get_ip_address(card->wandev.dev,WAN_LOCAL_IP) &&
- chdlc_priv_area->route_status != NO_ROUTE &&
- card->u.c.slarp_timer){
-
- process_route(card);
- }
- }
- break;
-
- case WAN_CONNECTED:
-
- /* In SMP machine this code can execute before the interface
- * comes up. In this case, we must make sure that we do not
- * try to bring up the interface before dev_open() is finished */
-
-
- /* DEV_DOWN will be set only when we bring down the interface
- * for the very first time. This way we know that it was us
- * that brought the interface down */
-
- if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) &&
- test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) &&
- !(card->wandev.dev->flags & IFF_UP)){
-
- printk(KERN_INFO "%s: Interface %s up.\n",
- card->devname,card->wandev.dev->name);
- change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP));
- clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down);
- check_gateway=1;
- }
-
- if (chdlc_priv_area->route_status == ADD_ROUTE &&
- card->u.c.slarp_timer){
-
- process_route(card);
- check_gateway=1;
- }
-
- if (chdlc_priv_area->gateway && check_gateway)
- add_gateway(card,dev);
-
- break;
- }
-
- clear_bit(POLL_CRIT,&card->wandev.critical);
-}
-
-/*============================================================
- * trigger_chdlc_poll
- *
- * Description:
- * Add a chdlc_poll() work entry into the keventd work queue
- * for a specific dlci/interface. This will kick
- * the fr_poll() routine at a later time.
- *
- * Usage:
- * Interrupts use this to defer a taks to
- * a polling routine.
- *
- */
-static void trigger_chdlc_poll(struct net_device *dev)
-{
- chdlc_private_area_t *chdlc_priv_area;
- sdla_t *card;
-
- if (!dev)
- return;
-
- if ((chdlc_priv_area = dev->priv)==NULL)
- return;
-
- card = chdlc_priv_area->card;
-
- if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){
- return;
- }
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- return;
- }
- schedule_work(&chdlc_priv_area->poll_work);
-}
-
-
-static void chdlc_poll_delay (unsigned long dev_ptr)
-{
- struct net_device *dev = (struct net_device *)dev_ptr;
- trigger_chdlc_poll(dev);
-}
-
-
-void s508_lock (sdla_t *card, unsigned long *smp_flags)
-{
- spin_lock_irqsave(&card->wandev.lock, *smp_flags);
- if (card->next){
- spin_lock(&card->next->wandev.lock);
- }
-}
-
-void s508_unlock (sdla_t *card, unsigned long *smp_flags)
-{
- if (card->next){
- spin_unlock(&card->next->wandev.lock);
- }
- spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
-}
-
-//*********** TTY SECTION ****************
-
-static void wanpipe_tty_trigger_tx_irq(sdla_t *card)
-{
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
- chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
-}
-
-static void wanpipe_tty_trigger_poll(sdla_t *card)
-{
- schedule_work(&card->tty_work);
-}
-
-static void tty_poll_work (void* data)
-{
- sdla_t *card = (sdla_t*)data;
- struct tty_struct *tty;
-
- if ((tty=card->tty)==NULL)
- return;
-
- tty_wakeup(tty);
-#if defined(SERIAL_HAVE_POLL_WAIT)
- wake_up_interruptible(&tty->poll_wait);
-#endif
- return;
-}
-
-static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp)
-{
- sdla_t *card;
- unsigned long smp_flags;
-
- if (!tty || !tty->driver_data){
- return;
- }
-
- card = (sdla_t*)tty->driver_data;
-
- if (!card)
- return;
-
- printk(KERN_INFO "%s: Closing TTY Driver!\n",
- card->devname);
-
- /* Sanity Check */
- if (!card->tty_open)
- return;
-
- wanpipe_close(card);
- if (--card->tty_open == 0){
-
- lock_adapter_irq(&card->wandev.lock,&smp_flags);
- card->tty=NULL;
- chdlc_disable_comm_shutdown(card);
- unlock_adapter_irq(&card->wandev.lock,&smp_flags);
-
- kfree(card->tty_buf);
- card->tty_buf = NULL;
- kfree(card->tty_rx);
- card->tty_rx = NULL;
- }
- return;
-}
-static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp)
-{
- unsigned long smp_flags;
- sdla_t *card;
-
- if (!tty){
- return -ENODEV;
- }
-
- if (!tty->driver_data){
- int port;
- port = tty->index;
- if ((port < 0) || (port >= NR_PORTS))
- return -ENODEV;
-
- tty->driver_data = WAN_CARD(port);
- if (!tty->driver_data)
- return -ENODEV;
- }
-
- card = (sdla_t*)tty->driver_data;
-
- if (!card){
- lock_adapter_irq(&card->wandev.lock,&smp_flags);
- card->tty=NULL;
- unlock_adapter_irq(&card->wandev.lock,&smp_flags);
- return -ENODEV;
- }
-
- printk(KERN_INFO "%s: Opening TTY Driver!\n",
- card->devname);
-
- if (card->tty_open == 0){
- lock_adapter_irq(&card->wandev.lock,&smp_flags);
- card->tty=tty;
- unlock_adapter_irq(&card->wandev.lock,&smp_flags);
-
- if (!card->tty_buf){
- card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL);
- if (!card->tty_buf){
- card->tty_buf=NULL;
- card->tty=NULL;
- return -ENOMEM;
- }
- }
-
- if (!card->tty_rx){
- card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL);
- if (!card->tty_rx){
- /* Free the buffer above */
- kfree(card->tty_buf);
- card->tty_buf=NULL;
- card->tty=NULL;
- return -ENOMEM;
- }
- }
- }
-
- ++card->tty_open;
- wanpipe_open(card);
- return 0;
-}
-
-static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
-{
- unsigned long smp_flags=0;
- sdla_t *card=NULL;
-
- if (!tty){
- dbg_printk(KERN_INFO "NO TTY in Write\n");
- return -ENODEV;
- }
-
- card = (sdla_t *)tty->driver_data;
-
- if (!card){
- dbg_printk(KERN_INFO "No Card in TTY Write\n");
- return -ENODEV;
- }
-
- if (count > card->wandev.mtu){
- dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n",
- count,card->wandev.mtu);
- return -EINVAL;
- }
-
- if (card->wandev.state != WAN_CONNECTED){
- dbg_printk(KERN_INFO "Card not connected in TTY Write\n");
- return -EINVAL;
- }
-
- /* Lock the 508 Card: SMP is supported */
- if(card->hw.type != SDLA_S514){
- s508_lock(card,&smp_flags);
- }
-
- if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){
- printk(KERN_INFO "%s: Critical in TTY Write\n",
- card->devname);
-
- /* Lock the 508 Card: SMP is supported */
- if(card->hw.type != SDLA_S514)
- s508_unlock(card,&smp_flags);
-
- return -EINVAL;
- }
-
- if (chdlc_send(card,(void*)buf,count)){
- dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n",
- card->devname);
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-
- wanpipe_tty_trigger_tx_irq(card);
-
- if(card->hw.type != SDLA_S514)
- s508_unlock(card,&smp_flags);
- return 0;
- }
- dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count);
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-
- if(card->hw.type != SDLA_S514)
- s508_unlock(card,&smp_flags);
-
- return count;
-}
-
-static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len)
-{
- unsigned offset=0;
- unsigned olen=len;
- char fp=0;
- struct tty_struct *tty;
- int i;
- struct tty_ldisc *ld;
-
- if (!card->tty_open){
- dbg_printk(KERN_INFO "%s: TTY not open during receive\n",
- card->devname);
- return;
- }
-
- if ((tty=card->tty) == NULL){
- dbg_printk(KERN_INFO "%s: No TTY on receive\n",
- card->devname);
- return;
- }
-
- if (!tty->driver_data){
- dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n",
- card->devname);
- return;
- }
-
-
- if (card->u.c.async_mode){
- if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Received packet size too big: %i bytes, Max: %i!\n",
- card->devname,len,TTY_FLIPBUF_SIZE);
- }
- return;
- }
-
-
- if((addr + len) > card->u.c.rx_top + 1) {
- offset = card->u.c.rx_top - addr + 1;
-
- sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset);
-
- addr = card->u.c.rx_base;
- len -= offset;
-
- tty->flip.char_buf_ptr+=offset;
- tty->flip.count+=offset;
- for (i=0;i<offset;i++){
- *tty->flip.flag_buf_ptr = 0;
- tty->flip.flag_buf_ptr++;
- }
- }
-
- sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len);
-
- tty->flip.char_buf_ptr+=len;
- card->tty->flip.count+=len;
- for (i=0;i<len;i++){
- *tty->flip.flag_buf_ptr = 0;
- tty->flip.flag_buf_ptr++;
- }
-
- tty->low_latency=1;
- tty_flip_buffer_push(tty);
- }else{
- if (!card->tty_rx){
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Receive sync buffer not available!\n",
- card->devname);
- }
- return;
- }
-
- if (len > TTY_CHDLC_MAX_MTU){
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Received packet size too big: %i bytes, Max: %i!\n",
- card->devname,len,TTY_FLIPBUF_SIZE);
- }
- return;
- }
-
-
- if((addr + len) > card->u.c.rx_top + 1) {
- offset = card->u.c.rx_top - addr + 1;
-
- sdla_peek(&card->hw, addr, card->tty_rx, offset);
-
- addr = card->u.c.rx_base;
- len -= offset;
- }
- sdla_peek(&card->hw, addr, card->tty_rx+offset, len);
- ld = tty_ldisc_ref(tty);
- if (ld) {
- if (ld->receive_buf)
- ld->receive_buf(tty,card->tty_rx,&fp,olen);
- tty_ldisc_deref(ld);
- }else{
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: NO TTY Sync line discipline!\n",
- card->devname);
- }
- }
- }
-
- dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen);
- return;
-}
-
-#if 0
-static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- return -ENOIOCTLCMD;
-}
-#endif
-
-static void wanpipe_tty_stop(struct tty_struct *tty)
-{
- return;
-}
-
-static void wanpipe_tty_start(struct tty_struct *tty)
-{
- return;
-}
-
-static int config_tty (sdla_t *card)
-{
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
-
- /* Setup the Board for asynchronous mode */
- if (card->u.c.async_mode){
-
- if (set_asy_config(card)) {
- printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n",
- card->devname);
- return -EINVAL;
- }
- }else{
- /* Setup the Board for CHDLC */
- if (set_chdlc_config(card)) {
- printk (KERN_INFO "%s: Failed CHDLC configuration!\n",
- card->devname);
- return -EINVAL;
- }
- }
-
- /* Set interrupt mode and mask */
- if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
- APP_INT_ON_GLOBAL_EXCEP_COND |
- APP_INT_ON_TX_FRAME |
- APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
- printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
- card->devname);
- return -EINVAL;
- }
-
-
- /* Mask the Transmit and Timer interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
-
-
- /* Enable communications */
- if (card->u.c.async_mode){
- if (asy_comm_enable(card) != 0) {
- printk(KERN_INFO "%s: Failed to enable async commnunication!\n",
- card->devname);
- flags->interrupt_info_struct.interrupt_permission = 0;
- card->u.c.comm_enabled=0;
- chdlc_set_intr_mode(card,0);
- return -EINVAL;
- }
- }else{
- if (chdlc_comm_enable(card) != 0) {
- printk(KERN_INFO "%s: Failed to enable chdlc communications!\n",
- card->devname);
- flags->interrupt_info_struct.interrupt_permission = 0;
- card->u.c.comm_enabled=0;
- chdlc_set_intr_mode(card,0);
- return -EINVAL;
- }
- }
-
- /* Initialize Rx/Tx buffer control fields */
- init_chdlc_tx_rx_buff(card);
- port_set_state(card, WAN_CONNECTING);
- return 0;
-}
-
-
-static int change_speed(sdla_t *card, struct tty_struct *tty,
- struct termios *old_termios)
-{
- int baud, ret=0;
- unsigned cflag;
- int dbits,sbits,parity,handshaking;
-
- cflag = tty->termios->c_cflag;
-
- /* There is always one stop bit */
- sbits=WANOPT_ONE;
-
- /* Parity is defaulted to NONE */
- parity = WANOPT_NONE;
-
- handshaking=0;
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: dbits = 5; break;
- case CS6: dbits = 6; break;
- case CS7: dbits = 7; break;
- case CS8: dbits = 8; break;
- /* Never happens, but GCC is too dumb to figure it out */
- default: dbits = 8; break;
- }
-
- /* One more stop bit should be supported, thus increment
- * the number of stop bits Max=2 */
- if (cflag & CSTOPB) {
- sbits = WANOPT_TWO;
- }
- if (cflag & PARENB) {
- parity = WANOPT_EVEN;
- }
- if (cflag & PARODD){
- parity = WANOPT_ODD;
- }
-
- /* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(tty);
-
- if (!baud)
- baud = 9600; /* B0 transition handled in rs_set_termios */
-
- if (cflag & CRTSCTS) {
- handshaking|=ASY_RTS_HS_FOR_RX;
- }
-
- if (I_IGNPAR(tty))
- parity = WANOPT_NONE;
-
- if (I_IXOFF(tty)){
- handshaking|=ASY_XON_XOFF_HS_FOR_RX;
- handshaking|=ASY_XON_XOFF_HS_FOR_TX;
- }
-
- if (I_IXON(tty)){
- handshaking|=ASY_XON_XOFF_HS_FOR_RX;
- handshaking|=ASY_XON_XOFF_HS_FOR_TX;
- }
-
- if (card->u.c.async_mode){
- if (card->wandev.bps != baud)
- ret=1;
- card->wandev.bps = baud;
- }
-
- if (card->u.c.async_mode){
- if (card->u.c.protocol_options != handshaking)
- ret=1;
- card->u.c.protocol_options = handshaking;
-
- if (card->u.c.tx_bits_per_char != dbits)
- ret=1;
- card->u.c.tx_bits_per_char = dbits;
-
- if (card->u.c.rx_bits_per_char != dbits)
- ret=1;
- card->u.c.rx_bits_per_char = dbits;
-
- if (card->u.c.stop_bits != sbits)
- ret=1;
- card->u.c.stop_bits = sbits;
-
- if (card->u.c.parity != parity)
- ret=1;
- card->u.c.parity = parity;
-
- card->u.c.break_timer = 50;
- card->u.c.inter_char_timer = 10;
- card->u.c.rx_complete_length = 100;
- card->u.c.xon_char = 0xFE;
- }else{
- card->u.c.protocol_options = HDLC_STREAMING_MODE;
- }
-
- return ret;
-}
-
-
-static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
- sdla_t *card;
- int err=1;
-
- if (!tty){
- return;
- }
-
- card = (sdla_t *)tty->driver_data;
-
- if (!card)
- return;
-
- if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){
- unsigned long smp_flags;
-
- if (card->u.c.comm_enabled){
- lock_adapter_irq(&card->wandev.lock,&smp_flags);
- chdlc_disable_comm_shutdown(card);
- unlock_adapter_irq(&card->wandev.lock,&smp_flags);
- }
- lock_adapter_irq(&card->wandev.lock,&smp_flags);
- err = config_tty(card);
- unlock_adapter_irq(&card->wandev.lock,&smp_flags);
- if (card->u.c.async_mode){
- printk(KERN_INFO "%s: TTY Async Configuration:\n"
- " Baud =%i\n"
- " Handshaking =%s\n"
- " Tx Dbits =%i\n"
- " Rx Dbits =%i\n"
- " Parity =%s\n"
- " Stop Bits =%i\n",
- card->devname,
- card->wandev.bps,
- opt_decode[card->u.c.protocol_options],
- card->u.c.tx_bits_per_char,
- card->u.c.rx_bits_per_char,
- p_decode[card->u.c.parity] ,
- card->u.c.stop_bits);
- }else{
- printk(KERN_INFO "%s: TTY Sync Configuration:\n"
- " Baud =%i\n"
- " Protocol =HDLC_STREAMING\n",
- card->devname,card->wandev.bps);
- }
- if (!err){
- port_set_state(card,WAN_CONNECTED);
- }else{
- port_set_state(card,WAN_DISCONNECTED);
- }
- }
- return;
-}
-
-static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
- sdla_t *card;
- unsigned long smp_flags=0;
-
- if (!tty){
- return;
- }
-
- card = (sdla_t *)tty->driver_data;
-
- if (!card)
- return;
-
- if (card->wandev.state != WAN_CONNECTED)
- return;
-
- if(card->hw.type != SDLA_S514)
- s508_lock(card,&smp_flags);
-
- if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){
-
- wanpipe_tty_trigger_tx_irq(card);
-
- if(card->hw.type != SDLA_S514)
- s508_unlock(card,&smp_flags);
- return;
- }
-
- if (chdlc_send(card,(void*)&ch,1)){
- wanpipe_tty_trigger_tx_irq(card);
- dbg_printk("%s: Failed to TX char!\n",card->devname);
- }
-
- dbg_printk("%s: Char TX OK\n",card->devname);
-
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
-
- if(card->hw.type != SDLA_S514)
- s508_unlock(card,&smp_flags);
-
- return;
-}
-
-static void wanpipe_tty_flush_chars(struct tty_struct *tty)
-{
- return;
-}
-
-static void wanpipe_tty_flush_buffer(struct tty_struct *tty)
-{
- if (!tty)
- return;
-
-#if defined(SERIAL_HAVE_POLL_WAIT)
- wake_up_interruptible(&tty->poll_wait);
-#endif
- tty_wakeup(tty);
- return;
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch)
-{
- return;
-}
-
-
-static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-
-static int wanpipe_tty_write_room(struct tty_struct *tty)
-{
- sdla_t *card;
-
- printk(KERN_INFO "TTY Write Room\n");
-
- if (!tty){
- return 0;
- }
-
- card = (sdla_t *)tty->driver_data;
- if (!card)
- return 0;
-
- if (card->wandev.state != WAN_CONNECTED)
- return 0;
-
- return SEC_MAX_NO_DATA_BYTES_IN_FRAME;
-}
-
-
-static int set_modem_status(sdla_t *card, unsigned char data)
-{
- CHDLC_MAILBOX_STRUCT *mb = card->mbox;
- int err;
-
- mb->buffer_length=1;
- mb->command=SET_MODEM_STATUS;
- mb->data[0]=data;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error (card, err, mb);
-
- return err;
-}
-
-static void wanpipe_tty_hangup(struct tty_struct *tty)
-{
- sdla_t *card;
- unsigned long smp_flags;
-
- printk(KERN_INFO "TTY Hangup!\n");
-
- if (!tty){
- return;
- }
-
- card = (sdla_t *)tty->driver_data;
- if (!card)
- return;
-
- lock_adapter_irq(&card->wandev.lock,&smp_flags);
- set_modem_status(card,0);
- unlock_adapter_irq(&card->wandev.lock,&smp_flags);
- return;
-}
-
-static void wanpipe_tty_break(struct tty_struct *tty, int break_state)
-{
- return;
-}
-
-static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- return;
-}
-
-static void wanpipe_tty_throttle(struct tty_struct * tty)
-{
- return;
-}
-
-static void wanpipe_tty_unthrottle(struct tty_struct * tty)
-{
- return;
-}
-
-int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- return 0;
-}
-
-/*
- * The serial driver boot-time initialization code!
- */
-int wanpipe_tty_init(sdla_t *card)
-{
- struct serial_state * state;
-
- /* Initialize the tty_driver structure */
-
- if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){
- printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n",
- card->devname,card->tty_minor);
- return -EINVAL;
- }
-
- if (WAN_CARD(card->tty_minor)){
- printk(KERN_INFO "%s: TTY Minor %i, already in use\n",
- card->devname,card->tty_minor);
- return -EBUSY;
- }
-
- if (tty_init_cnt==0){
-
- printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n",
- card->devname,
- card->u.c.async_mode ? "ASYNC" : "SYNC",
- WAN_TTY_MAJOR,MIN_PORT,MAX_PORT);
-
- tty_driver_mode = card->u.c.async_mode;
-
- memset(&serial_driver, 0, sizeof(struct tty_driver));
- serial_driver.magic = TTY_DRIVER_MAGIC;
- serial_driver.owner = THIS_MODULE;
- serial_driver.driver_name = "wanpipe_tty";
- serial_driver.name = "ttyW";
- serial_driver.major = WAN_TTY_MAJOR;
- serial_driver.minor_start = WAN_TTY_MINOR;
- serial_driver.num = NR_PORTS;
- serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver.subtype = SERIAL_TYPE_NORMAL;
-
- serial_driver.init_termios = tty_std_termios;
- serial_driver.init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver.flags = TTY_DRIVER_REAL_RAW;
-
- serial_driver.refcount = 1; /* !@!@^#^&!! */
-
- serial_driver.open = wanpipe_tty_open;
- serial_driver.close = wanpipe_tty_close;
- serial_driver.write = wanpipe_tty_write;
-
- serial_driver.put_char = wanpipe_tty_put_char;
- serial_driver.flush_chars = wanpipe_tty_flush_chars;
- serial_driver.write_room = wanpipe_tty_write_room;
- serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer;
- serial_driver.flush_buffer = wanpipe_tty_flush_buffer;
- //serial_driver.ioctl = wanpipe_tty_ioctl;
- serial_driver.throttle = wanpipe_tty_throttle;
- serial_driver.unthrottle = wanpipe_tty_unthrottle;
- serial_driver.send_xchar = wanpipe_tty_send_xchar;
- serial_driver.set_termios = wanpipe_tty_set_termios;
- serial_driver.stop = wanpipe_tty_stop;
- serial_driver.start = wanpipe_tty_start;
- serial_driver.hangup = wanpipe_tty_hangup;
- serial_driver.break_ctl = wanpipe_tty_break;
- serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent;
- serial_driver.read_proc = wanpipe_tty_read_proc;
-
- if (tty_register_driver(&serial_driver)){
- printk(KERN_INFO "%s: Failed to register serial driver!\n",
- card->devname);
- }
- }
-
-
- /* The subsequent ports must comply to the initial configuration */
- if (tty_driver_mode != card->u.c.async_mode){
- printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n",
- card->devname);
- printk(KERN_INFO "%s: The TTY driver is configured for %s!\n",
- card->devname, tty_driver_mode ? "ASYNC" : "SYNC");
- return -EINVAL;
- }
-
- tty_init_cnt++;
-
- printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n",
- card->devname,
- tty_driver_mode ? "ASYNC" : "SYNC",
- card->tty_minor);
-
- tty_card_map[card->tty_minor] = card;
- state = &rs_table[card->tty_minor];
-
- state->magic = SSTATE_MAGIC;
- state->line = 0;
- state->type = PORT_UNKNOWN;
- state->custom_divisor = 0;
- state->close_delay = 5*HZ/10;
- state->closing_wait = 30*HZ;
- state->icount.cts = state->icount.dsr =
- state->icount.rng = state->icount.dcd = 0;
- state->icount.rx = state->icount.tx = 0;
- state->icount.frame = state->icount.parity = 0;
- state->icount.overrun = state->icount.brk = 0;
- state->irq = card->wandev.irq;
-
- INIT_WORK(&card->tty_work, tty_poll_work, (void*)card);
- return 0;
-}
-
-
-MODULE_LICENSE("GPL");
-
-/****** End ****************************************************************/
diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
deleted file mode 100644
index 7f1ce9d4333e..000000000000
--- a/drivers/net/wan/sdla_fr.c
+++ /dev/null
@@ -1,5061 +0,0 @@
-/*****************************************************************************
-* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module.
-*
-* Author(s): Nenad Corbic <ncorbic@sangoma.com>
-* Gideon Hack
-*
-* Copyright: (c) 1995-2001 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels
-* Nov 15, 2000 David Rokavarg
-* Nenad Corbic o Added frame relay bridging support.
-* Original code from Mark Wells and Kristian Hoffmann has
-* been integrated into the frame relay driver.
-* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option.
-* Tcpdump doesn't support Frame Relay inteface
-* types, to fix this true type option will set
-* the interface type to RAW IP mode.
-* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging:
-* Deny all and specify allowed requests.
-* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces.
-* Moved the if_header into the if_send() routine.
-* The if_header() was breaking the libpcap
-* support. i.e. support for tcpdump, ethereal ...
-* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure
-* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time.
-* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface
-* when the channel gets disconnected.
-* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate
-* interface setups.
-* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove
-* new dlcis/interfaces.
-* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling.
-* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support
-* Mar 13, 2000 Nenad Corbic o Added new socket API support.
-* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery.
-* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem.
-* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels
-*
-* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function
-* o Removed the ARP support. This has to be done
-* in the next version.
-* o Only a Node can implement NO signalling.
-* Initialize DLCI during if_open() if NO
-* signalling.
-* o Took out IPX support, implement in next
-* version
-* Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update
-* function to use timer interrupt.
-* o Fixed the CIR bug: Set the value of BC
-* to CIR when the CIR is enabled.
-* o Updated comments, statistics and tracing.
-* Jun 02, 1999 Gideon Hack o Updated for S514 support.
-* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels.
-* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI
-* status is received through an event interrupt.
-* Jul 08, 1998 David Fong o Added inverse ARP support.
-* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds.
-* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs.
-* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH)
-* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support.
-* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards
-* o Added Cli() to protect enabling of interrupts
-* while polling is called.
-* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts
-* when they have been disabled by another
-* interface or routine (eg. wpf_poll).
-* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling
-* routine disable interrupts during interrupt
-* testing.
-* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time.
-* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow
-* control by avoiding RACE conditions. The
-* cli() and restore_flags() are taken out.
-* The fr_channel structure is appended for
-* Driver Statistics.
-* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX
-* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti()
-* o Abstracted the UDP management stuff
-* o Now use tbusy and critical more intelligently
-* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393
-* through router.conf.
-* o Protected calls to sdla_peek() by adDing
-* save_flags(), cli() and restore_flags().
-* o Added error message for Inactive DLCIs in
-* fr_event() and update_chan_state().
-* o Fixed freeing up of buffers using kfree()
-* when packets are received.
-* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets
-* o Added ability to discard multicast and
-* broadcast source addressed packets
-* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities
-* New case (0x44) statement in if_send routine
-* Added a global variable rCount to keep track
-* of FT1 status enabled on the board.
-* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem
-* With multiple boards a problem was seen where
-* the second board always stopped transmitting
-* packet after running for a while. The code
-* got into a stage where the interrupts were
-* disabled and dev->tbusy was set to 1.
-* This caused the If_send() routine to get into
-* the if clause for it(0,dev->tbusy)
-* forever.
-* The code got into this stage due to an
-* interrupt occurring within the if clause for
-* set_bit(0,dev->tbusy). Since an interrupt
-* disables furhter transmit interrupt and
-* makes dev->tbusy = 0, this effect was undone
-* by making dev->tbusy = 1 in the if clause.
-* The Fix checks to see if Transmit interrupts
-* are disabled then do not make dev->tbusy = 1
-* Introduced a global variable: int_occur and
-* added tx_int_enabled in the wan_device
-* structure.
-* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple
-* boards.
-*
-* Apr 25, 1997 Farhan Thawar o added UDP Management stuff
-* o fixed bug in if_send() and tx_intr() to
-* sleep and wakeup all devices
-* Mar 11, 1997 Farhan Thawar Version 3.1.1
-* o fixed (+1) bug in fr508_rx_intr()
-* o changed if_send() to return 0 if
-* wandev.critical() is true
-* o free socket buffer in if_send() if
-* returning 0
-* o added tx_intr() routine
-* Jan 30, 1997 Gene Kozin Version 3.1.0
-* o implemented exec() entry point
-* o fixed a bug causing driver configured as
-* a FR switch to be stuck in WAN_
-* mode
-* Jan 02, 1997 Gene Kozin Initial version.
-*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/workqueue.h>
-#include <linux/if_arp.h> /* ARPHRD_* defines */
-#include <asm/byteorder.h> /* htons(), etc. */
-#include <asm/io.h> /* for inb(), outb(), etc. */
-#include <linux/time.h> /* for do_gettimeofday */
-#include <linux/in.h> /* sockaddr_in */
-#include <linux/jiffies.h> /* time_after() macro */
-#include <asm/errno.h>
-
-#include <linux/ip.h>
-#include <linux/if.h>
-
-#include <linux/if_wanpipe_common.h> /* Wanpipe Socket */
-#include <linux/if_wanpipe.h>
-
-#include <linux/sdla_fr.h> /* frame relay firmware API definitions */
-
-#include <asm/uaccess.h>
-#include <linux/inetdevice.h>
-#include <linux/netdevice.h>
-
-#include <net/route.h> /* Dynamic Route Creation */
-#include <linux/etherdevice.h> /* eth_type_trans() used for bridging */
-#include <linux/random.h>
-
-/****** Defines & Macros ****************************************************/
-
-#define MAX_CMD_RETRY 10 /* max number of firmware retries */
-
-#define FR_HEADER_LEN 8 /* max encapsulation header size */
-#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */
-
-/* Q.922 frame types */
-#define Q922_UI 0x03 /* Unnumbered Info frame */
-#define Q922_XID 0xAF
-
-/* DLCI configured or not */
-#define DLCI_NOT_CONFIGURED 0x00
-#define DLCI_CONFIG_PENDING 0x01
-#define DLCI_CONFIGURED 0x02
-
-/* CIR enabled or not */
-#define CIR_ENABLED 0x00
-#define CIR_DISABLED 0x01
-
-#define FRAME_RELAY_API 1
-#define MAX_BH_BUFF 10
-
-/* For handle_IPXWAN() */
-#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-/****** Data Structures *****************************************************/
-
-/* This is an extention of the 'struct device' we create for each network
- * interface to keep the rest of channel-specific data.
- */
-typedef struct fr_channel
-{
- wanpipe_common_t common;
- char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
- unsigned dlci_configured ; /* check whether configured or not */
- unsigned cir_status; /* check whether CIR enabled or not */
- unsigned dlci; /* logical channel number */
- unsigned cir; /* committed information rate */
- unsigned bc; /* committed burst size */
- unsigned be; /* excess burst size */
- unsigned mc; /* multicast support on or off */
- unsigned tx_int_status; /* Transmit Interrupt Status */
- unsigned short pkt_length; /* Packet Length */
- unsigned long router_start_time;/* Router start time in seconds */
- unsigned long tick_counter; /* counter for transmit time out */
- char dev_pending_devtint; /* interface pending dev_tint() */
- void *dlci_int_interface; /* pointer to the DLCI Interface */
- unsigned long IB_addr; /* physical address of Interface Byte */
- unsigned long state_tick; /* time of the last state change */
- unsigned char enable_IPX; /* Enable/Disable the use of IPX */
- unsigned long network_number; /* Internal Network Number for IPX*/
- sdla_t *card; /* -> owner */
- unsigned route_flag; /* Add/Rem dest addr in route tables */
- unsigned inarp; /* Inverse Arp Request status */
- long inarp_ready; /* Ready to send requests */
- int inarp_interval; /* Time between InArp Requests */
- unsigned long inarp_tick; /* InArp jiffies tick counter */
- long interface_down; /* Bring interface down on disconnect */
- struct net_device_stats ifstats; /* interface statistics */
- if_send_stat_t drvstats_if_send;
- rx_intr_stat_t drvstats_rx_intr;
- pipe_mgmt_stat_t drvstats_gen;
- unsigned long router_up_time;
-
- unsigned short transmit_length;
- struct sk_buff *delay_skb;
-
- bh_data_t *bh_head; /* Circular buffer for chdlc_bh */
- unsigned long tq_working;
- volatile int bh_write;
- volatile int bh_read;
- atomic_t bh_buff_used;
-
- /* Polling task queue. Each interface
- * has its own task queue, which is used
- * to defer events from the interrupt */
- struct work_struct fr_poll_work;
- struct timer_list fr_arp_timer;
-
- u32 ip_local;
- u32 ip_remote;
- long config_dlci;
- long unconfig_dlci;
-
- /* Whether this interface should be setup as a gateway.
- * Used by dynamic route setup code */
- u8 gateway;
-
- /* True interface type */
- u8 true_if_encoding;
- u8 fr_header[FR_HEADER_LEN];
- char fr_header_len;
-
-} fr_channel_t;
-
-/* Route Flag options */
-#define NO_ROUTE 0x00
-#define ADD_ROUTE 0x01
-#define ROUTE_ADDED 0x02
-#define REMOVE_ROUTE 0x03
-#define ARP_REQ 0x04
-
-/* inarp options */
-#define INARP_NONE 0x00
-#define INARP_REQUEST 0x01
-#define INARP_CONFIGURED 0x02
-
-/* reasons for enabling the timer interrupt on the adapter */
-#define TMR_INT_ENABLED_UDP 0x01
-#define TMR_INT_ENABLED_UPDATE 0x02
-#define TMR_INT_ENABLED_ARP 0x04
-#define TMR_INT_ENABLED_UPDATE_STATE 0x08
-#define TMR_INT_ENABLED_CONFIG 0x10
-#define TMR_INT_ENABLED_UNCONFIG 0x20
-
-
-typedef struct dlci_status
-{
- unsigned short dlci PACKED;
- unsigned char state PACKED;
-} dlci_status_t;
-
-typedef struct dlci_IB_mapping
-{
- unsigned short dlci PACKED;
- unsigned long addr_value PACKED;
-} dlci_IB_mapping_t;
-
-/* This structure is used for DLCI list Tx interrupt mode. It is used to
- enable interrupt bit and set the packet length for transmission
- */
-typedef struct fr_dlci_interface
-{
- unsigned char gen_interrupt PACKED;
- unsigned short packet_length PACKED;
- unsigned char reserved PACKED;
-} fr_dlci_interface_t;
-
-/* variable for keeping track of enabling/disabling FT1 monitor status */
-static int rCount = 0;
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/* variable for keeping track of number of interrupts generated during
- * interrupt test routine
- */
-static int Intr_test_counter;
-
-/****** Function Prototypes *************************************************/
-
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(struct wan_device *wandev);
-static int new_if(struct wan_device *wandev, struct net_device *dev,
- wanif_conf_t *conf);
-static int del_if(struct wan_device *wandev, struct net_device *dev);
-static void disable_comm (sdla_t *card);
-
-/* WANPIPE-specific entry points */
-static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
-
-/* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-
-static void if_tx_timeout(struct net_device *dev);
-
-static int if_rebuild_hdr (struct sk_buff *skb);
-
-static int if_send(struct sk_buff *skb, struct net_device *dev);
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
- struct sk_buff *skb);
-static struct net_device_stats *if_stats(struct net_device *dev);
-
-/* Interrupt handlers */
-static void fr_isr(sdla_t *card);
-static void rx_intr(sdla_t *card);
-static void tx_intr(sdla_t *card);
-static void timer_intr(sdla_t *card);
-static void spur_intr(sdla_t *card);
-
-/* Frame relay firmware interface functions */
-static int fr_read_version(sdla_t *card, char *str);
-static int fr_configure(sdla_t *card, fr_conf_t *conf);
-static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci);
-static int fr_init_dlci (sdla_t *card, fr_channel_t *chan);
-static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout);
-static int fr_comm_enable(sdla_t *card);
-static void fr_comm_disable(sdla_t *card);
-static int fr_get_err_stats(sdla_t *card);
-static int fr_get_stats(sdla_t *card);
-static int fr_add_dlci(sdla_t *card, int dlci);
-static int fr_activate_dlci(sdla_t *card, int dlci);
-static int fr_delete_dlci (sdla_t* card, int dlci);
-static int fr_issue_isf(sdla_t *card, int isf);
-static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len,
- void *buf);
-static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len,
- void *buf,unsigned char hdr_len);
-static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset);
-
-static int check_dlci_config (sdla_t *card, fr_channel_t *chan);
-static void initialize_rx_tx_buffers (sdla_t *card);
-
-
-/* Firmware asynchronous event handlers */
-static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox);
-static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox);
-static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox);
-
-/* Miscellaneous functions */
-static int update_chan_state(struct net_device *dev);
-static void set_chan_state(struct net_device *dev, int state);
-static struct net_device *find_channel(sdla_t *card, unsigned dlci);
-static int is_tx_ready(sdla_t *card, fr_channel_t *chan);
-static unsigned int dec_to_uint(unsigned char *str, int len);
-static int reply_udp( unsigned char *data, unsigned int mbox_len );
-
-static int intr_test( sdla_t* card );
-static void init_chan_statistics( fr_channel_t* chan );
-static void init_global_statistics( sdla_t* card );
-static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
-static int setup_for_delayed_transmit(struct net_device* dev,
- struct sk_buff *skb);
-
-struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev);
-static int check_tx_status(sdla_t *card, struct net_device *dev);
-
-/* Frame Relay Socket API */
-static void trigger_fr_bh (fr_channel_t *);
-static void fr_bh(struct net_device *dev);
-static int fr_bh_cleanup(struct net_device *dev);
-static int bh_enqueue(struct net_device *dev, struct sk_buff *skb);
-
-static void trigger_fr_poll(struct net_device *dev);
-static void fr_poll(struct net_device *dev);
-//static void add_gateway(struct net_device *dev);
-
-static void trigger_unconfig_fr(struct net_device *dev);
-static void unconfig_fr (sdla_t *);
-
-static void trigger_config_fr (sdla_t *);
-static void config_fr (sdla_t *);
-
-
-/* Inverse ARP and Dynamic routing functions */
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev);
-int is_arp(void *buf);
-int send_inarp_request(sdla_t *card, struct net_device *dev);
-
-static void trigger_fr_arp(struct net_device *dev);
-static void fr_arp (unsigned long data);
-
-
-/* Udp management functions */
-static int process_udp_mgmt_pkt(sdla_t *card);
-static int udp_pkt_type( struct sk_buff *skb, sdla_t *card );
-static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, int dlci);
-
-/* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket,
- unsigned long network_number, unsigned char incoming);
-
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname,
- unsigned char enable_IPX, unsigned long network_number);
-
-/* Lock Functions: SMP supported */
-void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags);
-void s508_s514_lock(sdla_t *card, unsigned long *smp_flags);
-
-unsigned short calc_checksum (char *, int);
-static int setup_fr_header(struct sk_buff *skb,
- struct net_device* dev, char op_mode);
-
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * Frame relay protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup. At this
- * point adapter is completely initialized and firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
-int wpf_init(sdla_t *card, wandev_conf_t *conf)
-{
-
- int err;
- fr508_flags_t* flags;
-
- union
- {
- char str[80];
- fr_conf_t cfg;
- } u;
-
- fr_buf_info_t* buf_info;
- int i;
-
-
- printk(KERN_INFO "\n");
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_FR) {
-
- printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
- return -EINVAL;
-
- }
-
- /* Initialize protocol-specific fields of adapter data space */
- switch (card->hw.fwid) {
-
- case SFID_FR508:
- card->mbox = (void*)(card->hw.dpmbase +
- FR508_MBOX_OFFS);
- card->flags = (void*)(card->hw.dpmbase +
- FR508_FLAG_OFFS);
- if(card->hw.type == SDLA_S514) {
- card->mbox += FR_MB_VECTOR;
- card->flags += FR_MB_VECTOR;
- }
- card->isr = &fr_isr;
- break;
-
- default:
- return -EINVAL;
- }
-
- flags = card->flags;
-
- /* Read firmware version. Note that when adapter initializes, it
- * clears the mailbox, so it may appear that the first command was
- * executed successfully when in fact it was merely erased. To work
- * around this, we execute the first command twice.
- */
-
- if (fr_read_version(card, NULL) || fr_read_version(card, u.str))
- return -EIO;
-
- printk(KERN_INFO "%s: running frame relay firmware v%s\n",
- card->devname, u.str);
-
- /* Adjust configuration */
- conf->mtu += FR_HEADER_LEN;
- conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ?
- min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) :
- FR_CHANNEL_MTU + FR_HEADER_LEN;
-
- conf->bps = min_t(unsigned int, conf->bps, 2048000);
-
- /* Initialze the configuration structure sent to the board to zero */
- memset(&u.cfg, 0, sizeof(u.cfg));
-
- memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map));
-
- /* Configure adapter firmware */
-
- u.cfg.mtu = conf->mtu;
- u.cfg.kbps = conf->bps / 1000;
-
- u.cfg.cir_fwd = u.cfg.cir_bwd = 16;
- u.cfg.bc_fwd = u.cfg.bc_bwd = 16;
-
- u.cfg.options = 0x0000;
- printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname);
-
- switch (conf->u.fr.signalling) {
-
- case WANOPT_FR_ANSI:
- u.cfg.options = 0x0000;
- break;
-
- case WANOPT_FR_Q933:
- u.cfg.options |= 0x0200;
- break;
-
- case WANOPT_FR_LMI:
- u.cfg.options |= 0x0400;
- break;
-
- case WANOPT_NO:
- u.cfg.options |= 0x0800;
- break;
- default:
- printk(KERN_INFO "%s: Illegal Signalling option\n",
- card->wandev.name);
- return -EINVAL;
- }
-
-
- card->wandev.signalling = conf->u.fr.signalling;
-
- if (conf->station == WANOPT_CPE) {
-
-
- if (conf->u.fr.signalling == WANOPT_NO){
- printk(KERN_INFO
- "%s: ERROR - For NO signalling, station must be set to Node!",
- card->devname);
- return -EINVAL;
- }
-
- u.cfg.station = 0;
- u.cfg.options |= 0x8000; /* auto config DLCI */
- card->u.f.dlci_num = 0;
-
- } else {
-
- u.cfg.station = 1; /* switch emulation mode */
-
- /* For switch emulation we have to create a list of dlci(s)
- * that will be sent to be global SET_DLCI_CONFIGURATION
- * command in fr_configure() routine.
- */
-
- card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100);
-
- for ( i = 0; i < card->u.f.dlci_num; i++) {
-
- card->u.f.node_dlci[i] = (unsigned short)
- conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16;
-
- }
- }
-
- if (conf->clocking == WANOPT_INTERNAL)
- u.cfg.port |= 0x0001;
-
- if (conf->interface == WANOPT_RS232)
- u.cfg.port |= 0x0002;
-
- if (conf->u.fr.t391)
- u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30);
- else
- u.cfg.t391 = 5;
-
- if (conf->u.fr.t392)
- u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30);
- else
- u.cfg.t392 = 15;
-
- if (conf->u.fr.n391)
- u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255);
- else
- u.cfg.n391 = 2;
-
- if (conf->u.fr.n392)
- u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10);
- else
- u.cfg.n392 = 3;
-
- if (conf->u.fr.n393)
- u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10);
- else
- u.cfg.n393 = 4;
-
- if (fr_configure(card, &u.cfg))
- return -EIO;
-
- if (card->hw.type == SDLA_S514) {
-
- buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR +
- FR508_RXBC_OFFS);
-
- card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase);
-
- card->u.f.rxmb_base =
- (void*)(buf_info->rse_base + card->hw.dpmbase);
-
- card->u.f.rxmb_last =
- (void*)(buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
- card->hw.dpmbase);
- }else{
- buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
-
- card->rxmb = (void*)(buf_info->rse_next -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- card->u.f.rxmb_base =
- (void*)(buf_info->rse_base -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- card->u.f.rxmb_last =
- (void*)(buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) -
- FR_MB_VECTOR + card->hw.dpmbase);
- }
-
- card->u.f.rx_base = buf_info->buf_base;
- card->u.f.rx_top = buf_info->buf_top;
-
- card->u.f.tx_interrupts_pending = 0;
-
- card->wandev.mtu = conf->mtu;
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->poll = NULL;
- card->exec = &wpf_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- card->wandev.state = WAN_DISCONNECTED;
- card->wandev.ttl = conf->ttl;
- card->wandev.udp_port = conf->udp_port;
- card->disable_comm = &disable_comm;
- card->u.f.arp_dev = NULL;
-
- /* Intialize global statistics for a card */
- init_global_statistics( card );
-
- card->TracingEnabled = 0;
-
- /* Interrupt Test */
- Intr_test_counter = 0;
- card->intr_mode = INTR_TEST_MODE;
- err = intr_test( card );
-
- printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n",
- card->devname,err,Intr_test_counter);
-
- if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
- printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n",
- card->devname, Intr_test_counter);
- printk(KERN_ERR "Please choose another interrupt\n");
- err = -EIO;
- return err;
- }
-
- printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
- card->devname, Intr_test_counter);
-
-
- /* Apr 28 2000. Nenad Corbic
- * Enable commnunications here, not in if_open or new_if, since
- * interfaces come down when the link is disconnected.
- */
-
- /* If you enable comms and then set ints, you get a Tx int as you
- * perform the SET_INT_TRIGGERS command. So, we only set int
- * triggers and then adjust the interrupt mask (to disable Tx ints)
- * before enabling comms.
- */
- if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY |
- FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) ,
- card->wandev.mtu, 0)) {
- return -EIO;
- }
-
- flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER);
-
- if (fr_comm_enable(card)) {
- return -EIO;
- }
- wanpipe_set_state(card, WAN_CONNECTED);
- spin_lock_init(&card->u.f.if_send_lock);
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics.
- */
-static int update(struct wan_device* wandev)
-{
- volatile sdla_t* card;
- unsigned long timeout;
- fr508_flags_t* flags;
-
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
-
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- card = wandev->private;
- flags = card->flags;
-
-
- card->u.f.update_comms_stats = 1;
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
- flags->imask |= FR_INTR_TIMER;
- timeout = jiffies;
- for(;;) {
- if(card->u.f.update_comms_stats == 0)
- break;
- if (time_after(jiffies, timeout + 1 * HZ)){
- card->u.f.update_comms_stats = 0;
- return -EAGAIN;
- }
- }
-
- return 0;
-}
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return: 0 o.k.
- * < 0 failure (channel will not be created)
- */
-static int new_if(struct wan_device* wandev, struct net_device* dev,
- wanif_conf_t* conf)
-{
- sdla_t* card = wandev->private;
- fr_channel_t* chan;
- int dlci = 0;
- int err = 0;
-
-
- if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
-
- printk(KERN_INFO "%s: Invalid interface name!\n",
- card->devname);
- return -EINVAL;
- }
-
- /* allocate and initialize private data */
- chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL);
-
- if (chan == NULL)
- return -ENOMEM;
-
- memset(chan, 0, sizeof(fr_channel_t));
- strcpy(chan->name, conf->name);
- chan->card = card;
-
- /* verify media address */
- if (isdigit(conf->addr[0])) {
-
- dlci = dec_to_uint(conf->addr, 0);
-
- if (dlci && (dlci <= HIGHEST_VALID_DLCI)) {
-
- chan->dlci = dlci;
-
- } else {
-
- printk(KERN_ERR
- "%s: Invalid DLCI %u on interface %s!\n",
- wandev->name, dlci, chan->name);
- err = -EINVAL;
- }
-
- } else {
- printk(KERN_ERR
- "%s: Invalid media address on interface %s!\n",
- wandev->name, chan->name);
- err = -EINVAL;
- }
-
- if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){
- printk(KERN_INFO
- "%s: Enabling, true interface type encoding.\n",
- card->devname);
- }
-
-
-
- /* Setup wanpipe as a router (WANPIPE) even if it is
- * a bridged DLCI, or as an API
- */
- if (strcmp(conf->usedby, "WANPIPE") == 0 ||
- strcmp(conf->usedby, "BRIDGE") == 0 ||
- strcmp(conf->usedby, "BRIDGE_N") == 0){
-
- if(strcmp(conf->usedby, "WANPIPE") == 0){
- chan->common.usedby = WANPIPE;
-
- printk(KERN_INFO "%s: Running in WANPIPE mode.\n",
- card->devname);
-
- }else if(strcmp(conf->usedby, "BRIDGE") == 0){
-
- chan->common.usedby = BRIDGE;
-
- printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n",
- card->devname);
- }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){
-
- chan->common.usedby = BRIDGE_NODE;
-
- printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n",
- card->devname);
- }
-
- if (!err){
- /* Dynamic interface configuration option.
- * On disconnect, if the options is selected,
- * the interface will be brought down */
- if (conf->if_down == WANOPT_YES){
- set_bit(DYN_OPT_ON,&chan->interface_down);
- printk(KERN_INFO
- "%s: Dynamic interface configuration enabled.\n",
- card->devname);
- }
- }
-
- } else if(strcmp(conf->usedby, "API") == 0){
-
- chan->common.usedby = API;
- printk(KERN_INFO "%s: Running in API mode.\n",
- wandev->name);
- }
-
- if (err) {
-
- kfree(chan);
- return err;
- }
-
- /* place cir,be,bc and other channel specific information into the
- * chan structure
- */
- if (conf->cir) {
-
- chan->cir = max_t(unsigned int, 1,
- min_t(unsigned int, conf->cir, 512));
- chan->cir_status = CIR_ENABLED;
-
-
- /* If CIR is enabled, force BC to equal CIR
- * this solves number of potential problems if CIR is
- * set and BC is not
- */
- chan->bc = chan->cir;
-
- if (conf->be){
- chan->be = max_t(unsigned int,
- 0, min_t(unsigned int, conf->be, 511));
- }else{
- conf->be = 0;
- }
-
- printk (KERN_INFO "%s: CIR enabled for DLCI %i \n",
- wandev->name,chan->dlci);
- printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n",
- wandev->name,chan->cir,chan->bc,chan->be);
-
-
- }else{
- chan->cir_status = CIR_DISABLED;
- printk (KERN_INFO "%s: CIR disabled for DLCI %i\n",
- wandev->name,chan->dlci);
- }
-
- chan->mc = conf->mc;
-
- if (conf->inarp == WANOPT_YES){
- printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname);
- chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE;
- chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10;
- }else{
- printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname);
- chan->inarp = INARP_NONE;
- chan->inarp_interval = 10;
- }
-
-
- chan->dlci_configured = DLCI_NOT_CONFIGURED;
-
-
- /*FIXME: IPX disabled in this WANPIPE version */
- if (conf->enable_IPX == WANOPT_YES){
- printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n",
- card->devname);
- kfree(chan);
- return -EINVAL;
- }else{
- chan->enable_IPX = WANOPT_NO;
- }
-
- if (conf->network_number){
- chan->network_number = conf->network_number;
- }else{
- chan->network_number = 0xDEADBEEF;
- }
-
- chan->route_flag = NO_ROUTE;
-
- init_chan_statistics(chan);
-
- chan->transmit_length = 0;
-
- /* prepare network device data space for registration */
- strcpy(dev->name,chan->name);
-
- dev->init = &if_init;
- dev->priv = chan;
-
- /* Initialize FR Polling Task Queue
- * We need a poll routine for each network
- * interface.
- */
- INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev);
-
- init_timer(&chan->fr_arp_timer);
- chan->fr_arp_timer.data=(unsigned long)dev;
- chan->fr_arp_timer.function = fr_arp;
-
- wandev->new_if_cnt++;
-
- /* Tells us that if this interface is a
- * gateway or not */
- if ((chan->gateway = conf->gateway) == WANOPT_YES){
- printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
- card->devname,dev->name);
- }
-
- /* M. Grant Patch Apr 28 2000
- * Disallow duplicate dlci configurations. */
- if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) {
- kfree(chan);
- return -EBUSY;
- }
-
- /* Configure this dlci at a later date, when
- * the interface comes up. i.e. when if_open()
- * executes */
- set_bit(0,&chan->config_dlci);
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-/*============================================================================
- * Delete logical channel.
- */
-static int del_if(struct wan_device* wandev, struct net_device* dev)
-{
- fr_channel_t* chan = dev->priv;
- unsigned long smp_flags=0;
-
- /* This interface is dead, make sure the
- * ARP timer is stopped */
- del_timer(&chan->fr_arp_timer);
-
- /* If we are a NODE, we must unconfigure this DLCI
- * Trigger an unconfigure command that will
- * be executed in timer interrupt. We must wait
- * for the command to complete. */
- trigger_unconfig_fr(dev);
-
- lock_adapter_irq(&wandev->lock, &smp_flags);
- wandev->new_if_cnt--;
- unlock_adapter_irq(&wandev->lock, &smp_flags);
-
- return 0;
-}
-
-
-/*=====================================================================
- * disable_comm
- *
- * Description:
- * Disable communications.
- * This code runs in shutdown (sdlamain.c)
- * under critical flag. Therefore it is not
- * necessary to set a critical flag here
- *
- * Usage:
- * Commnunications are disabled only on a card
- * shutdown.
- */
-
-static void disable_comm (sdla_t *card)
-{
- printk(KERN_INFO "%s: Disabling Communications!\n",
- card->devname);
- fr_comm_disable(card);
-}
-
-/****** WANPIPE-specific entry points ***************************************/
-
-/*============================================================================
- * Execute adapter interface command.
- */
-static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err, len;
- fr_cmd_t cmd;
-
- if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
- return -EFAULT;
-
- /* execute command */
- do
- {
- memcpy(&mbox->cmd, &cmd, sizeof(cmd));
-
- if (cmd.length){
- if( copy_from_user((void*)&mbox->data, u_data, cmd.length))
- return -EFAULT;
- }
-
- if (sdla_exec(mbox))
- err = mbox->cmd.result;
-
- else return -EIO;
-
- } while (err && retry-- && fr_event(card, err, mbox));
-
- /* return result */
- if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t)))
- return -EFAULT;
-
- len = mbox->cmd.length;
-
- if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len))
- return -EFAULT;
- return 0;
-}
-
-/****** Network Device Interface ********************************************/
-
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration. Returning anything but zero will fail interface
- * registration.
- */
-static int if_init(struct net_device* dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- struct wan_device* wandev = &card->wandev;
-
- /* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = NULL;
- dev->rebuild_header = &if_rebuild_hdr;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
- dev->tx_timeout = &if_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- if (chan->common.usedby == WANPIPE || chan->common.usedby == API){
-
- /* Initialize media-specific parameters */
- if (chan->true_if_encoding){
- dev->type = ARPHRD_DLCI; /* This breaks tcpdump */
- }else{
- dev->type = ARPHRD_PPP; /* ARP h/w type */
- }
-
- dev->flags |= IFF_POINTOPOINT;
- dev->flags |= IFF_NOARP;
-
- /* Enable Multicast addressing */
- if (chan->mc == WANOPT_YES){
- dev->flags |= IFF_MULTICAST;
- }
-
- dev->mtu = wandev->mtu - FR_HEADER_LEN;
- /* For an API, the maximum number of bytes that the stack will pass
- to the driver is (dev->mtu + dev->hard_header_len). So, adjust the
- mtu so that a frame of maximum size can be transmitted by the API.
- */
- if(chan->common.usedby == API) {
- dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN);
- }
-
- dev->hard_header_len = FR_HEADER_LEN;/* media header length */
- dev->addr_len = 2; /* hardware address length */
- *(unsigned short*)dev->dev_addr = htons(chan->dlci);
-
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 100;
-
- }else{
-
- /* Setup the interface for Bridging */
- int hw_addr=0;
- ether_setup(dev);
-
- /* Use a random number to generate the MAC address */
- memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6);
- get_random_bytes(&hw_addr, sizeof(hw_addr));
- *(int *)(dev->dev_addr + 2) += hw_addr;
- }
-
- /* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
- SET_MODULE_OWNER(dev);
-
- return 0;
-}
-
-/*============================================================================
- * Open network interface.
- * o if this is the first open, then enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
-static int if_open(struct net_device* dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- int err = 0;
- struct timeval tv;
-
- if (netif_running(dev))
- return -EBUSY;
-
- /* Initialize the task queue */
- chan->tq_working=0;
-
- INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev);
-
- /* Allocate and initialize BH circular buffer */
- chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC);
- memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF));
- atomic_set(&chan->bh_buff_used, 0);
-
- netif_start_queue(dev);
-
- wanpipe_open(card);
- do_gettimeofday( &tv );
- chan->router_start_time = tv.tv_sec;
-
- if (test_bit(0,&chan->config_dlci)){
- trigger_config_fr (card);
- }else if (chan->inarp == INARP_REQUEST){
- trigger_fr_arp(dev);
- }
-
- return err;
-}
-
-/*============================================================================
- * Close network interface.
- * o if this is the last open, then disable communications and interrupts.
- * o reset flags.
- */
-static int if_close(struct net_device* dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
-
- if (chan->inarp == INARP_CONFIGURED) {
- chan->inarp = INARP_REQUEST;
- }
-
- netif_stop_queue(dev);
- wanpipe_close(card);
-
- return 0;
-}
-
-/*============================================================================
- * Re-build media header.
- *
- * Return: 1 physical address resolved.
- * 0 physical address not resolved
- */
-static int if_rebuild_hdr (struct sk_buff* skb)
-{
- struct net_device *dev = skb->dev;
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
-
- printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, dev->name);
- return 1;
-}
-
-/*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
-static void if_tx_timeout(struct net_device *dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
- /* If our device stays busy for at least 5 seconds then we will
- * kick start the device by making dev->tbusy = 0. We expect
- * that our device never stays busy more than 5 seconds. So this
- * is only used as a last resort.
- */
-
- chan->drvstats_if_send.if_send_tbusy++;
- ++chan->ifstats.collisions;
-
- printk (KERN_INFO "%s: Transmit timed out on %s\n",
- card->devname, dev->name);
- chan->drvstats_if_send.if_send_tbusy_timeout++;
- netif_wake_queue (dev);
-
-}
-
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- * transmit from overlapping.
- * o set critical flag when accessing board.
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- *
- * 2. Using netif_start_queue() and netif_stop_queue()
- * will inhibit further transmit requests from the protocol stack
- * and can be used for flow control with protocol layer.
- */
-static int if_send(struct sk_buff* skb, struct net_device* dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- int err;
- unsigned char *sendpacket;
- fr508_flags_t* adptr_flags = card->flags;
- int udp_type;
- long delay_tx_queued = 0;
- unsigned long smp_flags=0;
- unsigned char attr = 0;
-
- chan->drvstats_if_send.if_send_entry++;
-
- netif_stop_queue(dev);
-
- if (skb == NULL) {
- /* if we get here, some higher layer thinks we've missed an
- * tx-done interrupt.
- */
- printk(KERN_INFO "%s: interface %s got kicked!\n",
- card->devname, dev->name);
- chan->drvstats_if_send.if_send_skb_null ++;
-
- netif_wake_queue(dev);
- return 0;
- }
-
- /* If a peripheral task is running just drop packets */
- if (test_bit(PERI_CRIT, &card->wandev.critical)){
-
- printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n",
- card->devname);
-
- dev_kfree_skb_any(skb);
- netif_start_queue(dev);
- return 0;
- }
-
- /* We must set the 'tbusy' flag if we already have a packet queued for
- transmission in the transmit interrupt handler. However, we must
- ensure that the transmit interrupt does not reset the 'tbusy' flag
- just before we set it, as this will result in a "transmit timeout".
- */
- set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
- if(chan->transmit_length) {
- netif_stop_queue(dev);
- chan->tick_counter = jiffies;
- clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
- return 1;
- }
- clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical);
-
- /* Move the if_header() code to here. By inserting frame
- * relay header in if_header() we would break the
- * tcpdump and other packet sniffers */
- chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby);
- if (chan->fr_header_len < 0 ){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
-
- dev_kfree_skb_any(skb);
- netif_start_queue(dev);
- return 0;
- }
-
- sendpacket = skb->data;
-
- udp_type = udp_pkt_type(skb, card);
-
- if(udp_type != UDP_INVALID_TYPE) {
- if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb,
- chan->dlci)) {
- adptr_flags->imask |= FR_INTR_TIMER;
- if (udp_type == UDP_FPIPE_TYPE){
- chan->drvstats_if_send.
- if_send_PIPE_request ++;
- }
- }
- netif_start_queue(dev);
- return 0;
- }
-
- //FIXME: can we do better than sendpacket[2]?
- if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) {
-
- /* check to see if the source IP address is a broadcast or */
- /* multicast IP address */
- if(chk_bcast_mcast_addr(card, dev, skb)){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- dev_kfree_skb_any(skb);
- netif_start_queue(dev);
- return 0;
- }
- }
-
-
- /* Lock the S514/S508 card: SMP Supported */
- s508_s514_lock(card,&smp_flags);
-
- if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
-
- chan->drvstats_if_send.if_send_critical_non_ISR ++;
- chan->ifstats.tx_dropped ++;
- printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n",
- card->devname);
- goto if_send_start_and_exit;
- }
-
- /* API packet check: minimum packet size must be greater than
- * 16 byte API header */
- if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) {
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
-
-
- goto if_send_start_and_exit;
-
- }else{
- /* During API transmission, get rid of the API header */
- if (chan->common.usedby == API) {
- api_tx_hdr_t* api_tx_hdr;
- api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00];
- attr = api_tx_hdr->attr;
- skb_pull(skb,sizeof(api_tx_hdr_t));
- }
- }
-
- if (card->wandev.state != WAN_CONNECTED) {
- chan->drvstats_if_send.if_send_wan_disconnected ++;
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
-
- } else if (chan->common.state != WAN_CONNECTED) {
- chan->drvstats_if_send.if_send_dlci_disconnected ++;
-
- /* Update the DLCI state in timer interrupt */
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE;
- adptr_flags->imask |= FR_INTR_TIMER;
-
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
-
- } else if (!is_tx_ready(card, chan)) {
- /* No tx buffers available, store for delayed transmit */
- if (!setup_for_delayed_transmit(dev, skb)){
- set_bit(1,&delay_tx_queued);
- }
- chan->drvstats_if_send.if_send_no_bfrs++;
-
- } else if (!skb->protocol) {
- /* No protocols drop packet */
- chan->drvstats_if_send.if_send_protocol_error ++;
- ++card->wandev.stats.tx_errors;
-
- } else if (test_bit(ARP_CRIT,&card->wandev.critical)){
- /* We are trying to send an ARP Packet, block IP data until
- * ARP is sent */
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
-
- } else {
- //FIXME: IPX is not implemented in this version of Frame Relay ?
- if((chan->common.usedby == WANPIPE) &&
- sendpacket[1] == 0x00 &&
- sendpacket[2] == 0x80 &&
- sendpacket[6] == 0x81 &&
- sendpacket[7] == 0x37) {
-
- if( chan->enable_IPX ) {
- switch_net_numbers(sendpacket,
- chan->network_number, 0);
- } else {
- //FIXME: Take this out when IPX is fixed
- printk(KERN_INFO
- "%s: WARNING: Unsupported IPX data in send, packet dropped\n",
- card->devname);
- }
-
- }else{
- err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len);
- if (err) {
- switch(err) {
- case FRRES_CIR_OVERFLOW:
- case FRRES_BUFFER_OVERFLOW:
- if (!setup_for_delayed_transmit(dev, skb)){
- set_bit(1,&delay_tx_queued);
- }
- chan->drvstats_if_send.
- if_send_adptr_bfrs_full ++;
- break;
-
- case FRRES_TOO_LONG:
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Error: Frame too long, transmission failed %i\n",
- card->devname, (unsigned int)skb->len);
- }
- /* Drop down to default */
- default:
- chan->drvstats_if_send.
- if_send_dlci_disconnected ++;
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
- } else {
- chan->drvstats_if_send.
- if_send_bfr_passed_to_adptr++;
- ++chan->ifstats.tx_packets;
- ++card->wandev.stats.tx_packets;
-
- chan->ifstats.tx_bytes += skb->len;
- card->wandev.stats.tx_bytes += skb->len;
- dev->trans_start = jiffies;
- }
- }
- }
-
-if_send_start_and_exit:
-
- netif_start_queue(dev);
-
- /* If we queued the packet for transmission, we must not
- * deallocate it. The packet is unlinked from the IP stack
- * not copied. Therefore, we must keep the original packet */
- if (!test_bit(1,&delay_tx_queued)) {
- dev_kfree_skb_any(skb);
- }else{
- adptr_flags->imask |= FR_INTR_TXRDY;
- card->u.f.tx_interrupts_pending ++;
- }
-
- clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
-
- s508_s514_unlock(card,&smp_flags);
-
- return 0;
-}
-
-
-
-/*============================================================================
- * Setup so that a frame can be transmitted on the occurrence of a transmit
- * interrupt.
- */
-static int setup_for_delayed_transmit(struct net_device* dev,
- struct sk_buff *skb)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- fr_dlci_interface_t* dlci_interface;
- int len = skb->len;
-
- /* Check that the dlci is properly configured,
- * before using tx interrupt */
- if (!chan->dlci_int_interface){
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: ERROR on DLCI %i: Not configured properly !\n",
- card->devname, chan->dlci);
- printk(KERN_INFO "%s: Please contact Sangoma Technologies\n",
- card->devname);
- }
- return 1;
- }
-
- dlci_interface = chan->dlci_int_interface;
-
- if(chan->transmit_length) {
- printk(KERN_INFO "%s: Big mess in setup_for_del...\n",
- card->devname);
- return 1;
- }
-
- if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) {
- //FIXME: increment some statistic */
- return 1;
- }
-
- chan->transmit_length = len;
- chan->delay_skb = skb;
-
- dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
- dlci_interface->packet_length = len;
-
- /* Turn on TX interrupt at the end of if_send */
- return 0;
-}
-
-
-/*============================================================================
- * Check to see if the packet to be transmitted contains a broadcast or
- * multicast source IP address.
- * Return 0 if not broadcast/multicast address, otherwise return 1.
- */
-
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
- struct sk_buff *skb)
-{
- u32 src_ip_addr;
- u32 broadcast_ip_addr = 0;
- struct in_device *in_dev;
- fr_channel_t* chan = dev->priv;
-
- /* read the IP source address from the outgoing packet */
- src_ip_addr = *(u32 *)(skb->data + 14);
-
- /* read the IP broadcast address for the device */
- in_dev = dev->ip_ptr;
- if(in_dev != NULL) {
- struct in_ifaddr *ifa= in_dev->ifa_list;
- if(ifa != NULL)
- broadcast_ip_addr = ifa->ifa_broadcast;
- else
- return 0;
- }
-
- /* check if the IP Source Address is a Broadcast address */
- if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
- printk(KERN_INFO
- "%s: Broadcast Source Address silently discarded\n",
- card->devname);
- return 1;
- }
-
- /* check if the IP Source Address is a Multicast address */
- if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) &&
- (ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
- printk(KERN_INFO
- "%s: Multicast Source Address silently discarded\n",
- card->devname);
- return 1;
- }
-
- return 0;
-}
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return nothing.
- */
-static int reply_udp( unsigned char *data, unsigned int mbox_len )
-{
- unsigned short len, udp_length, temp, ip_length;
- unsigned long ip_temp;
- int even_bound = 0;
-
-
- fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data;
-
- /* Set length of packet */
- len = //sizeof(fr_encap_hdr_t)+
- sizeof(ip_pkt_t)+
- sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
-
- /* fill in UDP reply */
- fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
-
- /* fill in UDP length */
- udp_length = sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
-
- /* put it on an even boundary */
- if ( udp_length & 0x0001 ) {
- udp_length += 1;
- len += 1;
- even_bound = 1;
- }
-
- temp = (udp_length<<8)|(udp_length>>8);
- fr_udp_pkt->udp_pkt.udp_length = temp;
-
- /* swap UDP ports */
- temp = fr_udp_pkt->udp_pkt.udp_src_port;
- fr_udp_pkt->udp_pkt.udp_src_port =
- fr_udp_pkt->udp_pkt.udp_dst_port;
- fr_udp_pkt->udp_pkt.udp_dst_port = temp;
-
-
-
- /* add UDP pseudo header */
- temp = 0x1100;
- *((unsigned short *)
- (fr_udp_pkt->data+mbox_len+even_bound)) = temp;
- temp = (udp_length<<8)|(udp_length>>8);
- *((unsigned short *)
- (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp;
-
- /* calculate UDP checksum */
- fr_udp_pkt->udp_pkt.udp_checksum = 0;
-
- fr_udp_pkt->udp_pkt.udp_checksum =
- calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/],
- udp_length+UDP_OFFSET);
-
- /* fill in IP length */
- ip_length = udp_length + sizeof(ip_pkt_t);
- temp = (ip_length<<8)|(ip_length>>8);
- fr_udp_pkt->ip_pkt.total_length = temp;
-
- /* swap IP addresses */
- ip_temp = fr_udp_pkt->ip_pkt.ip_src_address;
- fr_udp_pkt->ip_pkt.ip_src_address =
- fr_udp_pkt->ip_pkt.ip_dst_address;
- fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
-
-
- /* fill in IP checksum */
- fr_udp_pkt->ip_pkt.hdr_checksum = 0;
- fr_udp_pkt->ip_pkt.hdr_checksum =
- calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0],
- sizeof(ip_pkt_t));
-
- return len;
-} /* reply_udp */
-
-unsigned short calc_checksum (char *data, int len)
-{
- unsigned short temp;
- unsigned long sum=0;
- int i;
-
- for( i = 0; i <len; i+=2 ) {
- memcpy(&temp,&data[i],2);
- sum += (unsigned long)temp;
- }
-
- while (sum >> 16 ) {
- sum = (sum & 0xffffUL) + (sum >> 16);
- }
-
- temp = (unsigned short)sum;
- temp = ~temp;
-
- if( temp == 0 )
- temp = 0xffff;
-
- return temp;
-}
-
-/*
- If incoming is 0 (outgoing)- if the net numbers is ours make it 0
- if incoming is 1 - if the net number is 0 make it ours
-
-*/
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
-{
- unsigned long pnetwork_number;
-
- pnetwork_number = (unsigned long)((sendpacket[14] << 24) +
- (sendpacket[15] << 16) + (sendpacket[16] << 8) +
- sendpacket[17]);
-
- if (!incoming) {
- /* If the destination network number is ours, make it 0 */
- if( pnetwork_number == network_number) {
- sendpacket[14] = sendpacket[15] = sendpacket[16] =
- sendpacket[17] = 0x00;
- }
- } else {
- /* If the incoming network is 0, make it ours */
- if( pnetwork_number == 0) {
- sendpacket[14] = (unsigned char)(network_number >> 24);
- sendpacket[15] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[16] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[17] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
-
-
- pnetwork_number = (unsigned long)((sendpacket[26] << 24) +
- (sendpacket[27] << 16) + (sendpacket[28] << 8) +
- sendpacket[29]);
-
- if( !incoming ) {
- /* If the source network is ours, make it 0 */
- if( pnetwork_number == network_number) {
- sendpacket[26] = sendpacket[27] = sendpacket[28] =
- sendpacket[29] = 0x00;
- }
- } else {
- /* If the source network is 0, make it ours */
- if( pnetwork_number == 0 ) {
- sendpacket[26] = (unsigned char)(network_number >> 24);
- sendpacket[27] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[28] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[29] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
-} /* switch_net_numbers */
-
-/*============================================================================
- * Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- */
-static struct net_device_stats *if_stats(struct net_device *dev)
-{
- fr_channel_t* chan = dev->priv;
-
- if(chan == NULL)
- return NULL;
-
- return &chan->ifstats;
-}
-
-/****** Interrupt Handlers **************************************************/
-
-/*============================================================================
- * fr_isr: S508 frame relay interrupt service routine.
- *
- * Description:
- * Frame relay main interrupt service route. This
- * function check the interrupt type and takes
- * the appropriate action.
- */
-static void fr_isr (sdla_t* card)
-{
- fr508_flags_t* flags = card->flags;
- char *ptr = &flags->iflag;
- int i,err;
- fr_mbox_t* mbox = card->mbox;
-
- /* This flag prevents nesting of interrupts. See sdla_isr() routine
- * in sdlamain.c. */
- card->in_isr = 1;
-
- ++card->statistics.isr_entry;
-
-
- /* All peripheral (configuraiton, re-configuration) events
- * take presidence over the ISR. Thus, retrigger */
- if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
- ++card->statistics.isr_already_critical;
- goto fr_isr_exit;
- }
-
- if(card->hw.type != SDLA_S514) {
- if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
- printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n",
- card->devname);
- ++card->statistics.isr_already_critical;
- goto fr_isr_exit;
- }
- }
-
- switch (flags->iflag) {
-
- case FR_INTR_RXRDY: /* receive interrupt */
- ++card->statistics.isr_rx;
- rx_intr(card);
- break;
-
-
- case FR_INTR_TXRDY: /* transmit interrupt */
- ++ card->statistics.isr_tx;
- tx_intr(card);
- break;
-
- case FR_INTR_READY:
- Intr_test_counter++;
- ++card->statistics.isr_intr_test;
- break;
-
- case FR_INTR_DLC: /* Event interrupt occurred */
- mbox->cmd.command = FR_READ_STATUS;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err)
- fr_event(card, err, mbox);
- break;
-
- case FR_INTR_TIMER: /* Timer interrupt */
- timer_intr(card);
- break;
-
- default:
- ++card->statistics.isr_spurious;
- spur_intr(card);
- printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n",
- card->devname, flags->iflag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
-
- break;
- }
-
-fr_isr_exit:
-
- card->in_isr = 0;
- flags->iflag = 0;
- return;
-}
-
-
-
-/*===========================================================
- * rx_intr Receive interrupt handler.
- *
- * Description
- * Upon receiveing an interrupt:
- * 1. Check that the firmware is in sync with
- * the driver.
- * 2. Find an appropriate network interface
- * based on the received dlci number.
- * 3. Check that the netowrk interface exists
- * and that it's setup properly.
- * 4. Copy the data into an skb buffer.
- * 5. Check the packet type and take
- * appropriate acton: UPD, API, ARP or Data.
- */
-
-static void rx_intr (sdla_t* card)
-{
- fr_rx_buf_ctl_t* frbuf = card->rxmb;
- fr508_flags_t* flags = card->flags;
- fr_channel_t* chan;
- char *ptr = &flags->iflag;
- struct sk_buff* skb;
- struct net_device* dev;
- void* buf;
- unsigned dlci, len, offs, len_incl_hdr;
- int i, udp_type;
-
-
- /* Check that firmware buffers are in sync */
- if (frbuf->flag != 0x01) {
-
- printk(KERN_INFO
- "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
- card->devname, (unsigned)frbuf, frbuf->flag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
-
- ++card->statistics.rx_intr_corrupt_rx_bfr;
-
- /* Bug Fix: Mar 6 2000
- * If we get a corrupted mailbox, it means that driver
- * is out of sync with the firmware. There is no recovery.
- * If we don't turn off all interrupts for this card
- * the machine will crash.
- */
- printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
- printk(KERN_INFO "Please contact Sangoma Technologies !\n");
- fr_set_intr_mode(card, 0, 0, 0);
- return;
- }
-
- len = frbuf->length;
- dlci = frbuf->dlci;
- offs = frbuf->offset;
-
- /* Find the network interface for this packet */
- dev = find_channel(card, dlci);
-
-
- /* Check that the network interface is active and
- * properly setup */
- if (dev == NULL) {
- if( net_ratelimit()) {
- printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
- card->devname, dlci);
- }
- ++card->statistics.rx_intr_on_orphaned_DLCI;
- ++card->wandev.stats.rx_dropped;
- goto rx_done;
- }
-
- if ((chan = dev->priv) == NULL){
- if( net_ratelimit()) {
- printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n",
- card->devname, dlci);
- }
- ++card->statistics.rx_intr_on_orphaned_DLCI;
- ++card->wandev.stats.rx_dropped;
- goto rx_done;
- }
-
- skb = dev_alloc_skb(len);
-
- if (!netif_running(dev) || (skb == NULL)){
-
- ++chan->ifstats.rx_dropped;
-
- if(skb == NULL) {
- if (net_ratelimit()) {
- printk(KERN_INFO
- "%s: no socket buffers available!\n",
- card->devname);
- }
- chan->drvstats_rx_intr.rx_intr_no_socket ++;
- }
-
- if (!netif_running(dev)){
- chan->drvstats_rx_intr.
- rx_intr_dev_not_started ++;
- if (skb){
- dev_kfree_skb_any(skb);
- }
- }
- goto rx_done;
- }
-
- /* Copy data from the board into the socket buffer */
- if ((offs + len) > card->u.f.rx_top + 1) {
- unsigned tmp = card->u.f.rx_top - offs + 1;
-
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, offs, buf, tmp);
- offs = card->u.f.rx_base;
- len -= tmp;
- }
-
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, offs, buf, len);
-
-
- /* We got the packet from the bard.
- * Check the packet type and take appropriate action */
-
- udp_type = udp_pkt_type( skb, card );
-
- if(udp_type != UDP_INVALID_TYPE) {
-
- /* UDP Debug packet received, store the
- * packet and handle it in timer interrupt */
-
- skb_pull(skb, 1);
- if (wanrouter_type_trans(skb, dev)){
- if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){
-
- flags->imask |= FR_INTR_TIMER;
-
- if (udp_type == UDP_FPIPE_TYPE){
- ++chan->drvstats_rx_intr.rx_intr_PIPE_request;
- }
- }
- }
-
- }else if (chan->common.usedby == API) {
-
- /* We are in API mode.
- * Add an API header to the RAW packet
- * and queue it into a circular buffer.
- * Then kick the fr_bh() bottom half handler */
-
- api_rx_hdr_t* api_rx_hdr;
- chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++;
- chan->ifstats.rx_packets ++;
- card->wandev.stats.rx_packets ++;
-
- chan->ifstats.rx_bytes += skb->len;
- card->wandev.stats.rx_bytes += skb->len;
-
- skb_push(skb, sizeof(api_rx_hdr_t));
- api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00];
- api_rx_hdr->attr = frbuf->attr;
- api_rx_hdr->time_stamp = frbuf->tmstamp;
-
- skb->protocol = htons(ETH_P_IP);
- skb->mac.raw = skb->data;
- skb->dev = dev;
- skb->pkt_type = WAN_PACKET_DATA;
-
- bh_enqueue(dev, skb);
-
- trigger_fr_bh(chan);
-
- }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){
-
- //FIXME: Frame Relay IPX is not supported, Yet !
- //if (chan->enable_IPX) {
- // fr_send(card, dlci, 0, skb->len,skb->data);
- //}
- dev_kfree_skb_any(skb);
-
- } else if (is_arp(skb->data)) {
-
- /* ARP support enabled Mar 16 2000
- * Process incoming ARP reply/request, setup
- * dynamic routes. */
-
- if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) {
- if (net_ratelimit()){
- printk (KERN_INFO
- "%s: Error processing ARP Packet.\n",
- card->devname);
- }
- }
- dev_kfree_skb_any(skb);
-
- } else if (skb->data[0] != 0x03) {
-
- if (net_ratelimit()) {
- printk(KERN_INFO "%s: Non IETF packet discarded.\n",
- card->devname);
- }
- dev_kfree_skb_any(skb);
-
- } else {
-
- len_incl_hdr = skb->len;
- /* Decapsulate packet and pass it up the
- protocol stack */
- skb->dev = dev;
-
- if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){
-
- /* Make sure it's an Ethernet frame, otherwise drop it */
- if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) {
- skb_pull(skb, 8);
- skb->protocol=eth_type_trans(skb,dev);
- }else{
- ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack;
- ++chan->ifstats.rx_errors;
- ++card->wandev.stats.rx_errors;
- goto rx_done;
- }
- }else{
-
- /* remove hardware header */
- buf = skb_pull(skb, 1);
-
- if (!wanrouter_type_trans(skb, dev)) {
-
- /* can't decapsulate packet */
- dev_kfree_skb_any(skb);
-
- ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack;
- ++chan->ifstats.rx_errors;
- ++card->wandev.stats.rx_errors;
- goto rx_done;
- }
- skb->mac.raw = skb->data;
- }
-
-
- /* Send a packet up the IP stack */
- skb->dev->last_rx = jiffies;
- netif_rx(skb);
- ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack;
- ++chan->ifstats.rx_packets;
- ++card->wandev.stats.rx_packets;
-
- chan->ifstats.rx_bytes += len_incl_hdr;
- card->wandev.stats.rx_bytes += len_incl_hdr;
- }
-
-rx_done:
-
- /* Release buffer element and calculate a pointer to the next one */
- frbuf->flag = 0;
- card->rxmb = ++frbuf;
- if ((void*)frbuf > card->u.f.rxmb_last)
- card->rxmb = card->u.f.rxmb_base;
-
-}
-
-/*==================================================================
- * tx_intr: Transmit interrupt handler.
- *
- * Rationale:
- * If the board is busy transmitting, if_send() will
- * buffers a single packet and turn on
- * the tx interrupt. Tx interrupt will be called
- * by the board, once the firmware can send more
- * data. Thus, no polling is required.
- *
- * Description:
- * Tx interrupt is called for each
- * configured dlci channel. Thus:
- * 1. Obtain the netowrk interface based on the
- * dlci number.
- * 2. Check that network interface is up and
- * properly setup.
- * 3. Check for a buffered packet.
- * 4. Transmit the packet.
- * 5. If we are in WANPIPE mode, mark the
- * NET_BH handler.
- * 6. If we are in API mode, kick
- * the AF_WANPIPE socket for more data.
- *
- */
-static void tx_intr(sdla_t *card)
-{
- fr508_flags_t* flags = card->flags;
- fr_tx_buf_ctl_t* bctl;
- struct net_device* dev;
- fr_channel_t* chan;
-
- if(card->hw.type == SDLA_S514){
- bctl = (void*)(flags->tse_offs + card->hw.dpmbase);
- }else{
- bctl = (void*)(flags->tse_offs - FR_MB_VECTOR +
- card->hw.dpmbase);
- }
-
- /* Find the structure and make it unbusy */
- dev = find_channel(card, flags->dlci);
- if (dev == NULL){
- printk(KERN_INFO "NO DEV IN TX Interrupt\n");
- goto end_of_tx_intr;
- }
-
- if ((chan = dev->priv) == NULL){
- printk(KERN_INFO "NO CHAN IN TX Interrupt\n");
- goto end_of_tx_intr;
- }
-
- if(!chan->transmit_length || !chan->delay_skb) {
- printk(KERN_INFO "%s: tx int error - transmit length zero\n",
- card->wandev.name);
- goto end_of_tx_intr;
- }
-
- /* If the 'if_send()' procedure is currently checking the 'tbusy'
- status, then we cannot transmit. Instead, we configure the microcode
- so as to re-issue this transmit interrupt at a later stage.
- */
- if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
-
- fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface;
- bctl->flag = 0xA0;
- dlci_interface->gen_interrupt |= FR_INTR_TXRDY;
- return;
-
- }else{
- bctl->dlci = flags->dlci;
- bctl->length = chan->transmit_length+chan->fr_header_len;
- sdla_poke(&card->hw,
- fr_send_hdr(card,bctl->dlci,bctl->offset),
- chan->delay_skb->data,
- chan->delay_skb->len);
- bctl->flag = 0xC0;
-
- ++chan->ifstats.tx_packets;
- ++card->wandev.stats.tx_packets;
- chan->ifstats.tx_bytes += chan->transmit_length;
- card->wandev.stats.tx_bytes += chan->transmit_length;
-
- /* We must free an sk buffer, which we used
- * for delayed transmission; Otherwise, the sock
- * will run out of memory */
- dev_kfree_skb_any(chan->delay_skb);
-
- chan->delay_skb = NULL;
- chan->transmit_length = 0;
-
- dev->trans_start = jiffies;
-
- if (netif_queue_stopped(dev)){
- /* If using API, than wakeup socket BH handler */
- if (chan->common.usedby == API){
- netif_start_queue(dev);
- wakeup_sk_bh(dev);
- }else{
- netif_wake_queue(dev);
- }
- }
- }
-
-end_of_tx_intr:
-
- /* if any other interfaces have transmit interrupts pending,
- * do not disable the global transmit interrupt */
- if(!(-- card->u.f.tx_interrupts_pending))
- flags->imask &= ~FR_INTR_TXRDY;
-
-
-}
-
-
-/*============================================================================
- * timer_intr: Timer interrupt handler.
- *
- * Rationale:
- * All commans must be executed within the timer
- * interrupt since no two commands should execute
- * at the same time.
- *
- * Description:
- * The timer interrupt is used to:
- * 1. Processing udp calls from 'fpipemon'.
- * 2. Processing update calls from /proc file system
- * 3. Reading board-level statistics for
- * updating the proc file system.
- * 4. Sending inverse ARP request packets.
- * 5. Configure a dlci/channel.
- * 6. Unconfigure a dlci/channel. (Node only)
- */
-
-static void timer_intr(sdla_t *card)
-{
- fr508_flags_t* flags = card->flags;
-
- /* UDP Debuging: fpipemon call */
- if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) {
- if(card->u.f.udp_type == UDP_FPIPE_TYPE) {
- if(process_udp_mgmt_pkt(card)) {
- card->u.f.timer_int_enabled &=
- ~TMR_INT_ENABLED_UDP;
- }
- }
- }
-
- /* /proc update call : triggered from update() */
- if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
- fr_get_err_stats(card);
- fr_get_stats(card);
- card->u.f.update_comms_stats = 0;
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
- }
-
- /* Update the channel state call. This is call is
- * triggered by if_send() function */
- if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){
- struct net_device *dev;
- if (card->wandev.state == WAN_CONNECTED){
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)){
- fr_channel_t *chan = dev->priv;
- if (chan->common.state != WAN_CONNECTED){
- update_chan_state(dev);
- }
- }
- }
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE;
- }
-
- /* configure a dlci/channel */
- if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){
- config_fr(card);
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
- }
-
- /* unconfigure a dlci/channel */
- if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){
- unconfig_fr(card);
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
- }
-
-
- /* Transmit ARP packets */
- if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){
- int i=0;
- struct net_device *dev;
-
- if (card->u.f.arp_dev == NULL)
- card->u.f.arp_dev = card->wandev.dev;
-
- dev = card->u.f.arp_dev;
-
- for (;;){
-
- fr_channel_t *chan = dev->priv;
-
- /* If the interface is brought down cancel sending In-ARPs */
- if (!(dev->flags&IFF_UP)){
- clear_bit(0,&chan->inarp_ready);
- }
-
- if (test_bit(0,&chan->inarp_ready)){
-
- if (check_tx_status(card,dev)){
- set_bit(ARP_CRIT,&card->wandev.critical);
- break;
- }
-
- if (!send_inarp_request(card,dev)){
- trigger_fr_arp(dev);
- chan->inarp_tick = jiffies;
- }
-
- clear_bit(0,&chan->inarp_ready);
- dev = move_dev_to_next(card,dev);
- break;
- }
- dev = move_dev_to_next(card,dev);
-
- if (++i == card->wandev.new_if_cnt){
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP;
- break;
- }
- }
- card->u.f.arp_dev = dev;
- }
-
- if(!card->u.f.timer_int_enabled)
- flags->imask &= ~FR_INTR_TIMER;
-}
-
-
-/*============================================================================
- * spur_intr: Spurious interrupt handler.
- *
- * Description:
- * We don't know this interrupt.
- * Print a warning.
- */
-
-static void spur_intr (sdla_t* card)
-{
- if (net_ratelimit()){
- printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
- }
-}
-
-
-//FIXME: Fix the IPX in next version
-/*===========================================================================
- * Return 0 for non-IPXWAN packet
- * 1 for IPXWAN packet or IPX is not enabled!
- * FIXME: Use a IPX structure here not offsets
- */
-static int handle_IPXWAN(unsigned char *sendpacket,
- char *devname, unsigned char enable_IPX,
- unsigned long network_number)
-{
- int i;
-
- if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 &&
- sendpacket[6] == 0x81 && sendpacket[7] == 0x37) {
-
- /* It's an IPX packet */
- if (!enable_IPX){
- /* Return 1 so we don't pass it up the stack. */
- //FIXME: Take this out when IPX is fixed
- if (net_ratelimit()){
- printk (KERN_INFO
- "%s: WARNING: Unsupported IPX packet received and dropped\n",
- devname);
- }
- return 1;
- }
- } else {
- /* It's not IPX so return and pass it up the stack. */
- return 0;
- }
-
- if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){
- /* It's IPXWAN */
-
- if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){
-
- /* It's a timer request packet */
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",
- devname);
-
- /* Go through the routing options and answer no to every
- * option except Unnumbered RIP/SAP
- */
- for(i = 49; sendpacket[i] == 0x00; i += 5){
- /* 0x02 is the option for Unnumbered RIP/SAP */
- if( sendpacket[i + 4] != 0x02){
- sendpacket[i + 1] = 0;
- }
- }
-
- /* Skip over the extended Node ID option */
- if( sendpacket[i] == 0x04 ){
- i += 8;
- }
-
- /* We also want to turn off all header compression opt.
- */
- for(; sendpacket[i] == 0x80 ;){
- sendpacket[i + 1] = 0;
- i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
- }
-
- /* Set the packet type to timer response */
- sendpacket[42] = 0x01;
-
- printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",
- devname);
-
- } else if( sendpacket[42] == 0x02 ){
-
- /* This is an information request packet */
- printk(KERN_INFO
- "%s: Received IPXWAN Information Request packet\n",
- devname);
-
- /* Set the packet type to information response */
- sendpacket[42] = 0x03;
-
- /* Set the router name */
- sendpacket[59] = 'F';
- sendpacket[60] = 'P';
- sendpacket[61] = 'I';
- sendpacket[62] = 'P';
- sendpacket[63] = 'E';
- sendpacket[64] = '-';
- sendpacket[65] = CVHexToAscii(network_number >> 28);
- sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24);
- sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20);
- sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16);
- sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12);
- sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8);
- sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4);
- sendpacket[72] = CVHexToAscii(network_number & 0x0000000F);
- for(i = 73; i < 107; i+= 1)
- {
- sendpacket[i] = 0;
- }
-
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",
- devname);
- } else {
-
- printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
- return 0;
- }
-
- /* Set the WNodeID to our network address */
- sendpacket[43] = (unsigned char)(network_number >> 24);
- sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16);
- sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8);
- sendpacket[46] = (unsigned char)(network_number & 0x000000FF);
-
- return 1;
- }
-
- /* If we get here, it's an IPX-data packet so it'll get passed up the
- * stack.
- * switch the network numbers
- */
- switch_net_numbers(sendpacket, network_number ,1);
- return 0;
-}
-/*============================================================================
- * process_route
- *
- * Rationale:
- * If the interface goes down, or we receive an ARP request,
- * we have to change the network interface ip addresses.
- * This cannot be done within the interrupt.
- *
- * Description:
- *
- * This routine is called as a polling routine to dynamically
- * add/delete routes negotiated by inverse ARP. It is in this
- * "task" because we don't want routes to be added while in
- * interrupt context.
- *
- * Usage:
- * This function is called by fr_poll() polling funtion.
- */
-
-static void process_route(struct net_device *dev)
-{
- fr_channel_t *chan = dev->priv;
- sdla_t *card = chan->card;
-
- struct ifreq if_info;
- struct sockaddr_in *if_data;
- mm_segment_t fs = get_fs();
- u32 ip_tmp;
- int err;
-
-
- switch(chan->route_flag){
-
- case ADD_ROUTE:
-
- /* Set remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
-
- set_fs(get_ds()); /* get user space block */
-
- if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data->sin_addr.s_addr = chan->ip_remote;
- if_data->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
-
- set_fs(fs); /* restore old block */
-
- if (err) {
- printk(KERN_INFO
- "%s: Route Add failed. Error: %d\n",
- card->devname,err);
- printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n",
- chan->name, NIPQUAD(chan->ip_remote));
-
- }else {
- printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n",
- card->devname,NIPQUAD(chan->ip_remote));
- chan->route_flag = ROUTE_ADDED;
- }
- break;
-
- case REMOVE_ROUTE:
-
- /* Set remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
-
- ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
-
- set_fs(get_ds()); /* get user space block */
-
- if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data->sin_addr.s_addr = 0;
- if_data->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
-
- set_fs(fs);
-
- if (err) {
- printk(KERN_INFO
- "%s: Deleting of route failed. Error: %d\n",
- card->devname,err);
- printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n",
- dev->name,NIPQUAD(chan->ip_remote) );
-
- } else {
- printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n",
- card->devname,NIPQUAD(ip_tmp));
- chan->route_flag = NO_ROUTE;
- }
- break;
-
- } /* Case Statement */
-
-}
-
-
-
-/****** Frame Relay Firmware-Specific Functions *****************************/
-
-/*============================================================================
- * Read firmware code version.
- * o fill string str with firmware version info.
- */
-static int fr_read_version (sdla_t* card, char* str)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- mbox->cmd.command = FR_READ_CODE_VERSION;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err && str) {
- int len = mbox->cmd.length;
- memcpy(str, mbox->data, len);
- str[len] = '\0';
- }
- return err;
-}
-
-/*============================================================================
- * Set global configuration.
- */
-static int fr_configure (sdla_t* card, fr_conf_t *conf)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int dlci_num = card->u.f.dlci_num;
- int err, i;
-
- do
- {
- memcpy(mbox->data, conf, sizeof(fr_conf_t));
-
- if (dlci_num) for (i = 0; i < dlci_num; ++i)
- ((fr_conf_t*)mbox->data)->dlci[i] =
- card->u.f.node_dlci[i];
-
- mbox->cmd.command = FR_SET_CONFIG;
- mbox->cmd.length =
- sizeof(fr_conf_t) + dlci_num * sizeof(short);
-
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && fr_event(card, err, mbox));
-
- /*NC Oct 12 2000 */
- if (err != CMD_OK){
- printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n",
- card->devname,err);
- }
-
- return err;
-}
-
-/*============================================================================
- * Set DLCI configuration.
- */
-static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t));
- mbox->cmd.dlci = (unsigned short) dlci;
- mbox->cmd.command = FR_SET_CONFIG;
- mbox->cmd.length = sizeof(fr_dlc_conf_t);
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry--);
-
- return err;
-}
-/*============================================================================
- * Set interrupt mode.
- */
-static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu,
- unsigned short timeout)
-{
- fr_mbox_t* mbox = card->mbox;
- fr508_intr_ctl_t* ictl = (void*)mbox->data;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(ictl, 0, sizeof(fr508_intr_ctl_t));
- ictl->mode = mode;
- ictl->tx_len = mtu;
- ictl->irq = card->hw.irq;
-
- /* indicate timeout on timer */
- if (mode & 0x20) ictl->timeout = timeout;
-
- mbox->cmd.length = sizeof(fr508_intr_ctl_t);
- mbox->cmd.command = FR_SET_INTR_MODE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
-}
-
-/*============================================================================
- * Enable communications.
- */
-static int fr_comm_enable (sdla_t* card)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- mbox->cmd.command = FR_COMM_ENABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
-}
-
-/*============================================================================
- * fr_comm_disable
- *
- * Warning: This functin is called by the shutdown() procedure. It is void
- * since dev->priv are has already been deallocated and no
- * error checking is possible using fr_event() function.
- */
-static void fr_comm_disable (sdla_t* card)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do {
- mbox->cmd.command = FR_SET_MODEM_STATUS;
- mbox->cmd.length = 1;
- mbox->data[0] = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry--);
-
- retry = MAX_CMD_RETRY;
-
- do
- {
- mbox->cmd.command = FR_COMM_DISABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry--);
-
- return;
-}
-
-
-
-/*============================================================================
- * Get communications error statistics.
- */
-static int fr_get_err_stats (sdla_t* card)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
-
- do
- {
- mbox->cmd.command = FR_READ_ERROR_STATS;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
- fr_comm_stat_t* stats = (void*)mbox->data;
- card->wandev.stats.rx_over_errors = stats->rx_overruns;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_aborts;
- card->wandev.stats.rx_length_errors = stats->rx_too_long;
- card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
-
- }
-
- return err;
-}
-
-/*============================================================================
- * Get statistics.
- */
-static int fr_get_stats (sdla_t* card)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
-
- do
- {
- mbox->cmd.command = FR_READ_STATISTICS;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
- fr_link_stat_t* stats = (void*)mbox->data;
- card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
- card->wandev.stats.rx_dropped =
- stats->rx_dropped + stats->rx_dropped2;
- }
-
- return err;
-}
-
-/*============================================================================
- * Add DLCI(s) (Access Node only!).
- * This routine will perform the ADD_DLCIs command for the specified DLCI.
- */
-static int fr_add_dlci (sdla_t* card, int dlci)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- unsigned short* dlci_list = (void*)mbox->data;
-
- mbox->cmd.length = sizeof(short);
- dlci_list[0] = dlci;
- mbox->cmd.command = FR_ADD_DLCI;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
-}
-
-/*============================================================================
- * Activate DLCI(s) (Access Node only!).
- * This routine will perform the ACTIVATE_DLCIs command with a DLCI number.
- */
-static int fr_activate_dlci (sdla_t* card, int dlci)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- unsigned short* dlci_list = (void*)mbox->data;
-
- mbox->cmd.length = sizeof(short);
- dlci_list[0] = dlci;
- mbox->cmd.command = FR_ACTIVATE_DLCI;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
-}
-
-/*============================================================================
- * Delete DLCI(s) (Access Node only!).
- * This routine will perform the DELETE_DLCIs command with a DLCI number.
- */
-static int fr_delete_dlci (sdla_t* card, int dlci)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- unsigned short* dlci_list = (void*)mbox->data;
-
- mbox->cmd.length = sizeof(short);
- dlci_list[0] = dlci;
- mbox->cmd.command = FR_DELETE_DLCI;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
-}
-
-
-
-/*============================================================================
- * Issue in-channel signalling frame.
- */
-static int fr_issue_isf (sdla_t* card, int isf)
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- mbox->data[0] = isf;
- mbox->cmd.length = 1;
- mbox->cmd.command = FR_ISSUE_IS_FRAME;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
-}
-
-
-static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset)
-{
- struct net_device *dev = find_channel(card,dlci);
- fr_channel_t *chan;
-
- if (!dev || !(chan=dev->priv))
- return offset;
-
- if (chan->fr_header_len){
- sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len);
- }
-
- return offset+chan->fr_header_len;
-}
-
-/*============================================================================
- * Send a frame on a selected DLCI.
- */
-static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len,
- void *buf, unsigned char hdr_len)
-{
- fr_mbox_t* mbox = card->mbox + 0x800;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- mbox->cmd.dlci = dlci;
- mbox->cmd.attr = attr;
- mbox->cmd.length = len+hdr_len;
- mbox->cmd.command = FR_WRITE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
- fr_tx_buf_ctl_t* frbuf;
-
- if(card->hw.type == SDLA_S514)
- frbuf = (void*)(*(unsigned long*)mbox->data +
- card->hw.dpmbase);
- else
- frbuf = (void*)(*(unsigned long*)mbox->data -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len);
- frbuf->flag = 0x01;
- }
-
- return err;
-}
-
-static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len,
- void *buf)
-{
- fr_mbox_t* mbox = card->mbox + 0x800;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- mbox->cmd.dlci = dlci;
- mbox->cmd.attr = attr;
- mbox->cmd.length = len;
- mbox->cmd.command = FR_WRITE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
- fr_tx_buf_ctl_t* frbuf;
-
- if(card->hw.type == SDLA_S514)
- frbuf = (void*)(*(unsigned long*)mbox->data +
- card->hw.dpmbase);
- else
- frbuf = (void*)(*(unsigned long*)mbox->data -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- sdla_poke(&card->hw, frbuf->offset, buf, len);
- frbuf->flag = 0x01;
- }
-
- return err;
-}
-
-
-/****** Firmware Asynchronous Event Handlers ********************************/
-
-/*============================================================================
- * Main asyncronous event/error handler.
- * This routine is called whenever firmware command returns non-zero
- * return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
-{
- fr508_flags_t* flags = card->flags;
- char *ptr = &flags->iflag;
- int i;
-
- switch (event) {
-
- case FRRES_MODEM_FAILURE:
- return fr_modem_failure(card, mbox);
-
- case FRRES_CHANNEL_DOWN: {
- struct net_device *dev;
-
- /* Remove all routes from associated DLCI's */
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)) {
- fr_channel_t *chan = dev->priv;
- if (chan->route_flag == ROUTE_ADDED) {
- chan->route_flag = REMOVE_ROUTE;
- }
-
- if (chan->inarp == INARP_CONFIGURED) {
- chan->inarp = INARP_REQUEST;
- }
-
- /* If the link becomes disconnected then,
- * all channels will be disconnected
- * as well.
- */
- set_chan_state(dev,WAN_DISCONNECTED);
- }
-
- wanpipe_set_state(card, WAN_DISCONNECTED);
- return 1;
- }
-
- case FRRES_CHANNEL_UP: {
- struct net_device *dev;
-
- /* FIXME: Only startup devices that are on the list */
-
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)) {
-
- set_chan_state(dev,WAN_CONNECTED);
- }
-
- wanpipe_set_state(card, WAN_CONNECTED);
- return 1;
- }
-
- case FRRES_DLCI_CHANGE:
- return fr_dlci_change(card, mbox);
-
- case FRRES_DLCI_MISMATCH:
- printk(KERN_INFO "%s: DLCI list mismatch!\n",
- card->devname);
- return 1;
-
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, mbox->cmd.command);
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i));
- printk(KERN_INFO "\n");
-
- break;
-
- case FRRES_DLCI_INACTIVE:
- break;
-
- case FRRES_CIR_OVERFLOW:
- break;
-
- case FRRES_BUFFER_OVERFLOW:
- break;
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
- , card->devname, mbox->cmd.command, event);
- }
-
- return 0;
-}
-
-/*============================================================================
- * Handle modem error.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox)
-{
- printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n",
- card->devname, mbox->data[0]);
-
- switch (mbox->cmd.command){
- case FR_WRITE:
-
- case FR_READ:
- return 0;
- }
-
- return 1;
-}
-
-/*============================================================================
- * Handle DLCI status change.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
-{
- dlci_status_t* status = (void*)mbox->data;
- int cnt = mbox->cmd.length / sizeof(dlci_status_t);
- fr_channel_t *chan;
- struct net_device* dev2;
-
-
- for (; cnt; --cnt, ++status) {
-
- unsigned short dlci= status->dlci;
- struct net_device* dev = find_channel(card, dlci);
-
- if (dev == NULL){
- printk(KERN_INFO
- "%s: CPE contains unconfigured DLCI= %d\n",
- card->devname, dlci);
-
- printk(KERN_INFO
- "%s: unconfigured DLCI %d reported by network\n"
- , card->devname, dlci);
-
- }else{
- if (status->state == FR_LINK_INOPER) {
- printk(KERN_INFO
- "%s: DLCI %u is inactive!\n",
- card->devname, dlci);
-
- if (dev && netif_running(dev))
- set_chan_state(dev, WAN_DISCONNECTED);
- }
-
- if (status->state & FR_DLCI_DELETED) {
-
- printk(KERN_INFO
- "%s: DLCI %u has been deleted!\n",
- card->devname, dlci);
-
- if (dev && netif_running(dev)){
-
- fr_channel_t *chan = dev->priv;
-
- if (chan->route_flag == ROUTE_ADDED) {
- chan->route_flag = REMOVE_ROUTE;
- /* The state change will trigger
- * the fr polling routine */
- }
-
- if (chan->inarp == INARP_CONFIGURED) {
- chan->inarp = INARP_REQUEST;
- }
-
- set_chan_state(dev, WAN_DISCONNECTED);
- }
-
- } else if (status->state & FR_DLCI_ACTIVE) {
-
- chan = dev->priv;
-
- /* This flag is used for configuring specific
- DLCI(s) when they become active.
- */
- chan->dlci_configured = DLCI_CONFIG_PENDING;
-
- set_chan_state(dev, WAN_CONNECTED);
-
- }
- }
- }
-
- for (dev2 = card->wandev.dev; dev2;
- dev2 = *((struct net_device **)dev2->priv)){
-
- chan = dev2->priv;
-
- if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
- if (fr_init_dlci(card, chan)){
- return 1;
- }
- }
-
- }
- return 1;
-}
-
-
-static int fr_init_dlci (sdla_t *card, fr_channel_t *chan)
-{
- fr_dlc_conf_t cfg;
-
- memset(&cfg, 0, sizeof(cfg));
-
- if ( chan->cir_status == CIR_DISABLED) {
-
- cfg.cir_fwd = cfg.cir_bwd = 16;
- cfg.bc_fwd = cfg.bc_bwd = 16;
- cfg.conf_flags = 0x0001;
-
- }else if (chan->cir_status == CIR_ENABLED) {
-
- cfg.cir_fwd = cfg.cir_bwd = chan->cir;
- cfg.bc_fwd = cfg.bc_bwd = chan->bc;
- cfg.be_fwd = cfg.be_bwd = chan->be;
- cfg.conf_flags = 0x0000;
- }
-
- if (fr_dlci_configure( card, &cfg , chan->dlci)){
- printk(KERN_INFO
- "%s: DLCI Configure failed for %d\n",
- card->devname, chan->dlci);
- return 1;
- }
-
- chan->dlci_configured = DLCI_CONFIGURED;
-
- /* Read the interface byte mapping into the channel
- * structure.
- */
- read_DLCI_IB_mapping( card, chan );
-
- return 0;
-}
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * Update channel state.
- */
-static int update_chan_state(struct net_device* dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err) {
-
- unsigned short* list = (void*)mbox->data;
- int cnt = mbox->cmd.length / sizeof(short);
-
- err=1;
-
- for (; cnt; --cnt, ++list) {
-
- if (*list == chan->dlci) {
- set_chan_state(dev, WAN_CONNECTED);
-
-
- /* May 23 2000. NC
- * When a dlci is added or restarted,
- * the dlci_int_interface pointer must
- * be reinitialized. */
- if (!chan->dlci_int_interface){
- err=fr_init_dlci (card,chan);
- }
- break;
- }
- }
- }
-
- return err;
-}
-
-/*============================================================================
- * Set channel state.
- */
-static void set_chan_state(struct net_device* dev, int state)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
-
- if (chan->common.state != state) {
-
- switch (state) {
-
- case WAN_CONNECTED:
- printk(KERN_INFO
- "%s: Interface %s: DLCI %d connected\n",
- card->devname, dev->name, chan->dlci);
-
- /* If the interface was previoulsy down,
- * bring it up, since the channel is active */
-
- trigger_fr_poll (dev);
- trigger_fr_arp (dev);
- break;
-
- case WAN_CONNECTING:
- printk(KERN_INFO
- "%s: Interface %s: DLCI %d connecting\n",
- card->devname, dev->name, chan->dlci);
- break;
-
- case WAN_DISCONNECTED:
- printk (KERN_INFO
- "%s: Interface %s: DLCI %d disconnected!\n",
- card->devname, dev->name, chan->dlci);
-
- /* If the interface is up, bring it down,
- * since the channel is now disconnected */
- trigger_fr_poll (dev);
- break;
- }
-
- chan->common.state = state;
- }
-
- chan->state_tick = jiffies;
-}
-
-/*============================================================================
- * Find network device by its channel number.
- *
- * We need this critical flag because we change
- * the dlci_to_dev_map outside the interrupt.
- *
- * NOTE: del_if() functions updates this array, it uses
- * the spin locks to avoid corruption.
- */
-static struct net_device* find_channel(sdla_t* card, unsigned dlci)
-{
- if(dlci > HIGHEST_VALID_DLCI)
- return NULL;
-
- return(card->u.f.dlci_to_dev_map[dlci]);
-}
-
-/*============================================================================
- * Check to see if a frame can be sent. If no transmit buffers available,
- * enable transmit interrupts.
- *
- * Return: 1 - Tx buffer(s) available
- * 0 - no buffers available
- */
-static int is_tx_ready (sdla_t* card, fr_channel_t* chan)
-{
- unsigned char sb;
-
- if(card->hw.type == SDLA_S514)
- return 1;
-
- sb = inb(card->hw.port);
- if (sb & 0x02)
- return 1;
-
- return 0;
-}
-
-/*============================================================================
- * Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted.
- */
-static unsigned int dec_to_uint (unsigned char* str, int len)
-{
- unsigned val;
-
- if (!len)
- len = strlen(str);
-
- for (val = 0; len && isdigit(*str); ++str, --len)
- val = (val * 10) + (*str - (unsigned)'0');
-
- return val;
-}
-
-
-
-/*=============================================================================
- * Store a UDP management packet for later processing.
- */
-
-static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, int dlci)
-{
- int udp_pkt_stored = 0;
-
- struct net_device *dev = find_channel(card, dlci);
- fr_channel_t *chan;
-
- if (!dev || !(chan=dev->priv))
- return 1;
-
- if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
- card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len;
- card->u.f.udp_type = udp_type;
- card->u.f.udp_pkt_src = udp_pkt_src;
- card->u.f.udp_dlci = dlci;
- memcpy(card->u.f.udp_pkt_data, skb->data, skb->len);
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP;
- udp_pkt_stored = 1;
-
- }else{
- printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n",
- dlci);
- }
-
- if(udp_pkt_src == UDP_PKT_FRM_STACK){
- dev_kfree_skb_any(skb);
- }else{
- dev_kfree_skb_any(skb);
- }
-
- return(udp_pkt_stored);
-}
-
-
-/*==============================================================================
- * Process UDP call of type FPIPE8ND
- */
-static int process_udp_mgmt_pkt(sdla_t* card)
-{
-
- int c_retry = MAX_CMD_RETRY;
- unsigned char *buf;
- unsigned char frames;
- unsigned int len;
- unsigned short buffer_length;
- struct sk_buff *new_skb;
- fr_mbox_t* mbox = card->mbox;
- int err;
- struct timeval tv;
- int udp_mgmt_req_valid = 1;
- struct net_device* dev;
- fr_channel_t* chan;
- fr_udp_pkt_t *fr_udp_pkt;
- unsigned short num_trc_els;
- fr_trc_el_t* ptr_trc_el;
- fr_trc_el_t trc_el;
- fpipemon_trc_t* fpipemon_trc;
-
- char udp_pkt_src = card->u.f.udp_pkt_src;
- int dlci = card->u.f.udp_dlci;
-
- /* Find network interface for this packet */
- dev = find_channel(card, dlci);
- if (!dev){
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
- if ((chan = dev->priv) == NULL){
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
-
- /* If the UDP packet is from the network, we are going to have to
- transmit a response. Before doing so, we must check to see that
- we are not currently transmitting a frame (in 'if_send()') and
- that we are not already in a 'delayed transmit' state.
- */
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- if (check_tx_status(card,dev)){
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
- }
-
- fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data;
-
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- switch(fr_udp_pkt->cblock.command) {
-
- case FR_READ_MODEM_STATUS:
- case FR_READ_STATUS:
- case FPIPE_ROUTER_UP_TIME:
- case FR_READ_ERROR_STATS:
- case FPIPE_DRIVER_STAT_GEN:
- case FR_READ_STATISTICS:
- case FR_READ_ADD_DLC_STATS:
- case FR_READ_CONFIG:
- case FR_READ_CODE_VERSION:
- udp_mgmt_req_valid = 1;
- break;
- default:
- udp_mgmt_req_valid = 0;
- break;
- }
- }
-
- if(!udp_mgmt_req_valid) {
- /* set length to 0 */
- fr_udp_pkt->cblock.length = 0;
- /* set return code */
- fr_udp_pkt->cblock.result = 0xCD;
-
- chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++;
-
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Warning, Illegal UDP command attempted from network: %x\n",
- card->devname,fr_udp_pkt->cblock.command);
- }
-
- } else {
-
- switch(fr_udp_pkt->cblock.command) {
-
- case FPIPE_ENABLE_TRACING:
- if(!card->TracingEnabled) {
- do {
- mbox->cmd.command = FR_SET_TRACE_CONFIG;
- mbox->cmd.length = 1;
- mbox->cmd.dlci = 0x00;
- mbox->data[0] = fr_udp_pkt->data[0] |
- RESET_TRC;
- err = sdla_exec(mbox) ?
- mbox->cmd.result : CMD_TIMEOUT;
- } while (err && c_retry-- && fr_event(card, err,
- mbox));
-
- if(err) {
- card->TracingEnabled = 0;
- /* set the return code */
- fr_udp_pkt->cblock.result =
- mbox->cmd.result;
- mbox->cmd.length = 0;
- break;
- }
-
- sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF,
- &num_trc_els, 2);
- sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF,
- &card->u.f.trc_el_base, 4);
- card->u.f.curr_trc_el = card->u.f.trc_el_base;
- card->u.f.trc_el_last = card->u.f.curr_trc_el +
- ((num_trc_els - 1) *
- sizeof(fr_trc_el_t));
-
- /* Calculate the maximum trace data area in */
- /* the UDP packet */
- card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT -
- //sizeof(fr_encap_hdr_t) -
- sizeof(ip_pkt_t) -
- sizeof(udp_pkt_t) -
- sizeof(wp_mgmt_t) -
- sizeof(cblock_t));
-
- /* set return code */
- fr_udp_pkt->cblock.result = 0;
-
- } else {
- /* set return code to line trace already
- enabled */
- fr_udp_pkt->cblock.result = 1;
- }
-
- mbox->cmd.length = 0;
- card->TracingEnabled = 1;
- break;
-
-
- case FPIPE_DISABLE_TRACING:
- if(card->TracingEnabled) {
-
- do {
- mbox->cmd.command = FR_SET_TRACE_CONFIG;
- mbox->cmd.length = 1;
- mbox->cmd.dlci = 0x00;
- mbox->data[0] = ~ACTIVATE_TRC;
- err = sdla_exec(mbox) ?
- mbox->cmd.result : CMD_TIMEOUT;
- } while (err && c_retry-- && fr_event(card, err, mbox));
- }
-
- /* set return code */
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 0;
- card->TracingEnabled = 0;
- break;
-
- case FPIPE_GET_TRACE_INFO:
-
- /* Line trace cannot be performed on the 502 */
- if(!card->TracingEnabled) {
- /* set return code */
- fr_udp_pkt->cblock.result = 1;
- mbox->cmd.length = 0;
- break;
- }
-
- ptr_trc_el = (void *)card->u.f.curr_trc_el;
-
- buffer_length = 0;
- fr_udp_pkt->data[0x00] = 0x00;
-
- for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) {
-
- sdla_peek(&card->hw, (unsigned long)ptr_trc_el,
- (void *)&trc_el.flag,
- sizeof(fr_trc_el_t));
- if(trc_el.flag == 0x00) {
- break;
- }
- if((card->u.f.trc_bfr_space - buffer_length)
- < sizeof(fpipemon_trc_hdr_t)) {
- fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
- break;
- }
-
- fpipemon_trc =
- (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length];
- fpipemon_trc->fpipemon_trc_hdr.status =
- trc_el.attr;
- fpipemon_trc->fpipemon_trc_hdr.tmstamp =
- trc_el.tmstamp;
- fpipemon_trc->fpipemon_trc_hdr.length =
- trc_el.length;
-
- if(!trc_el.offset || !trc_el.length) {
-
- fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00;
-
- }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) >
- (card->u.f.trc_bfr_space - buffer_length)){
-
- fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00;
- fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
-
- }else {
- fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01;
- sdla_peek(&card->hw, trc_el.offset,
- fpipemon_trc->data,
- trc_el.length);
- }
-
- trc_el.flag = 0x00;
- sdla_poke(&card->hw, (unsigned long)ptr_trc_el,
- &trc_el.flag, 1);
-
- ptr_trc_el ++;
- if((void *)ptr_trc_el > card->u.f.trc_el_last)
- ptr_trc_el = (void*)card->u.f.trc_el_base;
-
- buffer_length += sizeof(fpipemon_trc_hdr_t);
- if(fpipemon_trc->fpipemon_trc_hdr.data_passed) {
- buffer_length += trc_el.length;
- }
-
- if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) {
- break;
- }
- }
-
- if(frames == MAX_FRMS_TRACED) {
- fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
- }
-
- card->u.f.curr_trc_el = (void *)ptr_trc_el;
-
- /* set the total number of frames passed */
- fr_udp_pkt->data[0x00] |=
- ((frames << 1) & (MAX_FRMS_TRACED << 1));
-
- /* set the data length and return code */
- fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length;
- fr_udp_pkt->cblock.result = 0;
- break;
-
- case FPIPE_FT1_READ_STATUS:
- sdla_peek(&card->hw, 0xF020,
- &fr_udp_pkt->data[0x00] , 2);
- fr_udp_pkt->cblock.length = mbox->cmd.length = 2;
- fr_udp_pkt->cblock.result = 0;
- break;
-
- case FPIPE_FLUSH_DRIVER_STATS:
- init_chan_statistics(chan);
- init_global_statistics(card);
- mbox->cmd.length = 0;
- break;
-
- case FPIPE_ROUTER_UP_TIME:
- do_gettimeofday(&tv);
- chan->router_up_time = tv.tv_sec -
- chan->router_start_time;
- *(unsigned long *)&fr_udp_pkt->data =
- chan->router_up_time;
- mbox->cmd.length = fr_udp_pkt->cblock.length = 4;
- fr_udp_pkt->cblock.result = 0;
- break;
-
- case FPIPE_DRIVER_STAT_IFSEND:
- memcpy(fr_udp_pkt->data,
- &chan->drvstats_if_send.if_send_entry,
- sizeof(if_send_stat_t));
- mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t);
- fr_udp_pkt->cblock.result = 0;
- break;
-
- case FPIPE_DRIVER_STAT_INTR:
-
- memcpy(fr_udp_pkt->data,
- &card->statistics.isr_entry,
- sizeof(global_stats_t));
-
- memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)],
- &chan->drvstats_rx_intr.rx_intr_no_socket,
- sizeof(rx_intr_stat_t));
-
- mbox->cmd.length = fr_udp_pkt->cblock.length =
- sizeof(global_stats_t) +
- sizeof(rx_intr_stat_t);
- fr_udp_pkt->cblock.result = 0;
- break;
-
- case FPIPE_DRIVER_STAT_GEN:
- memcpy(fr_udp_pkt->data,
- &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err,
- sizeof(pipe_mgmt_stat_t));
-
- memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
- &card->statistics, sizeof(global_stats_t));
-
- mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
- sizeof(rx_intr_stat_t);
- fr_udp_pkt->cblock.result = 0;
- break;
-
-
- case FR_FT1_STATUS_CTRL:
- if(fr_udp_pkt->data[0] == 1) {
- if(rCount++ != 0 ){
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
-
- /* Disable FT1 MONITOR STATUS */
- if(fr_udp_pkt->data[0] == 0) {
- if( --rCount != 0) {
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
- goto udp_mgmt_dflt;
-
-
- default:
-udp_mgmt_dflt:
- do {
- memcpy(&mbox->cmd,
- &fr_udp_pkt->cblock.command,
- sizeof(fr_cmd_t));
- if(mbox->cmd.length) {
- memcpy(&mbox->data,
- (char *)fr_udp_pkt->data,
- mbox->cmd.length);
- }
-
- err = sdla_exec(mbox) ? mbox->cmd.result :
- CMD_TIMEOUT;
- } while (err && c_retry-- && fr_event(card, err, mbox));
-
- if(!err)
- chan->drvstats_gen.
- UDP_PIPE_mgmt_adptr_cmnd_OK ++;
- else
- chan->drvstats_gen.
- UDP_PIPE_mgmt_adptr_cmnd_timeout ++;
-
- /* copy the result back to our buffer */
- memcpy(&fr_udp_pkt->cblock.command,
- &mbox->cmd, sizeof(fr_cmd_t));
-
- if(mbox->cmd.length) {
- memcpy(&fr_udp_pkt->data,
- &mbox->data, mbox->cmd.length);
- }
- }
- }
-
- /* Fill UDP TTL */
- fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
- len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length);
-
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- chan->fr_header_len=2;
- chan->fr_header[0]=Q922_UI;
- chan->fr_header[1]=NLPID_IP;
-
- err = fr_send_data_header(card, dlci, 0, len,
- card->u.f.udp_pkt_data,chan->fr_header_len);
- if (err){
- chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++;
- }else{
- chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++;
- }
-
- } else {
- /* Allocate socket buffer */
- if((new_skb = dev_alloc_skb(len)) != NULL) {
-
- /* copy data into new_skb */
- buf = skb_put(new_skb, len);
- memcpy(buf, card->u.f.udp_pkt_data, len);
-
- chan->drvstats_gen.
- UDP_PIPE_mgmt_passed_to_stack ++;
- new_skb->dev = dev;
- new_skb->protocol = htons(ETH_P_IP);
- new_skb->mac.raw = new_skb->data;
- netif_rx(new_skb);
-
- } else {
- chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++;
- printk(KERN_INFO
- "%s: UDP mgmt cmnd, no socket buffers available!\n",
- card->devname);
- }
- }
-
- card->u.f.udp_pkt_lgth = 0;
-
- return 1;
-}
-
-/*==============================================================================
- * Send Inverse ARP Request
- */
-
-int send_inarp_request(sdla_t *card, struct net_device *dev)
-{
- int err=0;
-
- arphdr_1490_t *ArpPacket;
- arphdr_fr_t *arphdr;
- fr_channel_t *chan = dev->priv;
- struct in_device *in_dev;
-
- in_dev = dev->ip_ptr;
-
- if(in_dev != NULL ) {
-
- ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
- /* SNAP Header indicating ARP */
- ArpPacket->control = 0x03;
- ArpPacket->pad = 0x00;
- ArpPacket->NLPID = 0x80;
- ArpPacket->OUI[0] = 0;
- ArpPacket->OUI[1] = 0;
- ArpPacket->OUI[2] = 0;
- ArpPacket->PID = 0x0608;
-
- arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet
-
- /* InARP request */
- arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */
- arphdr->ar_pro = 0x0008; /* IP Protocol */
- arphdr->ar_hln = 2; /* HW addr length */
- arphdr->ar_pln = 4; /* IP addr length */
- arphdr->ar_op = htons(0x08); /* InARP Request */
- arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */
- if(in_dev->ifa_list != NULL)
- arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else
- arphdr->ar_sip = 0;
- arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */
- arphdr->ar_tip = 0; /* Remote Address -- what we want */
-
- err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
- (void *)ArpPacket);
-
- if (!err){
- printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n",
- card->devname, chan->dlci);
- clear_bit(ARP_CRIT,&card->wandev.critical);
- }
-
- kfree(ArpPacket);
- }else{
- printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n",
- card->devname,dev->name);
- return 1;
- }
-
- return 0;
-}
-
-
-/*==============================================================================
- * Check packet for ARP Type
- */
-
-int is_arp(void *buf)
-{
- arphdr_1490_t *arphdr = (arphdr_1490_t *)buf;
-
- if (arphdr->pad == 0x00 &&
- arphdr->NLPID == 0x80 &&
- arphdr->PID == 0x0608)
- return 1;
- else return 0;
-}
-
-/*==============================================================================
- * Process ARP Packet Type
- */
-
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev)
-{
-
-
- arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
- fr_rx_buf_ctl_t* frbuf = card->rxmb;
- struct in_device *in_dev;
- fr_channel_t *chan = dev->priv;
-
- /* Before we transmit ARP packet, we must check
- * to see that we are not currently transmitting a
- * frame (in 'if_send()') and that we are not
- * already in a 'delayed transmit' state. */
- if (check_tx_status(card,dev)){
- if (net_ratelimit()){
- printk(KERN_INFO "%s: Disabling comminication to process ARP\n",
- card->devname);
- }
- set_bit(ARP_CRIT,&card->wandev.critical);
- return 0;
- }
-
- in_dev = dev->ip_ptr;
-
- /* Check that IP addresses exist for our network address */
- if (in_dev == NULL || in_dev->ifa_list == NULL)
- return -1;
-
- switch (ntohs(arphdr->ar_op)) {
-
- case 0x08: // Inverse ARP request -- Send Reply, add route.
-
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n",
- card->devname, NIPQUAD(arphdr->ar_sip));
-
-
- /* Check that the network address is the same as ours, only
- * if the netowrk mask is not 255.255.255.255. Otherwise
- * this check would not make sense */
-
- if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF &&
- (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) !=
- (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){
- printk(KERN_INFO
- "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n",
- card->devname,NIPQUAD(arphdr->ar_sip));
-
- printk(KERN_INFO "%s: mask %u.%u.%u.%u\n",
- card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask));
- printk(KERN_INFO "%s: local %u.%u.%u.%u\n",
- card->devname,NIPQUAD(in_dev->ifa_list->ifa_local));
- return -1;
- }
-
- if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){
- printk(KERN_INFO
- "%s: Local addr = PtP addr. InARP ignored.\n",
- card->devname);
- return -1;
- }
-
- arphdr->ar_op = htons(0x09); /* InARP Reply */
-
- /* Set addresses */
- arphdr->ar_tip = arphdr->ar_sip;
- arphdr->ar_sip = in_dev->ifa_list->ifa_local;
-
- chan->ip_local = in_dev->ifa_list->ifa_local;
- chan->ip_remote = arphdr->ar_sip;
-
- fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
-
- if (test_bit(ARP_CRIT,&card->wandev.critical)){
- if (net_ratelimit()){
- printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n",
- card->devname);
- }
- }
- clear_bit(ARP_CRIT,&card->wandev.critical);
-
- chan->ip_local = in_dev->ifa_list->ifa_local;
- chan->ip_remote = arphdr->ar_sip;
-
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
-
- chan->route_flag = ADD_ROUTE;
- trigger_fr_poll (dev);
-
- break;
-
- case 0x09: // Inverse ARP reply
-
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n",
- card->devname, NIPQUAD(arphdr->ar_sip));
-
-
- /* Compare network addresses, only if network mask
- * is not 255.255.255.255 It would not make sense
- * to perform this test if the mask was all 1's */
-
- if (in_dev->ifa_list->ifa_mask != 0xffffffff &&
- (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) !=
- (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
-
- printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n",
- card->devname);
- return -1;
- }
-
- /* Make sure that the received IP address is not
- * the same as our own local address */
- if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
- printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n",
- card->devname);
- return -1;
- }
-
- chan->ip_local = in_dev->ifa_list->ifa_local;
- chan->ip_remote = arphdr->ar_sip;
-
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
-
- chan->route_flag = ADD_ROUTE;
- chan->inarp = INARP_CONFIGURED;
- trigger_fr_poll(dev);
-
- break;
- default:
- break; // ARP's and RARP's -- Shouldn't happen.
- }
-
- return 0;
-}
-
-
-/*============================================================
- * trigger_fr_arp
- *
- * Description:
- * Add an fr_arp() task into a arp
- * timer handler for a specific dlci/interface.
- * This will kick the fr_arp() routine
- * within the specified time interval.
- *
- * Usage:
- * This timer is used to send ARP requests at
- * certain time intervals.
- * Called by an interrupt to request an action
- * at a later date.
- */
-
-static void trigger_fr_arp(struct net_device *dev)
-{
- fr_channel_t* chan = dev->priv;
-
- mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ);
- return;
-}
-
-
-
-/*==============================================================================
- * ARP Request Action
- *
- * This funciton is called by timer interrupt to send an arp request
- * to the remote end.
- */
-
-static void fr_arp (unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- fr_channel_t *chan = dev->priv;
- volatile sdla_t *card = chan->card;
- fr508_flags_t* flags = card->flags;
-
- /* Send ARP packets for all devs' until
- * ARP state changes to CONFIGURED */
-
- if (chan->inarp == INARP_REQUEST &&
- chan->common.state == WAN_CONNECTED &&
- card->wandev.state == WAN_CONNECTED){
- set_bit(0,&chan->inarp_ready);
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP;
- flags->imask |= FR_INTR_TIMER;
- }
-
- return;
-}
-
-
-/*==============================================================================
- * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
- * TEST_COUNTER times.
- */
-static int intr_test( sdla_t* card )
-{
- fr_mbox_t* mb = card->mbox;
- int err,i;
-
- err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 );
-
- if (err == CMD_OK) {
-
- for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) {
- /* Run command READ_CODE_VERSION */
- mb->cmd.length = 0;
- mb->cmd.command = FR_READ_CODE_VERSION;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
- fr_event(card, err, mb);
- }
-
- } else {
- return err;
- }
-
- err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 );
-
- if( err != CMD_OK )
- return err;
-
- return 0;
-}
-
-/*==============================================================================
- * Determine what type of UDP call it is. FPIPE8ND ?
- */
-static int udp_pkt_type( struct sk_buff *skb, sdla_t* card )
-{
- fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data;
-
- /* Quick HACK */
-
-
- if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
- (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
- (fr_udp_pkt->udp_pkt.udp_dst_port ==
- ntohs(card->wandev.udp_port)) &&
- (fr_udp_pkt->wp_mgmt.request_reply ==
- UDPMGMT_REQUEST)) {
- if(!strncmp(fr_udp_pkt->wp_mgmt.signature,
- UDPMGMT_FPIPE_SIGNATURE, 8)){
- return UDP_FPIPE_TYPE;
- }
- }
- return UDP_INVALID_TYPE;
-}
-
-
-/*==============================================================================
- * Initializes the Statistics values in the fr_channel structure.
- */
-void init_chan_statistics( fr_channel_t* chan)
-{
- memset(&chan->drvstats_if_send.if_send_entry, 0,
- sizeof(if_send_stat_t));
- memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0,
- sizeof(rx_intr_stat_t));
- memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0,
- sizeof(pipe_mgmt_stat_t));
-}
-
-/*==============================================================================
- * Initializes the Statistics values in the Sdla_t structure.
- */
-void init_global_statistics( sdla_t* card )
-{
- /* Intialize global statistics for a card */
- memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t));
-}
-
-static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan )
-{
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- dlci_IB_mapping_t* result;
- int err, counter, found;
-
- do {
- mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if( mbox->cmd.result != 0){
- printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n",
- chan->name);
- }
-
- counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
- result = (void *)mbox->data;
-
- found = 0;
- for (; counter; --counter, ++result) {
- if ( result->dlci == chan->dlci ) {
- chan->IB_addr = result->addr_value;
- if(card->hw.type == SDLA_S514){
- chan->dlci_int_interface =
- (void*)(card->hw.dpmbase +
- chan->IB_addr);
- }else{
- chan->dlci_int_interface =
- (void*)(card->hw.dpmbase +
- (chan->IB_addr & 0x00001FFF));
-
- }
- found = 1;
- break;
- }
- }
- if (!found)
- printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n",
- card->devname, chan->dlci);
-}
-
-
-
-void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
-{
- if (card->hw.type != SDLA_S514){
-
- spin_lock_irqsave(&card->wandev.lock, *smp_flags);
- }else{
- spin_lock(&card->u.f.if_send_lock);
- }
- return;
-}
-
-
-void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
-{
- if (card->hw.type != SDLA_S514){
-
- spin_unlock_irqrestore (&card->wandev.lock, *smp_flags);
- }else{
- spin_unlock(&card->u.f.if_send_lock);
- }
- return;
-}
-
-
-
-/*----------------------------------------------------------------------
- RECEIVE INTERRUPT: BOTTOM HALF HANDLERS
- ----------------------------------------------------------------------*/
-
-
-/*========================================================
- * bh_enqueue
- *
- * Description:
- * Insert a received packet into a circular
- * rx queue. This packet will be picked up
- * by fr_bh() and sent up the stack to the
- * user.
- *
- * Usage:
- * This function is called by rx interrupt,
- * in API mode.
- *
- */
-
-static int bh_enqueue(struct net_device *dev, struct sk_buff *skb)
-{
- /* Check for full */
- fr_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
-
- if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){
- ++card->wandev.stats.rx_dropped;
- dev_kfree_skb_any(skb);
- return 1;
- }
-
- ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
-
- if (chan->bh_write == (MAX_BH_BUFF-1)){
- chan->bh_write=0;
- }else{
- ++chan->bh_write;
- }
-
- atomic_inc(&chan->bh_buff_used);
-
- return 0;
-}
-
-
-/*========================================================
- * trigger_fr_bh
- *
- * Description:
- * Kick the fr_bh() handler
- *
- * Usage:
- * rx interrupt calls this function during
- * the API mode.
- */
-
-static void trigger_fr_bh (fr_channel_t *chan)
-{
- if (!test_and_set_bit(0,&chan->tq_working)){
- wanpipe_queue_work(&chan->common.wanpipe_work);
- }
-}
-
-
-/*========================================================
- * fr_bh
- *
- * Description:
- * Frame relay receive BH handler.
- * Dequeue data from the BH circular
- * buffer and pass it up the API sock.
- *
- * Rationale:
- * This fuction is used to offload the
- * rx_interrupt during API operation mode.
- * The fr_bh() function executes for each
- * dlci/interface.
- *
- * Once receive interrupt copies data from the
- * card into an skb buffer, the skb buffer
- * is appended to a circular BH buffer.
- * Then the interrupt kicks fr_bh() to finish the
- * job at a later time (not within the interrupt).
- *
- * Usage:
- * Interrupts use this to defer a task to
- * a polling routine.
- *
- */
-
-static void fr_bh(struct net_device * dev)
-{
- fr_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
- struct sk_buff *skb;
-
- if (atomic_read(&chan->bh_buff_used) == 0){
- clear_bit(0, &chan->tq_working);
- return;
- }
-
- while (atomic_read(&chan->bh_buff_used)){
-
- if (chan->common.sk == NULL || chan->common.func == NULL){
- clear_bit(0, &chan->tq_working);
- return;
- }
-
- skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
-
- if (skb != NULL){
-
- if (chan->common.sk == NULL || chan->common.func == NULL){
- ++card->wandev.stats.rx_dropped;
- ++chan->ifstats.rx_dropped;
- dev_kfree_skb_any(skb);
- fr_bh_cleanup(dev);
- continue;
- }
-
- if (chan->common.func(skb,dev,chan->common.sk) != 0){
- /* Sock full cannot send, queue us for
- * another try */
- atomic_set(&chan->common.receive_block,1);
- return;
- }else{
- fr_bh_cleanup(dev);
- }
- }else{
- fr_bh_cleanup(dev);
- }
- }
- clear_bit(0, &chan->tq_working);
-
- return;
-}
-
-static int fr_bh_cleanup(struct net_device *dev)
-{
- fr_channel_t* chan = dev->priv;
-
- ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
-
- if (chan->bh_read == (MAX_BH_BUFF-1)){
- chan->bh_read=0;
- }else{
- ++chan->bh_read;
- }
-
- atomic_dec(&chan->bh_buff_used);
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
- POLL BH HANDLERS AND KICK ROUTINES
- ----------------------------------------------------------------------*/
-
-/*============================================================
- * trigger_fr_poll
- *
- * Description:
- * Add a fr_poll() task into a tq_scheduler bh handler
- * for a specific dlci/interface. This will kick
- * the fr_poll() routine at a later time.
- *
- * Usage:
- * Interrupts use this to defer a taks to
- * a polling routine.
- *
- */
-static void trigger_fr_poll(struct net_device *dev)
-{
- fr_channel_t* chan = dev->priv;
- schedule_work(&chan->fr_poll_work);
- return;
-}
-
-
-/*============================================================
- * fr_poll
- *
- * Rationale:
- * We cannot manipulate the routing tables, or
- * ip addresses withing the interrupt. Therefore
- * we must perform such actons outside an interrupt
- * at a later time.
- *
- * Description:
- * Frame relay polling routine, responsible for
- * shutting down interfaces upon disconnect
- * and adding/removing routes.
- *
- * Usage:
- * This function is executed for each frame relay
- * dlci/interface through a tq_schedule bottom half.
- *
- * trigger_fr_poll() function is used to kick
- * the fr_poll routine.
- */
-
-static void fr_poll(struct net_device *dev)
-{
-
- fr_channel_t* chan;
- sdla_t *card;
- u8 check_gateway=0;
-
- if (!dev || (chan = dev->priv) == NULL)
- return;
-
- card = chan->card;
-
- /* (Re)Configuraiton is in progress, stop what you are
- * doing and get out */
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- return;
- }
-
- switch (chan->common.state){
-
- case WAN_DISCONNECTED:
-
- if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
- !test_bit(DEV_DOWN, &chan->interface_down) &&
- dev->flags&IFF_UP){
-
- printk(KERN_INFO "%s: Interface %s is Down.\n",
- card->devname,dev->name);
- change_dev_flags(dev,dev->flags&~IFF_UP);
- set_bit(DEV_DOWN, &chan->interface_down);
- chan->route_flag = NO_ROUTE;
-
- }else{
- if (chan->inarp != INARP_NONE)
- process_route(dev);
- }
- break;
-
- case WAN_CONNECTED:
-
- if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
- test_bit(DEV_DOWN, &chan->interface_down) &&
- !(dev->flags&IFF_UP)){
-
- printk(KERN_INFO "%s: Interface %s is Up.\n",
- card->devname,dev->name);
-
- change_dev_flags(dev,dev->flags|IFF_UP);
- clear_bit(DEV_DOWN, &chan->interface_down);
- check_gateway=1;
- }
-
- if (chan->inarp != INARP_NONE){
- process_route(dev);
- check_gateway=1;
- }
-
- if (chan->gateway && check_gateway)
- add_gateway(card,dev);
-
- break;
-
- }
-
- return;
-}
-
-/*==============================================================
- * check_tx_status
- *
- * Rationale:
- * We cannot transmit from an interrupt while
- * the if_send is transmitting data. Therefore,
- * we must check whether the tx buffers are
- * begin used, before we transmit from an
- * interrupt.
- *
- * Description:
- * Checks whether it's safe to use the transmit
- * buffers.
- *
- * Usage:
- * ARP and UDP handling routines use this function
- * because, they need to transmit data during
- * an interrupt.
- */
-
-static int check_tx_status(sdla_t *card, struct net_device *dev)
-{
-
- if (card->hw.type == SDLA_S514){
- if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) ||
- test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
- return 1;
- }
- }
-
- if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending))
- return 1;
-
- return 0;
-}
-
-/*===============================================================
- * move_dev_to_next
- *
- * Description:
- * Move the dev pointer to the next location in the
- * link list. Check if we are at the end of the
- * list, if so start from the begining.
- *
- * Usage:
- * Timer interrupt uses this function to efficiently
- * step through the devices that need to send ARP data.
- *
- */
-
-struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev)
-{
- if (card->wandev.new_if_cnt != 1){
- if (!*((struct net_device **)dev->priv))
- return card->wandev.dev;
- else
- return *((struct net_device **)dev->priv);
- }
- return dev;
-}
-
-/*==============================================================
- * trigger_config_fr
- *
- * Rationale:
- * All commands must be performed inside of a
- * interrupt.
- *
- * Description:
- * Kick the config_fr() routine throught the
- * timer interrupt.
- */
-
-
-static void trigger_config_fr (sdla_t *card)
-{
- fr508_flags_t* flags = card->flags;
-
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
- flags->imask |= FR_INTR_TIMER;
-}
-
-
-/*==============================================================
- * config_fr
- *
- * Rationale:
- * All commands must be performed inside of a
- * interrupt.
- &
- * Description:
- * Configure a DLCI. This function is executed
- * by a timer_interrupt. The if_open() function
- * triggers it.
- *
- * Usage:
- * new_if() collects all data necessary to
- * configure the DLCI. It sets the chan->dlci_ready
- * bit. When the if_open() function is executed
- * it checks this bit, and if its set it triggers
- * the timer interrupt to execute the config_fr()
- * function.
- */
-
-static void config_fr (sdla_t *card)
-{
- struct net_device *dev;
- fr_channel_t *chan;
-
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)) {
-
- if ((chan=dev->priv) == NULL)
- continue;
-
- if (!test_bit(0,&chan->config_dlci))
- continue;
-
- clear_bit(0,&chan->config_dlci);
-
- /* If signalling is set to NO, then setup
- * DLCI addresses right away. Don't have to wait for
- * link to connect.
- */
- if (card->wandev.signalling == WANOPT_NO){
- printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n",
- card->wandev.name);
- if (fr_init_dlci(card,chan)){
- printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n",
- card->devname, chan->dlci);
- return;
- }
- }
-
- if (card->wandev.station == WANOPT_CPE) {
-
- update_chan_state(dev);
-
- /* CPE: issue full status enquiry */
- fr_issue_isf(card, FR_ISF_FSE);
-
- } else {
- /* FR switch: activate DLCI(s) */
-
- /* For Switch emulation we have to ADD and ACTIVATE
- * the DLCI(s) that were configured with the SET_DLCI_
- * CONFIGURATION command. Add and Activate will fail if
- * DLCI specified is not included in the list.
- *
- * Also If_open is called once for each interface. But
- * it does not get in here for all the interface. So
- * we have to pass the entire list of DLCI(s) to add
- * activate routines.
- */
-
- if (!check_dlci_config (card, chan)){
- fr_add_dlci(card, chan->dlci);
- fr_activate_dlci(card, chan->dlci);
- }
- }
-
- card->u.f.dlci_to_dev_map[chan->dlci] = dev;
- }
- return;
-}
-
-
-/*==============================================================
- * config_fr
- *
- * Rationale:
- * All commands must be executed during an interrupt.
- *
- * Description:
- * Trigger uncofig_fr() function through
- * the timer interrupt.
- *
- */
-
-static void trigger_unconfig_fr(struct net_device *dev)
-{
- fr_channel_t *chan = dev->priv;
- volatile sdla_t *card = chan->card;
- unsigned long timeout;
- fr508_flags_t* flags = card->flags;
- int reset_critical=0;
-
- if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
- clear_bit(PERI_CRIT,(void*)&card->wandev.critical);
- reset_critical=1;
- }
-
- /* run unconfig_dlci() function
- * throught the timer interrupt */
- set_bit(0,(void*)&chan->unconfig_dlci);
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG;
- flags->imask |= FR_INTR_TIMER;
-
- /* Wait for the command to complete */
- timeout = jiffies;
- for(;;) {
-
- if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG))
- break;
-
- if (time_after(jiffies, timeout + 1 * HZ)){
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
- printk(KERN_INFO "%s: Failed to delete DLCI %i\n",
- card->devname,chan->dlci);
- break;
- }
- }
-
- if (reset_critical){
- set_bit(PERI_CRIT,(void*)&card->wandev.critical);
- }
-}
-
-/*==============================================================
- * unconfig_fr
- *
- * Rationale:
- * All commands must be executed during an interrupt.
- *
- * Description:
- * Remove the dlci from firmware.
- * This funciton is used in NODE shutdown.
- */
-
-static void unconfig_fr (sdla_t *card)
-{
- struct net_device *dev;
- fr_channel_t *chan;
-
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)){
-
- if ((chan=dev->priv) == NULL)
- continue;
-
- if (!test_bit(0,&chan->unconfig_dlci))
- continue;
-
- clear_bit(0,&chan->unconfig_dlci);
-
- if (card->wandev.station == WANOPT_NODE){
- printk(KERN_INFO "%s: Unconfiguring DLCI %i\n",
- card->devname,chan->dlci);
- fr_delete_dlci(card,chan->dlci);
- }
- card->u.f.dlci_to_dev_map[chan->dlci] = NULL;
- }
-}
-
-static int setup_fr_header(struct sk_buff *skb, struct net_device* dev,
- char op_mode)
-{
- fr_channel_t *chan=dev->priv;
-
- if (op_mode == WANPIPE) {
- chan->fr_header[0]=Q922_UI;
-
- switch (htons(skb->protocol)){
- case ETH_P_IP:
- chan->fr_header[1]=NLPID_IP;
- break;
- default:
- return -EINVAL;
- }
-
- return 2;
- }
-
- /* If we are in bridging mode, we must apply
- * an Ethernet header
- */
- if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) {
- /* Encapsulate the packet as a bridged Ethernet frame. */
-#ifdef DEBUG
- printk(KERN_INFO "%s: encapsulating skb for frame relay\n",
- dev->name);
-#endif
- chan->fr_header[0] = 0x03;
- chan->fr_header[1] = 0x00;
- chan->fr_header[2] = 0x80;
- chan->fr_header[3] = 0x00;
- chan->fr_header[4] = 0x80;
- chan->fr_header[5] = 0xC2;
- chan->fr_header[6] = 0x00;
- chan->fr_header[7] = 0x07;
-
- /* Yuck. */
- skb->protocol = ETH_P_802_3;
- return 8;
- }
-
- return 0;
-}
-
-
-static int check_dlci_config (sdla_t *card, fr_channel_t *chan)
-{
- fr_mbox_t* mbox = card->mbox;
- int err=0;
- fr_conf_t *conf=NULL;
- unsigned short dlci_num = chan->dlci;
- int dlci_offset=0;
- struct net_device *dev = NULL;
-
- mbox->cmd.command = FR_READ_CONFIG;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = dlci_num;
-
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err == CMD_OK){
- return 0;
- }
-
- for (dev = card->wandev.dev; dev;
- dev=*((struct net_device **)dev->priv))
- set_chan_state(dev,WAN_DISCONNECTED);
-
- printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num);
-
- mbox->cmd.command = FR_COMM_DISABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK){
- fr_event(card, err, mbox);
- return 2;
- }
-
- printk(KERN_INFO "Disabled Communications \n");
-
- mbox->cmd.command = FR_READ_CONFIG;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = 0;
-
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK){
- fr_event(card, err, mbox);
- return 2;
- }
-
- conf = (fr_conf_t *)mbox->data;
-
- dlci_offset=0;
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)) {
- fr_channel_t *chan_tmp = dev->priv;
- conf->dlci[dlci_offset] = chan_tmp->dlci;
- dlci_offset++;
- }
-
- printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n",
- mbox->cmd.length,
- mbox->cmd.length > 0x20 ? conf->dlci[0] : -1,
- dlci_offset );
-
- mbox->cmd.length = 0x20 + dlci_offset*2;
-
- mbox->cmd.command = FR_SET_CONFIG;
- mbox->cmd.dlci = 0;
-
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK){
- fr_event(card, err, mbox);
- return 2;
- }
-
- initialize_rx_tx_buffers (card);
-
-
- printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num);
-
- if (fr_comm_enable (card)){
- return 2;
- }
-
- printk(KERN_INFO "Enabling Communications \n");
-
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)) {
- fr_channel_t *chan_tmp = dev->priv;
- fr_init_dlci(card,chan_tmp);
- fr_add_dlci(card, chan_tmp->dlci);
- fr_activate_dlci(card, chan_tmp->dlci);
- }
-
- printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num);
-
- return 1;
-}
-
-static void initialize_rx_tx_buffers (sdla_t *card)
-{
- fr_buf_info_t* buf_info;
-
- if (card->hw.type == SDLA_S514) {
-
- buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR +
- FR508_RXBC_OFFS);
-
- card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase);
-
- card->u.f.rxmb_base =
- (void*)(buf_info->rse_base + card->hw.dpmbase);
-
- card->u.f.rxmb_last =
- (void*)(buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
- card->hw.dpmbase);
- }else{
- buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
-
- card->rxmb = (void*)(buf_info->rse_next -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- card->u.f.rxmb_base =
- (void*)(buf_info->rse_base -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- card->u.f.rxmb_last =
- (void*)(buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) -
- FR_MB_VECTOR + card->hw.dpmbase);
- }
-
- card->u.f.rx_base = buf_info->buf_base;
- card->u.f.rx_top = buf_info->buf_top;
-
- card->u.f.tx_interrupts_pending = 0;
-
- return;
-}
-
-
-
-MODULE_LICENSE("GPL");
-
-/****** End *****************************************************************/
diff --git a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c
deleted file mode 100644
index 9d6528a50f7b..000000000000
--- a/drivers/net/wan/sdla_ft1.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*****************************************************************************
-* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module.
-*
-* Authors: Nenad Corbic <ncorbic@sangoma.com>
-* Gideon Hack
-*
-* Copyright: (c) 1995-1999 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup.
-* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing
-* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices.
-* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
-* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING).
-* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC.
-* Aug 07, 1998 David Fong Initial version.
-*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/if_arp.h> /* ARPHRD_* defines */
-#include <linux/jiffies.h> /* time_after() macro */
-
-#include <linux/inetdevice.h>
-#include <asm/uaccess.h>
-
-#include <linux/in.h> /* sockaddr_in */
-#include <linux/inet.h>
-#include <linux/if.h>
-#include <asm/byteorder.h> /* htons(), etc. */
-#include <linux/sdlapci.h>
-#include <asm/io.h>
-
-#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */
-
-/****** Defines & Macros ****************************************************/
-
-/* reasons for enabling the timer interrupt on the adapter */
-#define TMR_INT_ENABLED_UDP 0x0001
-#define TMR_INT_ENABLED_UPDATE 0x0002
-
-#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */
-#define CHDLC_HDR_LEN 1
-
-#define IFF_POINTTOPOINT 0x10
-
-#define WANPIPE 0x00
-#define API 0x01
-#define CHDLC_API 0x01
-
-#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" )
-
-
-/******Data Structures*****************************************************/
-
-/* This structure is placed in the private data area of the device structure.
- * The card structure used to occupy the private area but now the following
- * structure will incorporate the card structure along with CHDLC specific data
- */
-
-typedef struct chdlc_private_area
-{
- struct net_device *slave;
- sdla_t *card;
- int TracingEnabled; /* For enabling Tracing */
- unsigned long curr_trace_addr; /* Used for Tracing */
- unsigned long start_trace_addr;
- unsigned long end_trace_addr;
- unsigned long base_addr_trace_buffer;
- unsigned long end_addr_trace_buffer;
- unsigned short number_trace_elements;
- unsigned available_buffer_space;
- unsigned long router_start_time;
- unsigned char route_status;
- unsigned char route_removed;
- unsigned long tick_counter; /* For 5s timeout counter */
- unsigned long router_up_time;
- u32 IP_address; /* IP addressing */
- u32 IP_netmask;
- unsigned char mc; /* Mulitcast support on/off */
- unsigned short udp_pkt_lgth; /* udp packet processing */
- char udp_pkt_src;
- char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
- unsigned short timer_int_enabled;
- char update_comms_stats; /* updating comms stats */
- //FIXME: add driver stats as per frame relay!
-
-} chdlc_private_area_t;
-
-/* Route Status options */
-#define NO_ROUTE 0x00
-#define ADD_ROUTE 0x01
-#define ROUTE_ADDED 0x02
-#define REMOVE_ROUTE 0x03
-
-
-/****** Function Prototypes *************************************************/
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data);
-static int chdlc_read_version (sdla_t* card, char* str);
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * Cisco HDLC protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup. At this
- * point adapter is completely initialized and firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
-int wpft1_init (sdla_t* card, wandev_conf_t* conf)
-{
- unsigned char port_num;
- int err;
-
- union
- {
- char str[80];
- } u;
- volatile CHDLC_MAILBOX_STRUCT* mb;
- CHDLC_MAILBOX_STRUCT* mb1;
- unsigned long timeout;
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_CHDLC) {
- printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
- return -EINVAL;
- }
-
- /* Use primary port */
- card->u.c.comm_port = 0;
-
-
- /* Initialize protocol-specific fields */
- if(card->hw.type != SDLA_S514){
- card->mbox = (void *) card->hw.dpmbase;
- }else{
- card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT;
- }
-
- mb = mb1 = card->mbox;
-
- if (!card->configured){
-
- /* The board will place an 'I' in the return code to indicate that it is
- ready to accept commands. We expect this to be completed in less
- than 1 second. */
-
- timeout = jiffies;
- while (mb->return_code != 'I') /* Wait 1s for board to initialize */
- if (time_after(jiffies, timeout + 1*HZ)) break;
-
- if (mb->return_code != 'I') {
- printk(KERN_INFO
- "%s: Initialization not completed by adapter\n",
- card->devname);
- printk(KERN_INFO "Please contact Sangoma representative.\n");
- return -EIO;
- }
- }
-
- /* Read firmware version. Note that when adapter initializes, it
- * clears the mailbox, so it may appear that the first command was
- * executed successfully when in fact it was merely erased. To work
- * around this, we execute the first command twice.
- */
-
- if (chdlc_read_version(card, u.str))
- return -EIO;
-
- printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n",
- card->devname, u.str);
-
- card->isr = NULL;
- card->poll = NULL;
- card->exec = &wpft1_exec;
- card->wandev.update = NULL;
- card->wandev.new_if = NULL;
- card->wandev.del_if = NULL;
- card->wandev.state = WAN_DUALPORT;
- card->wandev.udp_port = conf->udp_port;
-
- card->wandev.new_if_cnt = 0;
-
- /* This is for the ports link state */
- card->u.c.state = WAN_DISCONNECTED;
-
- /* reset the number of times the 'update()' proc has been called */
- card->u.c.update_call_count = 0;
-
- card->wandev.ttl = 0x7F;
- card->wandev.interface = 0;
-
- card->wandev.clocking = 0;
-
- port_num = card->u.c.comm_port;
-
- /* Setup Port Bps */
-
- card->wandev.bps = 0;
-
- card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG;
-
- /* Set up the interrupt status area */
- /* Read the CHDLC Configuration and obtain:
- * Ptr to shared memory infor struct
- * Use this pointer to calculate the value of card->u.c.flags !
- */
- mb1->buffer_length = 0;
- mb1->command = READ_CHDLC_CONFIGURATION;
- err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
- if(err != COMMAND_OK) {
- chdlc_error(card, err, mb1);
- return -EIO;
- }
-
- if(card->hw.type == SDLA_S514){
- card->u.c.flags = (void *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
- ptr_shared_mem_info_struct));
- }else{
- card->u.c.flags = (void *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
- ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
- }
-
- card->wandev.state = WAN_FT1_READY;
- printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname);
-
- return 0;
-}
-
-static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data)
-{
- CHDLC_MAILBOX_STRUCT* mbox = card->mbox;
- int len;
-
- if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){
- return -EFAULT;
- }
-
- len = mbox->buffer_length;
-
- if (len) {
- if( copy_from_user((void*)&mbox->data, u_data, len)){
- return -EFAULT;
- }
- }
-
- /* execute command */
- if (!sdla_exec(mbox)){
- return -EIO;
- }
-
- /* return result */
- if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){
- return -EFAULT;
- }
-
- len = mbox->buffer_length;
-
- if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){
- return -EFAULT;
- }
-
- return 0;
-
-}
-
-/*============================================================================
- * Read firmware code version.
- * Put code version as ASCII string in str.
- */
-static int chdlc_read_version (sdla_t* card, char* str)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int len;
- char err;
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CODE_VERSION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if(err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- }
- else if (str) { /* is not null */
- len = mb->buffer_length;
- memcpy(str, mb->data, len);
- str[len] = '\0';
- }
- return (err);
-}
-
-/*============================================================================
- * Firmware error handler.
- * This routine is called whenever firmware command returns non-zero
- * return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb)
-{
- unsigned cmd = mb->command;
-
- switch (err) {
-
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd);
- break;
-
- case S514_BOTH_PORTS_SAME_CLK_MODE:
- if(cmd == SET_CHDLC_CONFIGURATION) {
- printk(KERN_INFO
- "%s: Configure both ports for the same clock source\n",
- card->devname);
- break;
- }
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, cmd, err);
- }
-
- return 0;
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
deleted file mode 100644
index a4b489cccbbf..000000000000
--- a/drivers/net/wan/sdla_ppp.c
+++ /dev/null
@@ -1,3430 +0,0 @@
-/*****************************************************************************
-* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module.
-*
-* Author: Nenad Corbic <ncorbic@sangoma.com>
-*
-* Copyright: (c) 1995-2001 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for
-* 2.4.X kernels.
-* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support:
-* get_ip_address() function has moved
-* into the ppp_poll() routine. It cannot
-* be called from an interrupt.
-* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging:
-* Deny all and specify allowed requests.
-* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown
-* option. When the link goes down, the
-* network interface IFF_UP flag is reset.
-* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery.
-* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem.
-* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called
-* with NULL dev pointer: no check.
-* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter.
-* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels
-* Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels
-* Moved dynamic route processing into
-* a polling routine.
-* Oct 07, 1999 Nenad Corbic o Support for S514 PCI card.
-* Gideon Hack o UPD and Updates executed using timer interrupt
-* Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics
-* Jul 20, 1999 Nenad Corbic o Remove the polling routines and use
-* interrupts instead.
-* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels.
-* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing.
-* Jun 22, 1998 David Fong o Added remote IP address assignment
-* Mar 15, 1998 Alan Cox o 2.1.8x basic port.
-* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol.
-* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP.
-* o Implemented new routines like
-* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(),
-* tokenize() and strstrip().
-* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
-* while they have been disabled.
-* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by
-* disabling and enabling of irqs.
-* o Added new counters for stats on disable/enable
-* IRQs.
-* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data'
-* before every netif_rx().
-* o Free up the device structure in del_if().
-* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing
-* command.
-* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time.
-* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow
-* control by avoiding RACE conditions. The
-* cli() and restore_flags() are taken out.
-* A new structure, "ppp_private_area", is added
-* to provide Driver Statistics.
-* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding
-* save_flags(), cli() and restore_flags().
-* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets
-* o Added ability to discard mulitcast and
-* broacast source addressed packets.
-* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities
-* New case (0x25) statement in if_send routine.
-* Added a global variable rCount to keep track
-* of FT1 status enabled on the board.
-* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for
-* 508 card to reflect changes in the new
-* ppp508.sfm for supporting:continous transmission
-* of Configure-Request packets without receiving a
-* reply
-* OR-ed 0x300 to conf_flags
-* o Changed connect_tmout from 900 to 0
-* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards
-* Apr 25, 1997 Farhan Thawar o added UDP Management stuff
-* Mar 11, 1997 Farhan Thawar Version 3.1.1
-* o fixed (+1) bug in rx_intr()
-* o changed if_send() to return 0 if
-* wandev.critical() is true
-* o free socket buffer in if_send() if
-* returning 0
-* Jan 15, 1997 Gene Kozin Version 3.1.0
-* o implemented exec() entry point
-* Jan 06, 1997 Gene Kozin Initial version.
-*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/if_arp.h> /* ARPHRD_* defines */
-#include <asm/byteorder.h> /* htons(), etc. */
-#include <linux/in.h> /* sockaddr_in */
-#include <linux/jiffies.h> /* time_after() macro */
-
-
-#include <asm/uaccess.h>
-#include <linux/inetdevice.h>
-#include <linux/netdevice.h>
-
-#include <linux/if.h>
-#include <linux/sdla_ppp.h> /* PPP firmware API definitions */
-#include <linux/sdlasfm.h> /* S514 Type Definition */
-/****** Defines & Macros ****************************************************/
-
-#define PPP_DFLT_MTU 1500 /* default MTU */
-#define PPP_MAX_MTU 4000 /* maximum MTU */
-#define PPP_HDR_LEN 1
-
-#define MAX_IP_ERRORS 100
-
-#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
-#define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */
-
-/* For handle_IPXWAN() */
-#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-/* Macro for enabling/disabling debugging comments */
-//#define NEX_DEBUG
-#ifdef NEX_DEBUG
-#define NEX_PRINTK(format, a...) printk(format, ## a)
-#else
-#define NEX_PRINTK(format, a...)
-#endif /* NEX_DEBUG */
-
-#define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" )
-#define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" )
-#define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" )
-#define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" )
-
-#define TMR_INT_ENABLED_UPDATE 0x01
-#define TMR_INT_ENABLED_PPP_EVENT 0x02
-#define TMR_INT_ENABLED_UDP 0x04
-#define TMR_INT_ENABLED_CONFIG 0x20
-
-/* Set Configuraton Command Definitions */
-#define PERCENT_TX_BUFF 60
-#define TIME_BETWEEN_CONF_REQ 30
-#define TIME_BETWEEN_PAP_CHAP_REQ 30
-#define WAIT_PAP_CHAP_WITHOUT_REPLY 300
-#define WAIT_AFTER_DCD_CTS_LOW 5
-#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10
-#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900
-#define MAX_CONF_REQ_WITHOUT_REPLY 10
-#define MAX_TERM_REQ_WITHOUT_REPLY 2
-#define NUM_CONF_NAK_WITHOUT_REPLY 5
-#define NUM_AUTH_REQ_WITHOUT_REPLY 10
-
-#define END_OFFSET 0x1F0
-
-
-/******Data Structures*****************************************************/
-
-/* This structure is placed in the private data area of the device structure.
- * The card structure used to occupy the private area but now the following
- * structure will incorporate the card structure along with PPP specific data
- */
-
-typedef struct ppp_private_area
-{
- struct net_device *slave;
- sdla_t* card;
- unsigned long router_start_time; /*router start time in sec */
- unsigned long tick_counter; /*used for 5 second counter*/
- unsigned mc; /*multicast support on or off*/
- unsigned char enable_IPX;
- unsigned long network_number;
- unsigned char pap;
- unsigned char chap;
- unsigned char sysname[31]; /* system name for in-bnd auth*/
- unsigned char userid[511]; /* list of user ids */
- unsigned char passwd[511]; /* list of passwords */
- unsigned protocol; /* SKB Protocol */
- u32 ip_local; /* Local IP Address */
- u32 ip_remote; /* remote IP Address */
-
- u32 ip_local_tmp;
- u32 ip_remote_tmp;
-
- unsigned char timer_int_enabled; /* Who enabled the timer inter*/
- unsigned char update_comms_stats; /* Used by update function */
- unsigned long curr_trace_addr; /* Trace information */
- unsigned long start_trace_addr;
- unsigned long end_trace_addr;
-
- unsigned char interface_down; /* Brind down interface when channel
- goes down */
- unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode,
- wait a few seconds before configuring */
-
- unsigned short udp_pkt_lgth;
- char udp_pkt_src;
- char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
-
- /* PPP specific statistics */
-
- if_send_stat_t if_send_stat;
- rx_intr_stat_t rx_intr_stat;
- pipe_mgmt_stat_t pipe_mgmt_stat;
-
- unsigned long router_up_time;
-
- /* Polling work queue entry. Each interface
- * has its own work queue entry, which is used
- * to defer events from the interrupt */
- struct work_struct poll_work;
- struct timer_list poll_delay_timer;
-
- u8 gateway;
- u8 config_ppp;
- u8 ip_error;
-
-}ppp_private_area_t;
-
-/* variable for keeping track of enabling/disabling FT1 monitor status */
-static int rCount = 0;
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/****** Function Prototypes *************************************************/
-
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(struct wan_device *wandev);
-static int new_if(struct wan_device *wandev, struct net_device *dev,
- wanif_conf_t *conf);
-static int del_if(struct wan_device *wandev, struct net_device *dev);
-
-/* WANPIPE-specific entry points */
-static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data);
-
-/* Network device interface */
-static int if_init(struct net_device *dev);
-static int if_open(struct net_device *dev);
-static int if_close(struct net_device *dev);
-static int if_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type,
- void *daddr, void *saddr, unsigned len);
-
-static void if_tx_timeout(struct net_device *dev);
-
-static int if_rebuild_hdr(struct sk_buff *skb);
-static struct net_device_stats *if_stats(struct net_device *dev);
-static int if_send(struct sk_buff *skb, struct net_device *dev);
-
-
-/* PPP firmware interface functions */
-static int ppp_read_version(sdla_t *card, char *str);
-static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area);
-static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area);
-static int ppp_configure(sdla_t *card, void *data);
-static int ppp_set_intr_mode(sdla_t *card, unsigned char mode);
-static int ppp_comm_enable(sdla_t *card);
-static int ppp_comm_disable(sdla_t *card);
-static int ppp_comm_disable_shutdown(sdla_t *card);
-static int ppp_get_err_stats(sdla_t *card);
-static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto);
-static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb);
-
-static void wpp_isr(sdla_t *card);
-static void rx_intr(sdla_t *card);
-static void event_intr(sdla_t *card);
-static void timer_intr(sdla_t *card);
-
-/* Background polling routines */
-static void process_route(sdla_t *card);
-static void retrigger_comm(sdla_t *card);
-
-/* Miscellaneous functions */
-static int read_info( sdla_t *card );
-static int read_connection_info (sdla_t *card);
-static void remove_route( sdla_t *card );
-static int config508(struct net_device *dev, sdla_t *card);
-static void show_disc_cause(sdla_t * card, unsigned cause);
-static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev,
- ppp_private_area_t *ppp_priv_area);
-static void init_ppp_tx_rx_buff( sdla_t *card );
-static int intr_test( sdla_t *card );
-static int udp_pkt_type( struct sk_buff *skb , sdla_t *card);
-static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area);
-static void init_global_statistics( sdla_t *card );
-static int tokenize(char *str, char **tokens);
-static char* strstrip(char *str, char *s);
-static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev,
- struct sk_buff *skb);
-
-static int config_ppp (sdla_t *);
-static void ppp_poll(struct net_device *dev);
-static void trigger_ppp_poll(struct net_device *dev);
-static void ppp_poll_delay (unsigned long dev_ptr);
-
-
-static int Read_connection_info;
-static int Intr_test_counter;
-static unsigned short available_buffer_space;
-
-
-/* IPX functions */
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number,
- unsigned char incoming);
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX,
- unsigned long network_number, unsigned short proto);
-
-/* Lock Functions */
-static void s508_lock (sdla_t *card, unsigned long *smp_flags);
-static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
-
-static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, struct net_device* dev,
- ppp_private_area_t* ppp_priv_area );
-static unsigned short calc_checksum (char *data, int len);
-static void disable_comm (sdla_t *card);
-static int detect_and_fix_tx_bug (sdla_t *card);
-
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * PPP protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup. At this
- * point adapter is completely initialized and firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
-int wpp_init(sdla_t *card, wandev_conf_t *conf)
-{
- ppp_flags_t *flags;
- union
- {
- char str[80];
- } u;
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_PPP) {
-
- printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
- return -EINVAL;
-
- }
-
- /* Initialize miscellaneous pointers to structures on the adapter */
- switch (card->hw.type) {
-
- case SDLA_S508:
- card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS);
- card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS);
- break;
-
- case SDLA_S514:
- card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS);
- card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS);
- break;
-
- default:
- return -EINVAL;
-
- }
- flags = card->flags;
-
- /* Read firmware version. Note that when adapter initializes, it
- * clears the mailbox, so it may appear that the first command was
- * executed successfully when in fact it was merely erased. To work
- * around this, we execute the first command twice.
- */
- if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str))
- return -EIO;
-
- printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str);
- /* Adjust configuration and set defaults */
- card->wandev.mtu = (conf->mtu) ?
- min_t(unsigned int, conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU;
-
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->isr = &wpp_isr;
- card->poll = NULL;
- card->exec = &wpp_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- card->wandev.udp_port = conf->udp_port;
- card->wandev.ttl = conf->ttl;
- card->wandev.state = WAN_DISCONNECTED;
- card->disable_comm = &disable_comm;
- card->irq_dis_if_send_count = 0;
- card->irq_dis_poll_count = 0;
- card->u.p.authenticator = conf->u.ppp.authenticator;
- card->u.p.ip_mode = conf->u.ppp.ip_mode ?
- conf->u.ppp.ip_mode : WANOPT_PPP_STATIC;
- card->TracingEnabled = 0;
- Read_connection_info = 1;
-
- /* initialize global statistics */
- init_global_statistics( card );
-
-
-
- if (!card->configured){
- int err;
-
- Intr_test_counter = 0;
- err = intr_test(card);
-
- if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
- printk("%s: Interrupt Test Failed, Counter: %i\n",
- card->devname, Intr_test_counter);
- printk( "%s: Please choose another interrupt\n",card->devname);
- return -EIO;
- }
-
- printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",
- card->devname, Intr_test_counter);
- card->configured = 1;
- }
-
- ppp_set_intr_mode(card, PPP_INTR_TIMER);
-
- /* Turn off the transmit and timer interrupt */
- flags->imask &= ~PPP_INTR_TIMER;
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics.
- */
-static int update(struct wan_device *wandev)
-{
- sdla_t* card = wandev->private;
- struct net_device* dev;
- volatile ppp_private_area_t *ppp_priv_area;
- ppp_flags_t *flags = card->flags;
- unsigned long timeout;
-
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
-
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- /* Shutdown bug fix. This function can be
- * called with NULL dev pointer during
- * shutdown
- */
- if ((dev=card->wandev.dev) == NULL){
- return -ENODEV;
- }
-
- if ((ppp_priv_area=dev->priv) == NULL){
- return -ENODEV;
- }
-
- ppp_priv_area->update_comms_stats = 2;
- ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
- flags->imask |= PPP_INTR_TIMER;
-
- /* wait a maximum of 1 second for the statistics to be updated */
- timeout = jiffies;
- for(;;) {
- if(ppp_priv_area->update_comms_stats == 0){
- break;
- }
- if (time_after(jiffies, timeout + 1 * HZ)){
- ppp_priv_area->update_comms_stats = 0;
- ppp_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_UPDATE;
- return -EAGAIN;
- }
- }
-
- return 0;
-}
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return: 0 o.k.
- * < 0 failure (channel will not be created)
- */
-static int new_if(struct wan_device *wandev, struct net_device *dev,
- wanif_conf_t *conf)
-{
- sdla_t *card = wandev->private;
- ppp_private_area_t *ppp_priv_area;
-
- if (wandev->ndev)
- return -EEXIST;
-
-
- printk(KERN_INFO "%s: Configuring Interface: %s\n",
- card->devname, conf->name);
-
- if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
-
- printk(KERN_INFO "%s: Invalid interface name!\n",
- card->devname);
- return -EINVAL;
-
- }
-
- /* allocate and initialize private data */
- ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL);
-
- if( ppp_priv_area == NULL )
- return -ENOMEM;
-
- memset(ppp_priv_area, 0, sizeof(ppp_private_area_t));
-
- ppp_priv_area->card = card;
-
- /* initialize data */
- strcpy(card->u.p.if_name, conf->name);
-
- /* initialize data in ppp_private_area structure */
-
- init_ppp_priv_struct( ppp_priv_area );
-
- ppp_priv_area->mc = conf->mc;
- ppp_priv_area->pap = conf->pap;
- ppp_priv_area->chap = conf->chap;
-
- /* Option to bring down the interface when
- * the link goes down */
- if (conf->if_down){
- set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down);
- printk("%s: Dynamic interface configuration enabled\n",
- card->devname);
- }
-
- /* If no user ids are specified */
- if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){
- kfree(ppp_priv_area);
- return -EINVAL;
- }
-
- /* If no passwords are specified */
- if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){
- kfree(ppp_priv_area);
- return -EINVAL;
- }
-
- if(strlen(conf->sysname) > 31){
- kfree(ppp_priv_area);
- return -EINVAL;
- }
-
- /* If no system name is specified */
- if(!strlen(conf->sysname) && (card->u.p.authenticator)){
- kfree(ppp_priv_area);
- return -EINVAL;
- }
-
- /* copy the data into the ppp private structure */
- memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid));
- memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd));
- memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname));
-
-
- ppp_priv_area->enable_IPX = conf->enable_IPX;
- if (conf->network_number){
- ppp_priv_area->network_number = conf->network_number;
- }else{
- ppp_priv_area->network_number = 0xDEADBEEF;
- }
-
- /* Tells us that if this interface is a
- * gateway or not */
- if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){
- printk(KERN_INFO "%s: Interface %s is set as a gateway.\n",
- card->devname,card->u.p.if_name);
- }
-
- /* prepare network device data space for registration */
- strcpy(dev->name,card->u.p.if_name);
-
- dev->init = &if_init;
- dev->priv = ppp_priv_area;
- dev->mtu = min_t(unsigned int, dev->mtu, card->wandev.mtu);
-
- /* Initialize the polling work routine */
- INIT_WORK(&ppp_priv_area->poll_work, (void*)(void*)ppp_poll, dev);
-
- /* Initialize the polling delay timer */
- init_timer(&ppp_priv_area->poll_delay_timer);
- ppp_priv_area->poll_delay_timer.data = (unsigned long)dev;
- ppp_priv_area->poll_delay_timer.function = ppp_poll_delay;
-
-
- /* Since we start with dummy IP addresses we can say
- * that route exists */
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-/*============================================================================
- * Delete logical channel.
- */
-static int del_if(struct wan_device *wandev, struct net_device *dev)
-{
- return 0;
-}
-
-static void disable_comm (sdla_t *card)
-{
- ppp_comm_disable_shutdown(card);
- return;
-}
-
-/****** WANPIPE-specific entry points ***************************************/
-
-/*============================================================================
- * Execute adapter interface command.
- */
-
-//FIXME: Why do we need this ????
-static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data)
-{
- ppp_mbox_t *mbox = card->mbox;
- int len;
-
- if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
- return -EFAULT;
-
- len = mbox->cmd.length;
-
- if (len) {
-
- if( copy_from_user((void*)&mbox->data, u_data, len))
- return -EFAULT;
-
- }
-
- /* execute command */
- if (!sdla_exec(mbox))
- return -EIO;
-
- /* return result */
- if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t)))
- return -EFAULT;
- len = mbox->cmd.length;
-
- if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
- return -EFAULT;
-
- return 0;
-}
-
-/****** Network Device Interface ********************************************/
-
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration. Returning anything but zero will fail interface
- * registration.
- */
-static int if_init(struct net_device *dev)
-{
- ppp_private_area_t *ppp_priv_area = dev->priv;
- sdla_t *card = ppp_priv_area->card;
- struct wan_device *wandev = &card->wandev;
-
- /* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = &if_header;
- dev->rebuild_header = &if_rebuild_hdr;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
- dev->tx_timeout = &if_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- /* Initialize media-specific parameters */
- dev->type = ARPHRD_PPP; /* ARP h/w type */
- dev->flags |= IFF_POINTOPOINT;
- dev->flags |= IFF_NOARP;
-
- /* Enable Mulitcasting if specified by user*/
- if (ppp_priv_area->mc == WANOPT_YES){
- dev->flags |= IFF_MULTICAST;
- }
-
- dev->mtu = wandev->mtu;
- dev->hard_header_len = PPP_HDR_LEN; /* media header length */
-
- /* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
-
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 100;
- SET_MODULE_OWNER(dev);
-
- return 0;
-}
-
-/*============================================================================
- * Open network interface.
- * o enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
-static int if_open(struct net_device *dev)
-{
- ppp_private_area_t *ppp_priv_area = dev->priv;
- sdla_t *card = ppp_priv_area->card;
- struct timeval tv;
- //unsigned long smp_flags;
-
- if (netif_running(dev))
- return -EBUSY;
-
- wanpipe_open(card);
-
- netif_start_queue(dev);
-
- do_gettimeofday( &tv );
- ppp_priv_area->router_start_time = tv.tv_sec;
-
- /* We cannot configure the card here because we don't
- * have access to the interface IP addresses.
- * Once the interface initilization is complete, we will be
- * able to access the IP addresses. Therefore,
- * configure the ppp link in the poll routine */
- set_bit(0,&ppp_priv_area->config_ppp);
- ppp_priv_area->config_wait_timeout=jiffies;
-
- /* Start the PPP configuration after 1sec delay.
- * This will give the interface initilization time
- * to finish its configuration */
- mod_timer(&ppp_priv_area->poll_delay_timer, jiffies + HZ);
- return 0;
-}
-
-/*============================================================================
- * Close network interface.
- * o if this is the last open, then disable communications and interrupts.
- * o reset flags.
- */
-static int if_close(struct net_device *dev)
-{
- ppp_private_area_t *ppp_priv_area = dev->priv;
- sdla_t *card = ppp_priv_area->card;
-
- netif_stop_queue(dev);
- wanpipe_close(card);
-
- del_timer (&ppp_priv_area->poll_delay_timer);
- return 0;
-}
-
-/*============================================================================
- * Build media header.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol' field of
- * the socket buffer, so that we don't forget it. If packet type is not
- * supported, set skb->protocol to 0 and discard packet later.
- *
- * Return: media header length.
- */
-static int if_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
-{
- switch (type)
- {
- case ETH_P_IP:
- case ETH_P_IPX:
- skb->protocol = htons(type);
- break;
-
- default:
- skb->protocol = 0;
- }
-
- return PPP_HDR_LEN;
-}
-
-/*============================================================================
- * Re-build media header.
- *
- * Return: 1 physical address resolved.
- * 0 physical address not resolved
- */
-static int if_rebuild_hdr (struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- ppp_private_area_t *ppp_priv_area = dev->priv;
- sdla_t *card = ppp_priv_area->card;
-
- printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, dev->name);
- return 1;
-}
-
-/*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
-static void if_tx_timeout(struct net_device *dev)
-{
- ppp_private_area_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
- /* If our device stays busy for at least 5 seconds then we will
- * kick start the device by making dev->tbusy = 0. We expect
- * that our device never stays busy more than 5 seconds. So this
- * is only used as a last resort.
- */
-
- ++ chan->if_send_stat.if_send_tbusy;
- ++card->wandev.stats.collisions;
-
- printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
- ++chan->if_send_stat.if_send_tbusy_timeout;
- netif_wake_queue (dev);
-}
-
-
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- * transmit from overlapping.
- * o check link state. If link is not up, then drop the packet.
- * o execute adapter send command.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- * protocol stack and can be used for flow control with protocol layer.
- */
-static int if_send (struct sk_buff *skb, struct net_device *dev)
-{
- ppp_private_area_t *ppp_priv_area = dev->priv;
- sdla_t *card = ppp_priv_area->card;
- unsigned char *sendpacket;
- unsigned long smp_flags;
- ppp_flags_t *flags = card->flags;
- int udp_type;
- int err=0;
-
- ++ppp_priv_area->if_send_stat.if_send_entry;
-
- netif_stop_queue(dev);
-
- if (skb == NULL) {
-
- /* If we get here, some higher layer thinks we've missed an
- * tx-done interrupt.
- */
- printk(KERN_INFO "%s: interface %s got kicked!\n",
- card->devname, dev->name);
-
- ++ppp_priv_area->if_send_stat.if_send_skb_null;
-
- netif_wake_queue(dev);
- return 0;
- }
-
- sendpacket = skb->data;
-
- udp_type = udp_pkt_type( skb, card );
-
-
- if (udp_type == UDP_PTPIPE_TYPE){
- if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
- ppp_priv_area)){
- flags->imask |= PPP_INTR_TIMER;
- }
- ++ppp_priv_area->if_send_stat.if_send_PIPE_request;
- netif_start_queue(dev);
- return 0;
- }
-
- /* Check for broadcast and multicast addresses
- * If found, drop (deallocate) a packet and return.
- */
- if(chk_bcast_mcast_addr(card, dev, skb)){
- ++card->wandev.stats.tx_dropped;
- dev_kfree_skb_any(skb);
- netif_start_queue(dev);
- return 0;
- }
-
-
- if(card->hw.type != SDLA_S514){
- s508_lock(card,&smp_flags);
- }
-
- if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
-
- printk(KERN_INFO "%s: Critical in if_send: %lx\n",
- card->wandev.name,card->wandev.critical);
-
- ++card->wandev.stats.tx_dropped;
- ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR;
- netif_start_queue(dev);
- goto if_send_exit_crit;
- }
-
- if (card->wandev.state != WAN_CONNECTED) {
-
- ++ppp_priv_area->if_send_stat.if_send_wan_disconnected;
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
-
- } else if (!skb->protocol) {
- ++ppp_priv_area->if_send_stat.if_send_protocol_error;
- ++card->wandev.stats.tx_errors;
- netif_start_queue(dev);
-
- } else {
-
- /*If it's IPX change the network numbers to 0 if they're ours.*/
- if( skb->protocol == htons(ETH_P_IPX) ) {
- if(ppp_priv_area->enable_IPX) {
- switch_net_numbers( skb->data,
- ppp_priv_area->network_number, 0);
- } else {
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
- goto if_send_exit_crit;
- }
- }
-
- if (ppp_send(card, skb->data, skb->len, skb->protocol)) {
- netif_stop_queue(dev);
- ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full;
- ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled;
- } else {
- ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr;
- ++card->wandev.stats.tx_packets;
- card->wandev.stats.tx_bytes += skb->len;
- netif_start_queue(dev);
- dev->trans_start = jiffies;
- }
- }
-
-if_send_exit_crit:
-
- if (!(err=netif_queue_stopped(dev))){
- dev_kfree_skb_any(skb);
- }else{
- ppp_priv_area->tick_counter = jiffies;
- flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */
- }
-
- clear_bit(SEND_CRIT,&card->wandev.critical);
- if(card->hw.type != SDLA_S514){
- s508_unlock(card,&smp_flags);
- }
-
- return err;
-}
-
-
-/*=============================================================================
- * Store a UDP management packet for later processing.
- */
-
-static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, struct net_device* dev,
- ppp_private_area_t* ppp_priv_area )
-{
- int udp_pkt_stored = 0;
-
- if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){
- ppp_priv_area->udp_pkt_lgth = skb->len;
- ppp_priv_area->udp_pkt_src = udp_pkt_src;
- memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len);
- ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP;
- ppp_priv_area->protocol = skb->protocol;
- udp_pkt_stored = 1;
- }else{
- if (skb->len > MAX_LGTH_UDP_MGNT_PKT){
- printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n",
- card->devname, skb->len);
- }else{
- printk(KERN_INFO "%s: PIPEMON UPD request already pending\n",
- card->devname);
- }
- ppp_priv_area->udp_pkt_lgth = 0;
- }
-
- if(udp_pkt_src == UDP_PKT_FRM_STACK){
- dev_kfree_skb_any(skb);
- }else{
- dev_kfree_skb_any(skb);
- }
-
- return(udp_pkt_stored);
-}
-
-
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return length of reply.
- */
-static int reply_udp( unsigned char *data, unsigned int mbox_len )
-{
- unsigned short len, udp_length, temp, ip_length;
- unsigned long ip_temp;
- int even_bound = 0;
- ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data;
-
- /* Set length of packet */
- len = sizeof(ip_pkt_t)+
- sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
- /* fill in UDP reply */
- p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
-
- /* fill in UDP length */
- udp_length = sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
-
- /* put it on an even boundary */
- if ( udp_length & 0x0001 ) {
- udp_length += 1;
- len += 1;
- even_bound=1;
- }
-
- temp = (udp_length<<8)|(udp_length>>8);
- p_udp_pkt->udp_pkt.udp_length = temp;
-
-
- /* swap UDP ports */
- temp = p_udp_pkt->udp_pkt.udp_src_port;
- p_udp_pkt->udp_pkt.udp_src_port =
- p_udp_pkt->udp_pkt.udp_dst_port;
- p_udp_pkt->udp_pkt.udp_dst_port = temp;
-
-
- /* add UDP pseudo header */
- temp = 0x1100;
- *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp;
- temp = (udp_length<<8)|(udp_length>>8);
- *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp;
-
- /* calculate UDP checksum */
- p_udp_pkt->udp_pkt.udp_checksum = 0;
- p_udp_pkt->udp_pkt.udp_checksum =
- calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET);
-
- /* fill in IP length */
- ip_length = udp_length + sizeof(ip_pkt_t);
- temp = (ip_length<<8)|(ip_length>>8);
- p_udp_pkt->ip_pkt.total_length = temp;
-
- /* swap IP addresses */
- ip_temp = p_udp_pkt->ip_pkt.ip_src_address;
- p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address;
- p_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
-
- /* fill in IP checksum */
- p_udp_pkt->ip_pkt.hdr_checksum = 0;
- p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t));
-
- return len;
-
-} /* reply_udp */
-
-unsigned short calc_checksum (char *data, int len)
-{
- unsigned short temp;
- unsigned long sum=0;
- int i;
-
- for( i = 0; i <len; i+=2 ) {
- memcpy(&temp,&data[i],2);
- sum += (unsigned long)temp;
- }
-
- while (sum >> 16 ) {
- sum = (sum & 0xffffUL) + (sum >> 16);
- }
-
- temp = (unsigned short)sum;
- temp = ~temp;
-
- if( temp == 0 )
- temp = 0xffff;
-
- return temp;
-}
-
-/*
- If incoming is 0 (outgoing)- if the net numbers is ours make it 0
- if incoming is 1 - if the net number is 0 make it ours
-
-*/
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
-{
- unsigned long pnetwork_number;
-
- pnetwork_number = (unsigned long)((sendpacket[6] << 24) +
- (sendpacket[7] << 16) + (sendpacket[8] << 8) +
- sendpacket[9]);
-
- if (!incoming) {
- //If the destination network number is ours, make it 0
- if( pnetwork_number == network_number) {
- sendpacket[6] = sendpacket[7] = sendpacket[8] =
- sendpacket[9] = 0x00;
- }
- } else {
- //If the incoming network is 0, make it ours
- if( pnetwork_number == 0) {
- sendpacket[6] = (unsigned char)(network_number >> 24);
- sendpacket[7] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[8] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[9] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
-
-
- pnetwork_number = (unsigned long)((sendpacket[18] << 24) +
- (sendpacket[19] << 16) + (sendpacket[20] << 8) +
- sendpacket[21]);
-
- if( !incoming ) {
- //If the source network is ours, make it 0
- if( pnetwork_number == network_number) {
- sendpacket[18] = sendpacket[19] = sendpacket[20] =
- sendpacket[21] = 0x00;
- }
- } else {
- //If the source network is 0, make it ours
- if( pnetwork_number == 0 ) {
- sendpacket[18] = (unsigned char)(network_number >> 24);
- sendpacket[19] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[20] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[21] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
-} /* switch_net_numbers */
-
-/*============================================================================
- * Get ethernet-style interface statistics.
- * Return a pointer to struct net_device_stats.
- */
-static struct net_device_stats *if_stats(struct net_device *dev)
-{
-
- ppp_private_area_t *ppp_priv_area = dev->priv;
- sdla_t* card;
-
- if( ppp_priv_area == NULL )
- return NULL;
-
- card = ppp_priv_area->card;
- return &card->wandev.stats;
-}
-
-/****** PPP Firmware Interface Functions ************************************/
-
-/*============================================================================
- * Read firmware code version.
- * Put code version as ASCII string in str.
- */
-static int ppp_read_version(sdla_t *card, char *str)
-{
- ppp_mbox_t *mb = card->mbox;
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.command = PPP_READ_CODE_VERSION;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
-
- ppp_error(card, err, mb);
-
- else if (str) {
-
- int len = mb->cmd.length;
-
- memcpy(str, mb->data, len);
- str[len] = '\0';
-
- }
-
- return err;
-}
-/*===========================================================================
- * Set Out-Bound Authentication.
-*/
-static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area)
-{
- ppp_mbox_t *mb = card->mbox;
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- memset(&mb->data, 0, (strlen(ppp_priv_area->userid) +
- strlen(ppp_priv_area->passwd) + 2 ) );
- memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid));
- memcpy((mb->data + strlen(ppp_priv_area->userid) + 1),
- ppp_priv_area->passwd, strlen(ppp_priv_area->passwd));
-
- mb->cmd.length = strlen(ppp_priv_area->userid) +
- strlen(ppp_priv_area->passwd) + 2 ;
-
- mb->cmd.command = PPP_SET_OUTBOUND_AUTH;
-
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
- ppp_error(card, err, mb);
-
- return err;
-}
-
-/*===========================================================================
- * Set In-Bound Authentication.
-*/
-static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area)
-{
- ppp_mbox_t *mb = card->mbox;
- int err, i;
- char* user_tokens[32];
- char* pass_tokens[32];
- int userids, passwds;
- int add_ptr;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- memset(&mb->data, 0, 1008);
- memcpy(mb->data, ppp_priv_area->sysname,
- strlen(ppp_priv_area->sysname));
-
- /* Parse the userid string and the password string and build a string
- to copy it to the data area of the command structure. The string
- will look like "SYS_NAME<NULL>USER1<NULL>PASS1<NULL>USER2<NULL>PASS2
- ....<NULL> "
- */
- userids = tokenize( ppp_priv_area->userid, user_tokens);
- passwds = tokenize( ppp_priv_area->passwd, pass_tokens);
-
- if (userids != passwds){
- printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname);
- return 1;
- }
-
- add_ptr = strlen(ppp_priv_area->sysname) + 1;
- for (i=0; i<userids; i++){
- memcpy((mb->data + add_ptr), user_tokens[i],
- strlen(user_tokens[i]));
- memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1),
- pass_tokens[i], strlen(pass_tokens[i]));
- add_ptr = add_ptr + strlen(user_tokens[i]) + 1 +
- strlen(pass_tokens[i]) + 1;
- }
-
- mb->cmd.length = add_ptr + 1;
- mb->cmd.command = PPP_SET_INBOUND_AUTH;
-
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
- ppp_error(card, err, mb);
-
- return err;
-}
-
-
-/*============================================================================
- * Tokenize string.
- * Parse a string of the following syntax:
- * <arg1>,<arg2>,...
- * and fill array of tokens with pointers to string elements.
- *
- */
-static int tokenize (char *str, char **tokens)
-{
- int cnt = 0;
-
- tokens[0] = strsep(&str, "/");
- while (tokens[cnt] && (cnt < 32 - 1))
- {
- tokens[cnt] = strstrip(tokens[cnt], " \t");
- tokens[++cnt] = strsep(&str, "/");
- }
- return cnt;
-}
-
-/*============================================================================
- * Strip leading and trailing spaces off the string str.
- */
-static char* strstrip (char *str, char* s)
-{
- char *eos = str + strlen(str); /* -> end of string */
-
- while (*str && strchr(s, *str))
- ++str /* strip leading spaces */
- ;
- while ((eos > str) && strchr(s, *(eos - 1)))
- --eos /* strip trailing spaces */
- ;
- *eos = '\0';
- return str;
-}
-/*============================================================================
- * Configure PPP firmware.
- */
-static int ppp_configure(sdla_t *card, void *data)
-{
- ppp_mbox_t *mb = card->mbox;
- int data_len = sizeof(ppp508_conf_t);
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- memcpy(mb->data, data, data_len);
- mb->cmd.length = data_len;
- mb->cmd.command = PPP_SET_CONFIG;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
- ppp_error(card, err, mb);
-
- return err;
-}
-
-/*============================================================================
- * Set interrupt mode.
- */
-static int ppp_set_intr_mode(sdla_t *card, unsigned char mode)
-{
- ppp_mbox_t *mb = card->mbox;
- ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0];
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- ppp_intr_data->i_enable = mode;
-
- ppp_intr_data->irq = card->hw.irq;
- mb->cmd.length = 2;
-
- /* If timer has been enabled, set the timer delay to 1sec */
- if (mode & 0x80){
- ppp_intr_data->timer_len = 250; //5;//100; //250;
- mb->cmd.length = 4;
- }
-
- mb->cmd.command = PPP_SET_INTR_FLAGS;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
- ppp_error(card, err, mb);
-
-
- return err;
-}
-
-/*============================================================================
- * Enable communications.
- */
-static int ppp_comm_enable(sdla_t *card)
-{
- ppp_mbox_t *mb = card->mbox;
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.command = PPP_COMM_ENABLE;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK)
- ppp_error(card, err, mb);
- else
- card->u.p.comm_enabled = 1;
-
- return err;
-}
-
-/*============================================================================
- * Disable communications.
- */
-static int ppp_comm_disable(sdla_t *card)
-{
- ppp_mbox_t *mb = card->mbox;
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.command = PPP_COMM_DISABLE;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
- ppp_error(card, err, mb);
- else
- card->u.p.comm_enabled = 0;
-
- return err;
-}
-
-static int ppp_comm_disable_shutdown(sdla_t *card)
-{
- ppp_mbox_t *mb = card->mbox;
- ppp_intr_info_t *ppp_intr_data;
- int err;
-
- if (!mb){
- return 1;
- }
-
- ppp_intr_data = (ppp_intr_info_t *) &mb->data[0];
-
- /* Disable all interrupts */
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- ppp_intr_data->i_enable = 0;
-
- ppp_intr_data->irq = card->hw.irq;
- mb->cmd.length = 2;
-
- mb->cmd.command = PPP_SET_INTR_FLAGS;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- /* Disable communicatinons */
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.command = PPP_COMM_DISABLE;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- card->u.p.comm_enabled = 0;
-
- return 0;
-}
-
-
-
-/*============================================================================
- * Get communications error statistics.
- */
-static int ppp_get_err_stats(sdla_t *card)
-{
- ppp_mbox_t *mb = card->mbox;
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.command = PPP_READ_ERROR_STATS;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err == CMD_OK) {
-
- ppp_err_stats_t* stats = (void*)mb->data;
- card->wandev.stats.rx_over_errors = stats->rx_overrun;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_abort;
- card->wandev.stats.rx_length_errors = stats->rx_lost;
- card->wandev.stats.tx_aborted_errors = stats->tx_abort;
-
- } else
- ppp_error(card, err, mb);
-
- return err;
-}
-
-/*============================================================================
- * Send packet.
- * Return: 0 - o.k.
- * 1 - no transmit buffers available
- */
-static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto)
-{
- ppp_buf_ctl_t *txbuf = card->u.p.txbuf;
-
- if (txbuf->flag)
- return 1;
-
- sdla_poke(&card->hw, txbuf->buf.ptr, data, len);
-
- txbuf->length = len; /* frame length */
-
- if (proto == htons(ETH_P_IPX))
- txbuf->proto = 0x01; /* protocol ID */
- else
- txbuf->proto = 0x00; /* protocol ID */
-
- txbuf->flag = 1; /* start transmission */
-
- /* Update transmit buffer control fields */
- card->u.p.txbuf = ++txbuf;
-
- if ((void*)txbuf > card->u.p.txbuf_last)
- card->u.p.txbuf = card->u.p.txbuf_base;
-
- return 0;
-}
-
-/****** Firmware Error Handler **********************************************/
-
-/*============================================================================
- * Firmware error handler.
- * This routine is called whenever firmware command returns non-zero
- * return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb)
-{
- unsigned cmd = mb->cmd.command;
-
- switch (err) {
-
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd);
- break;
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n"
- , card->devname, cmd, err);
- }
-
- return 0;
-}
-
-/****** Interrupt Handlers **************************************************/
-
-/*============================================================================
- * PPP interrupt service routine.
- */
-static void wpp_isr (sdla_t *card)
-{
- ppp_flags_t *flags = card->flags;
- char *ptr = &flags->iflag;
- struct net_device *dev = card->wandev.dev;
- int i;
-
- card->in_isr = 1;
- ++card->statistics.isr_entry;
-
- if (!dev && flags->iflag != PPP_INTR_CMD){
- card->in_isr = 0;
- flags->iflag = 0;
- return;
- }
-
- if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
- card->in_isr = 0;
- flags->iflag = 0;
- return;
- }
-
-
- if(card->hw.type != SDLA_S514){
- if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
- ++card->statistics.isr_already_critical;
- printk (KERN_INFO "%s: Critical while in ISR!\n",
- card->devname);
- card->in_isr = 0;
- flags->iflag = 0;
- return;
- }
- }
-
- switch (flags->iflag) {
-
- case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/
- ++card->statistics.isr_rx;
- rx_intr(card);
- break;
-
- case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/
- ++card->statistics.isr_tx;
- flags->imask &= ~PPP_INTR_TXRDY;
- netif_wake_queue(dev);
- break;
-
- case PPP_INTR_CMD: /* interface command completed */
- ++Intr_test_counter;
- ++card->statistics.isr_intr_test;
- break;
-
- case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/
- case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/
- case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/
- case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */
- event_intr(card);
- break;
-
- case PPP_INTR_TIMER:
- timer_intr(card);
- break;
-
- default: /* unexpected interrupt */
- ++card->statistics.isr_spurious;
- printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
- card->devname, flags->iflag);
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
- }
-
- card->in_isr = 0;
- flags->iflag = 0;
- return;
-}
-
-/*============================================================================
- * Receive interrupt handler.
- */
-static void rx_intr(sdla_t *card)
-{
- ppp_buf_ctl_t *rxbuf = card->rxmb;
- struct net_device *dev = card->wandev.dev;
- ppp_private_area_t *ppp_priv_area;
- struct sk_buff *skb;
- unsigned len;
- void *buf;
- int i;
- ppp_flags_t *flags = card->flags;
- char *ptr = &flags->iflag;
- int udp_type;
-
-
- if (rxbuf->flag != 0x01) {
-
- printk(KERN_INFO
- "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
- card->devname, (unsigned)rxbuf, rxbuf->flag);
-
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
-
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i));
- printk(KERN_INFO "\n");
-
- ++card->statistics.rx_intr_corrupt_rx_bfr;
-
-
- /* Bug Fix: Mar 6 2000
- * If we get a corrupted mailbox, it means that driver
- * is out of sync with the firmware. There is no recovery.
- * If we don't turn off all interrupts for this card
- * the machine will crash.
- */
- printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
- printk(KERN_INFO "Please contact Sangoma Technologies !\n");
- ppp_set_intr_mode(card,0);
- return;
- }
-
- if (dev && netif_running(dev) && dev->priv){
-
- len = rxbuf->length;
- ppp_priv_area = dev->priv;
-
- /* Allocate socket buffer */
- skb = dev_alloc_skb(len);
-
- if (skb != NULL) {
-
- /* Copy data to the socket buffer */
- unsigned addr = rxbuf->buf.ptr;
-
- if ((addr + len) > card->u.p.rx_top + 1) {
-
- unsigned tmp = card->u.p.rx_top - addr + 1;
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, addr, buf, tmp);
- addr = card->u.p.rx_base;
- len -= tmp;
- }
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, addr, buf, len);
-
- /* Decapsulate packet */
- switch (rxbuf->proto) {
-
- case 0x00:
- skb->protocol = htons(ETH_P_IP);
- break;
-
- case 0x01:
- skb->protocol = htons(ETH_P_IPX);
- break;
- }
-
- udp_type = udp_pkt_type( skb, card );
-
- if (udp_type == UDP_PTPIPE_TYPE){
-
- /* Handle a UDP Request in Timer Interrupt */
- if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev,
- ppp_priv_area)){
- flags->imask |= PPP_INTR_TIMER;
- }
- ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request;
-
-
- } else if (handle_IPXWAN(skb->data,card->devname,
- ppp_priv_area->enable_IPX,
- ppp_priv_area->network_number,
- skb->protocol)) {
-
- /* Handle an IPXWAN packet */
- if( ppp_priv_area->enable_IPX) {
-
- /* Make sure we are not already sending */
- if (!test_bit(SEND_CRIT, &card->wandev.critical)){
- ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX));
- }
- dev_kfree_skb_any(skb);
-
- } else {
- ++card->wandev.stats.rx_dropped;
- }
- } else {
- /* Pass data up the protocol stack */
- skb->dev = dev;
- skb->mac.raw = skb->data;
-
- ++card->wandev.stats.rx_packets;
- card->wandev.stats.rx_bytes += skb->len;
- ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
-
- } else {
-
- if (net_ratelimit()){
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- }
- ++card->wandev.stats.rx_dropped;
- ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket;
- }
-
- } else {
- ++card->statistics.rx_intr_dev_not_started;
- }
-
- /* Release buffer element and calculate a pointer to the next one */
- rxbuf->flag = 0x00;
- card->rxmb = ++rxbuf;
- if ((void*)rxbuf > card->u.p.rxbuf_last)
- card->rxmb = card->u.p.rxbuf_base;
-}
-
-
-void event_intr (sdla_t *card)
-{
-
- struct net_device* dev = card->wandev.dev;
- ppp_private_area_t* ppp_priv_area = dev->priv;
- volatile ppp_flags_t *flags = card->flags;
-
- switch (flags->iflag){
-
- case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/
-
- if (net_ratelimit()){
- printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n",
- card->devname, DCD(flags->mstatus), CTS(flags->mstatus));
- }
- break;
-
- case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/
-
- NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n",
- flags->disc_cause);
-
- if (flags->disc_cause &
- (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP |
- PPP_REMOTE_TERMINATION)) {
-
- if (card->u.p.ip_mode == WANOPT_PPP_PEER) {
- set_bit(0,&Read_connection_info);
- }
- wanpipe_set_state(card, WAN_DISCONNECTED);
-
- show_disc_cause(card, flags->disc_cause);
- ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT;
- flags->imask |= PPP_INTR_TIMER;
- trigger_ppp_poll(dev);
- }
- break;
-
- case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/
-
- NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n",
- card->devname,LCP(flags->lcp_state),
- IP(flags->ip_state));
-
- if (flags->lcp_state == 0x09 &&
- (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){
-
- /* Initialize the polling timer and set the state
- * to WAN_CONNNECTED */
-
-
- /* BUG FIX: When the protocol restarts, during heavy
- * traffic, board tx buffers and driver tx buffers
- * can go out of sync. This checks the condition
- * and if the tx buffers are out of sync, the
- * protocols are restarted.
- * I don't know why the board tx buffer is out
- * of sync. It could be that a packets is tx
- * while the link is down, but that is not
- * possible. The other possiblility is that the
- * firmware doesn't reinitialize properly.
- * FIXME: A better fix should be found.
- */
- if (detect_and_fix_tx_bug(card)){
-
- ppp_comm_disable(card);
-
- wanpipe_set_state(card, WAN_DISCONNECTED);
-
- ppp_priv_area->timer_int_enabled |=
- TMR_INT_ENABLED_PPP_EVENT;
- flags->imask |= PPP_INTR_TIMER;
- break;
- }
-
- card->state_tick = jiffies;
- wanpipe_set_state(card, WAN_CONNECTED);
-
- NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n",
- (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next,
- (unsigned long)card->rxmb, *card->u.p.rxbuf_next);
-
- /* Tell timer interrupt that PPP event occurred */
- ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT;
- flags->imask |= PPP_INTR_TIMER;
-
- /* If we are in PEER mode, we must first obtain the
- * IP information and then go into the poll routine */
- if (card->u.p.ip_mode != WANOPT_PPP_PEER){
- trigger_ppp_poll(dev);
- }
- }
- break;
-
- case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */
-
- NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n");
-
- if (card->u.p.ip_mode == WANOPT_PPP_PEER) {
- set_bit(0,&Read_connection_info);
- }
-
- wanpipe_set_state(card, WAN_DISCONNECTED);
-
- show_disc_cause(card, flags->disc_cause);
- ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT;
- flags->imask |= PPP_INTR_TIMER;
- trigger_ppp_poll(dev);
- break;
-
- default:
- printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname);
- }
-}
-
-
-
-/* TIMER INTERRUPT */
-
-void timer_intr (sdla_t *card)
-{
-
- struct net_device* dev = card->wandev.dev;
- ppp_private_area_t* ppp_priv_area = dev->priv;
- ppp_flags_t *flags = card->flags;
-
-
- if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){
- if (!config_ppp(card)){
- ppp_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_CONFIG;
- }
- }
-
- /* Update statistics */
- if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){
- ppp_get_err_stats(card);
- if(!(--ppp_priv_area->update_comms_stats)){
- ppp_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_UPDATE;
- }
- }
-
- /* PPIPEMON UDP request */
-
- if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){
- process_udp_mgmt_pkt(card,dev, ppp_priv_area);
- ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
- }
-
- /* PPP Event */
- if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){
-
- if (card->wandev.state == WAN_DISCONNECTED){
- retrigger_comm(card);
- }
-
- /* If the state is CONNECTING, it means that communicatins were
- * enabled. When the remote side enables its comminication we
- * should get an interrupt PPP_INTR_OPEN, thus turn off polling
- */
-
- else if (card->wandev.state == WAN_CONNECTING){
- /* Turn off the timer interrupt */
- ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT;
- }
-
- /* If state is connected and we are in PEER mode
- * poll for an IP address which will be provided by remote end.
- */
- else if ((card->wandev.state == WAN_CONNECTED &&
- card->u.p.ip_mode == WANOPT_PPP_PEER) &&
- test_bit(0,&Read_connection_info)){
-
- card->state_tick = jiffies;
- if (read_connection_info (card)){
- printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n",
- card->devname);
- }else{
- clear_bit(0,&Read_connection_info);
- set_bit(1,&Read_connection_info);
- trigger_ppp_poll(dev);
- }
- }else{
- //FIXME Put the comment back int
- ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT;
- }
-
- }/* End of PPP_EVENT */
-
-
- /* Only disable the timer interrupt if there are no udp, statistic */
- /* updates or events pending */
- if(!ppp_priv_area->timer_int_enabled) {
- flags->imask &= ~PPP_INTR_TIMER;
- }
-}
-
-
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
-{
- int i;
-
- if( proto == htons(ETH_P_IPX) ) {
- //It's an IPX packet
- if(!enable_IPX) {
- //Return 1 so we don't pass it up the stack.
- return 1;
- }
- } else {
- //It's not IPX so pass it up the stack.
- return 0;
- }
-
- if( sendpacket[16] == 0x90 &&
- sendpacket[17] == 0x04)
- {
- //It's IPXWAN
-
- if( sendpacket[2] == 0x02 &&
- sendpacket[34] == 0x00)
- {
- //It's a timer request packet
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
-
- //Go through the routing options and answer no to every
- //option except Unnumbered RIP/SAP
- for(i = 41; sendpacket[i] == 0x00; i += 5)
- {
- //0x02 is the option for Unnumbered RIP/SAP
- if( sendpacket[i + 4] != 0x02)
- {
- sendpacket[i + 1] = 0;
- }
- }
-
- //Skip over the extended Node ID option
- if( sendpacket[i] == 0x04 )
- {
- i += 8;
- }
-
- //We also want to turn off all header compression opt.
- for(; sendpacket[i] == 0x80 ;)
- {
- sendpacket[i + 1] = 0;
- i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
- }
-
- //Set the packet type to timer response
- sendpacket[34] = 0x01;
-
- printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
- }
- else if( sendpacket[34] == 0x02 )
- {
- //This is an information request packet
- printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
-
- //Set the packet type to information response
- sendpacket[34] = 0x03;
-
- //Set the router name
- sendpacket[51] = 'P';
- sendpacket[52] = 'T';
- sendpacket[53] = 'P';
- sendpacket[54] = 'I';
- sendpacket[55] = 'P';
- sendpacket[56] = 'E';
- sendpacket[57] = '-';
- sendpacket[58] = CVHexToAscii(network_number >> 28);
- sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
- sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
- sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
- sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
- sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
- sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
- sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
- for(i = 66; i < 99; i+= 1)
- {
- sendpacket[i] = 0;
- }
-
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
- }
- else
- {
- printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
- return 0;
- }
-
- //Set the WNodeID to our network address
- sendpacket[35] = (unsigned char)(network_number >> 24);
- sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
- sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
- sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
-
- return 1;
- } else {
- //If we get here it's an IPX-data packet, so it'll get passed up the stack.
-
- //switch the network numbers
- switch_net_numbers(sendpacket, network_number, 1);
- return 0;
- }
-}
-
-/****** Background Polling Routines ****************************************/
-
-/* All polling functions are invoked by the TIMER interrupt in the wpp_isr
- * routine.
- */
-
-/*============================================================================
- * Monitor active link phase.
- */
-static void process_route (sdla_t *card)
-{
- ppp_flags_t *flags = card->flags;
- struct net_device *dev = card->wandev.dev;
- ppp_private_area_t *ppp_priv_area = dev->priv;
-
- if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
- (flags->ip_state == 0x09)){
-
- /* We get ip_local from the firmware in PEER mode.
- * Therefore, if ip_local is 0, we failed to obtain
- * the remote IP address. */
- if (ppp_priv_area->ip_local == 0)
- return;
-
- printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname);
- if (read_info( card )) {
- printk(KERN_INFO
- "%s: An error occurred in IP assignment.\n",
- card->devname);
- } else {
- struct in_device *in_dev = dev->ip_ptr;
- if (in_dev != NULL ) {
- struct in_ifaddr *ifa = in_dev->ifa_list;
-
- printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n",
- card->devname, NIPQUAD(ifa->ifa_local));
- printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n",
- card->devname, NIPQUAD(ifa->ifa_address));
- }else{
- printk(KERN_INFO
- "%s: Error: Failed to add a route for PPP interface %s\n",
- card->devname,dev->name);
- }
- }
- }
-}
-
-/*============================================================================
- * Monitor physical link disconnected phase.
- * o if interface is up and the hold-down timeout has expired, then retry
- * connection.
- */
-static void retrigger_comm(sdla_t *card)
-{
- struct net_device *dev = card->wandev.dev;
-
- if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
-
- wanpipe_set_state(card, WAN_CONNECTING);
-
- if(ppp_comm_enable(card) == CMD_OK){
- init_ppp_tx_rx_buff( card );
- }
- }
-}
-
-/****** Miscellaneous Functions *********************************************/
-
-/*============================================================================
- * Configure S508 adapter.
- */
-static int config508(struct net_device *dev, sdla_t *card)
-{
- ppp508_conf_t cfg;
- struct in_device *in_dev = dev->ip_ptr;
- ppp_private_area_t *ppp_priv_area = dev->priv;
-
- /* Prepare PPP configuration structure */
- memset(&cfg, 0, sizeof(ppp508_conf_t));
-
- if (card->wandev.clocking)
- cfg.line_speed = card->wandev.bps;
-
- if (card->wandev.interface == WANOPT_RS232)
- cfg.conf_flags |= INTERFACE_LEVEL_RS232;
-
-
- cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/
- cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */
- cfg.mtu_local = card->wandev.mtu;
- cfg.mtu_remote = card->wandev.mtu; /* Default */
- cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */
- cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */
- cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */
- cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */
- cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */
- cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */
- cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */
- cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */
- cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */
- cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */
-
-
- if( !card->u.p.authenticator ) {
- printk(KERN_INFO "%s: Device is not configured as an authenticator\n",
- card->devname);
- cfg.auth_options = NO_AUTHENTICATION;
- }else{
- printk(KERN_INFO "%s: Device is configured as an authenticator\n",
- card->devname);
- cfg.auth_options = INBOUND_AUTH;
- }
-
- if( ppp_priv_area->pap == WANOPT_YES){
- cfg.auth_options |=PAP_AUTH;
- printk(KERN_INFO "%s: Pap enabled\n", card->devname);
- }
- if( ppp_priv_area->chap == WANOPT_YES){
- cfg.auth_options |= CHAP_AUTH;
- printk(KERN_INFO "%s: Chap enabled\n", card->devname);
- }
-
-
- if (ppp_priv_area->enable_IPX == WANOPT_YES){
- printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname);
- cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT;
- }else{
- cfg.ipx_options = DISABLE_IPX;
- }
-
- switch (card->u.p.ip_mode) {
-
- case WANOPT_PPP_STATIC:
-
- printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname);
- cfg.ip_options = L_AND_R_IP_NO_ASSIG |
- ENABLE_IP;
- cfg.ip_local = in_dev->ifa_list->ifa_local;
- cfg.ip_remote = in_dev->ifa_list->ifa_address;
- /* Debugging code used to check that IP addresses
- * obtained from the kernel are correct */
-
- NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n",
- NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name);
- break;
-
- case WANOPT_PPP_HOST:
-
- printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname);
- cfg.ip_options = L_IP_LOCAL_ASSIG |
- R_IP_LOCAL_ASSIG |
- ENABLE_IP;
- cfg.ip_local = in_dev->ifa_list->ifa_local;
- cfg.ip_remote = in_dev->ifa_list->ifa_address;
- /* Debugging code used to check that IP addresses
- * obtained from the kernel are correct */
- NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n",
- NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name);
-
- break;
-
- case WANOPT_PPP_PEER:
-
- printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname);
- cfg.ip_options = L_IP_REMOTE_ASSIG |
- R_IP_REMOTE_ASSIG |
- ENABLE_IP;
- cfg.ip_local = 0x00;
- cfg.ip_remote = 0x00;
- break;
-
- default:
- printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n",
- card->devname);
- printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n",
- card->devname);
- return 1;
- }
-
- return ppp_configure(card, &cfg);
-}
-
-/*============================================================================
- * Show disconnection cause.
- */
-static void show_disc_cause(sdla_t *card, unsigned cause)
-{
- if (cause & 0x0802)
-
- printk(KERN_INFO "%s: link terminated by peer\n",
- card->devname);
-
- else if (cause & 0x0004)
-
- printk(KERN_INFO "%s: link terminated by user\n",
- card->devname);
-
- else if (cause & 0x0008)
-
- printk(KERN_INFO "%s: authentication failed\n", card->devname);
-
- else if (cause & 0x0010)
-
- printk(KERN_INFO
- "%s: authentication protocol negotiation failed\n",
- card->devname);
-
- else if (cause & 0x0020)
-
- printk(KERN_INFO
- "%s: peer's request for authentication rejected\n",
- card->devname);
-
- else if (cause & 0x0040)
-
- printk(KERN_INFO "%s: MRU option rejected by peer\n",
- card->devname);
-
- else if (cause & 0x0080)
-
- printk(KERN_INFO "%s: peer's MRU was too small\n",
- card->devname);
-
- else if (cause & 0x0100)
-
- printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n",
- card->devname);
-
- else if (cause & 0x0200)
-
- printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n"
- , card->devname);
-
- else if (cause & 0x0400)
-
- printk(KERN_INFO
- "%s: failed to negotiate peer's IPXCP options\n",
- card->devname);
-}
-
-/*=============================================================================
- * Process UDP call of type PTPIPEAB.
- */
-static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev,
- ppp_private_area_t *ppp_priv_area )
-{
- unsigned char buf2[5];
- unsigned char *buf;
- unsigned int frames, len;
- struct sk_buff *new_skb;
- unsigned short data_length, buffer_length, real_len;
- unsigned long data_ptr;
- int udp_mgmt_req_valid = 1;
- ppp_mbox_t *mbox = card->mbox;
- struct timeval tv;
- int err;
- ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data;
-
- memcpy(&buf2, &card->wandev.udp_port, 2 );
-
-
- if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- switch(ppp_udp_pkt->cblock.command) {
-
- case PPIPE_GET_IBA_DATA:
- case PPP_READ_CONFIG:
- case PPP_GET_CONNECTION_INFO:
- case PPIPE_ROUTER_UP_TIME:
- case PPP_READ_STATISTICS:
- case PPP_READ_ERROR_STATS:
- case PPP_READ_PACKET_STATS:
- case PPP_READ_LCP_STATS:
- case PPP_READ_IPCP_STATS:
- case PPP_READ_IPXCP_STATS:
- case PPP_READ_PAP_STATS:
- case PPP_READ_CHAP_STATS:
- case PPP_READ_CODE_VERSION:
- udp_mgmt_req_valid = 1;
- break;
-
- default:
- udp_mgmt_req_valid = 0;
- break;
- }
- }
-
- if(!udp_mgmt_req_valid) {
-
- /* set length to 0 */
- ppp_udp_pkt->cblock.length = 0x00;
-
- /* set return code */
- ppp_udp_pkt->cblock.result = 0xCD;
- ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err;
-
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Warning, Illegal UDP command attempted from network: %x\n",
- card->devname,ppp_udp_pkt->cblock.command);
- }
- } else {
- /* Initialize the trace element */
- trace_element_t trace_element;
-
- switch (ppp_udp_pkt->cblock.command){
-
- /* PPIPE_ENABLE_TRACING */
- case PPIPE_ENABLE_TRACING:
- if (!card->TracingEnabled) {
-
- /* OPERATE_DATALINE_MONITOR */
- mbox->cmd.command = PPP_DATALINE_MONITOR;
- mbox->cmd.length = 0x01;
- mbox->data[0] = ppp_udp_pkt->data[0];
- err = sdla_exec(mbox) ?
- mbox->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK) {
-
- ppp_error(card, err, mbox);
- card->TracingEnabled = 0;
-
- /* set the return code */
-
- ppp_udp_pkt->cblock.result = mbox->cmd.result;
- mbox->cmd.length = 0;
- break;
- }
-
- sdla_peek(&card->hw, 0xC000, &buf2, 2);
-
- ppp_priv_area->curr_trace_addr = 0;
- memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2);
- ppp_priv_area->start_trace_addr =
- ppp_priv_area->curr_trace_addr;
- ppp_priv_area->end_trace_addr =
- ppp_priv_area->start_trace_addr + END_OFFSET;
-
- /* MAX_SEND_BUFFER_SIZE - 28 (IP header)
- - 32 (ppipemon CBLOCK) */
- available_buffer_space = MAX_LGTH_UDP_MGNT_PKT -
- sizeof(ip_pkt_t)-
- sizeof(udp_pkt_t)-
- sizeof(wp_mgmt_t)-
- sizeof(cblock_t);
- }
- ppp_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 0;
- card->TracingEnabled = 1;
- break;
-
- /* PPIPE_DISABLE_TRACING */
- case PPIPE_DISABLE_TRACING:
-
- if(card->TracingEnabled) {
-
- /* OPERATE_DATALINE_MONITOR */
- mbox->cmd.command = 0x33;
- mbox->cmd.length = 1;
- mbox->data[0] = 0x00;
- err = sdla_exec(mbox) ?
- mbox->cmd.result : CMD_TIMEOUT;
-
- }
-
- /*set return code*/
- ppp_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 0;
- card->TracingEnabled = 0;
- break;
-
- /* PPIPE_GET_TRACE_INFO */
- case PPIPE_GET_TRACE_INFO:
-
- if(!card->TracingEnabled) {
- /* set return code */
- ppp_udp_pkt->cblock.result = 1;
- mbox->cmd.length = 0;
- }
-
- buffer_length = 0;
-
- /* frames < 62, where 62 is the number of trace
- information elements. There is in total 496
- bytes of space and each trace information
- element is 8 bytes.
- */
- for ( frames=0; frames<62; frames++) {
-
- trace_pkt_t *trace_pkt = (trace_pkt_t *)
- &ppp_udp_pkt->data[buffer_length];
-
- /* Read the whole trace packet */
- sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr,
- &trace_element, sizeof(trace_element_t));
-
- /* no data on board so exit */
- if( trace_element.opp_flag == 0x00 )
- break;
-
- data_ptr = trace_element.trace_data_ptr;
-
- /* See if there is actual data on the trace buffer */
- if (data_ptr){
- data_length = trace_element.trace_length;
- }else{
- data_length = 0;
- ppp_udp_pkt->data[0] |= 0x02;
- }
-
- //FIXME: Do we need this check
- if ((available_buffer_space - buffer_length)
- < (sizeof(trace_element_t)+1)){
-
- /*indicate we have more frames
- * on board and exit
- */
- ppp_udp_pkt->data[0] |= 0x02;
- break;
- }
-
- trace_pkt->status = trace_element.trace_type;
- trace_pkt->time_stamp = trace_element.trace_time_stamp;
- trace_pkt->real_length = trace_element.trace_length;
-
- real_len = trace_element.trace_length;
-
- if(data_ptr == 0){
- trace_pkt->data_avail = 0x00;
- }else{
- /* we can take it next time */
- if ((available_buffer_space - buffer_length)<
- (real_len + sizeof(trace_pkt_t))){
-
- ppp_udp_pkt->data[0] |= 0x02;
- break;
- }
- trace_pkt->data_avail = 0x01;
-
- /* get the data */
- sdla_peek(&card->hw, data_ptr,
- &trace_pkt->data,
- real_len);
- }
- /* zero the opp flag to
- show we got the frame */
- buf2[0] = 0x00;
- sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr,
- &buf2, 1);
-
- /* now move onto the next
- frame */
- ppp_priv_area->curr_trace_addr += 8;
-
- /* check if we passed the last address */
- if ( ppp_priv_area->curr_trace_addr >=
- ppp_priv_area->end_trace_addr){
-
- ppp_priv_area->curr_trace_addr =
- ppp_priv_area->start_trace_addr;
- }
-
- /* update buffer length and make sure its even */
-
- if ( trace_pkt->data_avail == 0x01 ) {
- buffer_length += real_len - 1;
- }
-
- /* for the header */
- buffer_length += 8;
-
- if( buffer_length & 0x0001 )
- buffer_length += 1;
- }
-
- /* ok now set the total number of frames passed
- in the high 5 bits */
- ppp_udp_pkt->data[0] |= (frames << 2);
-
- /* set the data length */
- mbox->cmd.length = buffer_length;
- ppp_udp_pkt->cblock.length = buffer_length;
-
- /* set return code */
- ppp_udp_pkt->cblock.result = 0;
- break;
-
- /* PPIPE_GET_IBA_DATA */
- case PPIPE_GET_IBA_DATA:
-
- mbox->cmd.length = 0x09;
-
- sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data,
- mbox->cmd.length);
-
- /* set the length of the data */
- ppp_udp_pkt->cblock.length = 0x09;
-
- /* set return code */
- ppp_udp_pkt->cblock.result = 0x00;
- ppp_udp_pkt->cblock.result = 0;
- break;
-
- /* PPIPE_FT1_READ_STATUS */
- case PPIPE_FT1_READ_STATUS:
- sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2);
- ppp_udp_pkt->cblock.length = mbox->cmd.length = 2;
- ppp_udp_pkt->cblock.result = 0;
- break;
-
- case PPIPE_FLUSH_DRIVER_STATS:
- init_ppp_priv_struct( ppp_priv_area );
- init_global_statistics( card );
- mbox->cmd.length = 0;
- ppp_udp_pkt->cblock.result = 0;
- break;
-
-
- case PPIPE_ROUTER_UP_TIME:
-
- do_gettimeofday( &tv );
- ppp_priv_area->router_up_time = tv.tv_sec -
- ppp_priv_area->router_start_time;
- *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time;
- mbox->cmd.length = 4;
- ppp_udp_pkt->cblock.result = 0;
- break;
-
- /* PPIPE_DRIVER_STATISTICS */
- case PPIPE_DRIVER_STAT_IFSEND:
- memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat,
- sizeof(if_send_stat_t));
-
-
- ppp_udp_pkt->cblock.result = 0;
- ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t);
- mbox->cmd.length = sizeof(if_send_stat_t);
- break;
-
- case PPIPE_DRIVER_STAT_INTR:
- memcpy(&ppp_udp_pkt->data, &card->statistics,
- sizeof(global_stats_t));
-
- memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t),
- &ppp_priv_area->rx_intr_stat,
- sizeof(rx_intr_stat_t));
-
- ppp_udp_pkt->cblock.result = 0;
- ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+
- sizeof(rx_intr_stat_t);
- mbox->cmd.length = ppp_udp_pkt->cblock.length;
- break;
-
- case PPIPE_DRIVER_STAT_GEN:
- memcpy( &ppp_udp_pkt->data,
- &ppp_priv_area->pipe_mgmt_stat,
- sizeof(pipe_mgmt_stat_t));
-
- memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t),
- &card->statistics, sizeof(global_stats_t));
-
- ppp_udp_pkt->cblock.result = 0;
- ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+
- sizeof(rx_intr_stat_t);
- mbox->cmd.length = ppp_udp_pkt->cblock.length;
- break;
-
-
- /* FT1 MONITOR STATUS */
- case FT1_MONITOR_STATUS_CTRL:
-
- /* Enable FT1 MONITOR STATUS */
- if( ppp_udp_pkt->data[0] == 1) {
-
- if( rCount++ != 0 ) {
- ppp_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
-
- /* Disable FT1 MONITOR STATUS */
- if( ppp_udp_pkt->data[0] == 0) {
-
- if( --rCount != 0) {
- ppp_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
- goto udp_dflt_cmd;
-
- /* WARNING: FIXME: This should be fixed.
- * The FT1 Status Ctrl doesn't have a break
- * statment. Thus, no code must be inserted
- * HERE: between default and above case statement */
-
- default:
-udp_dflt_cmd:
-
- /* it's a board command */
- mbox->cmd.command = ppp_udp_pkt->cblock.command;
- mbox->cmd.length = ppp_udp_pkt->cblock.length;
-
- if(mbox->cmd.length) {
- memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data,
- mbox->cmd.length);
- }
-
- /* run the command on the board */
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK) {
-
- ppp_error(card, err, mbox);
- ++ppp_priv_area->pipe_mgmt_stat.
- UDP_PIPE_mgmt_adptr_cmnd_timeout;
- break;
- }
-
- ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK;
-
- /* copy the result back to our buffer */
- memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t));
-
- if(mbox->cmd.length) {
- memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length);
- }
-
- } /* end of switch */
- } /* end of else */
-
- /* Fill UDP TTL */
- ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
- len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length);
-
- if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- /* Make sure we are not already sending */
- if (!test_bit(SEND_CRIT,&card->wandev.critical)){
- ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr;
- ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol);
- }
-
- } else {
-
- /* Pass it up the stack
- Allocate socket buffer */
- if ((new_skb = dev_alloc_skb(len)) != NULL) {
-
- /* copy data into new_skb */
-
- buf = skb_put(new_skb, len);
- memcpy(buf,ppp_priv_area->udp_pkt_data, len);
-
- ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack;
-
- /* Decapsulate packet and pass it up the protocol
- stack */
- new_skb->protocol = htons(ETH_P_IP);
- new_skb->dev = dev;
- new_skb->mac.raw = new_skb->data;
- netif_rx(new_skb);
- dev->last_rx = jiffies;
-
- } else {
-
- ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket;
- printk(KERN_INFO "no socket buffers available!\n");
- }
- }
-
- ppp_priv_area->udp_pkt_lgth = 0;
-
- return;
-}
-
-/*=============================================================================
- * Initial the ppp_private_area structure.
- */
-static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area )
-{
-
- memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t));
- memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t));
- memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t));
-}
-
-/*============================================================================
- * Initialize Global Statistics
- */
-static void init_global_statistics( sdla_t *card )
-{
- memset(&card->statistics, 0, sizeof(global_stats_t));
-}
-
-/*============================================================================
- * Initialize Receive and Transmit Buffers.
- */
-static void init_ppp_tx_rx_buff( sdla_t *card )
-{
- ppp508_buf_info_t* info;
-
- if (card->hw.type == SDLA_S514) {
-
- info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS);
-
- card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
- info->txb_ptr);
-
- card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
- (info->txb_num - 1);
-
- card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
- info->rxb_ptr);
-
- card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
- (info->rxb_num - 1);
-
- } else {
-
- info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS);
-
- card->u.p.txbuf_base = (void*)(card->hw.dpmbase +
- (info->txb_ptr - PPP508_MB_VECT));
-
- card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base +
- (info->txb_num - 1);
-
- card->u.p.rxbuf_base = (void*)(card->hw.dpmbase +
- (info->rxb_ptr - PPP508_MB_VECT));
-
- card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base +
- (info->rxb_num - 1);
- }
-
- card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt;
- card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr;
-
- card->u.p.rx_base = info->rxb_base;
- card->u.p.rx_top = info->rxb_end;
-
- card->u.p.txbuf = card->u.p.txbuf_base;
- card->rxmb = card->u.p.rxbuf_base;
-
-}
-
-/*=============================================================================
- * Read Connection Information (ie for Remote IP address assginment).
- * Called when ppp interface connected.
- */
-static int read_info( sdla_t *card )
-{
- struct net_device *dev = card->wandev.dev;
- ppp_private_area_t *ppp_priv_area = dev->priv;
- int err;
-
- struct ifreq if_info;
- struct sockaddr_in *if_data1, *if_data2;
- mm_segment_t fs;
-
- /* Set Local and remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
-
-
- fs = get_fs();
- set_fs(get_ds()); /* get user space block */
-
- /* Change the local and remote ip address of the interface.
- * This will also add in the destination route.
- */
- if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
- if_data1->sin_addr.s_addr = ppp_priv_area->ip_local;
- if_data1->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFADDR, &if_info );
- if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote;
- if_data2->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
-
- set_fs(fs); /* restore old block */
-
- if (err) {
- printk (KERN_INFO "%s: Adding of route failed: %i\n",
- card->devname,err);
- printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n",
- card->devname,NIPQUAD(ppp_priv_area->ip_local));
- printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n",
- card->devname,NIPQUAD(ppp_priv_area->ip_remote));
- }
- return err;
-}
-
-/*=============================================================================
- * Remove Dynamic Route.
- * Called when ppp interface disconnected.
- */
-
-static void remove_route( sdla_t *card )
-{
-
- struct net_device *dev = card->wandev.dev;
- long ip_addr;
- int err;
-
- mm_segment_t fs;
- struct ifreq if_info;
- struct sockaddr_in *if_data1;
- struct in_device *in_dev = dev->ip_ptr;
- struct in_ifaddr *ifa = in_dev->ifa_list;
-
- ip_addr = ifa->ifa_local;
-
- /* Set Local and remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
-
- fs = get_fs();
- set_fs(get_ds()); /* get user space block */
-
- /* Change the local ip address of the interface to 0.
- * This will also delete the destination route.
- */
- if_data1 = (struct sockaddr_in *)&if_info.ifr_addr;
- if_data1->sin_addr.s_addr = 0;
- if_data1->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFADDR, &if_info );
-
- set_fs(fs); /* restore old block */
-
-
- if (err) {
- printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n",
- card->devname, err);
- return;
- }else{
- printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n",
- card->devname, NIPQUAD(ip_addr));
- }
- return;
-}
-
-/*=============================================================================
- * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR
- * _TEST_COUNTER times.
- */
-static int intr_test( sdla_t *card )
-{
- ppp_mbox_t *mb = card->mbox;
- int err,i;
-
- err = ppp_set_intr_mode( card, 0x08 );
-
- if (err == CMD_OK) {
-
- for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {
- /* Run command READ_CODE_VERSION */
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.length = 0;
- mb->cmd.command = PPP_READ_CODE_VERSION;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
- ppp_error(card, err, mb);
- }
- }
- else return err;
-
- err = ppp_set_intr_mode( card, 0 );
- if (err != CMD_OK)
- return err;
-
- return 0;
-}
-
-/*==============================================================================
- * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ?
- */
-static int udp_pkt_type( struct sk_buff *skb, sdla_t *card )
-{
- unsigned char *sendpacket;
- unsigned char buf2[5];
- ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data;
-
- sendpacket = skb->data;
- memcpy(&buf2, &card->wandev.udp_port, 2);
-
- if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */
- sendpacket[9] == 0x11 && /* UDP packet */
- sendpacket[22] == buf2[1] && /* UDP Port */
- sendpacket[23] == buf2[0] &&
- sendpacket[36] == 0x01 ) {
-
- if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */
- sendpacket[29] == 0x54 &&
- sendpacket[30] == 0x50 &&
- sendpacket[31] == 0x49 &&
- sendpacket[32] == 0x50 &&
- sendpacket[33] == 0x45 &&
- sendpacket[34] == 0x41 &&
- sendpacket[35] == 0x42 ){
-
- return UDP_PTPIPE_TYPE;
-
- } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */
- sendpacket[29] == 0x52 &&
- sendpacket[30] == 0x56 &&
- sendpacket[31] == 0x53 &&
- sendpacket[32] == 0x54 &&
- sendpacket[33] == 0x41 &&
- sendpacket[34] == 0x54 &&
- sendpacket[35] == 0x53 ){
-
- return UDP_DRVSTATS_TYPE;
-
- } else
- return UDP_INVALID_TYPE;
-
- } else
- return UDP_INVALID_TYPE;
-
-}
-
-/*============================================================================
- * Check to see if the packet to be transmitted contains a broadcast or
- * multicast source IP address.
- */
-
-static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
- struct sk_buff *skb)
-{
- u32 src_ip_addr;
- u32 broadcast_ip_addr = 0;
- struct in_device *in_dev;
-
- /* read the IP source address from the outgoing packet */
- src_ip_addr = *(u32 *)(skb->data + 12);
-
- /* read the IP broadcast address for the device */
- in_dev = dev->ip_ptr;
- if(in_dev != NULL) {
- struct in_ifaddr *ifa= in_dev->ifa_list;
- if(ifa != NULL)
- broadcast_ip_addr = ifa->ifa_broadcast;
- else
- return 0;
- }
-
- /* check if the IP Source Address is a Broadcast address */
- if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) {
- printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n",
- card->devname);
- return 1;
- }
-
- /* check if the IP Source Address is a Multicast address */
- if((ntohl(src_ip_addr) >= 0xE0000001) &&
- (ntohl(src_ip_addr) <= 0xFFFFFFFE)) {
- printk(KERN_INFO "%s: Multicast Source Address silently discarded\n",
- card->devname);
- return 1;
- }
-
- return 0;
-}
-
-void s508_lock (sdla_t *card, unsigned long *smp_flags)
-{
- spin_lock_irqsave(&card->wandev.lock, *smp_flags);
-}
-
-void s508_unlock (sdla_t *card, unsigned long *smp_flags)
-{
- spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
-}
-
-static int read_connection_info (sdla_t *card)
-{
- ppp_mbox_t *mb = card->mbox;
- struct net_device *dev = card->wandev.dev;
- ppp_private_area_t *ppp_priv_area = dev->priv;
- ppp508_connect_info_t *ppp508_connect_info;
- int err;
-
- memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
- mb->cmd.length = 0;
- mb->cmd.command = PPP_GET_CONNECTION_INFO;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK) {
- ppp_error(card, err, mb);
- ppp_priv_area->ip_remote = 0;
- ppp_priv_area->ip_local = 0;
- }
- else {
- ppp508_connect_info = (ppp508_connect_info_t *)mb->data;
- ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote;
- ppp_priv_area->ip_local = ppp508_connect_info->ip_local;
-
- NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n",
- ppp_priv_area->ip_remote,
- ppp_priv_area->ip_local);
- }
-
- return err;
-}
-
-/*===============================================================================
- * config_ppp
- *
- * Configure the ppp protocol and enable communications.
- *
- * The if_open function binds this function to the poll routine.
- * Therefore, this function will run every time the ppp interface
- * is brought up.
- *
- * If the communications are not enabled, proceed to configure
- * the card and enable communications.
- *
- * If the communications are enabled, it means that the interface
- * was shutdown by ether the user or driver. In this case, we
- * have to check that the IP addresses have not changed. If
- * the IP addresses changed, we have to reconfigure the firmware
- * and update the changed IP addresses. Otherwise, just exit.
- */
-static int config_ppp (sdla_t *card)
-{
-
- struct net_device *dev = card->wandev.dev;
- ppp_flags_t *flags = card->flags;
- ppp_private_area_t *ppp_priv_area = dev->priv;
-
- if (card->u.p.comm_enabled){
-
- if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local ||
- ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){
-
- /* The IP addersses have changed, we must
- * stop the communications and reconfigure
- * the card. Reason: the firmware must know
- * the local and remote IP addresses. */
- disable_comm(card);
- wanpipe_set_state(card, WAN_DISCONNECTED);
- printk(KERN_INFO
- "%s: IP addresses changed!\n",
- card->devname);
- printk(KERN_INFO "%s: Restarting communications ...\n",
- card->devname);
- }else{
- /* IP addresses are the same and the link is up,
- * we don't have to do anything here. Therefore, exit */
- return 0;
- }
- }
-
- /* Record the new IP addreses */
- ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp;
- ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp;
-
- if (config508(dev, card)){
- printk(KERN_INFO "%s: Failed to configure PPP device\n",
- card->devname);
- return 0;
- }
-
- if (ppp_set_intr_mode(card, PPP_INTR_RXRDY|
- PPP_INTR_TXRDY|
- PPP_INTR_MODEM|
- PPP_INTR_DISC |
- PPP_INTR_OPEN |
- PPP_INTR_DROP_DTR |
- PPP_INTR_TIMER)) {
-
- printk(KERN_INFO "%s: Failed to configure board interrupts !\n",
- card->devname);
- return 0;
- }
-
- /* Turn off the transmit and timer interrupt */
- flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ;
-
-
- /* If you are not the authenticator and any one of the protocol is
- * enabled then we call the set_out_bound_authentication.
- */
- if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) {
- if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){
- printk(KERN_INFO "%s: Outbound authentication failed !\n",
- card->devname);
- return 0;
- }
- }
-
- /* If you are the authenticator and any one of the protocol is enabled
- * then we call the set_in_bound_authentication.
- */
- if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){
- if (ppp_set_inbnd_auth(card, ppp_priv_area)){
- printk(KERN_INFO "%s: Inbound authentication failed !\n",
- card->devname);
- return 0;
- }
- }
-
- /* If we fail to enable communications here it's OK,
- * since the DTR timer will cause a disconnected, which
- * will retrigger communication in timer_intr() */
- if (ppp_comm_enable(card) == CMD_OK) {
- wanpipe_set_state(card, WAN_CONNECTING);
- init_ppp_tx_rx_buff(card);
- }
-
- return 0;
-}
-
-/*============================================================
- * ppp_poll
- *
- * Rationale:
- * We cannot manipulate the routing tables, or
- * ip addresses withing the interrupt. Therefore
- * we must perform such actons outside an interrupt
- * at a later time.
- *
- * Description:
- * PPP polling routine, responsible for
- * shutting down interfaces upon disconnect
- * and adding/removing routes.
- *
- * Usage:
- * This function is executed for each ppp
- * interface through a tq_schedule bottom half.
- *
- * trigger_ppp_poll() function is used to kick
- * the ppp_poll routine.
- */
-static void ppp_poll(struct net_device *dev)
-{
- ppp_private_area_t *ppp_priv_area;
- sdla_t *card;
- u8 check_gateway=0;
- ppp_flags_t *flags;
-
- if (!dev || (ppp_priv_area = dev->priv) == NULL)
- return;
-
- card = ppp_priv_area->card;
- flags = card->flags;
-
- /* Shutdown is in progress, stop what you are
- * doing and get out */
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- clear_bit(POLL_CRIT,&card->wandev.critical);
- return;
- }
-
- /* if_open() function has triggered the polling routine
- * to determine the configured IP addresses. Once the
- * addresses are found, trigger the chdlc configuration */
- if (test_bit(0,&ppp_priv_area->config_ppp)){
-
- ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP);
- ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
-
- if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp &&
- card->u.p.ip_mode == WANOPT_PPP_HOST){
-
- if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){
- printk(KERN_INFO "\n%s: --- WARNING ---\n",
- card->devname);
- printk(KERN_INFO "%s: The local IP address is the same as the\n",
- card->devname);
- printk(KERN_INFO "%s: Point-to-Point IP address.\n",
- card->devname);
- printk(KERN_INFO "%s: --- WARNING ---\n\n",
- card->devname);
- }else{
- clear_bit(POLL_CRIT,&card->wandev.critical);
- ppp_priv_area->poll_delay_timer.expires = jiffies+HZ;
- add_timer(&ppp_priv_area->poll_delay_timer);
- return;
- }
- }
-
- ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
- flags->imask |= PPP_INTR_TIMER;
- ppp_priv_area->ip_error=0;
-
- clear_bit(0,&ppp_priv_area->config_ppp);
- clear_bit(POLL_CRIT,&card->wandev.critical);
- return;
- }
-
- /* Dynamic interface implementation, as well as dynamic
- * routing. */
-
- switch (card->wandev.state) {
-
- case WAN_DISCONNECTED:
-
- /* If the dynamic interface configuration is on, and interface
- * is up, then bring down the netowrk interface */
-
- if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) &&
- !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) &&
- card->wandev.dev->flags & IFF_UP){
-
- printk(KERN_INFO "%s: Interface %s down.\n",
- card->devname,card->wandev.dev->name);
- change_dev_flags(card->wandev.dev,
- (card->wandev.dev->flags&~IFF_UP));
- set_bit(DEV_DOWN,&ppp_priv_area->interface_down);
- }else{
- /* We need to check if the local IP address is
- * zero. If it is, we shouldn't try to remove it.
- * For some reason the kernel crashes badly if
- * we try to remove the route twice */
-
- if (card->wandev.dev->flags & IFF_UP &&
- get_ip_address(card->wandev.dev,WAN_LOCAL_IP) &&
- card->u.p.ip_mode == WANOPT_PPP_PEER){
-
- remove_route(card);
- }
- }
- break;
-
- case WAN_CONNECTED:
-
- /* In SMP machine this code can execute before the interface
- * comes up. In this case, we must make sure that we do not
- * try to bring up the interface before dev_open() is finished */
-
-
- /* DEV_DOWN will be set only when we bring down the interface
- * for the very first time. This way we know that it was us
- * that brought the interface down */
-
- if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) &&
- test_bit(DEV_DOWN, &ppp_priv_area->interface_down) &&
- !(card->wandev.dev->flags & IFF_UP)){
-
- printk(KERN_INFO "%s: Interface %s up.\n",
- card->devname,card->wandev.dev->name);
-
- change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP));
- clear_bit(DEV_DOWN,&ppp_priv_area->interface_down);
- check_gateway=1;
- }
-
- if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
- test_bit(1,&Read_connection_info)) {
-
- process_route(card);
- clear_bit(1,&Read_connection_info);
- check_gateway=1;
- }
-
- if (ppp_priv_area->gateway && check_gateway)
- add_gateway(card,dev);
-
- break;
- }
- clear_bit(POLL_CRIT,&card->wandev.critical);
- return;
-}
-
-/*============================================================
- * trigger_ppp_poll
- *
- * Description:
- * Add a ppp_poll() task into a tq_scheduler bh handler
- * for a specific interface. This will kick
- * the ppp_poll() routine at a later time.
- *
- * Usage:
- * Interrupts use this to defer a taks to
- * a polling routine.
- *
- */
-
-static void trigger_ppp_poll(struct net_device *dev)
-{
- ppp_private_area_t *ppp_priv_area;
- if ((ppp_priv_area=dev->priv) != NULL){
-
- sdla_t *card = ppp_priv_area->card;
-
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- return;
- }
-
- if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){
- return;
- }
-
- schedule_work(&ppp_priv_area->poll_work);
- }
- return;
-}
-
-static void ppp_poll_delay (unsigned long dev_ptr)
-{
- struct net_device *dev = (struct net_device *)dev_ptr;
- trigger_ppp_poll(dev);
-}
-
-/*============================================================
- * detect_and_fix_tx_bug
- *
- * Description:
- * On connect, if the board tx buffer ptr is not the same
- * as the driver tx buffer ptr, we found a firmware bug.
- * Report the bug to the above layer. To fix the
- * error restart communications again.
- *
- * Usage:
- *
- */
-
-static int detect_and_fix_tx_bug (sdla_t *card)
-{
- if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){
- NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n");
- return 1;
- }
- return 0;
-}
-
-MODULE_LICENSE("GPL");
-
-/****** End *****************************************************************/
diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c
deleted file mode 100644
index 63f846d6f3a6..000000000000
--- a/drivers/net/wan/sdla_x25.c
+++ /dev/null
@@ -1,5497 +0,0 @@
-/*****************************************************************************
-* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module.
-*
-* Author: Nenad Corbic <ncorbic@sangoma.com>
-*
-* Copyright: (c) 1995-2001 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr().
-* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses
-* a kernel timer (more efficient).
-* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel
-* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering
-* for API to 4096+header_size.
-* Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable
-* communications only after all interfaces
-* come up. HIGH SVC/PVC is used to calculate
-* the number of channels.
-* Enable protocol only after all interfaces
-* are enabled.
-* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug.
-* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API.
-* Disable idle timeout in X25 API.
-* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support.
-* Maximum LCN number is 4095.
-* Maximum number of X25 channels is 255.
-* Apr 06, 2000 Nenad Corbic o Added SMP Support.
-* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card
-* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling.
-* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling
-* routines. Bug Fix.
-* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery.
-* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug.
-* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems.
-* Application must bring the link up
-* before tx/rx, and bring the
-* link down on close().
-* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup
-* information.
-* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API
-* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling.
-* No Modem OOB message will be passed
-* to the user.
-* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support
-* Dec 30, 1999 Nenad Corbic o Socket based X25API
-* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel
-* Mar 15, 1998 Alan Cox o 2.1.x porting
-* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support
-* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs
-* when they are disabled.
-* Nov 17, 1997 Farhan Thawar o Added IPX support
-* o Changed if_send() to now buffer packets when
-* the board is busy
-* o Removed queueing of packets via the polling
-* routing
-* o Changed if_send() critical flags to properly
-* handle race conditions
-* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts
-* o Changed PVC encapsulation to ETH_P_IP
-* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree()
-* when packets are received.
-* Mar 11, 1997 Farhan Thawar Version 3.1.1
-* o added support for V35
-* o changed if_send() to return 0 if
-* wandev.critical() is true
-* o free socket buffer in if_send() if
-* returning 0
-* o added support for single '@' address to
-* accept all incoming calls
-* o fixed bug in set_chan_state() to disconnect
-* Jan 15, 1997 Gene Kozin Version 3.1.0
-* o implemented exec() entry point
-* Jan 07, 1997 Gene Kozin Initial version.
-*****************************************************************************/
-
-/*======================================================
- * Includes
- *=====================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/ctype.h>
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/workqueue.h>
-#include <linux/jiffies.h> /* time_after() macro */
-#include <asm/byteorder.h> /* htons(), etc. */
-#include <asm/atomic.h>
-#include <linux/delay.h> /* Experimental delay */
-
-#include <asm/uaccess.h>
-
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include <linux/sdla_x25.h> /* X.25 firmware API definitions */
-#include <linux/if_wanpipe_common.h>
-#include <linux/if_wanpipe.h>
-
-
-/*======================================================
- * Defines & Macros
- *=====================================================*/
-
-
-#define CMD_OK 0 /* normal firmware return code */
-#define CMD_TIMEOUT 0xFF /* firmware command timed out */
-#define MAX_CMD_RETRY 10 /* max number of firmware retries */
-
-#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */
-#define X25_HRDHDR_SZ 7 /* max encapsulation header size */
-#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */
-#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */
-#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */
-#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */
-#define MAX_BH_BUFF 10
-#define M_BIT 0x01
-
-//#define PRINT_DEBUG 1
-#ifdef PRINT_DEBUG
-#define DBG_PRINTK(format, a...) printk(format, ## a)
-#else
-#define DBG_PRINTK(format, a...)
-#endif
-
-#define TMR_INT_ENABLED_POLL_ACTIVE 0x01
-#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02
-#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04
-#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08
-#define TMR_INT_ENABLED_CMD_EXEC 0x10
-#define TMR_INT_ENABLED_UPDATE 0x20
-#define TMR_INT_ENABLED_UDP_PKT 0x40
-
-#define MAX_X25_ADDR_SIZE 16
-#define MAX_X25_DATA_SIZE 129
-#define MAX_X25_FACL_SIZE 110
-
-#define TRY_CMD_AGAIN 2
-#define DELAY_RESULT 1
-#define RETURN_RESULT 0
-
-#define DCD(x) (x & 0x03 ? "HIGH" : "LOW")
-#define CTS(x) (x & 0x05 ? "HIGH" : "LOW")
-
-
-/* Driver will not write log messages about
- * modem status if defined.*/
-#define MODEM_NOT_LOG 1
-
-/*====================================================
- * For IPXWAN
- *===================================================*/
-
-#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b)))
-
-
-/*====================================================
- * MEMORY DEBUGGING FUNCTION
- *====================================================
-
-#define KMEM_SAFETYZONE 8
-
-static void * dbg_kmalloc(unsigned int size, int prio, int line) {
- int i = 0;
- void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio);
- char * c1 = v;
- c1 += sizeof(unsigned int);
- *((unsigned int *)v) = size;
-
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D';
- c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F';
- c1 += 8;
- }
- c1 += size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G';
- c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L';
- c1 += 8;
- }
- v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8;
- printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v);
- return v;
-}
-static void dbg_kfree(void * v, int line) {
- unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8));
- unsigned int size = *sp;
- char * c1 = ((char *)v) - KMEM_SAFETYZONE*8;
- int i = 0;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D'
- || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') {
- printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v);
- printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
- c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
- }
- c1 += 8;
- }
- c1 += size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G'
- || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L'
- ) {
- printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v);
- printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
- c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
- }
- c1 += 8;
- }
- printk(KERN_INFO "line %d kfree(%p)\n",line,v);
- v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8);
- kfree(v);
-}
-
-#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
-#define kfree(x) dbg_kfree(x,__LINE__)
-
-==============================================================*/
-
-
-
-/*===============================================
- * Data Structures
- *===============================================*/
-
-
-/*========================================================
- * Name: x25_channel
- *
- * Purpose: To hold private informaton for each
- * logical channel.
- *
- * Rationale: Per-channel debugging is possible if each
- * channel has its own private area.
- *
- * Assumptions:
- *
- * Description: This is an extention of the struct net_device
- * we create for each network interface to keep
- * the rest of X.25 channel-specific data.
- *
- * Construct: Typedef
- */
-typedef struct x25_channel
-{
- wanpipe_common_t common; /* common area for x25api and socket */
- char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
- char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
- unsigned tx_pkt_size;
- unsigned short protocol; /* ethertype, 0 - multiplexed */
- char drop_sequence; /* mark sequence for dropping */
- unsigned long state_tick; /* time of the last state change */
- unsigned idle_timeout; /* sec, before disconnecting */
- unsigned long i_timeout_sofar; /* # of sec's we've been idle */
- unsigned hold_timeout; /* sec, before re-connecting */
- unsigned long tick_counter; /* counter for transmit time out */
- char devtint; /* Weather we should dev_tint() */
- struct sk_buff* rx_skb; /* receive socket buffer */
- struct sk_buff* tx_skb; /* transmit socket buffer */
-
- bh_data_t *bh_head; /* Circular buffer for x25api_bh */
- unsigned long tq_working;
- volatile int bh_write;
- volatile int bh_read;
- atomic_t bh_buff_used;
-
- sdla_t* card; /* -> owner */
- struct net_device *dev; /* -> bound devce */
-
- int ch_idx;
- unsigned char enable_IPX;
- unsigned long network_number;
- struct net_device_stats ifstats; /* interface statistics */
- unsigned short transmit_length;
- unsigned short tx_offset;
- char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)];
-
- if_send_stat_t if_send_stat;
- rx_intr_stat_t rx_intr_stat;
- pipe_mgmt_stat_t pipe_mgmt_stat;
-
- unsigned long router_start_time; /* Router start time in seconds */
- unsigned long router_up_time;
-
-} x25_channel_t;
-
-/* FIXME Take this out */
-
-#ifdef NEX_OLD_CALL_INFO
-typedef struct x25_call_info
-{
- char dest[17]; PACKED;/* ASCIIZ destination address */
- char src[17]; PACKED;/* ASCIIZ source address */
- char nuser; PACKED;/* number of user data bytes */
- unsigned char user[127]; PACKED;/* user data */
- char nfacil; PACKED;/* number of facilities */
- struct
- {
- unsigned char code; PACKED;
- unsigned char parm; PACKED;
- } facil[64]; /* facilities */
-} x25_call_info_t;
-#else
-typedef struct x25_call_info
-{
- char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */
- char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */
- unsigned char nuser PACKED;
- unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */
- unsigned char nfacil PACKED;
- unsigned char facil[MAX_X25_FACL_SIZE] PACKED;
- unsigned short lcn PACKED;
-} x25_call_info_t;
-#endif
-
-
-
-/*===============================================
- * Private Function Prototypes
- *==============================================*/
-
-
-/*=================================================
- * WAN link driver entry points. These are
- * called by the WAN router module.
- */
-static int update(struct wan_device* wandev);
-static int new_if(struct wan_device* wandev, struct net_device* dev,
- wanif_conf_t* conf);
-static int del_if(struct wan_device* wandev, struct net_device* dev);
-static void disable_comm (sdla_t* card);
-static void disable_comm_shutdown(sdla_t *card);
-
-
-
-/*=================================================
- * WANPIPE-specific entry points
- */
-static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
-static void x25api_bh(struct net_device *dev);
-static int x25api_bh_cleanup(struct net_device *dev);
-static int bh_enqueue(struct net_device *dev, struct sk_buff *skb);
-
-
-/*=================================================
- * Network device interface
- */
-static int if_init(struct net_device* dev);
-static int if_open(struct net_device* dev);
-static int if_close(struct net_device* dev);
-static int if_header(struct sk_buff* skb, struct net_device* dev,
- unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (struct sk_buff* skb);
-static int if_send(struct sk_buff* skb, struct net_device* dev);
-static struct net_device_stats *if_stats(struct net_device* dev);
-
-static void if_tx_timeout(struct net_device *dev);
-
-/*=================================================
- * Interrupt handlers
- */
-static void wpx_isr (sdla_t *);
-static void rx_intr (sdla_t *);
-static void tx_intr (sdla_t *);
-static void status_intr (sdla_t *);
-static void event_intr (sdla_t *);
-static void spur_intr (sdla_t *);
-static void timer_intr (sdla_t *);
-
-static int tx_intr_send(sdla_t *card, struct net_device *dev);
-static struct net_device *move_dev_to_next(sdla_t *card,
- struct net_device *dev);
-
-/*=================================================
- * Background polling routines
- */
-static void wpx_poll (sdla_t* card);
-static void poll_disconnected (sdla_t* card);
-static void poll_connecting (sdla_t* card);
-static void poll_active (sdla_t* card);
-static void trigger_x25_poll(sdla_t *card);
-static void x25_timer_routine(unsigned long data);
-
-
-
-/*=================================================
- * X.25 firmware interface functions
- */
-static int x25_get_version (sdla_t* card, char* str);
-static int x25_configure (sdla_t* card, TX25Config* conf);
-static int hdlc_configure (sdla_t* card, TX25Config* conf);
-static int set_hdlc_level (sdla_t* card);
-static int x25_get_err_stats (sdla_t* card);
-static int x25_get_stats (sdla_t* card);
-static int x25_set_intr_mode (sdla_t* card, int mode);
-static int x25_close_hdlc (sdla_t* card);
-static int x25_open_hdlc (sdla_t* card);
-static int x25_setup_hdlc (sdla_t* card);
-static int x25_set_dtr (sdla_t* card, int dtr);
-static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan);
-static int x25_place_call (sdla_t* card, x25_channel_t* chan);
-static int x25_accept_call (sdla_t* card, int lcn, int qdm);
-static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn);
-static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf);
-static int x25_fetch_events (sdla_t* card);
-static int x25_error (sdla_t* card, int err, int cmd, int lcn);
-
-/*=================================================
- * X.25 asynchronous event handlers
- */
-static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb);
-
-
-/*=================================================
- * Miscellaneous functions
- */
-static int connect (sdla_t* card);
-static int disconnect (sdla_t* card);
-static struct net_device* get_dev_by_lcn(struct wan_device* wandev,
- unsigned lcn);
-static int chan_connect(struct net_device* dev);
-static int chan_disc(struct net_device* dev);
-static void set_chan_state(struct net_device* dev, int state);
-static int chan_send(struct net_device *dev, void* buff, unsigned data_len,
- unsigned char tx_intr);
-static unsigned char bps_to_speed_code (unsigned long bps);
-static unsigned int dec_to_uint (unsigned char* str, int len);
-static unsigned int hex_to_uint (unsigned char*, int);
-static void parse_call_info (unsigned char*, x25_call_info_t*);
-static struct net_device *find_channel(sdla_t *card, unsigned lcn);
-static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn);
-static void setup_for_delayed_transmit(struct net_device *dev,
- void *buf, unsigned len);
-
-
-/*=================================================
- * X25 API Functions
- */
-static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev,
- struct sk_buff **);
-static void timer_intr_exec(sdla_t *, unsigned char);
-static int execute_delayed_cmd(sdla_t *card, struct net_device *dev,
- mbox_cmd_t *usr_cmd, char bad_cmd);
-static int api_incoming_call (sdla_t*, TX25Mbox *, int);
-static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int);
-static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev,
- TX25Mbox* mbox);
-static int clear_confirm_event (sdla_t *, TX25Mbox*);
-static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox);
-static int timer_intr_cmd_exec(sdla_t *card);
-static void api_oob_event (sdla_t *card,TX25Mbox *mbox);
-static int check_bad_command(sdla_t *card, struct net_device *dev);
-static int channel_disconnect(sdla_t* card, struct net_device *dev);
-static void hdlc_link_down (sdla_t*);
-
-/*=================================================
- * XPIPEMON Functions
- */
-static int process_udp_mgmt_pkt(sdla_t *);
-static int udp_pkt_type( struct sk_buff *, sdla_t*);
-static int reply_udp( unsigned char *, unsigned int);
-static void init_x25_channel_struct( x25_channel_t *);
-static void init_global_statistics( sdla_t *);
-static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card,
- struct net_device *dev,
- struct sk_buff *skb, int lcn);
-static unsigned short calc_checksum (char *, int);
-
-
-
-/*=================================================
- * IPX functions
- */
-static void switch_net_numbers(unsigned char *, unsigned long, unsigned char);
-static int handle_IPXWAN(unsigned char *, char *, unsigned char ,
- unsigned long , unsigned short );
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-static void S508_S514_lock(sdla_t *, unsigned long *);
-static void S508_S514_unlock(sdla_t *, unsigned long *);
-
-
-/*=================================================
- * Global Variables
- *=================================================*/
-
-
-
-/*=================================================
- * Public Functions
- *=================================================*/
-
-
-
-
-/*===================================================================
- * wpx_init: X.25 Protocol Initialization routine.
- *
- * Purpose: To initialize the protocol/firmware.
- *
- * Rationale: This function is called by setup() function, in
- * sdlamain.c, to dynamically setup the x25 protocol.
- * This is the first protocol specific function, which
- * executes once on startup.
- *
- * Description: This procedure initializes the x25 firmware and
- * sets up the mailbox, transmit and receive buffer
- * pointers. It also initializes all debugging structures
- * and sets up the X25 environment.
- *
- * Sets up hardware options defined by user in [wanpipe#]
- * section of wanpipe#.conf configuration file.
- *
- * At this point adapter is completely initialized
- * and X.25 firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the
- * adapter data space.
- *
- * Called by: setup() function in sdlamain.c
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
-
-int wpx_init (sdla_t* card, wandev_conf_t* conf)
-{
- union{
- char str[80];
- TX25Config cfg;
- } u;
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_X25){
- printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id)
- ;
- return -EINVAL;
- }
-
- /* Initialize protocol-specific fields */
- card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS);
- card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS);
- card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS);
-
- /* Initialize for S514 Card */
- if(card->hw.type == SDLA_S514) {
- card->mbox += X25_MB_VECTOR;
- card->flags += X25_MB_VECTOR;
- card->rxmb += X25_MB_VECTOR;
- }
-
-
- /* Read firmware version. Note that when adapter initializes, it
- * clears the mailbox, so it may appear that the first command was
- * executed successfully when in fact it was merely erased. To work
- * around this, we execute the first command twice.
- */
- if (x25_get_version(card, NULL) || x25_get_version(card, u.str))
- return -EIO;
-
-
- /* X25 firmware can run ether in X25 or LAPB HDLC mode.
- * Check the user defined option and configure accordingly */
- if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){
- if (set_hdlc_level(card) != CMD_OK){
- return -EIO;
- }else{
- printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n",
- card->devname, u.str);
- }
- card->u.x.LAPB_hdlc = 1;
- }else{
- printk(KERN_INFO "%s: running X.25 firmware v%s\n",
- card->devname, u.str);
- card->u.x.LAPB_hdlc = 0;
- }
-
- /* Configure adapter. Here we set resonable defaults, then parse
- * device configuration structure and set configuration options.
- * Most configuration options are verified and corrected (if
- * necessary) since we can't rely on the adapter to do so.
- */
- memset(&u.cfg, 0, sizeof(u.cfg));
- u.cfg.t1 = 3;
- u.cfg.n2 = 10;
- u.cfg.autoHdlc = 1; /* automatic HDLC connection */
- u.cfg.hdlcWindow = 7;
- u.cfg.pktWindow = 2;
- u.cfg.station = 1; /* DTE */
- u.cfg.options = 0x0090; /* disable D-bit pragmatics */
- u.cfg.ccittCompat = 1988;
- u.cfg.t10t20 = 30;
- u.cfg.t11t21 = 30;
- u.cfg.t12t22 = 30;
- u.cfg.t13t23 = 30;
- u.cfg.t16t26 = 30;
- u.cfg.t28 = 30;
- u.cfg.r10r20 = 5;
- u.cfg.r12r22 = 5;
- u.cfg.r13r23 = 5;
- u.cfg.responseOpt = 1; /* RR's after every packet */
-
- if (card->u.x.LAPB_hdlc){
- u.cfg.hdlcMTU = 1027;
- }
-
- if (conf->u.x25.x25_conf_opt){
- u.cfg.options = conf->u.x25.x25_conf_opt;
- }
-
- if (conf->clocking != WANOPT_EXTERNAL)
- u.cfg.baudRate = bps_to_speed_code(conf->bps);
-
- if (conf->station != WANOPT_DTE){
- u.cfg.station = 0; /* DCE mode */
- }
-
- if (conf->interface != WANOPT_RS232 ){
- u.cfg.hdlcOptions |= 0x80; /* V35 mode */
- }
-
- /* adjust MTU */
- if (!conf->mtu || (conf->mtu >= 1024))
- card->wandev.mtu = 1024;
- else if (conf->mtu >= 512)
- card->wandev.mtu = 512;
- else if (conf->mtu >= 256)
- card->wandev.mtu = 256;
- else if (conf->mtu >= 128)
- card->wandev.mtu = 128;
- else
- card->wandev.mtu = 64;
-
- u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu;
-
- if (conf->u.x25.hi_pvc){
- card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM);
- card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc);
- }
-
- if (conf->u.x25.hi_svc){
- card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM);
- card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc);
- }
-
- /* Figure out the total number of channels to configure */
- card->u.x.num_of_ch = 0;
- if (card->u.x.hi_svc != 0){
- card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1;
- }
- if (card->u.x.hi_pvc != 0){
- card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1;
- }
-
- if (card->u.x.num_of_ch == 0){
- printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n"
- "%s: Please set the Lowest/Highest PVC/SVC values !\n",
- card->devname,card->devname);
- return -ECHRNG;
- }
-
- u.cfg.loPVC = card->u.x.lo_pvc;
- u.cfg.hiPVC = card->u.x.hi_pvc;
- u.cfg.loTwoWaySVC = card->u.x.lo_svc;
- u.cfg.hiTwoWaySVC = card->u.x.hi_svc;
-
- if (conf->u.x25.hdlc_window)
- u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7);
- if (conf->u.x25.pkt_window)
- u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7);
-
- if (conf->u.x25.t1)
- u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30);
- if (conf->u.x25.t2)
- u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29);
- if (conf->u.x25.t4)
- u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240);
- if (conf->u.x25.n2)
- u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30);
-
- if (conf->u.x25.t10_t20)
- u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255);
- if (conf->u.x25.t11_t21)
- u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255);
- if (conf->u.x25.t12_t22)
- u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255);
- if (conf->u.x25.t13_t23)
- u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255);
- if (conf->u.x25.t16_t26)
- u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255);
- if (conf->u.x25.t28)
- u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255);
-
- if (conf->u.x25.r10_r20)
- u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250);
- if (conf->u.x25.r12_r22)
- u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250);
- if (conf->u.x25.r13_r23)
- u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250);
-
-
- if (conf->u.x25.ccitt_compat)
- u.cfg.ccittCompat = conf->u.x25.ccitt_compat;
-
- /* initialize adapter */
- if (card->u.x.LAPB_hdlc){
- if (hdlc_configure(card, &u.cfg) != CMD_OK)
- return -EIO;
- }else{
- if (x25_configure(card, &u.cfg) != CMD_OK)
- return -EIO;
- }
-
- if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */
- (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */
- return -EIO;
-
- /* Initialize protocol-specific fields of adapter data space */
- card->wandev.bps = conf->bps;
- card->wandev.interface = conf->interface;
- card->wandev.clocking = conf->clocking;
- card->wandev.station = conf->station;
- card->isr = &wpx_isr;
- card->poll = NULL; //&wpx_poll;
- card->disable_comm = &disable_comm;
- card->exec = &wpx_exec;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
-
- /* WARNING: This function cannot exit with an error
- * after the change of state */
- card->wandev.state = WAN_DISCONNECTED;
-
- card->wandev.enable_tx_int = 0;
- card->irq_dis_if_send_count = 0;
- card->irq_dis_poll_count = 0;
- card->u.x.tx_dev = NULL;
- card->u.x.no_dev = 0;
-
-
- /* Configure for S514 PCI Card */
- if (card->hw.type == SDLA_S514) {
- card->u.x.hdlc_buf_status =
- (volatile unsigned char *)
- (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS);
- }else{
- card->u.x.hdlc_buf_status =
- (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS);
- }
-
- card->u.x.poll_device=NULL;
- card->wandev.udp_port = conf->udp_port;
-
- /* Enable or disable call setup logging */
- if (conf->u.x25.logging == WANOPT_YES){
- printk(KERN_INFO "%s: Enabling Call Logging.\n",
- card->devname);
- card->u.x.logging = 1;
- }else{
- card->u.x.logging = 0;
- }
-
- /* Enable or disable modem status reporting */
- if (conf->u.x25.oob_on_modem == WANOPT_YES){
- printk(KERN_INFO "%s: Enabling OOB on Modem change.\n",
- card->devname);
- card->u.x.oob_on_modem = 1;
- }else{
- card->u.x.oob_on_modem = 0;
- }
-
- init_global_statistics(card);
-
- INIT_WORK(&card->u.x.x25_poll_work, (void *)wpx_poll, card);
-
- init_timer(&card->u.x.x25_timer);
- card->u.x.x25_timer.data = (unsigned long)card;
- card->u.x.x25_timer.function = x25_timer_routine;
-
- return 0;
-}
-
-/*=========================================================
- * WAN Device Driver Entry Points
- *========================================================*/
-
-/*============================================================
- * Name: update(), Update device status & statistics.
- *
- * Purpose: To provide debugging and statitical
- * information to the /proc file system.
- * /proc/net/wanrouter/wanpipe#
- *
- * Rationale: The /proc file system is used to collect
- * information about the kernel and drivers.
- * Using the /proc file system the user
- * can see exactly what the sangoma drivers are
- * doing. And in what state they are in.
- *
- * Description: Collect all driver statistical information
- * and pass it to the top laywer.
- *
- * Since we have to execute a debugging command,
- * to obtain firmware statitics, we trigger a
- * UPDATE function within the timer interrtup.
- * We wait until the timer update is complete.
- * Once complete return the appropriate return
- * code to indicate that the update was successful.
- *
- * Called by: device_stat() in wanmain.c
- *
- * Assumptions:
- *
- * Warnings: This function will degrade the performance
- * of the router, since it uses the mailbox.
- *
- * Return: 0 OK
- * <0 Failed (or busy).
- */
-
-static int update(struct wan_device* wandev)
-{
- volatile sdla_t* card;
- TX25Status* status;
- unsigned long timeout;
-
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
-
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- if (test_bit(SEND_CRIT, (void*)&wandev->critical))
- return -EAGAIN;
-
- if (!wandev->dev)
- return -ENODEV;
-
- card = wandev->private;
- status = card->flags;
-
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE;
- status->imask |= INTR_ON_TIMER;
- timeout = jiffies;
-
- for (;;){
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){
- break;
- }
- if (time_after(jiffies, timeout + 1*HZ)){
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
- return -EAGAIN;
- }
- }
- return 0;
-}
-
-
-/*===================================================================
- * Name: new_if
- *
- * Purpose: To allocate and initialize resources for a
- * new logical channel.
- *
- * Rationale: A new channel can be added dynamically via
- * ioctl call.
- *
- * Description: Allocate a private channel structure, x25_channel_t.
- * Parse the user interface options from wanpipe#.conf
- * configuration file.
- * Bind the private are into the network device private
- * area pointer (dev->priv).
- * Prepare the network device structure for registration.
- *
- * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl()
- * (wanmain.c)
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok
- * <0 Failed (channel will not be created)
- */
-static int new_if(struct wan_device* wandev, struct net_device* dev,
- wanif_conf_t* conf)
-{
- sdla_t* card = wandev->private;
- x25_channel_t* chan;
- int err = 0;
-
- if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){
- printk(KERN_INFO "%s: invalid interface name!\n",
- card->devname);
- return -EINVAL;
- }
-
- if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) {
- printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n",
- card->devname);
- printk(KERN_INFO
- "%s: Maximum number of network interfaces must be one !\n",
- card->devname);
- return -EEXIST;
- }
-
- /* allocate and initialize private data */
- chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC);
- if (chan == NULL){
- return -ENOMEM;
- }
-
- memset(chan, 0, sizeof(x25_channel_t));
-
- /* Bug Fix: Seg Err on PVC startup
- * It must be here since bind_lcn_to_dev expects
- * it bellow */
- dev->priv = chan;
-
- strcpy(chan->name, conf->name);
- chan->card = card;
- chan->dev = dev;
- chan->common.sk = NULL;
- chan->common.func = NULL;
- chan->common.rw_bind = 0;
- chan->tx_skb = chan->rx_skb = NULL;
-
- /* verify media address */
- if (conf->addr[0] == '@'){ /* SVC */
- chan->common.svc = 1;
- strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
-
- /* Set channel timeouts (default if not specified) */
- chan->idle_timeout = (conf->idle_timeout) ?
- conf->idle_timeout : 90;
- chan->hold_timeout = (conf->hold_timeout) ?
- conf->hold_timeout : 10;
-
- }else if (isdigit(conf->addr[0])){ /* PVC */
- int lcn = dec_to_uint(conf->addr, 0);
-
- if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){
- bind_lcn_to_dev (card, dev, lcn);
- }else{
- printk(KERN_ERR
- "%s: PVC %u is out of range on interface %s!\n",
- wandev->name, lcn, chan->name);
- err = -EINVAL;
- }
- }else{
- printk(KERN_ERR
- "%s: invalid media address on interface %s!\n",
- wandev->name, chan->name);
- err = -EINVAL;
- }
-
- if(strcmp(conf->usedby, "WANPIPE") == 0){
- printk(KERN_INFO "%s: Running in WANPIPE mode %s\n",
- wandev->name, chan->name);
- chan->common.usedby = WANPIPE;
- chan->protocol = htons(ETH_P_IP);
-
- }else if(strcmp(conf->usedby, "API") == 0){
- chan->common.usedby = API;
- printk(KERN_INFO "%s: Running in API mode %s\n",
- wandev->name, chan->name);
- chan->protocol = htons(X25_PROT);
- }
-
-
- if (err){
- kfree(chan);
- dev->priv = NULL;
- return err;
- }
-
- chan->enable_IPX = conf->enable_IPX;
-
- if (chan->enable_IPX)
- chan->protocol = htons(ETH_P_IPX);
-
- if (conf->network_number)
- chan->network_number = conf->network_number;
- else
- chan->network_number = 0xDEADBEEF;
-
- /* prepare network device data space for registration */
- strcpy(dev->name,chan->name);
-
- dev->init = &if_init;
-
- init_x25_channel_struct(chan);
-
- return 0;
-}
-
-/*===================================================================
- * Name: del_if(), Remove a logical channel.
- *
- * Purpose: To dynamically remove a logical channel.
- *
- * Rationale: Each logical channel should be dynamically
- * removable. This functin is called by an
- * IOCTL_IFDEL ioctl call or shutdown().
- *
- * Description: Do nothing.
- *
- * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c
- * shutdown() from sdlamain.c
- *
- * Assumptions:
- *
- * Warnings:
- *
- * Return: 0 Ok. Void function.
- */
-
-//FIXME Del IF Should be taken out now.
-
-static int del_if(struct wan_device* wandev, struct net_device* dev)
-{
- return 0;
-}
-
-
-/*============================================================
- * Name: wpx_exec
- *
- * Description: Execute adapter interface command.
- * This option is currently dissabled.
- *===========================================================*/
-
-static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
-{
- return 0;
-}
-
-/*============================================================
- * Name: disable_comm
- *
- * Description: Disable communications during shutdown.
- * Dont check return code because there is
- * nothing we can do about it.
- *
- * Warning: Dev and private areas are gone at this point.
- *===========================================================*/
-
-static void disable_comm(sdla_t* card)
-{
- disable_comm_shutdown(card);
- del_timer(&card->u.x.x25_timer);
- return;
-}
-
-
-/*============================================================
- * Network Device Interface
- *===========================================================*/
-
-/*===================================================================
- * Name: if_init(), Netowrk Interface Initialization
- *
- * Purpose: To initialize a network interface device structure.
- *
- * Rationale: During network interface startup, the if_init
- * is called by the kernel to initialize the
- * netowrk device structure. Thus a driver
- * can customze a network device.
- *
- * Description: Initialize the netowrk device call back
- * routines. This is where we tell the kernel
- * which function to use when it wants to send
- * via our interface.
- * Furthermore, we initialize the device flags,
- * MTU and physical address of the board.
- *
- * Called by: Kernel (/usr/src/linux/net/core/dev.c)
- * (dev->init())
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok : Void function.
- */
-static int if_init(struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- struct wan_device* wandev = &card->wandev;
-
- /* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_header = &if_header;
- dev->rebuild_header = &if_rebuild_hdr;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
- dev->tx_timeout = &if_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- /* Initialize media-specific parameters */
- dev->type = ARPHRD_PPP; /* ARP h/w type */
- dev->flags |= IFF_POINTOPOINT;
- dev->flags |= IFF_NOARP;
-
- if (chan->common.usedby == API){
- dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t);
- }else{
- dev->mtu = card->wandev.mtu;
- }
-
- dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */
- dev->addr_len = 2; /* hardware address length */
-
- if (!chan->common.svc){
- *(unsigned short*)dev->dev_addr = htons(chan->common.lcn);
- }
-
- /* Initialize hardware parameters (just for reference) */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = (unsigned long)wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
-
- /* Set transmit buffer queue length */
- dev->tx_queue_len = 100;
- SET_MODULE_OWNER(dev);
-
- /* FIXME Why are we doing this */
- set_chan_state(dev, WAN_DISCONNECTED);
- return 0;
-}
-
-
-/*===================================================================
- * Name: if_open(), Open/Bring up the Netowrk Interface
- *
- * Purpose: To bring up a network interface.
- *
- * Rationale:
- *
- * Description: Open network interface.
- * o prevent module from unloading by incrementing use count
- * o if link is disconnected then initiate connection
- *
- * Called by: Kernel (/usr/src/linux/net/core/dev.c)
- * (dev->open())
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok
- * <0 Failure: Interface will not come up.
- */
-
-static int if_open(struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- struct timeval tv;
- unsigned long smp_flags;
-
- if (netif_running(dev))
- return -EBUSY;
-
- chan->tq_working = 0;
-
- /* Initialize the workqueue */
- INIT_WORK(&chan->common.wanpipe_work, (void *)x25api_bh, dev);
-
- /* Allocate and initialize BH circular buffer */
- /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */
- chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC);
-
- if (chan->bh_head == NULL){
- printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n",
- card->devname);
-
- return -ENOBUFS;
- }
- memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1)));
- atomic_set(&chan->bh_buff_used, 0);
-
- /* Increment the number of interfaces */
- ++card->u.x.no_dev;
-
- wanpipe_open(card);
-
- /* LAPB protocol only uses one interface, thus
- * start the protocol after it comes up. */
- if (card->u.x.LAPB_hdlc){
- if (card->open_cnt == 1){
- TX25Status* status = card->flags;
- S508_S514_lock(card, &smp_flags);
- x25_set_intr_mode(card, INTR_ON_TIMER);
- status->imask &= ~INTR_ON_TIMER;
- S508_S514_unlock(card, &smp_flags);
- }
- }else{
- /* X25 can have multiple interfaces thus, start the
- * protocol once all interfaces are up */
-
- //FIXME: There is a bug here. If interface is
- //brought down and up, it will try to enable comm.
- if (card->open_cnt == card->u.x.num_of_ch){
-
- S508_S514_lock(card, &smp_flags);
- connect(card);
- S508_S514_unlock(card, &smp_flags);
-
- mod_timer(&card->u.x.x25_timer, jiffies + HZ);
- }
- }
- /* Device is not up until the we are in connected state */
- do_gettimeofday( &tv );
- chan->router_start_time = tv.tv_sec;
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-/*===================================================================
- * Name: if_close(), Close/Bring down the Netowrk Interface
- *
- * Purpose: To bring down a network interface.
- *
- * Rationale:
- *
- * Description: Close network interface.
- * o decrement use module use count
- *
- * Called by: Kernel (/usr/src/linux/net/core/dev.c)
- * (dev->close())
- * ifconfig <name> down: will trigger the kernel
- * which will call this function.
- *
- * Assumptions: None
- *
- * Warnings: None
- *
- * Return: 0 Ok
- * <0 Failure: Interface will not exit properly.
- */
-static int if_close(struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- unsigned long smp_flags;
-
- netif_stop_queue(dev);
-
- if ((chan->common.state == WAN_CONNECTED) ||
- (chan->common.state == WAN_CONNECTING)){
- S508_S514_lock(card, &smp_flags);
- chan_disc(dev);
- S508_S514_unlock(card, &smp_flags);
- }
-
- wanpipe_close(card);
-
- S508_S514_lock(card, &smp_flags);
- if (chan->bh_head){
- int i;
- struct sk_buff *skb;
-
- for (i=0; i<(MAX_BH_BUFF+1); i++){
- skb = ((bh_data_t *)&chan->bh_head[i])->skb;
- if (skb != NULL){
- dev_kfree_skb_any(skb);
- }
- }
- kfree(chan->bh_head);
- chan->bh_head=NULL;
- }
- S508_S514_unlock(card, &smp_flags);
-
- /* If this is the last close, disconnect physical link */
- if (!card->open_cnt){
- S508_S514_lock(card, &smp_flags);
- disconnect(card);
- x25_set_intr_mode(card, 0);
- S508_S514_unlock(card, &smp_flags);
- }
-
- /* Decrement the number of interfaces */
- --card->u.x.no_dev;
- return 0;
-}
-
-/*======================================================================
- * Build media header.
- * o encapsulate packet according to encapsulation type.
- *
- * The trick here is to put packet type (Ethertype) into 'protocol'
- * field of the socket buffer, so that we don't forget it.
- * If encapsulation fails, set skb->protocol to 0 and discard
- * packet later.
- *
- * Return: media header length.
- *======================================================================*/
-
-static int if_header(struct sk_buff* skb, struct net_device* dev,
- unsigned short type, void* daddr, void* saddr,
- unsigned len)
-{
- x25_channel_t* chan = dev->priv;
- int hdr_len = dev->hard_header_len;
-
- skb->protocol = htons(type);
- if (!chan->protocol){
- hdr_len = wanrouter_encapsulate(skb, dev, type);
- if (hdr_len < 0){
- hdr_len = 0;
- skb->protocol = htons(0);
- }
- }
- return hdr_len;
-}
-
-/*===============================================================
- * Re-build media header.
- *
- * Return: 1 physical address resolved.
- * 0 physical address not resolved
- *==============================================================*/
-
-static int if_rebuild_hdr (struct sk_buff* skb)
-{
- struct net_device *dev = skb->dev;
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
-
- printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
- card->devname, dev->name);
- return 1;
-}
-
-
-/*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
-static void if_tx_timeout(struct net_device *dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
- /* If our device stays busy for at least 5 seconds then we will
- * kick start the device by making dev->tbusy = 0. We expect
- * that our device never stays busy more than 5 seconds. So this
- * is only used as a last resort.
- */
-
- ++chan->if_send_stat.if_send_tbusy_timeout;
- printk (KERN_INFO "%s: Transmit timed out on %s\n",
- card->devname, dev->name);
- netif_wake_queue (dev);
-}
-
-
-/*=========================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission).
- * o check link state. If link is not up, then drop the packet.
- * o check channel status. If it's down then initiate a call.
- * o pass a packet to corresponding WAN device.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- * protocol stack and can be used for flow control with protocol layer.
- *
- *========================================================================*/
-
-static int if_send(struct sk_buff* skb, struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- TX25Status* status = card->flags;
- int udp_type;
- unsigned long smp_flags=0;
-
- ++chan->if_send_stat.if_send_entry;
-
- netif_stop_queue(dev);
-
- /* No need to check frame length, since socket code
- * will perform the check for us */
-
- chan->tick_counter = jiffies;
-
- /* Critical region starts here */
- S508_S514_lock(card, &smp_flags);
-
- if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){
- printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical);
- goto if_send_crit_exit;
- }
-
- udp_type = udp_pkt_type(skb, card);
-
- if(udp_type != UDP_INVALID_TYPE) {
-
- if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb,
- chan->common.lcn)) {
-
- status->imask |= INTR_ON_TIMER;
- if (udp_type == UDP_XPIPE_TYPE){
- chan->if_send_stat.if_send_PIPE_request++;
- }
- }
- netif_start_queue(dev);
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
- S508_S514_unlock(card, &smp_flags);
- return 0;
- }
-
- if (chan->transmit_length){
- //FIXME: This check doesn't make sense any more
- if (chan->common.state != WAN_CONNECTED){
- chan->transmit_length=0;
- atomic_set(&chan->common.driver_busy,0);
- }else{
- netif_stop_queue(dev);
- ++card->u.x.tx_interrupts_pending;
- status->imask |= INTR_ON_TX_FRAME;
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
- S508_S514_unlock(card, &smp_flags);
- return 1;
- }
- }
-
- if (card->wandev.state != WAN_CONNECTED){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- ++chan->if_send_stat.if_send_wan_disconnected;
-
- }else if ( chan->protocol && (chan->protocol != skb->protocol)){
- printk(KERN_INFO
- "%s: unsupported Ethertype 0x%04X on interface %s!\n",
- chan->name, htons(skb->protocol), dev->name);
-
- printk(KERN_INFO "PROTO %Xn", htons(chan->protocol));
- ++chan->ifstats.tx_errors;
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- ++chan->if_send_stat.if_send_protocol_error;
-
- }else switch (chan->common.state){
-
- case WAN_DISCONNECTED:
- /* Try to establish connection. If succeded, then start
- * transmission, else drop a packet.
- */
- if (chan->common.usedby == API){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }else{
- if (chan_connect(dev) != 0){
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
- }
- /* fall through */
-
- case WAN_CONNECTED:
- if( skb->protocol == htons(ETH_P_IPX)) {
- if(chan->enable_IPX) {
- switch_net_numbers( skb->data,
- chan->network_number, 0);
- } else {
- ++card->wandev.stats.tx_dropped;
- ++chan->ifstats.tx_dropped;
- ++chan->if_send_stat.if_send_protocol_error;
- goto if_send_crit_exit;
- }
- }
- /* We never drop here, if cannot send than, copy
- * a packet into a transmit buffer
- */
- chan_send(dev, skb->data, skb->len, 0);
- break;
-
- default:
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- break;
- }
-
-
-if_send_crit_exit:
-
- dev_kfree_skb_any(skb);
-
- netif_start_queue(dev);
- clear_bit(SEND_CRIT,(void*)&card->wandev.critical);
- S508_S514_unlock(card, &smp_flags);
- return 0;
-}
-
-/*============================================================================
- * Setup so that a frame can be transmitted on the occurrence of a transmit
- * interrupt.
- *===========================================================================*/
-
-static void setup_for_delayed_transmit(struct net_device* dev, void* buf,
- unsigned len)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- TX25Status* status = card->flags;
-
- ++chan->if_send_stat.if_send_adptr_bfrs_full;
-
- if(chan->transmit_length) {
- printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n",
- card->devname);
- return;
- }
-
- if (chan->common.usedby == API){
- if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) {
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- printk(KERN_INFO "%s: Length is too big for delayed transmit\n",
- card->devname);
- return;
- }
- }else{
- if (len > X25_MAX_DATA) {
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- printk(KERN_INFO "%s: Length is too big for delayed transmit\n",
- card->devname);
- return;
- }
- }
-
- chan->transmit_length = len;
- atomic_set(&chan->common.driver_busy,1);
- memcpy(chan->transmit_buffer, buf, len);
-
- ++chan->if_send_stat.if_send_tx_int_enabled;
-
- /* Enable Transmit Interrupt */
- ++card->u.x.tx_interrupts_pending;
- status->imask |= INTR_ON_TX_FRAME;
-}
-
-
-/*===============================================================
- * net_device_stats
- *
- * Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- *
- *==============================================================*/
-static struct net_device_stats *if_stats(struct net_device* dev)
-{
- x25_channel_t *chan = dev->priv;
-
- if(chan == NULL)
- return NULL;
-
- return &chan->ifstats;
-}
-
-
-/*
- * Interrupt Handlers
- */
-
-/*
- * X.25 Interrupt Service Routine.
- */
-
-static void wpx_isr (sdla_t* card)
-{
- TX25Status* status = card->flags;
-
- card->in_isr = 1;
- ++card->statistics.isr_entry;
-
- if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
- card->in_isr=0;
- status->iflags = 0;
- return;
- }
-
- if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){
-
- printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n",
- card->devname, card->wandev.critical, status->iflags);
- card->in_isr = 0;
- status->iflags = 0;
- return;
- }
-
- /* For all interrupts set the critical flag to CRITICAL_RX_INTR.
- * If the if_send routine is called with this flag set it will set
- * the enable transmit flag to 1. (for a delayed interrupt)
- */
- switch (status->iflags){
-
- case RX_INTR_PENDING: /* receive interrupt */
- rx_intr(card);
- break;
-
- case TX_INTR_PENDING: /* transmit interrupt */
- tx_intr(card);
- break;
-
- case MODEM_INTR_PENDING: /* modem status interrupt */
- status_intr(card);
- break;
-
- case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */
- event_intr(card);
- break;
-
- case TIMER_INTR_PENDING:
- timer_intr(card);
- break;
-
- default: /* unwanted interrupt */
- spur_intr(card);
- }
-
- card->in_isr = 0;
- status->iflags = 0; /* clear interrupt condition */
-}
-
-/*
- * Receive interrupt handler.
- * This routine handles fragmented IP packets using M-bit according to the
- * RFC1356.
- * o map ligical channel number to network interface.
- * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then
- * decapsulate packet and pass socket buffer to the protocol stack.
- *
- * Notes:
- * 1. When allocating a socket buffer, if M-bit is set then more data is
- * coming and we have to allocate buffer for the maximum IP packet size
- * expected on this channel.
- * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
- * socket buffers available) the whole packet sequence must be discarded.
- */
-
-static void rx_intr (sdla_t* card)
-{
- TX25Mbox* rxmb = card->rxmb;
- unsigned lcn = rxmb->cmd.lcn;
- struct net_device* dev = find_channel(card,lcn);
- x25_channel_t* chan;
- struct sk_buff* skb=NULL;
-
- if (dev == NULL){
- /* Invalid channel, discard packet */
- printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
- card->devname, lcn);
- return;
- }
-
- chan = dev->priv;
- chan->i_timeout_sofar = jiffies;
-
-
- /* Copy the data from the board, into an
- * skb buffer
- */
- if (wanpipe_pull_data_in_skb(card,dev,&skb)){
- ++chan->ifstats.rx_dropped;
- ++card->wandev.stats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_no_socket;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- return;
- }
-
- dev->last_rx = jiffies; /* timestamp */
-
-
- /* ------------ API ----------------*/
-
- if (chan->common.usedby == API){
-
- if (bh_enqueue(dev, skb)){
- ++chan->ifstats.rx_dropped;
- ++card->wandev.stats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- dev_kfree_skb_any(skb);
- return;
- }
-
- ++chan->ifstats.rx_packets;
- chan->ifstats.rx_bytes += skb->len;
-
-
- chan->rx_skb = NULL;
- if (!test_and_set_bit(0, &chan->tq_working)){
- wanpipe_queue_work(&chan->common.wanpipe_work);
- }
- return;
- }
-
-
- /* ------------- WANPIPE -------------------*/
-
- /* set rx_skb to NULL so we won't access it later when kernel already owns it */
- chan->rx_skb=NULL;
-
- /* Decapsulate packet, if necessary */
- if (!skb->protocol && !wanrouter_type_trans(skb, dev)){
- /* can't decapsulate packet */
- dev_kfree_skb_any(skb);
- ++chan->ifstats.rx_errors;
- ++chan->ifstats.rx_dropped;
- ++card->wandev.stats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
-
- }else{
- if( handle_IPXWAN(skb->data, chan->name,
- chan->enable_IPX, chan->network_number,
- skb->protocol)){
-
- if( chan->enable_IPX ){
- if(chan_send(dev, skb->data, skb->len,0)){
- chan->tx_skb = skb;
- }else{
- dev_kfree_skb_any(skb);
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- }
- }else{
- /* increment IPX packet dropped statistic */
- ++chan->ifstats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- }
- }else{
- skb->mac.raw = skb->data;
- chan->ifstats.rx_bytes += skb->len;
- ++chan->ifstats.rx_packets;
- ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack;
- netif_rx(skb);
- }
- }
-
- return;
-}
-
-
-static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev,
- struct sk_buff **skb)
-{
- void *bufptr;
- TX25Mbox* rxmb = card->rxmb;
- unsigned len = rxmb->cmd.length; /* packet length */
- unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */
- x25_channel_t *chan = dev->priv;
- struct sk_buff *new_skb = *skb;
-
- if (chan->common.usedby == WANPIPE){
- if (chan->drop_sequence){
- if (!(qdm & 0x01)){
- chan->drop_sequence = 0;
- }
- return 1;
- }
- new_skb = chan->rx_skb;
- }else{
- /* Add on the API header to the received
- * data
- */
- len += sizeof(x25api_hdr_t);
- }
-
- if (new_skb == NULL){
- int bufsize;
-
- if (chan->common.usedby == WANPIPE){
- bufsize = (qdm & 0x01) ? dev->mtu : len;
- }else{
- bufsize = len;
- }
-
- /* Allocate new socket buffer */
- new_skb = dev_alloc_skb(bufsize + dev->hard_header_len);
- if (new_skb == NULL){
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- chan->drop_sequence = 1; /* set flag */
- ++chan->ifstats.rx_dropped;
- return 1;
- }
- }
-
- if (skb_tailroom(new_skb) < len){
- /* No room for the packet. Call off the whole thing! */
- dev_kfree_skb_any(new_skb);
- if (chan->common.usedby == WANPIPE){
- chan->rx_skb = NULL;
- if (qdm & 0x01){
- chan->drop_sequence = 1;
- }
- }
-
- printk(KERN_INFO "%s: unexpectedly long packet sequence "
- "on interface %s!\n", card->devname, dev->name);
- ++chan->ifstats.rx_length_errors;
- return 1;
- }
-
- bufptr = skb_put(new_skb,len);
-
-
- if (chan->common.usedby == API){
- /* Fill in the x25api header
- */
- x25api_t * api_data = (x25api_t*)bufptr;
- api_data->hdr.qdm = rxmb->cmd.qdm;
- api_data->hdr.cause = rxmb->cmd.cause;
- api_data->hdr.diagn = rxmb->cmd.diagn;
- api_data->hdr.length = rxmb->cmd.length;
- memcpy(api_data->data, rxmb->data, rxmb->cmd.length);
- }else{
- memcpy(bufptr, rxmb->data, len);
- }
-
- new_skb->dev = dev;
-
- if (chan->common.usedby == API){
- new_skb->mac.raw = new_skb->data;
- new_skb->protocol = htons(X25_PROT);
- new_skb->pkt_type = WAN_PACKET_DATA;
- }else{
- new_skb->protocol = chan->protocol;
- chan->rx_skb = new_skb;
- }
-
- /* If qdm bit is set, more data is coming
- * thus, exit and wait for more data before
- * sending the packet up. (Used by router only)
- */
- if ((qdm & 0x01) && (chan->common.usedby == WANPIPE))
- return 1;
-
- *skb = new_skb;
-
- return 0;
-}
-
-/*===============================================================
- * tx_intr
- *
- * Transmit interrupt handler.
- * For each dev, check that there is something to send.
- * If data available, transmit.
- *
- *===============================================================*/
-
-static void tx_intr (sdla_t* card)
-{
- struct net_device *dev;
- TX25Status* status = card->flags;
- unsigned char more_to_tx=0;
- x25_channel_t *chan=NULL;
- int i=0;
-
- if (card->u.x.tx_dev == NULL){
- card->u.x.tx_dev = card->wandev.dev;
- }
-
- dev = card->u.x.tx_dev;
-
- for (;;){
-
- chan = dev->priv;
- if (chan->transmit_length){
- /* Device was set to transmit, check if the TX
- * buffers are available
- */
- if (chan->common.state != WAN_CONNECTED){
- chan->transmit_length = 0;
- atomic_set(&chan->common.driver_busy,0);
- chan->tx_offset=0;
- if (netif_queue_stopped(dev)){
- if (chan->common.usedby == API){
- netif_start_queue(dev);
- wakeup_sk_bh(dev);
- }else{
- netif_wake_queue(dev);
- }
- }
- dev = move_dev_to_next(card,dev);
- break;
- }
-
- if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) &&
- (*card->u.x.hdlc_buf_status & 0x40) ){
- /* Tx buffer available, we can send */
-
- if (tx_intr_send(card, dev)){
- more_to_tx=1;
- }
-
- /* If more than one interface present, move the
- * device pointer to the next interface, so on the
- * next TX interrupt we will try sending from it.
- */
- dev = move_dev_to_next(card,dev);
- break;
- }else{
- /* Tx buffers not available, but device set
- * the TX interrupt. Set more_to_tx and try
- * to transmit for other devices.
- */
- more_to_tx=1;
- dev = move_dev_to_next(card,dev);
- }
-
- }else{
- /* This device was not set to transmit,
- * go to next
- */
- dev = move_dev_to_next(card,dev);
- }
-
- if (++i == card->u.x.no_dev){
- if (!more_to_tx){
- DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n",
- card->devname);
- }
- break;
- }
-
- } //End of FOR
-
- card->u.x.tx_dev = dev;
-
- if (!more_to_tx){
- /* if any other interfaces have transmit interrupts pending, */
- /* do not disable the global transmit interrupt */
- if (!(--card->u.x.tx_interrupts_pending)){
- status->imask &= ~INTR_ON_TX_FRAME;
- }
- }
- return;
-}
-
-/*===============================================================
- * move_dev_to_next
- *
- *
- *===============================================================*/
-
-
-struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev)
-{
- if (card->u.x.no_dev != 1){
- if (!*((struct net_device **)dev->priv))
- return card->wandev.dev;
- else
- return *((struct net_device **)dev->priv);
- }
- return dev;
-}
-
-/*===============================================================
- * tx_intr_send
- *
- *
- *===============================================================*/
-
-static int tx_intr_send(sdla_t *card, struct net_device *dev)
-{
- x25_channel_t* chan = dev->priv;
-
- if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){
-
- /* Packet was split up due to its size, do not disable
- * tx_intr
- */
- return 1;
- }
-
- chan->transmit_length=0;
- atomic_set(&chan->common.driver_busy,0);
- chan->tx_offset=0;
-
- /* If we are in API mode, wakeup the
- * sock BH handler, not the NET_BH */
- if (netif_queue_stopped(dev)){
- if (chan->common.usedby == API){
- netif_start_queue(dev);
- wakeup_sk_bh(dev);
- }else{
- netif_wake_queue(dev);
- }
- }
- return 0;
-}
-
-
-/*===============================================================
- * timer_intr
- *
- * Timer interrupt handler.
- * Check who called the timer interrupt and perform
- * action accordingly.
- *
- *===============================================================*/
-
-static void timer_intr (sdla_t *card)
-{
- TX25Status* status = card->flags;
-
- if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){
-
- if (timer_intr_cmd_exec(card) == 0){
- card->u.x.timer_int_enabled &=
- ~TMR_INT_ENABLED_CMD_EXEC;
- }
-
- }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) {
-
- if ((*card->u.x.hdlc_buf_status & 0x40) &&
- card->u.x.udp_type == UDP_XPIPE_TYPE){
-
- if(process_udp_mgmt_pkt(card)) {
- card->u.x.timer_int_enabled &=
- ~TMR_INT_ENABLED_UDP_PKT;
- }
- }
-
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) {
-
- struct net_device *dev = card->u.x.poll_device;
- x25_channel_t *chan = NULL;
-
- if (!dev){
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE;
- return;
- }
- chan = dev->priv;
-
- printk(KERN_INFO
- "%s: Closing down Idle link %s on LCN %d\n",
- card->devname,chan->name,chan->common.lcn);
- chan->i_timeout_sofar = jiffies;
- chan_disc(dev);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE;
- card->u.x.poll_device=NULL;
-
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) {
-
- wanpipe_set_state(card, WAN_CONNECTED);
- if (card->u.x.LAPB_hdlc){
- struct net_device *dev = card->wandev.dev;
- set_chan_state(dev,WAN_CONNECTED);
- send_delayed_cmd_result(card,dev,card->mbox);
- }
-
- /* 0x8F enable all interrupts */
- x25_set_intr_mode(card, INTR_ON_RX_FRAME|
- INTR_ON_TX_FRAME|
- INTR_ON_MODEM_STATUS_CHANGE|
- //INTR_ON_COMMAND_COMPLETE|
- X25_ASY_TRANS_INTR_PENDING |
- INTR_ON_TIMER |
- DIRECT_RX_INTR_USAGE
- );
-
- status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON;
-
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) {
-
- //printk(KERN_INFO "Poll connect, Turning OFF\n");
- disconnect(card);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF;
-
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) {
-
- //printk(KERN_INFO "POll disconnect, trying to connect\n");
- connect(card);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT;
-
- }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){
-
- if (*card->u.x.hdlc_buf_status & 0x40){
- x25_get_err_stats(card);
- x25_get_stats(card);
- card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE;
- }
- }
-
- if(!card->u.x.timer_int_enabled){
- //printk(KERN_INFO "Turning Timer Off \n");
- status->imask &= ~INTR_ON_TIMER;
- }
-}
-
-/*====================================================================
- * Modem status interrupt handler.
- *===================================================================*/
-static void status_intr (sdla_t* card)
-{
-
- /* Added to avoid Modem status message flooding */
- static TX25ModemStatus last_stat;
-
- TX25Mbox* mbox = card->mbox;
- TX25ModemStatus *modem_status;
- struct net_device *dev;
- x25_channel_t *chan;
- int err;
-
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_READ_MODEM_STATUS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err){
- x25_error(card, err, X25_READ_MODEM_STATUS, 0);
- }else{
-
- modem_status = (TX25ModemStatus*)mbox->data;
-
- /* Check if the last status was the same
- * if it was, do NOT print message again */
-
- if (last_stat.status != modem_status->status){
-
- printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n",
- card->devname,DCD(modem_status->status),CTS(modem_status->status));
-
- last_stat.status = modem_status->status;
-
- if (card->u.x.oob_on_modem){
-
- mbox->cmd.pktType = mbox->cmd.command;
- mbox->cmd.result = 0x08;
-
- /* Send a OOB to all connected sockets */
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device**)dev->priv)) {
- chan=dev->priv;
- if (chan->common.usedby == API){
- send_oob_msg(card,dev,mbox);
- }
- }
-
- /* The modem OOB message will probably kill the
- * the link. If we don't clear the flag here,
- * a deadlock could occur */
- if (atomic_read(&card->u.x.command_busy)){
- atomic_set(&card->u.x.command_busy,0);
- }
- }
- }
- }
-
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_STATUS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err){
- x25_error(card, err, X25_HDLC_LINK_STATUS, 0);
- }
-
-}
-
-/*====================================================================
- * Network event interrupt handler.
- *===================================================================*/
-static void event_intr (sdla_t* card)
-{
- x25_fetch_events(card);
-}
-
-/*====================================================================
- * Spurious interrupt handler.
- * o print a warning
- * o
- *====================================================================*/
-
-static void spur_intr (sdla_t* card)
-{
- printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);
-}
-
-
-/*
- * Background Polling Routines
- */
-
-/*====================================================================
- * Main polling routine.
- * This routine is repeatedly called by the WANPIPE 'thread' to allow for
- * time-dependent housekeeping work.
- *
- * Notes:
- * 1. This routine may be called on interrupt context with all interrupts
- * enabled. Beware!
- *====================================================================*/
-
-static void wpx_poll (sdla_t *card)
-{
- if (!card->wandev.dev){
- goto wpx_poll_exit;
- }
-
- if (card->open_cnt != card->u.x.num_of_ch){
- goto wpx_poll_exit;
- }
-
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- goto wpx_poll_exit;
- }
-
- if (test_bit(SEND_CRIT,&card->wandev.critical)){
- goto wpx_poll_exit;
- }
-
- switch(card->wandev.state){
- case WAN_CONNECTED:
- poll_active(card);
- break;
-
- case WAN_CONNECTING:
- poll_connecting(card);
- break;
-
- case WAN_DISCONNECTED:
- poll_disconnected(card);
- break;
- }
-
-wpx_poll_exit:
- clear_bit(POLL_CRIT,&card->wandev.critical);
- return;
-}
-
-static void trigger_x25_poll(sdla_t *card)
-{
- schedule_work(&card->u.x.x25_poll_work);
-}
-
-/*====================================================================
- * Handle physical link establishment phase.
- * o if connection timed out, disconnect the link.
- *===================================================================*/
-
-static void poll_connecting (sdla_t* card)
-{
- volatile TX25Status* status = card->flags;
-
- if (status->gflags & X25_HDLC_ABM){
-
- timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON);
-
- }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){
-
- timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF);
-
- }
-}
-
-/*====================================================================
- * Handle physical link disconnected phase.
- * o if hold-down timeout has expired and there are open interfaces,
- * connect link.
- *===================================================================*/
-
-static void poll_disconnected (sdla_t* card)
-{
- struct net_device *dev;
- x25_channel_t *chan;
- TX25Status* status = card->flags;
-
- if (!card->u.x.LAPB_hdlc && card->open_cnt &&
- ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){
- timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT);
- }
-
-
- if ((dev=card->wandev.dev) == NULL)
- return;
-
- if ((chan=dev->priv) == NULL)
- return;
-
- if (chan->common.usedby == API &&
- atomic_read(&chan->common.command) &&
- card->u.x.LAPB_hdlc){
-
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC))
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
-
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
-
-}
-
-/*====================================================================
- * Handle active link phase.
- * o fetch X.25 asynchronous events.
- * o kick off transmission on all interfaces.
- *===================================================================*/
-
-static void poll_active (sdla_t* card)
-{
- struct net_device* dev;
- TX25Status* status = card->flags;
-
- for (dev = card->wandev.dev; dev;
- dev = *((struct net_device **)dev->priv)){
- x25_channel_t* chan = dev->priv;
-
- /* If SVC has been idle long enough, close virtual circuit */
- if ( chan->common.svc &&
- chan->common.state == WAN_CONNECTED &&
- chan->common.usedby == WANPIPE ){
-
- if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){
- /* Close svc */
- card->u.x.poll_device=dev;
- timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE);
- }
- }
-
-#ifdef PRINT_DEBUG
- chan->ifstats.tx_compressed = atomic_read(&chan->common.command);
- chan->ifstats.tx_errors = chan->common.state;
- chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy);
- ++chan->ifstats.tx_bytes;
-
- chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect);
- chan->ifstats.multicast=atomic_read(&chan->bh_buff_used);
- chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status;
-#endif
-
- if (chan->common.usedby == API &&
- atomic_read(&chan->common.command) &&
- !card->u.x.LAPB_hdlc){
-
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC))
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
-
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
-
- if ((chan->common.usedby == API) &&
- atomic_read(&chan->common.disconnect)){
-
- if (chan->common.state == WAN_DISCONNECTED){
- atomic_set(&chan->common.disconnect,0);
- return;
- }
-
- atomic_set(&chan->common.command,X25_CLEAR_CALL);
- if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC))
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC;
-
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
- }
- }
-}
-
-static void timer_intr_exec(sdla_t *card, unsigned char TYPE)
-{
- TX25Status* status = card->flags;
- card->u.x.timer_int_enabled |= TYPE;
- if (!(status->imask & INTR_ON_TIMER))
- status->imask |= INTR_ON_TIMER;
-}
-
-
-/*====================================================================
- * SDLA Firmware-Specific Functions
- *
- * Almost all X.25 commands can unexpetedly fail due to so called 'X.25
- * asynchronous events' such as restart, interrupt, incoming call request,
- * call clear request, etc. They can't be ignored and have to be delt with
- * immediately. To tackle with this problem we execute each interface
- * command in a loop until good return code is received or maximum number
- * of retries is reached. Each interface command returns non-zero return
- * code, an asynchronous event/error handler x25_error() is called.
- *====================================================================*/
-
-/*====================================================================
- * Read X.25 firmware version.
- * Put code version as ASCII string in str.
- *===================================================================*/
-
-static int x25_get_version (sdla_t* card, char* str)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_READ_CODE_VERSION;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- &&
- x25_error(card, err, X25_READ_CODE_VERSION, 0));
-
- if (!err && str)
- {
- int len = mbox->cmd.length;
-
- memcpy(str, mbox->data, len);
- str[len] = '\0';
- }
- return err;
-}
-
-/*====================================================================
- * Configure adapter.
- *===================================================================*/
-
-static int x25_configure (sdla_t* card, TX25Config* conf)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
- mbox->cmd.length = sizeof(TX25Config);
- mbox->cmd.command = X25_SET_CONFIGURATION;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
- return err;
-}
-
-/*====================================================================
- * Configure adapter for HDLC only.
- *===================================================================*/
-
-static int hdlc_configure (sdla_t* card, TX25Config* conf)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- memcpy(mbox->data, (void*)conf, sizeof(TX25Config));
- mbox->cmd.length = sizeof(TX25Config);
- mbox->cmd.command = X25_HDLC_SET_CONFIG;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0));
-
- return err;
-}
-
-static int set_hdlc_level (sdla_t* card)
-{
-
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = SET_PROTOCOL_LEVEL;
- mbox->cmd.length = 1;
- mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0));
-
- return err;
-}
-
-
-
-/*====================================================================
- * Get communications error statistics.
- *====================================================================*/
-
-static int x25_get_err_stats (sdla_t* card)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0));
-
- if (!err)
- {
- THdlcCommErr* stats = (void*)mbox->data;
-
- card->wandev.stats.rx_over_errors = stats->rxOverrun;
- card->wandev.stats.rx_crc_errors = stats->rxBadCrc;
- card->wandev.stats.rx_missed_errors = stats->rxAborted;
- card->wandev.stats.tx_aborted_errors = stats->txAborted;
- }
- return err;
-}
-
-/*====================================================================
- * Get protocol statistics.
- *===================================================================*/
-
-static int x25_get_stats (sdla_t* card)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_READ_STATISTICS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ;
-
- if (!err)
- {
- TX25Stats* stats = (void*)mbox->data;
-
- card->wandev.stats.rx_packets = stats->rxData;
- card->wandev.stats.tx_packets = stats->txData;
- }
- return err;
-}
-
-/*====================================================================
- * Close HDLC link.
- *===================================================================*/
-
-static int x25_close_hdlc (sdla_t* card)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_CLOSE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0));
-
- return err;
-}
-
-
-/*====================================================================
- * Open HDLC link.
- *===================================================================*/
-
-static int x25_open_hdlc (sdla_t* card)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_OPEN;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0));
-
- return err;
-}
-
-/*=====================================================================
- * Setup HDLC link.
- *====================================================================*/
-static int x25_setup_hdlc (sdla_t* card)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_HDLC_LINK_SETUP;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0));
-
- return err;
-}
-
-/*====================================================================
- * Set (raise/drop) DTR.
- *===================================================================*/
-
-static int x25_set_dtr (sdla_t* card, int dtr)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->data[0] = 0;
- mbox->data[2] = 0;
- mbox->data[1] = dtr ? 0x02 : 0x01;
- mbox->cmd.length = 3;
- mbox->cmd.command = X25_SET_GLOBAL_VARS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0));
-
- return err;
-}
-
-/*====================================================================
- * Set interrupt mode.
- *===================================================================*/
-
-static int x25_set_intr_mode (sdla_t* card, int mode)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->data[0] = mode;
- if (card->hw.fwid == SFID_X25_508){
- mbox->data[1] = card->hw.irq;
- mbox->data[2] = 2;
- mbox->cmd.length = 3;
- }else {
- mbox->cmd.length = 1;
- }
- mbox->cmd.command = X25_SET_INTERRUPT_MODE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0));
-
- return err;
-}
-
-/*====================================================================
- * Read X.25 channel configuration.
- *===================================================================*/
-
-static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int lcn = chan->common.lcn;
- int err;
-
- do{
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.lcn = lcn;
- mbox->cmd.command = X25_READ_CHANNEL_CONFIG;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn));
-
- if (!err)
- {
- TX25Status* status = card->flags;
-
- /* calculate an offset into the array of status bytes */
- if (card->u.x.hi_svc <= X25_MAX_CHAN){
-
- chan->ch_idx = lcn - 1;
-
- }else{
- int offset;
-
- /* FIX: Apr 14 2000 : Nenad Corbic
- * The data field was being compared to 0x1F using
- * '&&' instead of '&'.
- * This caused X25API to fail for LCNs greater than 255.
- */
- switch (mbox->data[0] & 0x1F)
- {
- case 0x01:
- offset = status->pvc_map; break;
- case 0x03:
- offset = status->icc_map; break;
- case 0x07:
- offset = status->twc_map; break;
- case 0x0B:
- offset = status->ogc_map; break;
- default:
- offset = 0;
- }
- chan->ch_idx = lcn - 1 - offset;
- }
-
- /* get actual transmit packet size on this channel */
- switch(mbox->data[1] & 0x38)
- {
- case 0x00:
- chan->tx_pkt_size = 16;
- break;
- case 0x08:
- chan->tx_pkt_size = 32;
- break;
- case 0x10:
- chan->tx_pkt_size = 64;
- break;
- case 0x18:
- chan->tx_pkt_size = 128;
- break;
- case 0x20:
- chan->tx_pkt_size = 256;
- break;
- case 0x28:
- chan->tx_pkt_size = 512;
- break;
- case 0x30:
- chan->tx_pkt_size = 1024;
- break;
- }
- if (card->u.x.logging)
- printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n",
- card->devname, lcn, chan->tx_pkt_size);
- }
- return err;
-}
-
-/*====================================================================
- * Place X.25 call.
- *====================================================================*/
-
-static int x25_place_call (sdla_t* card, x25_channel_t* chan)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- char str[64];
-
-
- if (chan->protocol == htons(ETH_P_IP)){
- sprintf(str, "-d%s -uCC", chan->addr);
-
- }else if (chan->protocol == htons(ETH_P_IPX)){
- sprintf(str, "-d%s -u800000008137", chan->addr);
-
- }
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- strcpy(mbox->data, str);
- mbox->cmd.length = strlen(str);
- mbox->cmd.command = X25_PLACE_CALL;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0));
-
- if (!err){
- bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn);
- }
- return err;
-}
-
-/*====================================================================
- * Accept X.25 call.
- *====================================================================*/
-
-static int x25_accept_call (sdla_t* card, int lcn, int qdm)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.lcn = lcn;
- mbox->cmd.qdm = qdm;
- mbox->cmd.command = X25_ACCEPT_CALL;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn));
-
- return err;
-}
-
-/*====================================================================
- * Clear X.25 call.
- *====================================================================*/
-
-static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.lcn = lcn;
- mbox->cmd.cause = cause;
- mbox->cmd.diagn = diagn;
- mbox->cmd.command = X25_CLEAR_CALL;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn));
-
- return err;
-}
-
-/*====================================================================
- * Send X.25 data packet.
- *====================================================================*/
-
-static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- unsigned char cmd;
-
- if (card->u.x.LAPB_hdlc)
- cmd = X25_HDLC_WRITE;
- else
- cmd = X25_WRITE;
-
- do
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- memcpy(mbox->data, buf, len);
- mbox->cmd.length = len;
- mbox->cmd.lcn = lcn;
-
- if (card->u.x.LAPB_hdlc){
- mbox->cmd.pf = qdm;
- }else{
- mbox->cmd.qdm = qdm;
- }
-
- mbox->cmd.command = cmd;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && x25_error(card, err, cmd , lcn));
-
-
- /* If buffers are busy the return code for LAPB HDLC is
- * 1. The above functions are looking for return code
- * of X25RES_NOT_READY if busy. */
-
- if (card->u.x.LAPB_hdlc && err == 1){
- err = X25RES_NOT_READY;
- }
-
- return err;
-}
-
-/*====================================================================
- * Fetch X.25 asynchronous events.
- *===================================================================*/
-
-static int x25_fetch_events (sdla_t* card)
-{
- TX25Status* status = card->flags;
- TX25Mbox* mbox = card->mbox;
- int err = 0;
-
- if (status->gflags & 0x20)
- {
- memset(&mbox->cmd, 0, sizeof(TX25Cmd));
- mbox->cmd.command = X25_IS_DATA_AVAILABLE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0);
- }
- return err;
-}
-
-/*====================================================================
- * X.25 asynchronous event/error handler.
- * This routine is called each time interface command returns
- * non-zero return code to handle X.25 asynchronous events and
- * common errors. Return non-zero to repeat command or zero to
- * cancel it.
- *
- * Notes:
- * 1. This function may be called recursively, as handling some of the
- * asynchronous events (e.g. call request) requires execution of the
- * interface command(s) that, in turn, may also return asynchronous
- * events. To avoid re-entrancy problems we copy mailbox to dynamically
- * allocated memory before processing events.
- *====================================================================*/
-
-static int x25_error (sdla_t* card, int err, int cmd, int lcn)
-{
- int retry = 1;
- unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length;
- TX25Mbox* mb;
-
- mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC);
- if (mb == NULL)
- {
- printk(KERN_ERR "%s: x25_error() out of memory!\n",
- card->devname);
- return 0;
- }
- memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen);
- switch (err){
-
- case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */
-
- mb->data[dlen] = '\0';
-
- switch (mb->cmd.pktType & 0x7F){
-
- case ASE_CALL_RQST: /* incoming call */
- retry = incoming_call(card, cmd, lcn, mb);
- break;
-
- case ASE_CALL_ACCEPTED: /* connected */
- retry = call_accepted(card, cmd, lcn, mb);
- break;
-
- case ASE_CLEAR_RQST: /* call clear request */
- retry = call_cleared(card, cmd, lcn, mb);
- break;
-
- case ASE_RESET_RQST: /* reset request */
- printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
- "Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.lcn, mb->cmd.cause,
- mb->cmd.diagn);
- api_oob_event (card,mb);
- break;
-
- case ASE_RESTART_RQST: /* restart request */
- retry = restart_event(card, cmd, lcn, mb);
- break;
-
- case ASE_CLEAR_CONFRM:
- if (clear_confirm_event (card,mb))
- break;
-
- /* I use the goto statement here so if
- * somebody inserts code between the
- * case and default, we will not have
- * ghost problems */
-
- goto dflt_1;
-
- default:
-dflt_1:
- printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! "
- "Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.pktType,
- mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn);
- }
- break;
-
- case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */
-
- /* Bug Fix: Mar 14 2000
- * The Protocol violation error conditions were
- * not handled previously */
-
- switch (mb->cmd.pktType & 0x7F){
-
- case PVE_CLEAR_RQST: /* Clear request */
- retry = call_cleared(card, cmd, lcn, mb);
- break;
-
- case PVE_RESET_RQST: /* Reset request */
- printk(KERN_INFO "%s: X.25 reset request on LCN %d! "
- "Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.lcn, mb->cmd.cause,
- mb->cmd.diagn);
- api_oob_event (card,mb);
- break;
-
- case PVE_RESTART_RQST: /* Restart request */
- retry = restart_event(card, cmd, lcn, mb);
- break;
-
- default :
- printk(KERN_INFO
- "%s: X.25 protocol violation on LCN %d! "
- "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.lcn,
- mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn);
- api_oob_event(card,mb);
- }
- break;
-
- case 0x42: /* X.25 timeout */
- retry = timeout_event(card, cmd, lcn, mb);
- break;
-
- case 0x43: /* X.25 retry limit exceeded */
- printk(KERN_INFO
- "%s: exceeded X.25 retry limit on LCN %d! "
- "Packet:0x%02X Diagn:0x%02X\n", card->devname,
- mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn)
- ;
- break;
-
- case 0x08: /* modem failure */
-#ifndef MODEM_NOT_LOG
- printk(KERN_INFO "%s: modem failure!\n", card->devname);
-#endif /* MODEM_NOT_LOG */
- api_oob_event(card,mb);
- break;
-
- case 0x09: /* N2 retry limit */
- printk(KERN_INFO "%s: exceeded HDLC retry limit!\n",
- card->devname);
- api_oob_event(card,mb);
- break;
-
- case 0x06: /* unnumbered frame was received while in ABM */
- printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n",
- card->devname, mb->data[0]);
- api_oob_event(card,mb);
- break;
-
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd)
- ;
- retry = 0; /* abort command */
- break;
-
- case X25RES_NOT_READY:
- retry = 1;
- break;
-
- case 0x01:
- if (card->u.x.LAPB_hdlc)
- break;
-
- if (mb->cmd.command == 0x16)
- break;
- /* I use the goto statement here so if
- * somebody inserts code between the
- * case and default, we will not have
- * ghost problems */
- goto dflt_2;
-
- default:
-dflt_2:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n",
- card->devname, cmd, err, mb->cmd.lcn)
- ;
- retry = 0; /* abort command */
- }
- kfree(mb);
- return retry;
-}
-
-/*====================================================================
- * X.25 Asynchronous Event Handlers
- * These functions are called by the x25_error() and should return 0, if
- * the command resulting in the asynchronous event must be aborted.
- *====================================================================*/
-
-
-
-/*====================================================================
- *Handle X.25 incoming call request.
- * RFC 1356 establishes the following rules:
- * 1. The first octet in the Call User Data (CUD) field of the call
- * request packet contains NLPID identifying protocol encapsulation
- * 2. Calls MUST NOT be accepted unless router supports requested
- * protocol encapsulation.
- * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used
- * when clearing a call because protocol encapsulation is not
- * supported.
- * 4. If an incoming call is received while a call request is
- * pending (i.e. call collision has occurred), the incoming call
- * shall be rejected and call request shall be retried.
- *====================================================================*/
-
-static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
- struct wan_device* wandev = &card->wandev;
- int new_lcn = mb->cmd.lcn;
- struct net_device* dev = get_dev_by_lcn(wandev, new_lcn);
- x25_channel_t* chan = NULL;
- int accept = 0; /* set to '1' if o.k. to accept call */
- unsigned int user_data;
- x25_call_info_t* info;
-
- /* Make sure there is no call collision */
- if (dev != NULL)
- {
- printk(KERN_INFO
- "%s: X.25 incoming call collision on LCN %d!\n",
- card->devname, new_lcn);
-
- x25_clear_call(card, new_lcn, 0, 0);
- return 1;
- }
-
- /* Make sure D bit is not set in call request */
-//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT
-// if (mb->cmd.qdm & 0x02)
-// {
-// printk(KERN_INFO
-// "%s: X.25 incoming call on LCN %d with D-bit set!\n",
-// card->devname, new_lcn);
-//
-// x25_clear_call(card, new_lcn, 0, 0);
-// return 1;
-// }
-
- /* Parse call request data */
- info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC);
- if (info == NULL)
- {
- printk(KERN_ERR
- "%s: not enough memory to parse X.25 incoming call "
- "on LCN %d!\n", card->devname, new_lcn);
- x25_clear_call(card, new_lcn, 0, 0);
- return 1;
- }
-
- parse_call_info(mb->data, info);
-
- if (card->u.x.logging)
- printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n",
- card->devname, new_lcn);
-
- /* Conver the first two ASCII characters into an
- * interger. Used to check the incoming protocol
- */
- user_data = hex_to_uint(info->user,2);
-
- /* Find available channel */
- for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) {
- chan = dev->priv;
-
- if (chan->common.usedby == API)
- continue;
-
- if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED))
- continue;
-
- if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){
- printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n",
- htons(chan->protocol), info->user[0]);
- continue;
- }
-
- if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){
- printk(KERN_INFO "IPX packet but configured for IP: %x\n",
- htons(chan->protocol));
- continue;
- }
- if (strcmp(info->src, chan->addr) == 0)
- break;
-
- /* If just an '@' is specified, accept all incoming calls */
- if (strcmp(chan->addr, "") == 0)
- break;
- }
-
- if (dev == NULL){
-
- /* If the call is not for any WANPIPE interfaces
- * check to see if there is an API listening queue
- * waiting for data. If there is send the packet
- * up the stack.
- */
- if (card->sk != NULL && card->func != NULL){
- if (api_incoming_call(card,mb,new_lcn)){
- x25_clear_call(card, new_lcn, 0, 0);
- }
- accept = 0;
- }else{
- printk(KERN_INFO "%s: no channels available!\n",
- card->devname);
-
- x25_clear_call(card, new_lcn, 0, 0);
- }
-
- }else if (info->nuser == 0){
-
- printk(KERN_INFO
- "%s: no user data in incoming call on LCN %d!\n",
- card->devname, new_lcn)
- ;
- x25_clear_call(card, new_lcn, 0, 0);
-
- }else switch (info->user[0]){
-
- case 0: /* multiplexed */
- chan->protocol = htons(0);
- accept = 1;
- break;
-
- case NLPID_IP: /* IP datagrams */
- accept = 1;
- break;
-
- case NLPID_SNAP: /* IPX datagrams */
- accept = 1;
- break;
-
- default:
- printk(KERN_INFO
- "%s: unsupported NLPID 0x%02X in incoming call "
- "on LCN %d!\n", card->devname, info->user[0], new_lcn);
- x25_clear_call(card, new_lcn, 0, 249);
- }
-
- if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){
-
- bind_lcn_to_dev (card, chan->dev, new_lcn);
-
- if (x25_get_chan_conf(card, chan) == CMD_OK)
- set_chan_state(dev, WAN_CONNECTED);
- else
- x25_clear_call(card, new_lcn, 0, 0);
- }
- kfree(info);
- return 1;
-}
-
-/*====================================================================
- * Handle accepted call.
- *====================================================================*/
-
-static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
- unsigned new_lcn = mb->cmd.lcn;
- struct net_device* dev = find_channel(card, new_lcn);
- x25_channel_t* chan;
-
- if (dev == NULL){
- printk(KERN_INFO
- "%s: clearing orphaned connection on LCN %d!\n",
- card->devname, new_lcn);
- x25_clear_call(card, new_lcn, 0, 0);
- return 1;
- }
-
- if (card->u.x.logging)
- printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n",
- card->devname, dev->name, new_lcn);
-
- /* Get channel configuration and notify router */
- chan = dev->priv;
- if (x25_get_chan_conf(card, chan) != CMD_OK)
- {
- x25_clear_call(card, new_lcn, 0, 0);
- return 1;
- }
-
- set_chan_state(dev, WAN_CONNECTED);
-
- if (chan->common.usedby == API){
- send_delayed_cmd_result(card,dev,mb);
- bind_lcn_to_dev (card, dev, new_lcn);
- }
-
- return 1;
-}
-
-/*====================================================================
- * Handle cleared call.
- *====================================================================*/
-
-static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
- unsigned new_lcn = mb->cmd.lcn;
- struct net_device* dev = find_channel(card, new_lcn);
- x25_channel_t *chan;
- unsigned char old_state;
-
- if (card->u.x.logging){
- printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X "
- "Diagn:0x%02X\n",
- card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn);
- }
-
- if (dev == NULL){
- printk(KERN_INFO "%s: X.25 clear request : No device for clear\n",
- card->devname);
- return 1;
- }
-
- chan=dev->priv;
-
- old_state = chan->common.state;
-
- set_chan_state(dev, WAN_DISCONNECTED);
-
- if (chan->common.usedby == API){
-
- switch (old_state){
-
- case WAN_CONNECTING:
- send_delayed_cmd_result(card,dev,mb);
- break;
- case WAN_CONNECTED:
- send_oob_msg(card,dev,mb);
- break;
- }
- }
-
- return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1;
-}
-
-/*====================================================================
- * Handle X.25 restart event.
- *====================================================================*/
-
-static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
- struct wan_device* wandev = &card->wandev;
- struct net_device* dev;
- x25_channel_t *chan;
- unsigned char old_state;
-
- printk(KERN_INFO
- "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n",
- card->devname, mb->cmd.cause, mb->cmd.diagn);
-
- /* down all logical channels */
- for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) {
- chan=dev->priv;
- old_state = chan->common.state;
-
- set_chan_state(dev, WAN_DISCONNECTED);
-
- if (chan->common.usedby == API){
- switch (old_state){
-
- case WAN_CONNECTING:
- send_delayed_cmd_result(card,dev,mb);
- break;
- case WAN_CONNECTED:
- send_oob_msg(card,dev,mb);
- break;
- }
- }
- }
- return (cmd == X25_WRITE) ? 0 : 1;
-}
-
-/*====================================================================
- * Handle timeout event.
- *====================================================================*/
-
-static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
-{
- unsigned new_lcn = mb->cmd.lcn;
-
- if (mb->cmd.pktType == 0x05) /* call request time out */
- {
- struct net_device* dev = find_channel(card,new_lcn);
-
- printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
- card->devname, new_lcn);
-
- if (dev){
- x25_channel_t *chan = dev->priv;
- set_chan_state(dev, WAN_DISCONNECTED);
-
- if (chan->common.usedby == API){
- send_delayed_cmd_result(card,dev,card->mbox);
- }
- }
- }else{
- printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n",
- card->devname, mb->cmd.pktType, new_lcn);
- }
- return 1;
-}
-
-/*
- * Miscellaneous
- */
-
-/*====================================================================
- * Establish physical connection.
- * o open HDLC and raise DTR
- *
- * Return: 0 connection established
- * 1 connection is in progress
- * <0 error
- *===================================================================*/
-
-static int connect (sdla_t* card)
-{
- TX25Status* status = card->flags;
-
- if (x25_open_hdlc(card) || x25_setup_hdlc(card))
- return -EIO;
-
- wanpipe_set_state(card, WAN_CONNECTING);
-
- x25_set_intr_mode(card, INTR_ON_TIMER);
- status->imask &= ~INTR_ON_TIMER;
-
- return 1;
-}
-
-/*
- * Tear down physical connection.
- * o close HDLC link
- * o drop DTR
- *
- * Return: 0
- * <0 error
- */
-
-static int disconnect (sdla_t* card)
-{
- wanpipe_set_state(card, WAN_DISCONNECTED);
- x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */
- x25_close_hdlc(card); /* close HDLC link */
- x25_set_dtr(card, 0); /* drop DTR */
- return 0;
-}
-
-/*
- * Find network device by its channel number.
- */
-
-static struct net_device* get_dev_by_lcn(struct wan_device* wandev,
- unsigned lcn)
-{
- struct net_device* dev;
-
- for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv))
- if (((x25_channel_t*)dev->priv)->common.lcn == lcn)
- break;
- return dev;
-}
-
-/*
- * Initiate connection on the logical channel.
- * o for PVC we just get channel configuration
- * o for SVCs place an X.25 call
- *
- * Return: 0 connected
- * >0 connection in progress
- * <0 failure
- */
-
-static int chan_connect(struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
-
- if (chan->common.svc && chan->common.usedby == WANPIPE){
- if (!chan->addr[0]){
- printk(KERN_INFO "%s: No Destination Address\n",
- card->devname);
- return -EINVAL; /* no destination address */
- }
- printk(KERN_INFO "%s: placing X.25 call to %s ...\n",
- card->devname, chan->addr);
-
- if (x25_place_call(card, chan) != CMD_OK)
- return -EIO;
-
- set_chan_state(dev, WAN_CONNECTING);
- return 1;
- }else{
- if (x25_get_chan_conf(card, chan) != CMD_OK)
- return -EIO;
-
- set_chan_state(dev, WAN_CONNECTED);
- }
- return 0;
-}
-
-/*
- * Disconnect logical channel.
- * o if SVC then clear X.25 call
- */
-
-static int chan_disc(struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
-
- if (chan->common.svc){
- x25_clear_call(chan->card, chan->common.lcn, 0, 0);
-
- /* For API we disconnect on clear
- * confirmation.
- */
- if (chan->common.usedby == API)
- return 0;
- }
-
- set_chan_state(dev, WAN_DISCONNECTED);
-
- return 0;
-}
-
-/*
- * Set logical channel state.
- */
-
-static void set_chan_state(struct net_device* dev, int state)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (chan->common.state != state)
- {
- switch (state)
- {
- case WAN_CONNECTED:
- if (card->u.x.logging){
- printk (KERN_INFO
- "%s: interface %s connected, lcn %i !\n",
- card->devname, dev->name,chan->common.lcn);
- }
- *(unsigned short*)dev->dev_addr = htons(chan->common.lcn);
- chan->i_timeout_sofar = jiffies;
-
- /* LAPB is PVC Based */
- if (card->u.x.LAPB_hdlc)
- chan->common.svc=0;
- break;
-
- case WAN_CONNECTING:
- if (card->u.x.logging){
- printk (KERN_INFO
- "%s: interface %s connecting, lcn %i ...\n",
- card->devname, dev->name, chan->common.lcn);
- }
- break;
-
- case WAN_DISCONNECTED:
- if (card->u.x.logging){
- printk (KERN_INFO
- "%s: interface %s disconnected, lcn %i !\n",
- card->devname, dev->name,chan->common.lcn);
- }
- atomic_set(&chan->common.disconnect,0);
-
- if (chan->common.svc) {
- *(unsigned short*)dev->dev_addr = 0;
- card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL;
- chan->common.lcn = 0;
- }
-
- if (chan->transmit_length){
- chan->transmit_length=0;
- atomic_set(&chan->common.driver_busy,0);
- chan->tx_offset=0;
- if (netif_queue_stopped(dev)){
- netif_wake_queue(dev);
- }
- }
- atomic_set(&chan->common.command,0);
- break;
-
- case WAN_DISCONNECTING:
- if (card->u.x.logging){
- printk (KERN_INFO
- "\n%s: interface %s disconnecting, lcn %i ...\n",
- card->devname, dev->name,chan->common.lcn);
- }
- atomic_set(&chan->common.disconnect,0);
- break;
- }
- chan->common.state = state;
- }
- chan->state_tick = jiffies;
- restore_flags(flags);
-}
-
-/*
- * Send packet on a logical channel.
- * When this function is called, tx_skb field of the channel data
- * space points to the transmit socket buffer. When transmission
- * is complete, release socket buffer and reset 'tbusy' flag.
- *
- * Return: 0 - transmission complete
- * 1 - busy
- *
- * Notes:
- * 1. If packet length is greater than MTU for this channel, we'll fragment
- * the packet into 'complete sequence' using M-bit.
- * 2. When transmission is complete, an event notification should be issued
- * to the router.
- */
-
-static int chan_send(struct net_device* dev, void* buff, unsigned data_len,
- unsigned char tx_intr)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- TX25Status* status = card->flags;
- unsigned len=0, qdm=0, res=0, orig_len = 0;
- void *data;
-
- /* Check to see if channel is ready */
- if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) ||
- !(*card->u.x.hdlc_buf_status & 0x40)){
-
- if (!tx_intr){
- setup_for_delayed_transmit (dev, buff, data_len);
- return 0;
- }else{
- /* By returning 0 to tx_intr the packet will be dropped */
- ++card->wandev.stats.tx_dropped;
- ++chan->ifstats.tx_dropped;
- printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n",
- card->devname,dev->name);
- ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr;
- return 0;
- }
- }
-
- if (chan->common.usedby == API){
- /* Remove the API Header */
- x25api_hdr_t *api_data = (x25api_hdr_t *)buff;
-
- /* Set the qdm bits from the packet header
- * User has the option to set the qdm bits
- */
- qdm = api_data->qdm;
-
- orig_len = len = data_len - sizeof(x25api_hdr_t);
- data = (unsigned char*)buff + sizeof(x25api_hdr_t);
- }else{
- data = buff;
- orig_len = len = data_len;
- }
-
- if (tx_intr){
- /* We are in tx_intr, minus the tx_offset from
- * the total length. The tx_offset part of the
- * data has already been sent. Also, move the
- * data pointer to proper offset location.
- */
- len -= chan->tx_offset;
- data = (unsigned char*)data + chan->tx_offset;
- }
-
- /* Check if the packet length is greater than MTU
- * If YES: Cut the len to MTU and set the M bit
- */
- if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){
- len = chan->tx_pkt_size;
- qdm |= M_BIT;
- }
-
-
- /* Pass only first three bits of the qdm byte to the send
- * routine. In case user sets any other bit which might
- * cause errors.
- */
-
- switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){
- case 0x00: /* success */
- chan->i_timeout_sofar = jiffies;
-
- dev->trans_start=jiffies;
-
- if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){
- if (!tx_intr){
- /* The M bit was set, which means that part of the
- * packet has been sent. Copy the packet into a buffer
- * and set the offset to len, so on next tx_inter
- * the packet will be sent using the below offset.
- */
- chan->tx_offset += len;
-
- ++chan->ifstats.tx_packets;
- chan->ifstats.tx_bytes += len;
-
- if (chan->tx_offset < orig_len){
- setup_for_delayed_transmit (dev, buff, data_len);
- }
- res=0;
- }else{
- /* We are already in tx_inter, thus data is already
- * in the buffer. Update the offset and wait for
- * next tx_intr. We add on to the offset, since data can
- * be X number of times larger than max data size.
- */
- ++chan->ifstats.tx_packets;
- chan->ifstats.tx_bytes += len;
-
- ++chan->if_send_stat.if_send_bfr_passed_to_adptr;
- chan->tx_offset += len;
-
- /* The user can set the qdm bit as well.
- * If the entire packet was sent and qdm is still
- * set, than it's the user who has set the M bit. In that,
- * case indicate that the packet was send by returning
- * 0 and wait for a new packet. Otherwise, wait for next
- * tx interrupt to send the rest of the packet */
-
- if (chan->tx_offset < orig_len){
- res=1;
- }else{
- res=0;
- }
- }
- }else{
- ++chan->ifstats.tx_packets;
- chan->ifstats.tx_bytes += len;
- ++chan->if_send_stat.if_send_bfr_passed_to_adptr;
- res=0;
- }
- break;
-
- case 0x33: /* Tx busy */
- if (tx_intr){
- printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n",
- card->devname,dev->name);
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr;
- res=0;
- }else{
- DBG_PRINTK(KERN_INFO
- "%s: Send: Big Error should have tx: storring %s\n",
- card->devname,dev->name);
- setup_for_delayed_transmit (dev, buff, data_len);
- res=1;
- }
- break;
-
- default: /* failure */
- ++chan->ifstats.tx_errors;
- if (tx_intr){
- printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n",
- card->devname,dev->name);
- ++chan->ifstats.tx_dropped;
- ++card->wandev.stats.tx_dropped;
- ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr;
- res=0;
- }else{
- DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n",
- card->devname,dev->name);
- setup_for_delayed_transmit (dev, buff, data_len);
- res=1;
- }
- break;
- }
- return res;
-}
-
-
-/*
- * Parse X.25 call request data and fill x25_call_info_t structure.
- */
-
-static void parse_call_info (unsigned char* str, x25_call_info_t* info)
-{
- memset(info, 0, sizeof(x25_call_info_t));
- for (; *str; ++str)
- {
- int i;
- unsigned char ch;
-
- if (*str == '-') switch (str[1]) {
-
- /* Take minus 2 off the maximum size so that
- * last byte is 0. This way we can use string
- * manipulaton functions on call information.
- */
-
- case 'd': /* destination address */
- for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){
- ch = str[2+i];
- if (isspace(ch)) break;
- info->dest[i] = ch;
- }
- break;
-
- case 's': /* source address */
- for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){
- ch = str[2+i];
- if (isspace(ch)) break;
- info->src[i] = ch;
- }
- break;
-
- case 'u': /* user data */
- for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){
- ch = str[2+i];
- if (isspace(ch)) break;
- info->user[i] = ch;
- }
- info->nuser = i;
- break;
-
- case 'f': /* facilities */
- for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){
- ch = str[2+i];
- if (isspace(ch)) break;
- info->facil[i] = ch;
- }
- info->nfacil = i;
- break;
- }
- }
-}
-
-/*
- * Convert line speed in bps to a number used by S502 code.
- */
-
-static unsigned char bps_to_speed_code (unsigned long bps)
-{
- unsigned char number;
-
- if (bps <= 1200) number = 0x01;
- else if (bps <= 2400) number = 0x02;
- else if (bps <= 4800) number = 0x03;
- else if (bps <= 9600) number = 0x04;
- else if (bps <= 19200) number = 0x05;
- else if (bps <= 38400) number = 0x06;
- else if (bps <= 45000) number = 0x07;
- else if (bps <= 56000) number = 0x08;
- else if (bps <= 64000) number = 0x09;
- else if (bps <= 74000) number = 0x0A;
- else if (bps <= 112000) number = 0x0B;
- else if (bps <= 128000) number = 0x0C;
- else number = 0x0D;
-
- return number;
-}
-
-/*
- * Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted.
- */
-
-static unsigned int dec_to_uint (unsigned char* str, int len)
-{
- unsigned val;
-
- if (!len)
- len = strlen(str);
-
- for (val = 0; len && isdigit(*str); ++str, --len)
- val = (val * 10) + (*str - (unsigned)'0');
-
- return val;
-}
-
-/*
- * Convert hex string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are conferted.
- */
-
-static unsigned int hex_to_uint (unsigned char* str, int len)
-{
- unsigned val, ch;
-
- if (!len)
- len = strlen(str);
-
- for (val = 0; len; ++str, --len)
- {
- ch = *str;
- if (isdigit(ch))
- val = (val << 4) + (ch - (unsigned)'0');
- else if (isxdigit(ch))
- val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10);
- else break;
- }
- return val;
-}
-
-
-static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto)
-{
- int i;
-
- if( proto == ETH_P_IPX) {
- /* It's an IPX packet */
- if(!enable_IPX) {
- /* Return 1 so we don't pass it up the stack. */
- return 1;
- }
- } else {
- /* It's not IPX so pass it up the stack.*/
- return 0;
- }
-
- if( sendpacket[16] == 0x90 &&
- sendpacket[17] == 0x04)
- {
- /* It's IPXWAN */
-
- if( sendpacket[2] == 0x02 &&
- sendpacket[34] == 0x00)
- {
- /* It's a timer request packet */
- printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname);
-
- /* Go through the routing options and answer no to every
- * option except Unnumbered RIP/SAP
- */
- for(i = 41; sendpacket[i] == 0x00; i += 5)
- {
- /* 0x02 is the option for Unnumbered RIP/SAP */
- if( sendpacket[i + 4] != 0x02)
- {
- sendpacket[i + 1] = 0;
- }
- }
-
- /* Skip over the extended Node ID option */
- if( sendpacket[i] == 0x04 )
- {
- i += 8;
- }
-
- /* We also want to turn off all header compression opt. */
- for(; sendpacket[i] == 0x80 ;)
- {
- sendpacket[i + 1] = 0;
- i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4;
- }
-
- /* Set the packet type to timer response */
- sendpacket[34] = 0x01;
-
- printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname);
- }
- else if( sendpacket[34] == 0x02 )
- {
- /* This is an information request packet */
- printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname);
-
- /* Set the packet type to information response */
- sendpacket[34] = 0x03;
-
- /* Set the router name */
- sendpacket[51] = 'X';
- sendpacket[52] = 'T';
- sendpacket[53] = 'P';
- sendpacket[54] = 'I';
- sendpacket[55] = 'P';
- sendpacket[56] = 'E';
- sendpacket[57] = '-';
- sendpacket[58] = CVHexToAscii(network_number >> 28);
- sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24);
- sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20);
- sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16);
- sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12);
- sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8);
- sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4);
- sendpacket[65] = CVHexToAscii(network_number & 0x0000000F);
- for(i = 66; i < 99; i+= 1)
- {
- sendpacket[i] = 0;
- }
-
- printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname);
- }
- else
- {
- printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname);
- return 0;
- }
-
- /* Set the WNodeID to our network address */
- sendpacket[35] = (unsigned char)(network_number >> 24);
- sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16);
- sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8);
- sendpacket[38] = (unsigned char)(network_number & 0x000000FF);
-
- return 1;
- } else {
- /*If we get here it's an IPX-data packet, so it'll get passed up the stack.
- */
- /* switch the network numbers */
- switch_net_numbers(sendpacket, network_number, 1);
- return 0;
- }
-}
-
-/*
- * If incoming is 0 (outgoing)- if the net numbers is ours make it 0
- * if incoming is 1 - if the net number is 0 make it ours
- */
-
-static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming)
-{
- unsigned long pnetwork_number;
-
- pnetwork_number = (unsigned long)((sendpacket[6] << 24) +
- (sendpacket[7] << 16) + (sendpacket[8] << 8) +
- sendpacket[9]);
-
-
- if (!incoming) {
- /*If the destination network number is ours, make it 0 */
- if( pnetwork_number == network_number) {
- sendpacket[6] = sendpacket[7] = sendpacket[8] =
- sendpacket[9] = 0x00;
- }
- } else {
- /* If the incoming network is 0, make it ours */
- if( pnetwork_number == 0) {
- sendpacket[6] = (unsigned char)(network_number >> 24);
- sendpacket[7] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[8] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[9] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
-
-
- pnetwork_number = (unsigned long)((sendpacket[18] << 24) +
- (sendpacket[19] << 16) + (sendpacket[20] << 8) +
- sendpacket[21]);
-
-
- if( !incoming ) {
- /* If the source network is ours, make it 0 */
- if( pnetwork_number == network_number) {
- sendpacket[18] = sendpacket[19] = sendpacket[20] =
- sendpacket[21] = 0x00;
- }
- } else {
- /* If the source network is 0, make it ours */
- if( pnetwork_number == 0 ) {
- sendpacket[18] = (unsigned char)(network_number >> 24);
- sendpacket[19] = (unsigned char)((network_number &
- 0x00FF0000) >> 16);
- sendpacket[20] = (unsigned char)((network_number &
- 0x0000FF00) >> 8);
- sendpacket[21] = (unsigned char)(network_number &
- 0x000000FF);
- }
- }
-} /* switch_net_numbers */
-
-
-
-
-/********************* X25API SPECIFIC FUNCTIONS ****************/
-
-
-/*===============================================================
- * find_channel
- *
- * Manages the lcn to device map. It increases performance
- * because it eliminates the need to search through the link
- * list for a device which is bounded to a specific lcn.
- *
- *===============================================================*/
-
-
-struct net_device *find_channel(sdla_t *card, unsigned lcn)
-{
- if (card->u.x.LAPB_hdlc){
-
- return card->wandev.dev;
-
- }else{
- /* We don't know whether the incoming lcn
- * is a PVC or an SVC channel. But we do know that
- * the lcn cannot be for both the PVC and the SVC
- * channel.
-
- * If the lcn number is greater or equal to 255,
- * take the modulo 255 of that number. We only have
- * 255 locations, thus higher numbers must be mapped
- * to a number between 0 and 245.
-
- * We must separate pvc's and svc's since two don't
- * have to be contiguous. Meaning pvc's can start
- * from 1 to 10 and svc's can start from 256 to 266.
- * But 256%255 is 1, i.e. CONFLICT.
- */
-
-
- /* Highest LCN number must be less or equal to 4096 */
- if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){
-
- if (lcn < X25_MAX_CHAN){
- if (card->u.x.svc_to_dev_map[lcn])
- return card->u.x.svc_to_dev_map[lcn];
-
- if (card->u.x.pvc_to_dev_map[lcn])
- return card->u.x.pvc_to_dev_map[lcn];
-
- }else{
- int new_lcn = lcn%X25_MAX_CHAN;
- if (card->u.x.svc_to_dev_map[new_lcn])
- return card->u.x.svc_to_dev_map[new_lcn];
-
- if (card->u.x.pvc_to_dev_map[new_lcn])
- return card->u.x.pvc_to_dev_map[new_lcn];
- }
- }
- return NULL;
- }
-}
-
-void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn)
-{
- x25_channel_t *chan = dev->priv;
-
- /* Modulo the lcn number by X25_MAX_CHAN (255)
- * because the lcn number can be greater than 255
- *
- * We need to split svc and pvc since they don't have
- * to be contigous.
- */
-
- if (chan->common.svc){
- card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev;
- }else{
- card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev;
- }
- chan->common.lcn = lcn;
-}
-
-
-
-/*===============================================================
- * x25api_bh
- *
- *
- *==============================================================*/
-
-static void x25api_bh(struct net_device* dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- struct sk_buff *skb;
-
- if (atomic_read(&chan->bh_buff_used) == 0){
- printk(KERN_INFO "%s: BH Buffer Empty in BH\n",
- card->devname);
- clear_bit(0, &chan->tq_working);
- return;
- }
-
- while (atomic_read(&chan->bh_buff_used)){
-
- /* If the sock is in the process of unlinking the
- * driver from the socket, we must get out.
- * This never happends but is a sanity check. */
- if (test_bit(0,&chan->common.common_critical)){
- clear_bit(0, &chan->tq_working);
- return;
- }
-
- /* If LAPB HDLC, do not drop packets if socket is
- * not connected. Let the buffer fill up and
- * turn off rx interrupt */
- if (card->u.x.LAPB_hdlc){
- if (chan->common.sk == NULL || chan->common.func == NULL){
- clear_bit(0, &chan->tq_working);
- return;
- }
- }
-
- skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
-
- if (skb == NULL){
- printk(KERN_INFO "%s: BH Skb empty for read %i\n",
- card->devname,chan->bh_read);
- }else{
-
- if (chan->common.sk == NULL || chan->common.func == NULL){
- printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n",
- card->devname);
- dev_kfree_skb_any(skb);
- x25api_bh_cleanup(dev);
- ++chan->ifstats.rx_dropped;
- ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack;
- continue;
- }
-
-
- if (chan->common.func(skb,dev,chan->common.sk) != 0){
- /* Sock full cannot send, queue us for another
- * try
- */
- printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n",
- card->devname);
- atomic_set(&chan->common.receive_block,1);
- return;
- }else{
- x25api_bh_cleanup(dev);
- ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack;
- }
- }
- }
- clear_bit(0, &chan->tq_working);
-
- return;
-}
-
-/*===============================================================
- * x25api_bh_cleanup
- *
- *
- *==============================================================*/
-
-static int x25api_bh_cleanup(struct net_device *dev)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
- TX25Status* status = card->flags;
-
-
- ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
-
- if (chan->bh_read == MAX_BH_BUFF){
- chan->bh_read=0;
- }else{
- ++chan->bh_read;
- }
-
- /* If the Receive interrupt was off, it means
- * that we filled up our circular buffer. Check
- * that we have space in the buffer. If so
- * turn the RX interrupt back on.
- */
- if (!(status->imask & INTR_ON_RX_FRAME)){
- if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){
- printk(KERN_INFO "%s: BH: Turning on the interrupt\n",
- card->devname);
- status->imask |= INTR_ON_RX_FRAME;
- }
- }
-
- atomic_dec(&chan->bh_buff_used);
- return 0;
-}
-
-
-/*===============================================================
- * bh_enqueue
- *
- *
- *==============================================================*/
-
-static int bh_enqueue(struct net_device *dev, struct sk_buff *skb)
-{
- x25_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
- TX25Status* status = card->flags;
-
- if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){
- printk(KERN_INFO "%s: Bottom half buffer FULL\n",
- card->devname);
- return 1;
- }
-
- ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
-
- if (chan->bh_write == MAX_BH_BUFF){
- chan->bh_write=0;
- }else{
- ++chan->bh_write;
- }
-
- atomic_inc(&chan->bh_buff_used);
-
- if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){
- printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n",
- card->devname);
- status->imask &= ~INTR_ON_RX_FRAME;
- }
-
- return 0;
-}
-
-
-/*===============================================================
- * timer_intr_cmd_exec
- *
- * Called by timer interrupt to execute a command
- *===============================================================*/
-
-static int timer_intr_cmd_exec (sdla_t* card)
-{
- struct net_device *dev;
- unsigned char more_to_exec=0;
- volatile x25_channel_t *chan=NULL;
- int i=0,bad_cmd=0,err=0;
-
- if (card->u.x.cmd_dev == NULL){
- card->u.x.cmd_dev = card->wandev.dev;
- }
-
- dev = card->u.x.cmd_dev;
-
- for (;;){
-
- chan = dev->priv;
-
- if (atomic_read(&chan->common.command)){
-
- bad_cmd = check_bad_command(card,dev);
-
- if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) &&
- !bad_cmd){
-
- /* Socket has died or exited, We must bring the
- * channel down before anybody else tries to
- * use it */
- err = channel_disconnect(card,dev);
- }else{
- err = execute_delayed_cmd(card, dev,
- (mbox_cmd_t*)chan->common.mbox,
- bad_cmd);
- }
-
- switch (err){
-
- case RETURN_RESULT:
-
- /* Return the result to the socket without
- * delay. NO_WAIT Command */
- atomic_set(&chan->common.command,0);
- if (atomic_read(&card->u.x.command_busy))
- atomic_set(&card->u.x.command_busy,0);
-
- send_delayed_cmd_result(card,dev,card->mbox);
-
- more_to_exec=0;
- break;
- case DELAY_RESULT:
-
- /* Wait for the remote to respond, before
- * sending the result up to the socket.
- * WAIT command */
- if (atomic_read(&card->u.x.command_busy))
- atomic_set(&card->u.x.command_busy,0);
-
- atomic_set(&chan->common.command,0);
- more_to_exec=0;
- break;
- default:
-
- /* If command could not be executed for
- * some reason (i.e return code 0x33 busy)
- * set the more_to_exec bit which will
- * indicate that this command must be exectued
- * again during next timer interrupt
- */
- more_to_exec=1;
- if (atomic_read(&card->u.x.command_busy) == 0)
- atomic_set(&card->u.x.command_busy,1);
- break;
- }
-
- bad_cmd=0;
-
- /* If flags is set, there are no hdlc buffers,
- * thus, wait for the next pass and try the
- * same command again. Otherwise, start searching
- * from next device on the next pass.
- */
- if (!more_to_exec){
- dev = move_dev_to_next(card,dev);
- }
- break;
- }else{
- /* This device has nothing to execute,
- * go to next.
- */
- if (atomic_read(&card->u.x.command_busy))
- atomic_set(&card->u.x.command_busy,0);
- dev = move_dev_to_next(card,dev);
- }
-
- if (++i == card->u.x.no_dev){
- if (!more_to_exec){
- DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n",
- card->devname);
- if (atomic_read(&card->u.x.command_busy)){
- atomic_set(&card->u.x.command_busy,0);
- }
- }
- break;
- }
-
- } //End of FOR
-
- card->u.x.cmd_dev = dev;
-
- if (more_to_exec){
- /* If more commands are pending, do not turn off timer
- * interrupt */
- return 1;
- }else{
- /* No more commands, turn off timer interrupt */
- return 0;
- }
-}
-
-/*===============================================================
- * execute_delayed_cmd
- *
- * Execute an API command which was passed down from the
- * sock. Sock is very limited in which commands it can
- * execute. Wait and No Wait commands are supported.
- * Place Call, Clear Call and Reset wait commands, where
- * Accept Call is a no_wait command.
- *
- *===============================================================*/
-
-static int execute_delayed_cmd(sdla_t* card, struct net_device *dev,
- mbox_cmd_t *usr_cmd, char bad_cmd)
-{
- TX25Mbox* mbox = card->mbox;
- int err;
- x25_channel_t *chan = dev->priv;
- int delay=RETURN_RESULT;
-
- if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){
- return TRY_CMD_AGAIN;
- }
-
- /* This way a command is guaranteed to be executed for
- * a specific lcn, the network interface is bound to. */
- usr_cmd->cmd.lcn = chan->common.lcn;
-
-
- /* If channel is pvc, instead of place call
- * run x25_channel configuration. If running LAPB HDLC
- * enable communications.
- */
- if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){
-
- if (card->u.x.LAPB_hdlc){
- DBG_PRINTK(KERN_INFO "LAPB: Connecting\n");
- connect(card);
- set_chan_state(dev,WAN_CONNECTING);
- return DELAY_RESULT;
- }else{
- DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname);
- if (x25_get_chan_conf(card, chan) == CMD_OK){
- set_chan_state(dev, WAN_CONNECTED);
- }else{
- set_chan_state(dev, WAN_DISCONNECTED);
- }
- return RETURN_RESULT;
- }
- }
-
- /* Copy the socket mbox command onto the board */
-
- memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd));
- if (usr_cmd->cmd.length){
- memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length);
- }
-
- /* Check if command is bad. We need to copy the cmd into
- * the buffer regardless since we return the, mbox to
- * the user */
- if (bad_cmd){
- mbox->cmd.result=0x01;
- return RETURN_RESULT;
- }
-
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK && err != X25RES_NOT_READY)
- x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn);
-
- if (mbox->cmd.result == X25RES_NOT_READY){
- return TRY_CMD_AGAIN;
- }
-
- switch (mbox->cmd.command){
-
- case X25_PLACE_CALL:
-
- switch (mbox->cmd.result){
-
- case CMD_OK:
-
- /* Check if Place call is a wait command or a
- * no wait command */
- if (atomic_read(&chan->common.command) & 0x80)
- delay=RETURN_RESULT;
- else
- delay=DELAY_RESULT;
-
-
- DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n",
- card->devname,dev->name, mbox->cmd.lcn);
-
- bind_lcn_to_dev (card, dev, mbox->cmd.lcn);
- set_chan_state(dev, WAN_CONNECTING);
- break;
-
-
- default:
- delay=RETURN_RESULT;
- set_chan_state(dev, WAN_DISCONNECTED);
- break;
- }
- break;
-
- case X25_ACCEPT_CALL:
-
- switch (mbox->cmd.result){
-
- case CMD_OK:
-
- DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n",
- card->devname,dev->name,mbox->cmd.lcn);
-
- bind_lcn_to_dev (card, dev, mbox->cmd.lcn);
-
- if (x25_get_chan_conf(card, chan) == CMD_OK){
-
- set_chan_state(dev, WAN_CONNECTED);
- delay=RETURN_RESULT;
-
- }else{
- if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){
- /* if clear is successful, wait for clear confirm
- */
- delay=DELAY_RESULT;
- }else{
- /* Do not change the state here. If we fail
- * the accept the return code is send up
- *the stack, which will ether retry
- * or clear the call
- */
- DBG_PRINTK(KERN_INFO
- "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n",
- card->devname);
- delay=RETURN_RESULT;
- }
- }
- break;
-
-
- case X25RES_ASYNC_PACKET:
- delay=TRY_CMD_AGAIN;
- break;
-
- default:
- DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname);
- if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){
- delay=DELAY_RESULT;
- }else{
- /* Do not change the state here. If we fail the accept. The
- * return code is send up the stack, which will ether retry
- * or clear the call */
- DBG_PRINTK(KERN_INFO
- "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n",
- card->devname);
- delay=RETURN_RESULT;
- }
- }
- break;
-
- case X25_CLEAR_CALL:
-
- switch (mbox->cmd.result){
-
- case CMD_OK:
- DBG_PRINTK(KERN_INFO
- "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n",
- dev->name,mbox->cmd.lcn,chan->common.lcn);
- set_chan_state(dev, WAN_DISCONNECTING);
- delay = DELAY_RESULT;
- break;
-
- case X25RES_CHANNEL_IN_USE:
- case X25RES_ASYNC_PACKET:
- delay = TRY_CMD_AGAIN;
- break;
-
- case X25RES_LINK_NOT_IN_ABM:
- case X25RES_INVAL_LCN:
- case X25RES_INVAL_STATE:
- set_chan_state(dev, WAN_DISCONNECTED);
- delay = RETURN_RESULT;
- break;
-
- default:
- /* If command did not execute because of user
- * fault, do not change the state. This will
- * signal the socket that clear command failed.
- * User can retry or close the socket.
- * When socket gets killed, it will set the
- * chan->disconnect which will signal
- * driver to clear the call */
- printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n",
- card->devname,mbox->cmd.command);
- delay = RETURN_RESULT;
- }
- break;
- }
-
- return delay;
-}
-
-/*===============================================================
- * api_incoming_call
- *
- * Pass an incoming call request up the listening
- * sock. If the API sock is not listening reject the
- * call.
- *
- *===============================================================*/
-
-static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn)
-{
- struct sk_buff *skb;
- int len = sizeof(TX25Cmd)+mbox->cmd.length;
-
- if (alloc_and_init_skb_buf(card, &skb, len)){
- printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname);
- return 1;
- }
-
- memcpy(skb_put(skb,len),&mbox->cmd,len);
-
- skb->mac.raw = skb->data;
- skb->protocol = htons(X25_PROT);
- skb->pkt_type = WAN_PACKET_ASYNC;
-
- if (card->func(skb,card->sk) < 0){
- printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname);
- dev_kfree_skb_any(skb);
- return 1;
- }
-
- return 0;
-}
-
-/*===============================================================
- * send_delayed_cmd_result
- *
- * Wait commands like PLEACE CALL or CLEAR CALL must wait
- * until the result arrives. This function passes
- * the result to a waiting sock.
- *
- *===============================================================*/
-static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev,
- TX25Mbox* mbox)
-{
- x25_channel_t *chan = dev->priv;
- mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox;
- struct sk_buff *skb;
- int len=sizeof(unsigned char);
-
- atomic_set(&chan->common.command,0);
-
- /* If the sock is in the process of unlinking the
- * driver from the socket, we must get out.
- * This never happends but is a sanity check. */
- if (test_bit(0,&chan->common.common_critical)){
- return;
- }
-
- if (!usr_cmd || !chan->common.sk || !chan->common.func){
- DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n",
- (unsigned int)chan->common.sk,
- (unsigned int)chan->common.func,
- (unsigned int)usr_cmd);
- return;
- }
-
- memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd));
- if (mbox->cmd.length > 0){
- memcpy(usr_cmd->data, mbox->data, mbox->cmd.length);
- }
-
- if (alloc_and_init_skb_buf(card,&skb,len)){
- printk(KERN_INFO "Delay result: No sock buffers\n");
- return;
- }
-
- memcpy(skb_put(skb,len),&mbox->cmd.command,len);
-
- skb->mac.raw = skb->data;
- skb->pkt_type = WAN_PACKET_CMD;
-
- chan->common.func(skb,dev,chan->common.sk);
-}
-
-/*===============================================================
- * clear_confirm_event
- *
- * Pass the clear confirmation event up the sock. The
- * API will disconnect only after the clear confirmation
- * has been received.
- *
- * Depending on the state, clear confirmation could
- * be an OOB event, or a result of an API command.
- *===============================================================*/
-
-static int clear_confirm_event (sdla_t *card, TX25Mbox* mb)
-{
- struct net_device *dev;
- x25_channel_t *chan;
- unsigned char old_state;
-
- dev = find_channel(card,mb->cmd.lcn);
- if (!dev){
- DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n",
- card->devname,mb->cmd.lcn);
- return 0;
- }
-
- chan=dev->priv;
- DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n",
- card->devname, dev->name, mb->cmd.lcn, chan->common.lcn);
-
- /* If not API fall through to default.
- * If API, send the result to a waiting
- * socket.
- */
-
- old_state = chan->common.state;
- set_chan_state(dev, WAN_DISCONNECTED);
-
- if (chan->common.usedby == API){
- switch (old_state) {
-
- case WAN_DISCONNECTING:
- case WAN_CONNECTING:
- send_delayed_cmd_result(card,dev,mb);
- break;
- case WAN_CONNECTED:
- send_oob_msg(card,dev,mb);
- break;
- }
- return 1;
- }
-
- return 0;
-}
-
-/*===============================================================
- * send_oob_msg
- *
- * Construct an NEM Message and pass it up the connected
- * sock. If the sock is not bounded discard the NEM.
- *
- *===============================================================*/
-
-static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox)
-{
- x25_channel_t *chan = dev->priv;
- mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox;
- struct sk_buff *skb;
- int len=sizeof(x25api_hdr_t)+mbox->cmd.length;
- x25api_t *api_hdr;
-
- /* If the sock is in the process of unlinking the
- * driver from the socket, we must get out.
- * This never happends but is a sanity check. */
- if (test_bit(0,&chan->common.common_critical)){
- return;
- }
-
- if (!usr_cmd || !chan->common.sk || !chan->common.func){
- DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n");
- return;
- }
-
- memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd));
- if (mbox->cmd.length > 0){
- memcpy(usr_cmd->data, mbox->data, mbox->cmd.length);
- }
-
- if (alloc_and_init_skb_buf(card,&skb,len)){
- printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname);
- return;
- }
-
- api_hdr = (x25api_t*)skb_put(skb,len);
- api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F;
- api_hdr->hdr.qdm = mbox->cmd.qdm;
- api_hdr->hdr.cause = mbox->cmd.cause;
- api_hdr->hdr.diagn = mbox->cmd.diagn;
- api_hdr->hdr.length = mbox->cmd.length;
- api_hdr->hdr.result = mbox->cmd.result;
- api_hdr->hdr.lcn = mbox->cmd.lcn;
-
- if (mbox->cmd.length > 0){
- memcpy(api_hdr->data,mbox->data,mbox->cmd.length);
- }
-
- skb->mac.raw = skb->data;
- skb->pkt_type = WAN_PACKET_ERR;
-
- if (chan->common.func(skb,dev,chan->common.sk) < 0){
- if (bh_enqueue(dev,skb)){
- printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname);
- dev_kfree_skb_any(skb);
- }
- }
-
- DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n",
- card->devname, dev->name, mbox->cmd.lcn);
-}
-
-/*===============================================================
- * alloc_and_init_skb_buf
- *
- * Allocate and initialize an skb buffer.
- *
- *===============================================================*/
-
-static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len)
-{
- struct sk_buff *new_skb = *skb;
-
- new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ);
- if (new_skb == NULL){
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- return 1;
- }
-
- if (skb_tailroom(new_skb) < len){
- /* No room for the packet. Call off the whole thing! */
- dev_kfree_skb_any(new_skb);
- printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n"
- ,card->devname);
- *skb = NULL;
- return 1;
- }
-
- *skb = new_skb;
- return 0;
-
-}
-
-/*===============================================================
- * api_oob_event
- *
- * Send an OOB event up to the sock
- *
- *===============================================================*/
-
-static void api_oob_event (sdla_t *card,TX25Mbox *mbox)
-{
- struct net_device *dev = find_channel(card, mbox->cmd.lcn);
- x25_channel_t *chan;
-
- if (!dev)
- return;
-
- chan=dev->priv;
-
- if (chan->common.usedby == API)
- send_oob_msg(card,dev,mbox);
-
-}
-
-
-
-
-static int channel_disconnect(sdla_t* card, struct net_device *dev)
-{
-
- int err;
- x25_channel_t *chan = dev->priv;
-
- DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n",
- card->devname,dev->name);
-
- if (chan->common.svc){
- err = x25_clear_call(card,chan->common.lcn,0,0);
- }else{
- /* If channel is PVC or LAPB HDLC, there is no call
- * to be cleared, thus drop down to the default
- * area
- */
- err = 1;
- }
-
- switch (err){
-
- case X25RES_CHANNEL_IN_USE:
- case X25RES_NOT_READY:
- err = TRY_CMD_AGAIN;
- break;
- case CMD_OK:
- DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n",
- dev->name,chan->common.lcn);
-
- set_chan_state(dev,WAN_DISCONNECTING);
- atomic_set(&chan->common.command,0);
- err = DELAY_RESULT;
- break;
- default:
- /* If LAPB HDLC protocol, bring the whole link down
- * once the application terminates
- */
-
- set_chan_state(dev,WAN_DISCONNECTED);
-
- if (card->u.x.LAPB_hdlc){
- DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n");
- hdlc_link_down (card);
- }
- atomic_set(&chan->common.command,0);
- err = RETURN_RESULT;
- break;
- }
-
- return err;
-}
-
-static void hdlc_link_down (sdla_t *card)
-{
- TX25Mbox* mbox = card->mbox;
- int retry = 5;
- int err=0;
-
- do {
- memset(mbox,0,sizeof(TX25Mbox));
- mbox->cmd.command = X25_HDLC_LINK_DISC;
- mbox->cmd.length = 1;
- mbox->data[0]=0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0));
-
- if (err)
- printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err);
-
- disconnect (card);
-
-}
-
-static int check_bad_command(sdla_t* card, struct net_device *dev)
-{
- x25_channel_t *chan = dev->priv;
- int bad_cmd = 0;
-
- switch (atomic_read(&chan->common.command)&0x7F){
-
- case X25_PLACE_CALL:
- if (chan->common.state != WAN_DISCONNECTED)
- bad_cmd=1;
- break;
- case X25_CLEAR_CALL:
- if (chan->common.state == WAN_DISCONNECTED)
- bad_cmd=1;
- break;
- case X25_ACCEPT_CALL:
- if (chan->common.state != WAN_CONNECTING)
- bad_cmd=1;
- break;
- case X25_RESET:
- if (chan->common.state != WAN_CONNECTED)
- bad_cmd=1;
- break;
- default:
- bad_cmd=1;
- break;
- }
-
- if (bad_cmd){
- printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n",
- card->devname,atomic_read(&chan->common.command),dev->name,
- chan->common.lcn, chan->common.state);
- }
-
- return bad_cmd;
-}
-
-
-
-/*************************** XPIPEMON FUNCTIONS **************************/
-
-/*==============================================================================
- * Process UDP call of type XPIPE
- */
-
-static int process_udp_mgmt_pkt(sdla_t *card)
-{
- int c_retry = MAX_CMD_RETRY;
- unsigned int len;
- struct sk_buff *new_skb;
- TX25Mbox *mbox = card->mbox;
- int err;
- int udp_mgmt_req_valid = 1;
- struct net_device *dev;
- x25_channel_t *chan;
- unsigned short lcn;
- struct timeval tv;
-
-
- x25_udp_pkt_t *x25_udp_pkt;
- x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data;
-
- dev = card->u.x.udp_dev;
- chan = dev->priv;
- lcn = chan->common.lcn;
-
- switch(x25_udp_pkt->cblock.command) {
-
- /* XPIPE_ENABLE_TRACE */
- case XPIPE_ENABLE_TRACING:
-
- /* XPIPE_GET_TRACE_INFO */
- case XPIPE_GET_TRACE_INFO:
-
- /* SET FT1 MODE */
- case XPIPE_SET_FT1_MODE:
-
- if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err;
- udp_mgmt_req_valid = 0;
- break;
- }
-
- /* XPIPE_FT1_READ_STATUS */
- case XPIPE_FT1_READ_STATUS:
-
- /* FT1 MONITOR STATUS */
- case XPIPE_FT1_STATUS_CTRL:
- if(card->hw.fwid != SFID_X25_508) {
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err;
- udp_mgmt_req_valid = 0;
- break;
- }
- default:
- break;
- }
-
- if(!udp_mgmt_req_valid) {
- /* set length to 0 */
- x25_udp_pkt->cblock.length = 0;
- /* set return code */
- x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD;
-
- } else {
-
- switch (x25_udp_pkt->cblock.command) {
-
-
- case XPIPE_FLUSH_DRIVER_STATS:
- init_x25_channel_struct(chan);
- init_global_statistics(card);
- mbox->cmd.length = 0;
- break;
-
-
- case XPIPE_DRIVER_STAT_IFSEND:
- memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t));
- mbox->cmd.length = sizeof(if_send_stat_t);
- x25_udp_pkt->cblock.length = mbox->cmd.length;
- break;
-
- case XPIPE_DRIVER_STAT_INTR:
- memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t));
- memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)],
- &chan->rx_intr_stat, sizeof(rx_intr_stat_t));
-
- mbox->cmd.length = sizeof(global_stats_t) +
- sizeof(rx_intr_stat_t);
- x25_udp_pkt->cblock.length = mbox->cmd.length;
- break;
-
- case XPIPE_DRIVER_STAT_GEN:
- memcpy(x25_udp_pkt->data,
- &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,
- sizeof(pipe_mgmt_stat_t));
-
- memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
- &card->statistics, sizeof(global_stats_t));
-
- x25_udp_pkt->cblock.result = 0;
- x25_udp_pkt->cblock.length = sizeof(global_stats_t)+
- sizeof(rx_intr_stat_t);
- mbox->cmd.length = x25_udp_pkt->cblock.length;
- break;
-
- case XPIPE_ROUTER_UP_TIME:
- do_gettimeofday(&tv);
- chan->router_up_time = tv.tv_sec - chan->router_start_time;
- *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time;
- x25_udp_pkt->cblock.length = mbox->cmd.length = 4;
- x25_udp_pkt->cblock.result = 0;
- break;
-
- default :
-
- do {
- memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd));
- if(mbox->cmd.length){
- memcpy(&mbox->data,
- (char *)x25_udp_pkt->data,
- mbox->cmd.length);
- }
-
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0));
-
-
- if ( err == CMD_OK ||
- (err == 1 &&
- (mbox->cmd.command == 0x06 ||
- mbox->cmd.command == 0x16) ) ){
-
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK;
- } else {
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout;
- }
-
- /* copy the result back to our buffer */
- memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd));
-
- if(mbox->cmd.length) {
- memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length);
- }
- break;
-
- } //switch
-
- }
-
- /* Fill UDP TTL */
-
- x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
- len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length);
-
-
- if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data);
- if (!err)
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed;
- else
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed;
-
- } else {
-
- /* Allocate socket buffer */
- if((new_skb = dev_alloc_skb(len)) != NULL) {
- void *buf;
-
- /* copy data into new_skb */
- buf = skb_put(new_skb, len);
- memcpy(buf, card->u.x.udp_pkt_data, len);
-
- /* Decapsulate packet and pass it up the protocol
- stack */
- new_skb->dev = dev;
-
- if (chan->common.usedby == API)
- new_skb->protocol = htons(X25_PROT);
- else
- new_skb->protocol = htons(ETH_P_IP);
-
- new_skb->mac.raw = new_skb->data;
-
- netif_rx(new_skb);
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack;
-
- } else {
- ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket;
- printk(KERN_INFO
- "%s: UDP mgmt cmnd, no socket buffers available!\n",
- card->devname);
- }
- }
-
- card->u.x.udp_pkt_lgth = 0;
-
- return 1;
-}
-
-
-/*==============================================================================
- * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ?
- */
-static int udp_pkt_type( struct sk_buff *skb, sdla_t* card )
-{
- x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data;
-
- if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
- (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
- (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
- (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
-
- if(!strncmp(x25_udp_pkt->wp_mgmt.signature,
- UDPMGMT_XPIPE_SIGNATURE, 8)){
- return UDP_XPIPE_TYPE;
- }else{
- printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n",
- card->devname);
- }
- }
-
- return UDP_INVALID_TYPE;
-}
-
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return nothing.
- */
-static int reply_udp( unsigned char *data, unsigned int mbox_len )
-{
- unsigned short len, udp_length, temp, ip_length;
- unsigned long ip_temp;
- int even_bound = 0;
-
-
- x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data;
-
- /* Set length of packet */
- len = sizeof(ip_pkt_t)+
- sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
-
- /* fill in UDP reply */
- x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
-
- /* fill in UDP length */
- udp_length = sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- mbox_len;
-
-
- /* put it on an even boundary */
- if ( udp_length & 0x0001 ) {
- udp_length += 1;
- len += 1;
- even_bound = 1;
- }
-
- temp = (udp_length<<8)|(udp_length>>8);
- x25_udp_pkt->udp_pkt.udp_length = temp;
-
- /* swap UDP ports */
- temp = x25_udp_pkt->udp_pkt.udp_src_port;
- x25_udp_pkt->udp_pkt.udp_src_port =
- x25_udp_pkt->udp_pkt.udp_dst_port;
- x25_udp_pkt->udp_pkt.udp_dst_port = temp;
-
-
-
- /* add UDP pseudo header */
- temp = 0x1100;
- *((unsigned short *)
- (x25_udp_pkt->data+mbox_len+even_bound)) = temp;
- temp = (udp_length<<8)|(udp_length>>8);
- *((unsigned short *)
- (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp;
-
- /* calculate UDP checksum */
- x25_udp_pkt->udp_pkt.udp_checksum = 0;
-
- x25_udp_pkt->udp_pkt.udp_checksum =
- calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET);
-
- /* fill in IP length */
- ip_length = len;
- temp = (ip_length<<8)|(ip_length>>8);
- x25_udp_pkt->ip_pkt.total_length = temp;
-
- /* swap IP addresses */
- ip_temp = x25_udp_pkt->ip_pkt.ip_src_address;
- x25_udp_pkt->ip_pkt.ip_src_address =
- x25_udp_pkt->ip_pkt.ip_dst_address;
- x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
-
-
- /* fill in IP checksum */
- x25_udp_pkt->ip_pkt.hdr_checksum = 0;
- x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t));
-
- return len;
-} /* reply_udp */
-
-unsigned short calc_checksum (char *data, int len)
-{
- unsigned short temp;
- unsigned long sum=0;
- int i;
-
- for( i = 0; i <len; i+=2 ) {
- memcpy(&temp,&data[i],2);
- sum += (unsigned long)temp;
- }
-
- while (sum >> 16 ) {
- sum = (sum & 0xffffUL) + (sum >> 16);
- }
-
- temp = (unsigned short)sum;
- temp = ~temp;
-
- if( temp == 0 )
- temp = 0xffff;
-
- return temp;
-}
-
-/*=============================================================================
- * Store a UDP management packet for later processing.
- */
-
-static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
- struct net_device *dev, struct sk_buff *skb,
- int lcn)
-{
- int udp_pkt_stored = 0;
-
- if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
- card->u.x.udp_pkt_lgth = skb->len;
- card->u.x.udp_type = udp_type;
- card->u.x.udp_pkt_src = udp_pkt_src;
- card->u.x.udp_lcn = lcn;
- card->u.x.udp_dev = dev;
- memcpy(card->u.x.udp_pkt_data, skb->data, skb->len);
- card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT;
- udp_pkt_stored = 1;
-
- }else{
- printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n",
- card->devname,lcn);
- }
-
- if(udp_pkt_src == UDP_PKT_FRM_STACK){
- dev_kfree_skb_any(skb);
- }else{
- dev_kfree_skb_any(skb);
- }
-
- return(udp_pkt_stored);
-}
-
-
-
-/*=============================================================================
- * Initial the ppp_private_area structure.
- */
-static void init_x25_channel_struct( x25_channel_t *chan )
-{
- memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t));
- memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t));
- memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t));
-}
-
-/*============================================================================
- * Initialize Global Statistics
- */
-static void init_global_statistics( sdla_t *card )
-{
- memset(&card->statistics.isr_entry,0,sizeof(global_stats_t));
-}
-
-
-/*===============================================================
- * SMP Support
- * ==============================================================*/
-
-static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags)
-{
- spin_lock_irqsave(&card->wandev.lock, *smp_flags);
-}
-static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags)
-{
- spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
-}
-
-/*===============================================================
- * x25_timer_routine
- *
- * A more efficient polling routine. Each half a second
- * queue a polling task. We want to do the polling in a
- * task not timer, because timer runs in interrupt time.
- *
- * FIXME Polling should be rethinked.
- *==============================================================*/
-
-static void x25_timer_routine(unsigned long data)
-{
- sdla_t *card = (sdla_t*)data;
-
- if (!card->wandev.dev){
- printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n",
- card->devname);
- return;
- }
-
- if (card->open_cnt != card->u.x.num_of_ch){
- printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n",
- card->devname);
- return;
- }
-
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n",
- card->devname);
- return;
- }
-
- if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){
- trigger_x25_poll(card);
- }
-
- card->u.x.x25_timer.expires=jiffies+(HZ>>1);
- add_timer(&card->u.x.x25_timer);
- return;
-}
-
-void disable_comm_shutdown(sdla_t *card)
-{
- TX25Mbox* mbox = card->mbox;
- int err;
-
- /* Turn of interrutps */
- mbox->data[0] = 0;
- if (card->hw.fwid == SFID_X25_508){
- mbox->data[1] = card->hw.irq;
- mbox->data[2] = 2;
- mbox->cmd.length = 3;
- }else {
- mbox->cmd.length = 1;
- }
- mbox->cmd.command = X25_SET_INTERRUPT_MODE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err)
- printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err);
-
- /* Bring down HDLC */
- mbox->cmd.command = X25_HDLC_LINK_CLOSE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err)
- printk(KERN_INFO "LINK CLOSED FAILED %x\n",err);
-
-
- /* Brind down DTR */
- mbox->data[0] = 0;
- mbox->data[2] = 0;
- mbox->data[1] = 0x01;
- mbox->cmd.length = 3;
- mbox->cmd.command = X25_SET_GLOBAL_VARS;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err)
- printk(KERN_INFO "DTR DOWN FAILED %x\n",err);
-
-}
-
-MODULE_LICENSE("GPL");
-
-/****** End *****************************************************************/
diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c
deleted file mode 100644
index 032c0f81928e..000000000000
--- a/drivers/net/wan/sdladrv.c
+++ /dev/null
@@ -1,2314 +0,0 @@
-/*****************************************************************************
-* sdladrv.c SDLA Support Module. Main module.
-*
-* This module is a library of common hardware-specific functions
-* used by all Sangoma drivers.
-*
-* Author: Gideon Hack
-*
-* Copyright: (c) 1995-2000 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support
-* the PCISLOT #0.
-* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code.
-* The memory test at address 0xC8000.
-* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci
-* interrupt flags on initial load.
-* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
-* Updates for Linux 2.2.X kernels.
-* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels
-* Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul.
-* Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility.
-* Jun 12, 1996 Gene Kozin Added support for S503 card.
-* Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before
-* calling protocolspecific ISR.
-* Register I/O ports with Linux kernel.
-* Miscellaneous bug fixes.
-* Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine.
-* Oct 14, 1995 Gene Kozin Initial version.
-*****************************************************************************/
-
-/*****************************************************************************
- * Notes:
- * ------
- * 1. This code is ment to be system-independent (as much as possible). To
- * achive this, various macros are used to hide system-specific interfaces.
- * To compile this code, one of the following constants must be defined:
- *
- * Platform Define
- * -------- ------
- * Linux _LINUX_
- * SCO Unix _SCO_UNIX_
- *
- * 2. Supported adapter types:
- *
- * S502A
- * ES502A (S502E)
- * S503
- * S507
- * S508 (S509)
- *
- * 3. S502A Notes:
- *
- * There is no separate DPM window enable/disable control in S502A. It
- * opens immediately after a window number it written to the HMCR
- * register. To close the window, HMCR has to be written a value
- * ????1111b (e.g. 0x0F or 0xFF).
- *
- * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000).
- *
- * There should be a delay of ??? before reading back S502A status
- * register.
- *
- * 4. S502E Notes:
- *
- * S502E has a h/w bug: although default IRQ line state is HIGH, enabling
- * interrupts by setting bit 1 of the control register (BASE) to '1'
- * causes it to go LOW! Therefore, disabling interrupts by setting that
- * bit to '0' causes low-to-high transition on IRQ line (ghosty
- * interrupt). The same occurs when disabling CPU by resetting bit 0 of
- * CPU control register (BASE+3) - see the next note.
- *
- * S502E CPU and DPM control is limited:
- *
- * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi
- * control register (BASE+3) shuts the board down entirely, including
- * DPM;
- *
- * o DPM access cannot be controlled dynamically. Ones CPU is started,
- * bit 1 of the control register (BASE) is used to enable/disable IRQ,
- * so that access to shared memory cannot be disabled while CPU is
- * running.
- ****************************************************************************/
-
-#define _LINUX_
-
-#if defined(_LINUX_) /****** Linux *******************************/
-
-#include <linux/config.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/module.h> /* support for loadable modules */
-#include <linux/jiffies.h> /* for jiffies, HZ, etc. */
-#include <linux/sdladrv.h> /* API definitions */
-#include <linux/sdlasfm.h> /* SDLA firmware module definitions */
-#include <linux/sdlapci.h> /* SDLA PCI hardware definitions */
-#include <linux/pci.h> /* PCI defines and function prototypes */
-#include <asm/io.h> /* for inb(), outb(), etc. */
-
-#define _INB(port) (inb(port))
-#define _OUTB(port, byte) (outb((byte),(port)))
-#define SYSTEM_TICK jiffies
-
-#include <linux/init.h>
-
-
-#elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/
-
-#if !defined(INKERNEL)
-#error This code MUST be compiled in kernel mode!
-#endif
-#include <sys/sdladrv.h> /* API definitions */
-#include <sys/sdlasfm.h> /* SDLA firmware module definitions */
-#include <sys/inline.h> /* for inb(), outb(), etc. */
-#define _INB(port) (inb(port))
-#define _OUTB(port, byte) (outb((port),(byte)))
-#define SYSTEM_TICK lbolt
-
-#else
-#error Unknown system type!
-#endif
-
-#define MOD_VERSION 3
-#define MOD_RELEASE 0
-
-#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */
-#define EXEC_DELAY 20 /* shared memory access delay, mks */
-#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */
-
-/* I/O port address range */
-#define S502A_IORANGE 3
-#define S502E_IORANGE 4
-#define S503_IORANGE 3
-#define S507_IORANGE 4
-#define S508_IORANGE 4
-
-/* Maximum amount of memory */
-#define S502_MAXMEM 0x10000L
-#define S503_MAXMEM 0x10000L
-#define S507_MAXMEM 0x40000L
-#define S508_MAXMEM 0x40000L
-
-/* Minimum amount of memory */
-#define S502_MINMEM 0x8000L
-#define S503_MINMEM 0x8000L
-#define S507_MINMEM 0x20000L
-#define S508_MINMEM 0x20000L
-#define NO_PORT -1
-
-
-
-
-
-/****** Function Prototypes *************************************************/
-
-/* Hardware-specific functions */
-static int sdla_detect (sdlahw_t* hw);
-static int sdla_autodpm (sdlahw_t* hw);
-static int sdla_setdpm (sdlahw_t* hw);
-static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len);
-static int sdla_init (sdlahw_t* hw);
-static unsigned long sdla_memtest (sdlahw_t* hw);
-static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo);
-static unsigned char make_config_byte (sdlahw_t* hw);
-static int sdla_start (sdlahw_t* hw, unsigned addr);
-
-static int init_s502a (sdlahw_t* hw);
-static int init_s502e (sdlahw_t* hw);
-static int init_s503 (sdlahw_t* hw);
-static int init_s507 (sdlahw_t* hw);
-static int init_s508 (sdlahw_t* hw);
-
-static int detect_s502a (int port);
-static int detect_s502e (int port);
-static int detect_s503 (int port);
-static int detect_s507 (int port);
-static int detect_s508 (int port);
-static int detect_s514 (sdlahw_t* hw);
-static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card);
-
-/* Miscellaneous functions */
-static void peek_by_4 (unsigned long src, void* buf, unsigned len);
-static void poke_by_4 (unsigned long dest, void* buf, unsigned len);
-static int calibrate_delay (int mks);
-static int get_option_index (unsigned* optlist, unsigned optval);
-static unsigned check_memregion (void* ptr, unsigned len);
-static unsigned test_memregion (void* ptr, unsigned len);
-static unsigned short checksum (unsigned char* buf, unsigned len);
-static int init_pci_slot(sdlahw_t *);
-
-static int pci_probe(sdlahw_t *hw);
-
-/****** Global Data **********************************************************
- * Note: All data must be explicitly initialized!!!
- */
-
-static struct pci_device_id sdladrv_pci_tbl[] = {
- { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl);
-
-MODULE_LICENSE("GPL");
-
-/* private data */
-static char modname[] = "sdladrv";
-static char fullname[] = "SDLA Support Module";
-static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc.";
-static unsigned exec_idle;
-
-/* Hardware configuration options.
- * These are arrays of configuration options used by verification routines.
- * The first element of each array is its size (i.e. number of options).
- */
-static unsigned s502_port_options[] =
- { 4, 0x250, 0x300, 0x350, 0x360 }
-;
-static unsigned s503_port_options[] =
- { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 }
-;
-static unsigned s508_port_options[] =
- { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 }
-;
-
-static unsigned s502a_irq_options[] = { 0 };
-static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 };
-static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 };
-static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 };
-
-static unsigned s502a_dpmbase_options[] =
-{
- 28,
- 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000,
- 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000,
- 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000,
- 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000,
-};
-static unsigned s507_dpmbase_options[] =
-{
- 32,
- 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
- 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
- 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
- 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
-};
-static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */
-{
- 32,
- 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
- 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
- 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000,
- 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000,
-};
-
-/*
-static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 };
-static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 };
-static unsigned s508_dpmsize_options[] = { 1, 0x2000 };
-*/
-
-static unsigned s502a_pclk_options[] = { 2, 3600, 7200 };
-static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 };
-static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 };
-static unsigned s507_pclk_options[] = { 1, 12288 };
-static unsigned s508_pclk_options[] = { 1, 16000 };
-
-/* Host memory control register masks */
-static unsigned char s502a_hmcr[] =
-{
- 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */
- 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */
- 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */
- 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */
-};
-static unsigned char s502e_hmcr[] =
-{
- 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */
- 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */
- 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */
- 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */
-};
-static unsigned char s507_hmcr[] =
-{
- 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */
- 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */
- 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */
- 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */
-};
-static unsigned char s508_hmcr[] =
-{
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */
-};
-
-static unsigned char s507_irqmask[] =
-{
- 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
-};
-
-static int pci_slot_ar[MAX_S514_CARDS];
-
-/******* Kernel Loadable Module Entry Points ********************************/
-
-/*============================================================================
- * Module 'insert' entry point.
- * o print announcement
- * o initialize static data
- * o calibrate SDLA shared memory access delay.
- *
- * Return: 0 Ok
- * < 0 error.
- * Context: process
- */
-
-static int __init sdladrv_init(void)
-{
- int i=0;
-
- printk(KERN_INFO "%s v%u.%u %s\n",
- fullname, MOD_VERSION, MOD_RELEASE, copyright);
- exec_idle = calibrate_delay(EXEC_DELAY);
-#ifdef WANDEBUG
- printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
-#endif
-
- /* Initialize the PCI Card array, which
- * will store flags, used to mark
- * card initialization state */
- for (i=0; i<MAX_S514_CARDS; i++)
- pci_slot_ar[i] = 0xFF;
-
- return 0;
-}
-
-/*============================================================================
- * Module 'remove' entry point.
- * o release all remaining system resources
- */
-static void __exit sdladrv_cleanup(void)
-{
-}
-
-module_init(sdladrv_init);
-module_exit(sdladrv_cleanup);
-
-/******* Kernel APIs ********************************************************/
-
-/*============================================================================
- * Set up adapter.
- * o detect adapter type
- * o verify hardware configuration options
- * o check for hardware conflicts
- * o set up adapter shared memory
- * o test adapter memory
- * o load firmware
- * Return: 0 ok.
- * < 0 error
- */
-
-EXPORT_SYMBOL(sdla_setup);
-
-int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
-{
- unsigned* irq_opt = NULL; /* IRQ options */
- unsigned* dpmbase_opt = NULL; /* DPM window base options */
- unsigned* pclk_opt = NULL; /* CPU clock rate options */
- int err=0;
-
- if (sdla_detect(hw)) {
- if(hw->type != SDLA_S514)
- printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n",
- modname, hw->port);
- return -EINVAL;
- }
-
- if(hw->type != SDLA_S514) {
- printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n",
- modname, hw->type, hw->port);
-
- hw->dpmsize = SDLA_WINDOWSIZE;
- switch (hw->type) {
- case SDLA_S502A:
- hw->io_range = S502A_IORANGE;
- irq_opt = s502a_irq_options;
- dpmbase_opt = s502a_dpmbase_options;
- pclk_opt = s502a_pclk_options;
- break;
-
- case SDLA_S502E:
- hw->io_range = S502E_IORANGE;
- irq_opt = s502e_irq_options;
- dpmbase_opt = s508_dpmbase_options;
- pclk_opt = s502e_pclk_options;
- break;
-
- case SDLA_S503:
- hw->io_range = S503_IORANGE;
- irq_opt = s503_irq_options;
- dpmbase_opt = s508_dpmbase_options;
- pclk_opt = s503_pclk_options;
- break;
-
- case SDLA_S507:
- hw->io_range = S507_IORANGE;
- irq_opt = s508_irq_options;
- dpmbase_opt = s507_dpmbase_options;
- pclk_opt = s507_pclk_options;
- break;
-
- case SDLA_S508:
- hw->io_range = S508_IORANGE;
- irq_opt = s508_irq_options;
- dpmbase_opt = s508_dpmbase_options;
- pclk_opt = s508_pclk_options;
- break;
- }
-
- /* Verify IRQ configuration options */
- if (!get_option_index(irq_opt, hw->irq)) {
- printk(KERN_INFO "%s: IRQ %d is invalid!\n",
- modname, hw->irq);
- return -EINVAL;
- }
-
- /* Verify CPU clock rate configuration options */
- if (hw->pclk == 0)
- hw->pclk = pclk_opt[1]; /* use default */
-
- else if (!get_option_index(pclk_opt, hw->pclk)) {
- printk(KERN_INFO "%s: CPU clock %u is invalid!\n",
- modname, hw->pclk);
- return -EINVAL;
- }
- printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n",
- modname, hw->pclk);
-
- /* Setup adapter dual-port memory window and test memory */
- if (hw->dpmbase == 0) {
- err = sdla_autodpm(hw);
- if (err) {
- printk(KERN_INFO
- "%s: can't find available memory region!\n",
- modname);
- return err;
- }
- }
- else if (!get_option_index(dpmbase_opt,
- virt_to_phys(hw->dpmbase))) {
- printk(KERN_INFO
- "%s: memory address 0x%lX is invalid!\n",
- modname, virt_to_phys(hw->dpmbase));
- return -EINVAL;
- }
- else if (sdla_setdpm(hw)) {
- printk(KERN_INFO
- "%s: 8K memory region at 0x%lX is not available!\n",
- modname, virt_to_phys(hw->dpmbase));
- return -EINVAL;
- }
- printk(KERN_INFO
- "%s: dual-port memory window is set at 0x%lX.\n",
- modname, virt_to_phys(hw->dpmbase));
-
-
- /* If we find memory in 0xE**** Memory region,
- * warn the user to disable the SHADOW RAM.
- * Since memory corruption can occur if SHADOW is
- * enabled. This can causes random crashes ! */
- if (virt_to_phys(hw->dpmbase) >= 0xE0000){
- printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname);
- printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n",
- modname, virt_to_phys(hw->dpmbase));
- printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n");
- printk(KERN_WARNING " your system might crash randomly from time to time !\n");
- printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname);
- }
- }
-
- else {
- hw->memory = test_memregion((void*)hw->dpmbase,
- MAX_SIZEOF_S514_MEMORY);
- if(hw->memory < (256 * 1024)) {
- printk(KERN_INFO
- "%s: error in testing S514 memory (0x%lX)\n",
- modname, hw->memory);
- sdla_down(hw);
- return -EINVAL;
- }
- }
-
- printk(KERN_INFO "%s: found %luK bytes of on-board memory\n",
- modname, hw->memory / 1024);
-
- /* Load firmware. If loader fails then shut down adapter */
- err = sdla_load(hw, sfm, len);
- if (err) sdla_down(hw); /* shutdown adapter */
-
- return err;
-}
-
-/*============================================================================
- * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
- */
-
-EXPORT_SYMBOL(sdla_down);
-
-int sdla_down (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int i;
- unsigned char CPU_no;
- u32 int_config, int_status;
-
- if(!port && (hw->type != SDLA_S514))
- return -EFAULT;
-
- switch (hw->type) {
- case SDLA_S502A:
- _OUTB(port, 0x08); /* halt CPU */
- _OUTB(port, 0x08);
- _OUTB(port, 0x08);
- hw->regs[0] = 0x08;
- _OUTB(port + 1, 0xFF); /* close memory window */
- hw->regs[1] = 0xFF;
- break;
-
- case SDLA_S502E:
- _OUTB(port + 3, 0); /* stop CPU */
- _OUTB(port, 0); /* reset board */
- for (i = 0; i < S502E_IORANGE; ++i)
- hw->regs[i] = 0
- ;
- break;
-
- case SDLA_S503:
- case SDLA_S507:
- case SDLA_S508:
- _OUTB(port, 0); /* reset board logic */
- hw->regs[0] = 0;
- break;
-
- case SDLA_S514:
- /* halt the adapter */
- *(char *)hw->vector = S514_CPU_HALT;
- CPU_no = hw->S514_cpu_no[0];
-
- /* disable the PCI IRQ and disable memory access */
- pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config);
- int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B;
- pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config);
- read_S514_int_stat(hw, &int_status);
- S514_intack(hw, int_status);
- if(CPU_no == S514_CPU_A)
- pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD,
- PCI_CPU_A_MEM_DISABLE);
- else
- pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD,
- PCI_CPU_B_MEM_DISABLE);
-
- /* free up the allocated virtual memory */
- iounmap((void *)hw->dpmbase);
- iounmap((void *)hw->vector);
- break;
-
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/*============================================================================
- * Map shared memory window into SDLA address space.
- */
-
-EXPORT_SYMBOL(sdla_mapmem);
-
-int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
-{
- unsigned port = hw->port;
- register int tmp;
-
- switch (hw->type) {
- case SDLA_S502A:
- case SDLA_S502E:
- if (addr < S502_MAXMEM) { /* verify parameter */
- tmp = addr >> 13; /* convert to register mask */
- _OUTB(port + 2, tmp);
- hw->regs[2] = tmp;
- }
- else return -EINVAL;
- break;
-
- case SDLA_S503:
- if (addr < S503_MAXMEM) { /* verify parameter */
- tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70);
- _OUTB(port, tmp);
- hw->regs[0] = tmp;
- }
- else return -EINVAL;
- break;
-
- case SDLA_S507:
- if (addr < S507_MAXMEM) {
- if (!(_INB(port) & 0x02))
- return -EIO;
- tmp = addr >> 13; /* convert to register mask */
- _OUTB(port + 2, tmp);
- hw->regs[2] = tmp;
- }
- else return -EINVAL;
- break;
-
- case SDLA_S508:
- if (addr < S508_MAXMEM) {
- tmp = addr >> 13; /* convert to register mask */
- _OUTB(port + 2, tmp);
- hw->regs[2] = tmp;
- }
- else return -EINVAL;
- break;
-
- case SDLA_S514:
- return 0;
-
- default:
- return -EINVAL;
- }
- hw->vector = addr & 0xFFFFE000L;
- return 0;
-}
-
-/*============================================================================
- * Enable interrupt generation.
- */
-
-static int sdla_inten (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- switch (hw->type) {
- case SDLA_S502E:
- /* Note thar interrupt control operations on S502E are allowed
- * only if CPU is enabled (bit 0 of status register is set).
- */
- if (_INB(port) & 0x01) {
- _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */
- _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */
- hw->regs[0] = 0x06;
- }
- else return -EIO;
- break;
-
- case SDLA_S503:
- tmp = hw->regs[0] | 0x04;
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (!(_INB(port) & 0x02)) /* verify */
- return -EIO;
- break;
-
- case SDLA_S508:
- tmp = hw->regs[0] | 0x10;
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (!(_INB(port + 1) & 0x10)) /* verify */
- return -EIO;
- break;
-
- case SDLA_S502A:
- case SDLA_S507:
- break;
-
- case SDLA_S514:
- break;
-
- default:
- return -EINVAL;
-
- }
- return 0;
-}
-
-/*============================================================================
- * Disable interrupt generation.
- */
-
-#if 0
-int sdla_intde (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- switch (hw->type) {
- case SDLA_S502E:
- /* Notes:
- * 1) interrupt control operations are allowed only if CPU is
- * enabled (bit 0 of status register is set).
- * 2) disabling interrupts using bit 1 of control register
- * causes IRQ line go high, therefore we are going to use
- * 0x04 instead: lower it to inhibit interrupts to PC.
- */
- if (_INB(port) & 0x01) {
- _OUTB(port, hw->regs[0] & ~0x04);
- hw->regs[0] &= ~0x04;
- }
- else return -EIO;
- break;
-
- case SDLA_S503:
- tmp = hw->regs[0] & ~0x04;
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) & 0x02) /* verify */
- return -EIO;
- break;
-
- case SDLA_S508:
- tmp = hw->regs[0] & ~0x10;
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) & 0x10) /* verify */
- return -EIO;
- break;
-
- case SDLA_S502A:
- case SDLA_S507:
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-#endif /* 0 */
-
-/*============================================================================
- * Acknowledge SDLA hardware interrupt.
- */
-
-static int sdla_intack (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp;
-
- switch (hw->type) {
- case SDLA_S502E:
- /* To acknoledge hardware interrupt we have to toggle bit 3 of
- * control register: \_/
- * Note that interrupt control operations on S502E are allowed
- * only if CPU is enabled (bit 1 of status register is set).
- */
- if (_INB(port) & 0x01) {
- tmp = hw->regs[0] & ~0x04;
- _OUTB(port, tmp);
- tmp |= 0x04;
- _OUTB(port, tmp);
- hw->regs[0] = tmp;
- }
- else return -EIO;
- break;
-
- case SDLA_S503:
- if (_INB(port) & 0x04) {
- tmp = hw->regs[0] & ~0x08;
- _OUTB(port, tmp);
- tmp |= 0x08;
- _OUTB(port, tmp);
- hw->regs[0] = tmp;
- }
- break;
-
- case SDLA_S502A:
- case SDLA_S507:
- case SDLA_S508:
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-
-/*============================================================================
- * Acknowledge S514 hardware interrupt.
- */
-
-EXPORT_SYMBOL(S514_intack);
-
-void S514_intack (sdlahw_t* hw, u32 int_status)
-{
- pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
-}
-
-
-/*============================================================================
- * Read the S514 hardware interrupt status.
- */
-
-EXPORT_SYMBOL(read_S514_int_stat);
-
-void read_S514_int_stat (sdlahw_t* hw, u32* int_status)
-{
- pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
-}
-
-
-/*============================================================================
- * Generate an interrupt to adapter's CPU.
- */
-
-#if 0
-int sdla_intr (sdlahw_t* hw)
-{
- unsigned port = hw->port;
-
- switch (hw->type) {
- case SDLA_S502A:
- if (!(_INB(port) & 0x40)) {
- _OUTB(port, 0x10); /* issue NMI to CPU */
- hw->regs[0] = 0x10;
- }
- else return -EIO;
- break;
-
- case SDLA_S507:
- if ((_INB(port) & 0x06) == 0x06) {
- _OUTB(port + 3, 0);
- }
- else return -EIO;
- break;
-
- case SDLA_S508:
- if (_INB(port + 1) & 0x02) {
- _OUTB(port, 0x08);
- }
- else return -EIO;
- break;
-
- case SDLA_S502E:
- case SDLA_S503:
- default:
- return -EINVAL;
- }
- return 0;
-}
-#endif /* 0 */
-
-/*============================================================================
- * Execute Adapter Command.
- * o Set exec flag.
- * o Busy-wait until flag is reset.
- * o Return number of loops made, or 0 if command timed out.
- */
-
-EXPORT_SYMBOL(sdla_exec);
-
-int sdla_exec (void* opflag)
-{
- volatile unsigned char* flag = opflag;
- unsigned long tstop;
- int nloops;
-
- if(readb(flag) != 0x00) {
- printk(KERN_INFO
- "WANPIPE: opp flag set on entry to sdla_exec\n");
- return 0;
- }
-
- writeb(0x01, flag);
-
- tstop = SYSTEM_TICK + EXEC_TIMEOUT;
-
- for (nloops = 1; (readb(flag) == 0x01); ++ nloops) {
- unsigned delay = exec_idle;
- while (-- delay); /* delay */
- if (SYSTEM_TICK > tstop) return 0; /* time is up! */
- }
- return nloops;
-}
-
-/*============================================================================
- * Read absolute adapter memory.
- * Transfer data from adapter's memory to data buffer.
- *
- * Note:
- * Care should be taken when crossing dual-port memory window boundary.
- * This function is not atomic, so caller must disable interrupt if
- * interrupt routines are accessing adapter shared memory.
- */
-
-EXPORT_SYMBOL(sdla_peek);
-
-int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
-{
-
- if (addr + len > hw->memory) /* verify arguments */
- return -EINVAL;
-
- if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */
- peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len);
- return 0;
- }
-
- else { /* copy data for the S508 adapter */
- unsigned long oldvec = hw->vector;
- unsigned winsize = hw->dpmsize;
- unsigned curpos, curlen; /* current offset and block size */
- unsigned long curvec; /* current DPM window vector */
- int err = 0;
-
- while (len && !err) {
- curpos = addr % winsize; /* current window offset */
- curvec = addr - curpos; /* current window vector */
- curlen = (len > (winsize - curpos)) ?
- (winsize - curpos) : len;
- /* Relocate window and copy block of data */
- err = sdla_mapmem(hw, curvec);
- peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf,
- curlen);
- addr += curlen;
- buf = (char*)buf + curlen;
- len -= curlen;
- }
-
- /* Restore DPM window position */
- sdla_mapmem(hw, oldvec);
- return err;
- }
-}
-
-
-/*============================================================================
- * Read data from adapter's memory to a data buffer in 4-byte chunks.
- * Note that we ensure that the SDLA memory address is on a 4-byte boundary
- * before we begin moving the data in 4-byte chunks.
-*/
-
-static void peek_by_4 (unsigned long src, void* buf, unsigned len)
-{
-
- /* byte copy data until we get to a 4-byte boundary */
- while (len && (src & 0x03)) {
- *(char *)buf ++ = readb(src ++);
- len --;
- }
-
- /* copy data in 4-byte chunks */
- while (len >= 4) {
- *(unsigned long *)buf = readl(src);
- buf += 4;
- src += 4;
- len -= 4;
- }
-
- /* byte copy any remaining data */
- while (len) {
- *(char *)buf ++ = readb(src ++);
- len --;
- }
-}
-
-
-/*============================================================================
- * Write Absolute Adapter Memory.
- * Transfer data from data buffer to adapter's memory.
- *
- * Note:
- * Care should be taken when crossing dual-port memory window boundary.
- * This function is not atomic, so caller must disable interrupt if
- * interrupt routines are accessing adapter shared memory.
- */
-
-EXPORT_SYMBOL(sdla_poke);
-
-int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
-{
-
- if (addr + len > hw->memory) /* verify arguments */
- return -EINVAL;
-
- if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */
- poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len);
- return 0;
- }
-
- else { /* copy data for the S508 adapter */
- unsigned long oldvec = hw->vector;
- unsigned winsize = hw->dpmsize;
- unsigned curpos, curlen; /* current offset and block size */
- unsigned long curvec; /* current DPM window vector */
- int err = 0;
-
- while (len && !err) {
- curpos = addr % winsize; /* current window offset */
- curvec = addr - curpos; /* current window vector */
- curlen = (len > (winsize - curpos)) ?
- (winsize - curpos) : len;
- /* Relocate window and copy block of data */
- sdla_mapmem(hw, curvec);
- poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf,
- curlen);
- addr += curlen;
- buf = (char*)buf + curlen;
- len -= curlen;
- }
-
- /* Restore DPM window position */
- sdla_mapmem(hw, oldvec);
- return err;
- }
-}
-
-
-/*============================================================================
- * Write from a data buffer to adapter's memory in 4-byte chunks.
- * Note that we ensure that the SDLA memory address is on a 4-byte boundary
- * before we begin moving the data in 4-byte chunks.
-*/
-
-static void poke_by_4 (unsigned long dest, void* buf, unsigned len)
-{
-
- /* byte copy data until we get to a 4-byte boundary */
- while (len && (dest & 0x03)) {
- writeb (*(char *)buf ++, dest ++);
- len --;
- }
-
- /* copy data in 4-byte chunks */
- while (len >= 4) {
- writel (*(unsigned long *)buf, dest);
- dest += 4;
- buf += 4;
- len -= 4;
- }
-
- /* byte copy any remaining data */
- while (len) {
- writeb (*(char *)buf ++ , dest ++);
- len --;
- }
-}
-
-
-#ifdef DONT_COMPIPLE_THIS
-#endif /* DONT_COMPIPLE_THIS */
-
-/****** Hardware-Specific Functions *****************************************/
-
-/*============================================================================
- * Detect adapter type.
- * o if adapter type is specified then call detection routine for that adapter
- * type. Otherwise call detection routines for every adapter types until
- * adapter is detected.
- *
- * Notes:
- * 1) Detection tests are destructive! Adapter will be left in shutdown state
- * after the test.
- */
-static int sdla_detect (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int err = 0;
-
- if (!port && (hw->type != SDLA_S514))
- return -EFAULT;
-
- switch (hw->type) {
- case SDLA_S502A:
- if (!detect_s502a(port)) err = -ENODEV;
- break;
-
- case SDLA_S502E:
- if (!detect_s502e(port)) err = -ENODEV;
- break;
-
- case SDLA_S503:
- if (!detect_s503(port)) err = -ENODEV;
- break;
-
- case SDLA_S507:
- if (!detect_s507(port)) err = -ENODEV;
- break;
-
- case SDLA_S508:
- if (!detect_s508(port)) err = -ENODEV;
- break;
-
- case SDLA_S514:
- if (!detect_s514(hw)) err = -ENODEV;
- break;
-
- default:
- if (detect_s502a(port))
- hw->type = SDLA_S502A;
- else if (detect_s502e(port))
- hw->type = SDLA_S502E;
- else if (detect_s503(port))
- hw->type = SDLA_S503;
- else if (detect_s507(port))
- hw->type = SDLA_S507;
- else if (detect_s508(port))
- hw->type = SDLA_S508;
- else err = -ENODEV;
- }
- return err;
-}
-
-/*============================================================================
- * Autoselect memory region.
- * o try all available DMP address options from the top down until success.
- */
-static int sdla_autodpm (sdlahw_t* hw)
-{
- int i, err = -EINVAL;
- unsigned* opt;
-
- switch (hw->type) {
- case SDLA_S502A:
- opt = s502a_dpmbase_options;
- break;
-
- case SDLA_S502E:
- case SDLA_S503:
- case SDLA_S508:
- opt = s508_dpmbase_options;
- break;
-
- case SDLA_S507:
- opt = s507_dpmbase_options;
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Start testing from 8th position, address
- * 0xC8000 from the 508 address table.
- * We don't want to test A**** addresses, since
- * they are usually used for Video */
- for (i = 8; i <= opt[0] && err; i++) {
- hw->dpmbase = phys_to_virt(opt[i]);
- err = sdla_setdpm(hw);
- }
- return err;
-}
-
-/*============================================================================
- * Set up adapter dual-port memory window.
- * o shut down adapter
- * o make sure that no physical memory exists in this region, i.e entire
- * region reads 0xFF and is not writable when adapter is shut down.
- * o initialize adapter hardware
- * o make sure that region is usable with SDLA card, i.e. we can write to it
- * when adapter is configured.
- */
-static int sdla_setdpm (sdlahw_t* hw)
-{
- int err;
-
- /* Shut down card and verify memory region */
- sdla_down(hw);
- if (check_memregion(hw->dpmbase, hw->dpmsize))
- return -EINVAL;
-
- /* Initialize adapter and test on-board memory segment by segment.
- * If memory size appears to be less than shared memory window size,
- * assume that memory region is unusable.
- */
- err = sdla_init(hw);
- if (err) return err;
-
- if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */
- sdla_down(hw);
- return -EIO;
- }
- sdla_mapmem(hw, 0L); /* set window vector at bottom */
- return 0;
-}
-
-/*============================================================================
- * Load adapter from the memory image of the SDLA firmware module.
- * o verify firmware integrity and compatibility
- * o start adapter up
- */
-static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len)
-{
-
- int i;
-
- /* Verify firmware signature */
- if (strcmp(sfm->signature, SFM_SIGNATURE)) {
- printk(KERN_INFO "%s: not SDLA firmware!\n",
- modname);
- return -EINVAL;
- }
-
- /* Verify firmware module format version */
- if (sfm->version != SFM_VERSION) {
- printk(KERN_INFO
- "%s: firmware format %u rejected! Expecting %u.\n",
- modname, sfm->version, SFM_VERSION);
- return -EINVAL;
- }
-
- /* Verify firmware module length and checksum */
- if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
- (checksum((void*)&sfm->info,
- sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) {
- printk(KERN_INFO "%s: firmware corrupted!\n", modname);
- return -EINVAL;
- }
-
- /* Announce */
- printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname,
- (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware",
- sfm->info.codeid);
-
- if(hw->type == SDLA_S514)
- printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n",
- modname, hw->S514_cpu_no[0]);
-
- /* Scan through the list of compatible adapters and make sure our
- * adapter type is listed.
- */
- for (i = 0;
- (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
- ++i);
-
- if (i == SFM_MAX_SDLA) {
- printk(KERN_INFO "%s: firmware is not compatible with S%u!\n",
- modname, hw->type);
- return -EINVAL;
- }
-
-
- /* Make sure there is enough on-board memory */
- if (hw->memory < sfm->info.memsize) {
- printk(KERN_INFO
- "%s: firmware needs %lu bytes of on-board memory!\n",
- modname, sfm->info.memsize);
- return -EINVAL;
- }
-
- /* Move code onto adapter */
- if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) {
- printk(KERN_INFO "%s: failed to load code segment!\n",
- modname);
- return -EIO;
- }
-
- /* Prepare boot-time configuration data and kick-off CPU */
- sdla_bootcfg(hw, &sfm->info);
- if (sdla_start(hw, sfm->info.startoffs)) {
- printk(KERN_INFO "%s: Damn... Adapter won't start!\n",
- modname);
- return -EIO;
- }
-
- /* position DPM window over the mailbox and enable interrupts */
- if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) {
- printk(KERN_INFO "%s: adapter hardware failure!\n",
- modname);
- return -EIO;
- }
- hw->fwid = sfm->info.codeid; /* set firmware ID */
- return 0;
-}
-
-/*============================================================================
- * Initialize SDLA hardware: setup memory window, IRQ, etc.
- */
-static int sdla_init (sdlahw_t* hw)
-{
- int i;
-
- for (i = 0; i < SDLA_MAXIORANGE; ++i)
- hw->regs[i] = 0;
-
- switch (hw->type) {
- case SDLA_S502A: return init_s502a(hw);
- case SDLA_S502E: return init_s502e(hw);
- case SDLA_S503: return init_s503(hw);
- case SDLA_S507: return init_s507(hw);
- case SDLA_S508: return init_s508(hw);
- }
- return -EINVAL;
-}
-
-/*============================================================================
- * Test adapter on-board memory.
- * o slide DPM window from the bottom up and test adapter memory segment by
- * segment.
- * Return adapter memory size.
- */
-static unsigned long sdla_memtest (sdlahw_t* hw)
-{
- unsigned long memsize;
- unsigned winsize;
-
- for (memsize = 0, winsize = hw->dpmsize;
- !sdla_mapmem(hw, memsize) &&
- (test_memregion(hw->dpmbase, winsize) == winsize)
- ;
- memsize += winsize)
- ;
- hw->memory = memsize;
- return memsize;
-}
-
-/*============================================================================
- * Prepare boot-time firmware configuration data.
- * o position DPM window
- * o initialize configuration data area
- */
-static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo)
-{
- unsigned char* data;
-
- if (!sfminfo->datasize) return 0; /* nothing to do */
-
- if (sdla_mapmem(hw, sfminfo->dataoffs) != 0)
- return -EIO;
-
- if(hw->type == SDLA_S514)
- data = (void*)(hw->dpmbase + sfminfo->dataoffs);
- else
- data = (void*)((u8 *)hw->dpmbase +
- (sfminfo->dataoffs - hw->vector));
-
- memset_io (data, 0, sfminfo->datasize);
-
- writeb (make_config_byte(hw), &data[0x00]);
-
- switch (sfminfo->codeid) {
- case SFID_X25_502:
- case SFID_X25_508:
- writeb (3, &data[0x01]); /* T1 timer */
- writeb (10, &data[0x03]); /* N2 */
- writeb (7, &data[0x06]); /* HDLC window size */
- writeb (1, &data[0x0B]); /* DTE */
- writeb (2, &data[0x0C]); /* X.25 packet window size */
- writew (128, &data[0x0D]); /* default X.25 data size */
- writew (128, &data[0x0F]); /* maximum X.25 data size */
- break;
- }
- return 0;
-}
-
-/*============================================================================
- * Prepare configuration byte identifying adapter type and CPU clock rate.
- */
-static unsigned char make_config_byte (sdlahw_t* hw)
-{
- unsigned char byte = 0;
-
- switch (hw->pclk) {
- case 5000: byte = 0x01; break;
- case 7200: byte = 0x02; break;
- case 8000: byte = 0x03; break;
- case 10000: byte = 0x04; break;
- case 16000: byte = 0x05; break;
- }
-
- switch (hw->type) {
- case SDLA_S502E: byte |= 0x80; break;
- case SDLA_S503: byte |= 0x40; break;
- }
- return byte;
-}
-
-/*============================================================================
- * Start adapter's CPU.
- * o calculate a pointer to adapter's cold boot entry point
- * o position DPM window
- * o place boot instruction (jp addr) at cold boot entry point
- * o start CPU
- */
-static int sdla_start (sdlahw_t* hw, unsigned addr)
-{
- unsigned port = hw->port;
- unsigned char *bootp;
- int err, tmp, i;
-
- if (!port && (hw->type != SDLA_S514)) return -EFAULT;
-
- switch (hw->type) {
- case SDLA_S502A:
- bootp = hw->dpmbase;
- bootp += 0x66;
- break;
-
- case SDLA_S502E:
- case SDLA_S503:
- case SDLA_S507:
- case SDLA_S508:
- case SDLA_S514:
- bootp = hw->dpmbase;
- break;
-
- default:
- return -EINVAL;
- }
-
- err = sdla_mapmem(hw, 0);
- if (err) return err;
-
- writeb (0xC3, bootp); /* Z80: 'jp' opcode */
- bootp ++;
- writew (addr, bootp);
-
- switch (hw->type) {
- case SDLA_S502A:
- _OUTB(port, 0x10); /* issue NMI to CPU */
- hw->regs[0] = 0x10;
- break;
-
- case SDLA_S502E:
- _OUTB(port + 3, 0x01); /* start CPU */
- hw->regs[3] = 0x01;
- for (i = 0; i < SDLA_IODELAY; ++i);
- if (_INB(port) & 0x01) { /* verify */
- /*
- * Enabling CPU changes functionality of the
- * control register, so we have to reset its
- * mirror.
- */
- _OUTB(port, 0); /* disable interrupts */
- hw->regs[0] = 0;
- }
- else return -EIO;
- break;
-
- case SDLA_S503:
- tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i);
- if (!(_INB(port) & 0x01)) /* verify */
- return -EIO;
- break;
-
- case SDLA_S507:
- tmp = hw->regs[0] | 0x02;
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i);
- if (!(_INB(port) & 0x04)) /* verify */
- return -EIO;
- break;
-
- case SDLA_S508:
- tmp = hw->regs[0] | 0x02;
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i);
- if (!(_INB(port + 1) & 0x02)) /* verify */
- return -EIO;
- break;
-
- case SDLA_S514:
- writeb (S514_CPU_START, hw->vector);
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/*============================================================================
- * Initialize S502A adapter.
- */
-static int init_s502a (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- if (!detect_s502a(port))
- return -ENODEV;
-
- hw->regs[0] = 0x08;
- hw->regs[1] = 0xFF;
-
- /* Verify configuration options */
- i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase));
- if (i == 0)
- return -EINVAL;
-
- tmp = s502a_hmcr[i - 1];
- switch (hw->dpmsize) {
- case 0x2000:
- tmp |= 0x01;
- break;
-
- case 0x10000L:
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Setup dual-port memory window (this also enables memory access) */
- _OUTB(port + 1, tmp);
- hw->regs[1] = tmp;
- hw->regs[0] = 0x08;
- return 0;
-}
-
-/*============================================================================
- * Initialize S502E adapter.
- */
-static int init_s502e (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- if (!detect_s502e(port))
- return -ENODEV;
-
- /* Verify configuration options */
- i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
- if (i == 0)
- return -EINVAL;
-
- tmp = s502e_hmcr[i - 1];
- switch (hw->dpmsize) {
- case 0x2000:
- tmp |= 0x01;
- break;
-
- case 0x10000L:
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Setup dual-port memory window */
- _OUTB(port + 1, tmp);
- hw->regs[1] = tmp;
-
- /* Enable memory access */
- _OUTB(port, 0x02);
- hw->regs[0] = 0x02;
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- return (_INB(port) & 0x02) ? 0 : -EIO;
-}
-
-/*============================================================================
- * Initialize S503 adapter.
- * ---------------------------------------------------------------------------
- */
-static int init_s503 (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- if (!detect_s503(port))
- return -ENODEV;
-
- /* Verify configuration options */
- i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
- if (i == 0)
- return -EINVAL;
-
- tmp = s502e_hmcr[i - 1];
- switch (hw->dpmsize) {
- case 0x2000:
- tmp |= 0x01;
- break;
-
- case 0x10000L:
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Setup dual-port memory window */
- _OUTB(port + 1, tmp);
- hw->regs[1] = tmp;
-
- /* Enable memory access */
- _OUTB(port, 0x02);
- hw->regs[0] = 0x02; /* update mirror */
- return 0;
-}
-
-/*============================================================================
- * Initialize S507 adapter.
- */
-static int init_s507 (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- if (!detect_s507(port))
- return -ENODEV;
-
- /* Verify configuration options */
- i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase));
- if (i == 0)
- return -EINVAL;
-
- tmp = s507_hmcr[i - 1];
- switch (hw->dpmsize) {
- case 0x2000:
- tmp |= 0x01;
- break;
-
- case 0x10000L:
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Enable adapter's logic */
- _OUTB(port, 0x01);
- hw->regs[0] = 0x01;
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (!(_INB(port) & 0x20))
- return -EIO;
-
- /* Setup dual-port memory window */
- _OUTB(port + 1, tmp);
- hw->regs[1] = tmp;
-
- /* Enable memory access */
- tmp = hw->regs[0] | 0x04;
- if (hw->irq) {
- i = get_option_index(s508_irq_options, hw->irq);
- if (i) tmp |= s507_irqmask[i - 1];
- }
- _OUTB(port, tmp);
- hw->regs[0] = tmp; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- return (_INB(port) & 0x08) ? 0 : -EIO;
-}
-
-/*============================================================================
- * Initialize S508 adapter.
- */
-static int init_s508 (sdlahw_t* hw)
-{
- unsigned port = hw->port;
- int tmp, i;
-
- if (!detect_s508(port))
- return -ENODEV;
-
- /* Verify configuration options */
- i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase));
- if (i == 0)
- return -EINVAL;
-
- /* Setup memory configuration */
- tmp = s508_hmcr[i - 1];
- _OUTB(port + 1, tmp);
- hw->regs[1] = tmp;
-
- /* Enable memory access */
- _OUTB(port, 0x04);
- hw->regs[0] = 0x04; /* update mirror */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- return (_INB(port + 1) & 0x04) ? 0 : -EIO;
-}
-
-/*============================================================================
- * Detect S502A adapter.
- * Following tests are used to detect S502A adapter:
- * 1. All registers other than status (BASE) should read 0xFF
- * 2. After writing 00001000b to control register, status register should
- * read 01000000b.
- * 3. After writing 0 to control register, status register should still
- * read 01000000b.
- * 4. After writing 00000100b to control register, status register should
- * read 01000100b.
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test.
- */
-static int detect_s502a (int port)
-{
- int i, j;
-
- if (!get_option_index(s502_port_options, port))
- return 0;
-
- for (j = 1; j < SDLA_MAXIORANGE; ++j) {
- if (_INB(port + j) != 0xFF)
- return 0;
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- }
-
- _OUTB(port, 0x08); /* halt CPU */
- _OUTB(port, 0x08);
- _OUTB(port, 0x08);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0x40)
- return 0;
- _OUTB(port, 0x00);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0x40)
- return 0;
- _OUTB(port, 0x04);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0x44)
- return 0;
-
- /* Reset adapter */
- _OUTB(port, 0x08);
- _OUTB(port, 0x08);
- _OUTB(port, 0x08);
- _OUTB(port + 1, 0xFF);
- return 1;
-}
-
-/*============================================================================
- * Detect S502E adapter.
- * Following tests are used to verify adapter presence:
- * 1. All registers other than status (BASE) should read 0xFF.
- * 2. After writing 0 to CPU control register (BASE+3), status register
- * (BASE) should read 11111000b.
- * 3. After writing 00000100b to port BASE (set bit 2), status register
- * (BASE) should read 11111100b.
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test.
- */
-static int detect_s502e (int port)
-{
- int i, j;
-
- if (!get_option_index(s502_port_options, port))
- return 0;
- for (j = 1; j < SDLA_MAXIORANGE; ++j) {
- if (_INB(port + j) != 0xFF)
- return 0;
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- }
-
- _OUTB(port + 3, 0); /* CPU control reg. */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0xF8) /* read status */
- return 0;
- _OUTB(port, 0x04); /* set bit 2 */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0xFC) /* verify */
- return 0;
-
- /* Reset adapter */
- _OUTB(port, 0);
- return 1;
-}
-
-/*============================================================================
- * Detect s503 adapter.
- * Following tests are used to verify adapter presence:
- * 1. All registers other than status (BASE) should read 0xFF.
- * 2. After writing 0 to control register (BASE), status register (BASE)
- * should read 11110000b.
- * 3. After writing 00000100b (set bit 2) to control register (BASE),
- * status register should read 11110010b.
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test.
- */
-static int detect_s503 (int port)
-{
- int i, j;
-
- if (!get_option_index(s503_port_options, port))
- return 0;
- for (j = 1; j < SDLA_MAXIORANGE; ++j) {
- if (_INB(port + j) != 0xFF)
- return 0;
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- }
-
- _OUTB(port, 0); /* reset control reg.*/
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0xF0) /* read status */
- return 0;
- _OUTB(port, 0x04); /* set bit 2 */
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if (_INB(port) != 0xF2) /* verify */
- return 0;
-
- /* Reset adapter */
- _OUTB(port, 0);
- return 1;
-}
-
-/*============================================================================
- * Detect s507 adapter.
- * Following tests are used to detect s507 adapter:
- * 1. All ports should read the same value.
- * 2. After writing 0x00 to control register, status register should read
- * ?011000?b.
- * 3. After writing 0x01 to control register, status register should read
- * ?011001?b.
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test.
- */
-static int detect_s507 (int port)
-{
- int tmp, i, j;
-
- if (!get_option_index(s508_port_options, port))
- return 0;
- tmp = _INB(port);
- for (j = 1; j < S507_IORANGE; ++j) {
- if (_INB(port + j) != tmp)
- return 0;
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- }
-
- _OUTB(port, 0x00);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if ((_INB(port) & 0x7E) != 0x30)
- return 0;
- _OUTB(port, 0x01);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if ((_INB(port) & 0x7E) != 0x32)
- return 0;
-
- /* Reset adapter */
- _OUTB(port, 0x00);
- return 1;
-}
-
-/*============================================================================
- * Detect s508 adapter.
- * Following tests are used to detect s508 adapter:
- * 1. After writing 0x00 to control register, status register should read
- * ??000000b.
- * 2. After writing 0x10 to control register, status register should read
- * ??010000b
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test.
- */
-static int detect_s508 (int port)
-{
- int i;
-
- if (!get_option_index(s508_port_options, port))
- return 0;
- _OUTB(port, 0x00);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if ((_INB(port + 1) & 0x3F) != 0x00)
- return 0;
- _OUTB(port, 0x10);
- for (i = 0; i < SDLA_IODELAY; ++i); /* delay */
- if ((_INB(port + 1) & 0x3F) != 0x10)
- return 0;
-
- /* Reset adapter */
- _OUTB(port, 0x00);
- return 1;
-}
-
-/*============================================================================
- * Detect s514 PCI adapter.
- * Return 1 if detected o.k. or 0 if failed.
- * Note: This test is destructive! Adapter will be left in shutdown
- * state after the test.
- */
-static int detect_s514 (sdlahw_t* hw)
-{
- unsigned char CPU_no, slot_no, auto_slot_cfg;
- int number_S514_cards = 0;
- u32 S514_mem_base_addr = 0;
- u32 ut_u32;
- struct pci_dev *pci_dev;
-
-
-#ifndef CONFIG_PCI
- printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname);
- return 0;
-#endif
-
- /*
- The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the
- slot number defined in 'router.conf' via the 'port' definition.
- */
- CPU_no = hw->S514_cpu_no[0];
- slot_no = hw->S514_slot_no;
- auto_slot_cfg = hw->auto_pci_cfg;
-
- if (auto_slot_cfg){
- printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n",
- modname, CPU_no);
-
- }else{
- printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n",
- modname, CPU_no, slot_no);
- }
-
- /* check to see that CPU A or B has been selected in 'router.conf' */
- switch(CPU_no) {
- case S514_CPU_A:
- case S514_CPU_B:
- break;
-
- default:
- printk(KERN_INFO "%s: S514 CPU definition invalid.\n",
- modname);
- printk(KERN_INFO "Must be 'A' or 'B'\n");
- return 0;
- }
-
- number_S514_cards = find_s514_adapter(hw, 0);
- if(!number_S514_cards)
- return 0;
-
- /* we are using a single S514 adapter with a slot of 0 so re-read the */
- /* location of this adapter */
- if((number_S514_cards == 1) && auto_slot_cfg) {
- number_S514_cards = find_s514_adapter(hw, 1);
- if(!number_S514_cards) {
- printk(KERN_INFO "%s: Error finding PCI card\n",
- modname);
- return 0;
- }
- }
-
- pci_dev = hw->pci_dev;
- /* read the physical memory base address */
- S514_mem_base_addr = (CPU_no == S514_CPU_A) ?
- (pci_dev->resource[1].start) :
- (pci_dev->resource[2].start);
-
- printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n",
- modname, S514_mem_base_addr);
- if(!S514_mem_base_addr) {
- if(CPU_no == S514_CPU_B)
- printk(KERN_INFO "%s: CPU #B not present on the card\n", modname);
- else
- printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname);
- return 0;
- }
-
- /* enable the PCI memory */
- pci_read_config_dword(pci_dev,
- (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
- &ut_u32);
- pci_write_config_dword(pci_dev,
- (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
- (ut_u32 | PCI_MEMORY_ENABLE));
-
- /* check the IRQ allocated and enable IRQ usage */
- if(!(hw->irq = pci_dev->irq)) {
- printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
- modname);
- return 0;
- }
-
- /* BUG FIX : Mar 6 2000
- * On a initial loading of the card, we must check
- * and clear PCI interrupt bits, due to a reset
- * problem on some other boards. i.e. An interrupt
- * might be pending, even after system bootup,
- * in which case, when starting wanrouter the machine
- * would crash.
- */
- if (init_pci_slot(hw))
- return 0;
-
- pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32);
- ut_u32 |= (CPU_no == S514_CPU_A) ?
- PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
- pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32);
-
- printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n",
- modname, hw->irq);
-
- /* map the physical PCI memory to virtual memory */
- hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr,
- (unsigned long)MAX_SIZEOF_S514_MEMORY);
- /* map the physical control register memory to virtual memory */
- hw->vector = (unsigned long)ioremap(
- (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE),
- (unsigned long)16);
-
- if(!hw->dpmbase || !hw->vector) {
- printk(KERN_INFO "%s: PCI virtual memory allocation failed\n",
- modname);
- return 0;
- }
-
- /* halt the adapter */
- writeb (S514_CPU_HALT, hw->vector);
-
- return 1;
-}
-
-/*============================================================================
- * Find the S514 PCI adapter in the PCI bus.
- * Return the number of S514 adapters found (0 if no adapter found).
- */
-static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card)
-{
- unsigned char slot_no;
- int number_S514_cards = 0;
- char S514_found_in_slot = 0;
- u16 PCI_subsys_vendor;
-
- struct pci_dev *pci_dev = NULL;
-
- slot_no = hw->S514_slot_no;
-
- while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
- != NULL) {
-
- pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
- &PCI_subsys_vendor);
-
- if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
- continue;
-
- hw->pci_dev = pci_dev;
-
- if(find_first_S514_card)
- return(1);
-
- number_S514_cards ++;
-
- printk(KERN_INFO
- "%s: S514 card found, slot #%d (devfn 0x%X)\n",
- modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
- pci_dev->devfn);
-
- if (hw->auto_pci_cfg){
- hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK);
- slot_no = hw->S514_slot_no;
-
- }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){
- S514_found_in_slot = 1;
- break;
- }
- }
-
- /* if no S514 adapter has been found, then exit */
- if (!number_S514_cards) {
- printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname);
- return 0;
- }
- /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */
- else if ((number_S514_cards > 1) && hw->auto_pci_cfg) {
- printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n"
- "%s: More than one S514 adapter found.\n"
- "%s: Disable the Autodetect feature and supply\n"
- "%s: the PCISLOT numbers for each card.\n",
- modname,modname,modname,modname);
- return 0;
- }
- /* if the user has specified a slot number and the S514 adapter has */
- /* not been found in that slot, then exit */
- else if (!hw->auto_pci_cfg && !S514_found_in_slot) {
- printk(KERN_INFO
- "%s: Error, S514 card not found in specified slot #%d\n",
- modname, slot_no);
- return 0;
- }
-
- return (number_S514_cards);
-}
-
-
-
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * Calibrate SDLA memory access delay.
- * Count number of idle loops made within 1 second and then calculate the
- * number of loops that should be made to achive desired delay.
- */
-static int calibrate_delay (int mks)
-{
- unsigned int delay;
- unsigned long stop;
-
- for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay);
- return (delay/(1000000L/mks) + 1);
-}
-
-/*============================================================================
- * Get option's index into the options list.
- * Return option's index (1 .. N) or zero if option is invalid.
- */
-static int get_option_index (unsigned* optlist, unsigned optval)
-{
- int i;
-
- for (i = 1; i <= optlist[0]; ++i)
- if ( optlist[i] == optval)
- return i;
- return 0;
-}
-
-/*============================================================================
- * Check memory region to see if it's available.
- * Return: 0 ok.
- */
-static unsigned check_memregion (void* ptr, unsigned len)
-{
- volatile unsigned char* p = ptr;
-
- for (; len && (readb (p) == 0xFF); --len, ++p) {
- writeb (0, p); /* attempt to write 0 */
- if (readb(p) != 0xFF) { /* still has to read 0xFF */
- writeb (0xFF, p);/* restore original value */
- break; /* not good */
- }
- }
-
- return len;
-}
-
-/*============================================================================
- * Test memory region.
- * Return: size of the region that passed the test.
- * Note: Region size must be multiple of 2 !
- */
-static unsigned test_memregion (void* ptr, unsigned len)
-{
- volatile unsigned short* w_ptr;
- unsigned len_w = len >> 1; /* region len in words */
- unsigned i;
-
- for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
- writew (0xAA55, w_ptr);
-
- for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
- if (readw (w_ptr) != 0xAA55) {
- len_w = i;
- break;
- }
-
- for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
- writew (0x55AA, w_ptr);
-
- for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
- if (readw(w_ptr) != 0x55AA) {
- len_w = i;
- break;
- }
-
- for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr)
- writew (0, w_ptr);
-
- return len_w << 1;
-}
-
-/*============================================================================
- * Calculate 16-bit CRC using CCITT polynomial.
- */
-static unsigned short checksum (unsigned char* buf, unsigned len)
-{
- unsigned short crc = 0;
- unsigned mask, flag;
-
- for (; len; --len, ++buf) {
- for (mask = 0x80; mask; mask >>= 1) {
- flag = (crc & 0x8000);
- crc <<= 1;
- crc |= ((*buf & mask) ? 1 : 0);
- if (flag) crc ^= 0x1021;
- }
- }
- return crc;
-}
-
-static int init_pci_slot(sdlahw_t *hw)
-{
-
- u32 int_status;
- int volatile found=0;
- int i=0;
-
- /* Check if this is a very first load for a specific
- * pci card. If it is, clear the interrput bits, and
- * set the flag indicating that this card was initialized.
- */
-
- for (i=0; (i<MAX_S514_CARDS) && !found; i++){
- if (pci_slot_ar[i] == hw->S514_slot_no){
- found=1;
- break;
- }
- if (pci_slot_ar[i] == 0xFF){
- break;
- }
- }
-
- if (!found){
- read_S514_int_stat(hw,&int_status);
- S514_intack(hw,int_status);
- if (i == MAX_S514_CARDS){
- printk(KERN_INFO "%s: Critical Error !!!\n",modname);
- printk(KERN_INFO
- "%s: Number of Sangoma PCI cards exceeded maximum limit.\n",
- modname);
- printk(KERN_INFO "Please contact Sangoma Technologies\n");
- return 1;
- }
- pci_slot_ar[i] = hw->S514_slot_no;
- }
- return 0;
-}
-
-static int pci_probe(sdlahw_t *hw)
-{
-
- unsigned char slot_no;
- int number_S514_cards = 0;
- u16 PCI_subsys_vendor;
- u16 PCI_card_type;
-
- struct pci_dev *pci_dev = NULL;
- struct pci_bus *bus = NULL;
-
- slot_no = 0;
-
- while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
- != NULL) {
-
- pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
- &PCI_subsys_vendor);
-
- if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
- continue;
-
- pci_read_config_word(pci_dev, PCI_CARD_TYPE,
- &PCI_card_type);
-
- bus = pci_dev->bus;
-
- /* A dual cpu card can support up to 4 physical connections,
- * where a single cpu card can support up to 2 physical
- * connections. The FT1 card can only support a single
- * connection, however we cannot distinguish between a Single
- * CPU card and an FT1 card. */
- if (PCI_card_type == S514_DUAL_CPU){
- number_S514_cards += 4;
- printk(KERN_INFO
- "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
- bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
- pci_dev->irq);
- }else{
- number_S514_cards += 2;
- printk(KERN_INFO
- "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
- bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
- pci_dev->irq);
- }
- }
-
- return number_S514_cards;
-
-}
-
-
-
-EXPORT_SYMBOL(wanpipe_hw_probe);
-
-unsigned wanpipe_hw_probe(void)
-{
- sdlahw_t hw;
- unsigned* opt = s508_port_options;
- unsigned cardno=0;
- int i;
-
- memset(&hw, 0, sizeof(hw));
-
- for (i = 1; i <= opt[0]; i++) {
- if (detect_s508(opt[i])){
- /* S508 card can support up to two physical links */
- cardno+=2;
- printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]);
- }
- }
-
- #ifdef CONFIG_PCI
- hw.S514_slot_no = 0;
- cardno += pci_probe(&hw);
- #else
- printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n");
- printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n");
- #endif
-
- return cardno;
-}
-
-/****** End *****************************************************************/
diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c
deleted file mode 100644
index 7a8b22a7ea31..000000000000
--- a/drivers/net/wan/sdlamain.c
+++ /dev/null
@@ -1,1346 +0,0 @@
-/****************************************************************************
-* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module.
-*
-* Author: Nenad Corbic <ncorbic@sangoma.com>
-* Gideon Hack
-*
-* Copyright: (c) 1995-2000 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels.
-* Removed the polling routine.
-* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic
-* device allocation.
-* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels
-* 2.2.16 and above.
-* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on
-* kernels 2.2.16 or greater. The SyncPPP
-* has changed.
-* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP.
-* Jul 13, 2000 Nenad Corbic Added Multi-PPP support.
-* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection.
-* Sep 23, 1999 Nenad Corbic Added support for SMP
-* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device.
-* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
-* Updates for Linux 2.2.X kernels.
-* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel
-* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1
-* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags();
-* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0
-* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr
-* assignments are taken out and placed in the
-* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr
-* routines. Took out 'wandev->tx_int_enabled' and
-* replaced it with 'wandev->enable_tx_int'.
-* May 29, 1997 Jaspreet Singh Flow Control Problem
-* added "wandev->tx_int_enabled=1" line in the
-* init module. This line initializes the flag for
-* preventing Interrupt disabled with device set to
-* busy
-* Jan 15, 1997 Gene Kozin Version 3.1.0
-* o added UDP management stuff
-* Jan 02, 1997 Gene Kozin Initial version.
-*****************************************************************************/
-
-#include <linux/config.h> /* OS configuration options */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/init.h>
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/module.h> /* support for loadable modules */
-#include <linux/ioport.h> /* request_region(), release_region() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/rcupdate.h>
-
-#include <linux/in.h>
-#include <asm/io.h> /* phys_to_virt() */
-#include <linux/pci.h>
-#include <linux/sdlapci.h>
-#include <linux/if_wanpipe_common.h>
-
-#include <asm/uaccess.h> /* kernel <-> user copy */
-#include <linux/inetdevice.h>
-
-#include <linux/ip.h>
-#include <net/route.h>
-
-#define KMEM_SAFETYZONE 8
-
-
-#ifndef CONFIG_WANPIPE_FR
- #define wpf_init(a,b) (-EPROTONOSUPPORT)
-#endif
-
-#ifndef CONFIG_WANPIPE_CHDLC
- #define wpc_init(a,b) (-EPROTONOSUPPORT)
-#endif
-
-#ifndef CONFIG_WANPIPE_X25
- #define wpx_init(a,b) (-EPROTONOSUPPORT)
-#endif
-
-#ifndef CONFIG_WANPIPE_PPP
- #define wpp_init(a,b) (-EPROTONOSUPPORT)
-#endif
-
-#ifndef CONFIG_WANPIPE_MULTPPP
- #define wsppp_init(a,b) (-EPROTONOSUPPORT)
-#endif
-
-
-/***********FOR DEBUGGING PURPOSES*********************************************
-static void * dbg_kmalloc(unsigned int size, int prio, int line) {
- int i = 0;
- void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio);
- char * c1 = v;
- c1 += sizeof(unsigned int);
- *((unsigned int *)v) = size;
-
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D';
- c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F';
- c1 += 8;
- }
- c1 += size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G';
- c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L';
- c1 += 8;
- }
- v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8;
- printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v);
- return v;
-}
-static void dbg_kfree(void * v, int line) {
- unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8));
- unsigned int size = *sp;
- char * c1 = ((char *)v) - KMEM_SAFETYZONE*8;
- int i = 0;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D'
- || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') {
- printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v);
- printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
- c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
- }
- c1 += 8;
- }
- c1 += size;
- for (i = 0; i < KMEM_SAFETYZONE; i++) {
- if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G'
- || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L'
- ) {
- printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v);
- printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8,
- c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] );
- }
- c1 += 8;
- }
- printk(KERN_INFO "line %d kfree(%p)\n",line,v);
- v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8);
- kfree(v);
-}
-
-#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)
-#define kfree(x) dbg_kfree(x,__LINE__)
-******************************************************************************/
-
-
-
-/****** Defines & Macros ****************************************************/
-
-#ifdef _DEBUG_
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-#define DRV_VERSION 5 /* version number */
-#define DRV_RELEASE 0 /* release (minor version) number */
-#define MAX_CARDS 16 /* max number of adapters */
-
-#ifndef CONFIG_WANPIPE_CARDS /* configurable option */
-#define CONFIG_WANPIPE_CARDS 1
-#endif
-
-#define CMD_OK 0 /* normal firmware return code */
-#define CMD_TIMEOUT 0xFF /* firmware command timed out */
-#define MAX_CMD_RETRY 10 /* max number of firmware retries */
-/****** Function Prototypes *************************************************/
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/* WAN link driver entry points */
-static int setup(struct wan_device* wandev, wandev_conf_t* conf);
-static int shutdown(struct wan_device* wandev);
-static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg);
-
-/* IOCTL handlers */
-static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump);
-static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int);
-
-/* Miscellaneous functions */
-STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs);
-static void release_hw (sdla_t *card);
-
-static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*);
-static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*);
-
-
-/****** Global Data **********************************************************
- * Note: All data must be explicitly initialized!!!
- */
-
-/* private data */
-static char drvname[] = "wanpipe";
-static char fullname[] = "WANPIPE(tm) Multiprotocol Driver";
-static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc.";
-static int ncards;
-static sdla_t* card_array; /* adapter data space */
-
-/* Wanpipe's own workqueue, used for all API's.
- * All protocol specific tasks will be inserted
- * into the "wanpipe_wq" workqueue.
-
- * The kernel workqueue mechanism will execute
- * all pending tasks in the "wanpipe_wq" workqueue.
- */
-
-struct workqueue_struct *wanpipe_wq;
-DECLARE_WORK(wanpipe_work, NULL, NULL);
-
-static int wanpipe_bh_critical;
-
-/******* Kernel Loadable Module Entry Points ********************************/
-
-/*============================================================================
- * Module 'insert' entry point.
- * o print announcement
- * o allocate adapter data space
- * o initialize static data
- * o register all cards with WAN router
- * o calibrate SDLA shared memory access delay.
- *
- * Return: 0 Ok
- * < 0 error.
- * Context: process
- */
-
-static int __init wanpipe_init(void)
-{
- int cnt, err = 0;
-
- printk(KERN_INFO "%s v%u.%u %s\n",
- fullname, DRV_VERSION, DRV_RELEASE, copyright);
-
- wanpipe_wq = create_workqueue("wanpipe_wq");
- if (!wanpipe_wq)
- return -ENOMEM;
-
- /* Probe for wanpipe cards and return the number found */
- printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n");
- ncards = wanpipe_hw_probe();
- if (ncards){
- printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards);
- }else{
- printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n");
- destroy_workqueue(wanpipe_wq);
- return -ENODEV;
- }
-
- /* Verify number of cards and allocate adapter data space */
- card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL);
- if (card_array == NULL) {
- destroy_workqueue(wanpipe_wq);
- return -ENOMEM;
- }
-
- memset(card_array, 0, sizeof(sdla_t) * ncards);
-
- /* Register adapters with WAN router */
- for (cnt = 0; cnt < ncards; ++ cnt) {
- sdla_t* card = &card_array[cnt];
- struct wan_device* wandev = &card->wandev;
-
- card->next = NULL;
- sprintf(card->devname, "%s%d", drvname, cnt + 1);
- wandev->magic = ROUTER_MAGIC;
- wandev->name = card->devname;
- wandev->private = card;
- wandev->enable_tx_int = 0;
- wandev->setup = &setup;
- wandev->shutdown = &shutdown;
- wandev->ioctl = &ioctl;
- err = register_wan_device(wandev);
- if (err) {
- printk(KERN_INFO
- "%s: %s registration failed with error %d!\n",
- drvname, card->devname, err);
- break;
- }
- }
- if (cnt){
- ncards = cnt; /* adjust actual number of cards */
- }else {
- kfree(card_array);
- destroy_workqueue(wanpipe_wq);
- printk(KERN_INFO "IN Init Module: NO Cards registered\n");
- err = -ENODEV;
- }
-
- return err;
-}
-
-/*============================================================================
- * Module 'remove' entry point.
- * o unregister all adapters from the WAN router
- * o release all remaining system resources
- */
-static void __exit wanpipe_cleanup(void)
-{
- int i;
-
- if (!ncards)
- return;
-
- for (i = 0; i < ncards; ++i) {
- sdla_t* card = &card_array[i];
- unregister_wan_device(card->devname);
- }
- destroy_workqueue(wanpipe_wq);
- kfree(card_array);
-
- printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n");
-}
-
-module_init(wanpipe_init);
-module_exit(wanpipe_cleanup);
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Setup/configure WAN link driver.
- * o check adapter state
- * o make sure firmware is present in configuration
- * o make sure I/O port and IRQ are specified
- * o make sure I/O region is available
- * o allocate interrupt vector
- * o setup SDLA hardware
- * o call appropriate routine to perform protocol-specific initialization
- * o mark I/O region as used
- * o if this is the first active card, then schedule background task
- *
- * This function is called when router handles ROUTER_SETUP IOCTL. The
- * configuration structure is in kernel memory (including extended data, if
- * any).
- */
-
-static int setup(struct wan_device* wandev, wandev_conf_t* conf)
-{
- sdla_t* card;
- int err = 0;
- int irq=0;
-
- /* Sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){
- printk(KERN_INFO
- "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n",
- wandev->name,
- (unsigned int)wandev,(unsigned int)wandev->private,
- (unsigned int)conf);
- return -EFAULT;
- }
-
- printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name);
-
- card = wandev->private;
- if (wandev->state != WAN_UNCONFIGURED){
- printk(KERN_INFO "%s: failed sdlamain setup, busy!\n",
- wandev->name);
- return -EBUSY; /* already configured */
- }
-
- printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name);
-
- /* Initialize the counters for each wandev
- * Used for counting number of times new_if and
- * del_if get called.
- */
- wandev->del_if_cnt = 0;
- wandev->new_if_cnt = 0;
- wandev->config_id = conf->config_id;
-
- if (!conf->data_size || (conf->data == NULL)) {
- printk(KERN_INFO
- "%s: firmware not found in configuration data!\n",
- wandev->name);
- return -EINVAL;
- }
-
- /* Check for resource conflicts and setup the
- * card for piggibacking if necessary */
- if(!conf->S514_CPU_no[0]) {
- if ((err=check_s508_conflicts(card,conf,&irq)) != 0){
- return err;
- }
- }else {
- if ((err=check_s514_conflicts(card,conf,&irq)) != 0){
- return err;
- }
- }
-
- /* If the current card has already been configured
- * or it's a piggyback card, do not try to allocate
- * resources.
- */
- if (!card->wandev.piggyback && !card->configured){
-
- /* Configure hardware, load firmware, etc. */
- memset(&card->hw, 0, sizeof(sdlahw_t));
-
- /* for an S514 adapter, pass the CPU number and the slot number read */
- /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */
- /* parameter */
- if (conf->S514_CPU_no[0]){
-
- card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0];
- card->hw.S514_slot_no = conf->PCI_slot_no;
- card->hw.auto_pci_cfg = conf->auto_pci_cfg;
-
- if (card->hw.auto_pci_cfg == WANOPT_YES){
- printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n",
- card->devname, card->hw.S514_cpu_no[0]);
- }else{
- printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n",
- card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no);
- }
-
- }else{
- /* 508 Card io port and irq initialization */
- card->hw.port = conf->ioport;
- card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
- }
-
-
- /* Compute the virtual address of the card in kernel space */
- if(conf->maddr){
- card->hw.dpmbase = phys_to_virt(conf->maddr);
- }else{
- card->hw.dpmbase = (void *)conf->maddr;
- }
-
- card->hw.dpmsize = SDLA_WINDOWSIZE;
-
- /* set the adapter type if using an S514 adapter */
- card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0];
- card->hw.pclk = conf->hw_opt[1];
-
- err = sdla_setup(&card->hw, conf->data, conf->data_size);
- if (err){
- printk(KERN_INFO "%s: Hardware setup Failed %i\n",
- card->devname,err);
- return err;
- }
-
- if(card->hw.type != SDLA_S514)
- irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */
- else
- irq = card->hw.irq;
-
- /* request an interrupt vector - note that interrupts may be shared */
- /* when using the S514 PCI adapter */
-
- if(request_irq(irq, sdla_isr,
- (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0,
- wandev->name, card)){
-
- printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq);
- return -EINVAL;
- }
-
- }else{
- printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n",
- wandev->name,card->configured,card->wandev.piggyback);
- }
-
-
- if (!card->configured){
-
- /* Initialize the Spin lock */
- printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name);
-
- /* Piggyback spin lock has already been initialized,
- * in check_s514/s508_conflicts() */
- if (!card->wandev.piggyback){
- spin_lock_init(&card->wandev.lock);
- }
-
- /* Intialize WAN device data space */
- wandev->irq = irq;
- wandev->dma = 0;
- if(card->hw.type != SDLA_S514){
- wandev->ioport = card->hw.port;
- }else{
- wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0];
- wandev->S514_slot_no = card->hw.S514_slot_no;
- }
- wandev->maddr = (unsigned long)card->hw.dpmbase;
- wandev->msize = card->hw.dpmsize;
- wandev->hw_opt[0] = card->hw.type;
- wandev->hw_opt[1] = card->hw.pclk;
- wandev->hw_opt[2] = card->hw.memory;
- wandev->hw_opt[3] = card->hw.fwid;
- }
-
- /* Protocol-specific initialization */
- switch (card->hw.fwid) {
-
- case SFID_X25_502:
- case SFID_X25_508:
- printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n",
- card->devname);
- err = wpx_init(card, conf);
- break;
- case SFID_FR502:
- case SFID_FR508:
- printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n",
- card->devname);
- err = wpf_init(card, conf);
- break;
- case SFID_PPP502:
- case SFID_PPP508:
- printk(KERN_INFO "%s: Starting PPP Protocol Init.\n",
- card->devname);
- err = wpp_init(card, conf);
- break;
-
- case SFID_CHDLC508:
- case SFID_CHDLC514:
- if (conf->ft1){
- printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n",
- card->devname);
- err = wpft1_init(card, conf);
- break;
-
- }else if (conf->config_id == WANCONFIG_MPPP){
- printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n",
- card->devname);
- err = wsppp_init(card,conf);
- break;
-
- }else{
- printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n",
- card->devname);
- err = wpc_init(card, conf);
- break;
- }
- default:
- printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n",
- wandev->name,card->hw.fwid,SFID_CHDLC508);
- err = -EPROTONOSUPPORT;
- }
-
- if (err != 0){
- if (err == -EPROTONOSUPPORT){
- printk(KERN_INFO
- "%s: Error, Protocol selected has not been compiled!\n",
- card->devname);
- printk(KERN_INFO
- "%s: Re-configure the kernel and re-build the modules!\n",
- card->devname);
- }
-
- release_hw(card);
- wandev->state = WAN_UNCONFIGURED;
- return err;
- }
-
-
- /* Reserve I/O region and schedule background task */
- if(card->hw.type != SDLA_S514 && !card->wandev.piggyback)
- if (!request_region(card->hw.port, card->hw.io_range,
- wandev->name)) {
- printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port);
- release_hw(card);
- wandev->state = WAN_UNCONFIGURED;
- return -EBUSY;
- }
-
- /* Only use the polling routine for the X25 protocol */
-
- card->wandev.critical=0;
- return 0;
-}
-
-/*==================================================================
- * configure_s508_card
- *
- * For a S508 adapter, check for a possible configuration error in that
- * we are loading an adapter in the same IO port as a previously loaded S508
- * card.
- */
-
-static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq)
-{
- unsigned long smp_flags;
- int i;
-
- if (conf->ioport <= 0) {
- printk(KERN_INFO
- "%s: can't configure without I/O port address!\n",
- card->wandev.name);
- return -EINVAL;
- }
-
- if (conf->irq <= 0) {
- printk(KERN_INFO "%s: can't configure without IRQ!\n",
- card->wandev.name);
- return -EINVAL;
- }
-
- if (test_bit(0,&card->configured))
- return 0;
-
-
- /* Check for already loaded card with the same IO port and IRQ
- * If found, copy its hardware configuration and use its
- * resources (i.e. piggybacking)
- */
-
- for (i = 0; i < ncards; i++) {
- sdla_t *nxt_card = &card_array[i];
-
- /* Skip the current card ptr */
- if (nxt_card == card)
- continue;
-
-
- /* Find a card that is already configured with the
- * same IO Port */
- if ((nxt_card->hw.type == SDLA_S508) &&
- (nxt_card->hw.port == conf->ioport) &&
- (nxt_card->next == NULL)){
-
- /* We found a card the card that has same configuration
- * as us. This means, that we must setup this card in
- * piggibacking mode. However, only CHDLC and MPPP protocol
- * support this setup */
-
- if ((conf->config_id == WANCONFIG_CHDLC ||
- conf->config_id == WANCONFIG_MPPP) &&
- (nxt_card->wandev.config_id == WANCONFIG_CHDLC ||
- nxt_card->wandev.config_id == WANCONFIG_MPPP)){
-
- *irq = nxt_card->hw.irq;
- memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
-
- /* The master could already be running, we must
- * set this as a critical area */
- lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags);
-
- nxt_card->next = card;
- card->next = nxt_card;
-
- card->wandev.piggyback = WANOPT_YES;
-
- /* We must initialise the piggiback spin lock here
- * since isr will try to lock card->next if it
- * exists */
- spin_lock_init(&card->wandev.lock);
-
- unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags);
- break;
- }else{
- /* Trying to run piggibacking with a wrong protocol */
- printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n"
- "%s: This protocol doesn't support\n"
- "%s: multi-port operation!\n",
- card->devname,nxt_card->hw.port,
- card->devname,card->devname);
- return -EEXIST;
- }
- }
- }
-
-
- /* Make sure I/O port region is available only if we are the
- * master device. If we are running in piggybacking mode,
- * we will use the resources of the master card. */
- if (!card->wandev.piggyback) {
- struct resource *rr =
- request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain");
- release_region(conf->ioport, SDLA_MAXIORANGE);
-
- if (!rr) {
- printk(KERN_INFO
- "%s: I/O region 0x%X - 0x%X is in use!\n",
- card->wandev.name, conf->ioport,
- conf->ioport + SDLA_MAXIORANGE - 1);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/*==================================================================
- * configure_s514_card
- *
- * For a S514 adapter, check for a possible configuration error in that
- * we are loading an adapter in the same slot as a previously loaded S514
- * card.
- */
-
-
-static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq)
-{
- unsigned long smp_flags;
- int i;
-
- if (test_bit(0,&card->configured))
- return 0;
-
-
- /* Check for already loaded card with the same IO port and IRQ
- * If found, copy its hardware configuration and use its
- * resources (i.e. piggybacking)
- */
-
- for (i = 0; i < ncards; i ++) {
-
- sdla_t* nxt_card = &card_array[i];
- if(nxt_card == card)
- continue;
-
- if((nxt_card->hw.type == SDLA_S514) &&
- (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) &&
- (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&&
- (nxt_card->next == NULL)){
-
-
- if ((conf->config_id == WANCONFIG_CHDLC ||
- conf->config_id == WANCONFIG_MPPP) &&
- (nxt_card->wandev.config_id == WANCONFIG_CHDLC ||
- nxt_card->wandev.config_id == WANCONFIG_MPPP)){
-
- *irq = nxt_card->hw.irq;
- memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t));
-
- /* The master could already be running, we must
- * set this as a critical area */
- lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags);
- nxt_card->next = card;
- card->next = nxt_card;
-
- card->wandev.piggyback = WANOPT_YES;
-
- /* We must initialise the piggiback spin lock here
- * since isr will try to lock card->next if it
- * exists */
- spin_lock_init(&card->wandev.lock);
-
- unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags);
-
- }else{
- /* Trying to run piggibacking with a wrong protocol */
- printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n"
- "%s: This protocol doesn't support\n"
- "%s: multi-port operation!\n",
- card->devname,
- conf->S514_CPU_no[0],conf->PCI_slot_no,
- card->devname,card->devname);
- return -EEXIST;
- }
- }
- }
-
- return 0;
-}
-
-
-
-/*============================================================================
- * Shut down WAN link driver.
- * o shut down adapter hardware
- * o release system resources.
- *
- * This function is called by the router when device is being unregistered or
- * when it handles ROUTER_DOWN IOCTL.
- */
-static int shutdown(struct wan_device* wandev)
-{
- sdla_t *card;
- int err=0;
-
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL)){
- return -EFAULT;
- }
-
- if (wandev->state == WAN_UNCONFIGURED){
- return 0;
- }
-
- card = wandev->private;
-
- if (card->tty_opt){
- if (card->tty_open){
- printk(KERN_INFO
- "%s: Shutdown Failed: TTY is still open\n",
- card->devname);
- return -EBUSY;
- }
- }
-
- wandev->state = WAN_UNCONFIGURED;
-
- set_bit(PERI_CRIT,(void*)&wandev->critical);
-
- /* In case of piggibacking, make sure that
- * we never try to shutdown both devices at the same
- * time, because they depend on one another */
-
- if (card->disable_comm){
- card->disable_comm(card);
- }
-
- /* Release Resources */
- release_hw(card);
-
- /* only free the allocated I/O range if not an S514 adapter */
- if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){
- release_region(card->hw.port, card->hw.io_range);
- }
-
- if (!card->configured){
- memset(&card->hw, 0, sizeof(sdlahw_t));
- if (card->next){
- memset(&card->next->hw, 0, sizeof(sdlahw_t));
- }
- }
-
-
- clear_bit(PERI_CRIT,(void*)&wandev->critical);
- return err;
-}
-
-static void release_hw (sdla_t *card)
-{
- sdla_t *nxt_card;
-
-
- /* Check if next device exists */
- if (card->next){
- nxt_card = card->next;
- /* If next device is down then release resources */
- if (nxt_card->wandev.state == WAN_UNCONFIGURED){
- if (card->wandev.piggyback){
- /* If this device is piggyback then use
- * information of the master device
- */
- printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname);
- sdla_down(&card->next->hw);
- free_irq(card->wandev.irq, card->next);
- card->configured = 0;
- card->next->configured = 0;
- card->wandev.piggyback = 0;
- }else{
- /* Master device shutting down */
- printk(KERN_INFO "%s: Master shutting down\n",card->devname);
- sdla_down(&card->hw);
- free_irq(card->wandev.irq, card);
- card->configured = 0;
- card->next->configured = 0;
- }
- }else{
- printk(KERN_INFO "%s: Device still running %i\n",
- nxt_card->devname,nxt_card->wandev.state);
-
- card->configured = 1;
- }
- }else{
- printk(KERN_INFO "%s: Master shutting down\n",card->devname);
- sdla_down(&card->hw);
- free_irq(card->wandev.irq, card);
- card->configured = 0;
- }
- return;
-}
-
-
-/*============================================================================
- * Driver I/O control.
- * o verify arguments
- * o perform requested action
- *
- * This function is called when router handles one of the reserved user
- * IOCTLs. Note that 'arg' stil points to user address space.
- */
-static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg)
-{
- sdla_t* card;
- int err;
-
- /* sanity checks */
- if ((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
- if (wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- card = wandev->private;
-
- if(card->hw.type != SDLA_S514){
- disable_irq(card->hw.irq);
- }
-
- if (test_bit(SEND_CRIT, (void*)&wandev->critical)) {
- return -EAGAIN;
- }
-
- switch (cmd) {
- case WANPIPE_DUMP:
- err = ioctl_dump(wandev->private, (void*)arg);
- break;
-
- case WANPIPE_EXEC:
- err = ioctl_exec(wandev->private, (void*)arg, cmd);
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-/****** Driver IOCTL Handlers ***********************************************/
-
-/*============================================================================
- * Dump adapter memory to user buffer.
- * o verify request structure
- * o copy request structure to kernel data space
- * o verify length/offset
- * o verify user buffer
- * o copy adapter memory image to user buffer
- *
- * Note: when dumping memory, this routine switches curent dual-port memory
- * vector, so care must be taken to avoid racing conditions.
- */
-static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
-{
- sdla_dump_t dump;
- unsigned winsize;
- unsigned long oldvec; /* DPM window vector */
- unsigned long smp_flags;
- int err = 0;
-
- if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)))
- return -EFAULT;
-
- if ((dump.magic != WANPIPE_MAGIC) ||
- (dump.offset + dump.length > card->hw.memory))
- return -EINVAL;
-
- winsize = card->hw.dpmsize;
-
- if(card->hw.type != SDLA_S514) {
-
- lock_adapter_irq(&card->wandev.lock, &smp_flags);
-
- oldvec = card->hw.vector;
- while (dump.length) {
- /* current offset */
- unsigned pos = dump.offset % winsize;
- /* current vector */
- unsigned long vec = dump.offset - pos;
- unsigned len = (dump.length > (winsize - pos)) ?
- (winsize - pos) : dump.length;
- /* relocate window */
- if (sdla_mapmem(&card->hw, vec) != 0) {
- err = -EIO;
- break;
- }
-
- if(copy_to_user((void *)dump.ptr,
- (u8 *)card->hw.dpmbase + pos, len)){
-
- unlock_adapter_irq(&card->wandev.lock, &smp_flags);
- return -EFAULT;
- }
-
- dump.length -= len;
- dump.offset += len;
- dump.ptr = (char*)dump.ptr + len;
- }
-
- sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */
- unlock_adapter_irq(&card->wandev.lock, &smp_flags);
-
- }else {
-
- if(copy_to_user((void *)dump.ptr,
- (u8 *)card->hw.dpmbase + dump.offset, dump.length)){
- return -EFAULT;
- }
- }
-
- return err;
-}
-
-/*============================================================================
- * Execute adapter firmware command.
- * o verify request structure
- * o copy request structure to kernel data space
- * o call protocol-specific 'exec' function
- */
-static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd)
-{
- sdla_exec_t exec;
- int err=0;
-
- if (card->exec == NULL && cmd == WANPIPE_EXEC){
- return -ENODEV;
- }
-
- if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)))
- return -EFAULT;
-
- if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
- return -EINVAL;
-
- switch (cmd) {
- case WANPIPE_EXEC:
- err = card->exec(card, exec.cmd, exec.data);
- break;
- }
- return err;
-}
-
-/******* Miscellaneous ******************************************************/
-
-/*============================================================================
- * SDLA Interrupt Service Routine.
- * o acknowledge SDLA hardware interrupt.
- * o call protocol-specific interrupt service routine, if any.
- */
-STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs)
-{
-#define card ((sdla_t*)dev_id)
-
- if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */
- u32 int_status;
- unsigned char CPU_no = card->hw.S514_cpu_no[0];
- unsigned char card_found_for_IRQ;
- u8 IRQ_count = 0;
-
- for(;;) {
-
- read_S514_int_stat(&card->hw, &int_status);
-
- /* check if the interrupt is for this device */
- if(!((unsigned char)int_status &
- (IRQ_CPU_A | IRQ_CPU_B)))
- return IRQ_HANDLED;
-
- /* if the IRQ is for both CPUs on the same adapter, */
- /* then alter the interrupt status so as to handle */
- /* one CPU at a time */
- if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B))
- == (IRQ_CPU_A | IRQ_CPU_B)) {
- int_status &= (CPU_no == S514_CPU_A) ?
- ~IRQ_CPU_B : ~IRQ_CPU_A;
- }
-
- card_found_for_IRQ = 0;
-
- /* check to see that the CPU number for this device */
- /* corresponds to the interrupt status read */
- switch (CPU_no) {
- case S514_CPU_A:
- if((unsigned char)int_status &
- IRQ_CPU_A)
- card_found_for_IRQ = 1;
- break;
-
- case S514_CPU_B:
- if((unsigned char)int_status &
- IRQ_CPU_B)
- card_found_for_IRQ = 1;
- break;
- }
-
- /* exit if the interrupt is for another CPU on the */
- /* same IRQ */
- if(!card_found_for_IRQ)
- return IRQ_HANDLED;
-
- if (!card ||
- (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){
- printk(KERN_INFO
- "Received IRQ %d for CPU #%c\n",
- irq, CPU_no);
- printk(KERN_INFO
- "IRQ for unconfigured adapter\n");
- S514_intack(&card->hw, int_status);
- return IRQ_HANDLED;
- }
-
- if (card->in_isr) {
- printk(KERN_INFO
- "%s: interrupt re-entrancy on IRQ %d\n",
- card->devname, card->wandev.irq);
- S514_intack(&card->hw, int_status);
- return IRQ_HANDLED;
- }
-
- spin_lock(&card->wandev.lock);
- if (card->next){
- spin_lock(&card->next->wandev.lock);
- }
-
- S514_intack(&card->hw, int_status);
- if (card->isr)
- card->isr(card);
-
- if (card->next){
- spin_unlock(&card->next->wandev.lock);
- }
- spin_unlock(&card->wandev.lock);
-
- /* handle a maximum of two interrupts (one for each */
- /* CPU on the adapter) before returning */
- if((++ IRQ_count) == 2)
- return IRQ_HANDLED;
- }
- }
-
- else { /* handle interrupt on S508 adapter */
-
- if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured))
- return IRQ_HANDLED;
-
- if (card->in_isr) {
- printk(KERN_INFO
- "%s: interrupt re-entrancy on IRQ %d!\n",
- card->devname, card->wandev.irq);
- return IRQ_HANDLED;
- }
-
- spin_lock(&card->wandev.lock);
- if (card->next){
- spin_lock(&card->next->wandev.lock);
- }
-
- sdla_intack(&card->hw);
- if (card->isr)
- card->isr(card);
-
- if (card->next){
- spin_unlock(&card->next->wandev.lock);
- }
- spin_unlock(&card->wandev.lock);
-
- }
- return IRQ_HANDLED;
-#undef card
-}
-
-/*============================================================================
- * This routine is called by the protocol-specific modules when network
- * interface is being open. The only reason we need this, is because we
- * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void wanpipe_open (sdla_t* card)
-{
- ++card->open_cnt;
-}
-
-/*============================================================================
- * This routine is called by the protocol-specific modules when network
- * interface is being closed. The only reason we need this, is because we
- * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void wanpipe_close (sdla_t* card)
-{
- --card->open_cnt;
-}
-
-/*============================================================================
- * Set WAN device state.
- */
-void wanpipe_set_state (sdla_t* card, int state)
-{
- if (card->wandev.state != state) {
- switch (state) {
- case WAN_CONNECTED:
- printk (KERN_INFO "%s: link connected!\n",
- card->devname);
- break;
-
- case WAN_CONNECTING:
- printk (KERN_INFO "%s: link connecting...\n",
- card->devname);
- break;
-
- case WAN_DISCONNECTED:
- printk (KERN_INFO "%s: link disconnected!\n",
- card->devname);
- break;
- }
- card->wandev.state = state;
- }
- card->state_tick = jiffies;
-}
-
-sdla_t * wanpipe_find_card (char *name)
-{
- int cnt;
- for (cnt = 0; cnt < ncards; ++ cnt) {
- sdla_t* card = &card_array[cnt];
- if (!strcmp(card->devname,name))
- return card;
- }
- return NULL;
-}
-
-sdla_t * wanpipe_find_card_num (int num)
-{
- if (num < 1 || num > ncards)
- return NULL;
- num--;
- return &card_array[num];
-}
-
-/*
- * @work_pointer: work_struct to be done;
- * should already have PREPARE_WORK() or
- * INIT_WORK() done on it by caller;
- */
-void wanpipe_queue_work (struct work_struct *work_pointer)
-{
- if (test_and_set_bit(1, (void*)&wanpipe_bh_critical))
- printk(KERN_INFO "CRITICAL IN QUEUING WORK\n");
-
- queue_work(wanpipe_wq, work_pointer);
- clear_bit(1,(void*)&wanpipe_bh_critical);
-}
-
-void wakeup_sk_bh(struct net_device *dev)
-{
- wanpipe_common_t *chan = dev->priv;
-
- if (test_bit(0,&chan->common_critical))
- return;
-
- if (chan->sk && chan->tx_timer){
- chan->tx_timer->expires=jiffies+1;
- add_timer(chan->tx_timer);
- }
-}
-
-int change_dev_flags(struct net_device *dev, unsigned flags)
-{
- struct ifreq if_info;
- mm_segment_t fs = get_fs();
- int err;
-
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
- if_info.ifr_flags = flags;
-
- set_fs(get_ds()); /* get user space block */
- err = devinet_ioctl(SIOCSIFFLAGS, &if_info);
- set_fs(fs);
-
- return err;
-}
-
-unsigned long get_ip_address(struct net_device *dev, int option)
-{
-
- struct in_ifaddr *ifaddr;
- struct in_device *in_dev;
- unsigned long addr = 0;
-
- rcu_read_lock();
- if ((in_dev = __in_dev_get_rcu(dev)) == NULL){
- goto out;
- }
-
- if ((ifaddr = in_dev->ifa_list)== NULL ){
- goto out;
- }
-
- switch (option){
-
- case WAN_LOCAL_IP:
- addr = ifaddr->ifa_local;
- break;
-
- case WAN_POINTOPOINT_IP:
- addr = ifaddr->ifa_address;
- break;
-
- case WAN_NETMASK_IP:
- addr = ifaddr->ifa_mask;
- break;
-
- case WAN_BROADCAST_IP:
- addr = ifaddr->ifa_broadcast;
- break;
- default:
- break;
- }
-
-out:
- rcu_read_unlock();
- return addr;
-}
-
-void add_gateway(sdla_t *card, struct net_device *dev)
-{
- mm_segment_t oldfs;
- struct rtentry route;
- int res;
-
- memset((char*)&route,0,sizeof(struct rtentry));
-
- ((struct sockaddr_in *)
- &(route.rt_dst))->sin_addr.s_addr = 0;
- ((struct sockaddr_in *)
- &(route.rt_dst))->sin_family = AF_INET;
-
- ((struct sockaddr_in *)
- &(route.rt_genmask))->sin_addr.s_addr = 0;
- ((struct sockaddr_in *)
- &(route.rt_genmask)) ->sin_family = AF_INET;
-
-
- route.rt_flags = 0;
- route.rt_dev = dev->name;
-
- oldfs = get_fs();
- set_fs(get_ds());
- res = ip_rt_ioctl(SIOCADDRT,&route);
- set_fs(oldfs);
-
- if (res == 0){
- printk(KERN_INFO "%s: Gateway added for %s\n",
- card->devname,dev->name);
- }
-
- return;
-}
-
-MODULE_LICENSE("GPL");
-
-/****** End *********************************************************/
diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c
deleted file mode 100644
index 812a1183c502..000000000000
--- a/drivers/net/wan/wanpipe_multppp.c
+++ /dev/null
@@ -1,2358 +0,0 @@
-/*****************************************************************************
-* wanpipe_multppp.c Multi-Port PPP driver module.
-*
-* Authors: Nenad Corbic <ncorbic@sangoma.com>
-*
-* Copyright: (c) 1995-2001 Sangoma Technologies Inc.
-*
-* 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.
-* ============================================================================
-* Dec 15 2000 Updated for 2.4.X kernel
-* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher.
-* The pppstruct has changed.
-* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC
-* module.
-*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h> /* printk(), and other useful stuff */
-#include <linux/stddef.h> /* offsetof(), etc. */
-#include <linux/errno.h> /* return codes */
-#include <linux/string.h> /* inline memset(), etc. */
-#include <linux/slab.h> /* kmalloc(), kfree() */
-#include <linux/wanrouter.h> /* WAN router definitions */
-#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
-#include <linux/if_arp.h> /* ARPHRD_* defines */
-#include <linux/jiffies.h> /* time_after() macro */
-
-#include <linux/in.h> /* sockaddr_in */
-#include <linux/inet.h>
-#include <linux/if.h>
-#include <asm/byteorder.h> /* htons(), etc. */
-#include <linux/sdlapci.h>
-#include <asm/io.h>
-
-#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */
-#include <linux/sdla_asy.h> /* CHDLC (async) API definitions */
-
-#include <linux/if_wanpipe_common.h> /* Socket Driver common area */
-#include <linux/if_wanpipe.h>
-
-
-#include <linux/inetdevice.h>
-#include <asm/uaccess.h>
-
-#include <net/syncppp.h>
-
-
-/****** Defines & Macros ****************************************************/
-
-#ifdef _DEBUG_
-#define STATIC
-#else
-#define STATIC static
-#endif
-
-/* reasons for enabling the timer interrupt on the adapter */
-#define TMR_INT_ENABLED_UDP 0x01
-#define TMR_INT_ENABLED_UPDATE 0x02
-#define TMR_INT_ENABLED_CONFIG 0x04
-
-#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */
-#define CHDLC_HDR_LEN 1
-
-#define IFF_POINTTOPOINT 0x10
-
-#define CHDLC_API 0x01
-
-#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" )
-#define MAX_BH_BUFF 10
-
-#define CRC_LENGTH 2
-#define PPP_HEADER_LEN 4
-
-/******Data Structures*****************************************************/
-
-/* This structure is placed in the private data area of the device structure.
- * The card structure used to occupy the private area but now the following
- * structure will incorporate the card structure along with CHDLC specific data
- */
-
-typedef struct chdlc_private_area
-{
- void *if_ptr; /* General Pointer used by SPPP */
- wanpipe_common_t common;
- sdla_t *card;
- int TracingEnabled; /* For enabling Tracing */
- unsigned long curr_trace_addr; /* Used for Tracing */
- unsigned long start_trace_addr;
- unsigned long end_trace_addr;
- unsigned long base_addr_trace_buffer;
- unsigned long end_addr_trace_buffer;
- unsigned short number_trace_elements;
- unsigned available_buffer_space;
- unsigned long router_start_time;
- unsigned char route_status;
- unsigned char route_removed;
- unsigned long tick_counter; /* For 5s timeout counter */
- unsigned long router_up_time;
- u32 IP_address; /* IP addressing */
- u32 IP_netmask;
- unsigned char mc; /* Mulitcast support on/off */
- unsigned short udp_pkt_lgth; /* udp packet processing */
- char udp_pkt_src;
- char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
- unsigned short timer_int_enabled;
- char update_comms_stats; /* updating comms stats */
-
- //FIXME: add driver stats as per frame relay!
-
-} chdlc_private_area_t;
-
-/* Route Status options */
-#define NO_ROUTE 0x00
-#define ADD_ROUTE 0x01
-#define ROUTE_ADDED 0x02
-#define REMOVE_ROUTE 0x03
-
-
-/* variable for keeping track of enabling/disabling FT1 monitor status */
-static int rCount = 0;
-
-/* variable for tracking how many interfaces to open for WANPIPE on the
- two ports */
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
-/****** Function Prototypes *************************************************/
-/* WAN link driver entry points. These are called by the WAN router module. */
-static int update(struct wan_device* wandev);
-static int new_if(struct wan_device* wandev, struct net_device* dev,
- wanif_conf_t* conf);
-static int del_if(struct wan_device* wandev, struct net_device* dev);
-
-/* Network device interface */
-static int if_init(struct net_device* dev);
-static int if_open(struct net_device* dev);
-static int if_close(struct net_device* dev);
-static int if_send(struct sk_buff* skb, struct net_device* dev);
-static struct net_device_stats* if_stats(struct net_device* dev);
-
-static void if_tx_timeout(struct net_device *dev);
-
-/* CHDLC Firmware interface functions */
-static int chdlc_configure (sdla_t* card, void* data);
-static int chdlc_comm_enable (sdla_t* card);
-static int chdlc_comm_disable (sdla_t* card);
-static int chdlc_read_version (sdla_t* card, char* str);
-static int chdlc_set_intr_mode (sdla_t* card, unsigned mode);
-static int chdlc_send (sdla_t* card, void* data, unsigned len);
-static int chdlc_read_comm_err_stats (sdla_t* card);
-static int chdlc_read_op_stats (sdla_t* card);
-static int config_chdlc (sdla_t *card);
-
-
-/* Miscellaneous CHDLC Functions */
-static int set_chdlc_config (sdla_t* card);
-static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev);
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
-static int process_chdlc_exception(sdla_t *card);
-static int process_global_exception(sdla_t *card);
-static int update_comms_stats(sdla_t* card,
- chdlc_private_area_t* chdlc_priv_area);
-static void port_set_state (sdla_t *card, int);
-
-/* Interrupt handlers */
-static void wsppp_isr (sdla_t* card);
-static void rx_intr (sdla_t* card);
-static void timer_intr(sdla_t *);
-
-/* Miscellaneous functions */
-static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static int intr_test( sdla_t* card);
-static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
-static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area);
-static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area);
-static unsigned short calc_checksum (char *, int);
-static void s508_lock (sdla_t *card, unsigned long *smp_flags);
-static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
-static void send_ppp_term_request(struct net_device *dev);
-
-
-static int Intr_test_counter;
-/****** Public Functions ****************************************************/
-
-/*============================================================================
- * Cisco HDLC protocol initialization routine.
- *
- * This routine is called by the main WANPIPE module during setup. At this
- * point adapter is completely initialized and firmware is running.
- * o read firmware version (to make sure it's alive)
- * o configure adapter
- * o initialize protocol-specific fields of the adapter data space.
- *
- * Return: 0 o.k.
- * < 0 failure.
- */
-int wsppp_init (sdla_t* card, wandev_conf_t* conf)
-{
- unsigned char port_num;
- int err;
- unsigned long max_permitted_baud = 0;
- SHARED_MEMORY_INFO_STRUCT *flags;
-
- union
- {
- char str[80];
- } u;
- volatile CHDLC_MAILBOX_STRUCT* mb;
- CHDLC_MAILBOX_STRUCT* mb1;
- unsigned long timeout;
-
- /* Verify configuration ID */
- if (conf->config_id != WANCONFIG_MPPP) {
- printk(KERN_INFO "%s: invalid configuration ID %u!\n",
- card->devname, conf->config_id);
- return -EINVAL;
- }
-
- /* Find out which Port to use */
- if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){
- if (card->next){
-
- if (conf->comm_port != card->next->u.c.comm_port){
- card->u.c.comm_port = conf->comm_port;
- }else{
- printk(KERN_ERR "%s: ERROR - %s port used!\n",
- card->wandev.name, PORT(conf->comm_port));
- return -EINVAL;
- }
- }else{
- card->u.c.comm_port = conf->comm_port;
- }
- }else{
- printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n",
- card->wandev.name);
- return -EINVAL;
- }
-
-
- /* Initialize protocol-specific fields */
- if(card->hw.type != SDLA_S514){
-
- if (card->u.c.comm_port == WANOPT_PRI){
- card->mbox = (void *) card->hw.dpmbase;
- }else{
- card->mbox = (void *) card->hw.dpmbase +
- SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT;
- }
- }else{
- /* for a S514 adapter, set a pointer to the actual mailbox in the */
- /* allocated virtual memory area */
- if (card->u.c.comm_port == WANOPT_PRI){
- card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT;
- }else{
- card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT;
- }
- }
-
- mb = mb1 = card->mbox;
-
- if (!card->configured){
-
- /* The board will place an 'I' in the return code to indicate that it is
- ready to accept commands. We expect this to be completed in less
- than 1 second. */
-
- timeout = jiffies + 1 * HZ;
- while (mb->return_code != 'I') /* Wait 1s for board to initialize */
- if (time_after(jiffies, timeout)) break;
-
- if (mb->return_code != 'I') {
- printk(KERN_INFO
- "%s: Initialization not completed by adapter\n",
- card->devname);
- printk(KERN_INFO "Please contact Sangoma representative.\n");
- return -EIO;
- }
- }
-
- /* Read firmware version. Note that when adapter initializes, it
- * clears the mailbox, so it may appear that the first command was
- * executed successfully when in fact it was merely erased. To work
- * around this, we execute the first command twice.
- */
-
- if (chdlc_read_version(card, u.str))
- return -EIO;
-
- printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n"
- "%s: for Multi-Port PPP protocol.\n",
- card->devname,u.str,card->devname);
-
- card->isr = &wsppp_isr;
- card->poll = NULL;
- card->exec = NULL;
- card->wandev.update = &update;
- card->wandev.new_if = &new_if;
- card->wandev.del_if = &del_if;
- card->wandev.udp_port = conf->udp_port;
-
- card->wandev.new_if_cnt = 0;
-
- /* reset the number of times the 'update()' proc has been called */
- card->u.c.update_call_count = 0;
-
- card->wandev.ttl = conf->ttl;
- card->wandev.interface = conf->interface;
-
- if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&&
- card->hw.type != SDLA_S514){
- printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n",
- card->devname, PORT(card->u.c.comm_port));
- return -EIO;
- }
-
-
- card->wandev.clocking = conf->clocking;
-
- port_num = card->u.c.comm_port;
-
- /* Setup Port Bps */
-
- if(card->wandev.clocking) {
- if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
- /* For Primary Port 0 */
- max_permitted_baud =
- (card->hw.type == SDLA_S514) ?
- PRI_MAX_BAUD_RATE_S514 :
- PRI_MAX_BAUD_RATE_S508;
- }
- else if(port_num == WANOPT_SEC) {
- /* For Secondary Port 1 */
- max_permitted_baud =
- (card->hw.type == SDLA_S514) ?
- SEC_MAX_BAUD_RATE_S514 :
- SEC_MAX_BAUD_RATE_S508;
- }
-
- if(conf->bps > max_permitted_baud) {
- conf->bps = max_permitted_baud;
- printk(KERN_INFO "%s: Baud too high!\n",
- card->wandev.name);
- printk(KERN_INFO "%s: Baud rate set to %lu bps\n",
- card->wandev.name, max_permitted_baud);
- }
-
- card->wandev.bps = conf->bps;
- }else{
- card->wandev.bps = 0;
- }
-
- /* Setup the Port MTU */
- if((port_num == WANOPT_PRI) || card->u.c.receive_only) {
-
- /* For Primary Port 0 */
- card->wandev.mtu =
- (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
- min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) :
- CHDLC_DFLT_DATA_LEN;
- } else if(port_num == WANOPT_SEC) {
- /* For Secondary Port 1 */
- card->wandev.mtu =
- (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ?
- min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) :
- CHDLC_DFLT_DATA_LEN;
- }
-
- /* Add on a PPP Header */
- card->wandev.mtu += PPP_HEADER_LEN;
-
- /* Set up the interrupt status area */
- /* Read the CHDLC Configuration and obtain:
- * Ptr to shared memory infor struct
- * Use this pointer to calculate the value of card->u.c.flags !
- */
- mb1->buffer_length = 0;
- mb1->command = READ_CHDLC_CONFIGURATION;
- err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT;
- if(err != COMMAND_OK) {
- clear_bit(1, (void*)&card->wandev.critical);
-
- if(card->hw.type != SDLA_S514)
- enable_irq(card->hw.irq);
-
- chdlc_error(card, err, mb1);
- return -EIO;
- }
-
- if(card->hw.type == SDLA_S514){
- card->u.c.flags = (void *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
- ptr_shared_mem_info_struct));
- }else{
- card->u.c.flags = (void *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)->
- ptr_shared_mem_info_struct % SDLA_WINDOWSIZE));
- }
-
- flags = card->u.c.flags;
-
- /* This is for the ports link state */
- card->wandev.state = WAN_DUALPORT;
- card->u.c.state = WAN_DISCONNECTED;
-
-
- if (!card->wandev.piggyback){
- err = intr_test(card);
-
- if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) {
- printk(KERN_ERR "%s: Interrupt test failed (%i)\n",
- card->devname, Intr_test_counter);
- printk(KERN_ERR "%s: Please choose another interrupt\n",
- card->devname);
- return -EIO;
- }
-
- printk(KERN_INFO "%s: Interrupt test passed (%i)\n",
- card->devname, Intr_test_counter);
- }
-
-
- if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){
- printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
- card->devname);
- return -EIO;
- }
-
- /* Mask the Timer interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TIMER;
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-/******* WAN Device Driver Entry Points *************************************/
-
-/*============================================================================
- * Update device status & statistics
- * This procedure is called when updating the PROC file system and returns
- * various communications statistics. These statistics are accumulated from 3
- * different locations:
- * 1) The 'if_stats' recorded for the device.
- * 2) Communication error statistics on the adapter.
- * 3) CHDLC operational statistics on the adapter.
- * The board level statistics are read during a timer interrupt. Note that we
- * read the error and operational statistics during consecitive timer ticks so
- * as to minimize the time that we are inside the interrupt handler.
- *
- */
-static int update(struct wan_device* wandev)
-{
- sdla_t* card = wandev->private;
- struct net_device* dev;
- volatile chdlc_private_area_t* chdlc_priv_area;
- SHARED_MEMORY_INFO_STRUCT *flags;
- unsigned long timeout;
-
- /* sanity checks */
- if((wandev == NULL) || (wandev->private == NULL))
- return -EFAULT;
-
- if(wandev->state == WAN_UNCONFIGURED)
- return -ENODEV;
-
- /* more sanity checks */
- if(!card->u.c.flags)
- return -ENODEV;
-
- if((dev=card->wandev.dev) == NULL)
- return -ENODEV;
-
- if((chdlc_priv_area=dev->priv) == NULL)
- return -ENODEV;
-
- flags = card->u.c.flags;
-
- if(chdlc_priv_area->update_comms_stats){
- return -EAGAIN;
- }
-
- /* we will need 2 timer interrupts to complete the */
- /* reading of the statistics */
- chdlc_priv_area->update_comms_stats = 2;
- flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
- chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE;
-
- /* wait a maximum of 1 second for the statistics to be updated */
- timeout = jiffies + 1 * HZ;
- for(;;) {
- if(chdlc_priv_area->update_comms_stats == 0)
- break;
- if (time_after(jiffies, timeout)){
- chdlc_priv_area->update_comms_stats = 0;
- chdlc_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_UPDATE;
- return -EAGAIN;
- }
- }
-
- return 0;
-}
-
-
-/*============================================================================
- * Create new logical channel.
- * This routine is called by the router when ROUTER_IFNEW IOCTL is being
- * handled.
- * o parse media- and hardware-specific configuration
- * o make sure that a new channel can be created
- * o allocate resources, if necessary
- * o prepare network device structure for registaration.
- *
- * Return: 0 o.k.
- * < 0 failure (channel will not be created)
- */
-static int new_if(struct wan_device* wandev, struct net_device* pdev,
- wanif_conf_t* conf)
-{
-
- struct ppp_device *pppdev = (struct ppp_device *)pdev;
- struct net_device *dev = NULL;
- struct sppp *sp;
- sdla_t* card = wandev->private;
- chdlc_private_area_t* chdlc_priv_area;
-
- if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
- printk(KERN_INFO "%s: invalid interface name!\n",
- card->devname);
- return -EINVAL;
- }
-
- /* allocate and initialize private data */
- chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL);
-
- if(chdlc_priv_area == NULL)
- return -ENOMEM;
-
- memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t));
-
- chdlc_priv_area->card = card;
-
- /* initialize data */
- strcpy(card->u.c.if_name, conf->name);
-
- if(card->wandev.new_if_cnt > 0) {
- kfree(chdlc_priv_area);
- return -EEXIST;
- }
-
- card->wandev.new_if_cnt++;
-
- chdlc_priv_area->TracingEnabled = 0;
-
- //We don't need this any more
- chdlc_priv_area->route_status = NO_ROUTE;
- chdlc_priv_area->route_removed = 0;
-
- printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n",
- wandev->name);
-
- /* Setup wanpipe as a router (WANPIPE) or as an API */
- if( strcmp(conf->usedby, "WANPIPE") == 0) {
- printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n",
- wandev->name);
- card->u.c.usedby = WANPIPE;
- } else {
- printk(KERN_INFO
- "%s: API Mode is not supported for SyncPPP!\n",
- wandev->name);
- kfree(chdlc_priv_area);
- return -EINVAL;
- }
-
- /* Get Multicast Information */
- chdlc_priv_area->mc = conf->mc;
-
-
- chdlc_priv_area->if_ptr = pppdev;
-
- /* prepare network device data space for registration */
-
- strcpy(dev->name,card->u.c.if_name);
-
- /* Attach PPP protocol layer to pppdev
- * The sppp_attach() will initilize the dev structure
- * and setup ppp layer protocols.
- * All we have to do is to bind in:
- * if_open(), if_close(), if_send() and get_stats() functions.
- */
- sppp_attach(pppdev);
- dev = pppdev->dev;
- sp = &pppdev->sppp;
-
- /* Enable PPP Debugging */
- // FIXME Fix this up somehow
- //sp->pp_flags |= PP_DEBUG;
- sp->pp_flags &= ~PP_CISCO;
-
- dev->init = &if_init;
- dev->priv = chdlc_priv_area;
-
- return 0;
-}
-
-
-
-
-/*============================================================================
- * Delete logical channel.
- */
-static int del_if(struct wan_device* wandev, struct net_device* dev)
-{
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
- sdla_t *card = chdlc_priv_area->card;
- unsigned long smp_lock;
-
- /* Detach the PPP layer */
- printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n",
- wandev->name,dev->name);
-
- lock_adapter_irq(&wandev->lock,&smp_lock);
-
- sppp_detach(dev);
- chdlc_priv_area->if_ptr=NULL;
-
- chdlc_set_intr_mode(card, 0);
- if (card->u.c.comm_enabled)
- chdlc_comm_disable(card);
- unlock_adapter_irq(&wandev->lock,&smp_lock);
-
- port_set_state(card, WAN_DISCONNECTED);
-
- return 0;
-}
-
-
-/****** Network Device Interface ********************************************/
-
-/*============================================================================
- * Initialize Linux network interface.
- *
- * This routine is called only once for each interface, during Linux network
- * interface registration. Returning anything but zero will fail interface
- * registration.
- */
-static int if_init(struct net_device* dev)
-{
- chdlc_private_area_t* chdlc_priv_area = dev->priv;
- sdla_t* card = chdlc_priv_area->card;
- struct wan_device* wandev = &card->wandev;
-
- /* NOTE: Most of the dev initialization was
- * done in sppp_attach(), called by new_if()
- * function. All we have to do here is
- * to link four major routines below.
- */
-
- /* Initialize device driver entry points */
- dev->open = &if_open;
- dev->stop = &if_close;
- dev->hard_start_xmit = &if_send;
- dev->get_stats = &if_stats;
- dev->tx_timeout = &if_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
-
- /* Initialize hardware parameters */
- dev->irq = wandev->irq;
- dev->dma = wandev->dma;
- dev->base_addr = wandev->ioport;
- dev->mem_start = wandev->maddr;
- dev->mem_end = wandev->maddr + wandev->msize - 1;
-
- /* Set transmit buffer queue length
- * If we over fill this queue the packets will
- * be droped by the kernel.
- * sppp_attach() sets this to 10, but
- * 100 will give us more room at low speeds.
- */
- dev->tx_queue_len = 100;
-
- return 0;
-}
-
-
-/*============================================================================
- * Handle transmit timeout event from netif watchdog
- */
-static void if_tx_timeout(struct net_device *dev)
-{
- chdlc_private_area_t* chan = dev->priv;
- sdla_t *card = chan->card;
-
- /* If our device stays busy for at least 5 seconds then we will
- * kick start the device by making dev->tbusy = 0. We expect
- * that our device never stays busy more than 5 seconds. So this
- * is only used as a last resort.
- */
-
- ++card->wandev.stats.collisions;
-
- printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
- netif_wake_queue (dev);
-}
-
-
-/*============================================================================
- * Open network interface.
- * o enable communications and interrupts.
- * o prevent module from unloading by incrementing use count
- *
- * Return 0 if O.k. or errno.
- */
-static int if_open(struct net_device* dev)
-{
- chdlc_private_area_t* chdlc_priv_area = dev->priv;
- sdla_t* card = chdlc_priv_area->card;
- struct timeval tv;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
-
- /* Only one open per interface is allowed */
- if (netif_running(dev))
- return -EBUSY;
-
- /* Start PPP Layer */
- if (sppp_open(dev)){
- return -EIO;
- }
-
- do_gettimeofday(&tv);
- chdlc_priv_area->router_start_time = tv.tv_sec;
-
- netif_start_queue(dev);
-
- wanpipe_open(card);
-
- chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
- flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER;
- return 0;
-}
-
-/*============================================================================
- * Close network interface.
- * o if this is the last close, then disable communications and interrupts.
- * o reset flags.
- */
-static int if_close(struct net_device* dev)
-{
- chdlc_private_area_t* chdlc_priv_area = dev->priv;
- sdla_t* card = chdlc_priv_area->card;
-
- /* Stop the PPP Layer */
- sppp_close(dev);
- netif_stop_queue(dev);
-
- wanpipe_close(card);
-
- return 0;
-}
-
-/*============================================================================
- * Send a packet on a network interface.
- * o set tbusy flag (marks start of the transmission) to block a timer-based
- * transmit from overlapping.
- * o check link state. If link is not up, then drop the packet.
- * o execute adapter send command.
- * o free socket buffer
- *
- * Return: 0 complete (socket buffer must be freed)
- * non-0 packet may be re-transmitted (tbusy must be set)
- *
- * Notes:
- * 1. This routine is called either by the protocol stack or by the "net
- * bottom half" (with interrupts enabled).
- * 2. Setting tbusy flag will inhibit further transmit requests from the
- * protocol stack and can be used for flow control with protocol layer.
- */
-static int if_send(struct sk_buff* skb, struct net_device* dev)
-{
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
- sdla_t *card = chdlc_priv_area->card;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct;
- int udp_type = 0;
- unsigned long smp_flags;
- int err=0;
-
- netif_stop_queue(dev);
-
-
- if (skb == NULL){
- /* If we get here, some higher layer thinks we've missed an
- * tx-done interrupt.
- */
- printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n",
- card->devname, dev->name);
-
- netif_wake_queue(dev);
- return 0;
- }
-
- if (ntohs(skb->protocol) != htons(PVC_PROT)){
- /* check the udp packet type */
-
- udp_type = udp_pkt_type(skb, card);
- if (udp_type == UDP_CPIPE_TYPE){
- if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev,
- chdlc_priv_area)){
- chdlc_int->interrupt_permission |=
- APP_INT_ON_TIMER;
- }
- netif_start_queue(dev);
- return 0;
- }
- }
-
- /* Lock the 508 Card: SMP is supported */
- if(card->hw.type != SDLA_S514){
- s508_lock(card,&smp_flags);
- }
-
- if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){
-
- printk(KERN_INFO "%s: Critical in if_send: %lx\n",
- card->wandev.name,card->wandev.critical);
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
- goto if_send_crit_exit;
- }
-
- if (card->wandev.state != WAN_CONNECTED){
- ++card->wandev.stats.tx_dropped;
- netif_start_queue(dev);
- goto if_send_crit_exit;
- }
-
- if (chdlc_send(card, skb->data, skb->len)){
- netif_stop_queue(dev);
-
- }else{
- ++card->wandev.stats.tx_packets;
- card->wandev.stats.tx_bytes += skb->len;
- dev->trans_start = jiffies;
- netif_start_queue(dev);
- }
-
-if_send_crit_exit:
- if (!(err=netif_queue_stopped(dev))){
- dev_kfree_skb_any(skb);
- }else{
- chdlc_priv_area->tick_counter = jiffies;
- chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME;
- }
-
- clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
- if(card->hw.type != SDLA_S514){
- s508_unlock(card,&smp_flags);
- }
-
- return err;
-}
-
-
-/*============================================================================
- * Reply to UDP Management system.
- * Return length of reply.
- */
-static int reply_udp( unsigned char *data, unsigned int mbox_len )
-{
-
- unsigned short len, udp_length, temp, ip_length;
- unsigned long ip_temp;
- int even_bound = 0;
- chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data;
-
- /* Set length of packet */
- len = sizeof(ip_pkt_t)+
- sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- sizeof(trace_info_t)+
- mbox_len;
-
- /* fill in UDP reply */
- c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY;
-
- /* fill in UDP length */
- udp_length = sizeof(udp_pkt_t)+
- sizeof(wp_mgmt_t)+
- sizeof(cblock_t)+
- sizeof(trace_info_t)+
- mbox_len;
-
- /* put it on an even boundary */
- if ( udp_length & 0x0001 ) {
- udp_length += 1;
- len += 1;
- even_bound = 1;
- }
-
- temp = (udp_length<<8)|(udp_length>>8);
- c_udp_pkt->udp_pkt.udp_length = temp;
-
- /* swap UDP ports */
- temp = c_udp_pkt->udp_pkt.udp_src_port;
- c_udp_pkt->udp_pkt.udp_src_port =
- c_udp_pkt->udp_pkt.udp_dst_port;
- c_udp_pkt->udp_pkt.udp_dst_port = temp;
-
- /* add UDP pseudo header */
- temp = 0x1100;
- *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp;
- temp = (udp_length<<8)|(udp_length>>8);
- *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp;
-
-
- /* calculate UDP checksum */
- c_udp_pkt->udp_pkt.udp_checksum = 0;
- c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET);
-
- /* fill in IP length */
- ip_length = len;
- temp = (ip_length<<8)|(ip_length>>8);
- c_udp_pkt->ip_pkt.total_length = temp;
-
- /* swap IP addresses */
- ip_temp = c_udp_pkt->ip_pkt.ip_src_address;
- c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address;
- c_udp_pkt->ip_pkt.ip_dst_address = ip_temp;
-
- /* fill in IP checksum */
- c_udp_pkt->ip_pkt.hdr_checksum = 0;
- c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t));
-
- return len;
-
-} /* reply_udp */
-
-unsigned short calc_checksum (char *data, int len)
-{
- unsigned short temp;
- unsigned long sum=0;
- int i;
-
- for( i = 0; i <len; i+=2 ) {
- memcpy(&temp,&data[i],2);
- sum += (unsigned long)temp;
- }
-
- while (sum >> 16 ) {
- sum = (sum & 0xffffUL) + (sum >> 16);
- }
-
- temp = (unsigned short)sum;
- temp = ~temp;
-
- if( temp == 0 )
- temp = 0xffff;
-
- return temp;
-}
-
-
-/*============================================================================
- * Get ethernet-style interface statistics.
- * Return a pointer to struct enet_statistics.
- */
-static struct net_device_stats* if_stats(struct net_device* dev)
-{
- sdla_t *my_card;
- chdlc_private_area_t* chdlc_priv_area;
-
- /* Shutdown bug fix. In del_if() we kill
- * dev->priv pointer. This function, gets
- * called after del_if(), thus check
- * if pointer has been deleted */
- if ((chdlc_priv_area=dev->priv) == NULL)
- return NULL;
-
- my_card = chdlc_priv_area->card;
- return &my_card->wandev.stats;
-}
-
-
-/****** Cisco HDLC Firmware Interface Functions *******************************/
-
-/*============================================================================
- * Read firmware code version.
- * Put code version as ASCII string in str.
- */
-static int chdlc_read_version (sdla_t* card, char* str)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int len;
- char err;
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CODE_VERSION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if(err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- }
- else if (str) { /* is not null */
- len = mb->buffer_length;
- memcpy(str, mb->data, len);
- str[len] = '\0';
- }
- return (err);
-}
-
-/*-----------------------------------------------------------------------------
- * Configure CHDLC firmware.
- */
-static int chdlc_configure (sdla_t* card, void* data)
-{
- int err;
- CHDLC_MAILBOX_STRUCT *mailbox = card->mbox;
- int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT);
-
- mailbox->buffer_length = data_length;
- memcpy(mailbox->data, data, data_length);
- mailbox->command = SET_CHDLC_CONFIGURATION;
- err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT;
-
- if (err != COMMAND_OK) chdlc_error (card, err, mailbox);
-
- return err;
-}
-
-
-/*============================================================================
- * Set interrupt mode -- HDLC Version.
- */
-
-static int chdlc_set_intr_mode (sdla_t* card, unsigned mode)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- CHDLC_INT_TRIGGERS_STRUCT* int_data =
- (CHDLC_INT_TRIGGERS_STRUCT *)mb->data;
- int err;
-
- int_data->CHDLC_interrupt_triggers = mode;
- int_data->IRQ = card->hw.irq;
- int_data->interrupt_timer = 1;
-
- mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT);
- mb->command = SET_CHDLC_INTERRUPT_TRIGGERS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error (card, err, mb);
- return err;
-}
-
-
-/*============================================================================
- * Enable communications.
- */
-
-static int chdlc_comm_enable (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = ENABLE_CHDLC_COMMUNICATIONS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card, err, mb);
- else
- card->u.c.comm_enabled=1;
-
- return err;
-}
-
-/*============================================================================
- * Disable communications and Drop the Modem lines (DCD and RTS).
- */
-static int chdlc_comm_disable (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = DISABLE_CHDLC_COMMUNICATIONS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card,err,mb);
-
- return err;
-}
-
-/*============================================================================
- * Read communication error statistics.
- */
-static int chdlc_read_comm_err_stats (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = READ_COMMS_ERROR_STATS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card,err,mb);
- return err;
-}
-
-
-/*============================================================================
- * Read CHDLC operational statistics.
- */
-static int chdlc_read_op_stats (sdla_t* card)
-{
- int err;
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_OPERATIONAL_STATS;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK)
- chdlc_error(card,err,mb);
- return err;
-}
-
-
-/*============================================================================
- * Update communications error and general packet statistics.
- */
-static int update_comms_stats(sdla_t* card,
- chdlc_private_area_t* chdlc_priv_area)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- COMMS_ERROR_STATS_STRUCT* err_stats;
- CHDLC_OPERATIONAL_STATS_STRUCT *op_stats;
-
- /* on the first timer interrupt, read the comms error statistics */
- if(chdlc_priv_area->update_comms_stats == 2) {
- if(chdlc_read_comm_err_stats(card))
- return 1;
- err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data;
- card->wandev.stats.rx_over_errors =
- err_stats->Rx_overrun_err_count;
- card->wandev.stats.rx_crc_errors =
- err_stats->CRC_err_count;
- card->wandev.stats.rx_frame_errors =
- err_stats->Rx_abort_count;
- card->wandev.stats.rx_fifo_errors =
- err_stats->Rx_dis_pri_bfrs_full_count;
- card->wandev.stats.rx_missed_errors =
- card->wandev.stats.rx_fifo_errors;
- card->wandev.stats.tx_aborted_errors =
- err_stats->sec_Tx_abort_count;
- }
-
- /* on the second timer interrupt, read the operational statistics */
- else {
- if(chdlc_read_op_stats(card))
- return 1;
- op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data;
- card->wandev.stats.rx_length_errors =
- (op_stats->Rx_Data_discard_short_count +
- op_stats->Rx_Data_discard_long_count);
- }
-
- return 0;
-}
-
-/*============================================================================
- * Send packet.
- * Return: 0 - o.k.
- * 1 - no transmit buffers available
- */
-static int chdlc_send (sdla_t* card, void* data, unsigned len)
-{
- CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf;
-
- if (txbuf->opp_flag)
- return 1;
-
- sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len);
-
- txbuf->frame_length = len;
- txbuf->opp_flag = 1; /* start transmission */
-
- /* Update transmit buffer control fields */
- card->u.c.txbuf = ++txbuf;
-
- if ((void*)txbuf > card->u.c.txbuf_last)
- card->u.c.txbuf = card->u.c.txbuf_base;
-
- return 0;
-}
-
-/****** Firmware Error Handler **********************************************/
-
-/*============================================================================
- * Firmware error handler.
- * This routine is called whenever firmware command returns non-zero
- * return code.
- *
- * Return zero if previous command has to be cancelled.
- */
-static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb)
-{
- unsigned cmd = mb->command;
-
- switch (err) {
-
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!\n",
- card->devname, cmd);
- break;
-
- case S514_BOTH_PORTS_SAME_CLK_MODE:
- if(cmd == SET_CHDLC_CONFIGURATION) {
- printk(KERN_INFO
- "%s: Configure both ports for the same clock source\n",
- card->devname);
- break;
- }
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n",
- card->devname, cmd, err);
- }
-
- return 0;
-}
-
-/****** Interrupt Handlers **************************************************/
-
-/*============================================================================
- * Cisco HDLC interrupt service routine.
- */
-STATIC void wsppp_isr (sdla_t* card)
-{
- struct net_device* dev;
- SHARED_MEMORY_INFO_STRUCT* flags = NULL;
- int i;
- sdla_t *my_card;
-
-
- /* Check for which port the interrupt has been generated
- * Since Secondary Port is piggybacking on the Primary
- * the check must be done here.
- */
-
- flags = card->u.c.flags;
- if (!flags->interrupt_info_struct.interrupt_type){
- /* Check for a second port (piggybacking) */
- if((my_card = card->next)){
- flags = my_card->u.c.flags;
- if (flags->interrupt_info_struct.interrupt_type){
- card = my_card;
- card->isr(card);
- return;
- }
- }
- }
-
- dev = card->wandev.dev;
- card->in_isr = 1;
- flags = card->u.c.flags;
-
- /* If we get an interrupt with no network device, stop the interrupts
- * and issue an error */
- if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type !=
- COMMAND_COMPLETE_APP_INT_PEND){
- goto isr_done;
- }
-
-
- /* if critical due to peripheral operations
- * ie. update() or getstats() then reset the interrupt and
- * wait for the board to retrigger.
- */
- if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
- flags->interrupt_info_struct.
- interrupt_type = 0;
- goto isr_done;
- }
-
-
- /* On a 508 Card, if critical due to if_send
- * Major Error !!!
- */
- if(card->hw.type != SDLA_S514) {
- if(test_bit(0, (void*)&card->wandev.critical)) {
- printk(KERN_INFO "%s: Critical while in ISR: %lx\n",
- card->devname, card->wandev.critical);
- goto isr_done;
- }
- }
-
- switch(flags->interrupt_info_struct.interrupt_type) {
-
- case RX_APP_INT_PEND: /* 0x01: receive interrupt */
- rx_intr(card);
- break;
-
- case TX_APP_INT_PEND: /* 0x02: transmit interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TX_FRAME;
-
- netif_wake_queue(dev);
- break;
-
- case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
- ++ Intr_test_counter;
- break;
-
- case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */
- process_chdlc_exception(card);
- break;
-
- case GLOBAL_EXCEP_COND_APP_INT_PEND:
- process_global_exception(card);
- break;
-
- case TIMER_APP_INT_PEND:
- timer_intr(card);
- break;
-
- default:
- printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n",
- card->devname,
- flags->interrupt_info_struct.interrupt_type);
- printk(KERN_INFO "Code name: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codename[i]);
- printk(KERN_INFO "\nCode version: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codeversion[i]);
- printk(KERN_INFO "\n");
- break;
- }
-
-isr_done:
- card->in_isr = 0;
- flags->interrupt_info_struct.interrupt_type = 0;
-}
-
-/*============================================================================
- * Receive interrupt handler.
- */
-static void rx_intr (sdla_t* card)
-{
- struct net_device *dev;
- chdlc_private_area_t *chdlc_priv_area;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb;
- struct sk_buff *skb;
- unsigned len;
- unsigned addr = rxbuf->ptr_data_bfr;
- void *buf;
- int i,udp_type;
-
- if (rxbuf->opp_flag != 0x01) {
- printk(KERN_INFO
- "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
- card->devname, (unsigned)rxbuf, rxbuf->opp_flag);
- printk(KERN_INFO "Code name: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codename[i]);
- printk(KERN_INFO "\nCode version: ");
- for(i = 0; i < 4; i ++)
- printk(KERN_INFO "%c",
- flags->global_info_struct.codeversion[i]);
- printk(KERN_INFO "\n");
-
-
- /* Bug Fix: Mar 6 2000
- * If we get a corrupted mailbox, it measn that driver
- * is out of sync with the firmware. There is no recovery.
- * If we don't turn off all interrupts for this card
- * the machine will crash.
- */
- printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname);
- printk(KERN_INFO "Please contact Sangoma Technologies !\n");
- chdlc_set_intr_mode(card,0);
- return;
- }
-
- dev = card->wandev.dev;
-
- if (!dev){
- goto rx_exit;
- }
-
- if (!netif_running(dev)){
- goto rx_exit;
- }
-
- chdlc_priv_area = dev->priv;
-
- if (rxbuf->error_flag){
- goto rx_exit;
- }
- /* Take off two CRC bytes */
-
- if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){
- goto rx_exit;
- }
-
- len = rxbuf->frame_length - CRC_LENGTH;
-
- /* Allocate socket buffer */
- skb = dev_alloc_skb(len);
-
- if (skb == NULL) {
- if (net_ratelimit()){
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- }
- ++card->wandev.stats.rx_dropped;
- goto rx_exit;
- }
-
- /* Copy data to the socket buffer */
- if((addr + len) > card->u.c.rx_top + 1) {
- unsigned tmp = card->u.c.rx_top - addr + 1;
- buf = skb_put(skb, tmp);
- sdla_peek(&card->hw, addr, buf, tmp);
- addr = card->u.c.rx_base;
- len -= tmp;
- }
-
- buf = skb_put(skb, len);
- sdla_peek(&card->hw, addr, buf, len);
-
- skb->protocol = htons(ETH_P_WAN_PPP);
-
- card->wandev.stats.rx_packets ++;
- card->wandev.stats.rx_bytes += skb->len;
- udp_type = udp_pkt_type( skb, card );
-
- if(udp_type == UDP_CPIPE_TYPE) {
- if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK,
- card, skb, dev, chdlc_priv_area)) {
- flags->interrupt_info_struct.
- interrupt_permission |=
- APP_INT_ON_TIMER;
- }
- }else{
- /* Pass it up the protocol stack */
- skb->dev = dev;
- skb->mac.raw = skb->data;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
-
-rx_exit:
- /* Release buffer element and calculate a pointer to the next one */
- rxbuf->opp_flag = 0x00;
- card->u.c.rxmb = ++ rxbuf;
- if((void*)rxbuf > card->u.c.rxbuf_last){
- card->u.c.rxmb = card->u.c.rxbuf_base;
- }
-}
-
-/*============================================================================
- * Timer interrupt handler.
- * The timer interrupt is used for two purposes:
- * 1) Processing udp calls from 'cpipemon'.
- * 2) Reading board-level statistics for updating the proc file system.
- */
-void timer_intr(sdla_t *card)
-{
- struct net_device* dev;
- chdlc_private_area_t* chdlc_priv_area = NULL;
- SHARED_MEMORY_INFO_STRUCT* flags = NULL;
-
- dev = card->wandev.dev;
- chdlc_priv_area = dev->priv;
-
- if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) {
- if (!config_chdlc(card)){
- chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG;
- }
- }
-
- /* process a udp call if pending */
- if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) {
- process_udp_mgmt_pkt(card, dev,
- chdlc_priv_area);
- chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
- }
-
-
- /* read the communications statistics if required */
- if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
- update_comms_stats(card, chdlc_priv_area);
- if(!(-- chdlc_priv_area->update_comms_stats)) {
- chdlc_priv_area->timer_int_enabled &=
- ~TMR_INT_ENABLED_UPDATE;
- }
- }
-
- /* only disable the timer interrupt if there are no udp or statistic */
- /* updates pending */
- if(!chdlc_priv_area->timer_int_enabled) {
- flags = card->u.c.flags;
- flags->interrupt_info_struct.interrupt_permission &=
- ~APP_INT_ON_TIMER;
- }
-}
-
-/*------------------------------------------------------------------------------
- Miscellaneous Functions
- - set_chdlc_config() used to set configuration options on the board
-------------------------------------------------------------------------------*/
-
-static int set_chdlc_config(sdla_t* card)
-{
-
- CHDLC_CONFIGURATION_STRUCT cfg;
-
- memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT));
-
- if(card->wandev.clocking)
- cfg.baud_rate = card->wandev.bps;
-
- cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
- INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
-
- cfg.modem_config_options = 0;
- //API OPTIONS
- cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES;
- cfg.modem_status_timer = 100;
- cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE;
- cfg.percent_data_buffer_for_Tx = 50;
- cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT |
- CHDLC_RX_DATA_BYTE_COUNT_STAT);
- cfg.max_CHDLC_data_field_length = card->wandev.mtu;
-
- cfg.transmit_keepalive_timer = 0;
- cfg.receive_keepalive_timer = 0;
- cfg.keepalive_error_tolerance = 0;
- cfg.SLARP_request_timer = 0;
-
- cfg.IP_address = 0;
- cfg.IP_netmask = 0;
-
- return chdlc_configure(card, &cfg);
-}
-
-/*============================================================================
- * Process global exception condition
- */
-static int process_global_exception(sdla_t *card)
-{
- CHDLC_MAILBOX_STRUCT* mbox = card->mbox;
- int err;
-
- mbox->buffer_length = 0;
- mbox->command = READ_GLOBAL_EXCEPTION_CONDITION;
- err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT;
-
- if(err != CMD_TIMEOUT ){
-
- switch(mbox->return_code) {
-
- case EXCEP_MODEM_STATUS_CHANGE:
-
- printk(KERN_INFO "%s: Modem status change\n",
- card->devname);
-
- switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) {
- case (DCD_HIGH):
- printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname);
- break;
- case (CTS_HIGH):
- printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname);
- break;
- case ((DCD_HIGH | CTS_HIGH)):
- printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname);
- break;
- default:
- printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname);
- break;
- }
-
- if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){
- //printk(KERN_INFO "Sending TERM Request Manually !\n");
- send_ppp_term_request(card->wandev.dev);
- }
- break;
-
- case EXCEP_TRC_DISABLED:
- printk(KERN_INFO "%s: Line trace disabled\n",
- card->devname);
- break;
-
- case EXCEP_IRQ_TIMEOUT:
- printk(KERN_INFO "%s: IRQ timeout occurred\n",
- card->devname);
- break;
-
- default:
- printk(KERN_INFO "%s: Global exception %x\n",
- card->devname, mbox->return_code);
- break;
- }
- }
- return 0;
-}
-
-
-/*============================================================================
- * Process chdlc exception condition
- */
-static int process_chdlc_exception(sdla_t *card)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int err;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_EXCEPTION_CONDITION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if(err != CMD_TIMEOUT) {
-
- switch (err) {
-
- case EXCEP_LINK_ACTIVE:
- port_set_state(card, WAN_CONNECTED);
- break;
-
- case EXCEP_LINK_INACTIVE_MODEM:
- port_set_state(card, WAN_DISCONNECTED);
- break;
-
- case EXCEP_LOOPBACK_CONDITION:
- printk(KERN_INFO "%s: Loopback Condition Detected.\n",
- card->devname);
- break;
-
- case NO_CHDLC_EXCEP_COND_TO_REPORT:
- printk(KERN_INFO "%s: No exceptions reported.\n",
- card->devname);
- break;
- default:
- printk(KERN_INFO "%s: Exception Condition %x!\n",
- card->devname,err);
- break;
- }
-
- }
- return 0;
-}
-
-
-/*=============================================================================
- * Store a UDP management packet for later processing.
- */
-
-static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area )
-{
- int udp_pkt_stored = 0;
-
- if(!chdlc_priv_area->udp_pkt_lgth &&
- (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) {
- chdlc_priv_area->udp_pkt_lgth = skb->len;
- chdlc_priv_area->udp_pkt_src = udp_pkt_src;
- memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len);
- chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP;
- udp_pkt_stored = 1;
- }
-
- if(udp_pkt_src == UDP_PKT_FRM_STACK)
- dev_kfree_skb_any(skb);
- else
- dev_kfree_skb_any(skb);
-
- return(udp_pkt_stored);
-}
-
-
-/*=============================================================================
- * Process UDP management packet.
- */
-
-static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
- chdlc_private_area_t* chdlc_priv_area )
-{
- unsigned char *buf;
- unsigned int frames, len;
- struct sk_buff *new_skb;
- unsigned short buffer_length, real_len;
- unsigned long data_ptr;
- unsigned data_length;
- int udp_mgmt_req_valid = 1;
- CHDLC_MAILBOX_STRUCT *mb = card->mbox;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
- chdlc_udp_pkt_t *chdlc_udp_pkt;
- struct timeval tv;
- int err;
- char ut_char;
-
- chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data;
-
- if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- switch(chdlc_udp_pkt->cblock.command) {
- case READ_GLOBAL_STATISTICS:
- case READ_MODEM_STATUS:
- case READ_CHDLC_LINK_STATUS:
- case CPIPE_ROUTER_UP_TIME:
- case READ_COMMS_ERROR_STATS:
- case READ_CHDLC_OPERATIONAL_STATS:
-
- /* These two commands are executed for
- * each request */
- case READ_CHDLC_CONFIGURATION:
- case READ_CHDLC_CODE_VERSION:
- udp_mgmt_req_valid = 1;
- break;
- default:
- udp_mgmt_req_valid = 0;
- break;
- }
- }
-
- if(!udp_mgmt_req_valid) {
-
- /* set length to 0 */
- chdlc_udp_pkt->cblock.buffer_length = 0;
-
- /* set return code */
- chdlc_udp_pkt->cblock.return_code = 0xCD;
-
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Warning, Illegal UDP command attempted from network: %x\n",
- card->devname,chdlc_udp_pkt->cblock.command);
- }
-
- } else {
- unsigned long trace_status_cfg_addr = 0;
- TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct;
- TRACE_STATUS_ELEMENT_STRUCT trace_element_struct;
-
- switch(chdlc_udp_pkt->cblock.command) {
-
- case CPIPE_ENABLE_TRACING:
- if (!chdlc_priv_area->TracingEnabled) {
-
- /* OPERATE_DATALINE_MONITOR */
-
- mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
- mb->command = SET_TRACE_CONFIGURATION;
-
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
- trace_config = TRACE_ACTIVE;
- /* Trace delay mode is not used because it slows
- down transfer and results in a standoff situation
- when there is a lot of data */
-
- /* Configure the Trace based on user inputs */
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |=
- chdlc_udp_pkt->data[0];
-
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
- trace_deactivation_timer = 4000;
-
-
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- card->TracingEnabled = 0;
- chdlc_udp_pkt->cblock.return_code = err;
- mb->buffer_length = 0;
- break;
- }
-
- /* Get the base address of the trace element list */
- mb->buffer_length = 0;
- mb->command = READ_TRACE_CONFIGURATION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if (err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- chdlc_priv_area->TracingEnabled = 0;
- chdlc_udp_pkt->cblock.return_code = err;
- mb->buffer_length = 0;
- break;
- }
-
- trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *)
- mb->data) -> ptr_trace_stat_el_cfg_struct;
-
- sdla_peek(&card->hw, trace_status_cfg_addr,
- &trace_cfg_struct, sizeof(trace_cfg_struct));
-
- chdlc_priv_area->start_trace_addr = trace_cfg_struct.
- base_addr_trace_status_elements;
-
- chdlc_priv_area->number_trace_elements =
- trace_cfg_struct.number_trace_status_elements;
-
- chdlc_priv_area->end_trace_addr = (unsigned long)
- ((TRACE_STATUS_ELEMENT_STRUCT *)
- chdlc_priv_area->start_trace_addr +
- (chdlc_priv_area->number_trace_elements - 1));
-
- chdlc_priv_area->base_addr_trace_buffer =
- trace_cfg_struct.base_addr_trace_buffer;
-
- chdlc_priv_area->end_addr_trace_buffer =
- trace_cfg_struct.end_addr_trace_buffer;
-
- chdlc_priv_area->curr_trace_addr =
- trace_cfg_struct.next_trace_element_to_use;
-
- chdlc_priv_area->available_buffer_space = 2000 -
- sizeof(ip_pkt_t) -
- sizeof(udp_pkt_t) -
- sizeof(wp_mgmt_t) -
- sizeof(cblock_t) -
- sizeof(trace_info_t);
- }
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- mb->buffer_length = 0;
- chdlc_priv_area->TracingEnabled = 1;
- break;
-
-
- case CPIPE_DISABLE_TRACING:
- if (chdlc_priv_area->TracingEnabled) {
-
- /* OPERATE_DATALINE_MONITOR */
- mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT);
- mb->command = SET_TRACE_CONFIGURATION;
- ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->
- trace_config = TRACE_INACTIVE;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- }
-
- chdlc_priv_area->TracingEnabled = 0;
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- mb->buffer_length = 0;
- break;
-
-
- case CPIPE_GET_TRACE_INFO:
-
- if (!chdlc_priv_area->TracingEnabled) {
- chdlc_udp_pkt->cblock.return_code = 1;
- mb->buffer_length = 0;
- break;
- }
-
- chdlc_udp_pkt->trace_info.ismoredata = 0x00;
- buffer_length = 0; /* offset of packet already occupied */
-
- for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){
-
- trace_pkt_t *trace_pkt = (trace_pkt_t *)
- &chdlc_udp_pkt->data[buffer_length];
-
- sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr,
- (unsigned char *)&trace_element_struct,
- sizeof(TRACE_STATUS_ELEMENT_STRUCT));
-
- if (trace_element_struct.opp_flag == 0x00) {
- break;
- }
-
- /* get pointer to real data */
- data_ptr = trace_element_struct.ptr_data_bfr;
-
- /* See if there is actual data on the trace buffer */
- if (data_ptr){
- data_length = trace_element_struct.trace_length;
- }else{
- data_length = 0;
- chdlc_udp_pkt->trace_info.ismoredata = 0x01;
- }
-
- if( (chdlc_priv_area->available_buffer_space - buffer_length)
- < ( sizeof(trace_pkt_t) + data_length) ) {
-
- /* indicate there are more frames on board & exit */
- chdlc_udp_pkt->trace_info.ismoredata = 0x01;
- break;
- }
-
- trace_pkt->status = trace_element_struct.trace_type;
-
- trace_pkt->time_stamp =
- trace_element_struct.trace_time_stamp;
-
- trace_pkt->real_length =
- trace_element_struct.trace_length;
-
- /* see if we can fit the frame into the user buffer */
- real_len = trace_pkt->real_length;
-
- if (data_ptr == 0) {
- trace_pkt->data_avail = 0x00;
- } else {
- unsigned tmp = 0;
-
- /* get the data from circular buffer
- must check for end of buffer */
- trace_pkt->data_avail = 0x01;
-
- if ((data_ptr + real_len) >
- chdlc_priv_area->end_addr_trace_buffer + 1){
-
- tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1;
- sdla_peek(&card->hw, data_ptr,
- trace_pkt->data,tmp);
- data_ptr = chdlc_priv_area->base_addr_trace_buffer;
- }
-
- sdla_peek(&card->hw, data_ptr,
- &trace_pkt->data[tmp], real_len - tmp);
- }
-
- /* zero the opp flag to show we got the frame */
- ut_char = 0x00;
- sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1);
-
- /* now move onto the next frame */
- chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT);
-
- /* check if we went over the last address */
- if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) {
- chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr;
- }
-
- if(trace_pkt->data_avail == 0x01) {
- buffer_length += real_len - 1;
- }
-
- /* for the header */
- buffer_length += sizeof(trace_pkt_t);
-
- } /* For Loop */
-
- if (frames == chdlc_priv_area->number_trace_elements){
- chdlc_udp_pkt->trace_info.ismoredata = 0x01;
- }
- chdlc_udp_pkt->trace_info.num_frames = frames;
-
- mb->buffer_length = buffer_length;
- chdlc_udp_pkt->cblock.buffer_length = buffer_length;
-
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
-
- break;
-
-
- case CPIPE_FT1_READ_STATUS:
- ((unsigned char *)chdlc_udp_pkt->data )[0] =
- flags->FT1_info_struct.parallel_port_A_input;
-
- ((unsigned char *)chdlc_udp_pkt->data )[1] =
- flags->FT1_info_struct.parallel_port_B_input;
-
- chdlc_udp_pkt->cblock.return_code = COMMAND_OK;
- mb->buffer_length = 2;
- break;
-
- case CPIPE_ROUTER_UP_TIME:
- do_gettimeofday( &tv );
- chdlc_priv_area->router_up_time = tv.tv_sec -
- chdlc_priv_area->router_start_time;
- *(unsigned long *)&chdlc_udp_pkt->data =
- chdlc_priv_area->router_up_time;
- mb->buffer_length = sizeof(unsigned long);
- break;
-
- case FT1_MONITOR_STATUS_CTRL:
- /* Enable FT1 MONITOR STATUS */
- if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) ||
- (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) {
-
- if( rCount++ != 0 ) {
- chdlc_udp_pkt->cblock.
- return_code = COMMAND_OK;
- mb->buffer_length = 1;
- break;
- }
- }
-
- /* Disable FT1 MONITOR STATUS */
- if( chdlc_udp_pkt->data[0] == 0) {
-
- if( --rCount != 0) {
- chdlc_udp_pkt->cblock.
- return_code = COMMAND_OK;
- mb->buffer_length = 1;
- break;
- }
- }
-
- default:
- /* it's a board command */
- mb->command = chdlc_udp_pkt->cblock.command;
- mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length;
- if (mb->buffer_length) {
- memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt->
- data, mb->buffer_length);
- }
- /* run the command on the board */
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- if (err != COMMAND_OK) {
- break;
- }
-
- /* copy the result back to our buffer */
- memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t));
-
- if (mb->buffer_length) {
- memcpy(&chdlc_udp_pkt->data, &mb->data,
- mb->buffer_length);
- }
-
- } /* end of switch */
- } /* end of else */
-
- /* Fill UDP TTL */
- chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
-
- len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length);
-
- if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) {
- ++ card->wandev.stats.tx_packets;
- card->wandev.stats.tx_bytes += len;
- }
- } else {
-
- /* Pass it up the stack
- Allocate socket buffer */
- if ((new_skb = dev_alloc_skb(len)) != NULL) {
- /* copy data into new_skb */
-
- buf = skb_put(new_skb, len);
- memcpy(buf, chdlc_priv_area->udp_pkt_data, len);
-
- /* Decapsulate pkt and pass it up the protocol stack */
- new_skb->protocol = htons(ETH_P_IP);
- new_skb->dev = dev;
- new_skb->mac.raw = new_skb->data;
-
- netif_rx(new_skb);
- dev->last_rx = jiffies;
- } else {
-
- printk(KERN_INFO "%s: no socket buffers available!\n",
- card->devname);
- }
- }
-
- chdlc_priv_area->udp_pkt_lgth = 0;
-
- return 0;
-}
-
-/*============================================================================
- * Initialize Receive and Transmit Buffers.
- */
-
-static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config;
- CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config;
- char err;
-
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CONFIGURATION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
-
- if(err != COMMAND_OK) {
- chdlc_error(card,err,mb);
- return;
- }
-
- if(card->hw.type == SDLA_S514) {
- tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Tx_stat_el_cfg_struct));
- rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Rx_stat_el_cfg_struct));
-
- /* Setup Head and Tails for buffers */
- card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
- tx_config->base_addr_Tx_status_elements);
- card->u.c.txbuf_last =
- (CHDLC_DATA_TX_STATUS_EL_STRUCT *)
- card->u.c.txbuf_base +
- (tx_config->number_Tx_status_elements - 1);
-
- card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
- rx_config->base_addr_Rx_status_elements);
- card->u.c.rxbuf_last =
- (CHDLC_DATA_RX_STATUS_EL_STRUCT *)
- card->u.c.rxbuf_base +
- (rx_config->number_Rx_status_elements - 1);
-
- /* Set up next pointer to be used */
- card->u.c.txbuf = (void *)(card->hw.dpmbase +
- tx_config->next_Tx_status_element_to_use);
- card->u.c.rxmb = (void *)(card->hw.dpmbase +
- rx_config->next_Rx_status_element_to_use);
- }
- else {
- tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
-
- rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase +
- (((CHDLC_CONFIGURATION_STRUCT *)mb->data)->
- ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE));
-
- /* Setup Head and Tails for buffers */
- card->u.c.txbuf_base = (void *)(card->hw.dpmbase +
- (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE));
- card->u.c.txbuf_last =
- (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base
- + (tx_config->number_Tx_status_elements - 1);
- card->u.c.rxbuf_base = (void *)(card->hw.dpmbase +
- (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE));
- card->u.c.rxbuf_last =
- (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base
- + (rx_config->number_Rx_status_elements - 1);
-
- /* Set up next pointer to be used */
- card->u.c.txbuf = (void *)(card->hw.dpmbase +
- (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE));
- card->u.c.rxmb = (void *)(card->hw.dpmbase +
- (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE));
- }
-
- /* Setup Actual Buffer Start and end addresses */
- card->u.c.rx_base = rx_config->base_addr_Rx_buffer;
- card->u.c.rx_top = rx_config->end_addr_Rx_buffer;
-
-}
-
-/*=============================================================================
- * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR
- * _TEST_COUNTER times.
- */
-static int intr_test( sdla_t* card)
-{
- CHDLC_MAILBOX_STRUCT* mb = card->mbox;
- int err,i;
-
- Intr_test_counter = 0;
-
- /* The critical flag is unset because during initialization (if_open)
- * we want the interrupts to be enabled so that when the wpc_isr is
- * called it does not exit due to critical flag set.
- */
-
- err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE);
-
- if (err == CMD_OK) {
- for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {
- mb->buffer_length = 0;
- mb->command = READ_CHDLC_CODE_VERSION;
- err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT;
- }
- }
- else {
- return err;
- }
-
- err = chdlc_set_intr_mode(card, 0);
-
- if (err != CMD_OK)
- return err;
-
- return 0;
-}
-
-/*==============================================================================
- * Determine what type of UDP call it is. CPIPEAB ?
- */
-static int udp_pkt_type(struct sk_buff *skb, sdla_t* card)
-{
- chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data;
-
- if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) &&
- (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) &&
- (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
- (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) {
- return UDP_CPIPE_TYPE;
- }
- else return UDP_INVALID_TYPE;
-}
-
-/*============================================================================
- * Set PORT state.
- */
-static void port_set_state (sdla_t *card, int state)
-{
- struct net_device *dev = card->wandev.dev;
- chdlc_private_area_t *chdlc_priv_area = dev->priv;
-
- if (card->u.c.state != state)
- {
- switch (state)
- {
- case WAN_CONNECTED:
- printk (KERN_INFO "%s: HDLC link connected!\n",
- card->devname);
- break;
-
- case WAN_CONNECTING:
- printk (KERN_INFO "%s: HDLC link connecting...\n",
- card->devname);
- break;
-
- case WAN_DISCONNECTED:
- printk (KERN_INFO "%s: HDLC link disconnected!\n",
- card->devname);
- break;
- }
-
- card->wandev.state = card->u.c.state = state;
- chdlc_priv_area->common.state = state;
- }
-}
-
-void s508_lock (sdla_t *card, unsigned long *smp_flags)
-{
- spin_lock_irqsave(&card->wandev.lock, *smp_flags);
- if (card->next){
- /* It is ok to use spin_lock here, since we
- * already turned off interrupts */
- spin_lock(&card->next->wandev.lock);
- }
-}
-
-void s508_unlock (sdla_t *card, unsigned long *smp_flags)
-{
- if (card->next){
- spin_unlock(&card->next->wandev.lock);
- }
- spin_unlock_irqrestore(&card->wandev.lock, *smp_flags);
-}
-
-
-
-/*===========================================================================
- * config_chdlc
- *
- * Configure the chdlc protocol and enable communications.
- *
- * The if_open() function binds this function to the poll routine.
- * Therefore, this function will run every time the chdlc interface
- * is brought up. We cannot run this function from the if_open
- * because if_open does not have access to the remote IP address.
- *
- * If the communications are not enabled, proceed to configure
- * the card and enable communications.
- *
- * If the communications are enabled, it means that the interface
- * was shutdown by ether the user or driver. In this case, we
- * have to check that the IP addresses have not changed. If
- * the IP addresses have changed, we have to reconfigure the firmware
- * and update the changed IP addresses. Otherwise, just exit.
- *
- */
-
-static int config_chdlc (sdla_t *card)
-{
- struct net_device *dev = card->wandev.dev;
- SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
-
- if (card->u.c.comm_enabled){
- chdlc_comm_disable(card);
- port_set_state(card, WAN_DISCONNECTED);
- }
-
- if (set_chdlc_config(card)) {
- printk(KERN_INFO "%s: CHDLC Configuration Failed!\n",
- card->devname);
- return 0;
- }
- init_chdlc_tx_rx_buff(card, dev);
-
- /* Set interrupt mode and mask */
- if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME |
- APP_INT_ON_GLOBAL_EXCEP_COND |
- APP_INT_ON_TX_FRAME |
- APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){
- printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
- card->devname);
- return 0;
- }
-
-
- /* Mask the Transmit and Timer interrupt */
- flags->interrupt_info_struct.interrupt_permission &=
- ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER);
-
-
- if (chdlc_comm_enable(card) != 0) {
- printk(KERN_INFO "%s: Failed to enable chdlc communications!\n",
- card->devname);
- flags->interrupt_info_struct.interrupt_permission = 0;
- card->u.c.comm_enabled=0;
- chdlc_set_intr_mode(card,0);
- return 0;
- }
-
- /* Initialize Rx/Tx buffer control fields */
- port_set_state(card, WAN_CONNECTING);
- return 0;
-}
-
-
-static void send_ppp_term_request(struct net_device *dev)
-{
- struct sk_buff *new_skb;
- unsigned char *buf;
-
- if ((new_skb = dev_alloc_skb(8)) != NULL) {
- /* copy data into new_skb */
-
- buf = skb_put(new_skb, 8);
- sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07);
-
- /* Decapsulate pkt and pass it up the protocol stack */
- new_skb->protocol = htons(ETH_P_WAN_PPP);
- new_skb->dev = dev;
- new_skb->mac.raw = new_skb->data;
-
- netif_rx(new_skb);
- dev->last_rx = jiffies;
- }
-}
-
-
-MODULE_LICENSE("GPL");
-
-/****** End ****************************************************************/
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index d121644646b9..98b83a85c60e 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -100,8 +100,6 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
- { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 929dd8090578..65d090dbef46 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -147,6 +147,16 @@ config RTC_DRV_SA1100
To compile this driver as a module, choose M here: the
module will be called rtc-sa1100.
+config RTC_DRV_VR41XX
+ tristate "NEC VR41XX"
+ depends on RTC_CLASS && CPU_VR41XX
+ help
+ If you say Y here you will get access to the real time clock
+ built into your NEC VR41XX CPU.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-vr41xx.
+
config RTC_DRV_TEST
tristate "Test driver/device"
depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 8d4c7fe88d58..a9ca0f171686 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
+obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 8533936d50d8..413c7d54ea10 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -96,6 +96,8 @@ exit_idr:
idr_remove(&rtc_idr, id);
exit:
+ dev_err(dev, "rtc core: unable to register %s, err = %d\n",
+ name, err);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rtc_device_register);
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 358695a416f3..9be81fd4737c 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -1,6 +1,8 @@
/*
* An rtc/i2c driver for the Dallas DS1672
- * Copyright 2005 Alessandro Zummo
+ * Copyright 2005-06 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,7 +13,7 @@
#include <linux/i2c.h>
#include <linux/rtc.h>
-#define DRV_VERSION "0.2"
+#define DRV_VERSION "0.3"
/* Addresses to scan: none. This chip cannot be detected. */
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
@@ -25,6 +27,7 @@ I2C_CLIENT_INSMOD;
#define DS1672_REG_CONTROL 4
#define DS1672_REG_TRICKLE 5
+#define DS1672_REG_CONTROL_EOSC 0x80
/* Prototypes */
static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
@@ -53,8 +56,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev,
"%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
- __FUNCTION__,
- buf[0], buf[1], buf[2], buf[3]);
+ __FUNCTION__, buf[0], buf[1], buf[2], buf[3]);
time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
@@ -62,8 +64,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
+ __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
return 0;
@@ -72,16 +73,17 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
{
int xfer;
- unsigned char buf[5];
+ unsigned char buf[6];
buf[0] = DS1672_REG_CNT_BASE;
buf[1] = secs & 0x000000FF;
buf[2] = (secs & 0x0000FF00) >> 8;
buf[3] = (secs & 0x00FF0000) >> 16;
buf[4] = (secs & 0xFF000000) >> 24;
+ buf[5] = 0; /* set control reg to enable counting */
- xfer = i2c_master_send(client, buf, 5);
- if (xfer != 5) {
+ xfer = i2c_master_send(client, buf, 6);
+ if (xfer != 6) {
dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
return -EIO;
}
@@ -120,6 +122,40 @@ static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
return ds1672_set_mmss(to_i2c_client(dev), secs);
}
+static int ds1672_get_control(struct i2c_client *client, u8 *status)
+{
+ unsigned char addr = DS1672_REG_CONTROL;
+
+ struct i2c_msg msgs[] = {
+ { client->addr, 0, 1, &addr }, /* setup read ptr */
+ { client->addr, I2C_M_RD, 1, status }, /* read control */
+ };
+
+ /* read control register */
+ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_control(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 control;
+ int err;
+
+ err = ds1672_get_control(client, &control);
+ if (err)
+ return err;
+
+ return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC)
+ ? "disabled" : "enabled");
+}
+static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
+
static struct rtc_class_ops ds1672_rtc_ops = {
.read_time = ds1672_rtc_read_time,
.set_time = ds1672_rtc_set_time,
@@ -128,7 +164,6 @@ static struct rtc_class_ops ds1672_rtc_ops = {
static int ds1672_attach(struct i2c_adapter *adapter)
{
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
return i2c_probe(adapter, &addr_data, ds1672_probe);
}
@@ -137,8 +172,6 @@ static int ds1672_detach(struct i2c_client *client)
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __FUNCTION__);
-
if (rtc)
rtc_device_unregister(rtc);
@@ -162,6 +195,7 @@ static struct i2c_driver ds1672_driver = {
static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
{
int err = 0;
+ u8 control;
struct i2c_client *client;
struct rtc_device *rtc;
@@ -195,13 +229,23 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
goto exit_detach;
}
i2c_set_clientdata(client, rtc);
+ /* read control register */
+ err = ds1672_get_control(client, &control);
+ if (err)
+ goto exit_detach;
+
+ if (control & DS1672_REG_CONTROL_EOSC)
+ dev_warn(&client->dev, "Oscillator not enabled. "
+ "Set time to enable.\n");
+
+ /* Register sysfs hooks */
+ device_create_file(&client->dev, &dev_attr_control);
+
return 0;
exit_detach:
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 0dd80ea686a9..e1a1169e4664 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -67,7 +67,6 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
ep93xx_get_swcomp(dev, &preload, &delete);
- seq_printf(seq, "24hr\t\t: yes\n");
seq_printf(seq, "preload\t\t: %d\n", preload);
seq_printf(seq, "delete\t\t: %d\n", delete);
@@ -110,7 +109,6 @@ static int __devinit ep93xx_rtc_probe(struct platform_device *dev)
&dev->dev, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
- dev_err(&dev->dev, "unable to register\n");
return PTR_ERR(rtc);
}
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index db445c872b1b..f6e7ee04f3dc 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -23,7 +23,7 @@
#define M48T86_REG_SECALRM 0x01
#define M48T86_REG_MIN 0x02
#define M48T86_REG_MINALRM 0x03
-#define M48T86_REG_HOUR 0x04
+#define M48T86_REG_HOUR 0x04
#define M48T86_REG_HOURALRM 0x05
#define M48T86_REG_DOW 0x06 /* 1 = sunday */
#define M48T86_REG_DOM 0x07
@@ -127,9 +127,6 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
reg = ops->readb(M48T86_REG_B);
- seq_printf(seq, "24hr\t\t: %s\n",
- (reg & M48T86_REG_B_H24) ? "yes" : "no");
-
seq_printf(seq, "mode\t\t: %s\n",
(reg & M48T86_REG_B_DM) ? "binary" : "bcd");
@@ -154,10 +151,8 @@ static int __devinit m48t86_rtc_probe(struct platform_device *dev)
struct rtc_device *rtc = rtc_device_register("m48t86",
&dev->dev, &m48t86_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- dev_err(&dev->dev, "unable to register\n");
+ if (IS_ERR(rtc))
return PTR_ERR(rtc);
- }
platform_set_drvdata(dev, rtc);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index d857d45bdbe8..ba9a583b7b68 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -227,14 +227,7 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
return pcf8563_set_datetime(to_i2c_client(dev), tm);
}
-static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq)
-{
- seq_printf(seq, "24hr\t\t: yes\n");
- return 0;
-}
-
static struct rtc_class_ops pcf8563_rtc_ops = {
- .proc = pcf8563_rtc_proc,
.read_time = pcf8563_rtc_read_time,
.set_time = pcf8563_rtc_set_time,
};
@@ -297,8 +290,6 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
goto exit_detach;
}
@@ -321,8 +312,6 @@ static int pcf8563_detach(struct i2c_client *client)
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __FUNCTION__);
-
if (rtc)
rtc_device_unregister(rtc);
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index 90b8a97a0919..cef5f5a3bbf9 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -71,6 +71,8 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
alrm.pending ? "yes" : "no");
}
+ seq_printf(seq, "24hr\t\t: yes\n");
+
if (ops->proc)
ops->proc(class_dev->dev, seq);
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 396c8681f66c..7553d797603f 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -151,9 +151,8 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
{
int err, osc, trim;
- seq_printf(seq, "24hr\t\t: yes\n");
-
- if ((err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim)) == 0) {
+ err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim);
+ if (err == 0) {
seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000);
seq_printf(seq, "trim\t: %d\n", trim);
}
@@ -170,30 +169,31 @@ static struct rtc_class_ops rs5c372_rtc_ops = {
static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int trim;
+ int err, trim;
- if (rs5c372_get_trim(to_i2c_client(dev), NULL, &trim) == 0)
- return sprintf(buf, "0x%2x\n", trim);
+ err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim);
+ if (err)
+ return err;
- return 0;
+ return sprintf(buf, "0x%2x\n", trim);
}
static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);
static ssize_t rs5c372_sysfs_show_osc(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int osc;
+ int err, osc;
- if (rs5c372_get_trim(to_i2c_client(dev), &osc, NULL) == 0)
- return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);
+ err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL);
+ if (err)
+ return err;
- return 0;
+ return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);
}
static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);
static int rs5c372_attach(struct i2c_adapter *adapter)
{
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
return i2c_probe(adapter, &addr_data, rs5c372_probe);
}
@@ -233,8 +233,6 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
goto exit_detach;
}
@@ -260,8 +258,6 @@ static int rs5c372_detach(struct i2c_client *client)
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __FUNCTION__);
-
if (rtc)
rtc_device_unregister(rtc);
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 83b2bb480a16..a23ec54989f6 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -160,19 +160,19 @@ static int sa1100_rtc_open(struct device *dev)
ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT,
"rtc 1Hz", dev);
if (ret) {
- printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
+ dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz);
goto fail_ui;
}
ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT,
"rtc Alrm", dev);
if (ret) {
- printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
+ dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
goto fail_ai;
}
ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT,
"rtc timer", dev);
if (ret) {
- printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1);
+ dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1);
goto fail_pi;
}
return 0;
@@ -332,7 +332,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
*/
if (RTTR == 0) {
RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
- printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
+ dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n");
/* The current RTC value probably doesn't make sense either */
RCNR = 0;
}
@@ -340,15 +340,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
THIS_MODULE);
- if (IS_ERR(rtc)) {
- dev_err(&pdev->dev, "Unable to register the RTC device\n");
+ if (IS_ERR(rtc))
return PTR_ERR(rtc);
- }
platform_set_drvdata(pdev, rtc);
- dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n");
-
return 0;
}
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index 43d107487820..e1f7e8e86daf 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -49,7 +49,6 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct platform_device *plat_dev = to_platform_device(dev);
- seq_printf(seq, "24hr\t\t: yes\n");
seq_printf(seq, "test\t\t: yes\n");
seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
@@ -120,8 +119,6 @@ static int test_probe(struct platform_device *plat_dev)
&test_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- dev_err(&plat_dev->dev,
- "unable to register the class device\n");
return err;
}
device_create_file(&plat_dev->dev, &dev_attr_irq);
diff --git a/drivers/char/vr41xx_rtc.c b/drivers/rtc/rtc-vr41xx.c
index b109d9a502d6..4d49fd501198 100644
--- a/drivers/char/vr41xx_rtc.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -1,7 +1,7 @@
/*
- * Driver for NEC VR4100 series Real Time Clock unit.
+ * Driver for NEC VR4100 series Real Time Clock unit.
*
- * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2006 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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
@@ -17,23 +17,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/irq.h>
-#include <linux/mc146818rtc.h>
-#include <linux/miscdevice.h>
#include <linux/module.h>
-#include <linux/poll.h>
+#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/spinlock.h>
#include <linux/types.h>
-#include <linux/wait.h>
#include <asm/div64.h>
#include <asm/io.h>
-#include <asm/time.h>
#include <asm/uaccess.h>
#include <asm/vr41xx/vr41xx.h>
@@ -99,27 +94,11 @@ static void __iomem *rtc2_base;
static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */
-static spinlock_t rtc_task_lock;
-static wait_queue_head_t rtc_wait;
-static unsigned long rtc_irq_data;
-static struct fasync_struct *rtc_async_queue;
-static rtc_task_t *rtc_callback;
+static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
static char rtc_name[] = "RTC";
static unsigned long periodic_frequency;
static unsigned long periodic_count;
-typedef enum {
- RTC_RELEASE,
- RTC_OPEN,
-} rtc_status_t;
-
-static rtc_status_t rtc_status;
-
-typedef enum {
- FUNCTION_RTC_IOCTL,
- FUNCTION_RTC_CONTROL,
-} rtc_callfrom_t;
-
struct resource rtc_resource[2] = {
{ .name = rtc_name,
.flags = IORESOURCE_MEM, },
@@ -129,7 +108,9 @@ struct resource rtc_resource[2] = {
static inline unsigned long read_elapsed_second(void)
{
+
unsigned long first_low, first_mid, first_high;
+
unsigned long second_low, second_mid, second_high;
do {
@@ -156,50 +137,36 @@ static inline void write_elapsed_second(unsigned long sec)
spin_unlock_irq(&rtc_lock);
}
-static void set_alarm(struct rtc_time *time)
+static void vr41xx_rtc_release(struct device *dev)
{
- unsigned long alarm_sec;
-
- alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
- time->tm_hour, time->tm_min, time->tm_sec);
-
- spin_lock_irq(&rtc_lock);
-
- rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
- rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
- rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
-
- spin_unlock_irq(&rtc_lock);
-}
-
-static void read_alarm(struct rtc_time *time)
-{
- unsigned long low, mid, high;
spin_lock_irq(&rtc_lock);
- low = rtc1_read(ECMPLREG);
- mid = rtc1_read(ECMPMREG);
- high = rtc1_read(ECMPHREG);
+ rtc1_write(ECMPLREG, 0);
+ rtc1_write(ECMPMREG, 0);
+ rtc1_write(ECMPHREG, 0);
+ rtc1_write(RTCL1LREG, 0);
+ rtc1_write(RTCL1HREG, 0);
spin_unlock_irq(&rtc_lock);
- to_tm((high << 17) | (mid << 1) | (low >> 15), time);
- time->tm_year -= 1900;
+ disable_irq(ELAPSEDTIME_IRQ);
+ disable_irq(RTCLONG1_IRQ);
}
-static void read_time(struct rtc_time *time)
+static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time)
{
unsigned long epoch_sec, elapsed_sec;
epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
elapsed_sec = read_elapsed_second();
- to_tm(epoch_sec + elapsed_sec, time);
- time->tm_year -= 1900;
+ rtc_time_to_tm(epoch_sec + elapsed_sec, time);
+
+ return 0;
}
-static void set_time(struct rtc_time *time)
+static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time)
{
unsigned long epoch_sec, current_sec;
@@ -208,73 +175,49 @@ static void set_time(struct rtc_time *time)
time->tm_hour, time->tm_min, time->tm_sec);
write_elapsed_second(current_sec - epoch_sec);
+
+ return 0;
}
-static ssize_t rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long irq_data;
- int retval = 0;
-
- if (count != sizeof(unsigned int) && count != sizeof(unsigned long))
- return -EINVAL;
-
- add_wait_queue(&rtc_wait, &wait);
-
- do {
- __set_current_state(TASK_INTERRUPTIBLE);
+ unsigned long low, mid, high;
+ struct rtc_time *time = &wkalrm->time;
- spin_lock_irq(&rtc_lock);
- irq_data = rtc_irq_data;
- rtc_irq_data = 0;
- spin_unlock_irq(&rtc_lock);
+ spin_lock_irq(&rtc_lock);
- if (irq_data != 0)
- break;
+ low = rtc1_read(ECMPLREG);
+ mid = rtc1_read(ECMPMREG);
+ high = rtc1_read(ECMPHREG);
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
+ spin_unlock_irq(&rtc_lock);
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- } while (1);
+ rtc_time_to_tm((high << 17) | (mid << 1) | (low >> 15), time);
- if (retval == 0) {
- if (count == sizeof(unsigned int)) {
- retval = put_user(irq_data, (unsigned int __user *)buf);
- if (retval == 0)
- retval = sizeof(unsigned int);
- } else {
- retval = put_user(irq_data, (unsigned long __user *)buf);
- if (retval == 0)
- retval = sizeof(unsigned long);
- }
+ return 0;
+}
- }
+static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+ unsigned long alarm_sec;
+ struct rtc_time *time = &wkalrm->time;
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&rtc_wait, &wait);
+ alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
- return retval;
-}
+ spin_lock_irq(&rtc_lock);
-static unsigned int rtc_poll(struct file *file, struct poll_table_struct *table)
-{
- poll_wait(file, &rtc_wait, table);
+ rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
+ rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
+ rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
- if (rtc_irq_data != 0)
- return POLLIN | POLLRDNORM;
+ spin_unlock_irq(&rtc_lock);
return 0;
}
-static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from)
+static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
- struct rtc_time time;
unsigned long count;
switch (cmd) {
@@ -290,33 +233,6 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from
case RTC_PIE_OFF:
disable_irq(RTCLONG1_IRQ);
break;
- case RTC_ALM_SET:
- if (copy_from_user(&time, (struct rtc_time __user *)arg,
- sizeof(struct rtc_time)))
- return -EFAULT;
-
- set_alarm(&time);
- break;
- case RTC_ALM_READ:
- memset(&time, 0, sizeof(struct rtc_time));
- read_alarm(&time);
- break;
- case RTC_RD_TIME:
- memset(&time, 0, sizeof(struct rtc_time));
- read_time(&time);
- if (copy_to_user((void __user *)arg, &time, sizeof(struct rtc_time)))
- return -EFAULT;
- break;
- case RTC_SET_TIME:
- if (capable(CAP_SYS_TIME) == 0)
- return -EACCES;
-
- if (copy_from_user(&time, (struct rtc_time __user *)arg,
- sizeof(struct rtc_time)))
- return -EFAULT;
-
- set_time(&time);
- break;
case RTC_IRQP_READ:
return put_user(periodic_frequency, (unsigned long __user *)arg);
break;
@@ -324,8 +240,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from
if (arg > MAX_PERIODIC_RATE)
return -EINVAL;
- if (from == FUNCTION_RTC_IOCTL && arg > MAX_USER_PERIODIC_RATE &&
- capable(CAP_SYS_RESOURCE) == 0)
+ if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0)
return -EACCES;
periodic_frequency = arg;
@@ -361,205 +276,46 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from
return 0;
}
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return rtc_do_ioctl(cmd, arg, FUNCTION_RTC_IOCTL);
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
- spin_lock_irq(&rtc_lock);
-
- if (rtc_status == RTC_OPEN) {
- spin_unlock_irq(&rtc_lock);
- return -EBUSY;
- }
-
- rtc_status = RTC_OPEN;
- rtc_irq_data = 0;
-
- spin_unlock_irq(&rtc_lock);
-
- return 0;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
- if (file->f_flags & FASYNC)
- (void)fasync_helper(-1, file, 0, &rtc_async_queue);
-
- spin_lock_irq(&rtc_lock);
-
- rtc1_write(ECMPLREG, 0);
- rtc1_write(ECMPMREG, 0);
- rtc1_write(ECMPHREG, 0);
- rtc1_write(RTCL1LREG, 0);
- rtc1_write(RTCL1HREG, 0);
-
- rtc_status = RTC_RELEASE;
-
- spin_unlock_irq(&rtc_lock);
-
- disable_irq(ELAPSEDTIME_IRQ);
- disable_irq(RTCLONG1_IRQ);
-
- return 0;
-}
-
-static int rtc_fasync(int fd, struct file *file, int on)
-{
- return fasync_helper(fd, file, on, &rtc_async_queue);
-}
-
-static struct file_operations rtc_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = rtc_read,
- .poll = rtc_poll,
- .ioctl = rtc_ioctl,
- .open = rtc_open,
- .release = rtc_release,
- .fasync = rtc_fasync,
-};
-
static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- spin_lock(&rtc_lock);
- rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
-
- rtc_irq_data += 0x100;
- rtc_irq_data &= ~0xff;
- rtc_irq_data |= RTC_AF;
- spin_unlock(&rtc_lock);
+ struct platform_device *pdev = (struct platform_device *)dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
- spin_lock(&rtc_lock);
- if (rtc_callback)
- rtc_callback->func(rtc_callback->private_data);
- spin_unlock(&rtc_lock);
-
- wake_up_interruptible(&rtc_wait);
+ rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
- kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+ rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
return IRQ_HANDLED;
}
static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+ struct platform_device *pdev = (struct platform_device *)dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
unsigned long count = periodic_count;
- spin_lock(&rtc_lock);
rtc2_write(RTCINTREG, RTCLONG1_INT);
rtc1_write(RTCL1LREG, count);
rtc1_write(RTCL1HREG, count >> 16);
- rtc_irq_data += 0x100;
- rtc_irq_data &= ~0xff;
- rtc_irq_data |= RTC_PF;
- spin_unlock(&rtc_lock);
-
- spin_lock(&rtc_task_lock);
- if (rtc_callback)
- rtc_callback->func(rtc_callback->private_data);
- spin_unlock(&rtc_task_lock);
-
- wake_up_interruptible(&rtc_wait);
-
- kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
+ rtc_update_irq(&rtc->class_dev, 1, RTC_PF);
return IRQ_HANDLED;
}
-int rtc_register(rtc_task_t *task)
-{
- if (task == NULL || task->func == NULL)
- return -EINVAL;
-
- spin_lock_irq(&rtc_lock);
- if (rtc_status == RTC_OPEN) {
- spin_unlock_irq(&rtc_lock);
- return -EBUSY;
- }
-
- spin_lock(&rtc_task_lock);
- if (rtc_callback != NULL) {
- spin_unlock(&rtc_task_lock);
- spin_unlock_irq(&rtc_task_lock);
- return -EBUSY;
- }
-
- rtc_callback = task;
- spin_unlock(&rtc_task_lock);
-
- rtc_status = RTC_OPEN;
-
- spin_unlock_irq(&rtc_lock);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(rtc_register);
-
-int rtc_unregister(rtc_task_t *task)
-{
- spin_lock_irq(&rtc_task_lock);
- if (task == NULL || rtc_callback != task) {
- spin_unlock_irq(&rtc_task_lock);
- return -ENXIO;
- }
-
- spin_lock(&rtc_lock);
-
- rtc1_write(ECMPLREG, 0);
- rtc1_write(ECMPMREG, 0);
- rtc1_write(ECMPHREG, 0);
- rtc1_write(RTCL1LREG, 0);
- rtc1_write(RTCL1HREG, 0);
-
- rtc_status = RTC_RELEASE;
-
- spin_unlock(&rtc_lock);
-
- rtc_callback = NULL;
-
- spin_unlock_irq(&rtc_task_lock);
-
- disable_irq(ELAPSEDTIME_IRQ);
- disable_irq(RTCLONG1_IRQ);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(rtc_unregister);
-
-int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
-{
- int retval = 0;
-
- spin_lock_irq(&rtc_task_lock);
-
- if (rtc_callback != task)
- retval = -ENXIO;
- else
- rtc_do_ioctl(cmd, arg, FUNCTION_RTC_CONTROL);
-
- spin_unlock_irq(&rtc_task_lock);
-
- return retval;
-}
-
-EXPORT_SYMBOL_GPL(rtc_control);
-
-static struct miscdevice rtc_miscdevice = {
- .minor = RTC_MINOR,
- .name = rtc_name,
- .fops = &rtc_fops,
+static struct rtc_class_ops vr41xx_rtc_ops = {
+ .release = vr41xx_rtc_release,
+ .ioctl = vr41xx_rtc_ioctl,
+ .read_time = vr41xx_rtc_read_time,
+ .set_time = vr41xx_rtc_set_time,
+ .read_alarm = vr41xx_rtc_read_alarm,
+ .set_alarm = vr41xx_rtc_set_alarm,
};
static int __devinit rtc_probe(struct platform_device *pdev)
{
+ struct rtc_device *rtc;
unsigned int irq;
int retval;
@@ -577,13 +333,13 @@ static int __devinit rtc_probe(struct platform_device *pdev)
return -EBUSY;
}
- retval = misc_register(&rtc_miscdevice);
- if (retval < 0) {
+ rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
iounmap(rtc1_base);
iounmap(rtc2_base);
rtc1_base = NULL;
rtc2_base = NULL;
- return retval;
+ return PTR_ERR(rtc);
}
spin_lock_irq(&rtc_lock);
@@ -594,24 +350,20 @@ static int __devinit rtc_probe(struct platform_device *pdev)
rtc1_write(RTCL1LREG, 0);
rtc1_write(RTCL1HREG, 0);
- rtc_status = RTC_RELEASE;
- rtc_irq_data = 0;
-
spin_unlock_irq(&rtc_lock);
- init_waitqueue_head(&rtc_wait);
-
irq = ELAPSEDTIME_IRQ;
retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT,
- "elapsed_time", NULL);
+ "elapsed_time", pdev);
if (retval == 0) {
irq = RTCLONG1_IRQ;
retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT,
- "rtclong1", NULL);
+ "rtclong1", pdev);
}
if (retval < 0) {
printk(KERN_ERR "rtc: IRQ%d is busy\n", irq);
+ rtc_device_unregister(rtc);
if (irq == RTCLONG1_IRQ)
free_irq(ELAPSEDTIME_IRQ, NULL);
iounmap(rtc1_base);
@@ -621,23 +373,25 @@ static int __devinit rtc_probe(struct platform_device *pdev)
return retval;
}
+ platform_set_drvdata(pdev, rtc);
+
disable_irq(ELAPSEDTIME_IRQ);
disable_irq(RTCLONG1_IRQ);
- spin_lock_init(&rtc_task_lock);
-
printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
return 0;
}
-static int __devexit rtc_remove(struct platform_device *dev)
+static int __devexit rtc_remove(struct platform_device *pdev)
{
- int retval;
+ struct rtc_device *rtc;
- retval = misc_deregister(&rtc_miscdevice);
- if (retval < 0)
- return retval;
+ rtc = platform_get_drvdata(pdev);
+ if (rtc != NULL)
+ rtc_device_unregister(rtc);
+
+ platform_set_drvdata(pdev, NULL);
free_irq(ELAPSEDTIME_IRQ, NULL);
free_irq(RTCLONG1_IRQ, NULL);
@@ -651,7 +405,7 @@ static int __devexit rtc_remove(struct platform_device *dev)
static struct platform_device *rtc_platform_device;
-static struct platform_driver rtc_device_driver = {
+static struct platform_driver rtc_platform_driver = {
.probe = rtc_probe,
.remove = __devexit_p(rtc_remove),
.driver = {
@@ -686,7 +440,7 @@ static int __init vr41xx_rtc_init(void)
}
rtc_platform_device = platform_device_alloc("RTC", -1);
- if (!rtc_platform_device)
+ if (rtc_platform_device == NULL)
return -ENOMEM;
retval = platform_device_add_resources(rtc_platform_device,
@@ -700,7 +454,7 @@ static int __init vr41xx_rtc_init(void)
return retval;
}
- retval = platform_driver_register(&rtc_device_driver);
+ retval = platform_driver_register(&rtc_platform_driver);
if (retval < 0)
platform_device_unregister(rtc_platform_device);
@@ -709,7 +463,7 @@ static int __init vr41xx_rtc_init(void)
static void __exit vr41xx_rtc_exit(void)
{
- platform_driver_unregister(&rtc_device_driver);
+ platform_driver_unregister(&rtc_platform_driver);
platform_device_unregister(rtc_platform_device);
}
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 621d17afc0d9..788b6d1f8f2f 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -19,7 +19,7 @@
#include <linux/rtc.h>
#include <linux/delay.h>
-#define DRV_VERSION "1.0.6"
+#define DRV_VERSION "1.0.7"
/* Addresses to scan: none. This chip is located at
* 0x6f and uses a two bytes register addressing.
@@ -451,8 +451,6 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
{
int err, dtrim, atrim;
- seq_printf(seq, "24hr\t\t: yes\n");
-
if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
@@ -473,30 +471,31 @@ static struct rtc_class_ops x1205_rtc_ops = {
static ssize_t x1205_sysfs_show_atrim(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int atrim;
+ int err, atrim;
- if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0)
- return sprintf(buf, "%d.%02d pF\n",
- atrim / 1000, atrim % 1000);
- return 0;
+ err = x1205_get_atrim(to_i2c_client(dev), &atrim);
+ if (err)
+ return err;
+
+ return sprintf(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000);
}
static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int dtrim;
+ int err, dtrim;
- if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0)
- return sprintf(buf, "%d ppm\n", dtrim);
+ err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
+ if (err)
+ return err;
- return 0;
+ return sprintf(buf, "%d ppm\n", dtrim);
}
static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
static int x1205_attach(struct i2c_adapter *adapter)
{
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
return i2c_probe(adapter, &addr_data, x1205_probe);
}
@@ -545,8 +544,6 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
goto exit_detach;
}
@@ -585,8 +582,6 @@ static int x1205_detach(struct i2c_client *client)
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "%s\n", __FUNCTION__);
-
if (rtc)
rtc_device_unregister(rtc);
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 0a9f12c4e911..a3bfebcf31ef 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1257,25 +1257,28 @@ __dasd_start_head(struct dasd_device * device)
if (list_empty(&device->ccw_queue))
return;
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
- /* check FAILFAST */
+ if (cqr->status != DASD_CQR_QUEUED)
+ return;
+ /* Non-temporary stop condition will trigger fail fast */
if (device->stopped & ~DASD_STOPPED_PENDING &&
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
(!dasd_eer_enabled(device))) {
cqr->status = DASD_CQR_FAILED;
dasd_schedule_bh(device);
+ return;
}
- if ((cqr->status == DASD_CQR_QUEUED) &&
- (!device->stopped)) {
- /* try to start the first I/O that can be started */
- rc = device->discipline->start_IO(cqr);
- if (rc == 0)
- dasd_set_timer(device, cqr->expires);
- else if (rc == -EACCES) {
- dasd_schedule_bh(device);
- } else
- /* Hmpf, try again in 1/2 sec */
- dasd_set_timer(device, 50);
- }
+ /* Don't try to start requests if device is stopped */
+ if (device->stopped)
+ return;
+
+ rc = device->discipline->start_IO(cqr);
+ if (rc == 0)
+ dasd_set_timer(device, cqr->expires);
+ else if (rc == -EACCES) {
+ dasd_schedule_bh(device);
+ } else
+ /* Hmpf, try again in 1/2 sec */
+ dasd_set_timer(device, 50);
}
/*
@@ -1968,7 +1971,7 @@ int
dasd_generic_set_offline (struct ccw_device *cdev)
{
struct dasd_device *device;
- int max_count;
+ int max_count, open_count;
device = dasd_device_from_cdev(cdev);
if (IS_ERR(device))
@@ -1985,10 +1988,16 @@ dasd_generic_set_offline (struct ccw_device *cdev)
* in the other openers.
*/
max_count = device->bdev ? 0 : -1;
- if (atomic_read(&device->open_count) > max_count) {
- printk (KERN_WARNING "Can't offline dasd device with open"
- " count = %i.\n",
- atomic_read(&device->open_count));
+ open_count = (int) atomic_read(&device->open_count);
+ if (open_count > max_count) {
+ if (open_count > 0)
+ printk (KERN_WARNING "Can't offline dasd device with "
+ "open count = %i.\n",
+ open_count);
+ else
+ printk (KERN_WARNING "%s",
+ "Can't offline dasd device due to internal "
+ "use\n");
clear_bit(DASD_FLAG_OFFLINE, &device->flags);
dasd_put_device(device);
return -EBUSY;
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 1aa3c261718a..ad23aede356c 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -294,23 +294,40 @@ out_error:
#endif /* CONFIG_DASD_PROFILE */
}
+/*
+ * Create dasd proc-fs entries.
+ * In case creation failed, cleanup and return -ENOENT.
+ */
int
dasd_proc_init(void)
{
dasd_proc_root_entry = proc_mkdir("dasd", &proc_root);
+ if (!dasd_proc_root_entry)
+ goto out_nodasd;
dasd_proc_root_entry->owner = THIS_MODULE;
dasd_devices_entry = create_proc_entry("devices",
S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry);
+ if (!dasd_devices_entry)
+ goto out_nodevices;
dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
dasd_devices_entry->owner = THIS_MODULE;
dasd_statistics_entry = create_proc_entry("statistics",
S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry);
+ if (!dasd_statistics_entry)
+ goto out_nostatistics;
dasd_statistics_entry->read_proc = dasd_statistics_read;
dasd_statistics_entry->write_proc = dasd_statistics_write;
dasd_statistics_entry->owner = THIS_MODULE;
return 0;
+
+ out_nostatistics:
+ remove_proc_entry("devices", dasd_proc_root_entry);
+ out_nodevices:
+ remove_proc_entry("dasd", &proc_root);
+ out_nodasd:
+ return -ENOENT;
}
void
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 6badd8403409..d4d2ff0a9da2 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -54,7 +54,7 @@ kbd_alloc(void) {
if (!kbd)
goto out;
kbd->key_maps = kzalloc(sizeof(key_maps), GFP_KERNEL);
- if (!key_maps)
+ if (!kbd->key_maps)
goto out_kbd;
for (i = 0; i < ARRAY_SIZE(key_maps); i++) {
if (key_maps[i]) {
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 5c65cf3e5cc0..b70d92690242 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -432,8 +432,8 @@ tapeblock_ioctl(
) {
int rc;
int minor;
- struct gendisk *disk = inode->i_bdev->bd_disk;
- struct tape_device *device = disk->private_data;
+ struct gendisk *disk;
+ struct tape_device *device;
rc = 0;
disk = inode->i_bdev->bd_disk;
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 389ee2c0f443..e6e4086d3224 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -210,18 +210,14 @@ tape_state_set(struct tape_device *device, enum tape_state newstate)
return;
}
DBF_EVENT(4, "ts. dev: %x\n", device->first_minor);
- if (device->tape_state < TO_SIZE && device->tape_state >= 0)
- str = tape_state_verbose[device->tape_state];
- else
- str = "UNKNOWN TS";
- DBF_EVENT(4, "old ts: %s\n", str);
- if (device->tape_state < TO_SIZE && device->tape_state >=0 )
+ DBF_EVENT(4, "old ts:\t\n");
+ if (device->tape_state < TS_SIZE && device->tape_state >=0 )
str = tape_state_verbose[device->tape_state];
else
str = "UNKNOWN TS";
DBF_EVENT(4, "%s\n", str);
DBF_EVENT(4, "new ts:\t\n");
- if (newstate < TO_SIZE && newstate >= 0)
+ if (newstate < TS_SIZE && newstate >= 0)
str = tape_state_verbose[newstate];
else
str = "UNKNOWN TS";
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index cb8e2e672b68..0960bef7b199 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -414,11 +414,11 @@ cio_ignore_proc_init (void)
entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
&proc_root);
if (!entry)
- return 0;
+ return -ENOENT;
entry->proc_fops = &cio_ignore_proc_fops;
- return 1;
+ return 0;
}
__initcall (cio_ignore_proc_init);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index cbb86fa5f293..5b20d8c9c025 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -67,7 +67,7 @@ cio_debug_init (void)
goto out_unregister;
debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
debug_set_level (cio_debug_msg_id, 2);
- cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 8);
+ cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
if (!cio_debug_trace_id)
goto out_unregister;
debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index 6af8b27d366b..f88844adae1b 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -3,6 +3,11 @@
#include <asm/debug.h>
+/* for use of debug feature */
+extern debug_info_t *cio_debug_msg_id;
+extern debug_info_t *cio_debug_trace_id;
+extern debug_info_t *cio_debug_crw_id;
+
#define CIO_TRACE_EVENT(imp, txt) do { \
debug_text_event(cio_debug_trace_id, imp, txt); \
} while (0)
@@ -15,18 +20,19 @@
debug_sprintf_event(cio_debug_crw_id, imp , ##args); \
} while (0)
-#define CIO_HEX_EVENT(imp, args...) do { \
- debug_event(cio_debug_trace_id, imp, ##args); \
- } while (0)
+static inline void
+CIO_HEX_EVENT(int level, void *data, int length)
+{
+ while (length > 0) {
+ debug_event(cio_debug_trace_id, level, data, length);
+ length -= cio_debug_trace_id->buf_size;
+ data += cio_debug_trace_id->buf_size;
+ }
+}
#define CIO_DEBUG(printk_level,event_level,msg...) ({ \
if (cio_show_msg) printk(printk_level msg); \
CIO_MSG_EVENT (event_level, msg); \
})
-/* for use of debug feature */
-extern debug_info_t *cio_debug_msg_id;
-extern debug_info_t *cio_debug_trace_id;
-extern debug_info_t *cio_debug_crw_id;
-
#endif
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 25f678d0780b..e8e41e6eb42a 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1508,10 +1508,12 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
void *buf;
unsigned int transfer_len;
+ unsigned long flags = 0;
if (cmd->use_sg) {
struct scatterlist *sg =
(struct scatterlist *)cmd->request_buffer;
+ local_irq_save(flags);
buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
transfer_len = min(sg->length, len);
} else {
@@ -1526,6 +1528,7 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
sg = (struct scatterlist *)cmd->request_buffer;
kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
}
}
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 1bd82c4e52a0..b4f8fb1d628b 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -207,7 +207,6 @@ static struct scsi_host_template ahci_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = AHCI_MAX_SG,
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 24e71b555172..6dc88149f9f1 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -209,7 +209,6 @@ static struct scsi_host_template piix_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index ef57f253031c..dfcb96f3e60c 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -294,18 +294,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
- /* Check to see if this host has any error handling facilities */
- if (!sht->eh_strategy_handler && !sht->eh_abort_handler &&
- !sht->eh_device_reset_handler && !sht->eh_bus_reset_handler &&
- !sht->eh_host_reset_handler) {
- printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\n"
- "ERROR: This is not a safe way to run your "
- "SCSI host\n"
- "ERROR: The error handling must be added to "
- "this driver\n", sht->proc_name);
- dump_stack();
- }
-
shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
if (!shost)
return NULL;
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index e63c1ff1e102..bd147207f25d 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4938,7 +4938,6 @@ EXPORT_SYMBOL_GPL(ata_busy_sleep);
EXPORT_SYMBOL_GPL(ata_port_queue_task);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
-EXPORT_SYMBOL_GPL(ata_scsi_error);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 53f5b0d9161c..a0289ec3e283 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -53,6 +53,7 @@
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
static struct ata_device *
ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev);
+static void ata_scsi_error(struct Scsi_Host *host);
enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
#define RW_RECOVERY_MPAGE 0x1
@@ -99,6 +100,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
* It just needs the eh_timed_out hook.
*/
struct scsi_transport_template ata_scsi_transport_template = {
+ .eh_strategy_handler = ata_scsi_error,
.eh_timed_out = ata_scsi_timed_out,
};
@@ -772,12 +774,9 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
*
* LOCKING:
* Inherited from SCSI layer (none, can sleep)
- *
- * RETURNS:
- * Zero.
*/
-int ata_scsi_error(struct Scsi_Host *host)
+static void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap;
unsigned long flags;
@@ -805,7 +804,6 @@ int ata_scsi_error(struct Scsi_Host *host)
spin_unlock_irqrestore(&ap->host_set->lock, flags);
DPRINTK("EXIT\n");
- return 0;
}
static void ata_eh_scsidone(struct scsi_cmnd *scmd)
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 1c755b14521a..bac8cbae06fe 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -60,7 +60,6 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct scsi_transport_template ata_scsi_transport_template;
extern void ata_scsi_scan_host(struct ata_port *ap);
-extern int ata_scsi_error(struct Scsi_Host *host);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen);
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index 3c85c4b66e19..5cda16cfacb0 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -143,7 +143,6 @@ static struct scsi_host_template adma_ata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index fa901fd65085..d5fdcb9a8842 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -378,7 +378,6 @@ static struct scsi_host_template mv_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = MV_USE_Q_DEPTH,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = MV_MAX_SG_CT / 2,
@@ -748,7 +747,7 @@ static void mv_dump_all_regs(void __iomem *mmio_base, int port,
mv_dump_mem(mmio_base+0xf00, 0x4);
mv_dump_mem(mmio_base+0x1d00, 0x6c);
for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
- hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT);
+ hc_base = mv_hc_base(mmio_base, hc);
DPRINTK("HC regs (HC %i):\n", hc);
mv_dump_mem(hc_base, 0x1c);
}
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index f77bf183dfab..9f553081b5e8 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -201,7 +201,6 @@ static struct scsi_host_template nv_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index cc928c68a479..7eb67a6bdc64 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -111,7 +111,6 @@ static struct scsi_host_template pdc_ata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 9ffe1ef0d205..886f3447dd48 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -132,7 +132,6 @@ static struct scsi_host_template qs_ata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = QS_MAX_PRD,
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 18c296c56899..106627299d55 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -146,7 +146,6 @@ static struct scsi_host_template sil_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 068c98a4111b..f7264fd611c2 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -281,7 +281,6 @@ static struct scsi_host_template sil24_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index acc8439dea23..728530df2e07 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -87,7 +87,6 @@ static struct scsi_host_template sis_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = ATA_MAX_PRD,
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index 724f0ed6a52d..53b0d5c0a61f 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -290,7 +290,6 @@ static struct scsi_host_template k2_sata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index ae70f60c7c0d..4139ad4b1df0 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -182,7 +182,6 @@ static struct scsi_host_template pdc_sata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 7ac5a5f5a905..38b52bd3fa3f 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -81,7 +81,6 @@ static struct scsi_host_template uli_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 791bf652ba63..9e7ae4e0db32 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -94,7 +94,6 @@ static struct scsi_host_template svia_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 836bbbb26ff2..8a29ce340b47 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -263,7 +263,6 @@ static struct scsi_host_template vsc_sata_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 5f0fdfb2618c..1c75646f9689 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1537,8 +1537,8 @@ int scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
*/
- if (shost->hostt->eh_strategy_handler)
- shost->hostt->eh_strategy_handler(shost);
+ if (shost->transportt->eh_strategy_handler)
+ shost->transportt->eh_strategy_handler(shost);
else
scsi_unjam_host(shost);
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 93449a1a0065..0b49ff78efc1 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
@@ -619,9 +620,9 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
pci_set_master(pdev);
#ifdef USE_64BIT_DMA
- ret = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+ ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
if (!ret) {
- ret = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+ ret = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (ret < 0) {
printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA "
"for consistent allocations\n",
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 495db5755df9..5cf2b80add7a 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -28,6 +28,7 @@
2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
wants to send >2000 bytes.
+ 2006-04-10 v0.4.2 fixed two array overrun errors :-/
Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
@@ -582,14 +583,14 @@ static void option_setup_urbs(struct usb_serial *serial)
portdata = usb_get_serial_port_data(port);
/* Do indat endpoints first */
- for (j = 0; j <= N_IN_URB; ++j) {
+ for (j = 0; j < N_IN_URB; ++j) {
portdata->in_urbs[j] = option_setup_urb (serial,
port->bulk_in_endpointAddress, USB_DIR_IN, port,
portdata->in_buffer[j], IN_BUFLEN, option_indat_callback);
}
/* outdat endpoints */
- for (j = 0; j <= N_OUT_URB; ++j) {
+ for (j = 0; j < N_OUT_URB; ++j) {
portdata->out_urbs[j] = option_setup_urb (serial,
port->bulk_out_endpointAddress, USB_DIR_OUT, port,
portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f87c0171f4ec..9060e7137441 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -961,7 +961,7 @@ config FB_ATY128
config FB_ATY
tristate "ATI Mach64 display support" if PCI || ATARI
- depends on FB
+ depends on FB && !SPARC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index b39e72d5413b..d9d7d3c4cae2 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -3400,7 +3400,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
struct atyfb_par *par;
int i, rc = -ENOMEM;
- for (i = ARRAY_SIZE(aty_chips); i >= 0; i--)
+ for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
if (pdev->device == aty_chips[i].pci_id)
break;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 944855b3e4af..8d8eadb64853 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -435,6 +435,11 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
depth = info->var.green.length;
}
+ if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) {
+ /* assume console colormap */
+ depth = 4;
+ }
+
if (depth >= 8) {
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 8982e540214c..b0b9acfdd430 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -57,7 +57,7 @@ static unsigned short *pmi_base = NULL;
static void (*pmi_start)(void);
static void (*pmi_pal)(void);
static int depth;
-
+static int vga_compat;
/* --------------------------------------------------------------------- */
static int vesafb_pan_display(struct fb_var_screeninfo *var,
@@ -83,9 +83,10 @@ static int vesafb_pan_display(struct fb_var_screeninfo *var,
static void vesa_setpalette(int regno, unsigned red, unsigned green,
unsigned blue)
{
+ int shift = 16 - depth;
+
#ifdef __i386__
struct { u_char blue, green, red, pad; } entry;
- int shift = 16 - depth;
if (pmi_setpal) {
entry.red = red >> shift;
@@ -101,14 +102,20 @@ static void vesa_setpalette(int regno, unsigned red, unsigned green,
"d" (regno), /* EDX */
"D" (&entry), /* EDI */
"S" (&pmi_pal)); /* ESI */
- } else {
- /* without protected mode interface, try VGA registers... */
+ return;
+ }
+#endif
+
+/*
+ * without protected mode interface and if VGA compatible,
+ * try VGA registers...
+ */
+ if (vga_compat) {
outb_p(regno, dac_reg);
outb_p(red >> shift, dac_val);
outb_p(green >> shift, dac_val);
outb_p(blue >> shift, dac_val);
}
-#endif
}
static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -214,6 +221,7 @@ static int __init vesafb_probe(struct platform_device *dev)
if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
return -ENODEV;
+ vga_compat = (screen_info.capabilities & 2) ? 0 : 1;
vesafb_fix.smem_start = screen_info.lfb_base;
vesafb_defined.bits_per_pixel = screen_info.lfb_depth;
if (15 == vesafb_defined.bits_per_pixel)
@@ -318,6 +326,12 @@ static int __init vesafb_probe(struct platform_device *dev)
}
}
+ if (vesafb_defined.bits_per_pixel == 8 && !pmi_setpal && !vga_compat) {
+ printk(KERN_WARNING "vesafb: hardware palette is unchangeable,\n"
+ " colors may be incorrect\n");
+ vesafb_fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ }
+
vesafb_defined.xres_virtual = vesafb_defined.xres;
vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length;
if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) {
@@ -354,7 +368,8 @@ static int __init vesafb_probe(struct platform_device *dev)
printk(KERN_INFO "vesafb: %s: "
"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
(vesafb_defined.bits_per_pixel > 8) ?
- "Truecolor" : "Pseudocolor",
+ "Truecolor" : (vga_compat || pmi_setpal) ?
+ "Pseudocolor" : "Static Pseudocolor",
screen_info.rsvd_size,
screen_info.red_size,
screen_info.green_size,
OpenPOWER on IntegriCloud