summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:33:54 -0800
committerLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:33:54 -0800
commit1040c54c3b98ac4f8d91bc313cdc9d6669481da3 (patch)
treed2c91b7b7e2aa5ffc88774ce1aa9aef08d4c709f
parent5aa875d2cbee34727963bd81aa992b64480045ca (diff)
v2.4.14.8 -> v2.4.14.9
- David Brownell: usbnet update - Greg KH: USB and PCI hotplug update - Ingo/me: fix SCHED_FIFO for UP/SMP for good (flw). - Add back direct_IO now that it works again.
-rw-r--r--Documentation/Configure.help11
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/kernel/smp.c2
-rw-r--r--arch/i386/kernel/ptrace.c12
-rw-r--r--arch/i386/kernel/smpboot.c2
-rw-r--r--arch/ia64/kernel/ptrace.c24
-rw-r--r--arch/ia64/kernel/smpboot.c2
-rw-r--r--arch/mips/kernel/smp.c4
-rw-r--r--arch/mips64/sgi-ip27/ip27-init.c2
-rw-r--r--arch/ppc/8xx_io/micropatch.c2
-rw-r--r--arch/ppc/kernel/setup.c6
-rw-r--r--arch/ppc/kernel/smp.c2
-rw-r--r--arch/s390/kernel/smp.c2
-rw-r--r--arch/s390x/kernel/smp.c2
-rw-r--r--arch/sparc/kernel/sun4d_smp.c2
-rw-r--r--arch/sparc/kernel/sun4m_smp.c2
-rw-r--r--arch/sparc64/kernel/smp.c2
-rw-r--r--drivers/hotplug/pci_hotplug_core.c17
-rw-r--r--drivers/pcmcia/yenta.c1
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux.c3
-rw-r--r--drivers/scsi/aic7xxx_old.c3
-rw-r--r--drivers/usb/serial/io_edgeport.c137
-rw-r--r--drivers/usb/usb.c4
-rw-r--r--drivers/usb/usbnet.c1116
-rw-r--r--fs/block_dev.c6
-rw-r--r--fs/buffer.c53
-rw-r--r--fs/ext2/inode.c7
-rw-r--r--fs/inode.c15
-rw-r--r--fs/reiserfs/Makefile6
-rw-r--r--fs/super.c1
-rw-r--r--include/linux/blkdev.h14
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/sched.h26
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/ksyms.c1
-rw-r--r--kernel/ptrace.c36
-rw-r--r--kernel/sched.c97
-rw-r--r--kernel/signal.c2
-rw-r--r--mm/filemap.c141
-rw-r--r--mm/shmem.c2
43 files changed, 1003 insertions, 776 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 9b4a26e9ad1b..48a44d045475 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -12742,6 +12742,17 @@ CONFIG_USB_SERIAL_VISOR
The module will be called visor.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+USB IR Dongle Serial Driver
+CONFIG_USB_SERIAL_IR
+ Say Y here if you want to enable simple serial support for USB IrDA
+ devices. This is useful if you do not want to use the full IrDA
+ stack.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ir-usb.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
USB Belkin and Paracom Single Port Serial Driver
CONFIG_USB_SERIAL_BELKIN
Say Y here if you want to use a Belkin USB Serial single port
diff --git a/Makefile b/Makefile
index 8dfc61a9c5c9..c1f98a7cf45c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 15
-EXTRAVERSION =-pre8
+EXTRAVERSION =-pre9
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index dbb08b98a884..33ca873c46b2 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -491,9 +491,9 @@ smp_boot_one_cpu(int cpuid, int cpunum)
panic("idle process is init_task for CPU %d", cpuid);
idle->processor = cpuid;
+ idle->cpus_runnable = 1 << cpuid; /* we schedule the first task manually */
__cpu_logical_map[cpunum] = cpuid;
__cpu_number_map[cpuid] = cpunum;
- idle->has_cpu = 1; /* we schedule the first task manually */
del_from_runqueue(idle);
unhash_process(idle);
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index a51cbf13be48..0fe86897fb0d 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -181,15 +181,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = ptrace_attach(child);
goto out_tsk;
}
- ret = -ESRCH;
- if (!(child->ptrace & PT_PTRACED))
- goto out_tsk;
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
- goto out_tsk;
- }
- if (child->p_pptr != current)
+
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0)
goto out_tsk;
+
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index b2a797c68ef4..64d6c827cd96 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -800,10 +800,10 @@ static void __init do_boot_cpu (int apicid)
panic("No idle process for CPU %d", cpu);
idle->processor = cpu;
+ idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
map_cpu_to_boot_apicid(cpu, apicid);
- idle->has_cpu = 1; /* we schedule the first task manually */
idle->thread.eip = (unsigned long) start_secondary;
del_from_runqueue(idle);
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index fc69cf6e2a5e..dc932f60d612 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -846,31 +846,11 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
ret = ptrace_attach(child);
goto out_tsk;
}
- ret = -ESRCH;
- if (!(child->ptrace & PT_PTRACED))
- goto out_tsk;
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
- goto out_tsk;
- }
-
- if (child->p_pptr != current)
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0)
goto out_tsk;
- if (request != PTRACE_KILL) {
- if (child->state != TASK_STOPPED)
- goto out_tsk;
-
-#ifdef CONFIG_SMP
- while (child->has_cpu) {
- if (child->state != TASK_STOPPED)
- goto out_tsk;
- barrier();
- }
-#endif
- }
-
pt = ia64_task_regs(child);
sw = (struct switch_stack *) (child->thread.ksp + 16);
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index abc38103dd9a..bc3dbf7a31a7 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -418,7 +418,7 @@ do_boot_cpu (int sapicid)
idle->processor = cpu;
ia64_cpu_to_sapicid[cpu] = sapicid;
- idle->has_cpu = 1; /* we schedule the first task manually */
+ idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
del_from_runqueue(idle);
unhash_process(idle);
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 41404069877a..bcfdad667d7a 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -126,7 +126,7 @@ void __init smp_boot_cpus(void)
/* Schedule the first task manually */
p->processor = i;
- p->has_cpu = 1;
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually */
/* Attach to the address space of init_task. */
atomic_inc(&init_mm.mm_count);
@@ -155,7 +155,7 @@ void __init smp_boot_cpus(void)
sprintf(p->comm, "%s%d", "Idle", i);
init_tasks[i] = p;
p->processor = i;
- p->has_cpu = 1; /* we schedule the first task manually */
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually *
del_from_runqueue(p);
unhash_process(p);
/* Attach to the address space of init_task. */
diff --git a/arch/mips64/sgi-ip27/ip27-init.c b/arch/mips64/sgi-ip27/ip27-init.c
index e676a90369ae..4c5c7439f499 100644
--- a/arch/mips64/sgi-ip27/ip27-init.c
+++ b/arch/mips64/sgi-ip27/ip27-init.c
@@ -497,7 +497,7 @@ void allowboot(void)
alloc_cpupda(cpu, num_cpus);
del_from_runqueue(p);
p->processor = num_cpus;
- p->has_cpu = 1; /* we schedule the first task manually */
+ p->cpus_runnable = 1 << num_cpus; /* we schedule the first task manually */
unhash_process(p);
/* Attach to the address space of init_task. */
atomic_inc(&init_mm.mm_count);
diff --git a/arch/ppc/8xx_io/micropatch.c b/arch/ppc/8xx_io/micropatch.c
index f0485c361446..68a51ee22661 100644
--- a/arch/ppc/8xx_io/micropatch.c
+++ b/arch/ppc/8xx_io/micropatch.c
@@ -17,7 +17,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
-#include "commproc.h"
+#include <asm/commproc.h>
/* Define this to get SMC patches as well. You need to modify the uart
* driver as well......
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index b69f593bc41b..fe503e74a123 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * BK Id: SCCS/s.setup.c 1.63 11/13/01 21:26:07 paulus
+ * BK Id: SCCS/s.setup.c 1.65 11/18/01 20:57:25 trini
*/
/*
* Common prep/pmac/chrp boot and setup code.
@@ -472,8 +472,8 @@ int parse_bootinfo(void)
break;
#ifdef CONFIG_BLK_DEV_INITRD
case BI_INITRD:
- initrd_start = data[0];
- initrd_end = data[0] + data[1];
+ initrd_start = data[0] + KERNELBASE;
+ initrd_end = data[0] + data[1] + KERNELBASE;
break;
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_ALL_PPC
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index c27da90efc9c..cefcc690d252 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -349,7 +349,7 @@ void __init smp_boot_cpus(void)
init_tasks[i] = p;
p->processor = i;
- p->has_cpu = 1;
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually */
current_set[i] = p;
/*
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index a7e6c959c7e5..0171e0d4cb26 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -531,7 +531,7 @@ static void __init do_boot_cpu(int cpu)
if (!idle)
panic("No idle process for CPU %d",cpu);
idle->processor = cpu;
- idle->has_cpu = 1; /* we schedule the first task manually */
+ idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
del_from_runqueue(idle);
unhash_process(idle);
diff --git a/arch/s390x/kernel/smp.c b/arch/s390x/kernel/smp.c
index 0232aedbbc6a..21912c7734b8 100644
--- a/arch/s390x/kernel/smp.c
+++ b/arch/s390x/kernel/smp.c
@@ -510,7 +510,7 @@ static void __init do_boot_cpu(int cpu)
if (!idle)
panic("No idle process for CPU %d",cpu);
idle->processor = cpu;
- idle->has_cpu = 1; /* we schedule the first task manually */
+ idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
del_from_runqueue(idle);
unhash_process(idle);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 098b2e58dc18..e8f5fb37b01e 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -225,7 +225,7 @@ void __init smp4d_boot_cpus(void)
init_tasks[i] = p;
p->processor = i;
- p->has_cpu = 1; /* we schedule the first task manually */
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually */
current_set[i] = p;
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 04e3d65fa38a..676b9f261591 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -198,7 +198,7 @@ void __init smp4m_boot_cpus(void)
init_tasks[i] = p;
p->processor = i;
- p->has_cpu = 1; /* we schedule the first task manually */
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually */
current_set[i] = p;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 69a21837e2a5..1b44bc0abf79 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -276,7 +276,7 @@ void __init smp_boot_cpus(void)
init_tasks[cpucount] = p;
p->processor = i;
- p->has_cpu = 1; /* we schedule the first task manually */
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually */
del_from_runqueue(p);
unhash_process(p);
diff --git a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
index 0b851a24c374..1df5e3735adc 100644
--- a/drivers/hotplug/pci_hotplug_core.c
+++ b/drivers/hotplug/pci_hotplug_core.c
@@ -622,7 +622,7 @@ exit:
static ssize_t power_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
{
struct hotplug_slot *slot = file->private_data;
- const char *buff;
+ char *buff;
unsigned long lpower;
u8 power;
int retval = 0;
@@ -639,10 +639,11 @@ static ssize_t power_write_file (struct file *file, const char *ubuff, size_t co
return -ENODEV;
}
- buff = kmalloc (count, GFP_KERNEL);
+ buff = kmalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
-
+ memset (buff, 0x00, count + 1);
+
if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
retval = -EFAULT;
goto exit;
@@ -732,7 +733,7 @@ exit:
static ssize_t attention_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
{
struct hotplug_slot *slot = file->private_data;
- const char *buff;
+ char *buff;
unsigned long lattention;
u8 attention;
int retval = 0;
@@ -749,9 +750,10 @@ static ssize_t attention_write_file (struct file *file, const char *ubuff, size_
return -ENODEV;
}
- buff = kmalloc (count, GFP_KERNEL);
+ buff = kmalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
+ memset (buff, 0x00, count + 1);
if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
retval = -EFAULT;
@@ -868,7 +870,7 @@ exit:
static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
{
struct hotplug_slot *slot = file->private_data;
- const char *buff;
+ char *buff;
unsigned long ltest;
u32 test;
int retval = 0;
@@ -885,9 +887,10 @@ static ssize_t test_write_file (struct file *file, const char *ubuff, size_t cou
return -ENODEV;
}
- buff = kmalloc (count, GFP_KERNEL);
+ buff = kmalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
+ memset (buff, 0x00, count + 1);
if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
retval = -EFAULT;
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index dfbbda448903..bf2a097e59d3 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -770,6 +770,7 @@ static void yenta_close(pci_socket_t *sock)
{
/* Disable all events so we don't die in an IRQ storm */
cb_writel(sock, CB_SOCKET_MASK, 0x0);
+ exca_writeb(sock, I365_CSCINT, 0);
if (sock->cb_irq)
free_irq(sock->cb_irq, sock);
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index dc7fa3ae3cce..e78f2978d9e8 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -175,6 +175,8 @@ cpqfc.o: $(cpqfc-objs)
53c8xx_u.h: 53c8xx_d.h
+53c7,8xx.o: 53c8xx_u.h
+
53c7xx_d.h: 53c7xx.scr script_asm.pl
ln -sf 53c7xx.scr fake7.c
$(CPP) $(CPPFLAGS) -traditional -DCHIP=710 fake7.c | grep -v '^#' | $(PERL) -s script_asm.pl -ncr7x0_family
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
index 48c6716716f3..345e2546c63e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -129,6 +129,7 @@
#include "../sd.h" /* For geometry detection */
#include <linux/mm.h> /* For fetching system memory size */
+#include <linux/blk.h>
/*
* To generate the correct addresses for the controller to issue
@@ -2742,7 +2743,7 @@ ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
struct buffer_head *bh;
ahc = *((struct ahc_softc **)disk->device->host->hostdata);
- bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
+ bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
if (bh) {
ret = scsi_partsize(bh, disk->capacity,
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 0882f2faf171..b5b8b3945351 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -238,6 +238,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/smp.h>
+#include <linux/blk.h>
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
@@ -11739,7 +11740,7 @@ aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
struct buffer_head *bh;
p = (struct aic7xxx_host *) disk->device->host->hostdata;
- bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
+ bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev));
if ( bh )
{
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index de1a523ce5d3..9d898e8924b6 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -25,6 +25,14 @@
*
* Version history:
*
+ * 2.2 2001_11_14 greg kroah-hartman
+ * - fixed bug in edge_close that kept the port from being used more
+ * than once.
+ * - fixed memory leak on device removal.
+ * - fixed potential double free of memory when command urb submitting
+ * failed.
+ * - other small cleanups when the device is removed
+ *
* 2.1 2001_07_09 greg kroah-hartman
* - added support for TIOCMBIS and TIOCMBIC.
*
@@ -263,7 +271,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.1"
+#define DRIVER_VERSION "v2.2"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"
@@ -433,7 +441,7 @@ static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */
/* function prototypes for all URB callbacks */
static void edge_interrupt_callback (struct urb *urb);
-static void edge_bulk_in_callback (struct urb *urb);
+static void edge_bulk_in_callback (struct urb *urb);
static void edge_bulk_out_data_callback (struct urb *urb);
static void edge_bulk_out_cmd_callback (struct urb *urb);
@@ -646,12 +654,6 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
}
#endif
-
-
-/************************************************************************
- * *
- * *
- ************************************************************************/
static void get_product_info(struct edgeport_serial *edge_serial)
{
struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -933,7 +935,7 @@ static void edge_bulk_out_cmd_callback (struct urb *urb)
dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs);
- /* if this urb had a transfer buffer already (old transfer) free it */
+ /* clean up the transfer buffer */
if (urb->transfer_buffer != NULL) {
kfree(urb->transfer_buffer);
}
@@ -957,7 +959,6 @@ static void edge_bulk_out_cmd_callback (struct urb *urb)
/* tell the tty driver that something has changed */
wake_up_interruptible(&tty->write_wait);
-
/* we have completed the command */
edge_port->commandPending = FALSE;
wake_up_interruptible(&edge_port->wait_command);
@@ -987,6 +988,9 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
dbg(__FUNCTION__ " - port %d", port->number);
+ if (edge_port == NULL)
+ return -ENODEV;
+
++port->open_count;
MOD_INC_USE_COUNT;
@@ -1002,6 +1006,12 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
as the structures were not set up at that time.) */
serial = port->serial;
edge_serial = (struct edgeport_serial *)serial->private;
+ if (edge_serial == NULL) {
+ port->active = 0;
+ port->open_count = 0;
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
if (edge_serial->interrupt_in_buffer == NULL) {
struct usb_serial_port *port0 = &serial->port[0];
@@ -1015,27 +1025,22 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
/* set up our interrupt urb */
- /* Like to use FILL_INT_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */
- edge_serial->interrupt_read_urb->complete = edge_interrupt_callback;
- edge_serial->interrupt_read_urb->context = edge_serial;
- edge_serial->interrupt_read_urb->dev = serial->dev;
- /* FILL_INT_URB(edge_serial->interrupt_read_urb, serial->dev,
- usb_rcvintpipe (serial->dev, edge_serial->interrupt_in_endpoint),
- edge_serial->interrupt_in_buffer, edge_serial->interrupt_in_endpoint.wMaxPacketSize,
- edge_interrupt_callback, edge_serial, edge_serial->interrupt_in_endpoint.bInterval);
- */
+ FILL_INT_URB(edge_serial->interrupt_read_urb,
+ serial->dev,
+ usb_rcvintpipe(serial->dev,
+ port0->interrupt_in_endpointAddress),
+ port0->interrupt_in_buffer,
+ edge_serial->interrupt_read_urb->transfer_buffer_length,
+ edge_interrupt_callback, edge_serial,
+ edge_serial->interrupt_read_urb->interval);
/* set up our bulk in urb */
- /* Like to use FILL_BULK_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */
- edge_serial->read_urb->complete = edge_bulk_in_callback;
- edge_serial->read_urb->context = edge_serial;
- edge_serial->read_urb->dev = serial->dev;
- /* FILL_BULK_URB(edge_serial->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev, port->bulk_in_endpointAddress),
- edge_serial->bulk_in_buffer, edge_serial->bulk_in_endpoint->wMaxPacketSize,
+ FILL_BULK_URB(edge_serial->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
+ port0->bulk_in_buffer,
+ edge_serial->read_urb->transfer_buffer_length,
edge_bulk_in_callback, edge_serial);
- */
-
+
/* start interrupt read for this edgeport
* this interrupt will continue as long as the edgeport is connected */
response = usb_submit_urb (edge_serial->interrupt_read_urb);
@@ -1239,7 +1244,9 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
edge_serial = (struct edgeport_serial *)serial->private;
edge_port = (struct edgeport_port *)port->private;
-
+ if ((edge_serial == NULL) || (edge_port == NULL))
+ return;
+
--port->open_count;
if (port->open_count <= 0) {
@@ -1285,15 +1292,14 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
if (edge_port->txfifo.fifo) {
kfree(edge_port->txfifo.fifo);
}
+ port->active = 0;
+ port->open_count = 0;
}
MOD_DEC_USE_COUNT;
dbg(__FUNCTION__" exited");
}
-
-
-
/*****************************************************************************
* SerialWrite
* this function is called by the tty driver when data should be written to
@@ -1312,6 +1318,9 @@ static int edge_write (struct usb_serial_port *port, int from_user, const unsign
dbg(__FUNCTION__ " - port %d", port->number);
+ if (edge_port == NULL)
+ return -ENODEV;
+
// get a pointer to the Tx fifo
fifo = &edge_port->txfifo;
@@ -1509,9 +1518,10 @@ static int edge_write_room (struct usb_serial_port *port)
dbg(__FUNCTION__);
- if (edge_port->closePending == TRUE) {
+ if (edge_port == NULL)
+ return -ENODEV;
+ if (edge_port->closePending == TRUE)
return -ENODEV;
- }
dbg(__FUNCTION__" - port %d", port->number);
@@ -1544,6 +1554,11 @@ static int edge_chars_in_buffer (struct usb_serial_port *port)
dbg(__FUNCTION__);
+ if (edge_port == NULL)
+ return -ENODEV;
+ if (edge_port->closePending == TRUE)
+ return -ENODEV;
+
if (!edge_port->open) {
dbg (__FUNCTION__" - port not opened");
return -EINVAL;
@@ -1571,6 +1586,9 @@ static void edge_throttle (struct usb_serial_port *port)
dbg(__FUNCTION__" - port %d", port->number);
+ if (edge_port == NULL)
+ return;
+
if (!edge_port->open) {
dbg (__FUNCTION__" - port not opened");
return;
@@ -1613,6 +1631,9 @@ static void edge_unthrottle (struct usb_serial_port *port)
dbg(__FUNCTION__" - port %d", port->number);
+ if (edge_port == NULL)
+ return;
+
if (!edge_port->open) {
dbg (__FUNCTION__" - port not opened");
return;
@@ -1670,6 +1691,9 @@ static void edge_set_termios (struct usb_serial_port *port, struct termios *old_
dbg(__FUNCTION__" - port %d", port->number);
+ if (edge_port == NULL)
+ return;
+
if (!edge_port->open) {
dbg (__FUNCTION__" - port not opened");
return;
@@ -2457,15 +2481,12 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
/* Allocate our next urb */
urb = usb_alloc_urb (0);
+ if (!urb)
+ return -ENOMEM;
CmdUrbs++;
-
dbg(__FUNCTION__" - ALLOCATE URB %p (outstanding %d)", urb, CmdUrbs);
- if (!urb) {
- return -ENOMEM;
- }
-
FILL_BULK_URB (urb, edge_serial->serial->dev,
usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
buffer, length, edge_bulk_out_cmd_callback, edge_port);
@@ -2474,17 +2495,11 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
urb->transfer_flags |= USB_QUEUE_BULK;
edge_port->commandPending = TRUE;
- urb->dev = edge_serial->serial->dev;
status = usb_submit_urb(urb);
if (status) {
/* something went wrong */
dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
-
- /* if this urb had a transfer buffer already (old transfer) free it */
- if (urb->transfer_buffer != NULL) {
- kfree(urb->transfer_buffer);
- }
usb_unlink_urb (urb);
usb_free_urb (urb);
return status;
@@ -2548,6 +2563,10 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, LCR, edge_port->shadowLCR);
status = write_cmd_usb(edge_port, cmdBuffer, cmdLen );
+ if (status) {
+ /* something bad happened, let's free up the memory */
+ kfree (cmdBuffer);
+ }
return status;
}
@@ -2623,6 +2642,10 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->number, regNum, regValue);
status = write_cmd_usb(edge_port, cmdBuffer, cmdLen);
+ if (status) {
+ /* something bad happened, let's free up the memory */
+ kfree (cmdBuffer);
+ }
return status;
}
@@ -2707,10 +2730,8 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
unsigned char stop_char = STOP_CHAR(tty);
unsigned char start_char = START_CHAR(tty);
- {
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
- }
+ send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+ send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
/* if we are implementing INBOUND XON/XOFF */
if (I_IXOFF(tty)) {
@@ -2962,10 +2983,11 @@ static int edge_startup (struct usb_serial *serial)
get_product_info(edge_serial);
/* set the number of ports from the manufacturing description */
- // FIXME should we override this???
- //serial->num_ports = serial->product_info.NumPorts;
+ /* serial->num_ports = serial->product_info.NumPorts; */
if (edge_serial->product_info.NumPorts != serial->num_ports) {
- warn(__FUNCTION__ " - Device Reported %d serial ports vs core thinking we have %d ports, email greg@kroah.com this info.", edge_serial->product_info.NumPorts, serial->num_ports);
+ warn(__FUNCTION__ " - Device Reported %d serial ports vs core "
+ "thinking we have %d ports, email greg@kroah.com this info.",
+ edge_serial->product_info.NumPorts, serial->num_ports);
}
dbg(__FUNCTION__ " - time 1 %ld", jiffies);
@@ -3005,10 +3027,9 @@ static int edge_startup (struct usb_serial *serial)
/****************************************************************************
- * usb_edgeport_disconnect
+ * edge_shutdown
* This function is called whenever the device is removed from the usb bus.
****************************************************************************/
-//static void usb_edgeport_disconnect (struct usb_device *dev, void *ptr)
static void edge_shutdown (struct usb_serial *serial)
{
int i;
@@ -3020,11 +3041,11 @@ static void edge_shutdown (struct usb_serial *serial)
while (serial->port[i].open_count > 0) {
edge_close (&serial->port[i], NULL);
}
+ kfree (serial->port[i].private);
+ serial->port[i].private = NULL;
}
-
- /* free up any memory that we allocated */
- // FIXME
-
+ kfree (serial->private);
+ serial->private = NULL;
}
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index c580b6082e07..af4bd2c9eb00 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1019,7 +1019,7 @@ void usb_free_urb(urb_t* urb)
/*-------------------------------------------------------------------*/
int usb_submit_urb(urb_t *urb)
{
- if (urb && urb->dev)
+ if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
return urb->dev->bus->op->submit_urb(urb);
else
return -ENODEV;
@@ -1028,7 +1028,7 @@ int usb_submit_urb(urb_t *urb)
/*-------------------------------------------------------------------*/
int usb_unlink_urb(urb_t *urb)
{
- if (urb && urb->dev)
+ if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
return urb->dev->bus->op->unlink_urb(urb);
else
return -ENODEV;
diff --git a/drivers/usb/usbnet.c b/drivers/usb/usbnet.c
index 724defed3d82..96608c0d9106 100644
--- a/drivers/usb/usbnet.c
+++ b/drivers/usb/usbnet.c
@@ -16,11 +16,10 @@
*
* - AnchorChip 2720
* - Belkin, eTEK (interops with Win32 drivers)
+ * - GeneSys GL620USB-A
* - "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
* - NetChip 1080 (interoperates with NetChip Win32 drivers)
* - Prolific PL-2301/2302 (replaces "plusb" driver)
- * - GeneSys GL620USB-A
-
*
* USB devices can implement their side of this protocol at the cost
* of two bulk endpoints; it's not restricted to "cable" applications.
@@ -78,9 +77,11 @@
* 17-oct-2001 Handle "Advance USBNET" product, like Belkin/eTEK devices,
* from Ioannis Mavroukakis <i.mavroukakis@btinternet.com>;
* rx unlinks somehow weren't async; minor cleanup.
- * 25-oct-2001 Merged GeneSys driver, using code from
- * Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
- * by Stanislav Brabec <utx@penguin.cz>
+ * 03-nov-2001 Merged GeneSys driver; original code from Jiun-Jie Huang
+ * <huangjj@genesyslogic.com.tw>, updated by Stanislav Brabec
+ * <utx@penguin.cz>. Made framing options (NetChip/GeneSys)
+ * tie mostly to (sub)driver info. Workaround some PL-2302
+ * chips that seem to reject SET_INTERFACE requests.
*
*-------------------------------------------------------------------------*/
@@ -106,10 +107,10 @@
#define CONFIG_USB_AN2720
#define CONFIG_USB_BELKIN
+#define CONFIG_USB_GENESYS
#define CONFIG_USB_LINUXDEV
#define CONFIG_USB_NET1080
#define CONFIG_USB_PL2301
-#define CONFIG_USB_GENELINK
/*-------------------------------------------------------------------------*/
@@ -163,7 +164,10 @@ struct usbnet {
// protocol/interface state
struct net_device net;
struct net_device_stats stats;
+
+#ifdef CONFIG_USB_NET1080
u16 packet_id;
+#endif
// various kinds of pending driver work
struct sk_buff_head rxq;
@@ -171,9 +175,6 @@ struct usbnet {
struct sk_buff_head done;
struct tasklet_struct bh;
struct tq_struct ctrl_task;
-
- // various data structure may be needed
- void *priv_data;
};
// device-specific info used by the driver
@@ -182,7 +183,7 @@ struct driver_info {
int flags;
#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
-#define FLAG_GENELINK 0x0002 /* genelink flag */
+#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
/* reset device ... can sleep */
@@ -191,13 +192,15 @@ struct driver_info {
/* see if peer is connected ... can sleep */
int (*check_connect)(struct usbnet *);
- /* allocate and initialize the private resources per device */
- int (*initialize_private)(struct usbnet *);
+ /* fixup rx packet (strip framing) */
+ int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
- /* free the private resources per device */
- int (*release_private)(struct usbnet *);
+ /* fixup tx packet (add framing) */
+ struct sk_buff *(*tx_fixup)(struct usbnet *dev,
+ struct sk_buff *skb, int flags);
// FIXME -- also an interrupt mechanism
+ // useful for at least PL2301/2302 and GL620USB-A
/* framework currently "knows" bulk EPs talk packets */
int in; /* rx endpoint */
@@ -240,47 +243,6 @@ struct skb_data { // skb->cb is one of these
#define devinfo(usbnet, fmt, arg...) \
printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
-/*-------------------------------------------------------------------------
- *
- * NetChip framing of ethernet packets, supporting additional error
- * checks for links that may drop bulk packets from inside messages.
- * Odd USB length == always short read for last usb packet.
- * - nc_header
- * - Ethernet header (14 bytes)
- * - payload
- * - (optional padding byte, if needed so length becomes odd)
- * - nc_trailer
- *
- * This framing is to be avoided for non-NetChip devices.
- */
-
-struct nc_header { // packed:
- u16 hdr_len; // sizeof nc_header (LE, all)
- u16 packet_len; // payload size (including ethhdr)
- u16 packet_id; // detects dropped packets
-#define MIN_HEADER 6
-
- // all else is optional, and must start with:
- // u16 vendorId; // from usb-if
- // u16 productId;
-} __attribute__((__packed__));
-
-#define PAD_BYTE ((unsigned char)0xAC)
-
-struct nc_trailer {
- u16 packet_id;
-} __attribute__((__packed__));
-
-// packets may use FLAG_FRAMING_NC and optional pad
-#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
- + sizeof (struct ethhdr) \
- + (mtu) \
- + 1 \
- + sizeof (struct nc_trailer))
-
-#define MIN_FRAMED FRAMED_SIZE(0)
-
-
#ifdef CONFIG_USB_AN2720
@@ -329,6 +291,330 @@ static const struct driver_info belkin_info = {
+#ifdef CONFIG_USB_GENESYS
+
+/*-------------------------------------------------------------------------
+ *
+ * GeneSys GL620USB-A (www.genesyslogic.com.tw)
+ *
+ * ... should partially interop with the Win32 driver for this hardware
+ * The GeneSys docs imply there's some NDIS issue motivating this framing.
+ *
+ *-------------------------------------------------------------------------*/
+
+// control msg write command
+#define GENELINK_CONNECT_WRITE 0xF0
+// interrupt pipe index
+#define GENELINK_INTERRUPT_PIPE 0x03
+// interrupt read buffer size
+#define INTERRUPT_BUFSIZE 0x08
+// interrupt pipe interval value
+#define GENELINK_INTERRUPT_INTERVAL 0x10
+// max transmit packet number per transmit
+#define GL_MAX_TRANSMIT_PACKETS 32
+// max packet length
+#define GL_MAX_PACKET_LEN 1514
+// max receive buffer size
+#define GL_RCV_BUF_SIZE \
+ (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
+
+struct gl_packet {
+ u32 packet_length;
+ char packet_data [1];
+};
+
+struct gl_header {
+ u32 packet_count;
+ struct gl_packet packets;
+};
+
+#ifdef GENLINK_ACK
+
+// FIXME: this code is incomplete, not debugged; it doesn't
+// handle interrupts correctly. interrupts should be generic
+// code like all other device I/O, anyway.
+
+struct gl_priv {
+ struct urb *irq_urb;
+ char irq_buf [INTERRUPT_BUFSIZE];
+};
+
+static inline int gl_control_write (struct usbnet *dev, u8 request, u16 value)
+{
+ int retval;
+
+ retval = usb_control_msg (dev->udev,
+ usb_sndctrlpipe (dev->udev, 0),
+ request,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ value,
+ 0, // index
+ 0, // data buffer
+ 0, // size
+ CONTROL_TIMEOUT_JIFFIES);
+ return retval;
+}
+
+static void gl_interrupt_complete (struct urb *urb)
+{
+ int status = urb->status;
+
+ if (status)
+ dbg ("gl_interrupt_complete fail - %X", status);
+ else
+ dbg ("gl_interrupt_complete success...");
+}
+
+static int gl_interrupt_read (struct usbnet *dev)
+{
+ struct gl_priv *priv = dev->priv_data;
+ int retval;
+
+ // issue usb interrupt read
+ if (priv && priv->irq_urb) {
+ // submit urb
+ if ((retval = usb_submit_urb (priv->irq_urb)) != 0)
+ dbg ("gl_interrupt_read: submit fail - %X...", retval);
+ else
+ dbg ("gl_interrupt_read: submit success...");
+ }
+
+ return 0;
+}
+
+// check whether another side is connected
+static int genelink_check_connect (struct usbnet *dev)
+{
+ int retval;
+
+ dbg ("genelink_check_connect...");
+
+ // detect whether another side is connected
+ if ((retval = gl_control_write (dev, GENELINK_CONNECT_WRITE, 0)) != 0) {
+ dbg ("%s: genelink_check_connect write fail - %X",
+ dev->net.name, retval);
+ return retval;
+ }
+
+ // usb interrupt read to ack another side
+ if ((retval = gl_interrupt_read (dev)) != 0) {
+ dbg ("%s: genelink_check_connect read fail - %X",
+ dev->net.name, retval);
+ return retval;
+ }
+
+ dbg ("%s: genelink_check_connect read success", dev->net.name);
+ return 0;
+}
+
+// allocate and initialize the private data for genelink
+static int genelink_init (struct usbnet *dev)
+{
+ struct gl_priv *priv;
+
+ // allocate the private data structure
+ if ((priv = kmalloc (sizeof *priv, GFP_KERNEL)) == 0) {
+ dbg ("%s: cannot allocate private data per device",
+ dev->net.name);
+ return -ENOMEM;
+ }
+
+ // allocate irq urb
+ if ((priv->irq_urb = usb_alloc_urb (0)) == 0) {
+ dbg ("%s: cannot allocate private irq urb per device",
+ dev->net.name);
+ kfree (priv);
+ return -ENOMEM;
+ }
+
+ // fill irq urb
+ FILL_INT_URB (priv->irq_urb, dev->udev,
+ usb_rcvintpipe (dev->udev, GENELINK_INTERRUPT_PIPE),
+ priv->irq_buf, INTERRUPT_BUFSIZE,
+ gl_interrupt_complete, 0,
+ GENELINK_INTERRUPT_INTERVAL);
+
+ // set private data pointer
+ dev->priv_data = priv;
+
+ return 0;
+}
+
+// release the private data
+static int genelink_free (struct usbnet *dev)
+{
+ struct gl_priv *priv = dev->priv_data;
+
+ if (!priv)
+ return 0;
+
+// FIXME: can't cancel here; it's synchronous, and
+// should have happened earlier in any case (interrupt
+// handling needs to be generic)
+
+ // cancel irq urb first
+ usb_unlink_urb (priv->irq_urb);
+
+ // free irq urb
+ usb_free_urb (priv->irq_urb);
+
+ // free the private data structure
+ kfree (priv);
+
+ return 0;
+}
+
+#else
+
+static int genelink_check_connect (struct usbnet *dev)
+{
+ dbg ("%s: assuming peer is connected", dev->net.name);
+ return 0;
+}
+
+#endif
+
+// reset the device status
+static int genelink_reset (struct usbnet *dev)
+{
+ // we don't need to reset, just return 0
+ return 0;
+}
+
+static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
+{
+ struct gl_header *header;
+ struct gl_packet *packet;
+ struct sk_buff *gl_skb;
+ int status;
+ u32 size;
+
+ header = (struct gl_header *) skb->data;
+
+ // get the packet count of the received skb
+ le32_to_cpus (&header->packet_count);
+ if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
+ || (header->packet_count < 0)) {
+ dbg ("genelink: illegal received packet count %d",
+ header->packet_count);
+ return 0;
+ }
+
+ // set the current packet pointer to the first packet
+ packet = &header->packets;
+
+ // decrement the length for the packet count size 4 bytes
+ skb_pull (skb, 4);
+
+ while (header->packet_count > 1) {
+ // get the packet length
+ size = packet->packet_length;
+
+ // this may be a broken packet
+ if (size > GL_MAX_PACKET_LEN) {
+ dbg ("genelink: illegal rx length %d", size);
+ return 0;
+ }
+
+ // allocate the skb for the individual packet
+ gl_skb = alloc_skb (size, GFP_ATOMIC);
+ if (gl_skb == 0)
+ return 0;
+
+ // copy the packet data to the new skb
+ memcpy (gl_skb->data, packet->packet_data, size);
+
+ // set skb data size
+ gl_skb->len = size;
+ gl_skb->dev = &dev->net;
+
+ // determine the packet's protocol ID
+ gl_skb->protocol = eth_type_trans (gl_skb, &dev->net);
+
+ // update the status
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += size;
+
+ // notify os of the received packet
+ status = netif_rx (gl_skb);
+
+ // advance to the next packet
+ packet = (struct gl_packet *)
+ &packet->packet_data [size];
+ header->packet_count--;
+
+ // shift the data pointer to the next gl_packet
+ skb_pull (skb, size + 4);
+ }
+
+ // skip the packet length field 4 bytes
+ skb_pull (skb, 4);
+
+ if (skb->len > GL_MAX_PACKET_LEN) {
+ dbg ("genelink: illegal rx length %d", skb->len);
+ return 0;
+ }
+ return 1;
+}
+
+static struct sk_buff *
+genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
+{
+ int padlen;
+ int length = skb->len;
+ int headroom = skb_headroom (skb);
+ int tailroom = skb_tailroom (skb);
+ u32 *packet_count;
+ u32 *packet_len;
+
+ // FIXME: magic numbers, bleech
+ padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
+
+ if ((!skb_cloned (skb))
+ && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
+ if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
+ skb->data = memmove (skb->head + (4 + 4*1),
+ skb->data, skb->len);
+ skb->tail = skb->data + skb->len;
+ }
+ } else {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand (skb, (4 + 4*1) , padlen, flags);
+ dev_kfree_skb_any (skb);
+ skb = skb2;
+ }
+
+ // attach the packet count to the header
+ packet_count = (u32 *) skb_push (skb, (4 + 4*1));
+ packet_len = packet_count + 1;
+
+ // FIXME little endian?
+ *packet_count = 1;
+ *packet_len = length;
+
+ // add padding byte
+ if ((skb->len % EP_SIZE (dev)) == 0)
+ skb_put (skb, 1);
+
+ return skb;
+}
+
+static const struct driver_info genelink_info = {
+ description: "Genesys GeneLink",
+ flags: FLAG_FRAMING_GL | FLAG_NO_SETINT,
+ reset: genelink_reset,
+ check_connect: genelink_check_connect,
+ rx_fixup: genelink_rx_fixup,
+ tx_fixup: genelink_tx_fixup,
+
+ in: 1, out: 2,
+ epsize: 64,
+};
+
+#endif /* CONFIG_USB_GENESYS */
+
+
+
#ifdef CONFIG_USB_LINUXDEV
/*-------------------------------------------------------------------------
@@ -364,10 +650,51 @@ static const struct driver_info linuxdev_info = {
/*-------------------------------------------------------------------------
*
* Netchip 1080 driver ... http://www.netchip.com
+ * Used in LapLink cables
*
*-------------------------------------------------------------------------*/
/*
+ * NetChip framing of ethernet packets, supporting additional error
+ * checks for links that may drop bulk packets from inside messages.
+ * Odd USB length == always short read for last usb packet.
+ * - nc_header
+ * - Ethernet header (14 bytes)
+ * - payload
+ * - (optional padding byte, if needed so length becomes odd)
+ * - nc_trailer
+ *
+ * This framing is to be avoided for non-NetChip devices.
+ */
+
+struct nc_header { // packed:
+ u16 hdr_len; // sizeof nc_header (LE, all)
+ u16 packet_len; // payload size (including ethhdr)
+ u16 packet_id; // detects dropped packets
+#define MIN_HEADER 6
+
+ // all else is optional, and must start with:
+ // u16 vendorId; // from usb-if
+ // u16 productId;
+} __attribute__((__packed__));
+
+#define PAD_BYTE ((unsigned char)0xAC)
+
+struct nc_trailer {
+ u16 packet_id;
+} __attribute__((__packed__));
+
+// packets may use FLAG_FRAMING_NC and optional pad
+#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
+ + sizeof (struct ethhdr) \
+ + (mtu) \
+ + 1 \
+ + sizeof (struct nc_trailer))
+
+#define MIN_FRAMED FRAMED_SIZE(0)
+
+
+/*
* Zero means no timeout; else, how long a 64 byte bulk packet may be queued
* before the hardware drops it. If that's done, the driver will need to
* frame network packets to guard against the dropped USB packets. The win32
@@ -652,11 +979,113 @@ static int net1080_check_connect (struct usbnet *dev)
return 0;
}
+static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
+{
+ struct nc_header *header;
+ struct nc_trailer *trailer;
+
+ if (!(skb->len & 0x01)
+ || MIN_FRAMED > skb->len
+ || skb->len > FRAMED_SIZE (dev->net.mtu)) {
+ dev->stats.rx_frame_errors++;
+ dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
+ MIN_FRAMED, FRAMED_SIZE (dev->net.mtu),
+ dev->net.mtu
+ );
+ return 0;
+ }
+
+ header = (struct nc_header *) skb->data;
+ le16_to_cpus (&header->hdr_len);
+ le16_to_cpus (&header->packet_len);
+ if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) {
+ dev->stats.rx_frame_errors++;
+ dbg ("packet too big, %d", header->packet_len);
+ return 0;
+ } else if (header->hdr_len < MIN_HEADER) {
+ dev->stats.rx_frame_errors++;
+ dbg ("header too short, %d", header->hdr_len);
+ return 0;
+ } else if (header->hdr_len > MIN_HEADER) {
+ // out of band data for us?
+ dbg ("header OOB, %d bytes",
+ header->hdr_len - MIN_HEADER);
+ // switch (vendor/product ids) { ... }
+ }
+ skb_pull (skb, header->hdr_len);
+
+ trailer = (struct nc_trailer *)
+ (skb->data + skb->len - sizeof *trailer);
+ skb_trim (skb, skb->len - sizeof *trailer);
+
+ if ((header->packet_len & 0x01) == 0) {
+ if (skb->data [header->packet_len] != PAD_BYTE) {
+ dev->stats.rx_frame_errors++;
+ dbg ("bad pad");
+ return 0;
+ }
+ skb_trim (skb, skb->len - 1);
+ }
+ if (skb->len != header->packet_len) {
+ dev->stats.rx_frame_errors++;
+ dbg ("bad packet len %d (expected %d)",
+ skb->len, header->packet_len);
+ return 0;
+ }
+ if (header->packet_id != get_unaligned (&trailer->packet_id)) {
+ dev->stats.rx_fifo_errors++;
+ dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
+ header->packet_id, trailer->packet_id);
+ return 0;
+ }
+#if 0
+ devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len,
+ header->packet_len, header->packet_id);
+#endif
+ return 1;
+}
+
+static struct sk_buff *
+net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
+{
+ int padlen;
+ struct sk_buff *skb2;
+
+ padlen = ((skb->len + sizeof (struct nc_header)
+ + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
+ if (!skb_cloned (skb)) {
+ int headroom = skb_headroom (skb);
+ int tailroom = skb_tailroom (skb);
+
+ if ((padlen + sizeof (struct nc_trailer)) <= tailroom
+ && sizeof (struct nc_header) <= headroom)
+ return skb;
+
+ if ((sizeof (struct nc_header) + padlen
+ + sizeof (struct nc_trailer)) <
+ (headroom + tailroom)) {
+ skb->data = memmove (skb->head
+ + sizeof (struct nc_header),
+ skb->data, skb->len);
+ skb->tail = skb->data + skb->len;
+ return skb;
+ }
+ }
+ skb2 = skb_copy_expand (skb,
+ sizeof (struct nc_header),
+ sizeof (struct nc_trailer) + padlen,
+ flags);
+ dev_kfree_skb_any (skb);
+ return skb2;
+}
+
static const struct driver_info net1080_info = {
description: "NetChip TurboCONNECT",
flags: FLAG_FRAMING_NC,
reset: net1080_reset,
check_connect: net1080_check_connect,
+ rx_fixup: net1080_rx_fixup,
+ tx_fixup: net1080_tx_fixup,
in: 1, out: 1, // direction distinguishes these
epsize: 64,
@@ -730,6 +1159,8 @@ static int pl_check_connect (struct usbnet *dev)
static const struct driver_info prolific_info = {
description: "Prolific PL-2301/PL-2302",
+ flags: FLAG_NO_SETINT,
+ /* some PL-2302 versions seem to fail usb_set_interface() */
reset: pl_reset,
check_connect: pl_check_connect,
@@ -741,199 +1172,6 @@ static const struct driver_info prolific_info = {
-#ifdef CONFIG_USB_GENELINK
-
-/*-------------------------------------------------------------------------
- *
- * GeneSys GL620USB-A (www.genesyslogic.com.tw)
- *
- *-------------------------------------------------------------------------*/
-
-// control msg write command
-#define GENELINK_CONNECT_WRITE 0xF0
-// interrupt pipe index
-#define GENELINK_INTERRUPT_PIPE 0x03
-// interrupt read buffer size
-#define INTERRUPT_BUFSIZE 0x08
-// interrupt pipe interval value
-#define GENELINK_INTERRUPT_INTERVAL 0x10
-// max transmit packet number per transmit
-#define GL_MAX_TRANSMIT_PACKETS 32
-// max packet length
-#define GL_MAX_PACKET_LEN 1514
-// max receive buffer size
-#define GL_RCV_BUF_SIZE (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
-
-struct gl_priv
-{
- struct urb *irq_urb;
- char irq_buf[INTERRUPT_BUFSIZE];
-};
-
-struct gl_packet
-{
- u32 packet_length;
- char packet_data[1];
-};
-
-struct gl_header
-{
- u32 packet_count;
-
- struct gl_packet packets;
-};
-
-static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value)
-{
- int retval;
-
- retval = usb_control_msg (dev->udev,
- usb_sndctrlpipe (dev->udev, 0),
- request,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- value,
- 0, // index
- 0, // data buffer
- 0, // size
- CONTROL_TIMEOUT_JIFFIES);
-
- return retval;
-}
-
-static void gl_interrupt_complete (struct urb *urb)
-{
- int status = urb->status;
-
- if (status)
- dbg("gl_interrupt_complete fail - %X\n", status);
- else
- dbg("gl_interrupt_complete success...\n");
-}
-
-static inline int gl_interrupt_read(struct usbnet *dev)
-{
- struct gl_priv *priv = dev->priv_data;
- int retval;
-
- // issue usb interrupt read
- if (priv && priv->irq_urb) {
- // submit urb
- if ((retval = usb_submit_urb (priv->irq_urb)) != 0)
- dbg("gl_interrupt_read: submit interrupt read urb fail - %X...\n", retval);
- else
- dbg("gl_interrupt_read: submit interrupt read urb success...\n");
- }
-
- return 0;
-}
-
-// check whether another side is connected
-static int genelink_check_connect (struct usbnet *dev)
-{
- dbg ("%s: assuming peer is connected", dev->net.name);
- return 0;
-
- /*
- // FIXME Uncomment this code after genelink_check_connect
- // control hanshaking will be implemented
-
- int retval;
-
- dbg("genelink_check_connect...\n");
-
- // issue a usb control write command to detect whether another side is connected
- if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) {
- dbg ("%s: genelink_check_connect control write fail - %X\n", dev->net.name, retval);
- return retval;
- } else {
- dbg("%s: genelink_check_conntect control write success\n",dev->net.name);
-
- // issue a usb interrupt read command to ack another side
-
- if ((retval = gl_interrupt_read(dev)) != 0) {
- dbg("%s: genelink_check_connect interrupt read fail - %X\n", dev->net.name, retval);
- return retval;
- } else {
- dbg("%s: genelink_check_connect interrupt read success\n", dev->net.name);
- }
-
- }
- */
-
- return 0;
-}
-
-// allocate and initialize the private data for genelink
-static int genelink_init_priv(struct usbnet *dev)
-{
- struct gl_priv *priv;
-
- // allocate the private data structure
- if ((priv = kmalloc (sizeof *priv, GFP_KERNEL)) == 0) {
- dbg("%s: cannot allocate private data per device", dev->net.name);
- return -ENOMEM;
- }
-
- // allocate irq urb
- if ((priv->irq_urb = usb_alloc_urb(0)) == 0) {
- dbg("%s: cannot allocate private irq urb per device", dev->net.name);
- kfree(priv);
- return -ENOMEM;
- }
-
- // fill irq urb
- FILL_INT_URB(priv->irq_urb, dev->udev, usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE),
- priv->irq_buf, INTERRUPT_BUFSIZE, gl_interrupt_complete, 0, GENELINK_INTERRUPT_INTERVAL);
-
- // set private data pointer
- dev->priv_data = priv;
-
- return 0;
-}
-
-// release the private data
-static int genelink_release_priv(struct usbnet *dev)
-{
- struct gl_priv *priv = dev->priv_data;
-
- if (!priv)
- return 0;
-
- // cancel irq urb first
- usb_unlink_urb(priv->irq_urb);
-
- // free irq urb
- usb_free_urb(priv->irq_urb);
-
- // free the private data structure
- kfree(priv);
-
- return 0;
-}
-
-// reset the device status
-static int genelink_reset (struct usbnet *dev)
-{
- // we don't need to reset, just return 0
- return 0;
-}
-
-static const struct driver_info genelink_info = {
- description: "Genesys GeneLink",
- flags: FLAG_GENELINK | FLAG_NO_SETINT,
- reset: genelink_reset,
- check_connect: genelink_check_connect,
- initialize_private: genelink_init_priv,
- release_private: genelink_release_priv,
-
- in: 1, out: 2, // direction distinguishes these
- epsize: 64,
-};
-
-#endif /* CONFIG_USB_GENELINK */
-
-
-
/*-------------------------------------------------------------------------
*
* Network Device Driver (peer link to "Host Device", from USB host)
@@ -946,11 +1184,19 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
return -EINVAL;
+#ifdef CONFIG_USB_NET1080
if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) {
if (FRAMED_SIZE (new_mtu) > MAX_PACKET)
return -EINVAL;
+ }
+#endif
+#ifdef CONFIG_USB_GENESYS
+ if (((dev->driver_info->flags) & FLAG_FRAMING_GL)
+ && new_mtu > GL_MAX_PACKET_LEN)
+ return -EINVAL;
+#endif
// no second zero-length packet read wanted after mtu-sized packets
- } else if (((new_mtu + sizeof (struct ethhdr)) % EP_SIZE (dev)) == 0)
+ if (((new_mtu + sizeof (struct ethhdr)) % EP_SIZE (dev)) == 0)
return -EDOM;
net->mtu = new_mtu;
return 0;
@@ -994,14 +1240,16 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
unsigned long lockflags;
size_t size;
-#ifdef CONFIG_USB_GENELINK
- if (dev->driver_info->flags & FLAG_GENELINK)
- size = GL_RCV_BUF_SIZE;
- else
-#endif
+#ifdef CONFIG_USB_NET1080
if (dev->driver_info->flags & FLAG_FRAMING_NC)
size = FRAMED_SIZE (dev->net.mtu);
else
+#endif
+#ifdef CONFIG_USB_GENESYS
+ if (dev->driver_info->flags & FLAG_FRAMING_GL)
+ size = GL_RCV_BUF_SIZE;
+ else
+#endif
size = (sizeof (struct ethhdr) + dev->net.mtu);
if ((skb = alloc_skb (size, flags)) == 0) {
@@ -1055,181 +1303,14 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
{
- if (dev->driver_info->flags & FLAG_FRAMING_NC) {
- struct nc_header *header;
- struct nc_trailer *trailer;
-
- if (!(skb->len & 0x01)
- || MIN_FRAMED > skb->len
- || skb->len > FRAMED_SIZE (dev->net.mtu)) {
- dev->stats.rx_frame_errors++;
- dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
- MIN_FRAMED, FRAMED_SIZE (dev->net.mtu),
- dev->net.mtu
- );
- goto error;
- }
-
- header = (struct nc_header *) skb->data;
- le16_to_cpus (&header->hdr_len);
- le16_to_cpus (&header->packet_len);
- if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) {
- dev->stats.rx_frame_errors++;
- dbg ("packet too big, %d", header->packet_len);
- goto error;
- } else if (header->hdr_len < MIN_HEADER) {
- dev->stats.rx_frame_errors++;
- dbg ("header too short, %d", header->hdr_len);
- goto error;
- } else if (header->hdr_len > MIN_HEADER) {
- // out of band data for us?
- dbg ("header OOB, %d bytes",
- header->hdr_len - MIN_HEADER);
- // switch (vendor/product ids) { ... }
- }
- skb_pull (skb, header->hdr_len);
-
- trailer = (struct nc_trailer *)
- (skb->data + skb->len - sizeof *trailer);
- skb_trim (skb, skb->len - sizeof *trailer);
-
- if ((header->packet_len & 0x01) == 0) {
- if (skb->data [header->packet_len] != PAD_BYTE) {
- dev->stats.rx_frame_errors++;
- dbg ("bad pad");
- goto error;
- }
- skb_trim (skb, skb->len - 1);
- }
- if (skb->len != header->packet_len) {
- dev->stats.rx_frame_errors++;
- dbg ("bad packet len %d (expected %d)",
- skb->len, header->packet_len);
- goto error;
- }
- if (header->packet_id != get_unaligned (&trailer->packet_id)) {
- dev->stats.rx_fifo_errors++;
- dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
- header->packet_id, trailer->packet_id);
- goto error;
- }
-#if 0
- devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len,
- header->packet_len, header->packet_id);
-#endif
- } else {
- // we trust the network stack to remove
- // the extra byte we may have appended
- }
-
-#ifdef CONFIG_USB_GENELINK
- if (dev->driver_info->flags & FLAG_GENELINK) {
- struct gl_header *header;
- struct gl_packet *current_packet;
- struct sk_buff *gl_skb;
- int status;
- u32 size;
-
- header = (struct gl_header *)skb->data;
-
- // get the packet count of the received skb
- le32_to_cpus(&header->packet_count);
-
-// dbg("receive packet count = %d", header->packet_count);
-
- if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) ||
- (header->packet_count < 0)) {
- dbg("genelink: illegal received packet count %d", header->packet_count);
- goto error;
- }
-
- // set the current packet pointer to the first packet
- current_packet = &(header->packets);
-
- // decrement the length for the packet count size 4 bytes
- skb_pull(skb, 4);
-
- while (header->packet_count > 1) {
- // get the packet length
- size = current_packet->packet_length;
-
- // this may be a broken packet
- if (size > GL_MAX_PACKET_LEN) {
- dbg("genelink: illegal received packet length %d, maybe a broken packet", size);
- goto error;
- }
-
- // allocate the skb for the individual packet
- gl_skb = alloc_skb (size, in_interrupt () ? GFP_ATOMIC : GFP_KERNEL);
-
- if (gl_skb == 0)
- goto error;
-
- // copy the packet data to the new skb
- memcpy(gl_skb->data,current_packet->packet_data,size);
-
- // set skb data size
- gl_skb->len = size;
-/*
- dbg("rx_process one gl_packet, size = %d...", size);
-
- dbg("%02X %02X %02X %02X %02X %02X",
- (u8)gl_skb->data[0],(u8)gl_skb->data[1],(u8)gl_skb->data[2],
- (u8)gl_skb->data[3],(u8)gl_skb->data[4],(u8)gl_skb->data[5]);
- dbg("%02X %02X %02X %02X %02X %02X\n",
- (u8)gl_skb->data[6],(u8)gl_skb->data[7],(u8)gl_skb->data[8],
- (u8)gl_skb->data[9],(u8)gl_skb->data[10],(u8)gl_skb->data[11]);
-*/
- gl_skb->dev = &dev->net;
-
- // determine the packet's protocol ID
- gl_skb->protocol = eth_type_trans(gl_skb, &dev->net);
-
- // update the status
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += size;
-
- // notify os of the received packet
- status = netif_rx (gl_skb);
-
-// dev_kfree_skb (gl_skb); // just for debug purpose, delete this line for normal operation
-
- // advance to the next packet
- current_packet = (struct gl_packet *)(current_packet->packet_data + size);
-
- header->packet_count --;
-
- // shift the data pointer to the next gl_packet
- skb_pull(skb, size + 4);
- } // while (header->packet_count > 1)
-
- // skip the packet length field 4 bytes
- skb_pull(skb, 4);
- }
-#endif
+ if (dev->driver_info->rx_fixup
+ && !dev->driver_info->rx_fixup (dev, skb))
+ goto error;
+ // else network stack removes extra byte if we forced a short packet
if (skb->len) {
int status;
-#ifdef CONFIG_USB_GENELINK
-/*
- dbg("rx_process one packet, size = %d", skb->len);
-
- dbg("%02X %02X %02X %02X %02X %02X",
- (u8)skb->data[0],(u8)skb->data[1],(u8)skb->data[2],
- (u8)skb->data[3],(u8)skb->data[4],(u8)skb->data[5]);
- dbg("%02X %02X %02X %02X %02X %02X\n",
- (u8)skb->data[6],(u8)skb->data[7],(u8)skb->data[8],
- (u8)skb->data[9],(u8)skb->data[10],(u8)skb->data[11]);
-*/
-
- if ((dev->driver_info->flags & FLAG_GENELINK) &&
- (skb->len > GL_MAX_PACKET_LEN)) {
- dbg("genelink: illegal received packet length %d, maybe a broken packet", skb->len);
- goto error;
- }
-#endif
-
// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
skb->dev = &dev->net;
@@ -1241,7 +1322,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
devdbg (dev, "< rx, len %d, type 0x%x",
skb->len + sizeof (struct ethhdr), skb->protocol);
#endif
- memset (skb->cb,0,sizeof(struct skb_data));
+ memset (skb->cb, 0, sizeof (struct skb_data));
status = netif_rx (skb);
if (status != NET_RX_SUCCESS)
devdbg (dev, "netif_rx status %d", status);
@@ -1359,7 +1440,7 @@ static int usbnet_stop (struct net_device *net)
DECLARE_WAITQUEUE (wait, current);
mutex_lock (&dev->mutex);
- netif_stop_queue(net);
+ netif_stop_queue (net);
devdbg (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
dev->stats.rx_packets, dev->stats.tx_packets,
@@ -1375,16 +1456,13 @@ static int usbnet_stop (struct net_device *net)
while (skb_queue_len (&dev->rxq)
&& skb_queue_len (&dev->txq)
&& skb_queue_len (&dev->done)) {
- set_current_state(TASK_UNINTERRUPTIBLE);
+ set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (UNLINK_TIMEOUT_JIFFIES);
dbg ("waited for %d urb completions", temp);
}
dev->wait = 0;
remove_wait_queue (&unlink_wakeup, &wait);
- if (dev->driver_info->release_private)
- dev->driver_info->release_private(dev);
-
mutex_unlock (&dev->mutex);
return 0;
}
@@ -1412,14 +1490,6 @@ static int usbnet_open (struct net_device *net)
goto done;
}
- // initialize the private resources
- if (info->initialize_private) {
- if ((retval = info->initialize_private(dev)) < 0) {
- dbg("%s: open initialize private fail", dev->net.name);
- goto done;
- }
- }
-
// insist peer be connected
if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
devdbg (dev, "can't open; %d", retval);
@@ -1429,8 +1499,10 @@ static int usbnet_open (struct net_device *net)
netif_start_queue (net);
devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",
RX_QLEN, TX_QLEN, dev->net.mtu,
- (info->flags & FLAG_FRAMING_NC)
- ? "NetChip"
+ (info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL))
+ ? ((info->flags & FLAG_FRAMING_NC)
+ ? "NetChip"
+ : "GeneSys")
: "raw"
);
@@ -1446,7 +1518,7 @@ done:
/* usb_clear_halt cannot be called in interrupt context */
static void
-tx_clear_halt(void *data)
+tx_clear_halt (void *data)
{
struct usbnet *dev = data;
@@ -1467,7 +1539,7 @@ static void tx_complete (struct urb *urb)
if (dev->ctrl_task.sync == 0) {
dev->ctrl_task.routine = tx_clear_halt;
dev->ctrl_task.data = dev;
- schedule_task(&dev->ctrl_task);
+ schedule_task (&dev->ctrl_task);
} else {
dbg ("Cannot clear TX stall");
}
@@ -1491,79 +1563,6 @@ static void usbnet_tx_timeout (struct net_device *net)
/*-------------------------------------------------------------------------*/
-static inline struct sk_buff *fixup_skb (struct sk_buff *skb, int flags)
-{
- int padlen;
- struct sk_buff *skb2;
-
- padlen = ((skb->len + sizeof (struct nc_header)
- + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
- if (!skb_cloned (skb)) {
- int headroom = skb_headroom (skb);
- int tailroom = skb_tailroom (skb);
-
- if ((padlen + sizeof (struct nc_trailer)) <= tailroom
- && sizeof (struct nc_header) <= headroom)
- return skb;
-
- if ((sizeof (struct nc_header) + padlen
- + sizeof (struct nc_trailer)) <
- (headroom + tailroom)) {
- skb->data = memmove (skb->head
- + sizeof (struct nc_header),
- skb->data, skb->len);
- skb->tail = skb->data + skb->len;
- return skb;
- }
- }
- skb2 = skb_copy_expand (skb,
- sizeof (struct nc_header),
- sizeof (struct nc_trailer) + padlen,
- flags);
- dev_kfree_skb_any (skb);
- return skb2;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_USB_GENELINK
-static struct sk_buff *gl_build_skb (struct sk_buff *skb)
-{
- struct sk_buff *skb2;
- int padlen;
-
- int headroom = skb_headroom (skb);
- int tailroom = skb_tailroom (skb);
-
-// dbg("headroom = %d, tailroom = %d", headroom, tailroom);
-
- padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
-
- if ((!skb_cloned (skb)) && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
- if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
- skb->data = memmove (skb->head + (4 + 4*1),
- skb->data, skb->len);
- skb->tail = skb->data + skb->len;
- }
- skb2 = skb;
- } else {
- skb2 = skb_copy_expand (skb, (4 + 4*1) , padlen, in_interrupt () ? GFP_ATOMIC : GFP_KERNEL);
-
- if (!skb2) {
- dbg("genelink: skb_copy_expand fail");
- return 0;
- }
-
- // free the original skb
- dev_kfree_skb_any (skb);
- }
-
- return skb2;
-}
-#endif
-
-/*-------------------------------------------------------------------------*/
-
static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
{
struct usbnet *dev = (struct usbnet *) net->priv;
@@ -1571,30 +1570,25 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
int retval = NET_XMIT_SUCCESS;
struct urb *urb = 0;
struct skb_data *entry;
- struct nc_header *header = 0;
- struct nc_trailer *trailer = 0;
struct driver_info *info = dev->driver_info;
int flags;
+#ifdef CONFIG_USB_NET1080
+ struct nc_header *header = 0;
+ struct nc_trailer *trailer = 0;
+#endif /* CONFIG_USB_NET1080 */
flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
- if (info->flags & FLAG_FRAMING_NC) {
- struct sk_buff *skb2;
- skb2 = fixup_skb (skb, flags);
- if (!skb2) {
- dbg ("can't fixup skb");
+ // some devices want funky USB-level framing, for
+ // win32 driver (usually) and/or hardware quirks
+ if (info->tx_fixup) {
+ skb = info->tx_fixup (dev, skb, flags);
+ if (!skb) {
+ dbg ("can't tx_fixup skb");
goto drop;
}
- skb = skb2;
}
-#ifdef CONFIG_USB_GENELINK
- if ((info->flags & FLAG_GENELINK) && (skb = gl_build_skb(skb)) == 0) {
- dbg("can't build skb for genelink transmit");
- goto drop;
- }
-#endif
-
if (!(urb = usb_alloc_urb (0))) {
dbg ("no urb");
goto drop;
@@ -1606,6 +1600,10 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
entry->state = tx_start;
entry->length = length;
+ // FIXME: reorganize a bit, so that fixup() fills out NetChip
+ // framing too. (Packet ID update needs the spinlock...)
+
+#ifdef CONFIG_USB_NET1080
if (info->flags & FLAG_FRAMING_NC) {
header = (struct nc_header *) skb_push (skb, sizeof *header);
header->hdr_len = cpu_to_le16 (sizeof (*header));
@@ -1613,40 +1611,12 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
if (!((skb->len + sizeof *trailer) & 0x01))
*skb_put (skb, 1) = PAD_BYTE;
trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
- }
-#ifdef CONFIG_USB_GENELINK
- else if (info->flags & FLAG_GENELINK) {
- u32 *packet_count, *packet_len;
-
- // attach the packet count to the header
- packet_count = (u32 *)skb_push(skb, (4 + 4*1));
- packet_len = packet_count + 1;
-
- // set packet to 1
- *packet_count = 1;
-
- // set packet length
- *packet_len = length;
+ } else
+#endif /* CONFIG_USB_NET1080 */
- // add padding byte
- if ((skb->len % EP_SIZE(dev)) == 0)
- skb_put(skb, 1);
- }
-#endif
- else if ((length % EP_SIZE (dev)) == 0) {
- // not all hardware behaves with USB_ZERO_PACKET,
- // so we add an extra one-byte packet
- if (skb_shared (skb)) {
- struct sk_buff *skb2;
- skb2 = skb_unshare (skb, flags);
- if (!skb2) {
- dbg ("can't unshare skb");
- goto drop;
- }
- skb = skb2;
- }
+ /* don't assume the hardware handles USB_ZERO_PACKET */
+ if ((length % EP_SIZE (dev)) == 0)
skb->len++;
- }
FILL_BULK_URB (urb, dev->udev,
usb_sndbulkpipe (dev->udev, info->out),
@@ -1658,6 +1628,8 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
// FIXME urb->timeout = ... jiffies ... ;
spin_lock_irqsave (&dev->txq.lock, flags);
+
+#ifdef CONFIG_USB_NET1080
if (info->flags & FLAG_FRAMING_NC) {
header->packet_id = cpu_to_le16 (dev->packet_id++);
put_unaligned (header->packet_id, &trailer->packet_id);
@@ -1667,6 +1639,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
header->packet_id);
#endif
}
+#endif /* CONFIG_USB_NET1080 */
netif_stop_queue (net);
if ((retval = usb_submit_urb (urb)) != 0) {
@@ -1685,7 +1658,8 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
drop:
retval = NET_XMIT_DROP;
dev->stats.tx_dropped++;
- dev_kfree_skb_any (skb);
+ if (skb)
+ dev_kfree_skb_any (skb);
usb_free_urb (urb);
#ifdef VERBOSE
} else {
@@ -1911,6 +1885,13 @@ static const struct usb_device_id products [] = {
},
#endif
+#ifdef CONFIG_USB_GENESYS
+{
+ USB_DEVICE (0x05e3, 0x0502), // GL620USB-A
+ driver_info: (unsigned long) &genelink_info,
+},
+#endif
+
#ifdef CONFIG_USB_LINUXDEV
/*
* for example, this can be a host side talk-to-PDA driver.
@@ -1944,12 +1925,7 @@ static const struct usb_device_id products [] = {
},
#endif
-#ifdef CONFIG_USB_GENELINK
-{
- USB_DEVICE (0x05e3, 0x0502), // GL620USB-A
- driver_info: (unsigned long) &genelink_info,
-},
-#endif
+/* KC2190 from www.sepoong.co.kr "InstaNET" */
{ }, // END
};
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b61910674788..485e0bffed80 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -113,6 +113,11 @@ static int blkdev_get_block(struct inode * inode, long iblock, struct buffer_hea
return 0;
}
+static int blkdev_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
+{
+ return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, blkdev_get_block);
+}
+
static int blkdev_writepage(struct page * page)
{
return block_write_full_page(page, blkdev_get_block);
@@ -640,6 +645,7 @@ struct address_space_operations def_blk_aops = {
sync_page: block_sync_page,
prepare_write: blkdev_prepare_write,
commit_write: blkdev_commit_write,
+ direct_IO: blkdev_direct_IO,
};
struct file_operations def_blk_fops = {
diff --git a/fs/buffer.c b/fs/buffer.c
index fc7638503437..e0ba7b3d077b 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1172,6 +1172,7 @@ struct buffer_head * bread(kdev_t dev, int block, int size)
struct buffer_head * bh;
bh = getblk(dev, block, size);
+ touch_buffer(bh);
if (buffer_uptodate(bh))
return bh;
ll_rw_block(READ, 1, &bh);
@@ -1997,6 +1998,47 @@ int generic_block_bmap(struct address_space *mapping, long block, get_block_t *g
return tmp.b_blocknr;
}
+int generic_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize, get_block_t * get_block)
+{
+ int i, nr_blocks, retval;
+ unsigned long * blocks = iobuf->blocks;
+
+ nr_blocks = iobuf->length / blocksize;
+ /* build the blocklist */
+ for (i = 0; i < nr_blocks; i++, blocknr++) {
+ struct buffer_head bh;
+
+ bh.b_state = 0;
+ bh.b_dev = inode->i_dev;
+ bh.b_size = blocksize;
+
+ retval = get_block(inode, blocknr, &bh, rw == READ ? 0 : 1);
+ if (retval)
+ goto out;
+
+ if (rw == READ) {
+ if (buffer_new(&bh))
+ BUG();
+ if (!buffer_mapped(&bh)) {
+ /* there was an hole in the filesystem */
+ blocks[i] = -1UL;
+ continue;
+ }
+ } else {
+ if (buffer_new(&bh))
+ unmap_underlying_metadata(&bh);
+ if (!buffer_mapped(&bh))
+ BUG();
+ }
+ blocks[i] = bh.b_blocknr;
+ }
+
+ retval = brw_kiovec(rw, 1, &iobuf, inode->i_dev, iobuf->blocks, blocksize);
+
+ out:
+ return retval;
+}
+
/*
* IO completion routine for a buffer_head being used for kiobuf IO: we
* can't dispatch the kiobuf callback until io_count reaches 0.
@@ -2350,10 +2392,13 @@ static int grow_buffers(kdev_t dev, unsigned long block, int size)
unsigned long index;
int sizebits;
- if ((size & 511) || (size > PAGE_SIZE)) {
- printk(KERN_ERR "VFS: grow_buffers: size = %d\n",size);
- return 0;
- }
+ /* Size must be multiple of hard sectorsize */
+ if (size & (get_hardsect_size(dev)-1))
+ BUG();
+ /* Size must be within 512 bytes and PAGE_SIZE */
+ if (size < 512 || size > PAGE_SIZE)
+ BUG();
+
sizebits = -1;
do {
sizebits++;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 8e138cc9a2ad..45eeaa675c46 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -592,13 +592,18 @@ static int ext2_bmap(struct address_space *mapping, long block)
{
return generic_block_bmap(mapping,block,ext2_get_block);
}
+static int ext2_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
+{
+ return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, ext2_get_block);
+}
struct address_space_operations ext2_aops = {
readpage: ext2_readpage,
writepage: ext2_writepage,
sync_page: block_sync_page,
prepare_write: ext2_prepare_write,
commit_write: generic_commit_write,
- bmap: ext2_bmap
+ bmap: ext2_bmap,
+ direct_IO: ext2_direct_IO,
};
/*
diff --git a/fs/inode.c b/fs/inode.c
index 5e2d697efa6c..42d13e7afcf0 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -571,8 +571,7 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru
continue;
invalidate_inode_buffers(inode);
if (!atomic_read(&inode->i_count)) {
- list_del(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_hash);
+ list_del_init(&inode->i_hash);
list_del(&inode->i_list);
list_add(&inode->i_list, dispose);
inode->i_state |= I_FREEING;
@@ -1029,13 +1028,14 @@ void remove_inode_hash(struct inode *inode)
void iput(struct inode *inode)
{
if (inode) {
+ struct super_block *sb = inode->i_sb;
struct super_operations *op = NULL;
if (inode->i_state == I_CLEAR)
BUG();
- if (inode->i_sb && inode->i_sb->s_op)
- op = inode->i_sb->s_op;
+ if (sb && sb->s_op)
+ op = sb->s_op;
if (op && op->put_inode)
op->put_inode(inode);
@@ -1065,7 +1065,7 @@ void iput(struct inode *inode)
if (inode->i_state != I_CLEAR)
BUG();
} else {
- if (!list_empty(&inode->i_hash)) {
+ if (!list_empty(&inode->i_hash) && sb && sb->s_root) {
if (!(inode->i_state & (I_DIRTY|I_LOCK))) {
list_del(&inode->i_list);
list_add(&inode->i_list, &inode_unused);
@@ -1074,9 +1074,8 @@ void iput(struct inode *inode)
spin_unlock(&inode_lock);
return;
} else {
- /* magic nfs path */
- list_del(&inode->i_list);
- INIT_LIST_HEAD(&inode->i_list);
+ list_del_init(&inode->i_list);
+ list_del_init(&inode->i_hash);
inode->i_state|=I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile
index af4bdcbf322d..a52020c22ed5 100644
--- a/fs/reiserfs/Makefile
+++ b/fs/reiserfs/Makefile
@@ -13,13 +13,13 @@ lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o res
obj-m := $(O_TARGET)
-# gcc -O2 (the kernel default) is overaggressive on ppc when many inline
+# gcc -O2 (the kernel default) is overaggressive on ppc32 when many inline
# functions are used. This causes the compiler to advance the stack
# pointer out of the available stack space, corrupting kernel space,
-# and causing a panic. Since this behavior only affects ppc, this ifeq
+# and causing a panic. Since this behavior only affects ppc32, this ifeq
# will work around it. If any other architecture displays this behavior,
# add it here.
-ifeq ($(shell uname -m),ppc)
+ifeq ($(CONFIG_PPC32),y)
EXTRA_CFLAGS := -O1
endif
diff --git a/fs/super.c b/fs/super.c
index 9df5268060b3..c74d32726726 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -739,6 +739,7 @@ void kill_super(struct super_block *sb)
dput(root);
fsync_super(sb);
lock_super(sb);
+ invalidate_inodes(sb); /* bad name - it should be evict_inodes() */
if (sop) {
if (sop->write_super && sb->s_dirt)
sop->write_super(sb);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 9dbef2980770..cdb196ca50fb 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -195,11 +195,15 @@ extern void drive_stat_acct (kdev_t dev, int rw,
static inline int get_hardsect_size(kdev_t dev)
{
- extern int *hardsect_size[];
- if (hardsect_size[MAJOR(dev)] != NULL)
- return hardsect_size[MAJOR(dev)][MINOR(dev)];
- else
- return 512;
+ int retval = 512;
+ int major = MAJOR(dev);
+
+ if (hardsect_size[major]) {
+ int minor = MINOR(dev);
+ if (hardsect_size[major][minor])
+ retval = hardsect_size[major][minor];
+ }
+ return retval;
}
#define blk_finished_io(nsects) do { } while (0)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f170f9e036ec..867aa6ce8f5b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1386,6 +1386,7 @@ extern int block_sync_page(struct page *);
int generic_block_bmap(struct address_space *, long, get_block_t *);
int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
int block_truncate_page(struct address_space *, loff_t, get_block_t *);
+extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *);
extern int waitfor_one_page(struct page*);
extern int generic_file_mmap(struct file *, struct vm_area_struct *);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7737d585b0a2..5a85039279b0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -416,6 +416,7 @@ extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long d
extern int ptrace_attach(struct task_struct *tsk);
extern int ptrace_detach(struct task_struct *, unsigned int);
extern void ptrace_disable(struct task_struct *);
+extern int ptrace_check_attach(struct task_struct *task, int kill);
/*
* On a two-level page table, this ends up being trivial. Thus the
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9cdc5e05d025..97c574fe85d2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -304,8 +304,16 @@ struct task_struct {
long nice;
unsigned long policy;
struct mm_struct *mm;
- int has_cpu, processor;
- unsigned long cpus_allowed;
+ int processor;
+ /*
+ * cpus_runnable is ~0 if the process is not running on any
+ * CPU. It's (1 << cpu) if it's running on a CPU. This mask
+ * is updated under the runqueue lock.
+ *
+ * To determine whether a process might run on a CPU, this
+ * mask is AND-ed with cpus_allowed.
+ */
+ unsigned long cpus_runnable, cpus_allowed;
/*
* (only the 'next' pointer fits into the cacheline, but
* that's just fine.)
@@ -464,6 +472,7 @@ extern struct exec_domain default_exec_domain;
policy: SCHED_OTHER, \
mm: NULL, \
active_mm: &init_mm, \
+ cpus_runnable: -1, \
cpus_allowed: -1, \
run_list: LIST_HEAD_INIT(tsk.run_list), \
next_task: &tsk, \
@@ -541,6 +550,19 @@ static inline struct task_struct *find_task_by_pid(int pid)
return p;
}
+#define task_has_cpu(tsk) ((tsk)->cpus_runnable != ~0UL)
+
+static inline void task_set_cpu(struct task_struct *tsk, unsigned int cpu)
+{
+ tsk->processor = cpu;
+ tsk->cpus_runnable = 1UL << cpu;
+}
+
+static inline void task_release_cpu(struct task_struct *tsk)
+{
+ tsk->cpus_runnable = ~0UL;
+}
+
/* per-UID process charging. */
extern struct user_struct * alloc_uid(uid_t);
extern void free_uid(struct user_struct *);
diff --git a/kernel/exit.c b/kernel/exit.c
index 708cad8597f5..2650ac328e4a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -35,13 +35,13 @@ static void release_task(struct task_struct * p)
*/
for (;;) {
task_lock(p);
- if (!p->has_cpu)
+ if (!task_has_cpu(p))
break;
task_unlock(p);
do {
cpu_relax();
barrier();
- } while (p->has_cpu);
+ } while (task_has_cpu(p));
}
task_unlock(p);
#endif
diff --git a/kernel/fork.c b/kernel/fork.c
index 91aeda9ef591..3c28fc2a9777 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -638,7 +638,7 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
#ifdef CONFIG_SMP
{
int i;
- p->has_cpu = 0;
+ p->cpus_runnable = ~0UL;
p->processor = current->processor;
/* ?? should we just memset this ?? */
for(i = 0; i < smp_num_cpus; i++)
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 6ecd30f3d323..bd2d762baf94 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -199,6 +199,7 @@ EXPORT_SYMBOL(submit_bh);
EXPORT_SYMBOL(unlock_buffer);
EXPORT_SYMBOL(__wait_on_buffer);
EXPORT_SYMBOL(___wait_on_page);
+EXPORT_SYMBOL(generic_direct_IO);
EXPORT_SYMBOL(block_write_full_page);
EXPORT_SYMBOL(block_read_full_page);
EXPORT_SYMBOL(block_prepare_write);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b9cf12d4c02d..da45fa2be7a3 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -16,6 +16,42 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
+/*
+ * Check that we have indeed attached to the thing..
+ */
+int ptrace_check_attach(struct task_struct *child, int kill)
+{
+ if (!(child->ptrace & PT_PTRACED))
+ return -ESRCH;
+
+ if (child->p_pptr != current)
+ return -ESRCH;
+
+ if (!kill) {
+ if (child->state != TASK_STOPPED)
+ return -ESRCH;
+#ifdef CONFIG_SMP
+ /* Make sure the child gets off its CPU.. */
+ for (;;) {
+ task_lock(child);
+ if (!task_has_cpu(child))
+ break;
+ task_unlock(child);
+ do {
+ if (child->state != TASK_STOPPED)
+ return -ESRCH;
+ barrier();
+ cpu_relax();
+ } while (task_has_cpu(child));
+ }
+ task_unlock(child);
+#endif
+ }
+
+ /* All systems go.. */
+ return 0;
+}
+
int ptrace_attach(struct task_struct *task)
{
task_lock(task);
diff --git a/kernel/sched.c b/kernel/sched.c
index 11de5d6951a9..db3e42f74c42 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -28,6 +28,7 @@
#include <linux/kernel_stat.h>
#include <linux/completion.h>
#include <linux/prefetch.h>
+#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -114,8 +115,8 @@ extern struct task_struct *child_reaper;
#ifdef CONFIG_SMP
#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)])
-#define can_schedule(p,cpu) ((!(p)->has_cpu) && \
- ((p)->cpus_allowed & (1 << cpu)))
+#define can_schedule(p,cpu) \
+ ((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu))
#else
@@ -455,11 +456,11 @@ static inline void __schedule_tail(struct task_struct *prev)
/*
* prev->policy can be written from here only before `prev'
- * can be scheduled (before setting prev->has_cpu to zero).
+ * can be scheduled (before setting prev->cpus_runnable to ~0UL).
* Of course it must also be read before allowing prev
* to be rescheduled, but since the write depends on the read
* to complete, wmb() is enough. (the spin_lock() acquired
- * before setting has_cpu is not enough because the spin_lock()
+ * before setting cpus_runnable is not enough because the spin_lock()
* common code semantics allows code outside the critical section
* to enter inside the critical section)
*/
@@ -468,12 +469,12 @@ static inline void __schedule_tail(struct task_struct *prev)
wmb();
/*
- * fast path falls through. We have to clear has_cpu before
- * checking prev->state to avoid a wakeup race - thus we
- * also have to protect against the task exiting early.
+ * fast path falls through. We have to clear cpus_runnable before
+ * checking prev->state to avoid a wakeup race. Protect against
+ * the task exiting early.
*/
task_lock(prev);
- prev->has_cpu = 0;
+ task_release_cpu(prev);
mb();
if (prev->state == TASK_RUNNING)
goto needs_resched;
@@ -505,7 +506,7 @@ needs_resched:
goto out_unlock;
spin_lock_irqsave(&runqueue_lock, flags);
- if ((prev->state == TASK_RUNNING) && !prev->has_cpu)
+ if ((prev->state == TASK_RUNNING) && !task_has_cpu(prev))
reschedule_idle(prev);
spin_unlock_irqrestore(&runqueue_lock, flags);
goto out_unlock;
@@ -545,8 +546,10 @@ need_resched_back:
prev = current;
this_cpu = prev->processor;
- if (in_interrupt())
- goto scheduling_in_interrupt;
+ if (unlikely(in_interrupt())) {
+ printk("Scheduling in interrupt\n");
+ BUG();
+ }
release_kernel_lock(prev, this_cpu);
@@ -559,9 +562,11 @@ need_resched_back:
spin_lock_irq(&runqueue_lock);
/* move an exhausted RR process to be last.. */
- if (prev->policy == SCHED_RR)
- goto move_rr_last;
-move_rr_back:
+ if (unlikely(prev->policy == SCHED_RR))
+ if (!prev->counter) {
+ prev->counter = NICE_TO_TICKS(prev->nice);
+ move_last_runqueue(prev);
+ }
switch (prev->state) {
case TASK_INTERRUPTIBLE:
@@ -585,10 +590,6 @@ repeat_schedule:
*/
next = idle_task(this_cpu);
c = -1000;
- if (prev->state == TASK_RUNNING)
- goto still_running;
-
-still_running_back:
list_for_each(tmp, &runqueue_head) {
p = list_entry(tmp, struct task_struct, run_list);
if (can_schedule(p, this_cpu)) {
@@ -599,21 +600,28 @@ still_running_back:
}
/* Do we need to re-calculate counters? */
- if (!c)
- goto recalculate;
+ if (unlikely(!c)) {
+ struct task_struct *p;
+
+ spin_unlock_irq(&runqueue_lock);
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
+ read_unlock(&tasklist_lock);
+ spin_lock_irq(&runqueue_lock);
+ goto repeat_schedule;
+ }
+
/*
* from this point on nothing can prevent us from
* switching to the next task, save this fact in
* sched_data.
*/
sched_data->curr = next;
-#ifdef CONFIG_SMP
- next->has_cpu = 1;
- next->processor = this_cpu;
-#endif
+ task_set_cpu(next, this_cpu);
spin_unlock_irq(&runqueue_lock);
- if (prev == next) {
+ if (unlikely(prev == next)) {
/* We won't go through the normal tail, so do this by hand */
prev->policy &= ~SCHED_YIELD;
goto same_process;
@@ -678,38 +686,6 @@ same_process:
reacquire_kernel_lock(current);
if (current->need_resched)
goto need_resched_back;
-
- return;
-
-recalculate:
- {
- struct task_struct *p;
- spin_unlock_irq(&runqueue_lock);
- read_lock(&tasklist_lock);
- for_each_task(p)
- p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
- read_unlock(&tasklist_lock);
- spin_lock_irq(&runqueue_lock);
- }
- goto repeat_schedule;
-
-still_running:
- if (!(prev->cpus_allowed & (1UL << this_cpu)))
- goto still_running_back;
- c = goodness(prev, this_cpu, prev->active_mm);
- next = prev;
- goto still_running_back;
-
-move_rr_last:
- if (!prev->counter) {
- prev->counter = NICE_TO_TICKS(prev->nice);
- move_last_runqueue(prev);
- }
- goto move_rr_back;
-
-scheduling_in_interrupt:
- printk("Scheduling in interrupt\n");
- BUG();
return;
}
@@ -1072,6 +1048,10 @@ asmlinkage long sys_sched_yield(void)
if (current->policy == SCHED_OTHER)
current->policy |= SCHED_YIELD;
current->need_resched = 1;
+
+ spin_lock_irq(&runqueue_lock);
+ move_last_runqueue(current);
+ spin_unlock_irq(&runqueue_lock);
}
return 0;
}
@@ -1176,13 +1156,10 @@ static void show_task(struct task_struct * p)
else
printk(" (NOTLB)\n");
-#if defined(CONFIG_X86) || defined(CONFIG_SPARC64) || defined(CONFIG_ARM) || defined(CONFIG_ALPHA)
-/* This is very useful, but only works on ARM, x86 and sparc64 right now */
{
extern void show_trace_task(struct task_struct *tsk);
show_trace_task(p);
}
-#endif
}
char * render_sigset_t(sigset_t *set, char *buffer)
diff --git a/kernel/signal.c b/kernel/signal.c
index 7f4d2e71c751..44acecd851c7 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -479,7 +479,7 @@ static inline void signal_wake_up(struct task_struct *t)
* other than doing an extra (lightweight) IPI interrupt.
*/
spin_lock(&runqueue_lock);
- if (t->has_cpu && t->processor != smp_processor_id())
+ if (task_has_cpu(t) && t->processor != smp_processor_id())
smp_send_reschedule(t->processor);
spin_unlock(&runqueue_lock);
#endif /* CONFIG_SMP */
diff --git a/mm/filemap.c b/mm/filemap.c
index 1e2665a20f52..16f8da3d64af 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -555,8 +555,13 @@ int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsig
*/
int fail_writepage(struct page *page)
{
- activate_page(page);
- SetPageReferenced(page);
+ /* Only activate on memory-pressure, not fsync.. */
+ if (PageLaunder(page)) {
+ activate_page(page);
+ SetPageReferenced(page);
+ }
+
+ /* Set the page dirty again, unlock */
SetPageDirty(page);
UnlockPage(page);
return 0;
@@ -1476,6 +1481,87 @@ no_cached_page:
UPDATE_ATIME(inode);
}
+static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, size_t count, loff_t offset)
+{
+ ssize_t retval;
+ int new_iobuf, chunk_size, blocksize_mask, blocksize, blocksize_bits, iosize, progress;
+ struct kiobuf * iobuf;
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct address_space * mapping = inode->i_mapping;
+
+ new_iobuf = 0;
+ iobuf = filp->f_iobuf;
+ if (test_and_set_bit(0, &filp->f_iobuf_lock)) {
+ /*
+ * A parallel read/write is using the preallocated iobuf
+ * so just run slow and allocate a new one.
+ */
+ retval = alloc_kiovec(1, &iobuf);
+ if (retval)
+ goto out;
+ new_iobuf = 1;
+ }
+
+ blocksize = 1 << inode->i_blkbits;
+ blocksize_bits = inode->i_blkbits;
+ blocksize_mask = blocksize - 1;
+ chunk_size = KIO_MAX_ATOMIC_IO << 10;
+
+ retval = -EINVAL;
+ if ((offset & blocksize_mask) || (count & blocksize_mask))
+ goto out_free;
+ if (!mapping->a_ops->direct_IO)
+ goto out_free;
+
+ /*
+ * Flush to disk exlusively the _data_, metadata must remains
+ * completly asynchronous or performance will go to /dev/null.
+ */
+ filemap_fdatasync(mapping);
+ retval = fsync_inode_data_buffers(inode);
+ filemap_fdatawait(mapping);
+ if (retval < 0)
+ goto out_free;
+
+ progress = retval = 0;
+ while (count > 0) {
+ iosize = count;
+ if (iosize > chunk_size)
+ iosize = chunk_size;
+
+ retval = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize);
+ if (retval)
+ break;
+
+ retval = mapping->a_ops->direct_IO(rw, inode, iobuf, (offset+progress) >> blocksize_bits, blocksize);
+
+ if (rw == READ && retval > 0)
+ mark_dirty_kiobuf(iobuf, retval);
+
+ if (retval >= 0) {
+ count -= retval;
+ buf += retval;
+ progress += retval;
+ }
+
+ unmap_kiobuf(iobuf);
+
+ if (retval != iosize)
+ break;
+ }
+
+ if (progress)
+ retval = progress;
+
+ out_free:
+ if (!new_iobuf)
+ clear_bit(0, &filp->f_iobuf_lock);
+ else
+ free_kiovec(1, &iobuf);
+ out:
+ return retval;
+}
+
int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
{
char *kaddr;
@@ -1509,6 +1595,9 @@ ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *
if ((ssize_t) count < 0)
return -EINVAL;
+ if (filp->f_flags & O_DIRECT)
+ goto o_direct;
+
retval = -EFAULT;
if (access_ok(VERIFY_WRITE, buf, count)) {
retval = 0;
@@ -1527,7 +1616,29 @@ ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *
retval = desc.error;
}
}
+ out:
return retval;
+
+ o_direct:
+ {
+ loff_t pos = *ppos, size;
+ struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
+ struct inode *inode = mapping->host;
+
+ retval = 0;
+ if (!count)
+ goto out; /* skip atime */
+ size = inode->i_size;
+ if (pos < size) {
+ if (pos + count > size)
+ count = size - pos;
+ retval = generic_file_direct_IO(READ, filp, buf, count, pos);
+ if (retval > 0)
+ *ppos = pos + retval;
+ }
+ UPDATE_ATIME(filp->f_dentry->d_inode);
+ goto out;
+ }
}
static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size)
@@ -2765,7 +2876,8 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos)
written = 0;
- if (file->f_flags & O_APPEND)
+ /* FIXME: this is for backwards compatibility with 2.4 */
+ if (!S_ISBLK(inode->i_mode) && file->f_flags & O_APPEND)
pos = inode->i_size;
/*
@@ -2845,6 +2957,9 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos)
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty_sync(inode);
+ if (file->f_flags & O_DIRECT)
+ goto o_direct;
+
do {
unsigned long index, offset;
long page_fault;
@@ -2921,6 +3036,7 @@ unlock:
status = generic_osync_inode(inode, OSYNC_METADATA|OSYNC_DATA);
}
+out_status:
err = written ? written : status;
out:
@@ -2929,6 +3045,25 @@ out:
fail_write:
status = -EFAULT;
goto unlock;
+
+o_direct:
+ written = generic_file_direct_IO(WRITE, file, (char *) buf, count, pos);
+ if (written > 0) {
+ loff_t end = pos + written;
+ if (end > inode->i_size && !S_ISBLK(inode->i_mode)) {
+ inode->i_size = end;
+ mark_inode_dirty(inode);
+ }
+ *ppos = end;
+ invalidate_inode_pages2(mapping);
+ }
+ /*
+ * Sync the fs metadata but not the minor inode changes and
+ * of course not the data as we did direct DMA for the IO.
+ */
+ if (written >= 0 && file->f_flags & O_SYNC)
+ status = generic_osync_inode(inode, OSYNC_METADATA);
+ goto out_status;
}
void __init page_cache_init(unsigned long mempages)
diff --git a/mm/shmem.c b/mm/shmem.c
index 63e6838976c7..ddcac7a48a93 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -428,6 +428,8 @@ static int shmem_writepage(struct page * page)
if (!PageLocked(page))
BUG();
+ if (!PageLaunder(page))
+ return fail_writepage(page);
mapping = page->mapping;
index = page->index;