Commit bef89866 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.11pre5

parent fdf53efc
......@@ -88,6 +88,9 @@ SVGA_MODE= -DSVGA_MODE=NORMAL_VGA
CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
# use '-fno-strict-aliasing', but only if the compiler can take it
CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
ifdef CONFIG_SMP
CFLAGS += -D__SMP__
AFLAGS += -D__SMP__
......
......@@ -12,6 +12,9 @@
#
# Copyright (C) 1994 by Linus Torvalds
#
# 19990713 Artur Skawina <skawina@geocities.com>
# Added '-march' and '-mpreferred-stack-boundary' support
#
LD=$(CROSS_COMPILE)ld -m elf_i386
CPP=$(CC) -E
......@@ -23,6 +26,9 @@ CFLAGS_PIPE := -pipe
CFLAGS_NSR := -fno-strength-reduce
CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
# prevent gcc from keeping the stack 16 byte aligned
CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
ifdef CONFIG_M386
CFLAGS := $(CFLAGS) -m386 -DCPU=386
AFLAGS := $(AFLAGS) -DCPU=386
......@@ -30,21 +36,25 @@ endif
ifdef CONFIG_M486
CFLAGS := $(CFLAGS) -m486 -DCPU=486
CFLAGS += $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i486"; fi)
AFLAGS := $(AFLAGS) -DCPU=486
endif
ifdef CONFIG_M586
CFLAGS := $(CFLAGS) -DCPU=586
CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi)
AFLAGS := $(AFLAGS) -DCPU=586
endif
ifdef CONFIG_M586TSC
CFLAGS := $(CFLAGS) -DCPU=586
CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi)
AFLAGS := $(AFLAGS) -DCPU=586
endif
ifdef CONFIG_M686
CFLAGS := $(CFLAGS) -DCPU=686
CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
AFLAGS := $(AFLAGS) -DCPU=686
endif
......
......@@ -930,17 +930,21 @@ void free_irq(unsigned int irq, void *dev_id)
if (action->dev_id != dev_id)
continue;
/* Found it - now free it */
/* Found it - now remove it from the list of entries */
*p = action->next;
kfree(action);
if (!irq_desc[irq].action) {
irq_desc[irq].status |= IRQ_DISABLED;
irq_desc[irq].handler->shutdown(irq);
}
goto out;
spin_unlock_irqrestore(&irq_controller_lock,flags);
/* Wait to make sure it's not being used on another CPU */
while (irq_desc[irq].status & IRQ_INPROGRESS)
barrier();
kfree(action);
return;
}
printk("Trying to free free IRQ%d\n",irq);
out:
spin_unlock_irqrestore(&irq_controller_lock,flags);
}
......
......@@ -30,7 +30,6 @@ void (*kbd_reset_setup) (char *, int) __initdata = 0;
#include <linux/kd.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
......
......@@ -50,7 +50,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/gg2.h>
#include <asm/cache.h>
#include <asm/prom.h>
......
......@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/openpic.h>
#include <asm/processor.h>
......
......@@ -107,7 +107,6 @@
#include <asm/system.h>
#include <asm/signal.h>
#include <asm/system.h>
#include <asm/kgdb.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
......
......@@ -40,7 +40,6 @@
#include <asm/residual.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <linux/ide.h>
#include <asm/ide.h>
#include <asm/cache.h>
#include <asm/dma.h>
......
......@@ -32,7 +32,6 @@
#endif
#include <asm/bootx.h>
#include <asm/machdep.h>
#include <asm/ide.h>
extern void pmac_init(unsigned long r3,
unsigned long r4,
......
......@@ -2124,20 +2124,23 @@ int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
msf.cdmsf_frame0);
/* Make sure the TOC is up to date. */
if (cmd != CDROMREADRAW) {
stat = cdrom_read_toc (drive, NULL);
if (stat) return stat;
if (stat)
return stat;
toc = info->toc;
if (lba < 0 || lba >= toc->capacity)
return -EINVAL;
}
buf = (char *) kmalloc (blocksize, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize,
NULL);
stat = cdrom_read_block (drive, format, lba, 1, buf,
blocksize, NULL);
if (stat == 0) {
if (cmd == CDROMREADMODE2) {
......
......@@ -60,35 +60,44 @@ struct notifier_block idepmac_sleep_notifier = {
* N.B. this can't be an initfunc, because the media-bay task can
* call ide_[un]register at any time.
*/
void pmac_ide_init_hwif_ports ( hw_regs_t *hw,
ide_ioreg_t data_port,
ide_ioreg_t ctrl_port,
void pmac_ide_init_hwif_ports(hw_regs_t *hw,
ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
int *irq)
{
int i, r;
int i, ix;
if (data_port == 0)
return;
for (ix = 0; ix < MAX_HWIFS; ++ix)
if (data_port == pmac_ide_regbase[ix])
break;
if (ix >= MAX_HWIFS) {
/* Probably a PCI interface... */
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
/* XXX is this right? */
hw->io_ports[IDE_CONTROL_OFFSET] = 0;
if (irq != 0)
*irq = 0;
return;
}
/* we check only for -EINVAL meaning that we have found a matching
bay but with the wrong device type */
r = check_media_bay_by_base(data_port, MB_CD);
if (r == -EINVAL)
i = check_media_bay_by_base(data_port, MB_CD);
if (i == -EINVAL) {
hw->io_ports[IDE_DATA_OFFSET] = 0;
return;
}
for ( i = 0; i < 8 ; ++i )
for (i = 0; i < 8; ++i)
hw->io_ports[i] = data_port + i * 0x10;
hw->io_ports[8] = data_port + 0x160;
if (irq != NULL) {
*irq = 0;
for (i = 0; i < MAX_HWIFS; ++i) {
if (data_port == pmac_ide_regbase[i]) {
*irq = pmac_ide_irq[i];
break;
}
}
}
if (irq != NULL)
*irq = pmac_ide_irq[ix];
}
void pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
......@@ -100,10 +109,10 @@ void pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
pio = ide_get_best_pio_mode(drive, pio, 4, &d);
switch (pio) {
case 4:
out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x211025);
out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025);
break;
default:
out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x2f8526);
out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526);
break;
}
}
......@@ -145,13 +154,35 @@ __initfunc(void pmac_ide_probe(void))
*pp = removables;
for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
struct device_node *tp;
/*
* If this node is not under a mac-io or dbdma node,
* leave it to the generic PCI driver.
*/
for (tp = np->parent; tp != 0; tp = tp->parent)
if (tp->type && (strcmp(tp->type, "mac-io") == 0
|| strcmp(tp->type, "dbdma") == 0))
break;
if (tp == 0)
continue;
if (np->n_addrs == 0) {
printk(KERN_WARNING "ide: no address for device %s\n",
np->full_name);
continue;
}
base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
/*
* If this slot is taken (e.g. by ide-pci.c) try the next one.
*/
while (i < MAX_HWIFS
&& ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
++i;
if (i >= MAX_HWIFS)
break;
base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE;
/* XXX This is bogus. Should be fixed in the registry by checking
the kind of host interrupt controller, a bit like gatwick
......
......@@ -1145,7 +1145,9 @@ int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0));
strcpy(cdrom_drive_info+pos,"\n\n");
*lenp=pos+3;
pos += 3;
if (*lenp > pos)
*lenp = pos;
return proc_dostring(ctl, write, filp, buffer, lenp);
}
......
......@@ -38,7 +38,9 @@
#ifdef __powerpc__
#include <asm/processor.h>
#endif
#ifdef __mc68000__
#include <asm/setup.h>
#endif
static struct mouse_status mouse;
static unsigned char adb_mouse_buttons[16];
......@@ -242,7 +244,7 @@ static struct miscdevice adb_mouse = {
ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
};
int __init adb_mouse_init(void)
__initfunc(int adb_mouse_init(void))
{
mouse.active = 0;
mouse.ready = 0;
......@@ -268,7 +270,7 @@ int __init adb_mouse_init(void)
* option, which is about using ADB keyboard buttons to emulate
* mouse buttons. -- paulus
*/
void __init adb_mouse_setup(char *str, int *ints)
__initfunc(void adb_mouse_setup(char *str, int *ints))
{
if (ints[0] >= 1) {
adb_emulate_buttons = ints[1] > 0;
......@@ -280,6 +282,7 @@ void __init adb_mouse_setup(char *str, int *ints)
}
#ifdef MODULE
#include <asm/setup.h>
int init_module(void)
{
......
This diff is collapsed.
......@@ -14,7 +14,7 @@
* a subset of the standard printer control lines connected.
*/
#include <linux/tasks.h>
#include <linux/threads.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
......
......@@ -11,7 +11,7 @@
*/
#include <linux/config.h>
#include <linux/tasks.h>
#include <linux/threads.h>
#include <linux/parport.h>
#include <linux/delay.h>
#include <linux/kernel.h>
......
......@@ -10,7 +10,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tasks.h>
#include <linux/threads.h>
#include <linux/parport.h>
#include <linux/errno.h>
......
......@@ -314,8 +314,7 @@ void parport_pc_data_reverse (struct parport *p)
void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
{
struct parport_pc_private *priv = dev->port->physport->private_data;
priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
s->u.pc.ecr = 0x24;
}
......@@ -1377,7 +1376,8 @@ static int __init programmable_irq_support(struct parport *pb)
static int __init irq_probe_ECP(struct parport *pb)
{
int irqs, i;
int i;
unsigned long irqs;
sti();
irqs = probe_irq_on();
......
......@@ -15,7 +15,7 @@
#include <linux/config.h>
#include <linux/string.h>
#include <linux/tasks.h>
#include <linux/threads.h>
#include <linux/parport.h>
#include <linux/delay.h>
#include <linux/errno.h>
......
......@@ -121,8 +121,6 @@ typedef struct enet_statistics hp100_stats_t;
#ifndef __initfunc
#define __initfunc(__initarg) __initarg
#else
#include <linux/init.h>
#endif
#include "hp100.h"
......
......@@ -682,8 +682,10 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++mp->stats.tx_carrier_errors;
if (fs & (UFLO|LCOL|RTRY))
++mp->stats.tx_aborted_errors;
} else
} else {
mp->stats.tx_bytes += mp->tx_bufs[i]->len;
++mp->stats.tx_packets;
}
dev_kfree_skb(mp->tx_bufs[i]);
--mp->tx_active;
if (++i >= N_TX_RING)
......@@ -848,6 +850,7 @@ static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
mp->rx_bufs[i] = 0;
mp->stats.rx_bytes += skb->len;
++mp->stats.rx_packets;
}
} else {
......
......@@ -680,6 +680,7 @@ rtl8129_open(struct device *dev)
tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
free_irq(dev->irq, dev);
if (tp->tx_bufs)
kfree(tp->tx_bufs);
if (rtl8129_debug > 0)
......
......@@ -70,8 +70,8 @@ struct awacs_regs {
#define MASK_GAINMIC (0x0 << 8) /* Change Gain for Mic??? */
#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */
#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */
#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */
#define MASK_MUX_AUDIN (0x1 << 10) /* Select Audio In in MUX */
#define MASK_MUX_MIC (0x1 << 11) /* Select Mic in MUX */
#define MASK_MUX_LINE MASK_MUX_AUDIN
#define GAINRIGHT(x) ((x) & MASK_GAINRIGHT)
......
This diff is collapsed.
......@@ -34,6 +34,7 @@ if [ ! "$CONFIG_USB" = "n" ]; then
if [ "$CONFIG_USB_SCSI" != "n" ]; then
dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
fi
dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
fi
endmenu
......@@ -116,6 +116,15 @@ ifeq ($(CONFIG_USB_SCSI),y)
endif
endif
ifeq ($(CONFIG_USB_EZUSB),y)
L_OBJS += ezusb.o
endif
ifeq ($(CONFIG_USB_EZUSB),m)
M_OBJS += ezusb.o
MIX_OBJS += ezusb.o
endif
include $(TOPDIR)/Rules.make
keymap.o: keymap.c
......
This diff is collapsed.
/*****************************************************************************/
/*
* ezusb.h -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers.
*
* Copyright (C) 1999
* Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*****************************************************************************/
#ifndef _LINUX_EZUSB_H
#define _LINUX_EZUSB_H
#include <linux/ioctl.h>
/* --------------------------------------------------------------------- */
struct ezusb_ctrltransfer {
/* keep in sync with usb.h:devrequest */
unsigned char requesttype;
unsigned char request;
unsigned short value;
unsigned short index;
unsigned short length;
/* pointer to data */
unsigned dlen;
void *data;
};
#define EZUSB_CONTROL _IOWR('E', 0, struct ezusb_ctrltransfer)
struct ezusb_interrupttransfer {
unsigned int ep;
unsigned char data[64];
};
#define EZUSB_INTERRUPT _IOWR('E', 1, struct ezusb_interrupttransfer)
struct ezusb_bulktransfer {
unsigned int ep;
unsigned int len;
void *data;
};
#define EZUSB_BULK _IOWR('E', 2, struct ezusb_bulktransfer)
#define EZUSB_RESETEP _IOR('E', 3, unsigned int)
/* --------------------------------------------------------------------- */
#endif /* _LINUX_EZUSB_H */
......@@ -3,6 +3,7 @@
*
* (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Gregory P. Smith
*/
#include <linux/kernel.h>
......@@ -20,10 +21,16 @@
/* Wakes up khubd */
static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait);
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED;
/* List of hubs needing servicing */
static struct list_head hub_event_list;
#ifdef MODULE
/* List containing all of the hubs (for cleanup) */
static struct list_head all_hubs_list;
#endif
/* PID of khubd */
static int khubd_pid = 0;
......@@ -149,6 +156,7 @@ static int hub_probe(struct usb_device *dev)
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_hub *hub;
unsigned long flags;
/* We don't handle multi-config hubs */
if (dev->descriptor.bNumConfigurations != 1)
......@@ -196,9 +204,15 @@ static int hub_probe(struct usb_device *dev)
INIT_LIST_HEAD(&hub->event_list);
hub->dev = dev;
/* Record the new hub's existence */
spin_lock_irqsave(&hub_list_lock, flags);
INIT_LIST_HEAD(&hub->hub_list);
list_add(&hub->hub_list, &all_hubs_list);
spin_unlock_irqrestore(&hub_list_lock, flags);
usb_hub_configure(hub);
usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
/* Wake up khubd */
wake_up(&usb_hub_wait);
......@@ -216,9 +230,14 @@ static void hub_disconnect(struct usb_device *dev)
/* Delete it and then reset it */
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(&hub->hub_list);
INIT_LIST_HEAD(&hub->hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
usb_release_irq(hub->dev, hub->irq_handle);
hub->irq_handle = NULL;
/* Free the memory */
kfree(hub);
}
......@@ -353,13 +372,16 @@ static void usb_hub_events(void)
static int usb_hub_thread(void *__hub)
{
MOD_INC_USE_COUNT;
printk(KERN_INFO "USB hub driver registered\n");
lock_kernel();
/*
* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
printk("usb_hub_thread at %p\n", &usb_hub_thread);
exit_mm(current);
exit_files(current);
exit_fs(current);
......@@ -373,6 +395,8 @@ static int usb_hub_thread(void *__hub)
usb_hub_events();
} while (!signal_pending(current));
MOD_DEC_USE_COUNT;
printk("usb_hub_thread exiting\n");
return 0;
......@@ -393,6 +417,7 @@ int usb_hub_init(void)
int pid;
INIT_LIST_HEAD(&hub_event_list);
INIT_LIST_HEAD(&all_hubs_list);
usb_register(&hub_driver);
pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
......@@ -409,11 +434,39 @@ int usb_hub_init(void)
void usb_hub_cleanup(void)
{
if (khubd_pid >= 0)
kill_proc(khubd_pid, SIGINT, 1);
struct list_head *next, *tmp, *head = &all_hubs_list;
struct usb_hub *hub;
unsigned long flags, flags2;
/* Free the resources allocated by each hub */
spin_lock_irqsave(&hub_list_lock, flags);
spin_lock_irqsave(&hub_event_lock, flags2);
tmp = head->next;
while (tmp != head) {
hub = list_entry(tmp, struct usb_hub, hub_list);
next = tmp->next;
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(tmp); /* &hub->hub_list */
INIT_LIST_HEAD(tmp); /* &hub->hub_list */
/* XXX we should disconnect each connected port here */
usb_release_irq(hub->dev, hub->irq_handle);
hub->irq_handle = NULL;
kfree(hub);
tmp = next;
}
usb_deregister(&hub_driver);
}
spin_unlock_irqrestore(&hub_event_lock, flags2);
spin_unlock_irqrestore(&hub_list_lock, flags);
} /* usb_hub_cleanup() */
#ifdef MODULE
int init_module(void){
......
......@@ -68,6 +68,12 @@ struct usb_hub {
/* Device structure */
struct usb_device *dev;
/* Reference to the hub's polling IRQ */
void* irq_handle;
/* List of hubs */
struct list_head hub_list;
/* Temporary event list */
struct list_head event_list;
......
......@@ -53,6 +53,12 @@ struct mouse_state {
struct fasync_struct *fasync;
/* later, add a list here to support multiple mice */
/* but we will also need a list of file pointers to identify it */
/* FIXME: move these to a per-mouse structure */
struct usb_device *dev; /* host controller this mouse is on */
void* irq_handle; /* host controller's IRQ transfer handle */
__u8 bEndpointAddress; /* these are from the endpoint descriptor */
__u8 bInterval; /* ... used when calling usb_request_irq */
};
static struct mouse_state static_mouse_state;
......@@ -103,8 +109,16 @@ static int release_mouse(struct inode * inode, struct file * file)
struct mouse_state *mouse = &static_mouse_state;
fasync_mouse(-1, file, 0);
if (--mouse->active)
return 0;
MOD_DEC_USE_COUNT;
if (--mouse->active == 0) {
/* stop polling the mouse while its not in use */
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
mouse->irq_handle = NULL;
}
return 0;
}
......@@ -118,6 +132,13 @@ static int open_mouse(struct inode * inode, struct file * file)
return 0;
/* flush state */
mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
/* prevent the driver from being unloaded while its in use */
MOD_INC_USE_COUNT;
/* start the usb controller's polling of the mouse */
mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
return 0;
}
......@@ -274,7 +295,10 @@ static int mouse_probe(struct usb_device *dev)
usb_set_configuration(dev, dev->config[0].bConfigurationValue);
usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL);
/* these are used to request the irq when the mouse is opened */
mouse->dev = dev;
mouse->bEndpointAddress = endpoint->bEndpointAddress;
mouse->bInterval = endpoint->bInterval;
mouse->present = 1;
return 0;
......@@ -284,6 +308,15 @@ static void mouse_disconnect(struct usb_device *dev)
{
struct mouse_state *mouse = &static_mouse_state;
/* stop the usb interrupt transfer */
if (mouse->present) {
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
mouse->irq_handle = NULL;
}
mouse->irq_handle = NULL;
/* this might need work */
mouse->present = 0;
printk("Mouse disconnected\n");
......@@ -303,6 +336,7 @@ int usb_mouse_init(void)
misc_register(&usb_mouse);
mouse->present = mouse->active = 0;
mouse->irq_handle = NULL;
init_waitqueue_head(&mouse->wait);
mouse->fasync = NULL;
......@@ -313,6 +347,15 @@ int usb_mouse_init(void)
void usb_mouse_cleanup(void)
{
struct mouse_state *mouse = &static_mouse_state;
/* stop the usb interrupt transfer */
if (mouse->present) {
usb_release_irq(mouse->dev, mouse->irq_handle);
/* never keep a reference to a released IRQ! */
mouse->irq_handle = NULL;
}
/* this, too, probably needs work */
usb_deregister(&mouse_driver);
misc_deregister(&usb_mouse);
......
......@@ -437,6 +437,59 @@ inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK);
}
/*
* Remove a periodic ED from the host controller
*/
void ohci_remove_periodic_ed(struct ohci *ohci, struct ohci_ed *ed)
{
struct ohci_device *root_hub = usb_to_ohci(ohci->bus->root_hub);
struct ohci_ed *cur_ed = NULL, *prev_ed;
unsigned long flags;
/* FIXME: this will need to up fixed when add_periodic_ed()
* is updated to spread similar polling rate EDs out over
* multiple periodic queues. Currently this assumes that the
* 32ms (slowest) polling queue links to all others... */
/* search the periodic EDs, skipping the first one which is
* only a placeholder. */
prev_ed = &root_hub->ed[ED_INT_32];
if (prev_ed->next_ed)
cur_ed = bus_to_virt(le32_to_cpup(&prev_ed->next_ed));
while (cur_ed) {
if (ed == cur_ed) { /* remove the ED */
/* set its SKIP bit and be sure its not in use */
ohci_wait_for_ed_safe(ohci->regs, ed, HCD_ED_INT);
/* unlink it */
spin_lock_irqsave(&ohci_edtd_lock, flags);
prev_ed->next_ed = ed->next_ed;
spin_unlock_irqrestore(&ohci_edtd_lock, flags);
ed->next_ed = 0;
break;
}
spin_lock_irqsave(&ohci_edtd_lock, flags);
if (cur_ed->next_ed) {
prev_ed = cur_ed;
cur_ed = bus_to_virt(le32_to_cpup(&cur_ed->next_ed));
spin_unlock_irqrestore(&ohci_edtd_lock, flags);
} else {
spin_unlock_irqrestore(&ohci_edtd_lock, flags);
/* if multiple polling queues need to be checked,
* here is where you'd advance to the next one */
printk("usb-ohci: ed %p not found on periodic queue\n", ed);
break;
}
}
} /* ohci_remove_periodic_ed() */
/*
* Remove all the EDs which have a given device address from a list.
* Used when the device is unplugged.
......@@ -584,6 +637,8 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
new_td->info = cpu_to_le32(OHCI_TD_CC_NEW);
/* mark it as allocated */
allocate_td(new_td);
/* record the device that its on */
new_td->usb_dev = ohci_to_usb(dev);
return new_td;
}
}
......@@ -879,8 +934,11 @@ static __u16 ohci_td_bytes_done(struct ohci_td *td)
*
* Period is desired polling interval in ms. The closest, shorter
* match will be used. Powers of two from 1-32 are supported by OHCI.
*
* Returns: a "handle pointer" that release_irq can use to stop this
* interrupt. (It's really a pointer to the TD). NULL = error.
*/
static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
usb_device_irq handler, int period, void *dev_id)
{
struct ohci_device *dev = usb_to_ohci(usb);
......@@ -892,14 +950,14 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
interrupt_ed = ohci_get_free_ed(dev);
if (!interrupt_ed) {
printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
return -1;
return NULL;
}
td = ohci_get_free_td(dev);
if (!td) {
printk(KERN_ERR "Out of TDs in ohci_request_irq\n");
ohci_free_ed(interrupt_ed);
return -1;
return NULL;
}
/*
......@@ -917,10 +975,6 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
OHCI_TD_ROUND,
dev->data, maxps,
dev_id, handler);
/*
* TODO: be aware of how the OHCI controller deals with DMA
* spanning more than one page.
*/
/*
* Put the TD onto our ED and make sure its ready to run
......@@ -936,17 +990,54 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
/* Assimilate the new ED into the collective */
ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
/* FIXME: return a request handle that can be used by the
* caller to cancel this request. Be sure its guaranteed not
* to be re-used until the caller is guaranteed to know that
* the transfer has ended or been cancelled */
return 0;
return (void*)td;
} /* ohci_request_irq() */
/*
* Control thread operations:
* Release an interrupt handler previously allocated using
* ohci_request_irq. This function does no validity checking, so make
* sure you're not releasing an already released handle as it may be
* in use by something else..
*
* This function can NOT be called from an interrupt.
*/
int ohci_release_irq(void* handle)
{
struct ohci_device *dev;
struct ohci_td *int_td;
struct ohci_ed *int_ed;
#ifdef OHCI_DEBUG
if (handle)
printk("usb-ohci: Releasing irq handle %p\n", handle);
#endif
int_td = (struct ohci_td*)handle;
if (int_td == NULL)
return USB_ST_INTERNALERROR;
dev = usb_to_ohci(int_td->usb_dev);
int_ed = int_td->ed;
ohci_remove_periodic_ed(dev->ohci, int_ed);
/* Tell the driver that the IRQ has been killed. */
/* Passing NULL in the "buffer" void* along with the
* USB_ST_REMOVED status is the signal. */
if (int_td->completed != NULL)
int_td->completed(USB_ST_REMOVED, NULL, 0, int_td->dev_id);
/* Free the ED (& TD) */
ohci_free_ed(int_ed);
return USB_ST_NOERROR;
} /* ohci_release_irq() */
/************************************
* OHCI control transfer operations *
************************************/
static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
/*
......@@ -1134,7 +1225,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
#ifdef OHCI_DEBUG
if (completion_status != 0) {
char *what = (completion_status < 0)? "timed out":
const char *what = (completion_status < 0)? "timed out":
cc_names[completion_status & 0xf];
printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n",
what, pipe, cmd->requesttype, cmd->request,
......@@ -1407,6 +1498,7 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
/* .......... */
/*
* Allocate a new USB device to be attached to an OHCI controller
*/
......@@ -1488,6 +1580,7 @@ struct usb_operations ohci_device_operations = {
ohci_control_msg,
ohci_bulk_msg,
ohci_request_irq,
ohci_release_irq,
};
......
......@@ -44,8 +44,10 @@ struct ohci_td {
/* bit3: this is NOT the last TD in a contiguious TD chain
* on the indicated ED. (0 means it is the last) */
struct usb_device *usb_dev; /* the owning device */
void *dev_id; /* user defined pointer passed to irq handler */
} __attribute((aligned(16)));
} __attribute((aligned(32)));
#define OHCI_TD_ROUND (1 << 18) /* buffer rounding bit */
#define OHCI_TD_D (3 << 19) /* direction of xfer: */
......@@ -210,7 +212,7 @@ struct ohci_device {
struct ohci_td td[NUM_TDS]; /* Transfer Descriptors */
unsigned long data[DATA_BUF_LEN];
};
} __attribute((aligned(32)));
/* .... */
......
......@@ -414,8 +414,6 @@ int init_module(void)
void cleanup_module(void)
{
unsigned int offset;
usb_deregister(&printer_driver);
unregister_chrdev(mymajor, "usblp");
}
......
#!/bin/sh
killall khubd
killall ohci-control
killall uhci-control
sleep 2
rmmod hub
rmmod usb-ohci
rmmod usb-uhci
......@@ -346,8 +346,11 @@ static void uhci_remove_irq_list(struct uhci_td *td)
/*
* Request a interrupt handler..
*
* Returns: a "handle pointer" that release_irq can use to stop this
* interrupt. (It's really a pointer to the TD).
*/
static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
static void* uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
......@@ -388,13 +391,16 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
/* Add it into the skeleton */
uhci_insert_qh(interrupt_qh->skel, interrupt_qh);
return 0;
return (void*)td;
}
/*
* Remove running irq td from queues
*
* This function is not used anymore.
*/
#if 0
static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
......@@ -435,6 +441,51 @@ static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_de
spin_unlock_irqrestore(&irqlist_lock, flags);
return USB_ST_INTERNALERROR;
}
#endif
/*
* Release an interrupt handler previously allocated using
* uhci_request_irq. This function does no validity checking, so make
* sure you're not releasing an already released handle as it may be
* in use by something else..
*
* This function can NOT be called from an interrupt.
*/
int uhci_release_irq(void* handle)
{
struct uhci_td *td;
struct uhci_qh *interrupt_qh;
unsigned long flags;
#ifdef UHCI_DEBUG
printk("usb-uhci: Releasing irq handle %p\n", handle);
#endif
td = (struct uhci_td*)handle;
if (td == NULL)
return USB_ST_INTERNALERROR;
/* Remove it from the internal irq_list */
spin_lock_irqsave(&irqlist_lock, flags);
list_del(&td->irq_list);
spin_unlock_irqrestore(&irqlist_lock, flags);
/* Remove the interrupt TD and QH */
uhci_remove_td(td);
interrupt_qh = td->qh;
uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
if (td->completed != NULL)
td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
/* Free the TD and QH */
uhci_td_deallocate(td);
uhci_qh_deallocate(interrupt_qh);
return USB_ST_NOERROR;
} /* uhci_release_irq() */
/*
* Isochronous thread operations
*/
......@@ -1124,7 +1175,7 @@ struct usb_operations uhci_device_operations = {
uhci_control_msg,
uhci_bulk_msg,
uhci_request_irq,
uhci_remove_irq,
uhci_release_irq,
};
/*
......
......@@ -133,6 +133,8 @@ void usb_show_hub_descriptor(struct usb_hub_descriptor * desc)
void usb_show_string(struct usb_device* dev, char *id, int index)
{
if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
printk("%s: %s\n", id, dev->stringindex[index]);
char *p = usb_string(dev, index);
if (p != 0)
printk(KERN_INFO "%s: %s\n", id, p);
}
......@@ -476,10 +476,18 @@ void usb_destroy_configuration(struct usb_device *dev)
}
kfree(dev->config);
for (i = 1; i < USB_MAXSTRINGS; ++i) {
if (dev->stringindex[i]) {
kfree(dev->stringindex[i]);
dev->stringindex[i] = 0;
}
}
#if 0
if (dev->stringindex)
kfree(dev->stringindex);
if (dev->stringtable)
kfree(dev->stringtable);
#endif
}
void usb_init_root_hub(struct usb_device *dev)
......@@ -567,7 +575,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
dr.length = size;
while (i--) {
if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)))
if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size))
|| result == USB_ST_STALL)
break;
}
return result;
......@@ -588,11 +597,15 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char
int usb_get_device_descriptor(struct usb_device *dev)
{
return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
sizeof(dev->descriptor));
if (ret == 0) {
le16_to_cpus(&dev->descriptor.bcdUSB);
le16_to_cpus(&dev->descriptor.idVendor);
le16_to_cpus(&dev->descriptor.idProduct);
le16_to_cpus(&dev->descriptor.bcdDevice);
}
return ret;
}
int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
......@@ -884,6 +897,7 @@ int usb_get_configuration(struct usb_device *dev)
return parse;
}
#if 0
int usb_get_stringtable(struct usb_device *dev)
{
int i;
......@@ -938,6 +952,48 @@ int usb_get_stringtable(struct usb_device *dev)
dev->maxstring = maxindex;
return 0;
}
#endif
char *usb_string(struct usb_device *dev, int index)
{
int len, i;
char *ptr;
union {
unsigned char buffer[256];
struct usb_string_descriptor desc;
} u;
if (index <= 0 || index >= USB_MAXSTRINGS)
return 0;
if (dev->stringindex[index] != 0)
return dev->stringindex[index];
if (dev->string_langid == 0) {
/* read string descriptor 0 */
if (usb_get_string(dev, 0, 0, u.buffer, 2) == 0
&& u.desc.bLength >= 4
&& usb_get_string(dev, 0, 0, u.buffer, 4) == 0)
dev->string_langid = le16_to_cpup(&u.desc.wData[0]);
dev->string_langid |= 0x10000; /* so it's non-zero */
}
if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2)
|| usb_get_string(dev, dev->string_langid, index, u.buffer,
u.desc.bLength))
return 0;
len = u.desc.bLength / 2; /* includes terminating null */
ptr = kmalloc(len, GFP_KERNEL);
if (ptr == 0)
return 0;
for (i = 0; i < len - 1; ++i)
ptr[i] = le16_to_cpup(&u.desc.wData[i]);
ptr[i] = 0;
dev->stringindex[index] = ptr;
return ptr;
}
/*
* By the time we get here, the device has gotten a new device ID
......@@ -1010,7 +1066,7 @@ void usb_new_device(struct usb_device *dev)
return;
}
usb_get_stringtable(dev);
/* usb_get_stringtable(dev); */
dev->actconfig = dev->config;
dev->ifnum = 0;
......@@ -1036,7 +1092,12 @@ void usb_new_device(struct usb_device *dev)
}
}
int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
{
return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
}
int usb_release_irq(struct usb_device *dev, void* handle)
{
return dev->bus->op->release_irq(handle);
}
......@@ -169,7 +169,7 @@ struct usb_devmap {
#define USB_MAXALTSETTING 5
#define USB_MAXINTERFACES 32
#define USB_MAXENDPOINTS 32
#define USB_MAXSTRINGS 16
#define USB_MAXSTRINGS 32
struct usb_device_descriptor {
__u8 bLength;
......@@ -276,6 +276,9 @@ struct usb_driver {
* of the buffer by this transfer. (-1 = unknown/unsupported)
* void *dev_id - This is a user defined pointer set when the IRQ
* is requested that is passed back.
*
* Special Cases:
* if (status == USB_ST_REMOVED), don't trust buffer or len.
*/
typedef int (*usb_device_irq)(int, void *, int, void *);
......@@ -284,8 +287,8 @@ struct usb_operations {
int (*deallocate)(struct usb_device *);
int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int);
int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
int (*remove_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
int (*release_irq)(void* handle);
};
/*
......@@ -316,9 +319,8 @@ struct usb_device {
struct usb_device_descriptor descriptor;/* Descriptor */
struct usb_config_descriptor *config; /* All of the configs */
struct usb_device *parent;
char *stringtable; /* Strings (multiple, null term) */
char **stringindex; /* pointers to strings */
int maxstring; /* max valid index */
char *stringindex[USB_MAXSTRINGS]; /* pointers to strings */
int string_langid; /* language ID for strings */
/*
* Child devices - these can be either new devices
......@@ -341,7 +343,8 @@ extern void usb_deregister(struct usb_driver *);
extern void usb_register_bus(struct usb_bus *);
extern void usb_deregister_bus(struct usb_bus *);
extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
extern int usb_release_irq(struct usb_device *dev, void *handle);
extern void usb_init_root_hub(struct usb_device *dev);
extern void usb_connect(struct usb_device *dev);
......@@ -450,16 +453,11 @@ int usb_get_port_status(struct usb_device *dev, int port, void *data);
int usb_get_protocol(struct usb_device *dev);
int usb_set_protocol(struct usb_device *dev, int protocol);
int usb_set_idle(struct usb_device *dev, int duration, int report_id);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
int usb_set_configuration(struct usb_device *dev, int configuration);
int usb_get_report(struct usb_device *dev);
char *usb_string(struct usb_device *dev, int index);
int usb_clear_halt(struct usb_device *dev, int endp);
static inline char * usb_string(struct usb_device* dev, int index)
{
if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
return dev->stringindex[index];
else
return NULL;
}
/*
* Debugging helpers..
......
......@@ -116,16 +116,29 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
return 0;
}
void _fput(struct file *file)
/*
* Called when retiring the last use of a file pointer.
*/
static void __fput(struct file *filp)
{
atomic_inc(&file->f_count);
struct dentry * dentry = filp->f_dentry;
struct inode * inode = dentry->d_inode;
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
filp->f_dentry = NULL;
if (filp->f_mode & FMODE_WRITE)
put_write_access(inode);
dput(dentry);
}
void _fput(struct file *file)
{
lock_kernel();
locks_remove_flock(file); /* Still need the */
__fput(file); /* big lock here. */
unlock_kernel();
atomic_set(&file->f_count, 0);
file_list_lock();
list_del(&file->f_list);
list_add(&file->f_list, &free_list);
......
......@@ -764,22 +764,6 @@ asmlinkage int sys_creat(const char * pathname, int mode)
#endif
/*
* Called when retiring the last use of a file pointer.
*/
void __fput(struct file *filp)
{
struct dentry * dentry = filp->f_dentry;
struct inode * inode = dentry->d_inode;
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
filp->f_dentry = NULL;
if (filp->f_mode & FMODE_WRITE)
put_write_access(inode);
dput(dentry);
}
/*
* "id" is the POSIX thread ID. We use the
* files pointer for this..
......
......@@ -5,6 +5,8 @@
hardware ignores reprogramming. We also need userland buy-in to the
change in HZ, since this is visible in the wait4 resources etc. */
#include <linux/config.h>
#ifndef HZ
# ifndef CONFIG_ALPHA_RAWHIDE
# define HZ 1024
......
......@@ -5,7 +5,6 @@
#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
extern void __fput(struct file *); /* goner? */
extern void _fput(struct file *);
/*
......
......@@ -328,6 +328,7 @@ extern void mem_init(unsigned long start_mem, unsigned long end_mem);
extern void show_mem(void);
extern void oom(struct task_struct * tsk);
extern void si_meminfo(struct sysinfo * val);
extern void swapin_readahead(unsigned long);
/* mmap.c */
extern void vma_init(void);
......
......@@ -15,6 +15,7 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
......@@ -626,6 +627,8 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
pte_t pte;
struct shmid_kernel *shp;
unsigned int id, idx;
unsigned long page;
struct page * page_map;
id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
idx = (address - shmd->vm_start + shmd->vm_offset) >> PAGE_SHIFT;
......@@ -649,26 +652,32 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
}
#endif
lock_kernel();
again:
pte = __pte(shp->shm_pages[idx]);
if (!pte_present(pte)) {
unsigned long page = get_free_page(GFP_USER);
if (!page) {
oom(current);
return 0;
}
pte = __pte(shp->shm_pages[idx]);
if (pte_present(pte)) {
free_page (page); /* doesn't sleep */
goto done;
if (pte_none(pte)) {
page = get_free_page(GFP_USER);
if (!page)
goto oom;
if (pte_val(pte) != shp->shm_pages[idx])
goto changed;
} else {
unsigned long entry = pte_val(pte);
page_map = lookup_swap_cache(entry);
if (!page_map) {
swapin_readahead(entry);
page_map = read_swap_cache(entry);
}
if (!pte_none(pte)) {
rw_swap_page_nocache(READ, pte_val(pte), (char *)page);
pte = __pte(shp->shm_pages[idx]);
if (pte_present(pte)) {
free_page (page); /* doesn't sleep */
goto done;
}
swap_free(pte_val(pte));
page = page_address(page_map);
if (pte_present(pte))
goto present;
if (!page_map)
goto oom;
delete_from_swap_cache(page_map);
swap_free(entry);
shm_swp--;
}
shm_rss++;
......@@ -678,9 +687,21 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
--current->maj_flt; /* was incremented in do_no_page */
done: /* pte_val(pte) == shp->shm_pages[idx] */
unlock_kernel();
current->min_flt++;
get_page(mem_map + MAP_NR(pte_page(pte)));
return pte_page(pte);
changed:
free_page(page);
goto again;
present:
if (page_map)
free_page_and_swap_cache(page);
goto done;
oom:
unlock_kernel();
return -1;
}
/*
......@@ -697,6 +718,7 @@ int shm_swap (int prio, int gfp_mask)
unsigned long id, idx;
int loop = 0;
int counter;
struct page * page_map;
counter = shm_rss >> prio;
if (!counter || !(swap_nr = get_swap_page()))
......@@ -725,7 +747,8 @@ int shm_swap (int prio, int gfp_mask)
page = __pte(shp->shm_pages[idx]);
if (!pte_present(page))
goto check_table;
if ((gfp_mask & __GFP_DMA) && !PageDMA(&mem_map[MAP_NR(pte_page(page))]))
page_map = &mem_map[MAP_NR(pte_page(page))];
if ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))
goto check_table;
swap_attempts++;
......@@ -737,8 +760,11 @@ int shm_swap (int prio, int gfp_mask)
if (page_count(mem_map + MAP_NR(pte_page(page))) != 1)
goto check_table;
shp->shm_pages[idx] = swap_nr;
rw_swap_page_nocache (WRITE, swap_nr, (char *) pte_page(page));
free_page(pte_page(page));
swap_duplicate(swap_nr);
add_to_swap_cache(page_map, swap_nr);
rw_swap_page(WRITE, page_map, 0);
__free_page(page_map);
swap_successes++;
shm_swp++;
shm_rss--;
......
......@@ -116,7 +116,6 @@ EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_super);
EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(__fput); /* goner? */
EXPORT_SYMBOL(_fput);
EXPORT_SYMBOL(igrab);
EXPORT_SYMBOL(iunique);
......
......@@ -781,7 +781,7 @@ void vmtruncate(struct inode * inode, unsigned long offset)
* because it doesn't cost us any seek time. We also make sure to queue
* the 'original' request together with the readahead ones...
*/
static void swapin_readahead(unsigned long entry)
void swapin_readahead(unsigned long entry)
{
int i;
struct page *new_page;
......@@ -898,6 +898,8 @@ static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
if (!page)
return 0; /* SIGBUS - but we _really_ should know whether it is OOM or SIGBUS */
if (page == -1)
return -1; /* OOM */
++tsk->maj_flt;
++vma->vm_mm->rss;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment