summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2003-05-27 07:31:32 +1000
committerPaul Mackerras <paulus@samba.org>2003-05-27 07:31:32 +1000
commit8a865f4a97f4eecdba606a444601148668210ef1 (patch)
tree2f0f8451051a8cb82ecb0b27c459ab2e66ec976f
parent927bc10f742f603ced09dae59c94be4c70b5e949 (diff)
parent2f124a73c7e036388e2e998c8ae1abf9d0b3204a (diff)
Merge samba.org:/home/paulus/kernel/linux-2.5
into samba.org:/home/paulus/kernel/for-linus-ppc
-rw-r--r--Documentation/filesystems/Locking2
-rw-r--r--Documentation/filesystems/porting2
-rw-r--r--arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S4
-rw-r--r--arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S2
-rw-r--r--drivers/base/bus.c4
-rw-r--r--drivers/base/sys.c4
-rw-r--r--drivers/ide/ppc/pmac.c2
-rw-r--r--drivers/isdn/capi/capifs.c2
-rw-r--r--drivers/macintosh/adbhid.c45
-rw-r--r--drivers/net/arcnet/arcnet.c5
-rw-r--r--drivers/net/e100/e100.h30
-rw-r--r--drivers/net/e100/e100_main.c342
-rw-r--r--drivers/net/e100/e100_phy.c7
-rw-r--r--drivers/net/e100/e100_test.c155
-rw-r--r--drivers/net/e1000/Makefile2
-rw-r--r--drivers/net/e1000/e1000.h5
-rw-r--r--drivers/net/e1000/e1000_ethtool.c959
-rw-r--r--drivers/net/e1000/e1000_hw.c23
-rw-r--r--drivers/net/e1000/e1000_hw.h8
-rw-r--r--drivers/net/e1000/e1000_main.c145
-rw-r--r--drivers/net/fc/iph5526.c18
-rw-r--r--drivers/net/fec.c18
-rw-r--r--drivers/net/fmv18x.c6
-rw-r--r--drivers/net/hamradio/scc.c7
-rw-r--r--drivers/net/irda/Kconfig21
-rw-r--r--drivers/net/irda/Makefile9
-rw-r--r--drivers/net/irda/ali-ircc.c4
-rw-r--r--drivers/net/irda/donauboe.c4
-rw-r--r--drivers/net/irda/irport.c480
-rw-r--r--drivers/net/irda/irtty-sir.c9
-rw-r--r--drivers/net/irda/nsc-ircc.c4
-rw-r--r--drivers/net/irda/sir_kthread.c7
-rw-r--r--drivers/net/irda/smc-ircc.c12
-rw-r--r--drivers/net/irda/smsc-ircc2.c2441
-rw-r--r--drivers/net/irda/smsc-ircc2.h194
-rw-r--r--drivers/net/irda/smsc-sio.h100
-rw-r--r--drivers/net/irda/w83977af_ir.c2
-rw-r--r--drivers/net/myri_sbus.c4
-rw-r--r--drivers/net/ppp_synctty.c4
-rw-r--r--drivers/net/seeq8005.c9
-rw-r--r--drivers/net/sunqe.c1
-rw-r--r--drivers/net/tokenring/lanstreamer.c5
-rw-r--r--drivers/net/tulip/de4x5.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c8
-rw-r--r--drivers/net/wireless/airport.c4
-rw-r--r--drivers/oprofile/oprofilefs.c4
-rw-r--r--drivers/usb/core/inode.c2
-rw-r--r--fs/adfs/super.c2
-rw-r--r--fs/affs/super.c6
-rw-r--r--fs/afs/super.c10
-rw-r--r--fs/autofs/init.c2
-rw-r--r--fs/autofs4/init.c2
-rw-r--r--fs/befs/linuxvfs.c4
-rw-r--r--fs/bfs/inode.c2
-rw-r--r--fs/binfmt_misc.c8
-rw-r--r--fs/block_dev.c2
-rw-r--r--fs/cifs/cifsfs.c7
-rw-r--r--fs/cifs/connect.c6
-rw-r--r--fs/coda/inode.c2
-rw-r--r--fs/cramfs/inode.c2
-rw-r--r--fs/devfs/base.c5
-rw-r--r--fs/devpts/inode.c5
-rw-r--r--fs/efs/super.c2
-rw-r--r--fs/eventpoll.c19
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext3/super.c2
-rw-r--r--fs/freevxfs/vxfs_super.c2
-rw-r--r--fs/hfs/super.c2
-rw-r--r--fs/hpfs/super.c2
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/intermezzo/super.c5
-rw-r--r--fs/intermezzo/vfs.c2
-rw-r--r--fs/isofs/inode.c2
-rw-r--r--fs/jffs/inode-v23.c2
-rw-r--r--fs/jffs2/super.c17
-rw-r--r--fs/jfs/super.c5
-rw-r--r--fs/libfs.c2
-rw-r--r--fs/minix/inode.c2
-rw-r--r--fs/msdos/msdosfs_syms.c2
-rw-r--r--fs/namespace.c6
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/nfs/inode.c4
-rw-r--r--fs/nfs/nfsroot.c9
-rw-r--r--fs/nfsctl.c2
-rw-r--r--fs/nfsd/nfsctl.c2
-rw-r--r--fs/ntfs/super.c2
-rw-r--r--fs/openpromfs/inode.c2
-rw-r--r--fs/partitions/check.c2
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/root.c2
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/ramfs/inode.c4
-rw-r--r--fs/reiserfs/super.c8
-rw-r--r--fs/romfs/inode.c2
-rw-r--r--fs/smbfs/inode.c10
-rw-r--r--fs/super.c9
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--fs/sysv/super.c4
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/ufs/super.c2
-rw-r--r--fs/vfat/vfatfs_syms.c2
-rw-r--r--fs/xfs/linux/xfs_super.c2
-rw-r--r--include/asm-m68knommu/cacheflush.h10
-rw-r--r--include/linux/arcdevice.h2
-rw-r--r--include/linux/fs.h7
-rw-r--r--include/linux/mount.h5
-rw-r--r--include/linux/namespace.h4
-rw-r--r--include/linux/string.h3
-rw-r--r--include/net/irda/iriap.h2
-rw-r--r--include/net/irda/irlan_common.h2
-rw-r--r--include/net/irda/irlmp_event.h20
-rw-r--r--include/net/irda/irport.h1
-rw-r--r--init/do_mounts.c2
-rw-r--r--kernel/futex.c2
-rw-r--r--lib/string.c27
-rw-r--r--mm/nommu.c9
-rw-r--r--mm/shmem.c5
-rw-r--r--net/irda/af_irda.c13
-rw-r--r--net/irda/ircomm/ircomm_core.c36
-rw-r--r--net/irda/ircomm/ircomm_event.c10
-rw-r--r--net/irda/ircomm/ircomm_lmp.c56
-rw-r--r--net/irda/ircomm/ircomm_ttp.c53
-rw-r--r--net/irda/ircomm/ircomm_tty.c21
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c22
-rw-r--r--net/irda/iriap.c136
-rw-r--r--net/irda/iriap_event.c35
-rw-r--r--net/irda/irlan/irlan_common.c14
-rw-r--r--net/irda/irlan/irlan_eth.c8
-rw-r--r--net/irda/irlap.c16
-rw-r--r--net/irda/irlap_event.c7
-rw-r--r--net/irda/irlap_frame.c185
-rw-r--r--net/irda/irlmp.c171
-rw-r--r--net/irda/irlmp_event.c41
-rw-r--r--net/irda/irlmp_frame.c23
-rw-r--r--net/irda/irnet/irnet.h6
-rw-r--r--net/irda/irnet/irnet_irda.c30
-rw-r--r--net/irda/irnet/irnet_ppp.c2
-rw-r--r--net/irda/irttp.c119
-rw-r--r--net/socket.c2
-rw-r--r--net/sunrpc/rpc_pipe.c2
-rw-r--r--sound/core/control.c14
-rw-r--r--sound/core/hwdep.c6
-rw-r--r--sound/core/init.c2
-rw-r--r--sound/core/oss/mixer_oss.c17
-rw-r--r--sound/core/pcm.c2
-rw-r--r--sound/core/pcm_native.c6
-rw-r--r--sound/core/rawmidi.c2
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c5
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c7
-rw-r--r--sound/core/seq/seq_clientmgr.c18
-rw-r--r--sound/core/seq/seq_device.c6
-rw-r--r--sound/core/seq/seq_instr.c3
-rw-r--r--sound/core/seq/seq_ports.c14
-rw-r--r--sound/core/seq/seq_queue.c2
-rw-r--r--sound/core/timer.c10
-rw-r--r--sound/drivers/opl3/opl3_oss.c3
-rw-r--r--sound/i2c/i2c.c4
-rw-r--r--sound/isa/ad1848/ad1848_lib.c2
-rw-r--r--sound/isa/sb/sb16_csp.c3
-rw-r--r--sound/isa/sb/sb_mixer.c2
-rw-r--r--sound/oss/ac97_codec.c8
-rw-r--r--sound/oss/btaudio.c8
-rw-r--r--sound/oss/cmpci.c8
-rw-r--r--sound/oss/cs4281/cs4281m.c8
-rw-r--r--sound/oss/dev_table.c15
-rw-r--r--sound/oss/dmasound/dmasound_core.c5
-rw-r--r--sound/oss/emu10k1/mixer.c4
-rw-r--r--sound/oss/es1370.c8
-rw-r--r--sound/oss/esssolo1.c8
-rw-r--r--sound/oss/gus_wave.c24
-rw-r--r--sound/oss/maestro.c8
-rw-r--r--sound/oss/msnd_pinnacle.c4
-rw-r--r--sound/oss/sequencer.c2
-rw-r--r--sound/oss/sonicvibes.c8
-rw-r--r--sound/oss/soundcard.c10
-rw-r--r--sound/pci/emu10k1/emufx.c8
-rw-r--r--sound/usb/usbaudio.c32
-rw-r--r--sound/usb/usbmixer.c57
178 files changed, 5471 insertions, 1339 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 133bc87505fd..03f43b68e801 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -120,7 +120,7 @@ by better scheme anyway.
--------------------------- file_system_type ---------------------------
prototypes:
- struct super_block *(*get_sb) (struct file_system_type *, int, char *, void *);
+ struct super_block *(*get_sb) (struct file_system_type *, int, const char *, void *);
void (*kill_sb) (struct super_block *);
locking rules:
may block BKL
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 2f526cadf84f..2f388460cbe7 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -51,7 +51,7 @@ success and negative number in case of error (-EINVAL unless you have more
informative error value to report). Call it foo_fill_super(). Now declare
struct super_block foo_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
}
diff --git a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S
index 18ed9b2ad8ec..c28be59a53b2 100644
--- a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S
+++ b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S
@@ -118,8 +118,8 @@ _start:
move.l #(0x00<<ACR_BASE_POS)+(0<<ACR_MASK_POS)+ACR_ENABLE+ACR_ANY+ACR_CM_CP,%d0
movec %d0,%ACR3
- /* Enable cache */
- move.l #0x86088400, %d0
+ /* Enable cache */
+ move.l #0xa4098400, %d0 /* Write buffer, dflt precise */
movec %d0,%CACR
nop
diff --git a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S
index b84bef00c5c9..38c2b6d5592a 100644
--- a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S
+++ b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S
@@ -99,7 +99,7 @@ _start:
movec %d0, %ACR3
/* Enable cache */
- move.l #0x86088400, %d0
+ move.l #0xa4098400, %d0 /* Write buffer, dflt precise */
movec %d0,%CACR
nop
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 9d4e16eea0de..e290ffe53bdb 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -544,11 +544,11 @@ int bus_register(struct bus_type * bus)
subsys_set_kset(bus,bus_subsys);
subsystem_register(&bus->subsys);
- snprintf(bus->devices.kobj.name,KOBJ_NAME_LEN,"devices");
+ strlcpy(bus->devices.kobj.name, "devices", KOBJ_NAME_LEN);
bus->devices.subsys = &bus->subsys;
kset_register(&bus->devices);
- snprintf(bus->drivers.kobj.name,KOBJ_NAME_LEN,"drivers");
+ strlcpy(bus->drivers.kobj.name, "drivers", KOBJ_NAME_LEN);
bus->drivers.subsys = &bus->subsys;
bus->drivers.ktype = &ktype_driver;
kset_register(&bus->drivers);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 2d8972537461..41e8a546252f 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -63,8 +63,8 @@ int sys_register_root(struct sys_root * root)
error = device_register(&root->dev);
if (!error) {
- strncpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE);
- strncpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE);
+ strlcpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE);
+ strlcpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE);
root->sysdev.parent = &root->dev;
error = device_register(&root->sysdev);
};
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index e86d60a4477d..f86304224663 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -721,7 +721,7 @@ pmac_find_ide_boot(char *bootdevice, int n)
}
}
- return NODEV;
+ return 0;
}
void __init
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 8cdf0e65f9c6..945357b2c7c4 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -141,7 +141,7 @@ static int capifs_fill_super(struct super_block *s, void *data, int silent)
}
static struct super_block *capifs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, capifs_fill_super);
}
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index d9009024ac53..f47a476620fb 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -42,6 +42,10 @@
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/pmu.h>
+
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
@@ -65,7 +69,7 @@ unsigned char adb_to_linux_keycodes[128] = {
0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0,
0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124,
63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88,
- 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116
+ 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,126,116
};
struct adbhid {
@@ -84,7 +88,7 @@ static struct adbhid *adbhid[16] = { 0 };
static void adbhid_probe(void);
-static void adbhid_input_keycode(int, int, int);
+static void adbhid_input_keycode(int, int, int, struct pt_regs *);
static void leds_done(struct adb_request *);
static void init_trackpad(int id);
@@ -140,7 +144,7 @@ adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apo
}
static void
-adbhid_input_keycode(int id, int keycode, int repeat, pt_regs *regs)
+adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
{
int up_flag;
@@ -156,6 +160,15 @@ adbhid_input_keycode(int id, int keycode, int repeat, pt_regs *regs)
return;
case 0x3f: /* ignore Powerbook Fn key */
return;
+ case 0x7e: /* Power key on PBook 3400 needs remapping */
+ switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO,
+ NULL, PMAC_MB_INFO_MODEL, 0)) {
+ case PMAC_TYPE_COMET:
+ case PMAC_TYPE_HOOPER:
+ case PMAC_TYPE_KANGA:
+ keycode = 0x7f;
+ }
+ break;
}
if (adbhid[id]->keycode[keycode]) {
@@ -343,13 +356,12 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0xa: /* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
if (!disable_kernel_backlight) {
- if (!down || backlight < 0)
- break;
- if (backlight > BACKLIGHT_OFF)
- set_backlight_level(backlight-1);
- else
- set_backlight_level(BACKLIGHT_OFF);
- break;
+ if (down && backlight >= 0) {
+ if (backlight > BACKLIGHT_OFF)
+ set_backlight_level(backlight-1);
+ else
+ set_backlight_level(BACKLIGHT_OFF);
+ }
}
#endif /* CONFIG_PMAC_BACKLIGHT */
input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
@@ -358,13 +370,12 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0x9: /* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
if (!disable_kernel_backlight) {
- if (!down || backlight < 0)
- break;
- if (backlight < BACKLIGHT_MAX)
- set_backlight_level(backlight+1);
- else
- set_backlight_level(BACKLIGHT_MAX);
- break;
+ if (down && backlight >= 0) {
+ if (backlight < BACKLIGHT_MAX)
+ set_backlight_level(backlight+1);
+ else
+ set_backlight_level(BACKLIGHT_MAX);
+ }
}
#endif /* CONFIG_PMAC_BACKLIGHT */
input_report_key(&adbhid[id]->input, KEY_BRIGHTNESSUP, down);
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 3a77c6b81664..199bcfbdc1cd 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -671,7 +671,7 @@ static void arcnet_timeout(struct net_device *dev)
* interrupts. Establish which device needs attention, and call the correct
* chipset interrupt handler.
*/
-void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct arcnet_local *lp;
@@ -696,7 +696,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0);
spin_unlock(&arcnet_lock);
- return;
+ return IRQ_HANDLED;
}
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
@@ -864,6 +864,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
AINTMASK(lp->intmask);
spin_unlock(&arcnet_lock);
+ return IRQ_RETVAL(didsomething);
}
diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
index aa58407de02d..188bd6e19a21 100644
--- a/drivers/net/e100/e100.h
+++ b/drivers/net/e100/e100.h
@@ -60,7 +60,14 @@
#include <linux/if_vlan.h>
#include <linux/mii.h>
-#define E100_REGS_LEN 1
+#define E100_CABLE_UNKNOWN 0
+#define E100_CABLE_OK 1
+#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */
+#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */
+#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */
+#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */
+
+#define E100_REGS_LEN 2
/*
* Configure parameters for buffers per controller.
* If the machine this is being used on is a faster machine (i.e. > 150MHz)
@@ -105,8 +112,6 @@
#define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */
/* HWI feature related constant */
-#define HWI_MAX_LOOP 100
-#define MAX_SAME_RESULTS 3
#define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */
#define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */
@@ -942,7 +947,6 @@ struct e100_private {
#ifdef CONFIG_PM
u32 pci_state[16];
#endif
- char ifname[IFNAMSIZ];
#ifdef E100_CU_DEBUG
u8 last_cmd;
u8 last_sub_cmd;
@@ -956,7 +960,10 @@ struct e100_private {
#define E100_SPEED_100_FULL 4
/********* function prototypes *************/
+extern int e100_open(struct net_device *);
+extern int e100_close(struct net_device *);
extern void e100_isolate_driver(struct e100_private *bdp);
+extern unsigned char e100_hw_init(struct e100_private *);
extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
extern void e100_free_non_tx_cmd(struct e100_private *bdp,
@@ -981,14 +988,13 @@ extern unsigned char e100_cu_unknown_state(struct e100_private *bdp);
#define TEST_TIMEOUT 0x08
enum test_offsets {
- E100_EEPROM_TEST_FAIL = 0,
- E100_CHIP_TIMEOUT,
- E100_ROM_TEST_FAIL,
- E100_REG_TEST_FAIL,
- E100_MAC_TEST_FAIL,
- E100_LPBK_MAC_FAIL,
- E100_LPBK_PHY_FAIL,
- E100_MAX_TEST_RES
+ test_link,
+ test_eeprom,
+ test_self_test,
+ test_loopback_mac,
+ test_loopback_phy,
+ cable_diag,
+ max_test_res, /* must be last */
};
#endif
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
index 070c9fb9f0f4..4b503d7b50b8 100644
--- a/drivers/net/e100/e100_main.c
+++ b/drivers/net/e100/e100_main.c
@@ -46,6 +46,24 @@
/* Change Log
*
+ * 2.3.13 05/08/03
+ * o Feature remove: /proc/net/PRO_LAN_Adapters support gone completely
+ * o Feature remove: IDIAG support (use ethtool -t instead)
+ * o Cleanup: fixed spelling mistakes found by community
+ * o Feature add: ethtool cable diag test
+ * o Feature add: ethtool parameter support (ring size, xsum, flow ctrl)
+ * o Cleanup: move e100_asf_enable under CONFIG_PM to avoid warning
+ * [Stephen Rothwell (sfr@canb.auug.org.au)]
+ * o Bug fix: don't call any netif_carrier_* until netdev registered.
+ * [Andrew Morton (akpm@digeo.com)]
+ * o Cleanup: replace (skb->len - skb->data_len) with skb_headlen(skb)
+ * [jmorris@intercode.com.au]
+ * o Bug fix: cleanup of Tx skbs after running ethtool diags
+ * o Bug fix: incorrect reporting of ethtool diag overall results
+ * o Bug fix: must hold xmit_lock before stopping queue in ethtool
+ * operations that require reset h/w and driver structures.
+ * o Bug fix: statistic command failure would stop statistic collection.
+ *
* 2.2.21 02/11/03
* o Removed marketing brand strings. Instead, Using generic string
* "Intel(R) PRO/100 Network Connection" for all adapters.
@@ -61,21 +79,6 @@
* o New feature: added ICH5 support
*
* 2.1.27 11/20/02
- * o Bug fix: Device command timeout due to SMBus processing during init
- * o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
- * o Bug fix: Not using EEPROM WoL setting as default in ethtool
- * o Bug fix: Not able to set autoneg on using ethtool when interface down
- * o Bug fix: Not able to change speed/duplex using ethtool/mii
- * when interface up
- * o Bug fix: Ethtool shows autoneg on when forced to 100/Full
- * o Bug fix: Compiler error when CONFIG_PROC_FS not defined
- * o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled
- * (sleep while holding spinlock)
- * o Bug fix: 2.1.24-k1 doesn't display complete statistics
- * o Bug fix: System panic due to NULL watchdog timer dereference during
- * ifconfig down, rmmod and insmod
- *
- * 2.1.24 10/7/02
*/
#include <linux/config.h>
@@ -121,14 +124,13 @@ extern void e100_config_wol(struct e100_private *bdp);
extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
static int e100_ethtool_test(struct net_device *, struct ifreq *);
static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
-static char *test_strings[] = {
- "E100_EEPROM_TEST_FAIL",
- "E100_CHIP_TIMEOUT",
- "E100_ROM_TEST_FAIL",
- "E100_REG_TEST_FAIL",
- "E100_MAC_TEST_FAIL",
- "E100_LPBK_MAC_FAIL",
- "E100_LPBK_PHY_FAIL"
+static char test_strings[][ETH_GSTRING_LEN] = {
+ "Link test (on/offline)",
+ "Eeprom test (on/offline)",
+ "Self test (offline)",
+ "Mac loopback (offline)",
+ "Phy loopback (offline)",
+ "Cable diagnostic (offline)"
};
static int e100_ethtool_led_blink(struct net_device *, struct ifreq *);
@@ -139,10 +141,10 @@ static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
nxmit_cb_entry_t *);
static void e100_free_nontx_list(struct e100_private *);
static void e100_non_tx_background(unsigned long);
-
+static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";
-char e100_driver_version[]="2.2.21-k1";
+char e100_driver_version[]="2.3.13-k1";
const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
char e100_short_driver_name[] = "e100";
static int e100nics = 0;
@@ -155,6 +157,7 @@ static void e100_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
static int e100_suspend(struct pci_dev *pcid, u32 state);
static int e100_resume(struct pci_dev *pcid);
+static unsigned char e100_asf_enabled(struct e100_private *bdp);
struct notifier_block e100_notifier_reboot = {
.notifier_call = e100_notify_reboot,
.next = NULL,
@@ -182,8 +185,6 @@ struct notifier_block e100_notifier_reboot = {
static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
static u8 e100_D102_check_checksum(rfd_t *);
static int e100_ioctl(struct net_device *, struct ifreq *, int);
-static int e100_open(struct net_device *);
-static int e100_close(struct net_device *);
static int e100_change_mtu(struct net_device *, int);
static int e100_xmit_frame(struct sk_buff *, struct net_device *);
static unsigned char e100_init(struct e100_private *);
@@ -193,7 +194,6 @@ struct net_device_stats *e100_get_stats(struct net_device *);
static irqreturn_t e100intr(int, void *, struct pt_regs *);
static void e100_print_brd_conf(struct e100_private *);
static void e100_set_multi(struct net_device *);
-void e100_set_speed_duplex(struct e100_private *);
static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
static u8 e100_sw_init(struct e100_private *);
@@ -215,7 +215,6 @@ u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
static unsigned char e100_clr_cntrs(struct e100_private *);
static unsigned char e100_load_microcode(struct e100_private *);
-static unsigned char e100_hw_init(struct e100_private *);
static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
static unsigned char e100_update_stats(struct e100_private *bdp);
@@ -228,7 +227,6 @@ static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
char *);
unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
void e100_exec_cmplx(struct e100_private *, u32, u8);
-static unsigned char e100_asf_enabled(struct e100_private *bdp);
/**
* e100_get_rx_struct - retrieve cell to hold skb buff from the pool
@@ -616,6 +614,10 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto err_dealloc;
}
+ if ((rc = register_netdev(dev)) != 0) {
+ goto err_pci;
+ }
+
if (((bdp->pdev->device > 0x1030)
&& (bdp->pdev->device < 0x103F))
|| ((bdp->pdev->device >= 0x1050)
@@ -645,7 +647,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_ERR "e100: Failed to initialize, instance #%d\n",
e100nics);
rc = -ENODEV;
- goto err_pci;
+ goto err_unregister_netdev;
}
/* Check if checksum is valid */
@@ -655,7 +657,7 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
e100nics);
rc = -ENODEV;
- goto err_pci;
+ goto err_unregister_netdev;
}
dev->vlan_rx_register = e100_vlan_rx_register;
@@ -679,12 +681,6 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
e100_get_speed_duplex_caps(bdp);
- if ((rc = register_netdev(dev)) != 0) {
- goto err_pci;
- }
- memcpy(bdp->ifname, dev->name, IFNAMSIZ);
- bdp->ifname[IFNAMSIZ-1] = 0;
-
printk(KERN_NOTICE
"e100: %s: %s\n",
bdp->device->name, "Intel(R) PRO/100 Network Connection");
@@ -709,6 +705,8 @@ e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
goto out;
+err_unregister_netdev:
+ unregister_netdev(dev);
err_pci:
iounmap(bdp->scb);
pci_release_regions(pcid);
@@ -974,7 +972,7 @@ e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
}
}
-static int
+int
e100_open(struct net_device *dev)
{
struct e100_private *bdp;
@@ -1012,7 +1010,11 @@ e100_open(struct net_device *dev)
mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
- netif_start_queue(dev);
+ if (dev->flags & IFF_UP)
+ /* Otherwise process may sleep forever */
+ netif_wake_queue(dev);
+ else
+ netif_start_queue(dev);
e100_start_ru(bdp);
if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
@@ -1033,7 +1035,7 @@ exit:
return rc;
}
-static int
+int
e100_close(struct net_device *dev)
{
struct e100_private *bdp = dev->priv;
@@ -1074,7 +1076,8 @@ e100_xmit_frame(struct sk_buff *skb, struct net_device *dev)
goto exit2;
}
- if (!TCBS_AVAIL(bdp->tcb_pool) ||
+ /* tcb list may be empty temporarily during releasing resources */
+ if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) ||
(bdp->non_tx_command_state != E100_NON_TX_IDLE)) {
notify_stop = true;
rc = 1;
@@ -1285,10 +1288,8 @@ e100_init(struct e100_private *bdp)
/* read NIC's part number */
e100_rd_pwa_no(bdp);
- if (!e100_hw_init(bdp)) {
- printk(KERN_ERR "e100: hw init failed\n");
+ if (!e100_hw_init(bdp))
return false;
- }
/* Interrupts are enabled after device reset */
e100_disable_clear_intr(bdp);
@@ -1330,6 +1331,8 @@ e100_sw_init(struct e100_private *bdp)
spin_lock_init(&(bdp->bd_non_tx_lock));
spin_lock_init(&(bdp->config_lock));
spin_lock_init(&(bdp->mdi_access_lock));
+ /* Initialize configuration data */
+ e100_config_init(bdp);
return 1;
}
@@ -1384,11 +1387,11 @@ e100_tco_workaround(struct e100_private *bdp)
* true - If the adapter was initialized
* false - If the adapter failed initialization
*/
-unsigned char __devinit
+unsigned char
e100_hw_init(struct e100_private *bdp)
{
if (!e100_phy_init(bdp))
- return false;
+ goto err;
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
@@ -1398,27 +1401,25 @@ e100_hw_init(struct e100_private *bdp)
/* Load the CU BASE (set to 0, because we use linear mode) */
if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
- return false;
+ goto err;
if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
- return false;
+ goto err;
/* Load interrupt microcode */
if (e100_load_microcode(bdp)) {
bdp->flags |= DF_UCODE_LOADED;
}
- e100_config_init(bdp);
- if (!e100_config(bdp)) {
- return false;
- }
+ if (!e100_config(bdp))
+ goto err;
if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
- return false;
+ goto err;
/* Clear the internal counters */
if (!e100_clr_cntrs(bdp))
- return false;
+ goto err;
/* Change for 82558 enhancement */
/* If 82558/9 and if the user has enabled flow control, set up the
@@ -1431,6 +1432,9 @@ e100_hw_init(struct e100_private *bdp)
}
return true;
+err:
+ printk(KERN_ERR "e100: hw init failed\n");
+ return false;
}
/**
@@ -1591,9 +1595,22 @@ e100_alloc_tcb_pool(struct e100_private *bdp)
void
e100_free_tcb_pool(struct e100_private *bdp)
{
+ tcb_t *tcb;
+ int i;
+ /* Return tx skbs */
+ for (i = 0; i < bdp->params.TxDescriptors; i++) {
+ tcb = bdp->tcb_pool.data;
+ tcb += bdp->tcb_pool.head;
+ e100_tx_skb_free(bdp, tcb);
+ if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail)
+ break;
+ bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
+ }
pci_free_consistent(bdp->pdev,
sizeof (tcb_t) * bdp->params.TxDescriptors,
bdp->tcb_pool.data, bdp->tcb_phys);
+ bdp->tcb_pool.head = 0;
+ bdp->tcb_pool.tail = 1;
bdp->tcb_phys = 0;
}
@@ -1747,12 +1764,10 @@ e100_watchdog(struct net_device *dev)
e100_set_multi(dev);
}
}
-
- /* Update the statistics needed by the upper interface */
- /* This should be the last statistic related command
- * as it's async. now */
- e100_dump_stats_cntrs(bdp);
}
+ /* Issue command to dump statistics from device. */
+ /* Check for command completion on next watchdog timer. */
+ e100_dump_stats_cntrs(bdp);
wmb();
@@ -2544,6 +2559,7 @@ e100_update_stats(struct e100_private *bdp)
pcmd_complete = e100_cmd_complete_location(bdp);
if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
*pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
+ *pcmd_complete = 0;
return false;
}
@@ -3041,23 +3057,6 @@ e100_isolate_driver(struct e100_private *bdp)
e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
}
-void
-e100_set_speed_duplex(struct e100_private *bdp)
-{
- int carrier_ok;
- /* Device may lose link with some siwtches when */
- /* changing speed/duplex to non-autoneg. e100 */
- /* needs to remember carrier state in order to */
- /* start watchdog timer for recovering link */
- if ((carrier_ok = netif_carrier_ok(bdp->device)))
- e100_isolate_driver(bdp);
- e100_phy_set_speed_duplex(bdp, true);
- e100_config_fc(bdp); /* re-config flow-control if necessary */
- e100_config(bdp);
- if (carrier_ok)
- e100_deisolate_driver(bdp, false);
-}
-
static void
e100_tcb_add_C_bit(struct e100_private *bdp)
{
@@ -3213,6 +3212,144 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
case ETHTOOL_PHYS_ID:
rc = e100_ethtool_led_blink(dev,ifr);
break;
+#ifdef ETHTOOL_GRINGPARAM
+ case ETHTOOL_GRINGPARAM: {
+ struct ethtool_ringparam ering;
+ struct e100_private *bdp = dev->priv;
+ memset((void *) &ering, 0, sizeof(ering));
+ ering.rx_max_pending = E100_MAX_RFD;
+ ering.tx_max_pending = E100_MAX_TCB;
+ ering.rx_pending = bdp->params.RxDescriptors;
+ ering.tx_pending = bdp->params.TxDescriptors;
+ rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering))
+ ? -EFAULT : 0;
+ return rc;
+ }
+#endif
+#ifdef ETHTOOL_SRINGPARAM
+ case ETHTOOL_SRINGPARAM: {
+ struct ethtool_ringparam ering;
+ struct e100_private *bdp = dev->priv;
+ if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering)))
+ return -EFAULT;
+ if (ering.rx_pending > E100_MAX_RFD
+ || ering.rx_pending < E100_MIN_RFD)
+ return -EINVAL;
+ if (ering.tx_pending > E100_MAX_TCB
+ || ering.tx_pending < E100_MIN_TCB)
+ return -EINVAL;
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ /* Use new values to open interface */
+ bdp->params.RxDescriptors = ering.rx_pending;
+ bdp->params.TxDescriptors = ering.tx_pending;
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
+ else {
+ bdp->params.RxDescriptors = ering.rx_pending;
+ bdp->params.TxDescriptors = ering.tx_pending;
+ }
+ return 0;
+ }
+#endif
+#ifdef ETHTOOL_GPAUSEPARAM
+ case ETHTOOL_GPAUSEPARAM: {
+ struct ethtool_pauseparam epause;
+ struct e100_private *bdp = dev->priv;
+ memset((void *) &epause, 0, sizeof(epause));
+ if ((bdp->flags & IS_BACHELOR)
+ && (bdp->params.b_params & PRM_FC)) {
+ epause.autoneg = 1;
+ if (bdp->flags && DF_LINK_FC_CAP) {
+ epause.rx_pause = 1;
+ epause.tx_pause = 1;
+ }
+ if (bdp->flags && DF_LINK_FC_TX_ONLY)
+ epause.tx_pause = 1;
+ }
+ rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause))
+ ? -EFAULT : 0;
+ return rc;
+ }
+#endif
+#ifdef ETHTOOL_SPAUSEPARAM
+ case ETHTOOL_SPAUSEPARAM: {
+ struct ethtool_pauseparam epause;
+ struct e100_private *bdp = dev->priv;
+ if (!(bdp->flags & IS_BACHELOR))
+ return -EINVAL;
+ if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause)))
+ return -EFAULT;
+ if (epause.autoneg == 1)
+ bdp->params.b_params |= PRM_FC;
+ else
+ bdp->params.b_params &= ~PRM_FC;
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
+ return 0;
+ }
+#endif
+#ifdef ETHTOOL_GRXCSUM
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GTXCSUM:
+ case ETHTOOL_GSG:
+ { struct ethtool_value eval;
+ struct e100_private *bdp = dev->priv;
+ memset((void *) &eval, 0, sizeof(eval));
+ if ((ecmd.cmd == ETHTOOL_GRXCSUM)
+ && (bdp->params.b_params & PRM_XSUMRX))
+ eval.data = 1;
+ else
+ eval.data = 0;
+ rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval))
+ ? -EFAULT : 0;
+ return rc;
+ }
+#endif
+#ifdef ETHTOOL_SRXCSUM
+ case ETHTOOL_SRXCSUM:
+ case ETHTOOL_STXCSUM:
+ case ETHTOOL_SSG:
+ { struct ethtool_value eval;
+ struct e100_private *bdp = dev->priv;
+ if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval)))
+ return -EFAULT;
+ if (ecmd.cmd == ETHTOOL_SRXCSUM) {
+ if (eval.data == 1) {
+ if (bdp->rev_id >= D101MA_REV_ID)
+ bdp->params.b_params |= PRM_XSUMRX;
+ else
+ return -EINVAL;
+ } else {
+ if (bdp->rev_id >= D101MA_REV_ID)
+ bdp->params.b_params &= ~PRM_XSUMRX;
+ else
+ return 0;
+ }
+ } else {
+ if (eval.data == 1)
+ return -EINVAL;
+ else
+ return 0;
+ }
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
+ return 0;
+ }
+#endif
default:
break;
} //switch
@@ -3298,7 +3435,13 @@ e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
if ((ecmd.autoneg == AUTONEG_ENABLE)
&& (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
bdp->params.e100_speed_duplex = E100_AUTONEG;
- e100_set_speed_duplex(bdp);
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
} else {
if (ecmd.speed == SPEED_10) {
if (ecmd.duplex == DUPLEX_HALF) {
@@ -3329,7 +3472,13 @@ e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
bdp->params.e100_speed_duplex =
e100_new_speed_duplex;
- e100_set_speed_duplex(bdp);
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
} else {
return -EOPNOTSUPP;
}
@@ -3364,14 +3513,14 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
struct ethtool_test *info;
int rc = -EFAULT;
- info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
+ info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64),
GFP_ATOMIC);
if (!info)
return -ENOMEM;
memset((void *) info, 0, sizeof(*info) +
- E100_MAX_TEST_RES * sizeof(u64));
+ max_test_res * sizeof(u64));
if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
goto exit;
@@ -3379,7 +3528,7 @@ e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
info->flags = e100_run_diag(dev, info->data, info->flags);
if (!copy_to_user(ifr->ifr_data, info,
- sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
+ sizeof(*info) + max_test_res * sizeof(u64)))
rc = 0;
exit:
kfree(info);
@@ -3393,6 +3542,7 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
u32 regs_buff[E100_REGS_LEN];
struct ethtool_regs regs = {ETHTOOL_GREGS};
void *addr = ifr->ifr_data;
+ u16 mdi_reg;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -3405,6 +3555,8 @@ e100_ethtool_gregs(struct net_device *dev, struct ifreq *ifr)
regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 |
readb(&(bdp->scb->scb_cmd_low)) << 16 |
readw(&(bdp->scb->scb_status));
+ e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg);
+ regs_buff[1] = mdi_reg;
if(copy_to_user(addr, &regs, sizeof(regs)))
return -EFAULT;
@@ -3428,7 +3580,13 @@ e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) &&
(bdp->params.e100_speed_duplex == E100_AUTONEG)) {
- e100_set_speed_duplex(bdp);
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
} else {
return -EFAULT;
}
@@ -3454,7 +3612,7 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
info.n_stats = E100_STATS_LEN;
info.regdump_len = E100_REGS_LEN * sizeof(u32);
info.eedump_len = (bdp->eeprom_size << 1);
- info.testinfo_len = E100_MAX_TEST_RES;
+ info.testinfo_len = max_test_res;
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
@@ -3804,15 +3962,15 @@ static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
switch (info.string_set) {
case ETH_SS_TEST: {
int ret = 0;
- if (info.len > E100_MAX_TEST_RES)
- info.len = E100_MAX_TEST_RES;
+ if (info.len > max_test_res)
+ info.len = max_test_res;
strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
if (!strings)
return -ENOMEM;
memset(strings, 0, info.len * ETH_GSTRING_LEN);
for (i = 0; i < info.len; i++) {
- sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
+ sprintf(strings + i * ETH_GSTRING_LEN, "%s",
test_strings[i]);
}
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
@@ -3881,7 +4039,13 @@ e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
bdp->params.e100_speed_duplex = E100_SPEED_10_FULL;
else
bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
- e100_set_speed_duplex(bdp);
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ e100_hw_init(bdp);
+ e100_open(dev);
+ }
}
else
/* Only allows changing speed/duplex */
@@ -4164,7 +4328,6 @@ e100_resume(struct pci_dev *pcid)
return 0;
}
-#endif /* CONFIG_PM */
/**
* e100_asf_enabled - checks if ASF is configured on the current adaper
@@ -4190,6 +4353,7 @@ e100_asf_enabled(struct e100_private *bdp)
}
return false;
}
+#endif /* CONFIG_PM */
#ifdef E100_CU_DEBUG
unsigned char
diff --git a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c
index 08782934bdf6..e1473e816f1c 100644
--- a/drivers/net/e100/e100_phy.c
+++ b/drivers/net/e100/e100_phy.c
@@ -628,8 +628,6 @@ e100_force_speed_duplex(struct e100_private *bdp)
u16 control;
unsigned long expires;
- e100_phy_reset(bdp);
-
bdp->flags |= DF_SPEED_FORCED;
e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
@@ -912,6 +910,10 @@ e100_phy_reset(struct e100_private *bdp)
u16 ctrl_reg;
ctrl_reg = BMCR_RESET;
e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+ /* ieee 802.3 : The reset process shall be completed */
+ /* within 0.5 seconds from the settting of PHY reset bit. */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 2);
}
unsigned char __devinit
@@ -928,6 +930,7 @@ e100_phy_init(struct e100_private *bdp)
bdp->PhyDelay = 0;
bdp->zlock_state = ZLOCK_INITIAL;
+ e100_phy_reset(bdp);
e100_phy_set_speed_duplex(bdp, false);
e100_fix_polarity(bdp);
diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
index 0ff7266ef8e2..208a92049f19 100644
--- a/drivers/net/e100/e100_test.c
+++ b/drivers/net/e100/e100_test.c
@@ -25,7 +25,7 @@
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
-#include "e100.h"
+#include "e100_phy.h"
#include "e100_config.h"
extern u16 e100_eeprom_read(struct e100_private *, u16);
@@ -46,6 +46,7 @@ static u8 e100_diag_loopback_alloc(struct e100_private *);
static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
static u8 e100_diag_check_pkt(u8 *);
static void e100_diag_loopback_free(struct e100_private *);
+static int e100_cable_diag(struct e100_private *bdp);
#define LB_PACKET_SIZE 1500
@@ -60,46 +61,52 @@ u32
e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
{
struct e100_private* bdp = dev->priv;
- u8 test_result = true;
-
- e100_isolate_driver(bdp);
+ u8 test_result = 0;
+ if (!e100_get_link_state(bdp)) {
+ test_result = ETH_TEST_FL_FAILED;
+ test_info[test_link] = true;
+ }
+ if (!e100_diag_eeprom(dev)) {
+ test_result = ETH_TEST_FL_FAILED;
+ test_info[test_eeprom] = true;
+ }
if (flags & ETH_TEST_FL_OFFLINE) {
u8 fail_mask;
-
- fail_mask = e100_diag_selftest(dev);
- if (fail_mask) {
- test_result = false;
- if (fail_mask & REGISTER_TEST_FAIL)
- test_info [E100_REG_TEST_FAIL] = true;
- if (fail_mask & ROM_TEST_FAIL)
- test_info [E100_ROM_TEST_FAIL] = true;
- if (fail_mask & SELF_TEST_FAIL)
- test_info [E100_MAC_TEST_FAIL] = true;
- if (fail_mask & TEST_TIMEOUT)
- test_info [E100_CHIP_TIMEOUT] = true;
+ if (netif_running(dev)) {
+ spin_lock_bh(&dev->xmit_lock);
+ e100_close(dev);
+ spin_unlock_bh(&dev->xmit_lock);
+ }
+ if (e100_diag_selftest(dev)) {
+ test_result = ETH_TEST_FL_FAILED;
+ test_info[test_self_test] = true;
}
fail_mask = e100_diag_loopback(dev);
if (fail_mask) {
- test_result = false;
+ test_result = ETH_TEST_FL_FAILED;
if (fail_mask & PHY_LOOPBACK)
- test_info [E100_LPBK_PHY_FAIL] = true;
+ test_info[test_loopback_phy] = true;
if (fail_mask & MAC_LOOPBACK)
- test_info [E100_LPBK_MAC_FAIL] = true;
+ test_info[test_loopback_mac] = true;
}
- }
- if (!e100_diag_eeprom(dev)) {
- test_result = false;
- test_info [E100_EEPROM_TEST_FAIL] = true;
+ test_info[cable_diag] = e100_cable_diag(bdp);
+ /* Need hw init regardless of netif_running */
+ e100_hw_init(bdp);
+ if (netif_running(dev)) {
+ e100_open(dev);
+ }
+ }
+ else {
+ test_info[test_self_test] = false;
+ test_info[test_loopback_phy] = false;
+ test_info[test_loopback_mac] = false;
+ test_info[cable_diag] = false;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ * 2);
- e100_deisolate_driver(bdp, false);
-
- return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
+ return flags | test_result;
}
/**
@@ -126,8 +133,6 @@ e100_diag_selftest(struct net_device *dev)
}
}
- e100_configure_device(bdp);
-
return retval;
}
@@ -165,14 +170,14 @@ e100_diag_loopback (struct net_device *dev)
u8 rc = 0;
printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name);
- e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
+ e100_hw_init(dev->priv);
if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
rc |= PHY_LOOPBACK;
}
printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name);
printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name);
- e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
+ e100_hw_init(dev->priv);
if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
rc |= MAC_LOOPBACK;
}
@@ -257,15 +262,10 @@ e100_diag_config_loopback(struct e100_private* bdp,
if (set_loopback)
/* Set PHY loopback mode */
e100_phy_set_loopback(bdp);
- else { /* Back to normal speed and duplex */
- if (bdp->params.e100_speed_duplex == E100_AUTONEG)
- /* Reset PHY and do autoneg */
- e100_phy_autoneg(bdp);
- else
- /* Reset PHY and force speed and duplex */
- e100_force_speed_duplex(bdp);
- }
- /* Wait for PHY state change */
+ else
+ /* Reset PHY loopback mode */
+ e100_phy_reset(bdp);
+ /* Wait for PHY state change */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
} else { /* For MAC loopback wait 500 msec to take effect */
@@ -348,10 +348,6 @@ static void
e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
{
/*load CU & RU base */
- if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
- printk(KERN_ERR "e100: SCB_CUC_LOAD_BASE failed\n");
- if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
- printk(KERN_ERR "e100: SCB_RUC_LOAD_BASE failed!\n");
if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0))
printk(KERN_ERR "e100: SCB_RUC_START failed!\n");
@@ -433,3 +429,72 @@ e100_diag_loopback_free (struct e100_private *bdp)
bdp->loopback.dma_handle);
}
+static int
+e100_cable_diag(struct e100_private *bdp)
+{
+ int saved_open_circut = 0xffff;
+ int saved_short_circut = 0xffff;
+ int saved_distance = 0xffff;
+ int saved_same = 0;
+ int cable_status = E100_CABLE_UNKNOWN;
+ int i;
+
+ /* If we have link, */
+ if (e100_get_link_state(bdp))
+ return E100_CABLE_OK;
+
+ if (bdp->rev_id < D102_REV_ID)
+ return E100_CABLE_UNKNOWN;
+
+ /* Disable MDI/MDI-X auto switching */
+ e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
+ MDI_MDIX_RESET_ALL_MASK);
+ /* Set to 100 Full as required by cable test */
+ e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+ BMCR_SPEED100 | BMCR_FULLDPLX);
+
+ /* Test up to 100 times */
+ for (i = 0; i < 100; i++) {
+ u16 ctrl_reg;
+ int distance, open_circut, short_circut, near_end;
+
+ /* Enable and execute cable test */
+ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
+ (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
+ /* Wait for cable test finished */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/100 + 1);
+ /* Read results */
+ e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
+ distance = ctrl_reg & HWI_TEST_DISTANCE;
+ open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
+ short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
+
+ if ((distance == saved_distance) &&
+ (open_circut == saved_open_circut) &&
+ (short_circut == saved_short_circut))
+ saved_same++;
+ else {
+ saved_same = 0;
+ saved_distance = distance;
+ saved_open_circut = open_circut;
+ saved_short_circut = short_circut;
+ }
+ /* If results are the same 3 times */
+ if (saved_same == 3) {
+ near_end = ((distance * HWI_REGISTER_GRANULARITY) <
+ HWI_NEAR_END_BOUNDARY);
+ if (open_circut)
+ cable_status = (near_end) ?
+ E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR;
+ if (short_circut)
+ cable_status = (near_end) ?
+ E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR;
+ break;
+ }
+ }
+ /* Reset cable test */
+ e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK);
+ return cable_status;
+}
+
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
index 898c6a3a2c09..ca9f89552da3 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/e1000/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
#
-# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+# Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved.
#
# 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
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 307a2b1b22ad..8891f273269e 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -134,6 +134,7 @@ struct e1000_buffer {
uint64_t dma;
unsigned long length;
unsigned long time_stamp;
+ unsigned int next_to_watch;
};
struct e1000_desc_ring {
@@ -169,7 +170,6 @@ struct e1000_adapter {
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
- char *id_string;
uint32_t bd_number;
uint32_t rx_buffer_len;
uint32_t part_num;
@@ -218,6 +218,9 @@ struct e1000_adapter {
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
+ uint32_t test_icr;
+ struct e1000_desc_ring test_tx_ring;
+ struct e1000_desc_ring test_rx_ring;
uint32_t pci_state[16];
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index c64530107467..43b60a55ed58 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -40,15 +40,60 @@ extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
- "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
- "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
- "rx_length_errors", "rx_over_errors", "rx_crc_errors",
- "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
- "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
- "tx_heartbeat_errors", "tx_window_errors",
+struct e1000_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
};
-#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
+
+#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+static struct e1000_stats e1000_gstrings_stats[] = {
+ { "rx_packets", E1000_STAT(net_stats.rx_packets) },
+ { "tx_packets", E1000_STAT(net_stats.tx_packets) },
+ { "rx_bytes", E1000_STAT(net_stats.rx_bytes) },
+ { "tx_bytes", E1000_STAT(net_stats.tx_bytes) },
+ { "rx_errors", E1000_STAT(net_stats.rx_errors) },
+ { "tx_errors", E1000_STAT(net_stats.tx_errors) },
+ { "rx_dropped", E1000_STAT(net_stats.rx_dropped) },
+ { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+ { "multicast", E1000_STAT(net_stats.multicast) },
+ { "collisions", E1000_STAT(net_stats.collisions) },
+ { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
+ { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+ { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) },
+ { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) },
+ { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },
+ { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },
+ { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },
+ { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) },
+ { "tx_abort_late_coll", E1000_STAT(stats.latecol) },
+ { "tx_deferred_ok", E1000_STAT(stats.dc) },
+ { "tx_single_coll_ok", E1000_STAT(stats.scc) },
+ { "tx_multi_coll_ok", E1000_STAT(stats.mcc) },
+ { "rx_long_length_errors", E1000_STAT(stats.roc) },
+ { "rx_short_length_errors", E1000_STAT(stats.ruc) },
+ { "rx_align_errors", E1000_STAT(stats.algnerrc) },
+ { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) },
+ { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) },
+ { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) },
+ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
+ { "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
+ { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
+ { "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
+ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
+};
+#define E1000_STATS_LEN \
+ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+static char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register test (offline)", "Eeprom test (offline)",
+ "Interrupt test (offline)", "Loopback test (offline)",
+ "Link test (on/offline)"
+};
+#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
@@ -154,6 +199,7 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
drvinfo->n_stats = E1000_STATS_LEN;
+ drvinfo->testinfo_len = E1000_TEST_LEN;
#define E1000_REGS_LEN 32
drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t);
drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2;
@@ -164,6 +210,7 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter,
struct ethtool_regs *regs, uint32_t *regs_buff)
{
struct e1000_hw *hw = &adapter->hw;
+ uint16_t phy_data;
regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
@@ -182,6 +229,62 @@ e1000_ethtool_gregs(struct e1000_adapter *adapter,
regs_buff[10] = E1000_READ_REG(hw, TDT);
regs_buff[11] = E1000_READ_REG(hw, TIDV);
+ regs_buff[12] = adapter->hw.phy_type; /* PHY type (IGP=1, M88=0) */
+ if(hw->phy_type == e1000_phy_igp) {
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_A);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[13] = (uint32_t)phy_data; /* cable length */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_B);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_B &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[14] = (uint32_t)phy_data; /* cable length */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_C);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_C &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[15] = (uint32_t)phy_data; /* cable length */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_AGC_D);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_D &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[16] = (uint32_t)phy_data; /* cable length */
+ regs_buff[17] = 0; /* extended 10bt distance (not needed) */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[18] = (uint32_t)phy_data; /* cable polarity */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+ IGP01E1000_PHY_PCS_INIT_REG);
+ e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
+ IGP01E1000_PHY_PAGE_SELECT, &phy_data);
+ regs_buff[19] = (uint32_t)phy_data; /* cable polarity */
+ regs_buff[20] = 0; /* polarity correction enabled (always) */
+ regs_buff[22] = 0; /* phy receive errors (unavailable) */
+ regs_buff[23] = regs_buff[18]; /* mdix mode */
+ e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
+ } else {
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ regs_buff[13] = (uint32_t)phy_data; /* cable length */
+ regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */
+ regs_buff[18] = regs_buff[13]; /* cable polarity */
+ regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[20] = regs_buff[17]; /* polarity correction */
+ /* phy receive errors */
+ regs_buff[22] = adapter->phy_stats.receive_errors;
+ regs_buff[23] = regs_buff[13]; /* mdix mode */
+ }
+ regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */
+ e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
+ regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */
+ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
+
return;
}
@@ -219,7 +322,7 @@ e1000_ethtool_geeprom(struct e1000_adapter *adapter,
uint16_t i;
for (i = 0; i < last_word - first_word + 1; i++)
if((ret_val = e1000_read_eeprom(hw, first_word + i, 1,
- &eeprom_buff[i])))
+ &eeprom_buff[i])))
break;
}
geeprom_error:
@@ -249,7 +352,7 @@ e1000_ethtool_seeprom(struct e1000_adapter *adapter,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
eeprom_buff = kmalloc(max_len, GFP_KERNEL);
- if(eeprom_buff == NULL)
+ if(!eeprom_buff)
return -ENOMEM;
ptr = (void *)eeprom_buff;
@@ -284,6 +387,765 @@ seeprom_error:
return ret_val;
}
+#define REG_PATTERN_TEST(R, M, W) \
+{ \
+ uint32_t pat, value; \
+ uint32_t test[] = \
+ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+ for(pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \
+ E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
+ value = E1000_READ_REG(&adapter->hw, R); \
+ if(value != (test[pat] & W & M)) { \
+ *data = (adapter->hw.mac_type < e1000_82543) ? \
+ E1000_82542_##R : E1000_##R; \
+ return 1; \
+ } \
+ } \
+}
+
+#define REG_SET_AND_CHECK(R, M, W) \
+{ \
+ uint32_t value; \
+ E1000_WRITE_REG(&adapter->hw, R, W & M); \
+ value = E1000_READ_REG(&adapter->hw, R); \
+ if ((W & M) != (value & M)) { \
+ *data = (adapter->hw.mac_type < e1000_82543) ? \
+ E1000_82542_##R : E1000_##R; \
+ return 1; \
+ } \
+}
+
+static int
+e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ uint32_t value;
+ uint32_t i;
+
+ /* The status register is Read Only, so a write should fail.
+ * Some bits that get toggled are ignored.
+ */
+ value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
+ E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
+ if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+ *data = 1;
+ return 1;
+ }
+
+ REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF);
+ REG_PATTERN_TEST(RDH, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(RDT, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(FCRTH, 0x0000FFF8, 0x0000FFF8);
+ REG_PATTERN_TEST(FCTTV, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
+ REG_PATTERN_TEST(TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF);
+
+ REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000);
+ REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB);
+ REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
+
+ if(adapter->hw.mac_type >= e1000_82543) {
+
+ REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF);
+ REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
+
+ for(i = 0; i < E1000_RAR_ENTRIES; i++) {
+ REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF,
+ 0xFFFFFFFF);
+ REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
+ 0xFFFFFFFF);
+ }
+
+ } else {
+
+ REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
+ REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF);
+ REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF);
+
+ }
+
+ for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+ REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF);
+
+ return 0;
+}
+
+static int
+e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ uint16_t temp;
+ uint16_t checksum = 0;
+ uint16_t i;
+
+ *data = 0;
+ /* Read and add up the contents of the EEPROM */
+ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) {
+ *data = 1;
+ break;
+ }
+ checksum += temp;
+ }
+
+ /* If Checksum is not Correct return error else test passed */
+ if((checksum != (uint16_t) EEPROM_SUM) && !(*data))
+ *data = 2;
+
+ return *data;
+}
+
+static irqreturn_t
+e1000_test_intr(int irq,
+ void *data,
+ struct pt_regs *regs)
+{
+ struct net_device *netdev = (struct net_device *) data;
+ struct e1000_adapter *adapter = netdev->priv;
+
+ adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
+
+ return IRQ_HANDLED;
+}
+
+static int
+e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ struct net_device *netdev = adapter->netdev;
+ uint32_t icr, mask, i=0;
+
+ *data = 0;
+
+ /* Hook up test interrupt handler just for this test */
+ if(request_irq
+ (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) {
+ *data = 1;
+ return -1;
+ }
+
+ /* Disable all the interrupts */
+ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
+ msec_delay(10);
+
+ /* Interrupts are disabled, so read interrupt cause
+ * register (icr) twice to verify that there are no interrupts
+ * pending. icr is clear on read.
+ */
+ icr = E1000_READ_REG(&adapter->hw, ICR);
+ icr = E1000_READ_REG(&adapter->hw, ICR);
+
+ if(icr != 0) {
+ /* if icr is non-zero, there is no point
+ * running other interrupt tests.
+ */
+ *data = 2;
+ i = 10;
+ }
+
+ /* Test each interrupt */
+ for(; i < 10; i++) {
+
+ /* Interrupt to test */
+ mask = 1 << i;
+
+ /* Disable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+ msec_delay(10);
+
+ if(adapter->test_icr & mask) {
+ *data = 3;
+ break;
+ }
+
+ /* Enable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was not posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMS, mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, mask);
+ msec_delay(10);
+
+ if(!(adapter->test_icr & mask)) {
+ *data = 4;
+ break;
+ }
+
+ /* Disable the other interrupts to be reported in
+ * the cause register and then force the other
+ * interrupts and see if any get posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
+ E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
+ msec_delay(10);
+
+ if(adapter->test_icr) {
+ *data = 5;
+ break;
+ }
+ }
+
+ /* Disable all the interrupts */
+ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
+ msec_delay(10);
+
+ /* Unhook test interrupt handler */
+ free_irq(netdev->irq, netdev);
+
+ return *data;
+}
+
+static void
+e1000_free_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ int i;
+
+ if(txdr->desc && txdr->buffer_info) {
+ for(i = 0; i < txdr->count; i++) {
+ if(txdr->buffer_info[i].dma)
+ pci_unmap_single(pdev, txdr->buffer_info[i].dma,
+ txdr->buffer_info[i].length,
+ PCI_DMA_TODEVICE);
+ if(txdr->buffer_info[i].skb)
+ dev_kfree_skb(txdr->buffer_info[i].skb);
+ }
+ }
+
+ if(rxdr->desc && rxdr->buffer_info) {
+ for(i = 0; i < rxdr->count; i++) {
+ if(rxdr->buffer_info[i].dma)
+ pci_unmap_single(pdev, rxdr->buffer_info[i].dma,
+ rxdr->buffer_info[i].length,
+ PCI_DMA_FROMDEVICE);
+ if(rxdr->buffer_info[i].skb)
+ dev_kfree_skb(rxdr->buffer_info[i].skb);
+ }
+ }
+
+ if(txdr->desc)
+ pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma);
+ if(rxdr->desc)
+ pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);
+
+ if(txdr->buffer_info)
+ kfree(txdr->buffer_info);
+ if(rxdr->buffer_info)
+ kfree(rxdr->buffer_info);
+
+ return;
+}
+
+static int
+e1000_setup_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ uint32_t rctl;
+ int size, i, ret_val;
+
+ /* Setup Tx descriptor ring and Tx buffers */
+
+ txdr->count = 80;
+
+ size = txdr->count * sizeof(struct e1000_buffer);
+ if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ ret_val = 1;
+ goto err_nomem;
+ }
+ memset(txdr->buffer_info, 0, size);
+
+ txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
+ E1000_ROUNDUP(txdr->size, 4096);
+ if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
+ ret_val = 2;
+ goto err_nomem;
+ }
+ memset(txdr->desc, 0, txdr->size);
+ txdr->next_to_use = txdr->next_to_clean = 0;
+
+ E1000_WRITE_REG(&adapter->hw, TDBAL,
+ ((uint64_t) txdr->dma & 0x00000000FFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, TDBAH, ((uint64_t) txdr->dma >> 32));
+ E1000_WRITE_REG(&adapter->hw, TDLEN,
+ txdr->count * sizeof(struct e1000_tx_desc));
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
+ E1000_WRITE_REG(&adapter->hw, TCTL,
+ E1000_TCTL_PSP | E1000_TCTL_EN |
+ E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+ E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+ for(i = 0; i < txdr->count; i++) {
+ struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i);
+ struct sk_buff *skb;
+ unsigned int size = 1024;
+
+ if(!(skb = alloc_skb(size, GFP_KERNEL))) {
+ ret_val = 3;
+ goto err_nomem;
+ }
+ skb_put(skb, size);
+ txdr->buffer_info[i].skb = skb;
+ txdr->buffer_info[i].length = skb->len;
+ txdr->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);
+ tx_desc->lower.data = cpu_to_le32(skb->len);
+ tx_desc->lower.data |= E1000_TXD_CMD_EOP;
+ tx_desc->lower.data |= E1000_TXD_CMD_IFCS;
+ tx_desc->lower.data |= E1000_TXD_CMD_RPS;
+ tx_desc->upper.data = 0;
+ }
+
+ /* Setup Rx descriptor ring and Rx buffers */
+
+ rxdr->count = 80;
+
+ size = rxdr->count * sizeof(struct e1000_buffer);
+ if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ ret_val = 4;
+ goto err_nomem;
+ }
+ memset(rxdr->buffer_info, 0, size);
+
+ rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
+ if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
+ ret_val = 5;
+ goto err_nomem;
+ }
+ memset(rxdr->desc, 0, rxdr->size);
+ rxdr->next_to_use = rxdr->next_to_clean = 0;
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
+ E1000_WRITE_REG(&adapter->hw, RDBAL,
+ ((uint64_t) rxdr->dma & 0xFFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, RDBAH, ((uint64_t) rxdr->dma >> 32));
+ E1000_WRITE_REG(&adapter->hw, RDLEN, rxdr->size);
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, 0);
+ rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+
+ for(i = 0; i < rxdr->count; i++) {
+ struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i);
+ struct sk_buff *skb;
+
+ if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + 2, GFP_KERNEL))) {
+ ret_val = 6;
+ goto err_nomem;
+ }
+ skb_reserve(skb, 2);
+ rxdr->buffer_info[i].skb = skb;
+ rxdr->buffer_info[i].length = E1000_RXBUFFER_2048;
+ rxdr->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048,
+ PCI_DMA_FROMDEVICE);
+ rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);
+ memset(skb->data, 0x00, skb->len);
+ }
+
+ return 0;
+
+ err_nomem:
+ e1000_free_desc_rings(adapter);
+ return ret_val;
+}
+
+static void
+e1000_phy_disable_receiver(struct e1000_adapter *adapter)
+{
+ /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+ e1000_write_phy_reg(&adapter->hw, 29, 0x001F);
+ e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC);
+ e1000_write_phy_reg(&adapter->hw, 29, 0x001A);
+ e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0);
+
+ return;
+}
+
+static void
+e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
+{
+ uint16_t phy_reg;
+
+ /* Because we reset the PHY above, we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock. This
+ * value defaults back to a 2.5MHz clock when the PHY is reset.
+ */
+ e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
+ phy_reg |= M88E1000_EPSCR_TX_CLK_25;
+ e1000_write_phy_reg(&adapter->hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
+
+ /* In addition, because of the s/w reset above, we need to enable
+ * CRS on TX. This must be set for both full and half duplex
+ * operation.
+ */
+ e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
+ phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ e1000_write_phy_reg(&adapter->hw,
+ M88E1000_PHY_SPEC_CTRL, phy_reg);
+}
+
+static int
+e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
+{
+ uint32_t ctrl_reg;
+ uint16_t phy_reg;
+
+ /* Setup the Device Control Register for PHY loopback test. */
+
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */
+ E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
+
+ /* Read the PHY Specific Control Register (0x10) */
+ e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
+
+ /* Clear Auto-Crossover bits in PHY Specific Control Register
+ * (bits 6:5).
+ */
+ phy_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
+ e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg);
+
+ /* Perform software reset on the PHY */
+ e1000_phy_reset(&adapter->hw);
+
+ /* Have to setup TX_CLK and TX_CRS after software reset */
+ e1000_phy_reset_clk_and_crs(adapter);
+
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100);
+
+ /* Wait for reset to complete. */
+ udelay(500);
+
+ /* Have to setup TX_CLK and TX_CRS after software reset */
+ e1000_phy_reset_clk_and_crs(adapter);
+
+ /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+ e1000_phy_disable_receiver(adapter);
+
+ /* Set the loopback bit in the PHY control register. */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ phy_reg |= MII_CR_LOOPBACK;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
+
+ /* Setup TX_CLK and TX_CRS one more time. */
+ e1000_phy_reset_clk_and_crs(adapter);
+
+ /* Check Phy Configuration */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ if(phy_reg != 0x4100)
+ return 9;
+
+ e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
+ if(phy_reg != 0x0070)
+ return 10;
+
+ e1000_read_phy_reg(&adapter->hw, 29, &phy_reg);
+ if(phy_reg != 0x001A)
+ return 11;
+
+ return 0;
+}
+
+static int
+e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
+{
+ uint32_t ctrl_reg = 0;
+ uint32_t stat_reg = 0;
+
+ adapter->hw.autoneg = FALSE;
+
+ if(adapter->hw.phy_type == e1000_phy_m88) {
+ /* Auto-MDI/MDIX Off */
+ e1000_write_phy_reg(&adapter->hw,
+ M88E1000_PHY_SPEC_CTRL, 0x0808);
+ /* reset to update Auto-MDI/MDIX */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140);
+ /* autoneg off */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140);
+ }
+ /* force 1000, set loopback */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if(adapter->hw.media_type == e1000_media_type_copper &&
+ adapter->hw.phy_type == e1000_phy_m88) {
+ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+ } else {
+ /* Set the ILOS bit on the fiber Nic is half
+ * duplex link is detected. */
+ stat_reg = E1000_READ_REG(&adapter->hw, STATUS);
+ if((stat_reg & E1000_STATUS_FD) == 0)
+ ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+ }
+
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
+
+ /* Disable the receiver on the PHY so when a cable is plugged in, the
+ * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+ */
+ if(adapter->hw.phy_type == e1000_phy_m88)
+ e1000_phy_disable_receiver(adapter);
+
+ udelay(500);
+
+ return 0;
+}
+
+static int
+e1000_set_phy_loopback(struct e1000_adapter *adapter)
+{
+ uint16_t phy_reg = 0;
+ uint16_t count = 0;
+
+ switch (adapter->hw.mac_type) {
+ case e1000_82543:
+ if(adapter->hw.media_type == e1000_media_type_copper) {
+ /* Attempt to setup Loopback mode on Non-integrated PHY.
+ * Some PHY registers get corrupted at random, so
+ * attempt this 10 times.
+ */
+ while(e1000_nonintegrated_phy_loopback(adapter) &&
+ count++ < 10);
+ if(count < 11)
+ return 0;
+ }
+ break;
+
+ case e1000_82544:
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82546:
+ case e1000_82541:
+ case e1000_82547:
+ return e1000_integrated_phy_loopback(adapter);
+ break;
+
+ default:
+ /* Default PHY loopback work is to read the MII
+ * control register and assert bit 14 (loopback mode).
+ */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ phy_reg |= MII_CR_LOOPBACK;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
+ return 0;
+ break;
+ }
+
+ return 8;
+}
+
+static int
+e1000_setup_loopback_test(struct e1000_adapter *adapter)
+{
+ uint32_t rctl;
+
+ if(adapter->hw.media_type == e1000_media_type_fiber) {
+ if(adapter->hw.mac_type == e1000_82545 ||
+ adapter->hw.mac_type == e1000_82546)
+ return e1000_set_phy_loopback(adapter);
+ else {
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl |= E1000_RCTL_LBM_TCVR;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ return 0;
+ }
+ } else if(adapter->hw.media_type == e1000_media_type_copper)
+ return e1000_set_phy_loopback(adapter);
+
+ return 7;
+}
+
+static void
+e1000_loopback_cleanup(struct e1000_adapter *adapter)
+{
+ uint32_t rctl;
+ uint16_t phy_reg;
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+
+ if(adapter->hw.media_type == e1000_media_type_copper ||
+ (adapter->hw.media_type == e1000_media_type_fiber &&
+ (adapter->hw.mac_type == e1000_82545 ||
+ adapter->hw.mac_type == e1000_82546))) {
+ adapter->hw.autoneg = TRUE;
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
+ if(phy_reg & MII_CR_LOOPBACK) {
+ phy_reg &= ~MII_CR_LOOPBACK;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
+ e1000_phy_reset(&adapter->hw);
+ }
+ }
+}
+
+static void
+e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
+{
+ memset(skb->data, 0xFF, frame_size);
+ frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
+ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+ memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+ memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int
+e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
+{
+ frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size;
+ if(*(skb->data + 3) == 0xFF) {
+ if((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+ (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
+ return 0;
+ }
+ }
+ return 13;
+}
+
+static int
+e1000_run_loopback_test(struct e1000_adapter *adapter)
+{
+ struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ int i;
+
+ E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1);
+
+ for(i = 0; i < 64; i++) {
+ e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024);
+ pci_dma_sync_single(pdev, txdr->buffer_info[i].dma,
+ txdr->buffer_info[i].length,
+ PCI_DMA_TODEVICE);
+ }
+ E1000_WRITE_REG(&adapter->hw, TDT, i);
+
+ msec_delay(200);
+
+ pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma,
+ rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE);
+
+ return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024);
+}
+
+static int
+e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback;
+ if((*data = e1000_setup_loopback_test(adapter))) goto err_loopback;
+ *data = e1000_run_loopback_test(adapter);
+ e1000_loopback_cleanup(adapter);
+ e1000_free_desc_rings(adapter);
+err_loopback:
+ return *data;
+}
+
+static int
+e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
+{
+ *data = 0;
+ e1000_check_for_link(&adapter->hw);
+
+ if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
+ *data = 1;
+ }
+ return *data;
+}
+
+static int
+e1000_ethtool_test(struct e1000_adapter *adapter,
+ struct ethtool_test *eth_test, uint64_t *data)
+{
+ boolean_t if_running = netif_running(adapter->netdev);
+
+ if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ /* Offline tests */
+
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result */
+ if(e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ if(if_running)
+ e1000_down(adapter);
+
+ e1000_reset(adapter);
+ if(e1000_reg_test(adapter, &data[0]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(e1000_eeprom_test(adapter, &data[1]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(e1000_intr_test(adapter, &data[2]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(e1000_loopback_test(adapter, &data[3]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000_reset(adapter);
+ if(if_running)
+ e1000_up(adapter);
+ } else {
+ /* Online tests */
+ if(e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* Offline tests aren't run; pass by default */
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ }
+ return 0;
+}
+
static void
e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
@@ -443,24 +1305,46 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
case ETHTOOL_GSTRINGS: {
struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
char *strings = NULL;
+ int err = 0;
if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
return -EFAULT;
switch(gstrings.string_set) {
- case ETH_SS_STATS:
+ case ETH_SS_TEST:
+ gstrings.len = E1000_TEST_LEN;
+ strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN,
+ GFP_KERNEL);
+ if(!strings)
+ return -ENOMEM;
+ memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN *
+ ETH_GSTRING_LEN);
+ break;
+ case ETH_SS_STATS: {
+ int i;
gstrings.len = E1000_STATS_LEN;
- strings = *e1000_gstrings_stats;
+ strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN,
+ GFP_KERNEL);
+ if(!strings)
+ return -ENOMEM;
+ for(i=0; i < E1000_STATS_LEN; i++) {
+ memcpy(&strings[i * ETH_GSTRING_LEN],
+ e1000_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ }
break;
+ }
default:
return -EOPNOTSUPP;
}
if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
- return -EFAULT;
+ err = -EFAULT;
addr += offsetof(struct ethtool_gstrings, data);
- if(copy_to_user(addr, strings,
+ if(!err && copy_to_user(addr, strings,
gstrings.len * ETH_GSTRING_LEN))
- return -EFAULT;
- return 0;
+ err = -EFAULT;
+
+ kfree(strings);
+ return err;
}
case ETHTOOL_GREGS: {
struct ethtool_regs regs = {ETHTOOL_GREGS};
@@ -522,16 +1406,14 @@ e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
void *ptr;
int err = 0;
+ if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
+ return -EFAULT;
+
eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL);
- if(eeprom_buff == NULL)
+ if(!eeprom_buff)
return -ENOMEM;
- if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
- err = -EFAULT;
- goto err_geeprom_ioctl;
- }
-
if((err = e1000_ethtool_geeprom(adapter, &eeprom,
eeprom_buff)))
goto err_geeprom_ioctl;
@@ -565,18 +1447,45 @@ err_geeprom_ioctl:
}
case ETHTOOL_GSTATS: {
struct {
- struct ethtool_stats cmd;
+ struct ethtool_stats eth_stats;
uint64_t data[E1000_STATS_LEN];
} stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
int i;
for(i = 0; i < E1000_STATS_LEN; i++)
- stats.data[i] =
- ((unsigned long *)&adapter->net_stats)[i];
+ stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
+ sizeof(uint64_t)) ?
+ *(uint64_t *)((char *)adapter +
+ e1000_gstrings_stats[i].stat_offset) :
+ *(uint32_t *)((char *)adapter +
+ e1000_gstrings_stats[i].stat_offset);
if(copy_to_user(addr, &stats, sizeof(stats)))
return -EFAULT;
return 0;
}
+ case ETHTOOL_TEST: {
+ struct {
+ struct ethtool_test eth_test;
+ uint64_t data[E1000_TEST_LEN];
+ } test = { {ETHTOOL_TEST} };
+ int err;
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test)))
+ return -EFAULT;
+
+ test.eth_test.len = E1000_TEST_LEN;
+
+ if((err = e1000_ethtool_test(adapter, &test.eth_test,
+ test.data)))
+ return err;
+
+ if(copy_to_user(addr, &test, sizeof(test)) != 0)
+ return -EFAULT;
+ return 0;
+ }
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 3527e7794635..539533515e20 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -185,6 +185,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
hw->mac_type = e1000_82546;
break;
case E1000_DEV_ID_82541EI:
@@ -288,9 +289,7 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
- if(hw->mac_type == e1000_82547)
- led_ctrl |= IGP_LED3_MODE;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
}
@@ -737,9 +736,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
- if(hw->mac_type == e1000_82547)
- led_ctrl |= IGP_LED3_MODE;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
@@ -2293,9 +2290,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= IGP_ACTIVITY_LED_ENABLE;
- if(hw->mac_type == e1000_82547)
- led_ctrl |= IGP_LED3_MODE;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
}
}
@@ -3801,6 +3796,7 @@ e1000_setup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -3842,6 +3838,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82546EB_COPPER:
case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -3896,6 +3893,7 @@ e1000_led_on(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -3949,6 +3947,7 @@ e1000_led_off(struct e1000_hw *hw)
case E1000_DEV_ID_82540EM_LOM:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546EB_COPPER:
+ case E1000_DEV_ID_82546EB_QUAD_COPPER:
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EP:
case E1000_DEV_ID_82547EI:
@@ -4206,7 +4205,11 @@ e1000_get_bus_info(struct e1000_hw *hw)
status = E1000_READ_REG(hw, STATUS);
hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
e1000_bus_type_pcix : e1000_bus_type_pci;
- if(hw->bus_type == e1000_bus_type_pci) {
+
+ if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+ hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
+ e1000_bus_speed_66 : e1000_bus_speed_120;
+ } else if(hw->bus_type == e1000_bus_type_pci) {
hw->bus_speed = (status & E1000_STATUS_PCI66) ?
e1000_bus_speed_66 : e1000_bus_speed_33;
} else {
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 3fe0febaa7e7..bfb91bc5d8a2 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -99,6 +99,7 @@ typedef enum {
e1000_bus_speed_33,
e1000_bus_speed_66,
e1000_bus_speed_100,
+ e1000_bus_speed_120,
e1000_bus_speed_133,
e1000_bus_speed_reserved
} e1000_bus_speed;
@@ -314,10 +315,11 @@ void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EP 0x1018
#define E1000_DEV_ID_82547EI 0x1019
-#define NUM_DEV_IDS 19
+#define NUM_DEV_IDS 20
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -601,7 +603,7 @@ struct e1000_ffvt_entry {
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
-#define E1000_FLA 0x0001C /* Flash Access Register - RW */
+#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
@@ -730,6 +732,7 @@ struct e1000_ffvt_entry {
* the registers function in the same manner.
*/
#define E1000_82542_CTRL E1000_CTRL
+#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
#define E1000_82542_STATUS E1000_STATUS
#define E1000_82542_EECD E1000_EECD
#define E1000_82542_EERD E1000_EERD
@@ -1485,7 +1488,6 @@ struct e1000_hw {
#define E1000_COLLISION_DISTANCE 64
#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
-#define E1000_GB_HDX_COLLISION_DISTANCE 512
#define E1000_COLD_SHIFT 12
/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 86f15dbb0a21..377596f3f443 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -30,7 +30,14 @@
/* Change Log
*
- * 5.0.43 3/5/03
+ * 5.1.11 5/6/03
+ * o Feature: Added support for 82546EB (Quad-port) hardware.
+ * o Feature: Added support for Diagnostics through Ethtool.
+ * o Cleanup: Removed /proc support.
+ * o Cleanup: Removed proprietary IDIAG interface.
+ * o Bug fix: TSO bug fixes.
+ *
+ * 5.0.42 3/5/03
* o Feature: Added support for 82541 and 82547 hardware.
* o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of
* eeproms.
@@ -46,51 +53,22 @@
* shared interrupt instances.
*
* 4.4.18 11/27/02
- * o Feature: Added user-settable knob for interrupt throttle rate (ITR).
- * o Cleanup: removed large static array allocations.
- * o Cleanup: C99 struct initializer format.
- * o Bug fix: restore VLAN settings when interface is brought up.
- * o Bug fix: return cleanly in probe if error in detecting MAC type.
- * o Bug fix: Wake up on magic packet by default only if enabled in eeprom.
- * o Bug fix: Validate MAC address in set_mac.
- * o Bug fix: Throw away zero-length Tx skbs.
- * o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
- *
- * 4.4.12 10/15/02
*/
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.0.43-k3";
+char e1000_driver_version[] = "5.1.11-k1";
char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
- * Private driver_data field (last one) stores an index into e1000_strings
* Wildcard entries (PCI_ANY_ID) should come last
* Last entry must be all 0s
*
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
- * Class, Class Mask, String Index }
+ * Class, Class Mask, private data (not used) }
*/
static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
- /* Intel(R) PRO/1000 Network Connection */
- {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0},
- {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0},
- {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0},
- {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
- {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
- {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
- {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
- /* Compaq Gigabit Ethernet Server Adapter */
- {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
- {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
- {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1},
- /* IBM Mobile, Desktop & Server Adapters */
- {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2},
- {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2},
- {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2},
- /* Generic */
{0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -106,6 +84,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
@@ -114,12 +93,6 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
-static char *e1000_strings[] = {
- "Intel(R) PRO/1000 Network Connection",
- "HP Gigabit Ethernet Server Adapter",
- "IBM Mobile, Desktop & Server Adapters"
-};
-
/* Local Function Prototypes */
int e1000_up(struct e1000_adapter *adapter);
@@ -130,7 +103,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void e1000_remove(struct pci_dev *pdev);
+static void __devexit e1000_remove(struct pci_dev *pdev);
static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev);
@@ -195,7 +168,6 @@ struct notifier_block e1000_notifier_reboot = {
.priority = 0
};
-
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -234,8 +206,9 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
ret = pci_module_init(&e1000_driver);
- if(ret >= 0)
+ if(ret >= 0) {
register_reboot_notifier(&e1000_notifier_reboot);
+ }
return ret;
}
@@ -439,7 +412,6 @@ e1000_probe(struct pci_dev *pdev,
netdev->base_addr = adapter->hw.io_base;
adapter->bd_number = cards_found;
- adapter->id_string = e1000_strings[ent->driver_data];
/* setup the private structure */
@@ -500,15 +472,14 @@ e1000_probe(struct pci_dev *pdev,
(void (*)(void *))e1000_tx_timeout_task, netdev);
register_netdev(netdev);
- memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
- adapter->ifname[IFNAMSIZ-1] = 0;
/* we're going to reset, so assume we have no link for now */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
+ printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Connection\n",
+ netdev->name);
e1000_check_options(adapter);
/* Initial Wake on LAN setting
@@ -568,7 +539,6 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);
-
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
@@ -831,8 +801,9 @@ e1000_configure_tx(struct e1000_adapter *adapter)
e1000_config_collision_dist(&adapter->hw);
- /* Setup Transmit Descriptor Settings for this adapter */
- adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+ /* Setup Transmit Descriptor Settings for eop descriptor */
+ adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP |
+ E1000_TXD_CMD_IFCS;
if(adapter->hw.report_tx_early == 1)
adapter->txd_cmd |= E1000_TXD_CMD_RS;
@@ -1435,7 +1406,7 @@ e1000_watchdog(unsigned long data)
#define E1000_TX_FLAGS_VLAN_SHIFT 16
static inline boolean_t
-e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
+e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
{
#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
@@ -1471,7 +1442,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags)
context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
- context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd |
+ context_desc->cmd_and_length = cpu_to_le32(
E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
(skb->len - (hdr_len)));
@@ -1504,8 +1475,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->upper_setup.tcp_fields.tucso = cso;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
- context_desc->cmd_and_length =
- cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+ context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
if(++i == adapter->tx_ring.count) i = 0;
adapter->tx_ring.next_to_use = i;
@@ -1520,7 +1490,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)
static inline int
-e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
+ unsigned int first)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
int len = skb->len, offset = 0, size, count = 0, i;
@@ -1588,6 +1559,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
}
if(--i < 0) i = tx_ring->count - 1;
tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[first].next_to_watch = i;
return count;
}
@@ -1597,12 +1569,9 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_tx_desc *tx_desc = NULL;
- uint32_t txd_upper, txd_lower;
+ uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
int i;
- txd_upper = 0;
- txd_lower = adapter->txd_cmd;
-
if(tx_flags & E1000_TX_FLAGS_TSO) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
E1000_TXD_CMD_TSE;
@@ -1630,7 +1599,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
if(++i == tx_ring->count) i = 0;
}
- tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
+ tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
@@ -1690,6 +1659,7 @@ static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev->priv;
+ unsigned int first;
int tx_flags = 0;
if(skb->len <= 0) {
@@ -1715,12 +1685,14 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
- if(e1000_tso(adapter, skb, tx_flags))
+ first = adapter->tx_ring.next_to_use;
+
+ if(e1000_tso(adapter, skb))
tx_flags |= E1000_TX_FLAGS_TSO;
else if(e1000_tx_csum(adapter, skb))
tx_flags |= E1000_TX_FLAGS_CSUM;
- e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags);
+ e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first), tx_flags);
netdev->trans_start = jiffies;
@@ -1952,6 +1924,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
}
if((hw->mac_type <= e1000_82546) &&
+ (hw->phy_type == e1000_phy_m88) &&
!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
adapter->phy_stats.receive_errors += phy_tmp;
}
@@ -2069,39 +2042,47 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- struct e1000_tx_desc *tx_desc;
- int i, cleaned = FALSE;
+ struct e1000_tx_desc *tx_desc, *eop_desc;
+ struct e1000_buffer *buffer_info;
+ int i, eop, cleaned = FALSE;
i = tx_ring->next_to_clean;
- tx_desc = E1000_TX_DESC(*tx_ring, i);
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
- while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
- cleaned = TRUE;
+ for(cleaned = FALSE; !cleaned; ) {
+ tx_desc = E1000_TX_DESC(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
- if(tx_ring->buffer_info[i].dma) {
+ if(buffer_info->dma) {
- pci_unmap_page(pdev,
- tx_ring->buffer_info[i].dma,
- tx_ring->buffer_info[i].length,
- PCI_DMA_TODEVICE);
+ pci_unmap_page(pdev,
+ buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_TODEVICE);
- tx_ring->buffer_info[i].dma = 0;
- }
+ buffer_info->dma = 0;
+ }
- if(tx_ring->buffer_info[i].skb) {
+ if(buffer_info->skb) {
- dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
+ dev_kfree_skb_any(buffer_info->skb);
- tx_ring->buffer_info[i].skb = NULL;
- }
+ buffer_info->skb = NULL;
+ }
- tx_desc->buffer_addr = 0;
- tx_desc->lower.data = 0;
- tx_desc->upper.data = 0;
+ tx_desc->buffer_addr = 0;
+ tx_desc->lower.data = 0;
+ tx_desc->upper.data = 0;
- if(++i == tx_ring->count) i = 0;
- tx_desc = E1000_TX_DESC(*tx_ring, i);
+ cleaned = (i == eop);
+ if(++i == tx_ring->count) i = 0;
+ }
+
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
}
tx_ring->next_to_clean = i;
@@ -2224,7 +2205,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
netif_rx(skb);
}
#endif /* CONFIG_E1000_NAPI */
-
netdev->last_rx = jiffies;
rx_desc->status = 0;
@@ -2677,7 +2657,6 @@ e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
return NOTIFY_DONE;
}
-
static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
index ded48bef9f82..7ce83879b811 100644
--- a/drivers/net/fc/iph5526.c
+++ b/drivers/net/fc/iph5526.c
@@ -134,7 +134,7 @@ clone_list[] __initdata = {
{0,}
};
-static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs);
static int initialize_register_pointers(struct fc_info *fi);
@@ -623,7 +623,7 @@ u_int bus_addr, bus_indx_addr, i;
}
-static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
+static irqreturn_t tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
{
struct Scsi_Host *host = dev_id;
struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
@@ -632,6 +632,7 @@ u_long flags;
spin_lock_irqsave(&fi->fc_lock, flags);
tachyon_interrupt_handler(irq, dev_id, regs);
spin_unlock_irqrestore(&fi->fc_lock, flags);
+ return IRQ_HANDLED;
}
static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs)
@@ -3720,12 +3721,13 @@ struct fc_info *fi = (struct fc_info*)dev->priv;
int iph5526_detect(Scsi_Host_Template *tmpt)
{
-struct Scsi_Host *host = NULL;
-struct iph5526_hostdata *hostdata;
-struct fc_info *fi = NULL;
-int no_of_hosts = 0, timeout, i, j, count = 0;
-u_int pci_maddr = 0;
-struct pci_dev *pdev = NULL;
+ struct Scsi_Host *host = NULL;
+ struct iph5526_hostdata *hostdata;
+ struct fc_info *fi = NULL;
+ int no_of_hosts = 0, i, j, count = 0;
+ u_int pci_maddr = 0;
+ struct pci_dev *pdev = NULL;
+ unsigned long timeout;
tmpt->proc_name = "iph5526";
if (pci_present() == 0) {
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 539e9d434d10..47ce93a052f2 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -188,7 +188,7 @@ struct fec_enet_private {
static int fec_enet_open(struct net_device *dev);
static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void fec_enet_mii(struct net_device *dev);
-static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
@@ -393,12 +393,13 @@ fec_timeout(struct net_device *dev)
/* The interrupt handler.
* This is called from the MPC core interrupt.
*/
-static void
+static irqreturn_t
fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
+ int handled = 0;
fecp = (volatile fec_t*)dev->base_addr;
@@ -413,20 +414,27 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
/* Handle receive event in its own function.
*/
- if (int_events & FEC_ENET_RXF)
+ if (int_events & FEC_ENET_RXF) {
+ handled = 1;
fec_enet_rx(dev);
+ }
/* Transmit OK, or non-fatal error. Update the buffer
descriptors. FEC handles all errors, we just discover
them as part of the transmit process.
*/
- if (int_events & FEC_ENET_TXF)
+ if (int_events & FEC_ENET_TXF) {
+ handled = 1;
fec_enet_tx(dev);
+ }
- if (int_events & FEC_ENET_MII)
+ if (int_events & FEC_ENET_MII) {
+ handled = 1;
fec_enet_mii(dev);
+ }
}
+ return IRQ_RETVAL(handled);
}
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 1e79b90e3718..be537a80fce7 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -114,7 +114,7 @@ extern int fmv18x_probe(struct net_device *dev);
static int fmv18x_probe1(struct net_device *dev, short ioaddr);
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void net_rx(struct net_device *dev);
static void net_timeout(struct net_device *dev);
static int net_close(struct net_device *dev);
@@ -423,7 +423,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static void
+static irqreturn_t
net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
@@ -476,7 +476,7 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&lp->lock);
}
}
- return;
+ return IRQ_RETVAL(status);
}
/* We have a good packet(s), get it/them out of the buffers. */
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 538e35c128e8..1c5de989caaf 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -199,7 +199,7 @@ static void z8530_init(void);
static void init_channel(struct scc_channel *scc);
static void scc_key_trx (struct scc_channel *scc, char tx);
-static void scc_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
static void scc_init_timer(struct scc_channel *scc);
static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev);
@@ -625,7 +625,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector)
#define SCC_IRQTIMEOUT 30000
-static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char vector;
struct scc_channel *scc;
@@ -653,7 +653,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
if (k == SCC_IRQTIMEOUT)
printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
- return;
+ return IRQ_HANDLED;
}
/* Find the SCC generating the interrupt by polling all attached SCCs
@@ -701,6 +701,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs)
} else
ctrl++;
}
+ return IRQ_HANDLED;
}
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 379a7f6b3b6a..dfcb2e5dab44 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -289,16 +289,29 @@ config TOSHIBA_FIR
<file:Documentation/modules.txt>.
The module will be called donauboe.
-config SMC_IRCC_FIR
- tristate "SMC IrCC (EXPERIMENTAL)"
+config SMC_IRCC_OLD
+ tristate "SMC IrCC (old driver) (EXPERIMENTAL)"
depends on EXPERIMENTAL && IRDA
help
Say Y here if you want to build support for the SMC Infrared
Communications Controller. It is used in the Fujitsu Lifebook 635t
- and Sony PCG-505TX. If you want to compile it as a module, say M
- here and read <file:Documentation/modules.txt>. The module will be
+ and Sony PCG-505TX. This driver is obsolete, will no more be
+ maintained and will be removed in favor of the new driver.
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. The module will be
called smc-ircc.
+config SMC_IRCC_FIR
+ tristate "SMSC IrCC (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && IRDA
+ help
+ Say Y here if you want to build support for the SMC Infrared
+ Communications Controller. It is used in a wide variety of
+ laptops (Fujitsu, Sony, Compaq and some Toshiba).
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. The module will be
+ called smsc-ircc2.o.
+
config ALI_FIR
tristate "ALi M5123 FIR (EXPERIMENTAL)"
depends on EXPERIMENTAL && IRDA
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 4d31d2b3c95c..fa89bee5c77b 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -15,13 +15,14 @@ obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o
obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o
obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o
obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o
-obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o
+obj-$(CONFIG_SMC_IRCC_OLD) += smc-ircc.o irport.o
+obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o
obj-$(CONFIG_ALI_FIR) += ali-ircc.o
obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o
# Old dongle drivers for old SIR drivers
-obj-$(CONFIG_ESI_OLD) += esi.o
-obj-$(CONFIG_TEKRAM_OLD) += tekram.o
-obj-$(CONFIG_ACTISYS_OLD) += actisys.o
+obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o
+obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o
+obj-$(CONFIG_ACTISYS_DONGLE_OLD) += actisys.o
obj-$(CONFIG_GIRBIL_DONGLE) += girbil.o
obj-$(CONFIG_LITELINK_DONGLE) += litelink.o
obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin.o
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 46223bbbb7c3..15a81f7b3775 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1451,6 +1451,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */
if (!skb->len) {
ali_ircc_change_speed(self, speed);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -1560,6 +1561,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Restore bank register */
switch_bank(iobase, BANK0);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -1974,6 +1976,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */
if (!skb->len) {
ali_ircc_change_speed(self, speed);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -1993,6 +1996,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 185035d28b17..25d510e5deb3 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1051,7 +1051,9 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
toshoboe_checkstuck (self);
- /* Check if we need to change the speed */
+ dev->trans_start = jiffies;
+
+ /* Check if we need to change the speed */
/* But not now. Wait after transmission if mtt not required */
speed=irda_get_next_speed(skb);
if ((speed != self->io.speed) && (speed != -1))
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 310e7ead2f4a..e0d26d1b5cd5 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -11,6 +11,7 @@
* Sources: serial.c by Linus Torvalds
*
* Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -48,6 +49,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/delay.h>
#include <linux/rtnetlink.h>
#include <asm/system.h>
@@ -72,14 +74,14 @@ static unsigned int qos_mtt_bits = 0x03;
static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL};
static char *driver_name = "irport";
-static void irport_write_wakeup(struct irport_cb *self);
-static int irport_write(int iobase, int fifo_size, __u8 *buf, int len);
-static void irport_receive(struct irport_cb *self);
+static inline void irport_write_wakeup(struct irport_cb *self);
+static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len);
+static inline void irport_receive(struct irport_cb *self);
static int irport_net_init(struct net_device *dev);
static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq,
int cmd);
-static int irport_is_receiving(struct irport_cb *self);
+static inline int irport_is_receiving(struct irport_cb *self);
static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts);
static int irport_raw_write(struct net_device *dev, __u8 *buf, int len);
static struct net_device_stats *irport_net_get_stats(struct net_device *dev);
@@ -169,7 +171,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
self->io.sir_base = iobase;
self->io.sir_ext = IO_EXTENT;
self->io.irq = irq;
- self->io.fifo_size = 16;
+ self->io.fifo_size = 16; /* 16550A and compatible */
/* Initialize QoS for this device */
irda_init_max_qos_capabilies(&self->qos);
@@ -181,39 +183,47 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
irda_qos_bits_to_value(&self->qos);
self->flags = IFF_SIR|IFF_PIO;
+ self->mode = IRDA_IRLAP;
+
+ /* Bootstrap ZeroCopy Rx */
+ self->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+ self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize,
+ GFP_KERNEL);
+ if (self->rx_buff.skb == NULL)
+ return NULL;
+ skb_reserve(self->rx_buff.skb, 1);
+ self->rx_buff.head = self->rx_buff.skb->data;
+ /* No need to memset the buffer, unless you are really pedantic */
+
+ /* Finish setup the Rx buffer descriptor */
+ self->rx_buff.in_frame = FALSE;
+ self->rx_buff.state = OUTSIDE_FRAME;
+ self->rx_buff.data = self->rx_buff.head;
/* Specify how much memory we want */
- self->rx_buff.truesize = 4000;
self->tx_buff.truesize = 4000;
/* Allocate memory if needed */
- if (self->rx_buff.truesize > 0) {
- self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
- GFP_KERNEL);
- if (self->rx_buff.head == NULL)
- return NULL;
- memset(self->rx_buff.head, 0, self->rx_buff.truesize);
- }
if (self->tx_buff.truesize > 0) {
self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize,
GFP_KERNEL);
if (self->tx_buff.head == NULL) {
- kfree(self->rx_buff.head);
+ kfree_skb(self->rx_buff.skb);
+ self->rx_buff.skb = NULL;
+ self->rx_buff.head = NULL;
return NULL;
}
memset(self->tx_buff.head, 0, self->tx_buff.truesize);
}
- self->rx_buff.in_frame = FALSE;
- self->rx_buff.state = OUTSIDE_FRAME;
self->tx_buff.data = self->tx_buff.head;
- self->rx_buff.data = self->rx_buff.head;
- self->mode = IRDA_IRLAP;
if (!(dev = dev_alloc("irda%d", &err))) {
ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
return NULL;
}
self->netdev = dev;
+ /* Keep track of module usage */
+ SET_MODULE_OWNER(dev);
/* May be overridden by piggyback drivers */
dev->priv = (void *) self;
@@ -241,7 +251,8 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
return NULL;
}
- MESSAGE("IrDA: Registered device %s\n", dev->name);
+ MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n",
+ dev->name, iobase, irq);
return self;
}
@@ -270,8 +281,9 @@ int irport_close(struct irport_cb *self)
if (self->tx_buff.head)
kfree(self->tx_buff.head);
- if (self->rx_buff.head)
- kfree(self->rx_buff.head);
+ if (self->rx_buff.skb)
+ kfree_skb(self->rx_buff.skb);
+ self->rx_buff.skb = NULL;
/* Remove ourselves */
dev_self[self->index] = NULL;
@@ -306,6 +318,9 @@ void irport_stop(struct irport_cb *self)
/* We can't lock, we may be called from a FIR driver - Jean II */
+ /* We are not transmitting any more */
+ self->transmitting = 0;
+
/* Reset UART */
outb(0, iobase+UART_MCR);
@@ -327,6 +342,33 @@ int irport_probe(int iobase)
}
/*
+ * Function irport_get_fcr (speed)
+ *
+ * Compute value of fcr
+ *
+ */
+static inline unsigned int irport_get_fcr(__u32 speed)
+{
+ unsigned int fcr; /* FIFO control reg */
+
+ /* Enable fifos */
+ fcr = UART_FCR_ENABLE_FIFO;
+
+ /*
+ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+ * about this timeout since it will always be fast enough.
+ */
+ if (speed < 38400)
+ fcr |= UART_FCR_TRIGGER_1;
+ else
+ //fcr |= UART_FCR_TRIGGER_14;
+ fcr |= UART_FCR_TRIGGER_8;
+
+ return(fcr);
+}
+
+/*
* Function irport_change_speed (self, speed)
*
* Set speed of IrDA port to specified baudrate
@@ -337,11 +379,12 @@ void irport_change_speed(void *priv, __u32 speed)
{
struct irport_cb *self = (struct irport_cb *) priv;
int iobase;
- int fcr; /* FIFO control reg */
- int lcr; /* Line control reg */
+ unsigned int fcr; /* FIFO control reg */
+ unsigned int lcr; /* Line control reg */
int divisor;
ASSERT(self != NULL, return;);
+ ASSERT(speed != 0, return;);
IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n",
__FUNCTION__, speed, self->io.sir_base);
@@ -358,18 +401,9 @@ void irport_change_speed(void *priv, __u32 speed)
divisor = SPEED_MAX/speed;
- fcr = UART_FCR_ENABLE_FIFO;
+ /* Get proper fifo configuration */
+ fcr = irport_get_fcr(speed);
- /*
- * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
- * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
- * about this timeout since it will always be fast enough.
- */
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
-
/* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8;
@@ -380,7 +414,7 @@ void irport_change_speed(void *priv, __u32 speed)
outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
/* Turn on interrups */
- /* This will generate a fata interrupt storm.
+ /* This will generate a fatal interrupt storm.
* People calling us will do that properly - Jean II */
//outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
}
@@ -467,8 +501,8 @@ int __irport_change_speed(struct irda_task *task)
irda_task_next_state(task, IRDA_TASK_DONE);
ret = -1;
break;
- }
- /* Put stuff in the sate we found them - Jean II */
+ }
+ /* Put stuff in the state we found them - Jean II */
if(wasunlocked) {
spin_unlock_irqrestore(&self->lock, flags);
}
@@ -477,98 +511,6 @@ int __irport_change_speed(struct irda_task *task)
}
/*
- * Function irport_write_wakeup (tty)
- *
- * Called by the driver when there's room for more data. If we have
- * more packets to send, we send them here.
- *
- */
-static void irport_write_wakeup(struct irport_cb *self)
-{
- int actual = 0;
- int iobase;
- int fcr;
-
- ASSERT(self != NULL, return;);
-
- IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
-
- iobase = self->io.sir_base;
-
- /* Finished with frame? */
- if (self->tx_buff.len > 0) {
- /* Write data left in transmit buffer */
- actual = irport_write(iobase, self->io.fifo_size,
- self->tx_buff.data, self->tx_buff.len);
- self->tx_buff.data += actual;
- self->tx_buff.len -= actual;
-
- /* Turn on transmit finished interrupt. */
- outb(UART_IER_THRI, iobase+UART_IER);
- } else {
- /*
- * Now serial buffer is almost free & we can start
- * transmission of another packet. But first we must check
- * if we need to change the speed of the hardware
- */
- if (self->new_speed) {
- IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
- irda_task_execute(self, __irport_change_speed,
- irport_change_speed_complete,
- NULL, (void *) self->new_speed);
- self->new_speed = 0;
- IRDA_DEBUG(5, "%s(), Speed changed!\n", __FUNCTION__ );
- } else {
- /* Tell network layer that we want more frames */
- netif_wake_queue(self->netdev);
- }
- self->stats.tx_packets++;
-
- /*
- * Reset Rx FIFO to make sure that all reflected transmit data
- * is discarded. This is needed for half duplex operation
- */
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
- if (self->io.speed < 38400)
- fcr |= UART_FCR_TRIGGER_1;
- else
- fcr |= UART_FCR_TRIGGER_14;
-
- outb(fcr, iobase+UART_FCR);
-
- /* Turn on receive interrupts */
- outb(UART_IER_RDI, iobase+UART_IER);
- }
-}
-
-/*
- * Function irport_write (driver)
- *
- * Fill Tx FIFO with transmit data
- *
- */
-static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
-{
- int actual = 0;
-
- /* Tx FIFO should be empty! */
- if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__);
- return 0;
- }
-
- /* Fill FIFO with current frame */
- while ((fifo_size-- > 0) && (actual < len)) {
- /* Transmit next byte */
- outb(buf[actual], iobase+UART_TX);
-
- actual++;
- }
-
- return actual;
-}
-
-/*
* Function irport_change_speed_complete (task)
*
* Called when the change speed operation completes
@@ -604,24 +546,80 @@ static void irport_timeout(struct net_device *dev)
{
struct irport_cb *self;
int iobase;
+ int iir, lsr;
unsigned long flags;
self = (struct irport_cb *) dev->priv;
+ ASSERT(self != NULL, return;);
iobase = self->io.sir_base;
- WARNING("%s: transmit timed out\n", dev->name);
+ WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n",
+ dev->name, jiffies, dev->trans_start);
spin_lock_irqsave(&self->lock, flags);
+
+ /* Debug what's happening... */
+
+ /* Get interrupt status */
+ lsr = inb(iobase+UART_LSR);
+ /* Read interrupt register */
+ iir = inb(iobase+UART_IIR);
+ IRDA_DEBUG(0, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ __FUNCTION__, iir, lsr, iobase);
+
+ IRDA_DEBUG(0, "%s(), transmitting=%d, remain=%d, done=%d\n",
+ __FUNCTION__, self->transmitting, self->tx_buff.len,
+ self->tx_buff.data - self->tx_buff.head);
+
+ /* Now, restart the port */
irport_start(self);
self->change_speed(self->priv, self->io.speed);
/* This will re-enable irqs */
outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
- dev->trans_start = jiffies;
netif_wake_queue(dev);
}
/*
+ * Function irport_wait_hw_transmitter_finish ()
+ *
+ * Wait for the real end of HW transmission
+ *
+ * The UART is a strict FIFO, and we get called only when we have finished
+ * pushing data to the FIFO, so the maximum amount of time we must wait
+ * is only for the FIFO to drain out.
+ *
+ * We use a simple calibrated loop. We may need to adjust the loop
+ * delay (udelay) to balance I/O traffic and latency. And we also need to
+ * adjust the maximum timeout.
+ * It would probably be better to wait for the proper interrupt,
+ * but it doesn't seem to be available.
+ *
+ * We can't use jiffies or kernel timers because :
+ * 1) We are called from the interrupt handler, which disable softirqs,
+ * so jiffies won't be increased
+ * 2) Jiffies granularity is usually very coarse (10ms), and we don't
+ * want to wait that long to detect stuck hardware.
+ * Jean II
+ */
+
+static void irport_wait_hw_transmitter_finish(struct irport_cb *self)
+{
+ int iobase;
+ int count = 1000; /* 1 ms */
+
+ iobase = self->io.sir_base;
+
+ /* Calibrated busy loop */
+ while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
+ udelay(1);
+
+ if(count == 0)
+ IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
+}
+
+/*
* Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev)
*
* Transmits the current frame until FIFO is full, then
@@ -645,8 +643,8 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
iobase = self->io.sir_base;
netif_stop_queue(dev);
-
- /* Make sure tests *& speed change are atomic */
+
+ /* Make sure tests & speed change are atomic */
spin_lock_irqsave(&self->lock, flags);
/* Check if we need to change the speed */
@@ -654,10 +652,21 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
if ((speed != self->io.speed) && (speed != -1)) {
/* Check for empty frame */
if (!skb->len) {
+ /*
+ * We send frames one by one in SIR mode (no
+ * pipelining), so at this point, if we were sending
+ * a previous frame, we just received the interrupt
+ * telling us it is finished (UART_IIR_THRI).
+ * Therefore, waiting for the transmitter to really
+ * finish draining the fifo won't take too long.
+ * And the interrupt handler is not expected to run.
+ * - Jean II */
+ irport_wait_hw_transmitter_finish(self);
/* Better go there already locked - Jean II */
irda_task_execute(self, __irport_change_speed,
irport_change_speed_complete,
NULL, (void *) speed);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -674,9 +683,13 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->stats.tx_bytes += self->tx_buff.len;
+ /* We are transmitting */
+ self->transmitting = 1;
+
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -685,12 +698,100 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
}
/*
+ * Function irport_write (driver)
+ *
+ * Fill Tx FIFO with transmit data
+ *
+ * Called only from irport_write_wakeup()
+ */
+static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
+{
+ int actual = 0;
+
+ /* Fill FIFO with current frame */
+ while ((actual < fifo_size) && (actual < len)) {
+ /* Transmit next byte */
+ outb(buf[actual], iobase+UART_TX);
+
+ actual++;
+ }
+
+ return actual;
+}
+
+/*
+ * Function irport_write_wakeup (tty)
+ *
+ * Called by the driver when there's room for more data. If we have
+ * more packets to send, we send them here.
+ *
+ * Called only from irport_interrupt()
+ * Make sure this function is *not* called while we are receiving,
+ * otherwise we will reset fifo and loose data :-(
+ */
+static inline void irport_write_wakeup(struct irport_cb *self)
+{
+ int actual = 0;
+ int iobase;
+ unsigned int fcr;
+
+ ASSERT(self != NULL, return;);
+
+ IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+
+ iobase = self->io.sir_base;
+
+ /* Finished with frame? */
+ if (self->tx_buff.len > 0) {
+ /* Write data left in transmit buffer */
+ actual = irport_write(iobase, self->io.fifo_size,
+ self->tx_buff.data, self->tx_buff.len);
+ self->tx_buff.data += actual;
+ self->tx_buff.len -= actual;
+ } else {
+ /*
+ * Now serial buffer is almost free & we can start
+ * transmission of another packet. But first we must check
+ * if we need to change the speed of the hardware
+ */
+ if (self->new_speed) {
+ irport_wait_hw_transmitter_finish(self);
+ irda_task_execute(self, __irport_change_speed,
+ irport_change_speed_complete,
+ NULL, (void *) self->new_speed);
+ self->new_speed = 0;
+ } else {
+ /* Tell network layer that we want more frames */
+ netif_wake_queue(self->netdev);
+ }
+ self->stats.tx_packets++;
+
+ /*
+ * Reset Rx FIFO to make sure that all reflected transmit data
+ * is discarded. This is needed for half duplex operation
+ */
+ fcr = irport_get_fcr(self->io.speed);
+ fcr |= UART_FCR_CLEAR_RCVR;
+ outb(fcr, iobase+UART_FCR);
+
+ /* Finished transmitting */
+ self->transmitting = 0;
+
+ /* Turn on receive interrupts */
+ outb(UART_IER_RDI, iobase+UART_IER);
+
+ IRDA_DEBUG(1, "%s() : finished Tx\n", __FUNCTION__);
+ }
+}
+
+/*
* Function irport_receive (self)
*
* Receive one frame from the infrared port
*
+ * Called only from irport_interrupt()
*/
-static void irport_receive(struct irport_cb *self)
+static inline void irport_receive(struct irport_cb *self)
{
int boguscount = 0;
int iobase;
@@ -739,40 +840,51 @@ irqreturn_t irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
iobase = self->io.sir_base;
- iir = inb(iobase+UART_IIR) & UART_IIR_ID;
- while (iir) {
- handled = 1;
+ /* Cut'n'paste interrupt routine from serial.c
+ * This version try to minimise latency and I/O operations.
+ * Simplified and modified to enforce half duplex operation.
+ * - Jean II */
- /* Clear interrupt */
+ /* Check status even is iir reg is cleared, more robust and
+ * eliminate a read on the I/O bus - Jean II */
+ do {
+ /* Get interrupt status ; Clear interrupt */
lsr = inb(iobase+UART_LSR);
+
+ /* Are we receiving or transmitting ? */
+ if(!self->transmitting) {
+ /* Received something ? */
+ if (lsr & UART_LSR_DR)
+ irport_receive(self);
+ } else {
+ /* Room in Tx fifo ? */
+ if (lsr & (UART_LSR_THRE | UART_LSR_TEMT))
+ irport_write_wakeup(self);
+ }
- IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
- __FUNCTION__, iir, lsr, iobase);
+ /* A bit hackish, but working as expected... Jean II */
+ if(lsr & (UART_LSR_THRE | UART_LSR_TEMT | UART_LSR_DR))
+ handled = 1;
- switch (iir) {
- case UART_IIR_RLSI:
- IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);
- break;
- case UART_IIR_RDI:
- /* Receive interrupt */
- irport_receive(self);
- break;
- case UART_IIR_THRI:
- if (lsr & UART_LSR_THRE)
- /* Transmitter ready for data */
- irport_write_wakeup(self);
- break;
- default:
- IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir);
- break;
- }
-
- /* Make sure we don't stay here too long */
- if (boguscount++ > 100)
+ /* Make sure we don't stay here to long */
+ if (boguscount++ > 10) {
+ WARNING("%s() irq handler looping : lsr=%02x\n",
+ __FUNCTION__, lsr);
break;
+ }
+
+ /* Read interrupt register */
+ iir = inb(iobase+UART_IIR);
+
+ /* Enable this debug only when no other options and at low
+ * bit rates, otherwise it may cause Rx overruns (lsr=63).
+ * - Jean II */
+ IRDA_DEBUG(6, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ __FUNCTION__, iir, lsr, iobase);
+
+ /* As long as interrupt pending... */
+ } while ((iir & UART_IIR_NO_INT) == 0);
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
- }
spin_unlock(&self->lock);
return IRQ_RETVAL(handled);
}
@@ -800,8 +912,8 @@ int irport_net_open(struct net_device *dev)
char hwname[16];
unsigned long flags;
- IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
-
+ IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
ASSERT(dev != NULL, return -1;);
self = (struct irport_cb *) dev->priv;
@@ -815,7 +927,12 @@ int irport_net_open(struct net_device *dev)
}
spin_lock_irqsave(&self->lock, flags);
+ /* Init uart */
irport_start(self);
+ /* Set 9600 bauds per default, including at the dongle */
+ irda_task_execute(self, __irport_change_speed,
+ irport_change_speed_complete,
+ NULL, (void *) 9600);
spin_unlock_irqrestore(&self->lock, flags);
@@ -828,12 +945,9 @@ int irport_net_open(struct net_device *dev)
*/
self->irlap = irlap_open(dev, &self->qos, hwname);
- /* FIXME: change speed of dongle */
/* Ready to play! */
netif_start_queue(dev);
-
- MOD_INC_USE_COUNT;
return 0;
}
@@ -873,40 +987,16 @@ int irport_net_close(struct net_device *dev)
free_irq(self->io.irq, dev);
- MOD_DEC_USE_COUNT;
-
return 0;
}
/*
- * Function irport_wait_until_sent (self)
- *
- * Delay exectution until finished transmitting
- *
- */
-#if 0
-void irport_wait_until_sent(struct irport_cb *self)
-{
- int iobase;
-
- iobase = self->io.sir_base;
-
- /* Wait until Tx FIFO is empty */
- while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- IRDA_DEBUG(2, "%s(), waiting!\n", __FUNCTION__);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(MSECS_TO_JIFFIES(60));
- }
-}
-#endif
-
-/*
* Function irport_is_receiving (self)
*
* Returns true is we are currently receiving data
*
*/
-static int irport_is_receiving(struct irport_cb *self)
+static inline int irport_is_receiving(struct irport_cb *self)
{
return (self->rx_buff.state != OUTSIDE_FRAME);
}
@@ -998,6 +1088,12 @@ static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
break;
}
+ /* Locking :
+ * irda_device_dongle_init() can't be locked.
+ * irda_task_execute() doesn't need to be locked.
+ * Jean II
+ */
+
/* Initialize dongle */
dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
if (!dongle)
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 87deb312b94c..a2d387ced051 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -504,10 +504,7 @@ static int irtty_open(struct tty_struct *tty)
struct sirtty_cb *priv;
int ret = 0;
- /* unfortunately, there's no tty_ldisc->owner field
- * so there is some window for SMP race with rmmod
- */
- MOD_INC_USE_COUNT;
+ /* Module stuff handled via irda_ldisc.owner - Jean II */
/* First make sure we're not already connected. */
if (tty->disc_data != NULL) {
@@ -569,7 +566,6 @@ static int irtty_open(struct tty_struct *tty)
out_put:
sirdev_put_instance(dev);
out:
- MOD_DEC_USE_COUNT;
return ret;
}
@@ -614,8 +610,6 @@ static void irtty_close(struct tty_struct *tty)
tty->driver->stop(tty);
kfree(priv);
-
- MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------- */
@@ -633,6 +627,7 @@ static struct tty_ldisc irda_ldisc = {
.receive_buf = irtty_receive_buf,
.receive_room = irtty_receive_room,
.write_wakeup = irtty_write_wakeup,
+ .owner = THIS_MODULE,
};
/* ------------------------------------------------------- */
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index ada9a3feda69..6f847c07d710 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1096,6 +1096,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
* to make sure packets gets through the
* proper xmit handler - Jean II */
}
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -1120,6 +1121,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
/* Restore bank register */
outb(bank, iobase+BSR);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -1164,6 +1166,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
* the speed change has been done.
* Jean II */
}
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -1250,6 +1253,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
/* Restore bank register */
outb(bank, iobase+BSR);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c
index 293c05c27cd0..cc38b8809b14 100644
--- a/drivers/net/irda/sir_kthread.c
+++ b/drivers/net/irda/sir_kthread.c
@@ -151,6 +151,13 @@ static int irda_thread(void *startup)
while (irda_rq_queue.thread != NULL) {
+ /* We use TASK_INTERRUPTIBLE, rather than
+ * TASK_UNINTERRUPTIBLE. Andrew Morton made this
+ * change ; he told me that it is safe, because "signal
+ * blocking is now handled in daemonize()", he added
+ * that the problem is that "uninterruptible sleep
+ * contributes to load average", making user worry.
+ * Jean II */
set_task_state(current, TASK_INTERRUPTIBLE);
add_wait_queue(&irda_rq_queue.kick, &wait);
if (list_empty(&irda_rq_queue.request_list))
diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
index f802455b8ada..91f476547a83 100644
--- a/drivers/net/irda/smc-ircc.c
+++ b/drivers/net/irda/smc-ircc.c
@@ -529,6 +529,9 @@ static int __init ircc_open(unsigned int fir_base, unsigned int sir_base)
irport->priv = self;
+ /* Keep track of module usage */
+ SET_MODULE_OWNER(self->netdev);
+
/* Initialize IO */
self->io = &irport->io;
self->io->fir_base = fir_base;
@@ -747,6 +750,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */
if (!skb->len) {
ircc_change_speed(self, speed);
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->irport->lock, flags);
dev_kfree_skb(skb);
return 0;
@@ -776,6 +780,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Transmit frame */
ircc_dma_xmit(self, iobase, 0);
}
+ dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->irport->lock, flags);
dev_kfree_skb(skb);
@@ -1090,8 +1095,6 @@ static int ircc_net_open(struct net_device *dev)
WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma);
return -EAGAIN;
}
-
- MOD_INC_USE_COUNT;
return 0;
}
@@ -1124,8 +1127,6 @@ static int ircc_net_close(struct net_device *dev)
free_dma(self->io->dma);
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -1187,6 +1188,9 @@ static int __exit ircc_close(struct ircc_cb *self)
iobase = self->irport->io.fir_base;
+ if (self->pmdev)
+ pm_unregister(self->pmdev);
+
/* This will destroy irport */
irport_close(self->irport);
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
new file mode 100644
index 000000000000..447c6aa4d1c8
--- /dev/null
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -0,0 +1,2441 @@
+/*********************************************************************
+ * $Id: smsc-ircc2.c,v 1.19.2.5 2002/10/27 11:34:26 dip Exp $
+ *
+ * Description: Driver for the SMC Infrared Communications Controller
+ * Status: Experimental.
+ * Author: Daniele Peri (peri@csai.unipa.it)
+ * Created at:
+ * Modified at:
+ * Modified by:
+ *
+ * Copyright (c) 2002 Daniele Peri
+ * All Rights Reserved.
+ * Copyright (c) 2002 Jean Tourrilhes
+ *
+ *
+ * Based on smc-ircc.c:
+ *
+ * Copyright (c) 2001 Stefani Seibold
+ * Copyright (c) 1999-2001 Dag Brattli
+ * Copyright (c) 1998-1999 Thomas Davis,
+ *
+ * and irport.c:
+ *
+ * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/rtnetlink.h>
+#include <linux/serial_reg.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include "smsc-ircc2.h"
+#include "smsc-sio.h"
+
+/* Types */
+
+struct smsc_transceiver {
+ char *name;
+ void (*set_for_speed)(int fir_base, u32 speed);
+ int (*probe)(int fir_base);
+};
+typedef struct smsc_transceiver smsc_transceiver_t;
+
+#if 0
+struct smc_chip {
+ char *name;
+ u16 flags;
+ u8 devid;
+ u8 rev;
+};
+typedef struct smc_chip smc_chip_t;
+#endif
+
+struct smsc_chip {
+ char *name;
+ #if 0
+ u8 type;
+ #endif
+ u16 flags;
+ u8 devid;
+ u8 rev;
+};
+typedef struct smsc_chip smsc_chip_t;
+
+struct smsc_chip_address {
+ unsigned int cfg_base;
+ unsigned int type;
+};
+typedef struct smsc_chip_address smsc_chip_address_t;
+
+/* Private data for each instance */
+struct smsc_ircc_cb {
+ struct net_device *netdev; /* Yes! we are some kind of netdevice */
+ struct net_device_stats stats;
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+
+ chipio_t io; /* IrDA controller information */
+ iobuff_t tx_buff; /* Transmit buffer */
+ iobuff_t rx_buff; /* Receive buffer */
+
+ struct qos_info qos; /* QoS capabilities for this device */
+
+ spinlock_t lock; /* For serializing operations */
+
+ __u32 new_speed;
+ __u32 flags; /* Interface flags */
+
+ int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
+ int tx_len; /* Number of frames in tx_buff */
+
+ int transceiver;
+ struct pm_dev *pmdev;
+};
+
+/* Constants */
+
+static const char *driver_name = "smsc-ircc2";
+#define DIM(x) (sizeof(x)/(sizeof(*(x))))
+#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600
+#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1
+#define SMSC_IRCC2_C_NET_TIMEOUT 0
+#define SMSC_IRCC2_C_SIR_STOP 0
+
+/* Prototypes */
+
+static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq);
+static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base);
+static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq);
+static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self);
+static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self);
+static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self);
+static void smsc_ircc_init_chip(struct smsc_ircc_cb *self);
+static int __exit smsc_ircc_close(struct smsc_ircc_cb *self);
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase);
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase);
+static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self);
+static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
+static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs);
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase);
+static void smsc_ircc_change_speed(void *priv, u32 speed);
+static void smsc_ircc_set_sir_speed(void *priv, u32 speed);
+static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void smsc_ircc_interrupt_sir(int irq, void *dev_id, struct pt_regs *regs);
+static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
+#if SMSC_IRCC2_C_SIR_STOP
+static void smsc_ircc_sir_stop(struct smsc_ircc_cb *self);
+#endif
+static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self);
+static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len);
+static int smsc_ircc_net_init(struct net_device *dev);
+static int smsc_ircc_net_open(struct net_device *dev);
+static int smsc_ircc_net_close(struct net_device *dev);
+static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#if SMSC_IRCC2_C_NET_TIMEOUT
+static void smsc_ircc_timeout(struct net_device *dev);
+#endif
+static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev);
+static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
+static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
+static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
+static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
+
+/* Probing */
+static int __init smsc_ircc_look_for_chips(void);
+static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type);
+static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_paged(const smsc_chip_t *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);
+
+/* Transceivers specific functions */
+
+static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed);
+static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base);
+static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed);
+static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base);
+static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed);
+static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base);
+
+/* Power Management */
+
+static void smsc_ircc_suspend(struct smsc_ircc_cb *self);
+static void smsc_ircc_wakeup(struct smsc_ircc_cb *self);
+static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+
+/* Transceivers for SMSC-ircc */
+
+smsc_transceiver_t smsc_transceivers[]=
+{
+ { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800},
+ { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select},
+ { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc},
+ { NULL, NULL}
+};
+#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (DIM(smsc_transceivers)-1)
+
+/* SMC SuperIO chipsets definitions */
+
+#define KEY55_1 0 /* SuperIO Configuration mode with Key <0x55> */
+#define KEY55_2 1 /* SuperIO Configuration mode with Key <0x55,0x55> */
+#define NoIRDA 2 /* SuperIO Chip has no IRDA Port */
+#define SIR 0 /* SuperIO Chip has only slow IRDA */
+#define FIR 4 /* SuperIO Chip has fast IRDA */
+#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */
+
+static smsc_chip_t __initdata fdc_chips_flat[]=
+{
+ /* Base address 0x3f0 or 0x370 */
+ { "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */
+ { "37C665GT", KEY55_2|NoIRDA, 0x65, 0x01 },
+ { "37C665GT", KEY55_2|NoIRDA, 0x66, 0x01 },
+ { "37C669", KEY55_2|SIR|SERx4, 0x03, 0x02 },
+ { "37C669", KEY55_2|SIR|SERx4, 0x04, 0x02 }, /* ID? */
+ { "37C78", KEY55_2|NoIRDA, 0x78, 0x00 },
+ { "37N769", KEY55_1|FIR|SERx4, 0x28, 0x00 },
+ { "37N869", KEY55_1|FIR|SERx4, 0x29, 0x00 },
+ { NULL }
+};
+
+static smsc_chip_t __initdata fdc_chips_paged[]=
+{
+ /* Base address 0x3f0 or 0x370 */
+ { "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 },
+ { "37B77X", KEY55_1|SIR|SERx4, 0x43, 0x00 },
+ { "37B78X", KEY55_1|SIR|SERx4, 0x44, 0x00 },
+ { "37B80X", KEY55_1|SIR|SERx4, 0x42, 0x00 },
+ { "37C67X", KEY55_1|FIR|SERx4, 0x40, 0x00 },
+ { "37C93X", KEY55_2|SIR|SERx4, 0x02, 0x01 },
+ { "37C93XAPM", KEY55_1|SIR|SERx4, 0x30, 0x01 },
+ { "37C93XFR", KEY55_2|FIR|SERx4, 0x03, 0x01 },
+ { "37M707", KEY55_1|SIR|SERx4, 0x42, 0x00 },
+ { "37M81X", KEY55_1|SIR|SERx4, 0x4d, 0x00 },
+ { "37N958FR", KEY55_1|FIR|SERx4, 0x09, 0x04 },
+ { "37N971", KEY55_1|FIR|SERx4, 0x0a, 0x00 },
+ { "37N972", KEY55_1|FIR|SERx4, 0x0b, 0x00 },
+ { NULL }
+};
+
+static smsc_chip_t __initdata lpc_chips_flat[]=
+{
+ /* Base address 0x2E or 0x4E */
+ { "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 },
+ { "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 },
+ { NULL }
+};
+
+static smsc_chip_t __initdata lpc_chips_paged[]=
+{
+ /* Base address 0x2E or 0x4E */
+ { "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 },
+ { "47B37X", KEY55_1|SIR|SERx4, 0x52, 0x00 },
+ { "47M10X", KEY55_1|SIR|SERx4, 0x59, 0x00 },
+ { "47M120", KEY55_1|NoIRDA|SERx4, 0x5c, 0x00 },
+ { "47M13X", KEY55_1|SIR|SERx4, 0x59, 0x00 },
+ { "47M14X", KEY55_1|SIR|SERx4, 0x5f, 0x00 },
+ { "47N252", KEY55_1|FIR|SERx4, 0x0e, 0x00 },
+ { "47S42X", KEY55_1|SIR|SERx4, 0x57, 0x00 },
+ { NULL }
+};
+
+#define SMSCSIO_TYPE_FDC 1
+#define SMSCSIO_TYPE_LPC 2
+#define SMSCSIO_TYPE_FLAT 4
+#define SMSCSIO_TYPE_PAGED 8
+
+static smsc_chip_address_t __initdata possible_addresses[]=
+{
+ {0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
+ {0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
+ {0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
+ {0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
+ {0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED},
+ {0,0}
+};
+
+/* Globals */
+
+static struct smsc_ircc_cb *dev_self[] = { NULL, NULL};
+
+static int ircc_irq=255;
+static int ircc_dma=255;
+static int ircc_fir=0;
+static int ircc_sir=0;
+static int ircc_cfg=0;
+static int ircc_transceiver=0;
+
+static unsigned short dev_count=0;
+
+static inline void register_bank(int iobase, int bank)
+{
+ outb(((inb(iobase+IRCC_MASTER) & 0xf0) | (bank & 0x07)),
+ iobase+IRCC_MASTER);
+}
+
+
+/*******************************************************************************
+ *
+ *
+ * SMSC-ircc stuff
+ *
+ *
+ *******************************************************************************/
+
+/*
+ * Function smsc_ircc_init ()
+ *
+ * Initialize chip. Just try to find out how many chips we are dealing with
+ * and where they are
+ */
+int __init smsc_ircc_init(void)
+{
+ int ret=-ENODEV;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ dev_count=0;
+
+ if ((ircc_fir>0)&&(ircc_sir>0)) {
+ MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
+ MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
+
+ if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq) == 0)
+ return 0;
+
+ return -ENODEV;
+ }
+
+ /* try user provided configuration register base address */
+ if (ircc_cfg>0) {
+ MESSAGE(" Overriding configuration address 0x%04x\n", ircc_cfg);
+ if (!smsc_superio_fdc(ircc_cfg))
+ ret = 0;
+ if (!smsc_superio_lpc(ircc_cfg))
+ ret = 0;
+ }
+
+ if(smsc_ircc_look_for_chips()>0) ret = 0;
+
+ return ret;
+}
+
+/*
+ * Function smsc_ircc_open (firbase, sirbase, dma, irq)
+ *
+ * Try to open driver instance
+ *
+ */
+static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+{
+ struct smsc_ircc_cb *self;
+ int err;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ err= smsc_ircc_present(fir_base, sir_base);
+ if(err) return -ENODEV;
+
+ if (dev_count>DIM(dev_self)) {
+ WARNING("%s(), too many devices!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ /*
+ * Allocate new instance of the driver
+ */
+ self = kmalloc(sizeof(struct smsc_ircc_cb), GFP_KERNEL);
+ if (self == NULL) {
+ ERROR("%s, Can't allocate memory for control block!\n",
+ driver_name);
+ return -ENOMEM;
+ }
+ memset(self, 0, sizeof(struct smsc_ircc_cb));
+
+ /* Need to store self somewhere */
+ dev_self[dev_count++] = self;
+ spin_lock_init(&self->lock);
+
+ err = smsc_ircc_setup_buffers(self);
+ if(err) return err;
+
+ err= smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq);
+ if(err) return err;
+
+ smsc_ircc_setup_qos(self);
+
+ self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
+
+ smsc_ircc_init_chip(self);
+
+ if(ircc_transceiver > 0 && ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) self->transceiver = ircc_transceiver;
+ else smsc_ircc_probe_transceiver(self);
+
+ err = smsc_ircc_setup_netdev(self);
+ if(err) return err;
+
+ self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, smsc_ircc_pmproc);
+ if (self->pmdev)
+ self->pmdev->data = self;
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_present(fir_base, sir_base)
+ *
+ * Check the smsc-ircc chip presence
+ *
+ */
+static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base)
+{
+ unsigned char low, high, chip, config, dma, irq, version;
+
+ if (check_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT) < 0) {
+ WARNING("%s: can't get fir_base of 0x%03x\n",
+ __FUNCTION__, fir_base);
+ return -ENODEV;
+ }
+#if POSSIBLE_USED_BY_SERIAL_DRIVER
+ if (check_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT) < 0) {
+ WARNING("%s: can't get sir_base of 0x%03x\n",
+ __FUNCTION__, sir_base);
+ return -ENODEV;
+ }
+#endif
+
+ register_bank(fir_base, 3);
+
+ high = inb(fir_base+IRCC_ID_HIGH);
+ low = inb(fir_base+IRCC_ID_LOW);
+ chip = inb(fir_base+IRCC_CHIP_ID);
+ version = inb(fir_base+IRCC_VERSION);
+ config = inb(fir_base+IRCC_INTERFACE);
+ dma = config & IRCC_INTERFACE_DMA_MASK;
+ irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
+
+ if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) {
+ WARNING("%s(), addr 0x%04x - no device found!\n",
+ __FUNCTION__, fir_base);
+ return -ENODEV;
+ }
+ MESSAGE("SMsC IrDA Controller found\n IrCC version %d.%d, "
+ "firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n",
+ chip & 0x0f, version, fir_base, sir_base, dma, irq);
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_setup_buffers(self)
+ *
+ * Setup RX/TX buffers
+ *
+ */
+static int smsc_ircc_setup_buffers(struct smsc_ircc_cb *self)
+{
+ self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE;
+ self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE;
+
+ self->rx_buff.head = (u8 *) kmalloc(self->rx_buff.truesize,
+ GFP_KERNEL|GFP_DMA);
+ if (self->rx_buff.head == NULL) {
+ ERROR("%s, Can't allocate memory for receive buffer!\n",
+ driver_name);
+ kfree(self);
+ return -ENOMEM;
+ }
+
+ self->tx_buff.head = (u8 *) kmalloc(self->tx_buff.truesize,
+ GFP_KERNEL|GFP_DMA);
+ if (self->tx_buff.head == NULL) {
+ ERROR("%s, Can't allocate memory for transmit buffer!\n",
+ driver_name);
+ kfree(self->rx_buff.head);
+ kfree(self);
+ return -ENOMEM;
+ }
+
+ memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+ memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+
+ self->rx_buff.in_frame = FALSE;
+ self->rx_buff.state = OUTSIDE_FRAME;
+ self->tx_buff.data = self->tx_buff.head;
+ self->rx_buff.data = self->rx_buff.head;
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq)
+ *
+ * Setup I/O
+ *
+ */
+static int smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+{
+ unsigned char config, chip_dma, chip_irq;
+ void *ret;
+
+ register_bank(fir_base, 3);
+ config = inb(fir_base+IRCC_INTERFACE);
+ chip_dma = config & IRCC_INTERFACE_DMA_MASK;
+ chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4;
+
+ self->io.fir_base = fir_base;
+ self->io.sir_base = sir_base;
+ self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT;
+ self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT;
+ self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE;
+ self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED;
+
+ if (irq < 255) {
+ if (irq != chip_irq)
+ MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
+ driver_name, chip_irq, irq);
+ self->io.irq = irq;
+ }
+ else
+ self->io.irq = chip_irq;
+
+ if (dma < 255) {
+ if (dma != chip_dma)
+ MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
+ driver_name, chip_dma, dma);
+ self->io.dma = dma;
+ }
+ else
+ self->io.dma = chip_dma;
+
+ ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
+ if (!ret) {
+ WARNING("%s(), can't get iobase of 0x%03x\n",
+ __FUNCTION__, self->io.fir_base);
+ kfree(self->tx_buff.head);
+ kfree(self->rx_buff.head);
+ kfree(self);
+ return -ENODEV;
+ }
+ ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name);
+ if (!ret) {
+ WARNING("%s(), can't get iobase of 0x%03x\n",
+ __FUNCTION__, self->io.sir_base);
+ release_region(self->io.fir_base, self->io.fir_ext);
+ kfree(self->tx_buff.head);
+ kfree(self->rx_buff.head);
+ kfree(self);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_setup_qos(self)
+ *
+ * Setup qos
+ *
+ */
+static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self)
+{
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&self->qos);
+
+ self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+ IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
+
+ self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME;
+ self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE;
+ irda_qos_bits_to_value(&self->qos);
+}
+
+/*
+ * Function smsc_ircc_init_chip(self)
+ *
+ * Init chip
+ *
+ */
+static void smsc_ircc_init_chip(struct smsc_ircc_cb *self)
+{
+ int iobase, ir_mode, ctrl, fast;
+
+ ASSERT( self != NULL, return; );
+ iobase = self->io.fir_base;
+
+ ir_mode = IRCC_CFGA_IRDA_SIR_A;
+ ctrl = 0;
+ fast = 0;
+
+ register_bank(iobase, 0);
+ outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
+ outb(0x00, iobase+IRCC_MASTER);
+
+ register_bank(iobase, 1);
+ outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode),
+ iobase+IRCC_SCE_CFGA);
+
+#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */
+ outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ iobase+IRCC_SCE_CFGB);
+#else
+ outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ iobase+IRCC_SCE_CFGB);
+#endif
+ (void) inb(iobase+IRCC_FIFO_THRESHOLD);
+ outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase+IRCC_FIFO_THRESHOLD);
+
+ register_bank(iobase, 4);
+ outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
+
+ register_bank(iobase, 0);
+ outb(fast, iobase+IRCC_LCR_A);
+
+ smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
+
+ /* Power on device */
+ outb(0x00, iobase+IRCC_MASTER);
+}
+
+/*
+ * Function smsc_ircc_setup_netdev(self)
+ *
+ * Alloc and setup network device
+ *
+ */
+static int smsc_ircc_setup_netdev(struct smsc_ircc_cb *self)
+{
+ struct net_device *dev;
+ int err;
+ /* Alloc netdev */
+
+ if (!(dev = dev_alloc("irda%d", &err))) {
+ ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
+ kfree(self->tx_buff.head);
+ kfree(self->rx_buff.head);
+ kfree(self);
+ return -ENOMEM;
+ }
+
+ dev->priv = (void *) self;
+ self->netdev = dev;
+
+ dev->init = smsc_ircc_net_init;
+ dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
+ #if SMSC_IRCC2_C_NET_TIMEOUT
+ dev->tx_timeout = smsc_ircc_timeout;
+ dev->watchdog_timeo = HZ*2; /* Allow enough time for speed change */
+ #endif
+ dev->open = smsc_ircc_net_open;
+ dev->stop = smsc_ircc_net_close;
+ dev->do_ioctl = smsc_ircc_net_ioctl;
+ dev->get_stats = smsc_ircc_net_get_stats;
+
+ /* Make ifconfig display some details */
+ dev->base_addr = self->io.fir_base;
+ dev->irq = self->io.irq;
+
+ rtnl_lock();
+ err = register_netdevice(dev);
+ rtnl_unlock();
+ if (err) {
+ ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+ kfree(self->tx_buff.head);
+ kfree(self->rx_buff.head);
+ kfree(self);
+ return -ENODEV;
+ }
+ MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_net_ioctl (dev, rq, cmd)
+ *
+ * Process IOCTL commands for this device
+ *
+ */
+static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *) rq;
+ struct smsc_ircc_cb *self;
+ unsigned long flags;
+ int ret = 0;
+
+ ASSERT(dev != NULL, return -1;);
+
+ self = dev->priv;
+
+ ASSERT(self != NULL, return -1;);
+
+ IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ ret = -EPERM;
+ else {
+ /* Make sure we are the only one touching
+ * self->io.speed and the hardware - Jean II */
+ spin_lock_irqsave(&self->lock, flags);
+ smsc_ircc_change_speed(self, irq->ifr_baudrate);
+ spin_unlock_irqrestore(&self->lock, flags);
+ }
+ break;
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ break;
+ }
+
+ irda_device_set_media_busy(self->netdev, TRUE);
+ break;
+ case SIOCGRECEIVING: /* Check if we are receiving right now */
+ irq->ifr_receiving = smsc_ircc_is_receiving(self);
+ break;
+ #if 0
+ case SIOCSDTRRTS:
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ break;
+ }
+ smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+ break;
+ #endif
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
+{
+ struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) dev->priv;
+
+ return &self->stats;
+}
+
+#if SMSC_IRCC2_C_NET_TIMEOUT
+/*
+ * Function smsc_ircc_timeout (struct net_device *dev)
+ *
+ * The networking timeout management.
+ *
+ */
+
+static void smsc_ircc_timeout(struct net_device *dev)
+{
+ struct smsc_ircc_cb *self;
+ unsigned long flags;
+
+ self = (struct smsc_ircc_cb *) dev->priv;
+
+ WARNING("%s: transmit timed out, changing speed to: %d\n", dev->name, self->io.speed);
+ spin_lock_irqsave(&self->lock, flags);
+ smsc_ircc_sir_start(self);
+ smsc_ircc_change_speed(self, self->io.speed);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ spin_unlock_irqrestore(&self->lock, flags);
+}
+#endif
+
+/*
+ * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev)
+ *
+ * Transmits the current frame until FIFO is full, then
+ * waits until the next transmit interrupt, and continues until the
+ * frame is transmitted.
+ */
+int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
+{
+ struct smsc_ircc_cb *self;
+ unsigned long flags;
+ int iobase;
+ s32 speed;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(dev != NULL, return 0;);
+
+ self = (struct smsc_ircc_cb *) dev->priv;
+ ASSERT(self != NULL, return 0;);
+
+ iobase = self->io.sir_base;
+
+ netif_stop_queue(dev);
+
+ /* Make sure test of self->io.speed & speed change are atomic */
+ spin_lock_irqsave(&self->lock, flags);
+
+ /* Check if we need to change the speed */
+ speed = irda_get_next_speed(skb);
+ if ((speed != self->io.speed) && (speed != -1)) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ /*
+ * We send frames one by one in SIR mode (no
+ * pipelining), so at this point, if we were sending
+ * a previous frame, we just received the interrupt
+ * telling us it is finished (UART_IIR_THRI).
+ * Therefore, waiting for the transmitter to really
+ * finish draining the fifo won't take too long.
+ * And the interrupt handler is not expected to run.
+ * - Jean II */
+ smsc_ircc_sir_wait_hw_transmitter_finish(self);
+ smsc_ircc_change_speed(self, speed);
+ spin_unlock_irqrestore(&self->lock, flags);
+ dev_kfree_skb(skb);
+ return 0;
+ } else {
+ self->new_speed = speed;
+ }
+ }
+
+ /* Init tx buffer */
+ self->tx_buff.data = self->tx_buff.head;
+
+ /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
+ self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
+ self->tx_buff.truesize);
+
+ self->stats.tx_bytes += self->tx_buff.len;
+
+ /* Turn on transmit finished interrupt. Will fire immediately! */
+ outb(UART_IER_THRI, iobase+UART_IER);
+
+ spin_unlock_irqrestore(&self->lock, flags);
+
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_set_fir_speed (self, baud)
+ *
+ * Change the speed of the device
+ *
+ */
+static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed)
+{
+ int fir_base, ir_mode, ctrl, fast;
+
+ ASSERT(self != NULL, return;);
+ fir_base = self->io.fir_base;
+
+ self->io.speed = speed;
+
+ switch(speed) {
+ default:
+ case 576000:
+ ir_mode = IRCC_CFGA_IRDA_HDLC;
+ ctrl = IRCC_CRC;
+ fast = 0;
+ IRDA_DEBUG(0, "%s(), handling baud of 576000\n", __FUNCTION__);
+ break;
+ case 1152000:
+ ir_mode = IRCC_CFGA_IRDA_HDLC;
+ ctrl = IRCC_1152 | IRCC_CRC;
+ fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA;
+ IRDA_DEBUG(0, "%s(), handling baud of 1152000\n",
+ __FUNCTION__);
+ break;
+ case 4000000:
+ ir_mode = IRCC_CFGA_IRDA_4PPM;
+ ctrl = IRCC_CRC;
+ fast = IRCC_LCR_A_FAST;
+ IRDA_DEBUG(0, "%s(), handling baud of 4000000\n",
+ __FUNCTION__);
+ break;
+ }
+ #if 0
+ Now in tranceiver!
+ /* This causes an interrupt */
+ register_bank(fir_base, 0);
+ outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast, fir_base+IRCC_LCR_A);
+ #endif
+
+ register_bank(fir_base, 1);
+ outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base+IRCC_SCE_CFGA);
+
+ register_bank(fir_base, 4);
+ outb((inb(fir_base+IRCC_CONTROL) & 0x30) | ctrl, fir_base+IRCC_CONTROL);
+}
+
+/*
+ * Function smsc_ircc_fir_start(self)
+ *
+ * Change the speed of the device
+ *
+ */
+static void smsc_ircc_fir_start(struct smsc_ircc_cb *self)
+{
+ struct net_device *dev;
+ int fir_base;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(self != NULL, return;);
+ dev = self->netdev;
+ ASSERT(dev != NULL, return;);
+
+ fir_base = self->io.fir_base;
+
+ /* Reset everything */
+
+ /* Install FIR transmit handler */
+ dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
+
+ /* Clear FIFO */
+ outb(inb(fir_base+IRCC_LCR_A)|IRCC_LCR_A_FIFO_RESET, fir_base+IRCC_LCR_A);
+
+ /* Enable interrupt */
+ /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);*/
+
+ register_bank(fir_base, 1);
+
+ /* Select the TX/RX interface */
+#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */
+ outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM),
+ fir_base+IRCC_SCE_CFGB);
+#else
+ outb(((inb(fir_base+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+ fir_base+IRCC_SCE_CFGB);
+#endif
+ (void) inb(fir_base+IRCC_FIFO_THRESHOLD);
+
+ /* Enable SCE interrupts */
+ outb(0, fir_base+IRCC_MASTER);
+ register_bank(fir_base, 0);
+ outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base+IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, fir_base+IRCC_MASTER);
+}
+
+/*
+ * Function smsc_ircc_fir_stop(self, baud)
+ *
+ * Change the speed of the device
+ *
+ */
+static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self)
+{
+ int fir_base;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(self != NULL, return;);
+
+ fir_base = self->io.fir_base;
+ register_bank(fir_base, 0);
+ /*outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);*/
+ outb(inb(fir_base+IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base+IRCC_LCR_B);
+}
+
+
+/*
+ * Function smsc_ircc_change_speed(self, baud)
+ *
+ * Change the speed of the device
+ *
+ * This function *must* be called with spinlock held, because it may
+ * be called from the irq handler. - Jean II
+ */
+static void smsc_ircc_change_speed(void *priv, u32 speed)
+{
+ struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
+ struct net_device *dev;
+ int iobase;
+ int last_speed_was_sir;
+
+ IRDA_DEBUG(0, "%s() changing speed to: %d\n", __FUNCTION__, speed);
+
+ ASSERT(self != NULL, return;);
+ dev = self->netdev;
+ iobase = self->io.fir_base;
+
+ last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED;
+
+ #if 0
+ /* Temp Hack */
+ speed= 1152000;
+ self->io.speed = speed;
+ last_speed_was_sir = 0;
+ smsc_ircc_fir_start(self);
+ #endif
+
+ if(self->io.speed == 0)
+ smsc_ircc_sir_start(self);
+
+ #if 0
+ if(!last_speed_was_sir) speed = self->io.speed;
+ #endif
+
+ if(self->io.speed != speed) smsc_ircc_set_transceiver_for_speed(self, speed);
+
+ self->io.speed = speed;
+
+ if(speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+ if(!last_speed_was_sir) {
+ smsc_ircc_fir_stop(self);
+ smsc_ircc_sir_start(self);
+ }
+ smsc_ircc_set_sir_speed(self, speed);
+ }
+ else {
+ if(last_speed_was_sir) {
+ #if SMSC_IRCC2_C_SIR_STOP
+ smsc_ircc_sir_stop(self);
+ #endif
+ smsc_ircc_fir_start(self);
+ }
+ smsc_ircc_set_fir_speed(self, speed);
+
+ #if 0
+ self->tx_buff.len = 10;
+ self->tx_buff.data = self->tx_buff.head;
+
+ smsc_ircc_dma_xmit(self, iobase, 4000);
+ #endif
+ /* Be ready for incoming frames */
+ smsc_ircc_dma_receive(self, iobase);
+ }
+
+ netif_wake_queue(dev);
+}
+
+/*
+ * Function smsc_ircc_set_sir_speed (self, speed)
+ *
+ * Set speed of IrDA port to specified baudrate
+ *
+ */
+void smsc_ircc_set_sir_speed(void *priv, __u32 speed)
+{
+ struct smsc_ircc_cb *self = (struct smsc_ircc_cb *) priv;
+ int iobase;
+ int fcr; /* FIFO control reg */
+ int lcr; /* Line control reg */
+ int divisor;
+
+ IRDA_DEBUG(0, "%s(), Setting speed to: %d\n", __FUNCTION__, speed);
+
+ ASSERT(self != NULL, return;);
+ iobase = self->io.sir_base;
+
+ /* Update accounting for new speed */
+ self->io.speed = speed;
+
+ /* Turn off interrupts */
+ outb(0, iobase+UART_IER);
+
+ divisor = SMSC_IRCC2_MAX_SIR_SPEED/speed;
+
+ fcr = UART_FCR_ENABLE_FIFO;
+
+ /*
+ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+ * about this timeout since it will always be fast enough.
+ */
+ if (self->io.speed < 38400)
+ fcr |= UART_FCR_TRIGGER_1;
+ else
+ fcr |= UART_FCR_TRIGGER_14;
+
+ /* IrDA ports use 8N1 */
+ lcr = UART_LCR_WLEN8;
+
+ outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
+ outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */
+ outb(divisor >> 8, iobase+UART_DLM);
+ outb(lcr, iobase+UART_LCR); /* Set 8N1 */
+ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
+
+ /* Turn on interrups */
+ outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+
+ IRDA_DEBUG(2, "%s() speed changed to: %d\n", __FUNCTION__, speed);
+}
+
+
+/*
+ * Function smsc_ircc_hard_xmit_fir (skb, dev)
+ *
+ * Transmit the frame!
+ *
+ */
+static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
+{
+ struct smsc_ircc_cb *self;
+ unsigned long flags;
+ s32 speed;
+ int iobase;
+ int mtt;
+
+ ASSERT(dev != NULL, return 0;);
+ self = (struct smsc_ircc_cb *) dev->priv;
+ ASSERT(self != NULL, return 0;);
+
+ iobase = self->io.fir_base;
+
+ netif_stop_queue(dev);
+
+ /* Make sure test of self->io.speed & speed change are atomic */
+ spin_lock_irqsave(&self->lock, flags);
+
+ /* Check if we need to change the speed after this frame */
+ speed = irda_get_next_speed(skb);
+ if ((speed != self->io.speed) && (speed != -1)) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ /* Note : you should make sure that speed changes
+ * are not going to corrupt any outgoing frame.
+ * Look at nsc-ircc for the gory details - Jean II */
+ smsc_ircc_change_speed(self, speed);
+ spin_unlock_irqrestore(&self->lock, flags);
+ dev_kfree_skb(skb);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
+
+ memcpy(self->tx_buff.head, skb->data, skb->len);
+
+ self->tx_buff.len = skb->len;
+ self->tx_buff.data = self->tx_buff.head;
+
+ mtt = irda_get_mtt(skb);
+ if (mtt) {
+ int bofs;
+
+ /*
+ * Compute how many BOFs (STA or PA's) we need to waste the
+ * min turn time given the speed of the link.
+ */
+ bofs = mtt * (self->io.speed / 1000) / 8000;
+ if (bofs > 4095)
+ bofs = 4095;
+
+ smsc_ircc_dma_xmit(self, iobase, bofs);
+ } else {
+ /* Transmit frame */
+ smsc_ircc_dma_xmit(self, iobase, 0);
+ }
+ spin_unlock_irqrestore(&self->lock, flags);
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_dma_xmit (self, iobase)
+ *
+ * Transmit data using DMA
+ *
+ */
+static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int iobase, int bofs)
+{
+ u8 ctrl;
+
+ IRDA_DEBUG(3, "%s\n", __FUNCTION__);
+#if 1
+ /* Disable Rx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+#endif
+ register_bank(iobase, 1);
+ outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase+IRCC_SCE_CFGB);
+
+ self->io.direction = IO_XMIT;
+
+ /* Set BOF additional count for generating the min turn time */
+ register_bank(iobase, 4);
+ outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
+ ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
+ outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
+
+ /* Set max Tx frame size */
+ outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
+ outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
+
+ /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/
+
+ /* Enable burst mode chip Tx DMA */
+ register_bank(iobase, 1);
+ outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+
+ /* Setup DMA controller (must be done after enabling chip DMA) */
+ setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len,
+ DMA_TX_MODE);
+
+ /* Enable interrupt */
+
+ register_bank(iobase, 0);
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
+
+ /* Enable transmit */
+ outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
+}
+
+/*
+ * Function smsc_ircc_dma_xmit_complete (self)
+ *
+ * The transfer of a frame in finished. This function will only be called
+ * by the interrupt handler
+ *
+ */
+static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self, int iobase)
+{
+ IRDA_DEBUG(3, "%s\n", __FUNCTION__);
+#if 0
+ /* Disable Tx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+#endif
+ register_bank(self->io.fir_base, 1);
+ outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ self->io.fir_base+IRCC_SCE_CFGB);
+
+ /* Check for underrun! */
+ register_bank(iobase, 0);
+ if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
+ self->stats.tx_errors++;
+ self->stats.tx_fifo_errors++;
+
+ /* Reset error condition */
+ register_bank(iobase, 0);
+ outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
+ outb(0x00, iobase+IRCC_MASTER);
+ } else {
+ self->stats.tx_packets++;
+ self->stats.tx_bytes += self->tx_buff.len;
+ }
+
+ /* Check if it's time to change the speed */
+ if (self->new_speed) {
+ smsc_ircc_change_speed(self, self->new_speed);
+ self->new_speed = 0;
+ }
+
+ netif_wake_queue(self->netdev);
+}
+
+/*
+ * Function smsc_ircc_dma_receive(self)
+ *
+ * Get ready for receiving a frame. The device will initiate a DMA
+ * if it starts to receive a frame.
+ *
+ */
+static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self, int iobase)
+{
+#if 0
+ /* Turn off chip DMA */
+ register_bank(iobase, 1);
+ outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase+IRCC_SCE_CFGB);
+#endif
+
+ /* Disable Tx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+
+ /* Turn off chip DMA */
+ register_bank(iobase, 1);
+ outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+ iobase+IRCC_SCE_CFGB);
+
+ self->io.direction = IO_RECV;
+ self->rx_buff.data = self->rx_buff.head;
+
+ /* Set max Rx frame size */
+ register_bank(iobase, 4);
+ outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
+ outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
+
+ /* Setup DMA controller */
+ setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize,
+ DMA_RX_MODE);
+
+ /* Enable burst mode chip Rx DMA */
+ register_bank(iobase, 1);
+ outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+ IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
+
+ /* Enable interrupt */
+ register_bank(iobase, 0);
+ outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
+ outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
+
+
+ /* Enable receiver */
+ register_bank(iobase, 0);
+ outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE,
+ iobase+IRCC_LCR_B);
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_dma_receive_complete(self, iobase)
+ *
+ * Finished with receiving frames
+ *
+ */
+static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self, int iobase)
+{
+ struct sk_buff *skb;
+ int len, msgcnt, lsr;
+
+ register_bank(iobase, 0);
+
+ IRDA_DEBUG(3, "%s\n", __FUNCTION__);
+#if 0
+ /* Disable Rx */
+ register_bank(iobase, 0);
+ outb(0x00, iobase+IRCC_LCR_B);
+#endif
+ register_bank(iobase, 0);
+ outb(inb(iobase+IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase+IRCC_LSAR);
+ lsr= inb(iobase+IRCC_LSR);
+ msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
+
+ IRDA_DEBUG(2, "%s: dma count = %d\n", __FUNCTION__,
+ get_dma_residue(self->io.dma));
+
+ len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
+
+ /* Look for errors
+ */
+
+ if(lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
+ self->stats.rx_errors++;
+ if(lsr & IRCC_LSR_FRAME_ERROR) self->stats.rx_frame_errors++;
+ if(lsr & IRCC_LSR_CRC_ERROR) self->stats.rx_crc_errors++;
+ if(lsr & IRCC_LSR_SIZE_ERROR) self->stats.rx_length_errors++;
+ if(lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) self->stats.rx_length_errors++;
+ return;
+ }
+ /* Remove CRC */
+ if (self->io.speed < 4000000)
+ len -= 2;
+ else
+ len -= 4;
+
+ if ((len < 2) || (len > 2050)) {
+ WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
+ return;
+ }
+ IRDA_DEBUG(2, "%s: msgcnt = %d, len=%d\n", __FUNCTION__, msgcnt, len);
+
+ skb = dev_alloc_skb(len+1);
+ if (!skb) {
+ WARNING("%s(), memory squeeze, dropping frame.\n",
+ __FUNCTION__);
+ return;
+ }
+ /* Make sure IP header gets aligned */
+ skb_reserve(skb, 1);
+
+ memcpy(skb_put(skb, len), self->rx_buff.data, len);
+ self->stats.rx_packets++;
+ self->stats.rx_bytes += len;
+
+ skb->dev = self->netdev;
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IRDA);
+ netif_rx(skb);
+}
+
+/*
+ * Function smsc_ircc_sir_receive (self)
+ *
+ * Receive one frame from the infrared port
+ *
+ */
+static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
+{
+ int boguscount = 0;
+ int iobase;
+
+ ASSERT(self != NULL, return;);
+
+ iobase = self->io.sir_base;
+
+ /*
+ * Receive all characters in Rx FIFO, unwrap and unstuff them.
+ * async_unwrap_char will deliver all found frames
+ */
+ do {
+ async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+ inb(iobase+UART_RX));
+
+ /* Make sure we don't stay here to long */
+ if (boguscount++ > 32) {
+ IRDA_DEBUG(2, "%s(), breaking!\n", __FUNCTION__);
+ break;
+ }
+ } while (inb(iobase+UART_LSR) & UART_LSR_DR);
+}
+
+
+/*
+ * Function smsc_ircc_interrupt (irq, dev_id, regs)
+ *
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct smsc_ircc_cb *self;
+ int iobase, iir, lcra, lsr;
+
+ if (dev == NULL) {
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+ driver_name, irq);
+ return IRQ_NONE;
+ }
+ self = (struct smsc_ircc_cb *) dev->priv;
+ ASSERT(self != NULL, return IRQ_NONE;);
+
+ /* Serialise the interrupt handler in various CPUs, stop Tx path */
+ spin_lock(&self->lock);
+
+ /* Check if we should use the SIR interrupt handler */
+ if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) {
+ smsc_ircc_interrupt_sir(irq, dev_id, regs);
+ spin_unlock(&self->lock);
+ return IRQ_HANDLED;
+ }
+ iobase = self->io.fir_base;
+
+ register_bank(iobase, 0);
+ iir = inb(iobase+IRCC_IIR);
+ /* Disable interrupts */
+ outb(0, iobase+IRCC_IER);
+ lcra = inb(iobase+IRCC_LCR_A);
+ lsr = inb(iobase+IRCC_LSR);
+
+ IRDA_DEBUG(2, "%s(), iir = 0x%02x\n", __FUNCTION__, iir);
+
+ if (iir & IRCC_IIR_EOM) {
+ if (self->io.direction == IO_RECV)
+ smsc_ircc_dma_receive_complete(self, iobase);
+ else
+ smsc_ircc_dma_xmit_complete(self, iobase);
+
+ smsc_ircc_dma_receive(self, iobase);
+ }
+
+ if (iir & IRCC_IIR_ACTIVE_FRAME) {
+ /*printk(KERN_WARNING __FUNCTION__ "(): Active Frame\n");*/
+ }
+
+ /* Enable interrupts again */
+
+ register_bank(iobase, 0);
+ outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
+
+ spin_unlock(&self->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Function irport_interrupt_sir (irq, dev_id, regs)
+ *
+ * Interrupt handler for SIR modes
+ */
+void smsc_ircc_interrupt_sir(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct smsc_ircc_cb *self;
+ int boguscount = 0;
+ int iobase;
+ int iir, lsr;
+
+ if (!dev) {
+ WARNING("%s() irq %d for unknown device.\n",
+ __FUNCTION__, irq);
+ return;
+ }
+ self = (struct smsc_ircc_cb *) dev->priv;
+
+ /* Already locked comming here in smsc_ircc_interrupt() */
+ /*spin_lock(&self->lock);*/
+
+ iobase = self->io.sir_base;
+
+ iir = inb(iobase+UART_IIR) & UART_IIR_ID;
+ while (iir) {
+ /* Clear interrupt */
+ lsr = inb(iobase+UART_LSR);
+
+ IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ __FUNCTION__, iir, lsr, iobase);
+
+ switch (iir) {
+ case UART_IIR_RLSI:
+ IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);
+ break;
+ case UART_IIR_RDI:
+ /* Receive interrupt */
+ smsc_ircc_sir_receive(self);
+ break;
+ case UART_IIR_THRI:
+ if (lsr & UART_LSR_THRE)
+ /* Transmitter ready for data */
+ smsc_ircc_sir_write_wakeup(self);
+ break;
+ default:
+ IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n",
+ __FUNCTION__, iir);
+ break;
+ }
+
+ /* Make sure we don't stay here to long */
+ if (boguscount++ > 100)
+ break;
+
+ iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+ }
+ /*spin_unlock(&self->lock);*/
+}
+
+
+#if 0 /* unused */
+/*
+ * Function ircc_is_receiving (self)
+ *
+ * Return TRUE is we are currently receiving a frame
+ *
+ */
+static int ircc_is_receiving(struct smsc_ircc_cb *self)
+{
+ int status = FALSE;
+ /* int iobase; */
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(self != NULL, return FALSE;);
+
+ IRDA_DEBUG(0, "%s: dma count = %d\n", __FUNCTION__,
+ get_dma_residue(self->io.dma));
+
+ status = (self->rx_buff.state != OUTSIDE_FRAME);
+
+ return status;
+}
+#endif /* unused */
+
+static int smsc_ircc_net_init(struct net_device *dev)
+{
+ /* Keep track of module usage */
+ SET_MODULE_OWNER(dev);
+
+ /* Set up to be a normal IrDA network device driver */
+ irda_device_setup(dev);
+
+ /* Insert overrides below this line! */
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_net_open (dev)
+ *
+ * Start the device
+ *
+ */
+static int smsc_ircc_net_open(struct net_device *dev)
+{
+ struct smsc_ircc_cb *self;
+ int iobase;
+ char hwname[16];
+ unsigned long flags;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(dev != NULL, return -1;);
+ self = (struct smsc_ircc_cb *) dev->priv;
+ ASSERT(self != NULL, return 0;);
+
+ iobase = self->io.fir_base;
+
+ if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name,
+ (void *) dev)) {
+ IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
+ __FUNCTION__, self->io.irq);
+ return -EAGAIN;
+ }
+
+ spin_lock_irqsave(&self->lock, flags);
+ /*smsc_ircc_sir_start(self);*/
+ self->io.speed = 0;
+ smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED);
+ spin_unlock_irqrestore(&self->lock, flags);
+
+ /* Give self a hardware name */
+ /* It would be cool to offer the chip revision here - Jean II */
+ sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base);
+
+ /*
+ * Open new IrLAP layer instance, now that everything should be
+ * initialized properly
+ */
+ self->irlap = irlap_open(dev, &self->qos, hwname);
+
+ /*
+ * Always allocate the DMA channel after the IRQ,
+ * and clean up on failure.
+ */
+ if (request_dma(self->io.dma, dev->name)) {
+ smsc_ircc_net_close(dev);
+
+ WARNING("%s(), unable to allocate DMA=%d\n",
+ __FUNCTION__, self->io.dma);
+ return -EAGAIN;
+ }
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_net_close (dev)
+ *
+ * Stop the device
+ *
+ */
+static int smsc_ircc_net_close(struct net_device *dev)
+{
+ struct smsc_ircc_cb *self;
+ int iobase;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(dev != NULL, return -1;);
+ self = (struct smsc_ircc_cb *) dev->priv;
+ ASSERT(self != NULL, return 0;);
+
+ iobase = self->io.fir_base;
+
+ /* Stop device */
+ netif_stop_queue(dev);
+
+ /* Stop and remove instance of IrLAP */
+ if (self->irlap)
+ irlap_close(self->irlap);
+ self->irlap = NULL;
+
+ free_irq(self->io.irq, dev);
+
+ disable_dma(self->io.dma);
+
+ free_dma(self->io.dma);
+
+ return 0;
+}
+
+
+static void smsc_ircc_suspend(struct smsc_ircc_cb *self)
+{
+ MESSAGE("%s, Suspending\n", driver_name);
+
+ if (self->io.suspended)
+ return;
+
+ smsc_ircc_net_close(self->netdev);
+
+ self->io.suspended = 1;
+}
+
+static void smsc_ircc_wakeup(struct smsc_ircc_cb *self)
+{
+ if (!self->io.suspended)
+ return;
+
+ /* The code was doing a "cli()" here, but this can't be right.
+ * If you need protection, do it in net_open with a spinlock
+ * or give a good reason. - Jean II */
+
+ smsc_ircc_net_open(self->netdev);
+
+ MESSAGE("%s, Waking up\n", driver_name);
+}
+
+static int smsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ struct smsc_ircc_cb *self = (struct smsc_ircc_cb*) dev->data;
+ if (self) {
+ switch (rqst) {
+ case PM_SUSPEND:
+ smsc_ircc_suspend(self);
+ break;
+ case PM_RESUME:
+ smsc_ircc_wakeup(self);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_close (self)
+ *
+ * Close driver instance
+ *
+ */
+static int __exit smsc_ircc_close(struct smsc_ircc_cb *self)
+{
+ int iobase;
+ unsigned long flags;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ ASSERT(self != NULL, return -1;);
+
+ iobase = self->io.fir_base;
+
+ if (self->pmdev)
+ pm_unregister(self->pmdev);
+
+ /* Remove netdevice */
+ if (self->netdev) {
+ rtnl_lock();
+ unregister_netdevice(self->netdev);
+ rtnl_unlock();
+ }
+
+ /* Make sure the irq handler is not exectuting */
+ spin_lock_irqsave(&self->lock, flags);
+
+ /* Stop interrupts */
+ register_bank(iobase, 0);
+ outb(0, iobase+IRCC_IER);
+ outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
+ outb(0x00, iobase+IRCC_MASTER);
+#if 0
+ /* Reset to SIR mode */
+ register_bank(iobase, 1);
+ outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
+ outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
+#endif
+ spin_unlock_irqrestore(&self->lock, flags);
+
+ /* Release the PORTS that this driver is using */
+ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
+ self->io.fir_base);
+
+ release_region(self->io.fir_base, self->io.fir_ext);
+
+ IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__,
+ self->io.sir_base);
+
+ release_region(self->io.sir_base, self->io.sir_ext);
+
+ if (self->tx_buff.head)
+ kfree(self->tx_buff.head);
+
+ if (self->rx_buff.head)
+ kfree(self->rx_buff.head);
+
+ kfree(self);
+
+ return 0;
+}
+
+void __exit smsc_ircc_cleanup(void)
+{
+ int i;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ for (i=0; i < 2; i++) {
+ if (dev_self[i])
+ smsc_ircc_close(dev_self[i]);
+ }
+}
+
+/*
+ * Start SIR operations
+ *
+ * This function *must* be called with spinlock held, because it may
+ * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II
+ */
+void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
+{
+ struct net_device *dev;
+ int fir_base, sir_base;
+
+ IRDA_DEBUG(3, "%s\n", __FUNCTION__);
+
+ ASSERT(self != NULL, return;);
+ dev= self->netdev;
+ ASSERT(dev != NULL, return;);
+ dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
+
+ fir_base = self->io.fir_base;
+ sir_base = self->io.sir_base;
+
+ /* Reset everything */
+ outb(IRCC_MASTER_RESET, fir_base+IRCC_MASTER);
+
+ #if SMSC_IRCC2_C_SIR_STOP
+ /*smsc_ircc_sir_stop(self);*/
+ #endif
+
+ register_bank(fir_base, 1);
+ outb(((inb(fir_base+IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base+IRCC_SCE_CFGA);
+
+ /* Initialize UART */
+ outb(UART_LCR_WLEN8, sir_base+UART_LCR); /* Reset DLAB */
+ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base+UART_MCR);
+
+ /* Turn on interrups */
+ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base+UART_IER);
+
+ IRDA_DEBUG(3, "%s() - exit\n", __FUNCTION__);
+
+ outb(0x00, fir_base+IRCC_MASTER);
+}
+
+#if SMSC_IRCC2_C_SIR_STOP
+void smsc_ircc_sir_stop(struct smsc_ircc_cb *self)
+{
+ int iobase;
+
+ IRDA_DEBUG(3, "%s\n", __FUNCTION__);
+ iobase = self->io.sir_base;
+
+ /* Reset UART */
+ outb(0, iobase+UART_MCR);
+
+ /* Turn off interrupts */
+ outb(0, iobase+UART_IER);
+}
+#endif
+
+/*
+ * Function smsc_sir_write_wakeup (self)
+ *
+ * Called by the SIR interrupt handler when there's room for more data.
+ * If we have more packets to send, we send them here.
+ *
+ */
+static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
+{
+ int actual = 0;
+ int iobase;
+ int fcr;
+
+ ASSERT(self != NULL, return;);
+
+ IRDA_DEBUG(4, "%s\n", __FUNCTION__);
+
+ iobase = self->io.sir_base;
+
+ /* Finished with frame? */
+ if (self->tx_buff.len > 0) {
+ /* Write data left in transmit buffer */
+ actual = smsc_ircc_sir_write(iobase, self->io.fifo_size,
+ self->tx_buff.data, self->tx_buff.len);
+ self->tx_buff.data += actual;
+ self->tx_buff.len -= actual;
+ } else {
+
+ /*if (self->tx_buff.len ==0) {*/
+
+ /*
+ * Now serial buffer is almost free & we can start
+ * transmission of another packet. But first we must check
+ * if we need to change the speed of the hardware
+ */
+ if (self->new_speed) {
+ IRDA_DEBUG(5, "%s(), Changing speed to %d.\n",
+ __FUNCTION__, self->new_speed);
+ smsc_ircc_sir_wait_hw_transmitter_finish(self);
+ smsc_ircc_change_speed(self, self->new_speed);
+ self->new_speed = 0;
+ } else {
+ /* Tell network layer that we want more frames */
+ netif_wake_queue(self->netdev);
+ }
+ self->stats.tx_packets++;
+
+ if(self->io.speed <= 115200) {
+ /*
+ * Reset Rx FIFO to make sure that all reflected transmit data
+ * is discarded. This is needed for half duplex operation
+ */
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
+ if (self->io.speed < 38400)
+ fcr |= UART_FCR_TRIGGER_1;
+ else
+ fcr |= UART_FCR_TRIGGER_14;
+
+ outb(fcr, iobase+UART_FCR);
+
+ /* Turn on receive interrupts */
+ outb(UART_IER_RDI, iobase+UART_IER);
+ }
+ }
+}
+
+/*
+ * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len)
+ *
+ * Fill Tx FIFO with transmit data
+ *
+ */
+static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len)
+{
+ int actual = 0;
+
+ /* Tx FIFO should be empty! */
+ if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+ WARNING("%s(), failed, fifo not empty!\n", __FUNCTION__);
+ return 0;
+ }
+
+ /* Fill FIFO with current frame */
+ while ((fifo_size-- > 0) && (actual < len)) {
+ /* Transmit next byte */
+ outb(buf[actual], iobase+UART_TX);
+ actual++;
+ }
+ return actual;
+}
+
+/*
+ * Function smsc_ircc_is_receiving (self)
+ *
+ * Returns true is we are currently receiving data
+ *
+ */
+static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self)
+{
+ return (self->rx_buff.state != OUTSIDE_FRAME);
+}
+
+
+/*
+ * Function smsc_ircc_probe_transceiver(self)
+ *
+ * Tries to find the used Transceiver
+ *
+ */
+static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self)
+{
+ unsigned int i;
+
+ ASSERT(self != NULL, return;);
+
+ for(i=0; smsc_transceivers[i].name!=NULL; i++)
+ if((*smsc_transceivers[i].probe)(self->io.fir_base)) {
+ MESSAGE(" %s transceiver found\n", smsc_transceivers[i].name);
+ self->transceiver= i+1;
+ return;
+ }
+ MESSAGE("No transceiver found. Defaulting to %s\n", smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name);
+
+ self->transceiver= SMSC_IRCC2_C_DEFAULT_TRANSCEIVER;
+}
+
+
+/*
+ * Function smsc_ircc_set_transceiver_for_speed(self, speed)
+ *
+ * Set the transceiver according to the speed
+ *
+ */
+static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed)
+{
+ unsigned int trx;
+
+ trx = self->transceiver;
+ if(trx>0) (*smsc_transceivers[trx-1].set_for_speed)(self->io.fir_base, speed);
+}
+
+/*
+ * Function smsc_ircc_wait_hw_transmitter_finish ()
+ *
+ * Wait for the real end of HW transmission
+ *
+ * The UART is a strict FIFO, and we get called only when we have finished
+ * pushing data to the FIFO, so the maximum amount of time we must wait
+ * is only for the FIFO to drain out.
+ *
+ * We use a simple calibrated loop. We may need to adjust the loop
+ * delay (udelay) to balance I/O traffic and latency. And we also need to
+ * adjust the maximum timeout.
+ * It would probably be better to wait for the proper interrupt,
+ * but it doesn't seem to be available.
+ *
+ * We can't use jiffies or kernel timers because :
+ * 1) We are called from the interrupt handler, which disable softirqs,
+ * so jiffies won't be increased
+ * 2) Jiffies granularity is usually very coarse (10ms), and we don't
+ * want to wait that long to detect stuck hardware.
+ * Jean II
+ */
+
+static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self)
+{
+ int iobase;
+ int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US;
+
+ iobase = self->io.sir_base;
+
+ /* Calibrated busy loop */
+ while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
+ udelay(1);
+
+ if(count == 0)
+ IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
+}
+
+
+/* PROBING
+ *
+ *
+ */
+
+static int __init smsc_ircc_look_for_chips(void)
+{
+ smsc_chip_address_t *address;
+ char *type;
+ unsigned int cfg_base, found;
+
+ found = 0;
+ address = possible_addresses;
+
+ while(address->cfg_base){
+ cfg_base = address->cfg_base;
+
+ /*printk(KERN_WARNING __FUNCTION__ "(): probing: 0x%02x for: 0x%02x\n", cfg_base, address->type);*/
+
+ if( address->type & SMSCSIO_TYPE_FDC){
+ type = "FDC";
+ if((address->type) & SMSCSIO_TYPE_FLAT) {
+ if(!smsc_superio_flat(fdc_chips_flat,cfg_base, type)) found++;
+ }
+ if((address->type) & SMSCSIO_TYPE_PAGED) {
+ if(!smsc_superio_paged(fdc_chips_paged,cfg_base, type)) found++;
+ }
+ }
+ if( address->type & SMSCSIO_TYPE_LPC){
+ type = "LPC";
+ if((address->type) & SMSCSIO_TYPE_FLAT) {
+ if(!smsc_superio_flat(lpc_chips_flat,cfg_base,type)) found++;
+ }
+ if((address->type) & SMSCSIO_TYPE_PAGED) {
+ if(!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC")) found++;
+ }
+ }
+ address++;
+ }
+ return found;
+}
+
+/*
+ * Function smsc_superio_flat (chip, base, type)
+ *
+ * Try to get configuration of a smc SuperIO chip with flat register model
+ *
+ */
+static int __init smsc_superio_flat(const smsc_chip_t *chips, unsigned short cfgbase, char *type)
+{
+ unsigned short firbase, sirbase;
+ u8 mode, dma, irq;
+ int ret = -ENODEV;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type)==NULL)
+ return ret;
+
+ outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase);
+ mode = inb(cfgbase+1);
+
+ /*printk(KERN_WARNING __FUNCTION__ "(): mode: 0x%02x\n", mode);*/
+
+ if(!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA))
+ WARNING("%s(): IrDA not enabled\n", __FUNCTION__);
+
+ outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase);
+ sirbase = inb(cfgbase+1) << 2;
+
+ /* FIR iobase */
+ outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase);
+ firbase = inb(cfgbase+1) << 3;
+
+ /* DMA */
+ outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase);
+ dma = inb(cfgbase+1) & SMSCSIOFLAT_FIRDMASELECT_MASK;
+
+ /* IRQ */
+ outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase);
+ irq = inb(cfgbase+1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
+
+ MESSAGE("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", __FUNCTION__, firbase, sirbase, dma, irq, mode);
+
+ if (firbase) {
+ if (smsc_ircc_open(firbase, sirbase, dma, irq) == 0)
+ ret=0;
+ }
+
+ /* Exit configuration */
+ outb(SMSCSIO_CFGEXITKEY, cfgbase);
+
+ return ret;
+}
+
+/*
+ * Function smsc_superio_paged (chip, base, type)
+ *
+ * Try to get configuration of a smc SuperIO chip with paged register model
+ *
+ */
+static int __init smsc_superio_paged(const smsc_chip_t *chips, unsigned short cfg_base, char *type)
+{
+ unsigned short fir_io, sir_io;
+ int ret = -ENODEV;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ if (smsc_ircc_probe(cfg_base,0x20,chips,type)==NULL)
+ return ret;
+
+ /* Select logical device (UART2) */
+ outb(0x07, cfg_base);
+ outb(0x05, cfg_base + 1);
+
+ /* SIR iobase */
+ outb(0x60, cfg_base);
+ sir_io = inb(cfg_base + 1) << 8;
+ outb(0x61, cfg_base);
+ sir_io |= inb(cfg_base + 1);
+
+ /* Read FIR base */
+ outb(0x62, cfg_base);
+ fir_io = inb(cfg_base + 1) << 8;
+ outb(0x63, cfg_base);
+ fir_io |= inb(cfg_base + 1);
+ outb(0x2b, cfg_base); /* ??? */
+
+ if (fir_io) {
+ if (smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0)
+ ret=0;
+ }
+
+ /* Exit configuration */
+ outb(SMSCSIO_CFGEXITKEY, cfg_base);
+
+ return ret;
+}
+
+
+static int __init smsc_access(unsigned short cfg_base,unsigned char reg)
+{
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ outb(reg, cfg_base);
+
+ if (inb(cfg_base)!=reg)
+ return -1;
+
+ return 0;
+}
+
+static const smsc_chip_t * __init smsc_ircc_probe(unsigned short cfg_base,u8 reg,const smsc_chip_t *chip,char *type)
+{
+ u8 devid,xdevid,rev;
+
+ IRDA_DEBUG(1, "%s\n", __FUNCTION__);
+
+ /* Leave configuration */
+
+ outb(SMSCSIO_CFGEXITKEY, cfg_base);
+
+ if (inb(cfg_base) == SMSCSIO_CFGEXITKEY) /* not a smc superio chip */
+ return NULL;
+
+ outb(reg, cfg_base);
+
+ xdevid=inb(cfg_base+1);
+
+ /* Enter configuration */
+
+ outb(SMSCSIO_CFGACCESSKEY, cfg_base);
+
+ #if 0
+ if (smsc_access(cfg_base,0x55)) /* send second key and check */
+ return NULL;
+ #endif
+
+ /* probe device ID */
+
+ if (smsc_access(cfg_base,reg))
+ return NULL;
+
+ devid=inb(cfg_base+1);
+
+ if (devid==0) /* typical value for unused port */
+ return NULL;
+
+ if (devid==0xff) /* typical value for unused port */
+ return NULL;
+
+ /* probe revision ID */
+
+ if (smsc_access(cfg_base,reg+1))
+ return NULL;
+
+ rev=inb(cfg_base+1);
+
+ if (rev>=128) /* i think this will make no sense */
+ return NULL;
+
+ if (devid==xdevid) /* protection against false positives */
+ return NULL;
+
+ /* Check for expected device ID; are there others? */
+
+ while(chip->devid!=devid) {
+
+ chip++;
+
+ if (chip->name==NULL)
+ return NULL;
+ }
+
+ MESSAGE("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n",devid,rev,cfg_base,type,chip->name);
+
+ if (chip->rev>rev){
+ MESSAGE("Revision higher than expected\n");
+ return NULL;
+ }
+
+ if (chip->flags&NoIRDA)
+ MESSAGE("chipset does not support IRDA\n");
+
+ return chip;
+}
+
+static int __init smsc_superio_fdc(unsigned short cfg_base)
+{
+ if (check_region(cfg_base, 2) < 0) {
+ WARNING("%s: can't get cfg_base of 0x%03x\n",
+ __FUNCTION__, cfg_base);
+ return -1;
+ }
+
+ if (!smsc_superio_flat(fdc_chips_flat,cfg_base,"FDC")||!smsc_superio_paged(fdc_chips_paged,cfg_base,"FDC"))
+ return 0;
+
+ return -1;
+}
+
+static int __init smsc_superio_lpc(unsigned short cfg_base)
+{
+#if 0
+ if (check_region(cfg_base, 2) < 0) {
+ IRDA_DEBUG(0, __FUNCTION__ ": can't get cfg_base of 0x%03x\n",
+ cfg_base);
+ return -1;
+ }
+#endif
+
+ if (!smsc_superio_flat(lpc_chips_flat,cfg_base,"LPC")||!smsc_superio_paged(lpc_chips_paged,cfg_base,"LPC"))
+ return 0;
+
+ return -1;
+}
+
+/************************************************
+ *
+ * Transceivers specific functions
+ *
+ ************************************************/
+
+
+/*
+ * Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed)
+ *
+ * Program transceiver through smsc-ircc ATC circuitry
+ *
+ */
+
+static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed)
+{
+ unsigned long jiffies_now, jiffies_timeout;
+ u8 val;
+
+ jiffies_now= jiffies;
+ jiffies_timeout= jiffies+SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES;
+
+ /* ATC */
+ register_bank(fir_base, 4);
+ outb((inb(fir_base+IRCC_ATC) & IRCC_ATC_MASK) |IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, fir_base+IRCC_ATC);
+ while((val=(inb(fir_base+IRCC_ATC) & IRCC_ATC_nPROGREADY)) && !time_after(jiffies, jiffies_timeout));
+ if(val)
+ WARNING("%s(): ATC: 0x%02x\n", __FUNCTION__,
+ inb(fir_base+IRCC_ATC));
+}
+
+/*
+ * Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base)
+ *
+ * Probe transceiver smsc-ircc ATC circuitry
+ *
+ */
+
+static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base)
+{
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed)
+ *
+ * Set transceiver
+ *
+ */
+
+static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed)
+{
+ u8 fast_mode;
+
+ switch(speed)
+ {
+ default:
+ case 576000 :
+ fast_mode = 0;
+ break;
+ case 1152000 :
+ case 4000000 :
+ fast_mode = IRCC_LCR_A_FAST;
+ break;
+
+ }
+ register_bank(fir_base, 0);
+ outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+}
+
+/*
+ * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base)
+ *
+ * Probe transceiver
+ *
+ */
+
+static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base)
+{
+ return 0;
+}
+
+/*
+ * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed)
+ *
+ * Set transceiver
+ *
+ */
+
+static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed)
+{
+ u8 fast_mode;
+
+ switch(speed)
+ {
+ default:
+ case 576000 :
+ fast_mode = 0;
+ break;
+ case 1152000 :
+ case 4000000 :
+ fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA;
+ break;
+
+ }
+ /* This causes an interrupt */
+ register_bank(fir_base, 0);
+ outb((inb(fir_base+IRCC_LCR_A) & 0xbf) | fast_mode, fir_base+IRCC_LCR_A);
+}
+
+/*
+ * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base)
+ *
+ * Probe transceiver
+ *
+ */
+
+static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base)
+{
+ return 0;
+}
+
+
+module_init(smsc_ircc_init);
+module_exit(smsc_ircc_cleanup);
+
+MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
+MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(ircc_dma, "1i");
+MODULE_PARM_DESC(ircc_dma, "DMA channel");
+MODULE_PARM(ircc_irq, "1i");
+MODULE_PARM_DESC(ircc_irq, "IRQ line");
+MODULE_PARM(ircc_fir, "1-4i");
+MODULE_PARM_DESC(ircc_fir, "FIR Base Address");
+MODULE_PARM(ircc_sir, "1-4i");
+MODULE_PARM_DESC(ircc_sir, "SIR Base Address");
+MODULE_PARM(ircc_cfg, "1-4i");
+MODULE_PARM_DESC(ircc_cfg, "Configuration register base address");
+MODULE_PARM(ircc_transceiver, "1i");
+MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h
new file mode 100644
index 000000000000..458611cc0d40
--- /dev/null
+++ b/drivers/net/irda/smsc-ircc2.h
@@ -0,0 +1,194 @@
+/*********************************************************************
+ * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
+ *
+ * Description: Definitions for the SMC IrCC chipset
+ * Status: Experimental.
+ * Author: Daniele Peri (peri@csai.unipa.it)
+ *
+ * Copyright (c) 2002 Daniele Peri
+ * All Rights Reserved.
+ *
+ * Based on smc-ircc.h:
+ *
+ * Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no>
+ * Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net>
+ * All Rights Reserved
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ********************************************************************/
+
+#ifndef SMSC_IRCC2_H
+#define SMSC_IRCC2_H
+
+/* DMA modes needed */
+#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */
+
+/* Master Control Register */
+#define IRCC_MASTER 0x07
+#define IRCC_MASTER_POWERDOWN 0x80
+#define IRCC_MASTER_RESET 0x40
+#define IRCC_MASTER_INT_EN 0x20
+#define IRCC_MASTER_ERROR_RESET 0x10
+
+/* Register block 0 */
+
+/* Interrupt Identification */
+#define IRCC_IIR 0x01
+#define IRCC_IIR_ACTIVE_FRAME 0x80
+#define IRCC_IIR_EOM 0x40
+#define IRCC_IIR_RAW_MODE 0x20
+#define IRCC_IIR_FIFO 0x10
+
+/* Interrupt Enable */
+#define IRCC_IER 0x02
+#define IRCC_IER_ACTIVE_FRAME 0x80
+#define IRCC_IER_EOM 0x40
+#define IRCC_IER_RAW_MODE 0x20
+#define IRCC_IER_FIFO 0x10
+
+/* Line Status Register */
+#define IRCC_LSR 0x03
+#define IRCC_LSR_UNDERRUN 0x80
+#define IRCC_LSR_OVERRUN 0x40
+#define IRCC_LSR_FRAME_ERROR 0x20
+#define IRCC_LSR_SIZE_ERROR 0x10
+#define IRCC_LSR_CRC_ERROR 0x80
+#define IRCC_LSR_FRAME_ABORT 0x40
+
+/* Line Status Address Register */
+#define IRCC_LSAR 0x03
+#define IRCC_LSAR_ADDRESS_MASK 0x07
+
+/* Line Control Register A */
+#define IRCC_LCR_A 0x04
+#define IRCC_LCR_A_FIFO_RESET 0x80
+#define IRCC_LCR_A_FAST 0x40
+#define IRCC_LCR_A_GP_DATA 0x20
+#define IRCC_LCR_A_RAW_TX 0x10
+#define IRCC_LCR_A_RAW_RX 0x08
+#define IRCC_LCR_A_ABORT 0x04
+#define IRCC_LCR_A_DATA_DONE 0x02
+
+/* Line Control Register B */
+#define IRCC_LCR_B 0x05
+#define IRCC_LCR_B_SCE_DISABLED 0x00
+#define IRCC_LCR_B_SCE_TRANSMIT 0x40
+#define IRCC_LCR_B_SCE_RECEIVE 0x80
+#define IRCC_LCR_B_SCE_UNDEFINED 0xc0
+#define IRCC_LCR_B_SIP_ENABLE 0x20
+#define IRCC_LCR_B_BRICK_WALL 0x10
+
+/* Bus Status Register */
+#define IRCC_BSR 0x06
+#define IRCC_BSR_NOT_EMPTY 0x80
+#define IRCC_BSR_FIFO_FULL 0x40
+#define IRCC_BSR_TIMEOUT 0x20
+
+/* Register block 1 */
+
+#define IRCC_FIFO_THRESHOLD 0x02
+
+#define IRCC_SCE_CFGA 0x00
+#define IRCC_CFGA_AUX_IR 0x80
+#define IRCC_CFGA_HALF_DUPLEX 0x04
+#define IRCC_CFGA_TX_POLARITY 0x02
+#define IRCC_CFGA_RX_POLARITY 0x01
+
+#define IRCC_CFGA_COM 0x00
+#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87
+#define IRCC_CFGA_IRDA_SIR_A 0x08
+#define IRCC_CFGA_ASK_SIR 0x10
+#define IRCC_CFGA_IRDA_SIR_B 0x18
+#define IRCC_CFGA_IRDA_HDLC 0x20
+#define IRCC_CFGA_IRDA_4PPM 0x28
+#define IRCC_CFGA_CONSUMER 0x30
+#define IRCC_CFGA_RAW_IR 0x38
+#define IRCC_CFGA_OTHER 0x40
+
+#define IRCC_IR_HDLC 0x04
+#define IRCC_IR_4PPM 0x01
+#define IRCC_IR_CONSUMER 0x02
+
+#define IRCC_SCE_CFGB 0x01
+#define IRCC_CFGB_LOOPBACK 0x20
+#define IRCC_CFGB_LPBCK_TX_CRC 0x10
+#define IRCC_CFGB_NOWAIT 0x08
+#define IRCC_CFGB_STRING_MOVE 0x04
+#define IRCC_CFGB_DMA_BURST 0x02
+#define IRCC_CFGB_DMA_ENABLE 0x01
+
+#define IRCC_CFGB_MUX_COM 0x00
+#define IRCC_CFGB_MUX_IR 0x40
+#define IRCC_CFGB_MUX_AUX 0x80
+#define IRCC_CFGB_MUX_INACTIVE 0xc0
+
+/* Register block 3 - Identification Registers! */
+#define IRCC_ID_HIGH 0x00 /* 0x10 */
+#define IRCC_ID_LOW 0x01 /* 0xB8 */
+#define IRCC_CHIP_ID 0x02 /* 0xF1 */
+#define IRCC_VERSION 0x03 /* 0x01 */
+#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */
+
+/* Register block 4 - IrDA */
+#define IRCC_CONTROL 0x00
+#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */
+#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */
+#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */
+#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */
+#define IRCC_TX_SIZE_LO 0x04 /* Low byte */
+#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */
+#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */
+#define IRCC_RX_SIZE_LO 0x06 /* Low byte */
+
+#define IRCC_1152 0x80
+#define IRCC_CRC 0x40
+
+/* Register block 5 - IrDA */
+#define IRCC_ATC 0x00
+#define IRCC_ATC_nPROGREADY 0x80
+#define IRCC_ATC_SPEED 0x40
+#define IRCC_ATC_ENABLE 0x20
+#define IRCC_ATC_MASK 0xE0
+
+
+#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01
+
+#define IRCC_SCE_TX_DELAY_TIMER 0x02
+
+/*
+ * Other definitions
+ */
+
+#define SMSC_IRCC2_MAX_SIR_SPEED 115200
+#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8
+#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8
+#define SMSC_IRCC2_FIFO_SIZE 16
+#define SMSC_IRCC2_FIFO_THRESHOLD 64
+/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384
+#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384
+#define SMSC_IRCC2_MIN_TURN_TIME 0x07
+#define SMSC_IRCC2_WINDOW_SIZE 0x07
+/* Maximum wait for hw transmitter to finish */
+#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */
+/* Maximum wait for ATC transceiver programming to finish */
+#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1
+#endif /* SMSC_IRCC2_H */
diff --git a/drivers/net/irda/smsc-sio.h b/drivers/net/irda/smsc-sio.h
new file mode 100644
index 000000000000..59e20e653ebe
--- /dev/null
+++ b/drivers/net/irda/smsc-sio.h
@@ -0,0 +1,100 @@
+#ifndef SMSC_SIO_H
+#define SMSC_SIO_H
+
+/******************************************
+ Keys. They should work with every SMsC SIO
+ ******************************************/
+
+#define SMSCSIO_CFGACCESSKEY 0x55
+#define SMSCSIO_CFGEXITKEY 0xaa
+
+/*****************************
+ * Generic SIO Flat (!?) *
+ *****************************/
+
+/* Register 0x0d */
+#define SMSCSIOFLAT_DEVICEID_REG 0x0d
+
+/* Register 0x0c */
+#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c
+#define SMSCSIOFLAT_UART2MODE_MASK 0x38
+#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00
+#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08
+#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10
+
+/* Register 0x25 */
+#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25
+
+/* Register 0x2b */
+#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b
+
+/* Register 0x2c */
+#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c
+#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f
+
+/* Register 0x28 */
+#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28
+#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f
+#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0
+#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00
+
+
+/*********************
+ * LPC47N227 *
+ *********************/
+
+#define LPC47N227_CFGACCESSKEY 0x55
+#define LPC47N227_CFGEXITKEY 0xaa
+
+/* Register 0x00 */
+#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00
+#define LPC47N227_FDCPOWER_MASK 0x08
+#define LPC47N227_VALID_MASK 0x80
+
+/* Register 0x02 */
+#define LPC47N227_UART12POWER_REG 0x02
+#define LPC47N227_UART1POWERDOWN_MASK 0x08
+#define LPC47N227_UART2POWERDOWN_MASK 0x80
+
+/* Register 0x07 */
+#define LPC47N227_APMBOOTDRIVE_REG 0x07
+#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */
+#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */
+#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */
+
+/* Register 0x0c */
+#define LPC47N227_UARTMODE0C_REG 0x0c
+#define LPC47N227_UART2MODE_MASK 0x38
+#define LPC47N227_UART2MODE_VAL_COM 0x00
+#define LPC47N227_UART2MODE_VAL_IRDA 0x08
+#define LPC47N227_UART2MODE_VAL_ASKIR 0x10
+
+/* Register 0x0d */
+#define LPC47N227_DEVICEID_REG 0x0d
+#define LPC47N227_DEVICEID_DEFVAL 0x5a
+
+/* Register 0x0e */
+#define LPC47N227_REVISIONID_REG 0x0e
+
+/* Register 0x25 */
+#define LPC47N227_UART2BASEADDR_REG 0x25
+
+/* Register 0x28 */
+#define LPC47N227_UARTIRQSELECT_REG 0x28
+#define LPC47N227_UART2IRQSELECT_MASK 0x0f
+#define LPC47N227_UART1IRQSELECT_MASK 0xf0
+#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00
+
+/* Register 0x2b */
+#define LPC47N227_FIRBASEADDR_REG 0x2b
+
+/* Register 0x2c */
+#define LPC47N227_FIRDMASELECT_REG 0x2c
+#define LPC47N227_FIRDMASELECT_MASK 0x0f
+#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */
+#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02
+#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03
+#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f
+
+
+#endif
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 3013e4e821ab..709f375bb1d9 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -524,6 +524,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Check for empty frame */
if (!skb->len) {
w83977af_change_speed(self, speed);
+ dev->trans_start = jiffies;
dev_kfree_skb(skb);
return 0;
} else
@@ -579,6 +580,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
switch_bank(iobase, SET0);
outb(ICR_ETXTHI, iobase+ICR);
}
+ dev->trans_start = jiffies;
dev_kfree_skb(skb);
/* Restore set register */
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 9f10842ab0dd..7f4e64360f15 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -541,6 +541,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct myri_channel *chan = &mp->shmem->channel;
unsigned long flags;
u32 status;
+ int handled = 0;
spin_lock_irqsave(&mp->irq_lock, flags);
@@ -549,6 +550,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (status & ISTAT_HOST) {
u32 softstate;
+ handled = 1;
DIRQ(("IRQ_DISAB "));
myri_disable_irq(lregs, mp->cregs);
softstate = sbus_readl(&chan->state);
@@ -568,7 +570,7 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&mp->irq_lock, flags);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(handled);
}
static int myri_open(struct net_device *dev)
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index c4c6e0d13d41..06feb5870fc8 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -202,7 +202,6 @@ ppp_sync_open(struct tty_struct *tty)
struct syncppp *ap;
int err;
- MOD_INC_USE_COUNT;
ap = kmalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
if (ap == 0)
@@ -236,7 +235,6 @@ ppp_sync_open(struct tty_struct *tty)
out_free:
kfree(ap);
out:
- MOD_DEC_USE_COUNT;
return err;
}
@@ -276,7 +274,6 @@ ppp_sync_close(struct tty_struct *tty)
if (ap->tpkt != 0)
kfree_skb(ap->tpkt);
kfree(ap);
- MOD_DEC_USE_COUNT;
}
/*
@@ -404,6 +401,7 @@ ppp_sync_wakeup(struct tty_struct *tty)
static struct tty_ldisc ppp_sync_ldisc = {
+ .owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "pppsync",
.open = ppp_sync_open,
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index d0b1dc9ffa1a..08cd543eda47 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -84,7 +84,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr);
static int seeq8005_open(struct net_device *dev);
static void seeq8005_timeout(struct net_device *dev);
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void seeq8005_rx(struct net_device *dev);
static int seeq8005_close(struct net_device *dev);
static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
@@ -400,11 +400,12 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status, boguscount = 0;
+ int handled = 0;
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
@@ -416,17 +417,20 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
if (status & SEEQSTAT_WINDOW_INT) {
+ handled = 1;
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
if (net_debug) {
printk("%s: window int!\n",dev->name);
}
}
if (status & SEEQSTAT_TX_INT) {
+ handled = 1;
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
lp->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & SEEQSTAT_RX_INT) {
+ handled = 1;
/* Got a packet(s). */
seeq8005_rx(dev);
}
@@ -436,6 +440,7 @@ static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if(net_debug>2) {
printk("%s: eoi\n",dev->name);
}
+ return IRQ_RETVAL(handled);
}
/* We have a good packet(s), get it/them out of the buffers. */
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index a80a2f87c3e1..93949db1e758 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -124,6 +124,7 @@ static void qe_init_rings(struct sunqe *qep)
qb->qe_rxd[i].rx_flags =
(RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
}
+ return IRQ_HANDLED;
}
static int qe_init(struct sunqe *qep, int from_irq)
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 455702a8cd18..d74cb55dc3d9 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -201,7 +201,7 @@ static int streamer_open(struct net_device *dev);
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
static int streamer_close(struct net_device *dev);
static void streamer_set_rx_mode(struct net_device *dev);
-static void streamer_interrupt(int irq, void *dev_id,
+static irqreturn_t streamer_interrupt(int irq, void *dev_id,
struct pt_regs *regs);
static struct net_device_stats *streamer_get_stats(struct net_device *dev);
static int streamer_set_mac_address(struct net_device *dev, void *addr);
@@ -1021,7 +1021,7 @@ static void streamer_rx(struct net_device *dev)
} /* end for all completed rx descriptors */
}
-static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct streamer_private *streamer_priv =
@@ -1142,6 +1142,7 @@ static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} /* while() */
spin_unlock(&streamer_priv->streamer_lock) ;
+ return IRQ_HANDLED;
}
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 9a534bb64557..8a74d3280e73 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -2027,7 +2027,7 @@ set_multicast_list(struct net_device *dev)
}
}
- return;
+ return IRQ_HANDLED;
}
/*
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index d94ceadfcb9e..8685e91d5a9c 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -117,7 +117,7 @@ static int lmc_rx (struct net_device *dev);
static int lmc_open(struct net_device *dev);
static int lmc_close(struct net_device *dev);
static struct net_device_stats *lmc_get_stats(struct net_device *dev);
-static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int lmc_set_config(struct net_device *dev, struct ifmap *map);
static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
static void lmc_softreset(lmc_softc_t * const);
@@ -1388,7 +1388,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/
/* Interrupt handling routine. This will take an incoming packet, or clean
* up after a trasmit.
*/
-static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
+static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
{
struct net_device *dev = (struct net_device *) dev_instance;
lmc_softc_t *sc;
@@ -1398,6 +1398,7 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
unsigned int badtx;
u32 firstcsr;
int max_work = LMC_RXDESCS;
+ int handled = 0;
lmc_trace(dev, "lmc_interrupt in");
@@ -1421,6 +1422,8 @@ static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*
/* always go through this loop at least once */
while (csr & sc->lmc_intrmask) {
+ handled = 1;
+
/*
* Clear interrupt bits, we handle all case below
*/
@@ -1580,6 +1583,7 @@ lmc_int_fail_out:
spin_unlock(&sc->lmc_lock);
lmc_trace(dev, "lmc_interrupt out");
+ return IRQ_RETVAL(handled);
}
static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 7235f23f511a..d3cc5a0b4c67 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -275,15 +275,11 @@ init_airport(void)
printk(KERN_DEBUG "%s\n", version);
- MOD_INC_USE_COUNT;
-
/* Lookup card in device tree */
airport_node = find_devices("radio");
if (airport_node && !strcmp(airport_node->parent->name, "mac-io"))
airport_dev = airport_attach(airport_node);
- MOD_DEC_USE_COUNT;
-
return airport_dev ? 0 : -ENODEV;
}
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 869a3f5273e2..c82630ec1819 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -299,8 +299,8 @@ static int oprofilefs_fill_super(struct super_block * sb, void * data, int silen
}
-static struct super_block * oprofilefs_get_sb(struct file_system_type * fs_type,
- int flags, char * dev_name, void * data)
+static struct super_block *oprofilefs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, oprofilefs_fill_super);
}
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 53f05b670bb6..8fcd56ebb4e3 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -489,7 +489,7 @@ static void fs_remove_file (struct dentry *dentry)
static struct file_system_type usbdevice_fs_type;
static struct super_block *usb_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
if (fs_type == &usbdevice_fs_type)
printk (KERN_INFO "Please use the 'usbfs' filetype instead, "
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 14def9ef7385..d5b8294a2fa1 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -459,7 +459,7 @@ error:
}
static struct super_block *adfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super);
}
diff --git a/fs/affs/super.c b/fs/affs/super.c
index f3e7aad77c4a..61c71fe3f785 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -210,9 +210,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
optn = "volume";
if (!value || !*value)
goto out_no_arg;
- if (strlen(value) > 30)
- value[30] = 0;
- strncpy(volume,value,30);
+ strlcpy(volume,value,31);
} else if (!strcmp(this_char,"mode")) {
optn = "mode";
if (!value || !*value)
@@ -543,7 +541,7 @@ affs_statfs(struct super_block *sb, struct statfs *buf)
}
static struct super_block *affs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super);
}
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 0e4603081774..f02009bf7bd6 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -40,7 +40,8 @@ static inline char *strdup(const char *s)
static void afs_i_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags);
static struct super_block *afs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data);
+ int flags, const char *dev_name,
+ void *data);
static struct inode *afs_alloc_inode(struct super_block *sb);
@@ -407,10 +408,9 @@ static int afs_fill_super(struct super_block *sb, void *_data, int silent)
* get an AFS superblock
* - TODO: don't use get_sb_nodev(), but rather call sget() directly
*/
-static struct super_block *afs_get_sb(struct file_system_type *fs_type,
- int flags,
- char *dev_name,
- void *options)
+static struct super_block *
+afs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *options)
{
struct super_block *sb;
void *data[2] = { dev_name, options };
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index 87744e9bee0d..b977ece69f0c 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -15,7 +15,7 @@
#include "autofs_i.h"
static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, autofs_fill_super);
}
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index d8d9c3cf8d13..acecec8578ce 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -15,7 +15,7 @@
#include "autofs_i.h"
static struct super_block *autofs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, autofs4_fill_super);
}
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index c2d5ca4d16f2..5295f9d97c84 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -916,8 +916,8 @@ befs_statfs(struct super_block *sb, struct statfs *buf)
}
static struct super_block *
-befs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name,
- void *data)
+befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name,
+ void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super);
}
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 0aeab591b8cf..7a28495b0a87 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -379,7 +379,7 @@ out:
}
static struct super_block *bfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super);
}
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index d9e70fb1c0e1..bc72ed4d368e 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -113,10 +113,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
/* to keep locking time low, we copy the interpreter string */
read_lock(&entries_lock);
fmt = check_file(bprm);
- if (fmt) {
- strncpy(iname, fmt->interpreter, BINPRM_BUF_SIZE - 1);
- iname[BINPRM_BUF_SIZE - 1] = '\0';
- }
+ if (fmt)
+ strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE);
read_unlock(&entries_lock);
if (!fmt)
goto _ret;
@@ -623,7 +621,7 @@ static int bm_fill_super(struct super_block * sb, void * data, int silent)
}
static struct super_block *bm_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, bm_fill_super);
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 58b7813539e9..52e956455310 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -196,7 +196,7 @@ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
*/
static struct super_block *bd_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_pseudo(fs_type, "bdev:", NULL, 0x62646576);
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index d6244d17f236..f754ff70c9d2 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -57,13 +57,14 @@ unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
struct task_struct * oplockThread = NULL;
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
- char *);
+ const char *);
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
void cifs_proc_init(void);
void cifs_proc_clean(void);
static int
-cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
+cifs_read_super(struct super_block *sb, void *data,
+ const char *devname, int silent)
{
struct inode *inode;
struct cifs_sb_info *cifs_sb;
@@ -251,7 +252,7 @@ struct super_operations cifs_super_ops = {
static struct super_block *
cifs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
int rc;
struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 89fd14b85887..d74c9e601293 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -342,7 +342,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
int
-parse_mount_options(char *options, char *devname, struct smb_vol *vol)
+parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
{
char *value;
char *data;
@@ -795,7 +795,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
int
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
- char *mount_data, char *devname)
+ char *mount_data, const char *devname)
{
int rc = 0;
int xid;
@@ -811,7 +811,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
xid = GetXid();
cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data));
- if(parse_mount_options(mount_data, devname, &volume_info)) {
+ if (parse_mount_options(mount_data, devname, &volume_info)) {
FreeXid(xid);
return -EINVAL;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 2728e039f86a..03a21eb84918 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -303,7 +303,7 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf)
/* init_coda: used by filesystems.c to register coda */
static struct super_block *coda_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, coda_fill_super);
}
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index af2c968a5571..7e7f162fc0e3 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -464,7 +464,7 @@ static struct super_operations cramfs_ops = {
};
static struct super_block *cramfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super);
}
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 6ca2544a5322..5e6374bc8d20 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -2554,8 +2554,9 @@ out_no_root:
return -EINVAL;
} /* End Function devfs_fill_super */
-static struct super_block *devfs_get_sb (struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+static struct super_block *
+devfs_get_sb (struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
{
return get_sb_single (fs_type, flags, data, devfs_fill_super);
}
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 3f871c1fa42a..64a97888a1f1 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -73,7 +73,8 @@ static struct super_operations devpts_sops = {
.remount_fs = devpts_remount,
};
-static int devpts_fill_super(struct super_block *s, void *data, int silent)
+static int
+devpts_fill_super(struct super_block *s, void *data, int silent)
{
struct inode * inode;
@@ -106,7 +107,7 @@ fail:
}
static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, devpts_fill_super);
}
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 21be0cb8cb50..d3f72b95208c 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -16,7 +16,7 @@
#include <linux/vfs.h>
static struct super_block *efs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super);
}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index da1114d24455..f264bc7f3ddf 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -260,17 +260,20 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi);
static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync);
static int ep_eventpoll_close(struct inode *inode, struct file *file);
static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
-static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist, int maxevents);
+static int ep_collect_ready_items(struct eventpoll *ep,
+ struct list_head *txlist, int maxevents);
static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
struct epoll_event *events);
static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist);
-static int ep_events_transfer(struct eventpoll *ep, struct epoll_event *events, int maxevents);
-static int ep_poll(struct eventpoll *ep, struct epoll_event *events, int maxevents,
- long timeout);
+static int ep_events_transfer(struct eventpoll *ep,
+ struct epoll_event *events, int maxevents);
+static int ep_poll(struct eventpoll *ep, struct epoll_event *events,
+ int maxevents, long timeout);
static int eventpollfs_delete_dentry(struct dentry *dentry);
static struct inode *ep_eventpoll_inode(void);
static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data);
+ int flags, const char *dev_name,
+ void *data);
/* Safe wake up implementation */
@@ -1637,10 +1640,10 @@ eexit_1:
}
-static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+static struct super_block *
+eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
{
-
return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC);
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index dc7ced597149..48a3d099f9a0 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -989,7 +989,7 @@ static int ext2_statfs (struct super_block * sb, struct statfs * buf)
}
static struct super_block *ext2_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
}
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 6d27c23210b8..272197d032a2 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2029,7 +2029,7 @@ static int ext3_sync_dquot(struct dquot *dquot)
#endif
static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super);
}
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index c3d3f301ba20..d3ebd64c780e 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -230,7 +230,7 @@ out:
* The usual module blurb.
*/
static struct super_block *vxfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super);
}
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index f93f0e78789b..48be69ce4108 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -100,7 +100,7 @@ static struct super_operations hfs_super_operations = {
/*================ File-local variables ================*/
static struct super_block *hfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super);
}
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index aaa088d8601c..36aa38cd829a 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -637,7 +637,7 @@ bail0:
}
static struct super_block *hpfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super);
}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index db0e1597caa3..a1fe7e32422f 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -501,7 +501,7 @@ hugetlbfs_fill_super(struct super_block * sb, void * data, int silent)
}
static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super);
}
diff --git a/fs/intermezzo/super.c b/fs/intermezzo/super.c
index be225ba1155f..82104dd3093c 100644
--- a/fs/intermezzo/super.c
+++ b/fs/intermezzo/super.c
@@ -187,8 +187,9 @@ static int presto_set_channel(struct presto_cache *cache, char *channel)
/* We always need to remove the presto options before passing
mount options to cache FS */
-struct super_block * presto_get_sb(struct file_system_type *izo_type,
- int flags, char *devname, void * data)
+struct super_block *
+presto_get_sb(struct file_system_type *izo_type, int flags,
+ const char *devname, void *data)
{
struct file_system_type *fstype;
struct presto_cache *cache = NULL;
diff --git a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c
index 2125ee5af0d9..f0352cb1f35f 100644
--- a/fs/intermezzo/vfs.c
+++ b/fs/intermezzo/vfs.c
@@ -2388,7 +2388,7 @@ int presto_do_set_ext_attr(struct presto_file_set *fset,
/* We first "truncate" name to the maximum allowable in presto */
/* This simulates the strncpy_from_use code in fs/ext_attr.c */
- strncpy(temp,name,sizeof(temp));
+ strlcpy(temp,name,sizeof(temp));
/* Pass down to cache*/
error = iops->set_ext_attr(inode,temp,buffer,buffer_len,flags);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 9c47f2565297..b252fc2e3623 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1376,7 +1376,7 @@ void leak_check_brelse(struct buffer_head * bh){
#endif
static struct super_block *isofs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
}
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index e74ce5fc40f8..e7e6d5442774 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -1783,7 +1783,7 @@ static struct super_operations jffs_ops =
};
static struct super_block *jffs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, jffs_fill_super);
}
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index bce925b6c9ab..e87cdaececb6 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -101,9 +101,9 @@ static int jffs2_sb_set(struct super_block *sb, void *data)
return 0;
}
-static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
- int flags, char *dev_name,
- void *data, struct mtd_info *mtd)
+static struct super_block *
+jffs2_get_sb_mtd(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct mtd_info *mtd)
{
struct super_block *sb;
struct jffs2_sb_info *c;
@@ -153,9 +153,9 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
return sb;
}
-static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
- int flags, char *dev_name,
- void *data, int mtdnr)
+static struct super_block *
+jffs2_get_sb_mtdnr(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, int mtdnr)
{
struct mtd_info *mtd;
@@ -168,8 +168,9 @@ static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
}
-static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+static struct super_block *
+jffs2_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
{
int err;
struct nameidata nd;
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 84ddb9e25483..ebb881e50ad2 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -372,8 +372,9 @@ static void jfs_unlockfs(struct super_block *sb)
txResume(sb);
}
}
-static struct super_block *jfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+
+static struct super_block *jfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
}
diff --git a/fs/libfs.c b/fs/libfs.c
index f7d965e92338..932fd24707ee 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -7,8 +7,6 @@
#include <linux/mount.h>
#include <linux/vfs.h>
-extern struct vfsmount *do_kern_mount(const char *, int, char *, void *);
-
int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index aaaa4d9c3664..93005e83d319 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -554,7 +554,7 @@ void minix_truncate(struct inode * inode)
}
static struct super_block *minix_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super);
}
diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
index 54b493e9a2d4..29b3593fd733 100644
--- a/fs/msdos/msdosfs_syms.c
+++ b/fs/msdos/msdosfs_syms.c
@@ -25,7 +25,7 @@ EXPORT_SYMBOL(msdos_rmdir);
EXPORT_SYMBOL(msdos_unlink);
static struct super_block *msdos_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
}
diff --git a/fs/namespace.c b/fs/namespace.c
index 0174d8400c9d..3ba38cc13f33 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -23,7 +23,6 @@
#include <linux/mount.h>
#include <asm/uaccess.h>
-extern struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
extern int __init init_rootfs(void);
extern int __init fs_subsys_init(void);
@@ -39,7 +38,7 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
return tmp & hash_mask;
}
-struct vfsmount *alloc_vfsmnt(char *name)
+struct vfsmount *alloc_vfsmnt(const char *name)
{
struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL);
if (mnt) {
@@ -63,8 +62,7 @@ struct vfsmount *alloc_vfsmnt(char *name)
void free_vfsmnt(struct vfsmount *mnt)
{
- if (mnt->mnt_devname)
- kfree(mnt->mnt_devname);
+ kfree(mnt->mnt_devname);
kmem_cache_free(mnt_cache, mnt);
}
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 9de41ad18cbf..0744ac038279 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -955,7 +955,7 @@ int ncp_current_malloced;
#endif
static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, ncp_fill_super);
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index b97f81b911a1..825108da3ef2 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1192,7 +1192,7 @@ static int nfs_compare_super(struct super_block *sb, void *data)
}
static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *raw_data)
+ int flags, const char *dev_name, void *raw_data)
{
int error;
struct nfs_server *server;
@@ -1421,7 +1421,7 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
}
static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *raw_data)
+ int flags, const char *dev_name, void *raw_data)
{
int error;
struct nfs_server *server;
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 0e9370848f49..936d341c610a 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -226,10 +226,8 @@ static void __init root_nfs_parse(char *name, char *buf)
}
}
}
- if (name[0] && strcmp(name, "default")) {
- strncpy(buf, name, NFS_MAXPATHLEN-1);
- buf[NFS_MAXPATHLEN-1] = 0;
- }
+ if (name[0] && strcmp(name, "default"))
+ strlcpy(buf, name, NFS_MAXPATHLEN);
}
@@ -340,8 +338,7 @@ int __init nfs_root_setup(char *line)
{
ROOT_DEV = Root_NFS;
if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
- strncpy(nfs_root_name, line, sizeof(nfs_root_name));
- nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
+ strlcpy(nfs_root_name, line, sizeof(nfs_root_name));
} else {
int n = strlen(line) + strlen(NFS_ROOT);
if (n >= sizeof(nfs_root_name))
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index 46f0372bf2a5..12472dd2a99d 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -19,8 +19,6 @@
* open a file on nfsd fs
*/
-struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
-
static struct file *do_open(char *name, int flags)
{
struct nameidata nd;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index f5886a979e1b..93dfe60fdb3f 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -433,7 +433,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
}
static struct super_block *nfsd_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, nfsd_fill_super);
}
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 24afa0afcb3d..475799f476ac 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1656,7 +1656,7 @@ unsigned long ntfs_nr_mounts = 0;
DECLARE_MUTEX(ntfs_lock);
static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super);
}
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index a465eedc13f6..5a1fb89449be 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1053,7 +1053,7 @@ out_no_root:
}
static struct super_block *openprom_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, openprom_fill_super);
}
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 71a9cfd70968..8f09ea0494f8 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -308,7 +308,7 @@ void register_disk(struct gendisk *disk)
int j;
int err;
- strncpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
+ strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
/* ewww... some of these buggers have / in name... */
s = strchr(disk->kobj.name, '/');
if (s)
diff --git a/fs/pipe.c b/fs/pipe.c
index f3d1b93f75b5..3db9e975261d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -627,7 +627,7 @@ no_files:
*/
static struct super_block *pipefs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC);
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index d49f353378df..f6b7c065a969 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -25,7 +25,7 @@ struct proc_dir_entry *proc_sys_root;
#endif
static struct super_block *proc_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, proc_fill_super);
}
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 8c6a4dc19cd4..90f7a0034e64 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -555,7 +555,7 @@ static void destroy_inodecache(void)
}
static struct super_block *qnx4_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super);
}
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 15418ab4f490..372f06515900 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -192,13 +192,13 @@ static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
}
static struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, ramfs_fill_super);
}
static struct super_block *rootfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super);
}
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index ae31cff05cd1..4f16c0cd9f1e 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -1395,12 +1395,10 @@ static int reiserfs_statfs (struct super_block * s, struct statfs * buf)
}
static struct super_block*
-get_super_block (struct file_system_type *fs_type,
- int flags,
- char *dev_name,
- void *data)
+get_super_block (struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
{
- return get_sb_bdev (fs_type, flags, dev_name, data, reiserfs_fill_super);
+ return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super);
}
static int __init
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 7355ce94e60c..dd52de09689c 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -599,7 +599,7 @@ static struct super_operations romfs_ops = {
};
static struct super_block *romfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, romfs_fill_super);
}
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 74a424899996..abe004b1e78f 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -386,11 +386,11 @@ parse_options(struct smb_mount_data_kernel *mnt, char *options)
mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
break;
case 'i':
- strncpy(mnt->codepage.local_name, optarg,
+ strlcpy(mnt->codepage.local_name, optarg,
SMB_NLS_MAXNAMELEN);
break;
case 'c':
- strncpy(mnt->codepage.remote_name, optarg,
+ strlcpy(mnt->codepage.remote_name, optarg,
SMB_NLS_MAXNAMELEN);
break;
case 't':
@@ -535,9 +535,9 @@ int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
mnt = server->mnt;
memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
- strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
+ strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
SMB_NLS_MAXNAMELEN);
- strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
+ strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
SMB_NLS_MAXNAMELEN);
mnt->ttl = SMB_TTL_DEFAULT;
@@ -759,7 +759,7 @@ int smb_current_vmalloced;
#endif
static struct super_block *smb_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, smb_fill_super);
}
diff --git a/fs/super.c b/fs/super.c
index eba1a860a141..2aae8ed4cdcc 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -259,9 +259,6 @@ retry:
return s;
}
-struct vfsmount *alloc_vfsmnt(char *name);
-void free_vfsmnt(struct vfsmount *mnt);
-
void drop_super(struct super_block *sb)
{
up_read(&sb->s_umount);
@@ -558,7 +555,7 @@ static int test_bdev_super(struct super_block *s, void *data)
}
struct super_block *get_sb_bdev(struct file_system_type *fs_type,
- int flags, char *dev_name, void * data,
+ int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int))
{
struct block_device *bdev;
@@ -663,7 +660,7 @@ struct super_block *get_sb_single(struct file_system_type *fs_type,
}
struct vfsmount *
-do_kern_mount(const char *fstype, int flags, char *name, void *data)
+do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
struct file_system_type *type = get_fs_type(fstype);
struct super_block *sb = ERR_PTR(-ENOMEM);
@@ -702,5 +699,5 @@ out:
struct vfsmount *kern_mount(struct file_system_type *type)
{
- return do_kern_mount(type->name, 0, (char *)type->name, NULL);
+ return do_kern_mount(type->name, 0, type->name, NULL);
}
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 940fbcc5a805..c3e5dbe1710a 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -55,7 +55,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
}
static struct super_block *sysfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, sysfs_fill_super);
}
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index 9bac127e5c68..baf3157204b3 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -497,13 +497,13 @@ failed:
/* Every kernel module contains stuff like this. */
static struct super_block *sysv_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super);
}
static struct super_block *v7_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super);
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index e95e09fda8a8..00bfdd3d6a1b 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -99,7 +99,7 @@ static int udf_statfs(struct super_block *, struct statfs *);
/* UDF filesystem type */
static struct super_block *udf_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super);
}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 53029020b321..d9d96adb4672 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1055,7 +1055,7 @@ static struct super_operations ufs_super_ops = {
};
static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super);
}
diff --git a/fs/vfat/vfatfs_syms.c b/fs/vfat/vfatfs_syms.c
index b94296c7b786..a8bad844ea86 100644
--- a/fs/vfat/vfatfs_syms.c
+++ b/fs/vfat/vfatfs_syms.c
@@ -12,7 +12,7 @@
#include <linux/msdos_fs.h>
static struct super_block *vfat_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super);
}
diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c
index a6821a542818..7d2662e59031 100644
--- a/fs/xfs/linux/xfs_super.c
+++ b/fs/xfs/linux/xfs_super.c
@@ -747,7 +747,7 @@ STATIC struct super_block *
linvfs_get_sb(
struct file_system_type *fs_type,
int flags,
- char *dev_name,
+ const char *dev_name,
void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, linvfs_fill_super);
diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h
index dfa537d547b1..5429ea10ed3c 100644
--- a/include/asm-m68knommu/cacheflush.h
+++ b/include/asm-m68knommu/cacheflush.h
@@ -20,6 +20,11 @@
extern inline void __flush_cache_all(void)
{
#ifdef CONFIG_M5407
+ /*
+ * Use cpushl to push and invalidate all cache lines.
+ * Gas doesn't seem to know how to generate the ColdFire
+ * cpushl instruction... Oh well, bit stuff it for now.
+ */
__asm__ __volatile__ (
"nop\n\t"
"clrl %%d0\n\t"
@@ -33,11 +38,6 @@ extern inline void __flush_cache_all(void)
"addql #1,%%d0\n\t"
"cmpil #4,%%d0\n\t"
"bne 1b\n\t"
- "movel #0x01040100,%%d0\n\t"
- "movec %%d0,%%CACR\n\t"
- "nop\n\t"
- "movel #0x86088400,%%d0\n\t"
- "movec %%d0,%%CACR\n\t"
: : : "d0", "a0" );
#endif /* CONFIG_M5407 */
#ifdef CONFIG_M5272
diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h
index 8ddb454c85b5..b706151a0003 100644
--- a/include/linux/arcdevice.h
+++ b/include/linux/arcdevice.h
@@ -329,7 +329,7 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc);
#endif
void arcnet_unregister_proto(struct ArcProto *proto);
-void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
void arcdev_setup(struct net_device *dev);
void arcnet_rx(struct net_device *dev, int bufnum);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index de57729940ef..78b45c4afd9c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -919,7 +919,8 @@ struct file_system_type {
const char *name;
struct subsystem subsys;
int fs_flags;
- struct super_block *(*get_sb) (struct file_system_type *, int, char *, void *);
+ struct super_block *(*get_sb) (struct file_system_type *, int,
+ const char *, void *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
@@ -927,7 +928,7 @@ struct file_system_type {
};
struct super_block *get_sb_bdev(struct file_system_type *fs_type,
- int flags, char *dev_name, void * data,
+ int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int));
struct super_block *get_sb_single(struct file_system_type *fs_type,
int flags, void *data,
@@ -1117,7 +1118,7 @@ extern void sync_filesystems(int wait);
extern void emergency_sync(void);
extern void emergency_remount(void);
extern int do_remount_sb(struct super_block *sb, int flags,
- void *data, int force);
+ void *data, int force);
extern sector_t bmap(struct inode *, sector_t);
extern int setattr_mask(unsigned int);
extern int notify_change(struct dentry *, struct iattr *);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index d02e7845565a..d6996e7c7310 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -50,5 +50,10 @@ static inline void mntput(struct vfsmount *mnt)
}
}
+extern void free_vfsmnt(struct vfsmount *mnt);
+extern struct vfsmount *alloc_vfsmnt(const char *name);
+extern struct vfsmount *do_kern_mount(const char *fstype, int flags,
+ const char *name, void *data);
+
#endif
#endif /* _LINUX_MOUNT_H */
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index acd64b4ca117..e7b313a202b6 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -12,9 +12,8 @@ struct namespace {
struct rw_semaphore sem;
};
-void umount_tree(struct vfsmount *mnt);
-
extern void umount_tree(struct vfsmount *);
+extern int copy_namespace(int, struct task_struct *);
static inline void put_namespace(struct namespace *namespace)
{
@@ -38,7 +37,6 @@ static inline void exit_namespace(struct task_struct *p)
put_namespace(namespace);
}
}
-extern int copy_namespace(int, struct task_struct *);
static inline void get_namespace(struct namespace *namespace)
{
diff --git a/include/linux/string.h b/include/linux/string.h
index 0f9e63df583d..f37b7a6813d3 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -37,6 +37,9 @@ extern char * strcat(char *, const char *);
#ifndef __HAVE_ARCH_STRNCAT
extern char * strncat(char *, const char *, __kernel_size_t);
#endif
+#ifndef __HAVE_ARCH_STRLCAT
+extern size_t strlcat(char *, const char *, __kernel_size_t);
+#endif
#ifndef __HAVE_ARCH_STRCMP
extern int strcmp(const char *,const char *);
#endif
diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h
index 917e6701e7ab..ccd692fdef36 100644
--- a/include/net/irda/iriap.h
+++ b/include/net/irda/iriap.h
@@ -66,7 +66,7 @@ struct iriap_cb {
__u32 daddr;
__u8 operation;
- struct sk_buff *skb;
+ struct sk_buff *request_skb;
struct lsap_cb *lsap;
__u8 slsap_sel;
diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
index 02ecaf8e30cb..de3a7fdbebc3 100644
--- a/include/net/irda/irlan_common.h
+++ b/include/net/irda/irlan_common.h
@@ -195,8 +195,6 @@ struct irlan_cb {
struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr);
void irlan_close(struct irlan_cb *self);
void irlan_close_tsaps(struct irlan_cb *self);
-void irlan_mod_inc_use_count(void);
-void irlan_mod_dec_use_count(void);
int irlan_register_netdev(struct irlan_cb *self);
void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel);
diff --git a/include/net/irda/irlmp_event.h b/include/net/irda/irlmp_event.h
index b056e06c29d1..03c6f81a502a 100644
--- a/include/net/irda/irlmp_event.h
+++ b/include/net/irda/irlmp_event.h
@@ -79,26 +79,6 @@ typedef enum {
LM_LAP_IDLE_TIMEOUT,
} IRLMP_EVENT;
-/*
- * Information which is used by the current thread, when executing in the
- * state machine.
- */
-struct irlmp_event {
- IRLMP_EVENT *event;
- struct sk_buff *skb;
-
- __u8 hint;
- __u32 daddr;
- __u32 saddr;
-
- __u8 slsap;
- __u8 dlsap;
-
- int reason;
-
- struct discovery_t *discovery;
-};
-
extern const char *irlmp_state[];
extern const char *irlsap_state[];
diff --git a/include/net/irda/irport.h b/include/net/irda/irport.h
index 79b4d8904346..991f956c096c 100644
--- a/include/net/irda/irport.h
+++ b/include/net/irda/irport.h
@@ -67,6 +67,7 @@ struct irport_cb {
__u32 new_speed;
int mode;
int index; /* Instance index */
+ int transmitting; /* Are we transmitting ? */
spinlock_t lock; /* For serializing operations */
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 51f1ff56ff4d..0869bc8e6a2f 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -176,7 +176,7 @@ fail:
static int __init root_dev_setup(char *line)
{
- strncpy(saved_root_name, line, 63);
+ strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
diff --git a/kernel/futex.c b/kernel/futex.c
index df2dcbf557d0..5cd746c3c86c 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -545,7 +545,7 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
static struct super_block *
futexfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_pseudo(fs_type, "futex", NULL, 0xBAD1DEA);
}
diff --git a/lib/string.c b/lib/string.c
index b19212bc5d00..112389ed554a 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -169,6 +169,33 @@ char * strncat(char *dest, const char *src, size_t count)
}
#endif
+#ifndef __HAVE_ARCH_STRLCAT
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The size of the destination buffer.
+ */
+size_t strlcat(char *dest, const char *src, size_t count)
+{
+ size_t dsize = strlen(dest);
+ size_t len = strlen(src);
+ size_t res = dsize + len;
+
+ /* This would be a bug */
+ BUG_ON(dsize >= count);
+
+ dest += dsize;
+ count -= dsize;
+ if (len >= count)
+ len = count-1;
+ memcpy(dest, src, len);
+ dest[len] = 0;
+ return res;
+}
+EXPORT_SYMBOL(strlcat);
+#endif
+
#ifndef __HAVE_ARCH_STRCMP
/**
* strcmp - Compare two strings
diff --git a/mm/nommu.c b/mm/nommu.c
index a40138c746c2..cd7900bf3fe8 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -4,7 +4,7 @@
* Replacement code for mm functions to support CPU's that don't
* have any form of memory management unit (thus no virtual memory).
*
- * Copyright (c) 2000-2002 David McCullough <davidm@snapgear.com>
+ * Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com>
* Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org>
* Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com>
*/
@@ -30,6 +30,8 @@ unsigned long max_mapnr;
unsigned long num_physpages;
unsigned long askedalloc, realalloc;
atomic_t vm_committed_space = ATOMIC_INIT(0);
+int sysctl_overcommit_memory = 0; /* default is heuristic overcommit */
+int sysctl_overcommit_ratio = 50; /* default is 50% */
/*
* Handle all mappings that got truncated by a "truncate()"
@@ -102,6 +104,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
struct page **pages, struct vm_area_struct **vmas)
{
int i;
+ static struct vm_area_struct dummy_vma;
for (i = 0; i < len; i++) {
if (pages) {
@@ -109,6 +112,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
if (pages[i])
page_cache_get(pages[i]);
}
+ if (vmas)
+ vmas[i] = &dummy_vma;
start += PAGE_SIZE;
}
return(i);
@@ -180,7 +185,7 @@ void *vmalloc_32(unsigned long size)
return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
}
-void *vmap(struct page **pages, unsigned int count)
+void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot)
{
BUG();
return NULL;
diff --git a/mm/shmem.c b/mm/shmem.c
index 6703b33d0458..83514240a7ef 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1647,7 +1647,8 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
}
#endif
-static int shmem_fill_super(struct super_block *sb, void *data, int silent)
+static int shmem_fill_super(struct super_block *sb,
+ void *data, int silent)
{
struct inode *inode;
struct dentry *root;
@@ -1814,7 +1815,7 @@ static struct vm_operations_struct shmem_vm_ops = {
};
static struct super_block *shmem_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_nodev(fs_type, flags, data, shmem_fill_super);
}
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 90077d0f1168..6d0245b8c7b4 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -11,7 +11,7 @@
* Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
*
* Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1999-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com>
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -190,6 +190,9 @@ static void irda_connect_confirm(void *instance, void *sap,
if (sk == NULL)
return;
+ dev_kfree_skb(skb);
+ // Should be ??? skb_queue_tail(&sk->receive_queue, skb);
+
/* How much header space do we need to reserve */
self->max_header_size = max_header_size;
@@ -220,8 +223,6 @@ static void irda_connect_confirm(void *instance, void *sap,
self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
- dev_kfree_skb(skb);
- // Should be ??? skb_queue_tail(&sk->receive_queue, skb);
/* We are now connected! */
sk->state = TCP_ESTABLISHED;
@@ -260,6 +261,7 @@ static void irda_connect_indication(void *instance, void *sap,
case SOCK_STREAM:
if (max_sdu_size != 0) {
ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__);
+ kfree_skb(skb);
return;
}
self->max_data_size = irttp_get_max_seg_size(self->tsap);
@@ -267,6 +269,7 @@ static void irda_connect_indication(void *instance, void *sap,
case SOCK_SEQPACKET:
if (max_sdu_size == 0) {
ERROR("%s: max_sdu_size cannot be 0\n", __FUNCTION__);
+ kfree_skb(skb);
return;
}
self->max_data_size = max_sdu_size;
@@ -359,7 +362,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
* doesn't touch the dtsap_sel and save the full value structure...
*/
static void irda_getvalue_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv)
+ struct ias_value *value, void *priv)
{
struct irda_sock *self;
@@ -908,6 +911,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
new->tsap = irttp_dup(self->tsap, new);
if (!new->tsap) {
IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+ kfree_skb(skb);
return -1;
}
@@ -926,6 +930,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
/* Clean up the original one to keep it in listen state */
irttp_listen(self->tsap);
+ /* Wow ! What is that ? Jean II */
skb->sk = NULL;
skb->destructor = NULL;
kfree_skb(skb);
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index 122e62971306..552a105d7a9c 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -10,6 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -251,7 +252,6 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
info->max_header_size, skb);
else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
- dev_kfree_skb(skb);
}
}
@@ -295,7 +295,6 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
info->max_header_size, skb);
else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
- dev_kfree_skb(skb);
}
}
@@ -338,7 +337,6 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
self->notify.data_indication(self->notify.instance, self, skb);
else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
- dev_kfree_skb(skb);
}
}
@@ -370,9 +368,8 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
if (skb->len)
ircomm_data_indication(self, skb);
else {
- IRDA_DEBUG(4,
- "%s(), data was control info only!\n", __FUNCTION__ );
- dev_kfree_skb(skb);
+ IRDA_DEBUG(4, "%s(), data was control info only!\n",
+ __FUNCTION__ );
}
}
@@ -408,24 +405,28 @@ EXPORT_SYMBOL(ircomm_control_request);
static void ircomm_control_indication(struct ircomm_cb *self,
struct sk_buff *skb, int clen)
{
- struct sk_buff *ctrl_skb;
-
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
- ctrl_skb = skb_clone(skb, GFP_ATOMIC);
- if (!ctrl_skb)
- return;
+ /* Use udata for delivering data on the control channel */
+ if (self->notify.udata_indication) {
+ struct sk_buff *ctrl_skb;
+
+ /* We don't own the skb, so clone it */
+ ctrl_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!ctrl_skb)
+ return;
- /* Remove data channel from control channel */
- skb_trim(ctrl_skb, clen+1);
+ /* Remove data channel from control channel */
+ skb_trim(ctrl_skb, clen+1);
- /* Use udata for delivering data on the control channel */
- if (self->notify.udata_indication)
self->notify.udata_indication(self->notify.instance, self,
ctrl_skb);
- else {
+
+ /* Drop reference count -
+ * see ircomm_tty_control_indication(). */
+ dev_kfree_skb(ctrl_skb);
+ } else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
- dev_kfree_skb(skb);
}
}
@@ -470,7 +471,6 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
info->reason, skb);
} else {
IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
- dev_kfree_skb(skb);
}
}
diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c
index 21dbea74e50a..3ad421cbea83 100644
--- a/net/irda/ircomm/ircomm_event.c
+++ b/net/irda/ircomm/ircomm_event.c
@@ -109,9 +109,7 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_event[event]);
- if (skb)
- dev_kfree_skb(skb);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
@@ -141,8 +139,6 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -EINVAL;
}
return ret;
@@ -176,8 +172,6 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
ircomm_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -EINVAL;
}
return ret;
@@ -220,8 +214,6 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
default:
IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
ircomm_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -EINVAL;
}
return ret;
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
index 6b01349b6d4d..af27a51d08c5 100644
--- a/net/irda/ircomm/ircomm_lmp.c
+++ b/net/irda/ircomm/ircomm_lmp.c
@@ -11,6 +11,7 @@
* Sources: Previous IrLPT work by Thomas Davis
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -93,6 +94,10 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self,
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+ /* Don't forget to refcount it - should be NULL anyway */
+ if(userdata)
+ skb_get(userdata);
+
ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
info->saddr, info->daddr, NULL, userdata);
return ret;
@@ -106,29 +111,32 @@ int ircomm_lmp_connect_request(struct ircomm_cb *self,
*/
int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
int ret;
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
/* Any userdata supplied? */
if (userdata == NULL) {
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return -ENOMEM;
/* Reserve space for MUX and LAP header */
- skb_reserve(skb, LMP_MAX_HEADER);
+ skb_reserve(tx_skb, LMP_MAX_HEADER);
} else {
- skb = userdata;
/*
* Check that the client has reserved enough space for
* headers
*/
- ASSERT(skb_headroom(skb) >= LMP_MAX_HEADER, return -1;);
+ ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, return -1;);
+
+ /* Don't forget to refcount it - should be NULL anyway */
+ skb_get(userdata);
+ tx_skb = userdata;
}
- ret = irlmp_connect_response(self->lsap, skb);
+ ret = irlmp_connect_response(self->lsap, tx_skb);
return 0;
}
@@ -137,20 +145,24 @@ int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
struct sk_buff *userdata,
struct ircomm_info *info)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
int ret;
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
if (!userdata) {
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return -ENOMEM;
/* Reserve space for MUX and LAP header */
- skb_reserve(skb, LMP_MAX_HEADER);
- userdata = skb;
+ skb_reserve(tx_skb, LMP_MAX_HEADER);
+ userdata = tx_skb;
+ } else {
+ /* Don't forget to refcount it - should be NULL anyway */
+ skb_get(userdata);
}
+
ret = irlmp_disconnect_request(self->lsap, userdata);
return ret;
@@ -217,8 +229,11 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ );
+ /* Don't forget to refcount it - see ircomm_tty_do_softint() */
+ skb_get(skb);
+
skb->destructor = ircomm_lmp_flow_control;
-
+
if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ );
self->flow_status = FLOW_STOP;
@@ -229,7 +244,7 @@ int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
ret = irlmp_data_request(self->lsap, skb);
if (ret) {
ERROR("%s(), failed\n", __FUNCTION__);
- dev_kfree_skb(skb);
+ /* irlmp_data_request already free the packet */
}
return ret;
@@ -254,6 +269,9 @@ int ircomm_lmp_data_indication(void *instance, void *sap,
ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
+ /* Drop reference count - see ircomm_tty_data_indication(). */
+ dev_kfree_skb(skb);
+
return 0;
}
@@ -285,6 +303,9 @@ void ircomm_lmp_connect_confirm(void *instance, void *sap,
info.qos = qos;
ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
+
+ /* Drop reference count - see ircomm_tty_connect_confirm(). */
+ dev_kfree_skb(skb);
}
/*
@@ -315,6 +336,9 @@ void ircomm_lmp_connect_indication(void *instance, void *sap,
info.qos = qos;
ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
+
+ /* Drop reference count - see ircomm_tty_connect_indication(). */
+ dev_kfree_skb(skb);
}
/*
@@ -338,4 +362,8 @@ void ircomm_lmp_disconnect_indication(void *instance, void *sap,
info.reason = reason;
ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
+
+ /* Drop reference count - see ircomm_tty_disconnect_indication(). */
+ if(skb)
+ dev_kfree_skb(skb);
}
diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c
index ec53428259b9..c3b946e40fe6 100644
--- a/net/irda/ircomm/ircomm_ttp.c
+++ b/net/irda/ircomm/ircomm_ttp.c
@@ -10,6 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -94,9 +95,14 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self,
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+ /* Don't forget to refcount it - should be NULL anyway */
+ if(userdata)
+ skb_get(userdata);
+
ret = irttp_connect_request(self->tsap, info->dlsap_sel,
info->saddr, info->daddr, NULL,
TTP_SAR_DISABLE, userdata);
+
return ret;
}
@@ -106,13 +112,18 @@ int ircomm_ttp_connect_request(struct ircomm_cb *self,
*
*
*/
-int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
+int ircomm_ttp_connect_response(struct ircomm_cb *self,
+ struct sk_buff *userdata)
{
int ret;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
- ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, skb);
+ /* Don't forget to refcount it - should be NULL anyway */
+ if(userdata)
+ skb_get(userdata);
+
+ ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
return ret;
}
@@ -126,7 +137,8 @@ int ircomm_ttp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
* some of them are sent after connection establishment, so this can
* increase the latency a bit.
*/
-int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
+int ircomm_ttp_data_request(struct ircomm_cb *self,
+ struct sk_buff *skb,
int clen)
{
int ret;
@@ -140,6 +152,10 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
* only frames, to make things easier and avoid queueing
*/
ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
+
+ /* Don't forget to refcount it - see ircomm_tty_do_softint() */
+ skb_get(skb);
+
skb_push(skb, IRCOMM_HEADER_SIZE);
skb->data[0] = clen;
@@ -147,7 +163,7 @@ int ircomm_ttp_data_request(struct ircomm_cb *self, struct sk_buff *skb,
ret = irttp_data_request(self->tsap, skb);
if (ret) {
ERROR("%s(), failed\n", __FUNCTION__);
- dev_kfree_skb(skb);
+ /* irttp_data_request already free the packet */
}
return ret;
@@ -172,6 +188,9 @@ int ircomm_ttp_data_indication(void *instance, void *sap,
ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
+ /* Drop reference count - see ircomm_tty_data_indication(). */
+ dev_kfree_skb(skb);
+
return 0;
}
@@ -189,12 +208,11 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_MAGIC, return;);
ASSERT(skb != NULL, return;);
- ASSERT(qos != NULL, return;);
+ ASSERT(qos != NULL, goto out;);
if (max_sdu_size != TTP_SAR_DISABLE) {
ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
- dev_kfree_skb(skb);
- return;
+ goto out;
}
info.max_data_size = irttp_get_max_seg_size(self->tsap)
@@ -203,6 +221,10 @@ void ircomm_ttp_connect_confirm(void *instance, void *sap,
info.qos = qos;
ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
+
+out:
+ /* Drop reference count - see ircomm_tty_connect_confirm(). */
+ dev_kfree_skb(skb);
}
/*
@@ -226,12 +248,11 @@ void ircomm_ttp_connect_indication(void *instance, void *sap,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRCOMM_MAGIC, return;);
ASSERT(skb != NULL, return;);
- ASSERT(qos != NULL, return;);
+ ASSERT(qos != NULL, goto out;);
if (max_sdu_size != TTP_SAR_DISABLE) {
ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
- dev_kfree_skb(skb);
- return;
+ goto out;
}
info.max_data_size = irttp_get_max_seg_size(self->tsap)
@@ -240,6 +261,10 @@ void ircomm_ttp_connect_indication(void *instance, void *sap,
info.qos = qos;
ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
+
+out:
+ /* Drop reference count - see ircomm_tty_connect_indication(). */
+ dev_kfree_skb(skb);
}
/*
@@ -254,6 +279,10 @@ int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
{
int ret;
+ /* Don't forget to refcount it - should be NULL anyway */
+ if(userdata)
+ skb_get(userdata);
+
ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
return ret;
@@ -280,6 +309,10 @@ void ircomm_ttp_disconnect_indication(void *instance, void *sap,
info.reason = reason;
ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
+
+ /* Drop reference count - see ircomm_tty_disconnect_indication(). */
+ if(skb)
+ dev_kfree_skb(skb);
}
/*
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index e8ba645fc366..19a25ea6c3b9 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -11,6 +11,7 @@
* Sources: serial.c and previous IrCOMM work by Takahide Higuchi
*
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -663,8 +664,12 @@ static void ircomm_tty_do_softint(void *private_)
spin_unlock_irqrestore(&self->spinlock, flags);
/* Flush control buffer if any */
- if (ctrl_skb && self->flow == FLOW_START)
- ircomm_control_request(self->ircomm, ctrl_skb);
+ if(ctrl_skb) {
+ if(self->flow == FLOW_START)
+ ircomm_control_request(self->ircomm, ctrl_skb);
+ /* Drop reference count - see ircomm_ttp_data_request(). */
+ dev_kfree_skb(ctrl_skb);
+ }
if (tty->hw_stopped)
return;
@@ -678,8 +683,11 @@ static void ircomm_tty_do_softint(void *private_)
spin_unlock_irqrestore(&self->spinlock, flags);
/* Flush transmit buffer if any */
- if (skb)
+ if (skb) {
ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
+ /* Drop reference count - see ircomm_ttp_data_request(). */
+ dev_kfree_skb(skb);
+ }
/* Check if user (still) wants to be waken up */
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -1179,7 +1187,6 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
if (!self->tty) {
IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ );
- dev_kfree_skb(skb);
return 0;
}
@@ -1204,7 +1211,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
* handler
*/
self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len);
- dev_kfree_skb(skb);
+
+ /* No need to kfree_skb - see ircomm_ttp_data_indication() */
return 0;
}
@@ -1231,7 +1239,8 @@ static int ircomm_tty_control_indication(void *instance, void *sap,
irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen),
&ircomm_param_info);
- dev_kfree_skb(skb);
+
+ /* No need to kfree_skb - see ircomm_control_indication() */
return 0;
}
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index 2261d8ca5528..fa066ee2026a 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -10,6 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -236,8 +237,9 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
irias_insert_object(self->obj);
}
self->skey = irlmp_register_service(hints);
- self->ckey = irlmp_register_client(
- hints, ircomm_tty_discovery_indication, NULL, (void *) self);
+ self->ckey = irlmp_register_client(hints,
+ ircomm_tty_discovery_indication,
+ NULL, (void *) self);
}
/*
@@ -459,7 +461,7 @@ void ircomm_tty_connect_confirm(void *instance, void *sap,
ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
- dev_kfree_skb(skb);
+ /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */
}
/*
@@ -496,7 +498,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
- dev_kfree_skb(skb);
+ /* No need to kfree_skb - see ircomm_ttp_connect_indication() */
}
/*
@@ -647,7 +649,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
@@ -718,7 +720,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
@@ -774,7 +776,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
@@ -822,7 +824,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
@@ -874,7 +876,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
@@ -917,7 +919,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
default:
IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
ircomm_tty_event[event]);
- return -EINVAL;
+ ret = -EINVAL;
}
return ret;
}
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 6a16559dab9e..232fb7a78a6e 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -210,8 +210,8 @@ static void __iriap_close(struct iriap_cb *self)
del_timer(&self->watchdog_timer);
- if (self->skb)
- dev_kfree_skb(self->skb);
+ if (self->request_skb)
+ dev_kfree_skb(self->request_skb);
self->magic = 0;
@@ -278,7 +278,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
*/
static void iriap_disconnect_indication(void *instance, void *sap,
LM_REASON reason,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
struct iriap_cb *self;
@@ -293,6 +293,10 @@ static void iriap_disconnect_indication(void *instance, void *sap,
del_timer(&self->watchdog_timer);
+ /* Not needed */
+ if (skb)
+ dev_kfree_skb(skb);
+
if (self->mode == IAS_CLIENT) {
IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__);
@@ -312,9 +316,6 @@ static void iriap_disconnect_indication(void *instance, void *sap,
NULL);
iriap_close(self);
}
-
- if (userdata)
- dev_kfree_skb(userdata);
}
/*
@@ -322,15 +323,15 @@ static void iriap_disconnect_indication(void *instance, void *sap,
*/
void iriap_disconnect_request(struct iriap_cb *self)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
- skb = dev_alloc_skb(64);
- if (skb == NULL) {
+ tx_skb = dev_alloc_skb(64);
+ if (tx_skb == NULL) {
IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n",
__FUNCTION__, 64);
return;
@@ -339,9 +340,9 @@ void iriap_disconnect_request(struct iriap_cb *self)
/*
* Reserve space for MUX control and LAP header
*/
- skb_reserve(skb, LMP_MAX_HEADER);
+ skb_reserve(tx_skb, LMP_MAX_HEADER);
- irlmp_disconnect_request(self->lsap, skb);
+ irlmp_disconnect_request(self->lsap, tx_skb);
}
void iriap_getinfobasedetails_request(void)
@@ -379,7 +380,7 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self,
__u32 saddr, __u32 daddr,
char *name, char *attr)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
int name_len, attr_len, skb_len;
__u8 *frame;
@@ -405,14 +406,14 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self,
attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */
skb_len = self->max_header_size+2+name_len+1+attr_len+4;
- skb = dev_alloc_skb(skb_len);
- if (!skb)
+ tx_skb = dev_alloc_skb(skb_len);
+ if (!tx_skb)
return -ENOMEM;
/* Reserve space for MUX and LAP header */
- skb_reserve(skb, self->max_header_size);
- skb_put(skb, 3+name_len+attr_len);
- frame = skb->data;
+ skb_reserve(tx_skb, self->max_header_size);
+ skb_put(tx_skb, 3+name_len+attr_len);
+ frame = tx_skb->data;
/* Build frame */
frame[0] = IAP_LST | GET_VALUE_BY_CLASS;
@@ -421,7 +422,10 @@ int iriap_getvaluebyclass_request(struct iriap_cb *self,
frame[2+name_len] = attr_len; /* Insert length of attr */
memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */
- iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb);
+ iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb);
+
+ /* Drop reference count - see state_s_disconnect(). */
+ dev_kfree_skb(tx_skb);
return 0;
}
@@ -495,7 +499,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
/* Aborting, close connection! */
iriap_disconnect_request(self);
- dev_kfree_skb(skb);
return;
/* break; */
}
@@ -533,7 +536,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__);
irias_delete_value(value);
}
- dev_kfree_skb(skb);
}
/*
@@ -545,7 +547,7 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
__u8 ret_code, struct ias_value *value)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
int n;
__u32 tmp_be32, tmp_be16;
__u8 *fp;
@@ -565,15 +567,15 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
* value. We add 32 bytes because of the 6 bytes for the frame and
* max 5 bytes for the value coding.
*/
- skb = dev_alloc_skb(value->len + self->max_header_size + 32);
- if (!skb)
+ tx_skb = dev_alloc_skb(value->len + self->max_header_size + 32);
+ if (!tx_skb)
return;
/* Reserve space for MUX and LAP header */
- skb_reserve(skb, self->max_header_size);
- skb_put(skb, 6);
+ skb_reserve(tx_skb, self->max_header_size);
+ skb_put(tx_skb, 6);
- fp = skb->data;
+ fp = tx_skb->data;
/* Build frame */
fp[n++] = GET_VALUE_BY_CLASS | IAP_LST;
@@ -589,21 +591,21 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
switch (value->type) {
case IAS_STRING:
- skb_put(skb, 3 + value->len);
+ skb_put(tx_skb, 3 + value->len);
fp[n++] = value->type;
fp[n++] = 0; /* ASCII */
fp[n++] = (__u8) value->len;
memcpy(fp+n, value->t.string, value->len); n+=value->len;
break;
case IAS_INTEGER:
- skb_put(skb, 5);
+ skb_put(tx_skb, 5);
fp[n++] = value->type;
tmp_be32 = cpu_to_be32(value->t.integer);
memcpy(fp+n, &tmp_be32, 4); n += 4;
break;
case IAS_OCT_SEQ:
- skb_put(skb, 3 + value->len);
+ skb_put(tx_skb, 3 + value->len);
fp[n++] = value->type;
tmp_be16 = cpu_to_be16(value->len);
@@ -612,14 +614,17 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
break;
case IAS_MISSING:
IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__);
- skb_put(skb, 1);
+ skb_put(tx_skb, 1);
fp[n++] = value->type;
break;
default:
IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__);
break;
}
- iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, skb);
+ iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
+
+ /* Drop reference count - see state_r_execute(). */
+ dev_kfree_skb(tx_skb);
}
/*
@@ -657,9 +662,6 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
memcpy(attr, fp+n, attr_len); n+=attr_len;
attr[attr_len] = '\0';
- /* We do not need the buffer anymore */
- dev_kfree_skb(skb);
-
IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr);
obj = irias_find_object(name);
@@ -694,7 +696,7 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
*/
void iriap_send_ack(struct iriap_cb *self)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
__u8 *frame;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
@@ -702,19 +704,19 @@ void iriap_send_ack(struct iriap_cb *self)
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return;
/* Reserve space for MUX and LAP header */
- skb_reserve(skb, self->max_header_size);
- skb_put(skb, 1);
- frame = skb->data;
+ skb_reserve(tx_skb, self->max_header_size);
+ skb_put(tx_skb, 1);
+ frame = tx_skb->data;
/* Build frame */
frame[0] = IAP_LST | IAP_ACK | self->operation;
- irlmp_data_request(self->lsap, skb);
+ irlmp_data_request(self->lsap, tx_skb);
}
void iriap_connect_request(struct iriap_cb *self)
@@ -742,7 +744,7 @@ void iriap_connect_request(struct iriap_cb *self)
static void iriap_connect_confirm(void *instance, void *sap,
struct qos_info *qos, __u32 max_seg_size,
__u8 max_header_size,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
struct iriap_cb *self;
@@ -750,14 +752,17 @@ static void iriap_connect_confirm(void *instance, void *sap,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IAS_MAGIC, return;);
- ASSERT(userdata != NULL, return;);
+ ASSERT(skb != NULL, return;);
self->max_data_size = max_seg_size;
self->max_header_size = max_header_size;
del_timer(&self->watchdog_timer);
- iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata);
+ iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb);
+
+ /* Drop reference count - see state_s_make_call(). */
+ dev_kfree_skb(skb);
}
/*
@@ -769,7 +774,7 @@ static void iriap_connect_confirm(void *instance, void *sap,
static void iriap_connect_indication(void *instance, void *sap,
struct qos_info *qos, __u32 max_seg_size,
__u8 max_header_size,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
struct iriap_cb *self, *new;
@@ -777,22 +782,22 @@ static void iriap_connect_indication(void *instance, void *sap,
self = (struct iriap_cb *) instance;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IAS_MAGIC, return;);
+ ASSERT(skb != NULL, return;);
+ ASSERT(self != NULL, goto out;);
+ ASSERT(self->magic == IAS_MAGIC, goto out;);
/* Start new server */
new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
if (!new) {
IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__);
- dev_kfree_skb(userdata);
- return;
+ goto out;
}
/* Now attach up the new "socket" */
new->lsap = irlmp_dup(self->lsap, new);
if (!new->lsap) {
IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
- return;
+ goto out;
}
new->max_data_size = max_seg_size;
@@ -801,7 +806,11 @@ static void iriap_connect_indication(void *instance, void *sap,
/* Clean up the original one to keep it in listen state */
irlmp_listen(self->lsap);
- iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, userdata);
+ iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb);
+
+out:
+ /* Drop reference count - see state_r_disconnect(). */
+ dev_kfree_skb(skb);
}
/*
@@ -821,10 +830,9 @@ static int iriap_data_indication(void *instance, void *sap,
self = (struct iriap_cb *) instance;
- ASSERT(self != NULL, return 0;);
- ASSERT(self->magic == IAS_MAGIC, return 0;);
-
ASSERT(skb != NULL, return 0;);
+ ASSERT(self != NULL, goto out;);
+ ASSERT(self->magic == IAS_MAGIC, goto out;);
frame = skb->data;
@@ -832,22 +840,19 @@ static int iriap_data_indication(void *instance, void *sap,
/* Call server */
IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__);
iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
-
- return 0;
+ goto out;
}
opcode = frame[0];
if (~opcode & IAP_LST) {
WARNING("%s:, IrIAS multiframe commands or "
"results is not implemented yet!\n", __FUNCTION__);
- dev_kfree_skb(skb);
- return 0;
+ goto out;
}
/* Check for ack frames since they don't contain any data */
if (opcode & IAP_ACK) {
IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__);
- dev_kfree_skb(skb);
- return 0;
+ goto out;
}
opcode &= ~IAP_LST; /* Mask away LST bit */
@@ -855,7 +860,6 @@ static int iriap_data_indication(void *instance, void *sap,
switch (opcode) {
case GET_INFO_BASE:
IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n");
- dev_kfree_skb(skb);
break;
case GET_VALUE_BY_CLASS:
iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
@@ -876,7 +880,6 @@ static int iriap_data_indication(void *instance, void *sap,
if (self->confirm)
self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
self->priv);
- dev_kfree_skb(skb);
break;
case IAS_ATTRIB_UNKNOWN:
IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__);
@@ -890,16 +893,18 @@ static int iriap_data_indication(void *instance, void *sap,
if (self->confirm)
self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL,
self->priv);
- dev_kfree_skb(skb);
break;
}
break;
default:
IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__,
opcode);
- dev_kfree_skb(skb);
break;
}
+
+out:
+ /* Cleanup - sub-calls will have done skb_get() as needed. */
+ dev_kfree_skb(skb);
return 0;
}
@@ -939,6 +944,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
iriap_getvaluebyclass_indication(self, skb);
break;
}
+ /* skb will be cleaned up in iriap_data_indication */
}
/*
diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
index 07f27182e743..ce209ad44eaf 100644
--- a/net/irda/iriap_event.c
+++ b/net/irda/iriap_event.c
@@ -11,6 +11,7 @@
*
* Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -174,8 +175,11 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
switch (event) {
case IAP_CALL_REQUEST_GVBC:
iriap_next_client_state(self, S_CONNECTING);
- ASSERT(self->skb == NULL, return;);
- self->skb = skb;
+ ASSERT(self->request_skb == NULL, return;);
+ /* Don't forget to refcount it -
+ * see iriap_getvaluebyclass_request(). */
+ skb_get(skb);
+ self->request_skb = skb;
iriap_connect_request(self);
break;
case IAP_LM_DISCONNECT_INDICATION:
@@ -251,20 +255,21 @@ static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event,
static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event,
struct sk_buff *skb)
{
+ struct sk_buff *tx_skb;
+
ASSERT(self != NULL, return;);
switch (event) {
case IAP_CALL_REQUEST:
- skb = self->skb;
- self->skb = NULL;
+ /* Already refcounted - see state_s_disconnect() */
+ tx_skb = self->request_skb;
+ self->request_skb = NULL;
- irlmp_data_request(self->lsap, skb);
+ irlmp_data_request(self->lsap, tx_skb);
iriap_next_call_state(self, S_OUTSTANDING);
break;
default:
IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
- if (skb)
- dev_kfree_skb(skb);
break;
}
}
@@ -379,10 +384,6 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
* care about LM_Idle_request()!
*/
iriap_next_r_connect_state(self, R_RECEIVING);
-
- if (skb)
- dev_kfree_skb(skb);
-
break;
default:
IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event);
@@ -450,7 +451,6 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
break;
}
-
}
/*
@@ -465,11 +465,8 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
ASSERT(skb != NULL, return;);
-
- if (!self || self->magic != IAS_MAGIC) {
- IRDA_DEBUG(0, "%s(), bad pointer self\n", __FUNCTION__);
- return;
- }
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == IAS_MAGIC, return;);
switch (event) {
case IAP_CALL_RESPONSE:
@@ -479,6 +476,10 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
*/
iriap_next_r_connect_state(self, R_RECEIVING);
+ /* Don't forget to refcount it - see
+ * iriap_getvaluebyclass_response(). */
+ skb_get(skb);
+
irlmp_data_request(self->lsap, skb);
break;
default:
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 727c1eb64c2f..69236887ac55 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -1180,20 +1180,6 @@ void print_ret_code(__u8 code)
}
}
-void irlan_mod_inc_use_count(void)
-{
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-}
-
-void irlan_mod_dec_use_count(void)
-{
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-}
-
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
MODULE_LICENSE("GPL");
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 8639f6a5ea07..6ba413f5e82b 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -31,6 +31,7 @@
#include <linux/inetdevice.h>
#include <linux/if_arp.h>
#include <linux/random.h>
+#include <linux/module.h>
#include <net/arp.h>
#include <net/irda/irda.h>
@@ -61,6 +62,7 @@ int irlan_eth_init(struct net_device *dev)
dev->hard_start_xmit = irlan_eth_xmit;
dev->get_stats = irlan_eth_get_stats;
dev->set_multicast_list = irlan_eth_set_multicast_list;
+ SET_MODULE_OWNER(dev);
ether_setup(dev);
@@ -112,8 +114,6 @@ int irlan_eth_open(struct net_device *dev)
self->disconnect_reason = 0;
irlan_client_wakeup(self, self->saddr, self->daddr);
- irlan_mod_inc_use_count();
-
/* Make sure we have a hardware address before we return, so DHCP clients gets happy */
interruptible_sleep_on(&self->open_wait);
@@ -138,8 +138,6 @@ int irlan_eth_close(struct net_device *dev)
/* Stop device */
netif_stop_queue(dev);
- irlan_mod_dec_use_count();
-
irlan_close_data_channel(self);
irlan_close_tsaps(self);
@@ -206,7 +204,7 @@ int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev)
* confuse do_dev_queue_xmit() in dev.c! I have
* tried :-) DB
*/
- dev_kfree_skb(skb);
+ /* irttp_data_request already free the packet */
self->stats.tx_dropped++;
} else {
self->stats.tx_packets++;
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 59b08f0d698c..627278c5fef9 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -10,7 +10,7 @@
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -244,7 +244,6 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
irlap_init_qos_capabilities(self, NULL); /* No user QoS! */
- skb_get(skb); /*LEVEL4*/
irlmp_link_connect_indication(self->notify.instance, self->saddr,
self->daddr, &self->qos_tx, skb);
}
@@ -255,12 +254,11 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
* Service user has accepted incoming connection
*
*/
-void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb)
+void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
{
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
- irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
- kfree_skb(skb);
+ irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);
}
/*
@@ -305,7 +303,6 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- skb_get(skb); /*LEVEL4*/
irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);
}
@@ -322,7 +319,6 @@ void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
/* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
- skb_get(skb); /*LEVEL4*/
irlmp_link_data_indication(self->notify.instance, skb, unreliable);
}
@@ -354,6 +350,9 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
else
skb->data[1] = I_FRAME;
+ /* Don't forget to refcount it - see irlmp_connect_request(). */
+ skb_get(skb);
+
/* Add at the end of the queue (keep ordering) - Jean II */
skb_queue_tail(&self->txq, skb);
@@ -392,6 +391,8 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
skb->data[0] = CBROADCAST;
skb->data[1] = UI_FRAME;
+ /* Don't need to refcount, see irlmp_connless_data_request() */
+
skb_queue_tail(&self->txq_ultra, skb);
irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
@@ -416,7 +417,6 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
/* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
- skb_get(skb); /*LEVEL4*/
irlmp_link_unitdata_indication(self->notify.instance, skb);
}
#endif /* CONFIG_IRDA_ULTRA */
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 975c30d3d119..b6df8f99d6f6 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -12,7 +12,7 @@
* Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>,
* Copyright (c) 1998 Thomas Davis <ratbert@radiks.net>
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -287,6 +287,9 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
/* Send one frame */
ret = (*state[self->state])(self, SEND_I_CMD,
skb, NULL);
+ /* Drop reference count.
+ * It will be increase as needed in
+ * irlap_send_data_xxx() */
kfree_skb(skb);
/* Poll the higher layers for one more frame */
@@ -517,6 +520,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
CMD_FRAME);
else
break;
+ /* irlap_send_ui_frame() won't increase skb reference
+ * count, so no dev_kfree_skb() - Jean II */
}
if (i == 2) {
/* Force us to listen 500 ms again */
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index c40c1197c129..856c3c63cfe4 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -106,7 +106,7 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
*/
void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
struct snrm_frame *frame;
int ret;
@@ -114,11 +114,11 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
ASSERT(self->magic == LAP_MAGIC, return;);
/* Allocate frame */
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return;
- frame = (struct snrm_frame *) skb_put(skb, 2);
+ frame = (struct snrm_frame *) skb_put(tx_skb, 2);
/* Insert connection address field */
if (qos)
@@ -133,19 +133,19 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
* If we are establishing a connection then insert QoS paramerters
*/
if (qos) {
- skb_put(skb, 9); /* 21 left */
+ skb_put(tx_skb, 9); /* 21 left */
frame->saddr = cpu_to_le32(self->saddr);
frame->daddr = cpu_to_le32(self->daddr);
frame->ncaddr = self->caddr;
- ret = irlap_insert_qos_negotiation_params(self, skb);
+ ret = irlap_insert_qos_negotiation_params(self, tx_skb);
if (ret < 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb(tx_skb);
return;
}
}
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -162,8 +162,8 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
frame = (struct snrm_frame *) skb->data;
if (skb->len >= sizeof(struct snrm_frame)) {
- /* Copy the new connection address */
- info->caddr = frame->ncaddr;
+ /* Copy the new connection address ignoring the C/R bit */
+ info->caddr = frame->ncaddr & 0xFE;
/* Check if the new connection address is valid */
if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
@@ -197,7 +197,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
*/
void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
struct ua_frame *frame;
int ret;
@@ -206,14 +206,12 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- skb = NULL;
-
/* Allocate frame */
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return;
- frame = (struct ua_frame *) skb_put(skb, 10);
+ frame = (struct ua_frame *) skb_put(tx_skb, 10);
/* Build UA response */
frame->caddr = self->caddr;
@@ -224,14 +222,14 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
/* Should we send QoS negotiation parameters? */
if (qos) {
- ret = irlap_insert_qos_negotiation_params(self, skb);
+ ret = irlap_insert_qos_negotiation_params(self, tx_skb);
if (ret < 0) {
- dev_kfree_skb(skb);
+ dev_kfree_skb(tx_skb);
return;
}
}
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
@@ -243,17 +241,17 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
*/
void irlap_send_dm_frame( struct irlap_cb *self)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *tx_skb = NULL;
__u8 *frame;
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- skb = dev_alloc_skb(32);
- if (!skb)
+ tx_skb = dev_alloc_skb(32);
+ if (!tx_skb)
return;
- frame = skb_put( skb, 2);
+ frame = skb_put(tx_skb, 2);
if (self->state == LAP_NDM)
frame[0] = CBROADCAST;
@@ -262,7 +260,7 @@ void irlap_send_dm_frame( struct irlap_cb *self)
frame[1] = DM_RSP | PF_BIT;
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -273,7 +271,7 @@ void irlap_send_dm_frame( struct irlap_cb *self)
*/
void irlap_send_disc_frame(struct irlap_cb *self)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *tx_skb = NULL;
__u8 *frame;
IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
@@ -281,16 +279,16 @@ void irlap_send_disc_frame(struct irlap_cb *self)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- skb = dev_alloc_skb(16);
- if (!skb)
+ tx_skb = dev_alloc_skb(16);
+ if (!tx_skb)
return;
- frame = skb_put(skb, 2);
+ frame = skb_put(tx_skb, 2);
frame[0] = self->caddr | CMD_FRAME;
frame[1] = DISC_CMD | PF_BIT;
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -302,7 +300,7 @@ void irlap_send_disc_frame(struct irlap_cb *self)
void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
__u8 command, discovery_t *discovery)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *tx_skb = NULL;
struct xid_frame *frame;
__u32 bcast = BROADCAST;
__u8 *info;
@@ -314,12 +312,12 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
ASSERT(self->magic == LAP_MAGIC, return;);
ASSERT(discovery != NULL, return;);
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return;
- skb_put(skb, 14);
- frame = (struct xid_frame *) skb->data;
+ skb_put(tx_skb, 14);
+ frame = (struct xid_frame *) tx_skb->data;
if (command) {
frame->caddr = CBROADCAST | CMD_FRAME;
@@ -367,21 +365,21 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
int len;
if (discovery->data.hints[0] & HINT_EXTENSION) {
- info = skb_put(skb, 2);
+ info = skb_put(tx_skb, 2);
info[0] = discovery->data.hints[0];
info[1] = discovery->data.hints[1];
} else {
- info = skb_put(skb, 1);
+ info = skb_put(tx_skb, 1);
info[0] = discovery->data.hints[0];
}
- info = skb_put(skb, 1);
+ info = skb_put(tx_skb, 1);
info[0] = discovery->data.charset;
- len = IRDA_MIN(discovery->name_len, skb_tailroom(skb));
- info = skb_put(skb, len);
+ len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb));
+ info = skb_put(tx_skb, len);
memcpy(info, discovery->data.info, len);
}
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -498,7 +496,6 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
break;
default:
/* Error!! */
- dev_kfree_skb(skb);
return;
}
info->s = xid->slotnr;
@@ -561,21 +558,21 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
*/
void irlap_send_rr_frame(struct irlap_cb *self, int command)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
__u8 *frame;
- skb = dev_alloc_skb(16);
- if (!skb)
+ tx_skb = dev_alloc_skb(16);
+ if (!tx_skb)
return;
- frame = skb_put(skb, 2);
+ frame = skb_put(tx_skb, 2);
frame[0] = self->caddr;
frame[0] |= (command) ? CMD_FRAME : 0;
frame[1] = RR | PF_BIT | (self->vr << 5);
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -586,19 +583,19 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command)
*/
void irlap_send_rd_frame(struct irlap_cb *self)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
__u8 *frame;
- skb = dev_alloc_skb(16);
- if (!skb)
+ tx_skb = dev_alloc_skb(16);
+ if (!tx_skb)
return;
- frame = skb_put(skb, 2);
+ frame = skb_put(tx_skb, 2);
frame[0] = self->caddr;
frame[1] = RD_RSP | PF_BIT;
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -623,17 +620,17 @@ static inline void irlap_recv_rr_frame(struct irlap_cb *self,
void irlap_send_frmr_frame( struct irlap_cb *self, int command)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *tx_skb = NULL;
__u8 *frame;
ASSERT( self != NULL, return;);
ASSERT( self->magic == LAP_MAGIC, return;);
- skb = dev_alloc_skb( 32);
- if (!skb)
+ tx_skb = dev_alloc_skb( 32);
+ if (!tx_skb)
return;
- frame = skb_put( skb, 2);
+ frame = skb_put(tx_skb, 2);
frame[0] = self->caddr;
frame[0] |= (command) ? CMD_FRAME : 0;
@@ -646,7 +643,7 @@ void irlap_send_frmr_frame( struct irlap_cb *self, int command)
IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies);
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -739,17 +736,19 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
*/
skb->data[1] = I_FRAME | (self->vs << 1);
+ /*
+ * Insert frame in store, in case of retransmissions
+ * Increase skb reference count, see irlap_do_event()
+ */
+ skb_get(skb);
+ skb_queue_tail(&self->wx_list, skb);
+
/* Copy buffer */
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
return;
}
- /*
- * Insert frame in store, in case of retransmissions
- */
- skb_queue_tail(&self->wx_list, skb_get(skb));
-
self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE;
self->window -= 1;
@@ -782,6 +781,13 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
*/
skb->data[1] = I_FRAME | (self->vs << 1);
+ /*
+ * Insert frame in store, in case of retransmissions
+ * Increase skb reference count, see irlap_do_event()
+ */
+ skb_get(skb);
+ skb_queue_tail(&self->wx_list, skb);
+
/* Copy buffer */
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
@@ -789,11 +795,6 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
}
/*
- * Insert frame in store, in case of retransmissions
- */
- skb_queue_tail(&self->wx_list, skb_get(skb));
-
- /*
* Set poll bit if necessary. We do this to the copied
* skb, since retransmitted need to set or clear the poll
* bit depending on when they are sent.
@@ -850,14 +851,18 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
*/
skb->data[1] = I_FRAME | (self->vs << 1);
+ /*
+ * Insert frame in store, in case of retransmissions
+ * Increase skb reference count, see irlap_do_event()
+ */
+ skb_get(skb);
+ skb_queue_tail(&self->wx_list, skb);
+
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
return;
}
- /* Insert frame in store */
- skb_queue_tail(&self->wx_list, skb_get(skb));
-
tx_skb->data[1] |= PF_BIT;
self->vs = (self->vs + 1) % 8;
@@ -903,14 +908,18 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
*/
skb->data[1] = I_FRAME | (self->vs << 1);
+ /*
+ * Insert frame in store, in case of retransmissions
+ * Increase skb reference count, see irlap_do_event()
+ */
+ skb_get(skb);
+ skb_queue_tail(&self->wx_list, skb);
+
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
return;
}
- /* Insert frame in store */
- skb_queue_tail(&self->wx_list, skb_get(skb));
-
self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE;
self->window -= 1;
@@ -939,8 +948,6 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
ASSERT(self->magic == LAP_MAGIC, return;);
/* Initialize variables */
- skb = tx_skb = NULL;
-
count = skb_queue_len(&self->wx_list);
/* Resend unacknowledged frame(s) */
@@ -1020,9 +1027,6 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
- /* Initialize variables */
- skb = tx_skb = NULL;
-
/* Resend unacknowledged frame(s) */
skb = skb_peek(&self->wx_list);
if (skb != NULL) {
@@ -1186,35 +1190,35 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
struct sk_buff *cmd)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
struct test_frame *frame;
__u8 *info;
- skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame));
- if (!skb)
+ tx_skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame));
+ if (!tx_skb)
return;
/* Broadcast frames must include saddr and daddr fields */
if (caddr == CBROADCAST) {
frame = (struct test_frame *)
- skb_put(skb, sizeof(struct test_frame));
+ skb_put(tx_skb, sizeof(struct test_frame));
/* Insert the swapped addresses */
frame->saddr = cpu_to_le32(self->saddr);
frame->daddr = cpu_to_le32(daddr);
} else
- frame = (struct test_frame *) skb_put(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
+ frame = (struct test_frame *) skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
frame->caddr = caddr;
frame->control = TEST_RSP | PF_BIT;
/* Copy info */
- info = skb_put(skb, cmd->len);
+ info = skb_put(tx_skb, cmd->len);
memcpy(info, cmd->data, cmd->len);
/* Return to sender */
irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_queue_xmit(self, skb);
+ irlap_queue_xmit(self, tx_skb);
}
/*
@@ -1263,6 +1267,15 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
* Called when a frame is received. Dispatches the right receive function
* for processing of the frame.
*
+ * Note on skb management :
+ * After calling the higher layers of the IrDA stack, we always
+ * kfree() the skb, which drop the reference count (and potentially
+ * destroy it).
+ * If a higher layer of the stack want to keep the skb around (to put
+ * in a queue or pass it to the higher layer), it will need to use
+ * skb_get() to keep a reference on it. This is usually done at the
+ * LMP level in irlmp.c.
+ * Jean II
*/
int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype)
@@ -1286,6 +1299,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
* we don't need to be clever about it. Jean II */
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
+ dev_kfree_skb(skb);
return -1;
}
if (skb_is_nonlinear(skb))
@@ -1390,6 +1404,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
break;
}
out:
+ /* Always drop our reference on the skb */
dev_kfree_skb(skb);
return 0;
}
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index a44327be74d8..b6d41fc2772f 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -345,9 +345,10 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
__u32 saddr, __u32 daddr,
struct qos_info *qos, struct sk_buff *userdata)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *tx_skb = userdata;
struct lap_cb *lap;
struct lsap_cb *lsap;
+ int ret;
ASSERT(self != NULL, return -EBADR;);
ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
@@ -356,26 +357,29 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
"%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
__FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr);
- if (test_bit(0, &self->connected))
- return -EISCONN;
+ if (test_bit(0, &self->connected)) {
+ ret = -EISCONN;
+ goto err;
+ }
/* Client must supply destination device address */
- if (!daddr)
- return -EINVAL;
+ if (!daddr) {
+ ret = -EINVAL;
+ goto err;
+ }
/* Any userdata? */
- if (userdata == NULL) {
- skb = dev_alloc_skb(64);
- if (!skb)
+ if (tx_skb == NULL) {
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return -ENOMEM;
- skb_reserve(skb, LMP_MAX_HEADER);
- } else
- skb = userdata;
+ skb_reserve(tx_skb, LMP_MAX_HEADER);
+ }
/* Make room for MUX control header (3 bytes) */
- ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
- skb_push(skb, LMP_CONTROL_HEADER);
+ ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;);
+ skb_push(tx_skb, LMP_CONTROL_HEADER);
self->dlsap_sel = dlsap_sel;
@@ -409,7 +413,8 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
lap = hashbin_lock_find(irlmp->links, saddr, NULL);
if (lap == NULL) {
IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__);
- return -EHOSTUNREACH;
+ ret = -EHOSTUNREACH;
+ goto err;
}
/* Check if LAP is disconnected or already connected */
@@ -423,13 +428,15 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
* Maybe we could give LAP a bit of help in this case.
*/
IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto err;
}
/* LAP is already connected to a different node, and LAP
* can only talk to one node at a time */
IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__);
- return -EBUSY;
+ ret = -EBUSY;
+ goto err;
}
self->lap = lap;
@@ -456,9 +463,18 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
if (qos)
self->qos = *qos;
- irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, skb);
+ irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb);
+
+ /* Drop reference count - see irlap_data_request(). */
+ dev_kfree_skb(tx_skb);
return 0;
+
+err:
+ /* Cleanup */
+ if(tx_skb)
+ dev_kfree_skb(tx_skb);
+ return ret;
}
/*
@@ -495,12 +511,13 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP_CONTROL_HEADER header from layer above */
skb_pull(skb, LMP_CONTROL_HEADER);
- if (self->notify.connect_indication)
+ if (self->notify.connect_indication) {
+ /* Don't forget to refcount it - see irlap_driver_rcv(). */
+ skb_get(skb);
self->notify.connect_indication(self->notify.instance, self,
&self->qos, max_seg_size,
max_header_size, skb);
- else
- dev_kfree_skb(skb);
+ }
}
/*
@@ -526,6 +543,9 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
+ /* Drop reference count - see irlap_data_request(). */
+ dev_kfree_skb(userdata);
+
return 0;
}
@@ -560,11 +580,12 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
skb_pull(skb, LMP_CONTROL_HEADER);
if (self->notify.connect_confirm) {
+ /* Don't forget to refcount it - see irlap_driver_rcv() */
+ skb_get(skb);
self->notify.connect_confirm(self->notify.instance, self,
&self->qos, max_seg_size,
max_header_size, skb);
- } else
- dev_kfree_skb(skb);
+ }
}
/*
@@ -602,6 +623,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
memcpy(new, orig, sizeof(struct lsap_cb));
/* new->lap = orig->lap; => done in the memcpy() */
/* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */
+ new->conn_skb = NULL;
spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
@@ -653,6 +675,9 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
*/
irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata);
+ /* Drop reference count - see irlap_data_request(). */
+ dev_kfree_skb(userdata);
+
/*
* Remove LSAP from list of connected LSAPs for the particular link
* and insert it into the list of unconnected LSAPs
@@ -686,7 +711,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
* LSAP is being closed!
*/
void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
struct lsap_cb *lsap;
@@ -703,8 +728,6 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
* Jean II */
if (! test_and_clear_bit(0, &self->connected)) {
IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
- if (userdata)
- dev_kfree_skb(userdata);
return;
}
@@ -730,13 +753,14 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
/*
* Inform service user
*/
- if (self->notify.disconnect_indication)
+ if (self->notify.disconnect_indication) {
+ /* Don't forget to refcount it - see irlap_driver_rcv(). */
+ if(skb)
+ skb_get(skb);
self->notify.disconnect_indication(self->notify.instance,
- self, reason, userdata);
- else {
+ self, reason, skb);
+ } else {
IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__);
- if (userdata)
- dev_kfree_skb(userdata);
}
}
@@ -1047,17 +1071,31 @@ discovery_t *irlmp_get_discovery_response()
*
* Send some data to peer device
*
+ * Note on skb management :
+ * After calling the lower layers of the IrDA stack, we always
+ * kfree() the skb, which drop the reference count (and potentially
+ * destroy it).
+ * IrLMP and IrLAP may queue the packet, and in those cases will need
+ * to use skb_get() to keep it around.
+ * Jean II
*/
-int irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb)
+int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata)
{
+ int ret;
+
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
/* Make room for MUX header */
- ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
- skb_push(skb, LMP_HEADER);
+ ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
+ skb_push(userdata, LMP_HEADER);
+
+ ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata);
- return irlmp_do_lsap_event(self, LM_DATA_REQUEST, skb);
+ /* Drop reference count - see irlap_data_request(). */
+ dev_kfree_skb(userdata);
+
+ return ret;
}
/*
@@ -1071,26 +1109,34 @@ void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP header from layer above */
skb_pull(skb, LMP_HEADER);
- if (self->notify.data_indication)
+ if (self->notify.data_indication) {
+ /* Don't forget to refcount it - see irlap_driver_rcv(). */
+ skb_get(skb);
self->notify.data_indication(self->notify.instance, self, skb);
- else
- dev_kfree_skb(skb);
+ }
}
/*
* Function irlmp_udata_request (self, skb)
*/
-int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *skb)
+int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata)
{
+ int ret;
+
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
- ASSERT(skb != NULL, return -1;);
+ ASSERT(userdata != NULL, return -1;);
/* Make room for MUX header */
- ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
- skb_push(skb, LMP_HEADER);
+ ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;);
+ skb_push(userdata, LMP_HEADER);
+
+ ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata);
- return irlmp_do_lsap_event(self, LM_UDATA_REQUEST, skb);
+ /* Drop reference count - see irlap_data_request(). */
+ dev_kfree_skb(userdata);
+
+ return ret;
}
/*
@@ -1110,51 +1156,57 @@ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP header from layer above */
skb_pull(skb, LMP_HEADER);
- if (self->notify.udata_indication)
+ if (self->notify.udata_indication) {
+ /* Don't forget to refcount it - see irlap_driver_rcv(). */
+ skb_get(skb);
self->notify.udata_indication(self->notify.instance, self,
skb);
- else
- dev_kfree_skb(skb);
+ }
}
/*
* Function irlmp_connless_data_request (self, skb)
*/
#ifdef CONFIG_IRDA_ULTRA
-int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *skb)
+int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata)
{
struct sk_buff *clone_skb;
struct lap_cb *lap;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
- ASSERT(skb != NULL, return -1;);
+ ASSERT(userdata != NULL, return -1;);
/* Make room for MUX and PID header */
- ASSERT(skb_headroom(skb) >= LMP_HEADER+LMP_PID_HEADER, return -1;);
+ ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER,
+ return -1;);
/* Insert protocol identifier */
- skb_push(skb, LMP_PID_HEADER);
- skb->data[0] = self->pid;
+ skb_push(userdata, LMP_PID_HEADER);
+ userdata->data[0] = self->pid;
/* Connectionless sockets must use 0x70 */
- skb_push(skb, LMP_HEADER);
- skb->data[0] = skb->data[1] = LSAP_CONNLESS;
+ skb_push(userdata, LMP_HEADER);
+ userdata->data[0] = userdata->data[1] = LSAP_CONNLESS;
/* Try to send Connectionless packets out on all links */
lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
while (lap != NULL) {
ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;);
- clone_skb = skb_clone(skb, GFP_ATOMIC);
- if (!clone_skb)
+ clone_skb = skb_clone(userdata, GFP_ATOMIC);
+ if (!clone_skb) {
+ dev_kfree_skb(userdata);
return -ENOMEM;
+ }
irlap_unitdata_request(lap->irlap, clone_skb);
+ /* irlap_unitdata_request() don't increase refcount,
+ * so no dev_kfree_skb() - Jean II */
lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
}
- dev_kfree_skb(skb);
+ dev_kfree_skb(userdata);
return 0;
}
@@ -1178,11 +1230,12 @@ void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
/* Hide LMP and PID header from layer above */
skb_pull(skb, LMP_HEADER+LMP_PID_HEADER);
- if (self->notify.udata_indication)
+ if (self->notify.udata_indication) {
+ /* Don't forget to refcount it - see irlap_driver_rcv(). */
+ skb_get(skb);
self->notify.udata_indication(self->notify.instance, self,
skb);
- else
- dev_kfree_skb(skb);
+ }
}
#endif /* CONFIG_IRDA_ULTRA */
diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
index 0d976b6662c6..91f8ad67bc33 100644
--- a/net/irda/irlmp_event.c
+++ b/net/irda/irlmp_event.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -295,8 +295,6 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
__FUNCTION__, irlmp_event[event]);
- if (skb)
- dev_kfree_skb(skb);
break;
}
}
@@ -373,8 +371,6 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
__FUNCTION__, irlmp_event[event]);
- if (skb)
- dev_kfree_skb(skb);
break;
}
}
@@ -468,8 +464,6 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s\n",
__FUNCTION__, irlmp_event[event]);
- if (skb)
- dev_kfree_skb(skb);
break;
}
}
@@ -499,6 +493,9 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
switch (event) {
#ifdef CONFIG_IRDA_ULTRA
case LM_UDATA_INDICATION:
+ /* This is most bizzare. Those packets are aka unreliable
+ * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA.
+ * Why do we pass them as Ultra ??? Jean II */
irlmp_connless_data_indication(self, skb);
break;
#endif /* CONFIG_IRDA_ULTRA */
@@ -510,6 +507,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
__FUNCTION__);
return -EBUSY;
}
+ /* Don't forget to refcount it (see irlmp_connect_request()) */
+ skb_get(skb);
self->conn_skb = skb;
irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
@@ -525,6 +524,8 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
__FUNCTION__);
return -EBUSY;
}
+ /* Don't forget to refcount it (see irlap_driver_rcv()) */
+ skb_get(skb);
self->conn_skb = skb;
irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
@@ -547,8 +548,6 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel);
- if (skb)
- dev_kfree_skb(skb);
break;
}
return ret;
@@ -606,8 +605,6 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel);
- if (skb)
- dev_kfree_skb(skb);
break;
}
return ret;
@@ -622,6 +619,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
+ struct sk_buff *tx_skb;
int ret = 0;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
@@ -647,10 +645,12 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__);
irlmp_next_lsap_state(self, LSAP_CONNECT);
- skb = self->conn_skb;
+ tx_skb = self->conn_skb;
self->conn_skb = NULL;
- irlmp_connect_indication(self, skb);
+ irlmp_connect_indication(self, tx_skb);
+ /* Drop reference count - see irlmp_connect_indication(). */
+ dev_kfree_skb(tx_skb);
break;
case LM_WATCHDOG_TIMEOUT:
/* Will happen in some rare cases because of a race condition.
@@ -668,8 +668,6 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel);
- if (skb)
- dev_kfree_skb(skb);
break;
}
return ret;
@@ -759,8 +757,6 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel);
- if (skb)
- dev_kfree_skb(skb);
break;
}
return ret;
@@ -832,8 +828,6 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel);
- if (skb)
- dev_kfree_skb(skb);
break;
}
return ret;
@@ -850,6 +844,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
struct sk_buff *skb)
{
+ struct sk_buff *tx_skb;
LM_REASON reason;
int ret = 0;
@@ -862,11 +857,13 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
case LM_LAP_CONNECT_CONFIRM:
ASSERT(self->conn_skb != NULL, return -1;);
- skb = self->conn_skb;
+ tx_skb = self->conn_skb;
self->conn_skb = NULL;
irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
- self->slsap_sel, CONNECT_CMD, skb);
+ self->slsap_sel, CONNECT_CMD, tx_skb);
+ /* Drop reference count - see irlap_data_request(). */
+ dev_kfree_skb(tx_skb);
irlmp_next_lsap_state(self, LSAP_SETUP);
break;
@@ -891,8 +888,6 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
default:
IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
__FUNCTION__, irlmp_event[event], self->slsap_sel);
- if (skb)
- dev_kfree_skb(skb);
break;
}
return ret;
diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
index 616fd22f01d1..c00ccfd31022 100644
--- a/net/irda/irlmp_frame.c
+++ b/net/irda/irlmp_frame.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -144,7 +144,6 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
} else {
IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__);
}
- dev_kfree_skb(skb);
return;
}
@@ -168,16 +167,13 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
break;
case ACCESSMODE_CMD:
IRDA_DEBUG(0, "Access mode cmd not implemented!\n");
- dev_kfree_skb(skb);
break;
case ACCESSMODE_CNF:
IRDA_DEBUG(0, "Access mode cnf not implemented!\n");
- dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n",
__FUNCTION__, fp[2]);
- dev_kfree_skb(skb);
break;
}
} else if (unreliable) {
@@ -230,16 +226,12 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
if (pid & 0x80) {
IRDA_DEBUG(0, "%s(), extension in PID not supp!\n",
__FUNCTION__);
- dev_kfree_skb(skb);
-
return;
}
/* Check if frame is addressed to the connectionless LSAP */
if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__);
- dev_kfree_skb(skb);
-
return;
}
@@ -264,7 +256,6 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
irlmp_connless_data_indication(lsap, skb);
else {
IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__);
- dev_kfree_skb(skb);
}
}
#endif /* CONFIG_IRDA_ULTRA */
@@ -278,7 +269,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
void irlmp_link_disconnect_indication(struct lap_cb *lap,
struct irlap_cb *irlap,
LAP_REASON reason,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
@@ -288,9 +279,7 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap,
lap->reason = reason;
lap->daddr = DEV_ADDR_ANY;
- /* FIXME: must do something with the userdata if any */
- if (userdata)
- dev_kfree_skb(userdata);
+ /* FIXME: must do something with the skb if any */
/*
* Inform station state machine
@@ -327,7 +316,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
*
*/
void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
- struct sk_buff *userdata)
+ struct sk_buff *skb)
{
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
@@ -335,9 +324,7 @@ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
ASSERT(qos != NULL, return;);
- /* Don't need use the userdata for now */
- if (userdata)
- dev_kfree_skb(userdata);
+ /* Don't need use the skb for now */
/* Copy QoS settings for this session */
self->qos = qos;
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
index 37aa3d7e4b9f..0ed25a123047 100644
--- a/net/irda/irnet/irnet.h
+++ b/net/irda/irnet/irnet.h
@@ -229,6 +229,11 @@
* v14 - 20.2.03 - Jean II
* o Add discovery hint bits in the control channel.
* o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner
+ *
+ * v15 - 7.4.03 - Jean II
+ * o Replace spin_lock_irqsave() with spin_lock_bh() so that we can
+ * use ppp_unit_number(). It's probably also better overall...
+ * o Disable call to ppp_unregister_channel(), because we can't do it.
*/
/***************************** INCLUDES *****************************/
@@ -276,6 +281,7 @@
#undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */
#undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */
#undef PASS_CONNECT_PACKETS /* Not needed ? Safe */
+#undef MISSING_PPP_API /* Stuff I wish I could do */
/* PPP side of the business */
#define BLOCK_WHEN_CONNECT /* Block packets when connecting */
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
index 517b76e3281e..83966549d07f 100644
--- a/net/irda/irnet/irnet_irda.c
+++ b/net/irda/irnet/irnet_irda.c
@@ -31,7 +31,6 @@ irnet_post_event(irnet_socket * ap,
char * name,
__u16 hints)
{
- unsigned long flags; /* For spinlock */
int index; /* In the log */
DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n",
@@ -41,7 +40,7 @@ irnet_post_event(irnet_socket * ap,
* Note : as we are the only event producer, we only need to exclude
* ourself when touching the log, which is nice and easy.
*/
- spin_lock_irqsave(&irnet_events.spinlock, flags);
+ spin_lock_bh(&irnet_events.spinlock);
/* Copy the event in the log */
index = irnet_events.index;
@@ -69,7 +68,7 @@ irnet_post_event(irnet_socket * ap,
DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);
/* Spin lock end */
- spin_unlock_irqrestore(&irnet_events.spinlock, flags);
+ spin_unlock_bh(&irnet_events.spinlock);
/* Now : wake up everybody waiting for events... */
wake_up_interruptible_all(&irnet_events.rwait);
@@ -536,10 +535,9 @@ irda_irnet_connect(irnet_socket * self)
* Can't re-insert (MUST remove first) so check for that... */
if((irnet_server.running) && (self->q.q_next == NULL))
{
- unsigned long flags;
- spin_lock_irqsave(&irnet_server.spinlock, flags);
+ spin_lock_bh(&irnet_server.spinlock);
hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname);
- spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+ spin_unlock_bh(&irnet_server.spinlock);
DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname);
}
@@ -596,12 +594,11 @@ irda_irnet_destroy(irnet_socket * self)
if((irnet_server.running) && (self->q.q_next != NULL))
{
struct irnet_socket * entry;
- unsigned long flags;
DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n");
- spin_lock_irqsave(&irnet_server.spinlock, flags);
+ spin_lock_bh(&irnet_server.spinlock);
entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self);
self->q.q_next = NULL;
- spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+ spin_unlock_bh(&irnet_server.spinlock);
DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");
}
@@ -723,7 +720,6 @@ static inline irnet_socket *
irnet_find_socket(irnet_socket * self)
{
irnet_socket * new = (irnet_socket *) NULL;
- unsigned long flags;
int err;
DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);
@@ -736,7 +732,7 @@ irnet_find_socket(irnet_socket * self)
err = irnet_daddr_to_dname(self);
/* Protect access to the instance list */
- spin_lock_irqsave(&irnet_server.spinlock, flags);
+ spin_lock_bh(&irnet_server.spinlock);
/* So now, try to get an socket having specifically
* requested that nickname */
@@ -790,7 +786,7 @@ irnet_find_socket(irnet_socket * self)
}
/* Spin lock end */
- spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+ spin_unlock_bh(&irnet_server.spinlock);
DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new);
return new;
@@ -1135,10 +1131,15 @@ irnet_disconnect_indication(void * instance,
{
if(test_open)
{
+#ifdef MISSING_PPP_API
+ /* ppp_unregister_channel() wants a user context, which we
+ * are guaranteed to NOT have here. What are we supposed
+ * to do here ? Jean II */
/* If we were connected, cleanup & close the PPP channel,
* which will kill pppd (hangup) and the rest */
ppp_unregister_channel(&self->chan);
self->ppp_open = 0;
+#endif
}
else
{
@@ -1711,7 +1712,6 @@ irnet_proc_read(char * buf,
{
irnet_socket * self;
char * state;
- unsigned long flags;
int i = 0;
len = 0;
@@ -1728,7 +1728,7 @@ irnet_proc_read(char * buf,
return len;
/* Protect access to the instance list */
- spin_lock_irqsave(&irnet_server.spinlock, flags);
+ spin_lock_bh(&irnet_server.spinlock);
/* Get the sockets one by one... */
self = (irnet_socket *) hashbin_get_first(irnet_server.list);
@@ -1780,7 +1780,7 @@ irnet_proc_read(char * buf,
}
/* Spin lock end */
- spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+ spin_unlock_bh(&irnet_server.spinlock);
return len;
}
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index 6f5125b289cf..187871a4208a 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -927,7 +927,7 @@ ppp_irnet_send(struct ppp_channel * chan,
* Jean II
*/
DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret);
- dev_kfree_skb(skb);
+ /* irttp_data_request already free the packet */
}
DEXIT(PPP_TRACE, "\n");
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 5ddded65c67d..bb51edc7d99b 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -11,7 +11,7 @@
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
- * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -259,11 +259,17 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
dev_kfree_skb(frag);
}
- IRDA_DEBUG(2, "%s(), frame len=%d\n", __FUNCTION__, n);
- IRDA_DEBUG(2, "%s(), rx_sdu_size=%d\n", __FUNCTION__,
- self->rx_sdu_size);
- ASSERT(n <= self->rx_sdu_size, return NULL;);
+ IRDA_DEBUG(2,
+ "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
+ __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size);
+ /* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
+ * by summing the size of all fragments, so we should always
+ * have n == self->rx_sdu_size, except in cases where we
+ * droped the last fragment (when self->rx_sdu_size exceed
+ * self->rx_max_sdu_size), where n < self->rx_sdu_size.
+ * Jean II */
+ ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;);
/* Set the new length */
skb_trim(skb, n);
@@ -537,19 +543,23 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
if ((skb->len == 0) || (!self->connected)) {
IRDA_DEBUG(1, "%s(), No data, or not connected\n",
__FUNCTION__);
- return -1;
+ goto err;
}
if (skb->len > self->max_seg_size) {
IRDA_DEBUG(1, "%s(), UData is to large for IrLAP!\n",
__FUNCTION__);
- return -1;
+ goto err;
}
irlmp_udata_request(self->lsap, skb);
self->stats.tx_packets++;
return 0;
+
+err:
+ dev_kfree_skb(skb);
+ return -1;
}
/*
@@ -561,6 +571,7 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
{
__u8 *frame;
+ int ret;
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
@@ -572,7 +583,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
/* Check that nothing bad happens */
if ((skb->len == 0) || (!self->connected)) {
WARNING("%s: No data, or not connected\n", __FUNCTION__);
- return -ENOTCONN;
+ ret = -ENOTCONN;
+ goto err;
}
/*
@@ -582,7 +594,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
ERROR("%s: SAR disabled, and data is to large for IrLAP!\n",
__FUNCTION__);
- return -EMSGSIZE;
+ ret = -EMSGSIZE;
+ goto err;
}
/*
@@ -595,7 +608,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
{
ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
__FUNCTION__);
- return -EMSGSIZE;
+ ret = -EMSGSIZE;
+ goto err;
}
/*
* Check if transmit queue is full
@@ -607,8 +621,9 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
irttp_run_tx_queue(self);
/* Drop packet. This error code should trigger the caller
- * to requeue the packet in the client code - Jean II */
- return -ENOBUFS;
+ * to resend the data in the client code - Jean II */
+ ret = -ENOBUFS;
+ goto err;
}
/* Queue frame, or queue frame segments */
@@ -651,6 +666,10 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
irttp_run_tx_queue(self);
return 0;
+
+err:
+ dev_kfree_skb(skb);
+ return ret;
}
/*
@@ -822,6 +841,7 @@ static int irttp_udata_indication(void *instance, void *sap,
struct sk_buff *skb)
{
struct tsap_cb *self;
+ int err;
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
@@ -831,14 +851,19 @@ static int irttp_udata_indication(void *instance, void *sap,
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
ASSERT(skb != NULL, return -1;);
- /* Just pass data to layer above */
- if (self->notify.udata_indication)
- self->notify.udata_indication(self->notify.instance, self,skb);
- else
- dev_kfree_skb(skb);
-
self->stats.rx_packets++;
+ /* Just pass data to layer above */
+ if (self->notify.udata_indication) {
+ err = self->notify.udata_indication(self->notify.instance,
+ self,skb);
+ /* Same comment as in irttp_do_data_indication() */
+ if (err != -ENOMEM)
+ return 0;
+ }
+ /* Either no handler, or -ENOMEM */
+ dev_kfree_skb(skb);
+
return 0;
}
@@ -1040,7 +1065,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
struct qos_info *qos, __u32 max_sdu_size,
struct sk_buff *userdata)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
__u8 *frame;
__u8 n;
@@ -1049,19 +1074,22 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
ASSERT(self != NULL, return -EBADR;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
- if (self->connected)
+ if (self->connected) {
+ if(userdata)
+ dev_kfree_skb(userdata);
return -EISCONN;
+ }
/* Any userdata supplied? */
if (userdata == NULL) {
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return -ENOMEM;
/* Reserve space for MUX_CONTROL and LAP header */
- skb_reserve(skb, TTP_MAX_HEADER);
+ skb_reserve(tx_skb, TTP_MAX_HEADER);
} else {
- skb = userdata;
+ tx_skb = userdata;
/*
* Check that the client has reserved enough space for
* headers
@@ -1094,11 +1122,11 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
/* SAR enabled? */
if (max_sdu_size > 0) {
- ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
+ ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER),
return -1;);
/* Insert SAR parameters */
- frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
+ frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
frame[0] = TTP_PARAMETERS | n;
frame[1] = 0x04; /* Length */
@@ -1109,7 +1137,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
(__u16 *)(frame+4));
} else {
/* Insert plain TTP header */
- frame = skb_push(skb, TTP_HEADER);
+ frame = skb_push(tx_skb, TTP_HEADER);
/* Insert initial credit in frame */
frame[0] = n & 0x7f;
@@ -1117,7 +1145,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
/* Connect with IrLMP. No QoS parameters for now */
return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos,
- skb);
+ tx_skb);
}
/*
@@ -1201,7 +1229,8 @@ static void irttp_connect_confirm(void *instance, void *sap,
self->notify.connect_confirm(self->notify.instance, self, qos,
self->tx_max_sdu_size,
self->max_header_size, skb);
- }
+ } else
+ dev_kfree_skb(skb);
}
/*
@@ -1286,7 +1315,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
struct sk_buff *userdata)
{
- struct sk_buff *skb;
+ struct sk_buff *tx_skb;
__u8 *frame;
int ret;
__u8 n;
@@ -1299,19 +1328,19 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
/* Any userdata supplied? */
if (userdata == NULL) {
- skb = dev_alloc_skb(64);
- if (!skb)
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return -ENOMEM;
/* Reserve space for MUX_CONTROL and LAP header */
- skb_reserve(skb, TTP_MAX_HEADER);
+ skb_reserve(tx_skb, TTP_MAX_HEADER);
} else {
- skb = userdata;
+ tx_skb = userdata;
/*
* Check that the client has reserved enough space for
* headers
*/
- ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return -1;);
+ ASSERT(skb_headroom(tx_skb) >= TTP_MAX_HEADER, return -1;);
}
self->avail_credit = 0;
@@ -1333,11 +1362,11 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
/* SAR enabled? */
if (max_sdu_size > 0) {
- ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER),
+ ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER),
return -1;);
/* Insert TTP header with SAR parameters */
- frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
+ frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER);
frame[0] = TTP_PARAMETERS | n;
frame[1] = 0x04; /* Length */
@@ -1352,12 +1381,12 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
(__u16 *)(frame+4));
} else {
/* Insert TTP header */
- frame = skb_push(skb, TTP_HEADER);
+ frame = skb_push(tx_skb, TTP_HEADER);
frame[0] = n & 0x7f;
}
- ret = irlmp_connect_response(self->lsap, skb);
+ ret = irlmp_connect_response(self->lsap, tx_skb);
return ret;
}
@@ -1423,7 +1452,6 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
int priority)
{
- struct sk_buff *skb;
int ret;
ASSERT(self != NULL, return -1;);
@@ -1488,16 +1516,17 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
self->connected = FALSE;
if (!userdata) {
- skb = dev_alloc_skb(64);
- if (!skb)
+ struct sk_buff *tx_skb;
+ tx_skb = dev_alloc_skb(64);
+ if (!tx_skb)
return -ENOMEM;
/*
* Reserve space for MUX and LAP header
*/
- skb_reserve(skb, TTP_MAX_HEADER);
+ skb_reserve(tx_skb, TTP_MAX_HEADER);
- userdata = skb;
+ userdata = tx_skb;
}
ret = irlmp_disconnect_request(self->lsap, userdata);
@@ -1556,7 +1585,7 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
/*
* Function irttp_do_data_indication (self, skb)
*
- * Try to deliver reassebled skb to layer above, and requeue it if that
+ * Try to deliver reassembled skb to layer above, and requeue it if that
* for some reason should fail. We mark rx sdu as busy to apply back
* pressure is necessary.
*/
diff --git a/net/socket.c b/net/socket.c
index 4d62ac970ca6..76d29acb146a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -325,7 +325,7 @@ static struct super_operations sockfs_ops = {
};
static struct super_block *sockfs_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC);
}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 768d5b373fd2..abcb5ee4b890 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -749,7 +749,7 @@ out:
static struct super_block *
rpc_get_sb(struct file_system_type *fs_type,
- int flags, char *dev_name, void *data)
+ int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, rpc_fill_super);
}
diff --git a/sound/core/control.c b/sound/core/control.c
index c01a2ce81cd3..14541cd122f5 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -222,7 +222,7 @@ snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data)
kctl.id.device = ncontrol->device;
kctl.id.subdevice = ncontrol->subdevice;
if (ncontrol->name)
- strncpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name)-1);
+ strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
kctl.id.index = ncontrol->index;
kctl.count = ncontrol->count ? ncontrol->count : 1;
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
@@ -449,12 +449,12 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
memset(&info, 0, sizeof(info));
down_read(&snd_ioctl_rwsem);
info.card = card->number;
- strncpy(info.id, card->id, sizeof(info.id) - 1);
- strncpy(info.driver, card->driver, sizeof(info.driver) - 1);
- strncpy(info.name, card->shortname, sizeof(info.name) - 1);
- strncpy(info.longname, card->longname, sizeof(info.longname) - 1);
- strncpy(info.mixername, card->mixername, sizeof(info.mixername) - 1);
- strncpy(info.components, card->components, sizeof(info.components) - 1);
+ strlcpy(info.id, card->id, sizeof(info.id));
+ strlcpy(info.driver, card->driver, sizeof(info.driver));
+ strlcpy(info.name, card->shortname, sizeof(info.name));
+ strlcpy(info.longname, card->longname, sizeof(info.longname));
+ strlcpy(info.mixername, card->mixername, sizeof(info.mixername));
+ strlcpy(info.components, card->components, sizeof(info.components));
up_read(&snd_ioctl_rwsem);
if (copy_to_user((void *) arg, &info, sizeof(snd_ctl_card_info_t)))
return -EFAULT;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 2f9dbfaffdf8..94f7feffabed 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -169,8 +169,8 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t *_info)
memset(&info, 0, sizeof(info));
info.card = hw->card->number;
- strncpy(info.id, hw->id, sizeof(info.id) - 1);
- strncpy(info.name, hw->name, sizeof(info.name) - 1);
+ strlcpy(info.id, hw->id, sizeof(info.id));
+ strlcpy(info.name, hw->name, sizeof(info.name));
info.iface = hw->iface;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@@ -343,7 +343,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep
hwdep->card = card;
hwdep->device = device;
if (id) {
- strncpy(hwdep->id, id, sizeof(hwdep->id) - 1);
+ strlcpy(hwdep->id, id, sizeof(hwdep->id));
}
#ifdef CONFIG_SND_OSSEMUL
hwdep->oss_type = -1;
diff --git a/sound/core/init.c b/sound/core/init.c
index 5a45b82f4993..e34e8480f1c7 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -76,7 +76,7 @@ snd_card_t *snd_card_new(int idx, const char *xid,
if (xid) {
if (!snd_info_check_reserved_words(xid))
goto __error;
- strncpy(card->id, xid, sizeof(card->id) - 1);
+ strlcpy(card->id, xid, sizeof(card->id));
}
write_lock(&snd_card_rwlock);
if (idx < 0) {
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index c01b1fffad65..cd1dd357d292 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -85,8 +85,8 @@ static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer,
struct mixer_info info;
memset(&info, 0, sizeof(info));
- strncpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id) - 1);
- strncpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name) - 1);
+ strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
+ strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
info.modify_counter = card->mixer_oss_change_count;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@@ -101,8 +101,8 @@ static int snd_mixer_oss_info_obsolete(snd_mixer_oss_file_t *fmixer,
_old_mixer_info info;
memset(&info, 0, sizeof(info));
- strncpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id) - 1);
- strncpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name) - 1);
+ strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
+ strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
return 0;
@@ -1215,11 +1215,10 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd)
}
mixer->oss_dev_alloc = 1;
mixer->card = card;
- if (*card->mixername) {
- strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1);
- mixer->name[sizeof(mixer->name)-1] = 0;
- } else
- strcpy(mixer->name, name);
+ if (*card->mixername)
+ strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
+ else
+ strlcpy(mixer->name, name, sizeof(mixer->name));
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
card->number,
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 427e6f5de9d1..a494f3c1eb62 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -639,7 +639,7 @@ int snd_pcm_new(snd_card_t * card, char *id, int device,
pcm->card = card;
pcm->device = device;
if (id) {
- strncpy(pcm->id, id, sizeof(pcm->id) - 1);
+ strlcpy(pcm->id, id, sizeof(pcm->id));
}
if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
snd_pcm_free(pcm);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 4b3fab10f1e5..c1f9a5041aa9 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -92,13 +92,13 @@ int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info)
info->device = pcm->device;
info->stream = substream->stream;
info->subdevice = substream->number;
- strncpy(info->id, pcm->id, sizeof(info->id)-1);
- strncpy(info->name, pcm->name, sizeof(info->name)-1);
+ strlcpy(info->id, pcm->id, sizeof(info->id));
+ strlcpy(info->name, pcm->name, sizeof(info->name));
info->dev_class = pcm->dev_class;
info->dev_subclass = pcm->dev_subclass;
info->subdevices_count = pstr->substream_count;
info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
- strncpy(info->subname, substream->name, sizeof(info->subname)-1);
+ strlcpy(info->subname, substream->name, sizeof(info->subname));
runtime = substream->runtime;
/* AB: FIXME!!! This is definitely nonsense */
if (runtime) {
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 8285d83f4b0f..7071db966506 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -1394,7 +1394,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device,
init_MUTEX(&rmidi->open_mutex);
init_waitqueue_head(&rmidi->open_wait);
if (id != NULL)
- strncpy(rmidi->id, id, sizeof(rmidi->id) - 1);
+ strlcpy(rmidi->id, id, sizeof(rmidi->id));
if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count)) < 0) {
snd_rawmidi_free(rmidi);
return err;
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 599d0c71d3b4..17d8712cf4a9 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -184,8 +184,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
snd_use_lock_init(&mdev->use_lock);
/* copy and truncate the name of synth device */
- strncpy(mdev->name, pinfo->name, sizeof(mdev->name));
- mdev->name[sizeof(mdev->name) - 1] = 0;
+ strlcpy(mdev->name, pinfo->name, sizeof(mdev->name));
/* create MIDI coder */
if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
@@ -659,7 +658,7 @@ snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf
inf->device = dev;
inf->dev_type = 0; /* FIXME: ?? */
inf->capabilities = 0; /* FIXME: ?? */
- strncpy(inf->name, mdev->name, sizeof(inf->name));
+ strlcpy(inf->name, mdev->name, sizeof(inf->name));
snd_use_lock_free(&mdev->use_lock);
return 0;
}
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index a8bc4a7b999d..bbc7cb8dda11 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -117,8 +117,7 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev)
snd_use_lock_init(&rec->use_lock);
/* copy and truncate the name of synth device */
- strncpy(rec->name, dev->name, sizeof(rec->name));
- rec->name[sizeof(rec->name)-1] = 0;
+ strlcpy(rec->name, dev->name, sizeof(rec->name));
/* registration */
spin_lock_irqsave(&register_lock, flags);
@@ -611,7 +610,7 @@ snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *i
inf->synth_subtype = 0;
inf->nr_voices = 16;
inf->device = dev;
- strncpy(inf->name, minf.name, sizeof(inf->name));
+ strlcpy(inf->name, minf.name, sizeof(inf->name));
} else {
if ((rec = get_synthdev(dp, dev)) == NULL)
return -ENXIO;
@@ -619,7 +618,7 @@ snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *i
inf->synth_subtype = rec->synth_subtype;
inf->nr_voices = rec->nr_voices;
inf->device = dev;
- strncpy(inf->name, rec->name, sizeof(inf->name));
+ strlcpy(inf->name, rec->name, sizeof(inf->name));
snd_use_lock_free(&rec->use_lock);
}
return 0;
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 6be15ff87c7b..7f39dfc9d2cb 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1184,10 +1184,9 @@ static int snd_seq_ioctl_set_client_info(client_t * client, void __user *arg)
return -EINVAL;
/* fill the info fields */
- if (client_info.name[0]) {
- strncpy(client->name, client_info.name, sizeof(client->name)-1);
- client->name[sizeof(client->name)-1] = '\0';
- }
+ if (client_info.name[0])
+ strlcpy(client->name, client_info.name, sizeof(client->name));
+
client->filter = client_info.filter;
client->event_lost = client_info.event_lost;
memcpy(client->event_filter, client_info.event_filter, 32);
@@ -1487,9 +1486,8 @@ static int snd_seq_ioctl_create_queue(client_t *client, void __user *arg)
/* set queue name */
if (! info.name[0])
- sprintf(info.name, "Queue-%d", q->queue);
- strncpy(q->name, info.name, sizeof(q->name)-1);
- q->name[sizeof(q->name)-1] = 0;
+ snprintf(info.name, sizeof(info.name), "Queue-%d", q->queue);
+ strlcpy(q->name, info.name, sizeof(q->name));
queuefree(q);
if (copy_to_user(arg, &info, sizeof(info)))
@@ -1526,8 +1524,7 @@ static int snd_seq_ioctl_get_queue_info(client_t *client, void __user *arg)
info.queue = q->queue;
info.owner = q->owner;
info.locked = q->locked;
- strncpy(info.name, q->name, sizeof(info.name) - 1);
- info.name[sizeof(info.name)-1] = 0;
+ strlcpy(info.name, q->name, sizeof(info.name));
queuefree(q);
if (copy_to_user(arg, &info, sizeof(info)))
@@ -1565,8 +1562,7 @@ static int snd_seq_ioctl_set_queue_info(client_t *client, void __user *arg)
queuefree(q);
return -EPERM;
}
- strncpy(q->name, info.name, sizeof(q->name) - 1);
- q->name[sizeof(q->name)-1] = 0;
+ strlcpy(q->name, info.name, sizeof(q->name));
queuefree(q);
return 0;
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 64ccb69b4865..297f918522e8 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -187,8 +187,7 @@ int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize,
/* set up device info */
dev->card = card;
dev->device = device;
- strncpy(dev->id, id, sizeof(dev->id) - 1);
- dev->id[sizeof(dev->id) - 1] = 0;
+ strlcpy(dev->id, id, sizeof(dev->id));
dev->argsize = argsize;
dev->status = SNDRV_SEQ_DEVICE_FREE;
@@ -350,8 +349,7 @@ static ops_list_t * create_driver(char *id)
memset(ops, 0, sizeof(*ops));
/* set up driver entry */
- strncpy(ops->id, id, sizeof(ops->id) - 1);
- ops->id[sizeof(ops->id) - 1] = 0;
+ strlcpy(ops->id, id, sizeof(ops->id));
init_MUTEX(&ops->reg_mutex);
ops->driver = DRIVER_EMPTY;
INIT_LIST_HEAD(&ops->dev_list);
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
index 97e5b740816d..d8ca16f6f293 100644
--- a/sound/core/seq/seq_instr.c
+++ b/sound/core/seq/seq_instr.c
@@ -478,8 +478,7 @@ static int instr_put(snd_seq_kinstr_ops_t *ops,
}
instr->ops = ops;
instr->instr = put.id.instr;
- strncpy(instr->name, put.data.name, sizeof(instr->name)-1);
- instr->name[sizeof(instr->name)-1] = '\0';
+ strlcpy(instr->name, put.data.name, sizeof(instr->name));
instr->type = put.data.type;
if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) {
result = ops->put(ops->private_data,
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 2988ba6c5691..9167e164d592 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -338,10 +338,8 @@ int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info)
snd_assert(port && info, return -EINVAL);
/* set port name */
- if (info->name[0]) {
- strncpy(port->name, info->name, sizeof(port->name)-1);
- port->name[sizeof(port->name)-1] = '\0';
- }
+ if (info->name[0])
+ strlcpy(port->name, info->name, sizeof(port->name));
/* set capabilities */
port->capability = info->capability;
@@ -363,7 +361,7 @@ int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info)
snd_assert(port && info, return -EINVAL);
/* get port name */
- strncpy(info->name, port->name, sizeof(info->name));
+ strlcpy(info->name, port->name, sizeof(info->name));
/* get capabilities */
info->capability = port->capability;
@@ -621,10 +619,8 @@ int snd_seq_event_port_attach(int client,
/* Set up the port */
memset(&portinfo, 0, sizeof(portinfo));
portinfo.addr.client = client;
- if (portname)
- strncpy(portinfo.name, portname, sizeof(portinfo.name));
- else
- sprintf(portinfo.name, "Unamed port");
+ strlcpy(portinfo.name, portname ? portname : "Unamed port",
+ sizeof(portinfo.name));
portinfo.capability = cap;
portinfo.type = type;
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index b16f02b0026c..e81f8fcfd6f6 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -241,7 +241,7 @@ queue_t *snd_seq_queue_find_name(char *name)
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) != NULL) {
- if (strncpy(q->name, name, sizeof(q->name)) == 0)
+ if (strncmp(q->name, name, sizeof(q->name)) == 0)
return q;
queuefree(q);
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index c426c77e45c3..1a2f9285ccdb 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -749,7 +749,7 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t *
timer->tmr_device = tid->device;
timer->tmr_subdevice = tid->subdevice;
if (id)
- strncpy(timer->id, id, sizeof(timer->id) - 1);
+ strlcpy(timer->id, id, sizeof(timer->id));
INIT_LIST_HEAD(&timer->device_list);
INIT_LIST_HEAD(&timer->open_list_head);
INIT_LIST_HEAD(&timer->active_list_head);
@@ -1317,8 +1317,8 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo)
ginfo.card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
ginfo.flags |= SNDRV_TIMER_FLG_SLAVE;
- strncpy(ginfo.id, t->id, sizeof(ginfo.id)-1);
- strncpy(ginfo.name, t->name, sizeof(ginfo.name)-1);
+ strlcpy(ginfo.id, t->id, sizeof(ginfo.id));
+ strlcpy(ginfo.name, t->name, sizeof(ginfo.name));
ginfo.resolution = t->hw.resolution;
if (t->hw.resolution_min > 0) {
ginfo.resolution_min = t->hw.resolution_min;
@@ -1457,8 +1457,8 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info)
info.card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
info.flags |= SNDRV_TIMER_FLG_SLAVE;
- strncpy(info.id, t->id, sizeof(info.id)-1);
- strncpy(info.name, t->name, sizeof(info.name)-1);
+ strlcpy(info.id, t->id, sizeof(info.id));
+ strlcpy(info.name, t->name, sizeof(info.name));
info.resolution = t->hw.resolution;
if (copy_to_user(_info, &info, sizeof(*_info)))
return -EFAULT;
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 80c6545d72fd..5504605adc74 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -123,8 +123,7 @@ void snd_opl3_init_seq_oss(opl3_t *opl3, char *name)
return;
opl3->oss_seq_dev = dev;
- strncpy(dev->name, name, sizeof(dev->name) - 1);
- dev->name[sizeof(dev->name) - 1] = 0;
+ strlcpy(dev->name, name, sizeof(dev->name));
arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
arg->type = SYNTH_TYPE_FM;
if (opl3->hardware < OPL3_HW_OPL3) {
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index 5015a8bc8c0d..cdb9c74adc5c 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -93,7 +93,7 @@ int snd_i2c_bus_create(snd_card_t *card, const char *name, snd_i2c_bus_t *master
list_add_tail(&bus->buses, &master->buses);
bus->master = master;
}
- strncpy(bus->name, name, sizeof(bus->name) - 1);
+ strlcpy(bus->name, name, sizeof(bus->name));
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, bus, &ops)) < 0) {
snd_i2c_bus_free(bus);
return err;
@@ -112,7 +112,7 @@ int snd_i2c_device_create(snd_i2c_bus_t *bus, const char *name, unsigned char ad
if (device == NULL)
return -ENOMEM;
device->addr = addr;
- strncpy(device->name, name, sizeof(device->name)-1);
+ strlcpy(device->name, name, sizeof(device->name));
list_add_tail(&device->list, &bus->devices);
device->bus = bus;
*rdevice = device;
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 1ea965fbc635..125fd3507ce5 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -1148,7 +1148,7 @@ int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, un
ctl = snd_ctl_new1(&newctls[type], chip);
if (! ctl)
return -ENOMEM;
- strncpy(ctl->id.name, name, sizeof(ctl->id.name)-1);
+ strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
ctl->id.index = index;
ctl->private_value = value;
if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 8ea3dae9d802..524e43db882a 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -393,8 +393,7 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t * mcode
return err;
/* fill in codec header */
- strncpy(p->codec_name, info.codec_name, sizeof(p->codec_name) - 1);
- p->codec_name[sizeof(p->codec_name) - 1] = 0;
+ strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name));
p->func_nr = func_nr;
p->mode = LE_SHORT(funcdesc_h.flags_play_rec);
switch (LE_SHORT(funcdesc_h.VOC_type)) {
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index b5532d9e19da..31baf2030e26 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -452,7 +452,7 @@ int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsig
ctl = snd_ctl_new1(&newctls[type], chip);
if (! ctl)
return -ENOMEM;
- strncpy(ctl->id.name, name, sizeof(ctl->id.name)-1);
+ strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
ctl->id.index = index;
ctl->private_value = value;
if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index 7eaad4f5c9ce..be1820ea876f 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -487,8 +487,8 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, codec->name, sizeof(info.id));
- strncpy(info.name, codec->name, sizeof(info.name));
+ strlcpy(info.id, codec->name, sizeof(info.id));
+ strlcpy(info.name, codec->name, sizeof(info.name));
info.modify_counter = codec->modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -496,8 +496,8 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, codec->name, sizeof(info.id));
- strncpy(info.name, codec->name, sizeof(info.name));
+ strlcpy(info.id, codec->name, sizeof(info.id));
+ strlcpy(info.name, codec->name, sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
index 0585b44d67b5..22e3b6cfd817 100644
--- a/sound/oss/btaudio.c
+++ b/sound/oss/btaudio.c
@@ -328,8 +328,8 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
memset(&info,0,sizeof(info));
- strncpy(info.id,"bt878",sizeof(info.id)-1);
- strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1);
+ strlcpy(info.id,"bt878",sizeof(info.id));
+ strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
info.modify_counter = bta->mixcount;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -338,8 +338,8 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
memset(&info,0,sizeof(info));
- strncpy(info.id,"bt878",sizeof(info.id)-1);
- strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1);
+ strlcpy(info.id,"bt878",sizeof(info.id)-1);
+ strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
index 967b6521b803..f9d784231635 100644
--- a/sound/oss/cmpci.c
+++ b/sound/oss/cmpci.c
@@ -1268,8 +1268,8 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
VALIDATE_STATE(s);
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, "cmpci", sizeof(info.id));
- strncpy(info.name, "C-Media PCI", sizeof(info.name));
+ strlcpy(info.id, "cmpci", sizeof(info.id));
+ strlcpy(info.name, "C-Media PCI", sizeof(info.name));
info.modify_counter = s->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -1277,8 +1277,8 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, "cmpci", sizeof(info.id));
- strncpy(info.name, "C-Media cmpci", sizeof(info.name));
+ strlcpy(info.id, "cmpci", sizeof(info.id));
+ strlcpy(info.name, "C-Media cmpci", sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
index 5757af590054..3d23a8006f97 100644
--- a/sound/oss/cs4281/cs4281m.c
+++ b/sound/oss/cs4281/cs4281m.c
@@ -2266,8 +2266,8 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
}
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, "CS4281", sizeof(info.id));
- strncpy(info.name, "Crystal CS4281", sizeof(info.name));
+ strlcpy(info.id, "CS4281", sizeof(info.id));
+ strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
info.modify_counter = s->mix.modcnt;
if (copy_to_user((void *) arg, &info, sizeof(info)))
return -EFAULT;
@@ -2275,8 +2275,8 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, "CS4281", sizeof(info.id));
- strncpy(info.name, "Crystal CS4281", sizeof(info.name));
+ strlcpy(info.id, "CS4281", sizeof(info.id));
+ strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
if (copy_to_user((void *) arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
index 96e8fd9eef17..4658e62d24ca 100644
--- a/sound/oss/dev_table.c
+++ b/sound/oss/dev_table.c
@@ -22,7 +22,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
{
struct audio_driver *d;
struct audio_operations *op;
- int l, num;
+ int num;
if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
@@ -58,11 +58,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
memcpy((char *) d, (char *) driver, driver_size);
op->d = d;
- l = strlen(name) + 1;
- if (l > sizeof(op->name))
- l = sizeof(op->name);
- strncpy(op->name, name, l);
- op->name[l - 1] = 0;
+ strlcpy(op->name, name, sizeof(op->name));
op->flags = flags;
op->format_mask = format_mask;
op->devc = devc;
@@ -82,7 +78,6 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
int driver_size, void *devc)
{
struct mixer_operations *op;
- int l;
int n = sound_alloc_mixerdev();
@@ -110,11 +105,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
memset((char *) op, 0, sizeof(struct mixer_operations));
memcpy((char *) op, (char *) driver, driver_size);
- l = strlen(name) + 1;
- if (l > sizeof(op->name))
- l = sizeof(op->name);
- strncpy(op->name, name, l);
- op->name[l - 1] = 0;
+ strlcpy(op->name, name, sizeof(op->name));
op->devc = devc;
mixer_devs[n] = op;
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 98627ddea56f..069bd881589c 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -351,9 +351,8 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
case SOUND_MIXER_INFO:
{
mixer_info info;
- strncpy(info.id, dmasound.mach.name2, sizeof(info.id));
- strncpy(info.name, dmasound.mach.name2, sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
+ strlcpy(info.id, dmasound.mach.name2, sizeof(info.id));
+ strlcpy(info.name, dmasound.mach.name2, sizeof(info.name));
info.modify_counter = mixer.modify_counter;
if (copy_to_user((int *)arg, &info, sizeof(info)))
return -EFAULT;
diff --git a/sound/oss/emu10k1/mixer.c b/sound/oss/emu10k1/mixer.c
index 6ca3b79430a1..d61778e096d3 100644
--- a/sound/oss/emu10k1/mixer.c
+++ b/sound/oss/emu10k1/mixer.c
@@ -623,8 +623,8 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, card->ac97.name, sizeof(info.id));
- strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
+ strlcpy(info.id, card->ac97.name, sizeof(info.id));
+ strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
info.modify_counter = card->ac97.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
index 6f9aef48f5ba..835d2170e8c9 100644
--- a/sound/oss/es1370.c
+++ b/sound/oss/es1370.c
@@ -889,8 +889,8 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
}
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, "ES1370", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
+ strlcpy(info.id, "ES1370", sizeof(info.id));
+ strlcpy(info.name, "Ensoniq ES1370", sizeof(info.name));
info.modify_counter = s->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -898,8 +898,8 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, "ES1370", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
+ strlcpy(info.id, "ES1370", sizeof(info.id));
+ strlcpy(info.name, "Ensoniq ES1370", sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
index 78a6adad3d7d..d78a4dd797a4 100644
--- a/sound/oss/esssolo1.c
+++ b/sound/oss/esssolo1.c
@@ -721,8 +721,8 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
}
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, "Solo1", sizeof(info.id));
- strncpy(info.name, "ESS Solo1", sizeof(info.name));
+ strlcpy(info.id, "Solo1", sizeof(info.id));
+ strlcpy(info.name, "ESS Solo1", sizeof(info.name));
info.modify_counter = s->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -730,8 +730,8 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, "Solo1", sizeof(info.id));
- strncpy(info.name, "ESS Solo1", sizeof(info.name));
+ strlcpy(info.id, "Solo1", sizeof(info.id));
+ strlcpy(info.name, "ESS Solo1", sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
index 722e48137967..8be49423b6d9 100644
--- a/sound/oss/gus_wave.c
+++ b/sound/oss/gus_wave.c
@@ -2851,7 +2851,7 @@ void __init gus_wave_init(struct address_info *hw_config)
unsigned long flags;
unsigned char val;
char *model_num = "2.4";
- char tmp[64], tmp2[64];
+ char tmp[64];
int gus_type = 0x24; /* 2.4 */
int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
@@ -2998,19 +2998,14 @@ void __init gus_wave_init(struct address_info *hw_config)
}
if (hw_config->name)
- {
- strncpy(tmp, hw_config->name, 45);
- tmp[45] = 0;
- sprintf(tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
- tmp2[sizeof(tmp2) - 1] = 0;
- }
+ snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name,
+ (int) gus_mem_size / 1024);
else if (gus_pnp_flag)
- {
- sprintf(tmp2, "Gravis UltraSound PnP (%dk)",
- (int) gus_mem_size / 1024);
- }
+ snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)",
+ (int) gus_mem_size / 1024);
else
- sprintf(tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num,
+ (int) gus_mem_size / 1024);
samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
@@ -3019,9 +3014,8 @@ void __init gus_wave_init(struct address_info *hw_config)
printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
return;
}
- conf_printf(tmp2, hw_config);
- tmp2[sizeof(gus_info.name) - 1] = 0;
- strcpy(gus_info.name, tmp2);
+ conf_printf(tmp, hw_config);
+ strlcpy(gus_info.name, tmp, sizeof(gus_info.name));
if ((sdev = sound_alloc_synthdev()) == -1)
printk(KERN_WARNING "gus_init: Too many synthesizers\n");
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
index 013b70187245..f62ad9be51e9 100644
--- a/sound/oss/maestro.c
+++ b/sound/oss/maestro.c
@@ -2024,8 +2024,8 @@ static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long ar
VALIDATE_CARD(card);
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, card_names[card->card_type], sizeof(info.id));
- strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+ strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
+ strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
info.modify_counter = card->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -2033,8 +2033,8 @@ static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long ar
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, card_names[card->card_type], sizeof(info.id));
- strncpy(info.name,card_names[card->card_type],sizeof(info.name));
+ strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
+ strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index 760a617ec17a..25977734cc6a 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -555,8 +555,8 @@ static unsigned long force_recsrc(unsigned long recsrc)
}
#define set_mixer_info() \
- strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \
- strncpy(info.name, "MultiSound Mixer", sizeof(info.name));
+ strlcpy(info.id, "MSNDMIXER", sizeof(info.id)); \
+ strlcpy(info.name, "MultiSound Mixer", sizeof(info.name));
static int mixer_ioctl(unsigned int cmd, unsigned long arg)
{
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 8a2f0055f1ac..d2031bc12434 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -1477,7 +1477,7 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg)
if (!(synth_open_mask & (1 << dev)) && !orig_dev)
return -EBUSY;
memcpy(&inf, synth_devs[dev]->info, sizeof(inf));
- strncpy(inf.name, synth_devs[dev]->id, sizeof(inf.name));
+ strlcpy(inf.name, synth_devs[dev]->id, sizeof(inf.name));
inf.device = dev;
return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0;
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
index 975e1c42ed78..5c042a70dda1 100644
--- a/sound/oss/sonicvibes.c
+++ b/sound/oss/sonicvibes.c
@@ -1046,8 +1046,8 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
VALIDATE_STATE(s);
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, "SonicVibes", sizeof(info.id));
- strncpy(info.name, "S3 SonicVibes", sizeof(info.name));
+ strlcpy(info.id, "SonicVibes", sizeof(info.id));
+ strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
info.modify_counter = s->mix.modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -1055,8 +1055,8 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
}
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
- strncpy(info.id, "SonicVibes", sizeof(info.id));
- strncpy(info.name, "S3 SonicVibes", sizeof(info.name));
+ strlcpy(info.id, "SonicVibes", sizeof(info.id));
+ strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 220a5faa8d70..087f1af7c7e5 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -289,9 +289,8 @@ static int get_mixer_info(int dev, caddr_t arg)
{
mixer_info info;
- strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id));
- strncpy(info.name, mixer_devs[dev]->name, sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
+ strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id));
+ strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name));
info.modify_counter = mixer_devs[dev]->modify_counter;
if (__copy_to_user(arg, &info, sizeof(info)))
return -EFAULT;
@@ -302,9 +301,8 @@ static int get_old_mixer_info(int dev, caddr_t arg)
{
_old_mixer_info info;
- strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id));
- strncpy(info.name, mixer_devs[dev]->name, sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
+ strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id));
+ strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name));
if (copy_to_user(arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 02e2ec335502..9dcc09318548 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1033,7 +1033,7 @@ static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod
memset(&gctl, 0, sizeof(gctl));
id = &ctl->kcontrol->id;
gctl.id.iface = id->iface;
- strncpy(gctl.id.name, id->name, sizeof(gctl.id.name));
+ strlcpy(gctl.id.name, id->name, sizeof(gctl.id.name));
gctl.id.index = id->index;
gctl.id.device = id->device;
gctl.id.subdevice = id->subdevice;
@@ -1063,8 +1063,7 @@ static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
down(&emu->fx8010.lock);
if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
goto __error;
- strncpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)-1);
- emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0';
+ strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
/* stop FX processor - this may be dangerous, but it's better to miss
some samples than generate wrong ones - [jk] */
if (emu->audigy)
@@ -1092,8 +1091,7 @@ static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
int err;
down(&emu->fx8010.lock);
- strncpy(icode->name, emu->fx8010.name, sizeof(icode->name)-1);
- emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0';
+ strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
/* ok, do the main job */
snd_emu10k1_gpr_peek(emu, icode);
snd_emu10k1_tram_peek(emu, icode);
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index c8d3b928e108..47772eb33250 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2392,8 +2392,7 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
len = 0;
if (len <= 0) {
if (quirk && quirk->product_name) {
- strncpy(card->shortname, quirk->product_name, sizeof(card->shortname) - 1);
- card->shortname[sizeof(card->shortname) - 1] = '\0';
+ strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname));
} else {
sprintf(card->shortname, "USB Device %#04x:%#04x",
dev->descriptor.idVendor, dev->descriptor.idProduct);
@@ -2403,37 +2402,32 @@ static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
/* retrieve the vendor and device strings as longname */
if (dev->descriptor.iManufacturer)
len = usb_string(dev, dev->descriptor.iManufacturer,
- card->longname, sizeof(card->longname) - 1);
+ card->longname, sizeof(card->longname));
else
len = 0;
if (len <= 0) {
if (quirk && quirk->vendor_name) {
- strncpy(card->longname, quirk->vendor_name, sizeof(card->longname) - 2);
- card->longname[sizeof(card->longname) - 2] = '\0';
- len = strlen(card->longname);
+ len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname));
} else {
len = 0;
}
}
- if (len > 0) {
- card->longname[len] = ' ';
- len++;
- }
- card->longname[len] = '\0';
+ if (len > 0)
+ strlcat(card->longname, ' ', sizeof(card->longname));
+
+ len = strlen(card->longname);
+
if ((!dev->descriptor.iProduct
|| usb_string(dev, dev->descriptor.iProduct,
card->longname + len, sizeof(card->longname) - len) <= 0)
&& quirk && quirk->product_name) {
- strncpy(card->longname + len, quirk->product_name, sizeof(card->longname) - len - 1);
- card->longname[sizeof(card->longname) - 1] = '\0';
+ strlcat(card->longname, quirk->product_name, sizeof(card->longname));
}
- /* add device path to longname */
- len = strlen(card->longname);
- if (sizeof(card->longname) - len > 10) {
- strcpy(card->longname + len, " at ");
- len += 4;
+
+ len = strlcat(card->longname, " at ", sizeof(card->longname));
+
+ if (len < sizeof(card->longname))
usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
- }
*rchip = chip;
return 0;
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index c9a5b382bda5..b5b04447f499 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -164,9 +164,7 @@ static int check_mapped_name(mixer_build_t *state, int unitid, int control, char
if (p->id == unitid &&
(! control || ! p->control || control == p->control)) {
buflen--;
- strncpy(buf, p->name, buflen);
- buf[buflen] = 0;
- return strlen(buf);
+ return strlcpy(buf, p->name, buflen);
}
}
return 0;
@@ -816,7 +814,8 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
if (! len)
len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1);
if (! len)
- len = sprintf(kctl->id.name, "Feature %d", unitid);
+ len = snprintf(kctl->id.name, sizeof(kctl->id.name),
+ "Feature %d", unitid);
}
/* determine the stream direction:
* if the connected output is USB stream, then it's likely a
@@ -824,24 +823,19 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
*/
if (! mapped_name && ! (state->oterm.type >> 16)) {
if ((state->oterm.type & 0xff00) == 0x0100) {
- if (len + 8 < sizeof(kctl->id.name)) {
- strcpy(kctl->id.name + len, " Capture");
- len += 8;
- }
+ len = strlcat(kctl->id.name, " Capture", sizeof(kctl->id.name));
} else {
- if (len + 9 < sizeof(kctl->id.name)) {
- strcpy(kctl->id.name + len, " Playback");
- len += 9;
- }
+ len = strlcat(kctl->id.name + len, " Playback", sizeof(kctl->id.name));
}
}
- if (len + 7 < sizeof(kctl->id.name))
- strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume");
+ strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume",
+ sizeof(kctl->id.name));
break;
default:
if (! len)
- strcpy(kctl->id.name, audio_feature_info[control-1].name);
+ strlcpy(kctl->id.name, audio_feature_info[control-1].name,
+ sizeof(kctl->id.name));
break;
}
@@ -969,8 +963,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0);
if (! len)
len = sprintf(kctl->id.name, "Mixer Source %d", in_ch);
- if (len + 7 < sizeof(kctl->id.name))
- strcpy(kctl->id.name + len, " Volume");
+ strlcat(kctl->id.name + len, " Volume", sizeof(kctl->id.name));
snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
@@ -1189,22 +1182,18 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char
if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name)))
;
else if (info->name)
- strcpy(kctl->id.name, info->name);
+ strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
else {
nameid = dsc[12 + num_ins + dsc[11 + num_ins]];
len = 0;
if (nameid)
len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
- if (! len) {
- strncpy(kctl->id.name, name, sizeof(kctl->id.name) - 1);
- kctl->id.name[sizeof(kctl->id.name)-1] = 0;
- }
- }
- len = strlen(kctl->id.name);
- if (len + sizeof(valinfo->suffix) + 1 < sizeof(kctl->id.name)) {
- kctl->id.name[len] = ' ';
- strcpy(kctl->id.name + len + 1, valinfo->suffix);
+ if (! len)
+ strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
}
+ strlcat(kctl->id.name, ' ', sizeof(kctl->id.name));
+ strlcat(kctl->id.name, valinfo->suffix, sizeof(kctl->id.name));
+
snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
@@ -1402,14 +1391,12 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned
len = get_term_name(state, &state->oterm,
kctl->id.name, sizeof(kctl->id.name), 0);
if (! len)
- len = sprintf(kctl->id.name, "USB");
- if ((state->oterm.type & 0xff00) == 0x0100) {
- if (len + 15 < sizeof(kctl->id.name))
- strcpy(kctl->id.name + len, " Capture Source");
- } else {
- if (len + 16 < sizeof(kctl->id.name))
- strcpy(kctl->id.name + len, " Playback Source");
- }
+ strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
+
+ if ((state->oterm.type & 0xff00) == 0x0100)
+ strlcat(kctl->id.name, " Capture Source", sizeof(kctl->id.name));
+ else
+ strlcat(kctl->id.name, " Playback Source", sizeof(kctl->id.name));
}
snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",