Commit bc586e63 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.2.0 (pre1) (28 Dec 1998)

 we're in the pre-2.2.0 series now, I'm all synched up with Alan, and I
don't have anything pending any more. Over the internet nobody can hear
you all scream in pain over all your favourite features that didn't make
it.

	Linus "another year older and wise as hell by now" Torvalds
parent a6b5d744
VERSION = 2 VERSION = 2
PATCHLEVEL = 1 PATCHLEVEL = 2
SUBLEVEL = 133 SUBLEVEL = 0
EXTRAVERSION =-pre1
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
...@@ -58,6 +59,8 @@ endif ...@@ -58,6 +59,8 @@ endif
ROOT_DEV = CURRENT ROOT_DEV = CURRENT
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
# #
# INSTALL_PATH specifies where to place the updated kernel and system map # INSTALL_PATH specifies where to place the updated kernel and system map
# images. Uncomment if you want to place them anywhere other than root. # images. Uncomment if you want to place them anywhere other than root.
...@@ -278,7 +281,7 @@ include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion ...@@ -278,7 +281,7 @@ include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
@mv -f .ver $@ @mv -f .ver $@
include/linux/version.h: ./Makefile include/linux/version.h: ./Makefile
@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver
@echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
@echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
@mv -f .ver $@ @mv -f .ver $@
...@@ -305,7 +308,7 @@ $(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h ...@@ -305,7 +308,7 @@ $(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h
modules_install: modules_install:
@( \ @( \
MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \ MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \
cd modules; \ cd modules; \
MODULES=""; \ MODULES=""; \
inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \ inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \
......
...@@ -215,7 +215,7 @@ static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) ...@@ -215,7 +215,7 @@ static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
} else } else
lockup = 0; lockup = 0;
if (!last || time_after(jiffies, last + 500)) { if (!last || time_after(jiffies, last + 5*HZ)) {
last = jiffies; last = jiffies;
printk(KERN_ERR "\nUnrecognised interrupt from backplane\n"); printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
} }
......
...@@ -682,7 +682,8 @@ void __init print_IO_APIC(void) ...@@ -682,7 +682,8 @@ void __init print_IO_APIC(void)
printk(".... register #01: %08X\n", *(int *)&reg_01); printk(".... register #01: %08X\n", *(int *)&reg_01);
printk("....... : max redirection entries: %04X\n", reg_01.entries); printk("....... : max redirection entries: %04X\n", reg_01.entries);
if ( (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */ if ( (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */
(reg_01.entries != 0x17) /* ISA+PCI boards */ (reg_01.entries != 0x17) && /* ISA+PCI boards */
(reg_01.entries != 0x3F) /* Xeon boards */
) )
UNEXPECTED_IO_APIC(); UNEXPECTED_IO_APIC();
if (reg_01.entries == 0x0f) if (reg_01.entries == 0x0f)
...@@ -690,7 +691,8 @@ void __init print_IO_APIC(void) ...@@ -690,7 +691,8 @@ void __init print_IO_APIC(void)
printk("....... : IO APIC version: %04X\n", reg_01.version); printk("....... : IO APIC version: %04X\n", reg_01.version);
if ( (reg_01.version != 0x10) && /* oldest IO-APICs */ if ( (reg_01.version != 0x10) && /* oldest IO-APICs */
(reg_01.version != 0x11) /* my IO-APIC */ (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
(reg_01.version != 0x13) /* Xeon IO-APICs */
) )
UNEXPECTED_IO_APIC(); UNEXPECTED_IO_APIC();
if (reg_01.__reserved_1 || reg_01.__reserved_2) if (reg_01.__reserved_1 || reg_01.__reserved_2)
......
...@@ -140,7 +140,6 @@ unsigned long mp_ioapic_addr = 0xFEC00000; /* Address of the I/O apic (not yet ...@@ -140,7 +140,6 @@ unsigned long mp_ioapic_addr = 0xFEC00000; /* Address of the I/O apic (not yet
unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */ unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */
static int smp_activated = 0; /* Tripped once we need to start cross invalidating */ static int smp_activated = 0; /* Tripped once we need to start cross invalidating */
int apic_version[NR_CPUS]; /* APIC version number */ int apic_version[NR_CPUS]; /* APIC version number */
volatile int smp_commenced=0; /* Tripped when we start scheduling */
unsigned long apic_retval; /* Just debugging the assembler.. */ unsigned long apic_retval; /* Just debugging the assembler.. */
volatile unsigned long kernel_counter=0; /* Number of times the processor holds the lock */ volatile unsigned long kernel_counter=0; /* Number of times the processor holds the lock */
...@@ -633,13 +632,17 @@ void __init smp_store_cpu_info(int id) ...@@ -633,13 +632,17 @@ void __init smp_store_cpu_info(int id)
* we use to track CPUs as they power up. * we use to track CPUs as they power up.
*/ */
static atomic_t smp_commenced = ATOMIC_INIT(0);
void __init smp_commence(void) void __init smp_commence(void)
{ {
/* /*
* Lets the callins below out of their loop. * Lets the callins below out of their loop.
*/ */
SMP_PRINTK(("Setting commenced=1, go go go\n")); SMP_PRINTK(("Setting commenced=1, go go go\n"));
smp_commenced=1;
wmb();
atomic_set(&smp_commenced,1);
} }
void __init enable_local_APIC(void) void __init enable_local_APIC(void)
...@@ -740,8 +743,8 @@ int __init start_secondary(void *unused) ...@@ -740,8 +743,8 @@ int __init start_secondary(void *unused)
mtrr_init_secondary_cpu (); mtrr_init_secondary_cpu ();
#endif #endif
smp_callin(); smp_callin();
while (!smp_commenced) while (!atomic_read(&smp_commenced))
barrier(); /* nothing */ ;
return cpu_idle(NULL); return cpu_idle(NULL);
} }
...@@ -972,6 +975,27 @@ static void __init do_boot_cpu(int i) ...@@ -972,6 +975,27 @@ static void __init do_boot_cpu(int i)
*((volatile unsigned long *)phys_to_virt(8192)) = 0; *((volatile unsigned long *)phys_to_virt(8192)) = 0;
} }
cycles_t cacheflush_time;
extern unsigned long cpu_hz;
static void smp_tune_scheduling (void)
{
/*
* Rough estimation for SMP scheduling, this is the number of
* cycles it takes for a fully memory-limited process to flush
* the SMP-local cache.
*
* (For a P5 this pretty much means we will choose another idle
* CPU almost always at wakeup time (this is due to the small
* L1 cache), on PIIs it's around 50-100 usecs, depending on
* the cache size)
*/
cacheflush_time = cpu_hz/1024*boot_cpu_data.x86_cache_size/5000;
printk("per-CPU timeslice cutoff: %ld.%ld usecs.\n",
(long)cacheflush_time/(cpu_hz/1000000),
((long)cacheflush_time*100/(cpu_hz/1000000)) % 100);
}
unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS]; unsigned int prof_counter[NR_CPUS];
...@@ -1004,6 +1028,7 @@ void __init smp_boot_cpus(void) ...@@ -1004,6 +1028,7 @@ void __init smp_boot_cpus(void)
*/ */
smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */ smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
smp_tune_scheduling();
printk("CPU%d: ", boot_cpu_id); printk("CPU%d: ", boot_cpu_id);
print_cpu_info(&cpu_data[boot_cpu_id]); print_cpu_info(&cpu_data[boot_cpu_id]);
......
...@@ -72,8 +72,6 @@ extern int setup_x86_irq(int, struct irqaction *); ...@@ -72,8 +72,6 @@ extern int setup_x86_irq(int, struct irqaction *);
unsigned long cpu_hz; /* Detected as we calibrate the TSC */ unsigned long cpu_hz; /* Detected as we calibrate the TSC */
cycles_t cacheflush_time;
/* Number of usecs that the last interrupt was delayed */ /* Number of usecs that the last interrupt was delayed */
static int delay_at_last_interrupt; static int delay_at_last_interrupt;
...@@ -88,7 +86,7 @@ static unsigned long fast_gettimeoffset_quotient=0; ...@@ -88,7 +86,7 @@ static unsigned long fast_gettimeoffset_quotient=0;
extern rwlock_t xtime_lock; extern rwlock_t xtime_lock;
static unsigned long do_fast_gettimeoffset(void) static inline unsigned long do_fast_gettimeoffset(void)
{ {
register unsigned long eax asm("ax"); register unsigned long eax asm("ax");
register unsigned long edx asm("dx"); register unsigned long edx asm("dx");
...@@ -118,6 +116,13 @@ static unsigned long do_fast_gettimeoffset(void) ...@@ -118,6 +116,13 @@ static unsigned long do_fast_gettimeoffset(void)
return delay_at_last_interrupt + edx; return delay_at_last_interrupt + edx;
} }
#define TICK_SIZE tick
/*
* Older CPU's don't have the rdtsc instruction..
*/
#if CPU < 586
/* This function must be called with interrupts disabled /* This function must be called with interrupts disabled
* It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
* *
...@@ -150,8 +155,6 @@ static unsigned long do_fast_gettimeoffset(void) ...@@ -150,8 +155,6 @@ static unsigned long do_fast_gettimeoffset(void)
* comp.protocols.time.ntp! * comp.protocols.time.ntp!
*/ */
#define TICK_SIZE tick
static unsigned long do_slow_gettimeoffset(void) static unsigned long do_slow_gettimeoffset(void)
{ {
int count; int count;
...@@ -233,6 +236,12 @@ static unsigned long do_slow_gettimeoffset(void) ...@@ -233,6 +236,12 @@ static unsigned long do_slow_gettimeoffset(void)
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
#else
#define do_gettimeoffset() do_fast_gettimeoffset()
#endif
/* /*
* This version of gettimeofday has microsecond resolution * This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC. * and better than microsecond precision on fast x86 machines with TSC.
...@@ -625,7 +634,9 @@ __initfunc(void time_init(void)) ...@@ -625,7 +634,9 @@ __initfunc(void time_init(void))
* smart. See arch/i386/kernel/apm.c. * smart. See arch/i386/kernel/apm.c.
*/ */
if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
#ifndef do_gettimeoffset
do_gettimeoffset = do_fast_gettimeoffset; do_gettimeoffset = do_fast_gettimeoffset;
#endif
do_get_fast_time = do_gettimeofday; do_get_fast_time = do_gettimeofday;
use_tsc = 1; use_tsc = 1;
fast_gettimeoffset_quotient = calibrate_tsc(); fast_gettimeoffset_quotient = calibrate_tsc();
...@@ -642,13 +653,5 @@ __initfunc(void time_init(void)) ...@@ -642,13 +653,5 @@ __initfunc(void time_init(void))
printk("Detected %ld Hz processor.\n", cpu_hz); printk("Detected %ld Hz processor.\n", cpu_hz);
} }
} }
/*
* Rough estimation for SMP scheduling, this is the number of
* cycles it takes for a fully memory-limited process to flush
* the SMP-local cache.
*/
cacheflush_time = cpu_hz/10000;
setup_x86_irq(0, &irq0); setup_x86_irq(0, &irq0);
} }
...@@ -644,6 +644,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) ...@@ -644,6 +644,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
if (bh[i]) { if (bh[i]) {
clear_bit(BH_Dirty, &bh[i]->b_state); clear_bit(BH_Dirty, &bh[i]->b_state);
clear_bit(BH_Uptodate, &bh[i]->b_state); clear_bit(BH_Uptodate, &bh[i]->b_state);
bh[i]->b_end_io(bh[i], 0);
} }
} }
return; return;
......
...@@ -761,6 +761,11 @@ static int fasync_aux(int fd, struct file *filp, int on) ...@@ -761,6 +761,11 @@ static int fasync_aux(int fd, struct file *filp, int on)
} }
/*
* Random magic cookie for the aux device
*/
#define AUX_DEV ((void *)queue)
static int release_aux(struct inode * inode, struct file * file) static int release_aux(struct inode * inode, struct file * file)
{ {
fasync_aux(-1, file, 0); fasync_aux(-1, file, 0);
...@@ -768,11 +773,7 @@ static int release_aux(struct inode * inode, struct file * file) ...@@ -768,11 +773,7 @@ static int release_aux(struct inode * inode, struct file * file)
return 0; return 0;
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);
#ifdef CONFIG_MCA free_irq(AUX_IRQ, AUX_DEV);
free_irq(AUX_IRQ, inode);
#else
free_irq(AUX_IRQ, NULL);
#endif
return 0; return 0;
} }
...@@ -787,11 +788,7 @@ static int open_aux(struct inode * inode, struct file * file) ...@@ -787,11 +788,7 @@ static int open_aux(struct inode * inode, struct file * file)
return 0; return 0;
} }
queue->head = queue->tail = 0; /* Flush input queue */ queue->head = queue->tail = 0; /* Flush input queue */
#ifdef CONFIG_MCA if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) {
if (request_irq(AUX_IRQ, keyboard_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) {
#else
if (request_irq(AUX_IRQ, keyboard_interrupt, 0, "PS/2 Mouse", NULL)) {
#endif
aux_count--; aux_count--;
return -EBUSY; return -EBUSY;
} }
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
68K Macintosh. Support >16bit I/O spaces 68K Macintosh. Support >16bit I/O spaces
Paul Gortmaker : add kmod support for auto-loading of the 8390 Paul Gortmaker : add kmod support for auto-loading of the 8390
module by all drivers that require it. module by all drivers that require it.
Alan Cox : Spinlocking work, added 'BUG_83C690'
Sources: Sources:
The National Semiconductor LAN Databook, and the 3Com 3c503 databook. The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
...@@ -72,6 +72,8 @@ static const char *version = ...@@ -72,6 +72,8 @@ static const char *version =
#define NS8390_CORE #define NS8390_CORE
#include "8390.h" #include "8390.h"
#define BUG_83C690
/* These are the operational function interfaces to board-specific /* These are the operational function interfaces to board-specific
routines. routines.
void reset_8390(struct device *dev) void reset_8390(struct device *dev)
...@@ -110,6 +112,34 @@ static void ei_rx_overrun(struct device *dev); ...@@ -110,6 +112,34 @@ static void ei_rx_overrun(struct device *dev);
static void NS8390_trigger_send(struct device *dev, unsigned int length, static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page); int start_page);
static void set_multicast_list(struct device *dev); static void set_multicast_list(struct device *dev);
static void do_set_multicast_list(struct device *dev);
/*
* SMP and the 8390 setup.
*
* The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
* a page register that controls bank and packet buffer access. We guard
* this with ei_local->page_lock. Nobody should assume or set the page other
* than zero when the lock is not held. Lock holders must restore page 0
* before unlocking. Even pure readers must take the lock to protect in
* page 0.
*
* To make life difficult the chip can also be very slow. We therefore can't
* just use spinlocks. For the longer lockups we disable the irq the device
* sits on and hold the lock. We must hold the lock because there is a dual
* processor case other than interrupts (get stats/set multicast list in
* parallel with each other and transmit).
*
* Note: in theory we can just disable the irq on the card _but_ there is
* a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
* enter lock, take the queued irq. So we waddle instead of flying.
*
* Finally by special arrangement for the purpose of being generally
* annoying the transmit function is called bh atomic. That places
* restrictions on the user context callers as disable_irq won't save
* them.
*/
/* Open/initialize the board. This routine goes all-out, setting everything /* Open/initialize the board. This routine goes all-out, setting everything
...@@ -118,6 +148,7 @@ static void set_multicast_list(struct device *dev); ...@@ -118,6 +148,7 @@ static void set_multicast_list(struct device *dev);
*/ */
int ei_open(struct device *dev) int ei_open(struct device *dev)
{ {
unsigned long flags;
struct ei_device *ei_local = (struct ei_device *) dev->priv; struct ei_device *ei_local = (struct ei_device *) dev->priv;
/* This can't happen unless somebody forgot to call ethdev_init(). */ /* This can't happen unless somebody forgot to call ethdev_init(). */
...@@ -127,7 +158,14 @@ int ei_open(struct device *dev) ...@@ -127,7 +158,14 @@ int ei_open(struct device *dev)
return -ENXIO; return -ENXIO;
} }
/*
* Grab the page lock so we own the register set, then call
* the init function.
*/
spin_lock_irqsave(&ei_local->page_lock, flags);
NS8390_init(dev, 1); NS8390_init(dev, 1);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
dev->start = 1; dev->start = 1;
ei_local->irqlock = 0; ei_local->irqlock = 0;
return 0; return 0;
...@@ -136,7 +174,16 @@ int ei_open(struct device *dev) ...@@ -136,7 +174,16 @@ int ei_open(struct device *dev)
/* Opposite of above. Only used when "ifconfig <devname> down" is done. */ /* Opposite of above. Only used when "ifconfig <devname> down" is done. */
int ei_close(struct device *dev) int ei_close(struct device *dev)
{ {
struct ei_device *ei_local = (struct ei_device *) dev->priv;
unsigned long flags;
/*
* Hold the page lock during close
*/
spin_lock_irqsave(&ei_local->page_lock, flags);
NS8390_init(dev, 0); NS8390_init(dev, 0);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
dev->start = 0; dev->start = 0;
return 0; return 0;
} }
...@@ -146,24 +193,39 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -146,24 +193,39 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
int e8390_base = dev->base_addr; int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv; struct ei_device *ei_local = (struct ei_device *) dev->priv;
int length, send_length, output_page; int length, send_length, output_page;
unsigned long flags;
/* /*
* We normally shouldn't be called if dev->tbusy is set, but the * We normally shouldn't be called if dev->tbusy is set, but the
* existing code does anyway. If it has been too long since the * existing code does anyway. If it has been too long since the
* last Tx, we assume the board has died and kick it. * last Tx, we assume the board has died and kick it. We are
* bh_atomic here.
*/ */
if (dev->tbusy) if (dev->tbusy)
{ /* Do timeouts, just like the 8003 driver. */ { /* Do timeouts, just like the 8003 driver. */
int txsr = inb(e8390_base+EN0_TSR), isr; int txsr;
int isr;
int tickssofar = jiffies - dev->trans_start; int tickssofar = jiffies - dev->trans_start;
/*
* Need the page lock. Now see what went wrong. This bit is
* fast.
*/
spin_lock_irqsave(&ei_local->page_lock, flags);
txsr = inb(e8390_base+EN0_TSR);
if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX))) if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX)))
{
spin_unlock_irqrestore(&ei_local->page_lock, flags);
return 1; return 1;
}
ei_local->stat.tx_errors++; ei_local->stat.tx_errors++;
isr = inb(e8390_base+EN0_ISR); isr = inb(e8390_base+EN0_ISR);
if (dev->start == 0) if (dev->start == 0)
{ {
spin_unlock_irqrestore(&ei_local->page_lock, flags);
printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name); printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name);
return 1; return 1;
} }
...@@ -184,22 +246,54 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -184,22 +246,54 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
ei_local->interface_num ^= 1; /* Try a different xcvr. */ ei_local->interface_num ^= 1; /* Try a different xcvr. */
} }
/*
* Play shuffle the locks, a reset on some chips takes a few
* mS. We very rarely hit this point.
*/
spin_unlock_irqrestore(&ei_local->page_lock, flags);
/* Ugly but a reset can be slow, yet must be protected */
disable_irq(dev->irq);
synchronize_irq();
spin_lock(&ei_local->page_lock);
/* Try to restart the card. Perhaps the user has fixed something. */ /* Try to restart the card. Perhaps the user has fixed something. */
ei_reset_8390(dev); ei_reset_8390(dev);
NS8390_init(dev, 1); NS8390_init(dev, 1);
spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq);
dev->trans_start = jiffies; dev->trans_start = jiffies;
} }
length = skb->len; length = skb->len;
/* Mask interrupts from the ethercard. */ /* Mask interrupts from the ethercard.
SMP: We have to grab the lock here otherwise the IRQ handler
on another CPU can flip window and race the IRQ mask set. We end
up trashing the mcast filter not disabling irqs if we dont lock */
spin_lock_irqsave(&ei_local->page_lock, flags);
outb_p(0x00, e8390_base + EN0_IMR); outb_p(0x00, e8390_base + EN0_IMR);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
/*
* Slow phase with lock held.
*/
disable_irq(dev->irq); disable_irq(dev->irq);
synchronize_irq(); synchronize_irq();
spin_lock(&ei_local->page_lock);
if (dev->interrupt) if (dev->interrupt)
{ {
printk(KERN_WARNING "%s: Tx request while isr active.\n",dev->name); printk(KERN_WARNING "%s: Tx request while isr active.\n",dev->name);
outb_p(ENISR_ALL, e8390_base + EN0_IMR); outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq); enable_irq(dev->irq);
ei_local->stat.tx_errors++; ei_local->stat.tx_errors++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
...@@ -243,6 +337,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -243,6 +337,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
ei_local->irqlock = 0; ei_local->irqlock = 0;
dev->tbusy = 1; dev->tbusy = 1;
outb_p(ENISR_ALL, e8390_base + EN0_IMR); outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq); enable_irq(dev->irq);
ei_local->stat.tx_errors++; ei_local->stat.tx_errors++;
return 1; return 1;
...@@ -294,6 +389,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) ...@@ -294,6 +389,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
/* Turn 8390 interrupts back on. */ /* Turn 8390 interrupts back on. */
ei_local->irqlock = 0; ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR); outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq); enable_irq(dev->irq);
dev_kfree_skb (skb); dev_kfree_skb (skb);
...@@ -320,6 +417,13 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -320,6 +417,13 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
e8390_base = dev->base_addr; e8390_base = dev->base_addr;
ei_local = (struct ei_device *) dev->priv; ei_local = (struct ei_device *) dev->priv;
/*
* Protect the irq test too.
*/
spin_lock(&ei_local->page_lock);
if (dev->interrupt || ei_local->irqlock) if (dev->interrupt || ei_local->irqlock)
{ {
#if 1 /* This might just be an interrupt for a PCI device sharing this line */ #if 1 /* This might just be an interrupt for a PCI device sharing this line */
...@@ -330,15 +434,17 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -330,15 +434,17 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
dev->name, inb_p(e8390_base + EN0_ISR), dev->name, inb_p(e8390_base + EN0_ISR),
inb_p(e8390_base + EN0_IMR)); inb_p(e8390_base + EN0_IMR));
#endif #endif
spin_unlock(&ei_local->page_lock);
return; return;
} }
dev->interrupt = 1; dev->interrupt = 1;
/* Change to page 0 and read the intr status reg. */ /* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD); outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
if (ei_debug > 3) if (ei_debug > 3)
printk("%s: interrupt(isr=%#2.2x).\n", dev->name, printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
inb_p(e8390_base + EN0_ISR)); inb_p(e8390_base + EN0_ISR));
/* !!Assumption!! -- we stay in page 0. Don't break this. */ /* !!Assumption!! -- we stay in page 0. Don't break this. */
...@@ -386,15 +492,16 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -386,15 +492,16 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD); outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
if (nr_serviced >= MAX_SERVICE) if (nr_serviced >= MAX_SERVICE)
{ {
printk("%s: Too much work at interrupt, status %#2.2x\n", printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
dev->name, interrupts); dev->name, interrupts);
outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */ outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
} else { } else {
printk("%s: unknown interrupt %#2x\n", dev->name, interrupts); printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */ outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
} }
} }
dev->interrupt = 0; dev->interrupt = 0;
spin_unlock(&ei_local->page_lock);
return; return;
} }
...@@ -405,6 +512,8 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -405,6 +512,8 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* letting the failed packet sit and collect dust in the Tx buffer. This * letting the failed packet sit and collect dust in the Tx buffer. This
* is a much better solution as it avoids kernel based Tx timeouts, and * is a much better solution as it avoids kernel based Tx timeouts, and
* an unnecessary card reset. * an unnecessary card reset.
*
* Called with lock held
*/ */
static void ei_tx_err(struct device *dev) static void ei_tx_err(struct device *dev)
...@@ -443,7 +552,7 @@ static void ei_tx_err(struct device *dev) ...@@ -443,7 +552,7 @@ static void ei_tx_err(struct device *dev)
} }
/* We have finished a transmit: check for errors and then trigger the next /* We have finished a transmit: check for errors and then trigger the next
packet to be sent. */ packet to be sent. Called with lock held */
static void ei_tx_intr(struct device *dev) static void ei_tx_intr(struct device *dev)
{ {
...@@ -532,7 +641,8 @@ static void ei_tx_intr(struct device *dev) ...@@ -532,7 +641,8 @@ static void ei_tx_intr(struct device *dev)
mark_bh (NET_BH); mark_bh (NET_BH);
} }
/* We have a good packet(s), get it/them out of the buffers. */ /* We have a good packet(s), get it/them out of the buffers.
Called with lock held */
static void ei_receive(struct device *dev) static void ei_receive(struct device *dev)
{ {
...@@ -659,6 +769,8 @@ static void ei_receive(struct device *dev) ...@@ -659,6 +769,8 @@ static void ei_receive(struct device *dev)
* the updated datasheets, or "the NIC may act in an unpredictable manner." * the updated datasheets, or "the NIC may act in an unpredictable manner."
* This includes causing "the NIC to defer indefinitely when it is stopped * This includes causing "the NIC to defer indefinitely when it is stopped
* on a busy network." Ugh. * on a busy network." Ugh.
* Called with lock held. Don't call this with the interrupts off or your
* computer will hate you - it takes 10mS or so.
*/ */
static void ei_rx_overrun(struct device *dev) static void ei_rx_overrun(struct device *dev)
...@@ -726,19 +838,26 @@ static void ei_rx_overrun(struct device *dev) ...@@ -726,19 +838,26 @@ static void ei_rx_overrun(struct device *dev)
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD); outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
} }
/*
* Collect the stats. This is called unlocked and from several contexts.
*/
static struct net_device_stats *get_stats(struct device *dev) static struct net_device_stats *get_stats(struct device *dev)
{ {
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv; struct ei_device *ei_local = (struct ei_device *) dev->priv;
unsigned long flags;
/* If the card is stopped, just return the present stats. */ /* If the card is stopped, just return the present stats. */
if (dev->start == 0) if (dev->start == 0)
return &ei_local->stat; return &ei_local->stat;
spin_lock_irqsave(&ei_local->page_lock,flags);
/* Read the counter registers, assuming we are in page 0. */ /* Read the counter registers, assuming we are in page 0. */
ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0); ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1); ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2); ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
return &ei_local->stat; return &ei_local->stat;
} }
...@@ -794,14 +913,14 @@ static inline void make_mc_bits(u8 *bits, struct device *dev) ...@@ -794,14 +913,14 @@ static inline void make_mc_bits(u8 *bits, struct device *dev)
} }
/* /*
* Set or clear the multicast filter for this adaptor. * Set or clear the multicast filter for this adaptor. May be called
* from a BH in 2.1.x. Must be called with lock held.
*/ */
static void set_multicast_list(struct device *dev) static void do_set_multicast_list(struct device *dev)
{ {
int e8390_base = dev->base_addr; int e8390_base = dev->base_addr;
int i; int i;
unsigned long flags;
struct ei_device *ei_local = (struct ei_device*)dev->priv; struct ei_device *ei_local = (struct ei_device*)dev->priv;
if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
...@@ -825,21 +944,19 @@ static void set_multicast_list(struct device *dev) ...@@ -825,21 +944,19 @@ static void set_multicast_list(struct device *dev)
* them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and * them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
* Ultra32 EISA) appears to have this bug fixed. * Ultra32 EISA) appears to have this bug fixed.
*/ */
if (dev->start) if (dev->start)
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
save_flags(flags);
cli();
outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++)
{ {
outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i)); outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
#ifdef NOT_83C690 #ifndef BUG_83C690
if(inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i]) if(inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
printk(KERN_ERR "Multicast filter read/write mismap %d\n",i); printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
#endif #endif
} }
outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD); outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
restore_flags(flags);
if(dev->flags&IFF_PROMISC) if(dev->flags&IFF_PROMISC)
outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR); outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
...@@ -847,12 +964,29 @@ static void set_multicast_list(struct device *dev) ...@@ -847,12 +964,29 @@ static void set_multicast_list(struct device *dev)
outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR); outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
else else
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
} }
/*
* Called without lock held. This is invoked from user context and may
* be parallel to just about everything else. Its also fairly quick and
* not called too often. Must protect against both bh and irq users
*/
static void set_multicast_list(struct device *dev)
{
unsigned long flags;
struct ei_device *ei_local = (struct ei_device*)dev->priv;
spin_lock_irqsave(&ei_local->page_lock, flags);
do_set_multicast_list(dev);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
}
/* /*
* Initialize the rest of the 8390 device structure. Do NOT __initfunc * Initialize the rest of the 8390 device structure. Do NOT __initfunc
* this, as it is used by 8390 based modular drivers too. * this, as it is used by 8390 based modular drivers too.
*/ */
int ethdev_init(struct device *dev) int ethdev_init(struct device *dev)
{ {
if (ei_debug > 1) if (ei_debug > 1)
...@@ -867,6 +1001,7 @@ int ethdev_init(struct device *dev) ...@@ -867,6 +1001,7 @@ int ethdev_init(struct device *dev)
return -ENOMEM; return -ENOMEM;
memset(dev->priv, 0, sizeof(struct ei_device)); memset(dev->priv, 0, sizeof(struct ei_device));
ei_local = (struct ei_device *)dev->priv; ei_local = (struct ei_device *)dev->priv;
spin_lock_init(&ei_local->page_lock);
} }
dev->hard_start_xmit = &ei_start_xmit; dev->hard_start_xmit = &ei_start_xmit;
...@@ -883,13 +1018,16 @@ int ethdev_init(struct device *dev) ...@@ -883,13 +1018,16 @@ int ethdev_init(struct device *dev)
/* This page of functions should be 8390 generic */ /* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */ /* Follow National Semi's recommendations for initializing the "NIC". */
/*
* Must be called with lock held.
*/
void NS8390_init(struct device *dev, int startp) void NS8390_init(struct device *dev, int startp)
{ {
int e8390_base = dev->base_addr; int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv; struct ei_device *ei_local = (struct ei_device *) dev->priv;
int i; int i;
int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
unsigned long flags;
if(sizeof(struct e8390_pkt_hdr)!=4) if(sizeof(struct e8390_pkt_hdr)!=4)
panic("8390.c: header struct mispacked\n"); panic("8390.c: header struct mispacked\n");
...@@ -914,8 +1052,7 @@ void NS8390_init(struct device *dev, int startp) ...@@ -914,8 +1052,7 @@ void NS8390_init(struct device *dev, int startp)
outb_p(0x00, e8390_base + EN0_IMR); outb_p(0x00, e8390_base + EN0_IMR);
/* Copy the station address into the DS8390 registers. */ /* Copy the station address into the DS8390 registers. */
save_flags(flags);
cli();
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
for(i = 0; i < 6; i++) for(i = 0; i < 6; i++)
{ {
...@@ -926,7 +1063,7 @@ void NS8390_init(struct device *dev, int startp) ...@@ -926,7 +1063,7 @@ void NS8390_init(struct device *dev, int startp)
outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
restore_flags(flags);
dev->tbusy = 0; dev->tbusy = 0;
dev->interrupt = 0; dev->interrupt = 0;
ei_local->tx1 = ei_local->tx2 = 0; ei_local->tx1 = ei_local->tx2 = 0;
...@@ -940,18 +1077,20 @@ void NS8390_init(struct device *dev, int startp) ...@@ -940,18 +1077,20 @@ void NS8390_init(struct device *dev, int startp)
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */ /* 3c503 TechMan says rxconfig only after the NIC is started. */
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
set_multicast_list(dev); /* (re)load the mcast table */ do_set_multicast_list(dev); /* (re)load the mcast table */
} }
return; return;
} }
/* Trigger a transmit start, assuming the length is valid. */ /* Trigger a transmit start, assuming the length is valid.
Always called with the page lock held */
static void NS8390_trigger_send(struct device *dev, unsigned int length, static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page) int start_page)
{ {
int e8390_base = dev->base_addr; int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv; struct ei_device *ei_local = (struct ei_device *) dev->priv;
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
if (inb_p(e8390_base) & E8390_TRANS) if (inb_p(e8390_base) & E8390_TRANS)
......
...@@ -155,30 +155,30 @@ extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); ...@@ -155,30 +155,30 @@ extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
things in there should be here!) */ things in there should be here!) */
/* You have one of these per-board */ /* You have one of these per-board */
struct ei_device { struct ei_device {
const char *name; const char *name;
void (*reset_8390)(struct device *); void (*reset_8390)(struct device *);
void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int); void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
void (*block_output)(struct device *, int, const unsigned char *, int); void (*block_output)(struct device *, int, const unsigned char *, int);
void (*block_input)(struct device *, int, struct sk_buff *, int); void (*block_input)(struct device *, int, struct sk_buff *, int);
unsigned char mcfilter[8]; unsigned char mcfilter[8];
unsigned open:1; unsigned open:1;
unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */ unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
unsigned txing:1; /* Transmit Active */ unsigned txing:1; /* Transmit Active */
unsigned irqlock:1; /* 8390's intrs disabled when '1'. */ unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
unsigned dmaing:1; /* Remote DMA Active */ unsigned dmaing:1; /* Remote DMA Active */
unsigned char tx_start_page, rx_start_page, stop_page; unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */ unsigned char current_page; /* Read pointer in buffer */
unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */ unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
unsigned char txqueue; /* Tx Packet buffer queue length. */ unsigned char txqueue; /* Tx Packet buffer queue length. */
short tx1, tx2; /* Packet lengths for ping-pong tx. */ short tx1, tx2; /* Packet lengths for ping-pong tx. */
short lasttx; /* Alpha version consistency check. */ short lasttx; /* Alpha version consistency check. */
unsigned char reg0; /* Register '0' in a WD8013 */ unsigned char reg0; /* Register '0' in a WD8013 */
unsigned char reg5; /* Register '5' in a WD8013 */ unsigned char reg5; /* Register '5' in a WD8013 */
unsigned char saved_irq; /* Original dev->irq value. */ unsigned char saved_irq; /* Original dev->irq value. */
/* The new statistics table. */ struct net_device_stats stat; /* The new statistics table. */
struct net_device_stats stat; u32 *reg_offset; /* Register mapping table */
unsigned char *reg_offset; /* Register mapping table */ spinlock_t page_lock; /* Page register locks */
unsigned long priv; /* Private field to store bus IDs etc. */ unsigned long priv; /* Private field to store bus IDs etc. */
}; };
/* The maximum number of 8390 interrupt service routines called per IRQ. */ /* The maximum number of 8390 interrupt service routines called per IRQ. */
...@@ -190,12 +190,12 @@ struct ei_device { ...@@ -190,12 +190,12 @@ struct ei_device {
#define ei_status (*(struct ei_device *)(dev->priv)) #define ei_status (*(struct ei_device *)(dev->priv))
/* Some generic ethernet register configurations. */ /* Some generic ethernet register configurations. */
#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ #define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
#define E8390_RX_IRQ_MASK 0x5 #define E8390_RX_IRQ_MASK 0x5
#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */ #define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */ #define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */ #define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */ #define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
/* Register accessed at EN_CMD, the 8390 base addr. */ /* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */ #define E8390_STOP 0x01 /* Stop and reset the chip */
...@@ -208,6 +208,10 @@ struct ei_device { ...@@ -208,6 +208,10 @@ struct ei_device {
#define E8390_PAGE1 0x40 /* using the two high-order bits */ #define E8390_PAGE1 0x40 /* using the two high-order bits */
#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ #define E8390_PAGE2 0x80 /* Page 3 is invalid. */
/*
* Only generate indirect loads given a machine that needs them.
*/
#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \ #if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE)
#define EI_SHIFT(x) (ei_local->reg_offset[x]) #define EI_SHIFT(x) (ei_local->reg_offset[x])
......
/* $Id: cosa.c,v 1.9 1998/12/08 02:24:23 kas Exp $ */ /* $Id: cosa.c,v 1.11 1998/12/24 23:44:23 kas Exp $ */
/* /*
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz> * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
...@@ -357,7 +357,7 @@ __initfunc(static int cosa_init(void)) ...@@ -357,7 +357,7 @@ __initfunc(static int cosa_init(void))
#endif #endif
{ {
int i; int i;
printk(KERN_INFO "cosa v1.02 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n"); printk(KERN_INFO "cosa v1.03 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef __SMP__ #ifdef __SMP__
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif #endif
...@@ -995,7 +995,9 @@ static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d) ...@@ -995,7 +995,9 @@ static inline int cosa_download(struct cosa_data *cosa, struct cosa_download *d)
get_user_ret(len, &(d->len), -EFAULT); get_user_ret(len, &(d->len), -EFAULT);
get_user_ret(code, &(d->code), -EFAULT); get_user_ret(code, &(d->code), -EFAULT);
if (d->len < 0) if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
return -EINVAL;
if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
return -EINVAL; return -EINVAL;
if ((i=download(cosa, d->code, len, addr)) < 0) { if ((i=download(cosa, d->code, len, addr)) < 0) {
...@@ -1555,6 +1557,15 @@ static int puthexnumber(struct cosa_data *cosa, int number) ...@@ -1555,6 +1557,15 @@ static int puthexnumber(struct cosa_data *cosa, int number)
* separate functions to make it more readable. These functions are inline, * separate functions to make it more readable. These functions are inline,
* so there should be no overhead of function call. * so there should be no overhead of function call.
*/ */
/*
* Transmit interrupt routine - called when COSA is willing to obtain
* data from the OS. The most tricky part of the routine is selection
* of channel we (OS) want to send packet for. For SRP we should probably
* use the round-robin approach. The newer COSA firmwares have a simple
* flow-control - in the status word has bits 2 and 3 set to 1 means that the
* channel 0 or 1 doesn't want to receive data.
*/
static inline void tx_interrupt(struct cosa_data *cosa, int status) static inline void tx_interrupt(struct cosa_data *cosa, int status)
{ {
unsigned long flags, flags1; unsigned long flags, flags1;
...@@ -1564,16 +1575,24 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status) ...@@ -1564,16 +1575,24 @@ static inline void tx_interrupt(struct cosa_data *cosa, int status)
#endif #endif
spin_lock_irqsave(&cosa->lock, flags); spin_lock_irqsave(&cosa->lock, flags);
set_bit(TXBIT, &cosa->rxtx); set_bit(TXBIT, &cosa->rxtx);
/*
* Using a round-robin algorithm select a first channel that has
* data ready for transmit.
*/
if (!test_bit(IRQBIT, &cosa->rxtx)) { if (!test_bit(IRQBIT, &cosa->rxtx)) {
/* flow control */
int i=0;
do { do {
if (i++ > cosa->nchannels) {
printk(KERN_WARNING
"%s: No channel wants data in TX IRQ\n",
cosa->name);
clear_bit(TXBIT, &cosa->rxtx);
spin_unlock_irqrestore(&cosa->lock, flags);
return;
}
cosa->txchan++; cosa->txchan++;
if (cosa->txchan >= cosa->nchannels) if (cosa->txchan >= cosa->nchannels)
cosa->txchan = 0; cosa->txchan = 0;
} while(!(cosa->txbitmap & (1<<cosa->txchan))); } while ((!(cosa->txbitmap & (1<<cosa->txchan)))
|| status & (1<<(cosa->txchan+DRIVER_TXMAP_SHIFT)));
cosa->txsize = cosa->chan[cosa->txchan].txsize; cosa->txsize = cosa->chan[cosa->txchan].txsize;
if (cosa_dma_able(cosa->chan+cosa->txchan, if (cosa_dma_able(cosa->chan+cosa->txchan,
cosa->chan[cosa->txchan].txbuf, cosa->txsize)) { cosa->chan[cosa->txchan].txbuf, cosa->txsize)) {
......
/* $Id: cosa.h,v 1.8 1998/11/09 03:54:49 kas Exp $ */ /* $Id: cosa.h,v 1.5 1998/12/24 12:40:18 kas Exp $ */
/* /*
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz> * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
#define SR_START_ADDR 0x4400 /* SRP microcode start address */ #define SR_START_ADDR 0x4400 /* SRP microcode start address */
#define COSA_LOAD_ADDR 0x400 /* SRP microcode load address */ #define COSA_LOAD_ADDR 0x400 /* SRP microcode load address */
#define COSA_MAX_FIRMWARE_SIZE 0x10000
/* ioctls */ /* ioctls */
struct cosa_download { struct cosa_download {
......
...@@ -303,6 +303,10 @@ static int io[MAX_CARDS] = { 0, }; ...@@ -303,6 +303,10 @@ static int io[MAX_CARDS] = { 0, };
static int dma[MAX_CARDS] = { 0, }; static int dma[MAX_CARDS] = { 0, };
static int irq[MAX_CARDS] = { 0, }; static int irq[MAX_CARDS] = { 0, };
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, }; static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
static struct device dev_lance[MAX_CARDS] = static struct device dev_lance[MAX_CARDS] =
{{ {{
...@@ -363,11 +367,12 @@ int lance_probe(struct device *dev) ...@@ -363,11 +367,12 @@ int lance_probe(struct device *dev)
{ {
int *port, result; int *port, result;
if (high_memory <= 16*1024*1024) if (high_memory <= phys_to_virt(16*1024*1024))
lance_need_isa_bounce_buffers = 0; lance_need_isa_bounce_buffers = 0;
#if defined(CONFIG_PCI) #if defined(CONFIG_PCI)
if (pci_present()) { if (pci_present())
{
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
if (lance_debug > 1) if (lance_debug > 1)
printk("lance.c: PCI bios is present, checking for devices...\n"); printk("lance.c: PCI bios is present, checking for devices...\n");
......
...@@ -29,10 +29,6 @@ ...@@ -29,10 +29,6 @@
* Jan 02, 1997 Gene Kozin Initial version. * Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/ *****************************************************************************/
#if !defined(__KERNEL__) || !defined(MODULE)
#error This code MUST be compiled as a kernel module!
#endif
#include <linux/config.h> /* OS configuration options */ #include <linux/config.h> /* OS configuration options */
#include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */ #include <linux/errno.h> /* return codes */
...@@ -122,7 +118,12 @@ static struct tq_struct sdla_tq = ...@@ -122,7 +118,12 @@ static struct tq_struct sdla_tq =
* < 0 error. * < 0 error.
* Context: process * Context: process
*/ */
#ifdef MODULE
int init_module (void) int init_module (void)
#else
int wanpipe_init(void)
#endif
{ {
int cnt, err = 0; int cnt, err = 0;
...@@ -173,6 +174,7 @@ int init_module (void) ...@@ -173,6 +174,7 @@ int init_module (void)
return err; return err;
} }
#ifdef MODULE
/*============================================================================ /*============================================================================
* Module 'remove' entry point. * Module 'remove' entry point.
* o unregister all adapters from the WAN router * o unregister all adapters from the WAN router
...@@ -190,6 +192,8 @@ void cleanup_module (void) ...@@ -190,6 +192,8 @@ void cleanup_module (void)
kfree(card_array); kfree(card_array);
} }
#endif
/******* WAN Device Driver Entry Points *************************************/ /******* WAN Device Driver Entry Points *************************************/
/*============================================================================ /*============================================================================
......
...@@ -66,6 +66,7 @@ static const int multicast_filter_limit = 32; ...@@ -66,6 +66,7 @@ static const int multicast_filter_limit = 32;
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/version.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/errno.h> #include <linux/errno.h>
......
...@@ -389,9 +389,11 @@ static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int l ...@@ -389,9 +389,11 @@ static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int l
* In case you are wondering what the last line of the asm does... * In case you are wondering what the last line of the asm does...
* <output allocation> : <input allocation> : <trashed registers> * <output allocation> : <input allocation> : <trashed registers>
*/ */
register int d0;
asm("shr $2,%%ecx\n" \ asm("shr $2,%%ecx\n" \
" jz .no_more_bulk_bo\n" \ " jz .no_more_bulk_bo\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".loop_bulk_bo:\n" \ ".loop_bulk_bo:\n" \
" movl (%%esi),%%ebx\n" \ " movl (%%esi),%%ebx\n" \
BYTE_OUT(%%bl) \ BYTE_OUT(%%bl) \
...@@ -401,19 +403,23 @@ static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int l ...@@ -401,19 +403,23 @@ static inline int ppa_byte_out(unsigned short base, char *buffer, unsigned int l
BYTE_OUT(%%bh) \ BYTE_OUT(%%bh) \
" addl $4,%%esi\n" \ " addl $4,%%esi\n" \
" loop .loop_bulk_bo\n" \ " loop .loop_bulk_bo\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".no_more_bulk_bo:" \ ".no_more_bulk_bo:" \
: "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); : "=S"(buffer), "=c"(d0)
: "1"(len), "d"(base), "0"(buffer)
: "eax", "ebx");
asm("andl $3,%%ecx\n" \ asm("andl $3,%%ecx\n" \
" jz .no_more_loose_bo\n" \ " jz .no_more_loose_bo\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".loop_loose_bo:\n" \ ".loop_loose_bo:\n" \
BYTE_OUT((%%esi)) \ BYTE_OUT((%%esi)) \
" incl %%esi\n" \ " incl %%esi\n" \
" loop .loop_loose_bo\n" \ " loop .loop_loose_bo\n" \
".no_more_loose_bo:\n" \ ".no_more_loose_bo:\n" \
: /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); : "=c"(d0)
: "0"(len), "d"(base), "S"(buffer)
: "eax", "ebx");
return 1; /* All went well - we hope! */ return 1; /* All went well - we hope! */
} }
...@@ -439,9 +445,11 @@ static inline int ppa_byte_in(unsigned short base, char *buffer, int len) ...@@ -439,9 +445,11 @@ static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
* In case you are wondering what the last line of the asm does... * In case you are wondering what the last line of the asm does...
* <output allocation> : <input allocation> : <trashed registers> * <output allocation> : <input allocation> : <trashed registers>
*/ */
register int d0;
asm("shr $2,%%ecx\n" \ asm("shr $2,%%ecx\n" \
" jz .no_more_bulk_bi\n" \ " jz .no_more_bulk_bi\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".loop_bulk_bi:\n" \ ".loop_bulk_bi:\n" \
BYTE_IN(%%bl) \ BYTE_IN(%%bl) \
BYTE_IN(%%bh) \ BYTE_IN(%%bh) \
...@@ -452,19 +460,23 @@ static inline int ppa_byte_in(unsigned short base, char *buffer, int len) ...@@ -452,19 +460,23 @@ static inline int ppa_byte_in(unsigned short base, char *buffer, int len)
" movl %%ebx,(%%esi)\n" \ " movl %%ebx,(%%esi)\n" \
" addl $4,%%esi\n" \ " addl $4,%%esi\n" \
" loop .loop_bulk_bi\n" \ " loop .loop_bulk_bi\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".no_more_bulk_bi:" \ ".no_more_bulk_bi:" \
: "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); : "=S"(buffer), "=c"(d0)
: "1"(len), "d"(base), "0"(buffer)
: "eax", "ebx");
asm("andl $3,%%ecx\n" \ asm("andl $3,%%ecx\n" \
" jz .no_more_loose_bi\n" \ " jz .no_more_loose_bi\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".loop_loose_bi:\n" \ ".loop_loose_bi:\n" \
BYTE_IN((%%esi)) \ BYTE_IN((%%esi)) \
" incl %%esi\n" \ " incl %%esi\n" \
" loop .loop_loose_bi\n" \ " loop .loop_loose_bi\n" \
".no_more_loose_bi:\n" \ ".no_more_loose_bi:\n" \
: /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx"); : "=c"(d0)
: "0"(len), "d"(base), "S"(buffer)
: "eax", "ebx");
return 1; /* All went well - we hope! */ return 1; /* All went well - we hope! */
} }
...@@ -496,9 +508,11 @@ static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len) ...@@ -496,9 +508,11 @@ static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
* In case you are wondering what the last line of the asm does... * In case you are wondering what the last line of the asm does...
* <output allocation> : <input allocation> : <trashed registers> * <output allocation> : <input allocation> : <trashed registers>
*/ */
register int d0;
asm("shr $2,%%ecx\n" \ asm("shr $2,%%ecx\n" \
" jz .no_more_bulk_ni\n" \ " jz .no_more_bulk_ni\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".loop_bulk_ni:\n" \ ".loop_bulk_ni:\n" \
NIBBLE_IN(%%bl) \ NIBBLE_IN(%%bl) \
NIBBLE_IN(%%bh) \ NIBBLE_IN(%%bh) \
...@@ -509,19 +523,23 @@ static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len) ...@@ -509,19 +523,23 @@ static inline int ppa_nibble_in(unsigned short str_p, char *buffer, int len)
" movl %%ebx,(%%esi)\n" \ " movl %%ebx,(%%esi)\n" \
" addl $4,%%esi\n" \ " addl $4,%%esi\n" \
" loop .loop_bulk_ni\n" \ " loop .loop_bulk_ni\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".no_more_bulk_ni:" \ ".no_more_bulk_ni:" \
: "=S"(buffer): "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx"); : "=S"(buffer), "=c"(d0)
: "1"(len), "d"(str_p), "0"(buffer)
: "eax", "ebx");
asm("andl $3,%%ecx\n" \ asm("andl $3,%%ecx\n" \
" jz .no_more_loose_ni\n" \ " jz .no_more_loose_ni\n" \
" .align 4\n" \ " .p2align 4,,7\n" \
".loop_loose_ni:\n" \ ".loop_loose_ni:\n" \
NIBBLE_IN((%%esi)) \ NIBBLE_IN((%%esi)) \
" incl %%esi\n" \ " incl %%esi\n" \
" loop .loop_loose_ni\n" \ " loop .loop_loose_ni\n" \
".no_more_loose_ni:\n" \ ".no_more_loose_ni:\n" \
: /* no output */ : "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx"); : "=c"(d0)
: "0"(len), "d"(str_p), "S"(buffer)
: "eax", "ebx");
return 1; /* All went well - we hope! */ return 1; /* All went well - we hope! */
} }
#else /* Old style C routines */ #else /* Old style C routines */
......
...@@ -2678,7 +2678,7 @@ static int joystick[NR_DEVICE] = { 0, }; ...@@ -2678,7 +2678,7 @@ static int joystick[NR_DEVICE] = { 0, };
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static const struct initvol { static struct initvol {
int mixch; int mixch;
int vol; int vol;
} initvol[] __initdata = { } initvol[] __initdata = {
......
...@@ -65,6 +65,8 @@ ...@@ -65,6 +65,8 @@
* Improved debugging support. 16-May-1998 * Improved debugging support. 16-May-1998
* Fixed bug. 16-Jun-1998 * Fixed bug. 16-Jun-1998
* *
* Torsten Duwe Made Opti924 PnP support non-destructive
* 1998-12-23
*/ */
#include "sound_config.h" #include "sound_config.h"
...@@ -279,19 +281,21 @@ static int detect_c930(void) ...@@ -279,19 +281,21 @@ static int detect_c930(void)
if ((mad_read(MC0_PORT+13) & 0x80) == 0) if ((mad_read(MC0_PORT+13) & 0x80) == 0)
return 1; return 1;
#if 0
/* Force off PnP mode. This is not recommended because /* Force off PnP mode. This is not recommended because
* the PnP bios will not recognize the chip on the next * the PnP bios will not recognize the chip on the next
* warm boot and may assignd different resources to other * warm boot and may assignd different resources to other
* PnP/PCI cards. * PnP/PCI cards.
*/ */
mad_write(MC0_PORT+17, 0x04); mad_write(MC0_PORT+17, 0x04);
#endif
return 1; return 1;
} }
static int detect_mad16(void) static int detect_mad16(void)
{ {
unsigned char tmp, tmp2; unsigned char tmp, tmp2, bit;
int i; int i, port;
/* /*
* Check that reading a register doesn't return bus float (0xff) * Check that reading a register doesn't return bus float (0xff)
...@@ -323,14 +327,19 @@ static int detect_mad16(void) ...@@ -323,14 +327,19 @@ static int detect_mad16(void)
DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
return 0; return 0;
} }
mad_write(MC1_PORT, tmp ^ 0x80); /* Toggle a bit */
if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ bit = (c924pnp) ? 0x20 : 0x80;
port = (c924pnp) ? MC2_PORT : MC1_PORT;
tmp = mad_read(port);
mad_write(port, tmp ^ bit); /* Toggle a bit */
if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */
{ {
mad_write(MC1_PORT, tmp); /* Restore */ mad_write(port, tmp); /* Restore */
DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
return 0; return 0;
} }
mad_write(MC1_PORT, tmp); /* Restore */ mad_write(port, tmp); /* Restore */
return 1; /* Bingo */ return 1; /* Bingo */
} }
...@@ -456,14 +465,8 @@ static int chip_detect(void) ...@@ -456,14 +465,8 @@ static int chip_detect(void)
DDB(printk("Detect using password = 0xE5\n")); DDB(printk("Detect using password = 0xE5\n"));
if (!detect_mad16()) {
c924pnp++;
DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
}
if (!detect_mad16()) /* No luck. Try different model */ if (!detect_mad16()) /* No luck. Try different model */
{ {
c924pnp=0;
board_type = C928; board_type = C928;
DDB(printk("Detect using password = 0xE2\n")); DDB(printk("Detect using password = 0xE2\n"));
...@@ -493,10 +496,19 @@ static int chip_detect(void) ...@@ -493,10 +496,19 @@ static int chip_detect(void)
for (i = 0xf8d; i <= 0xf93; i++) for (i = 0xf8d; i <= 0xf93; i++)
DDB(printk("port %03x = %02x\n", i, mad_read(i))); DDB(printk("port %03x = %02x\n", i, mad_read(i)));
if (!detect_mad16()) if (!detect_mad16()) {
return 0; board_type = C924;
c924pnp++;
DDB(printk("mad16.c: 82C930 detected\n")); DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
if (!detect_mad16()) {
c924pnp=0;
return 0;
}
DDB(printk("mad16.c: 82C924 PnP detected\n"));
}
else
DDB(printk("mad16.c: 82C930 detected\n"));
} else } else
DDB(printk("mad16.c: 82C929 detected\n")); DDB(printk("mad16.c: 82C929 detected\n"));
} else { } else {
......
...@@ -260,7 +260,6 @@ void unload_opl3sa_wss(struct address_info *hw_config) ...@@ -260,7 +260,6 @@ void unload_opl3sa_wss(struct address_info *hw_config)
hw_config->dma, hw_config->dma,
dma2, dma2,
0); 0);
sound_unload_audiodev(hw_config->slots[0]);
} }
void unload_opl3sa_mpu(struct address_info *hw_config) void unload_opl3sa_mpu(struct address_info *hw_config)
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
#define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ #define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */
#define MDL_AEDSP 15 /* Audio Excel DSP 16 */ #define MDL_AEDSP 15 /* Audio Excel DSP 16 */
#define SUBMDL_ES18XX 0x10 /* Introduced a subtype ESS 18XX (Rolf) */ #define SUBMDL_ES188X 0x10 /* Subtype ES188X for specific handling */
#define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ #define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */
/* register assignment */ /* register assignment */
/* /*
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
/* /*
* Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
* for full duplex support ( only sb16 by now ) * for full duplex support ( only sb16 by now )
* Rolf Fokkens: Added (BETA?) support for ES18XX chips. * Rolf Fokkens: Added (BETA?) support for ES188x chips.
* Which means: you can adjust the recording levels. * (fokkensr@vertis.nl) Which means: You can adjust the recording levels.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -545,8 +545,9 @@ static int ess_init(sb_devc * devc, struct address_info *hw_config) ...@@ -545,8 +545,9 @@ static int ess_init(sb_devc * devc, struct address_info *hw_config)
/* /*
* This the detection heuristic of ESS technology, though somewhat * This the detection heuristic of ESS technology, though somewhat
* changed to actually make it work :-) * changed to actually make it work.
* This is the most BETA part of the software: Will it work? * This is the most BETA part of the software: Will the detection
* always work?
*/ */
devc->model = MDL_ESS; devc->model = MDL_ESS;
devc->submodel = ess_minor & 0x0f; devc->submodel = ess_minor & 0x0f;
...@@ -558,8 +559,8 @@ static int ess_init(sb_devc * devc, struct address_info *hw_config) ...@@ -558,8 +559,8 @@ static int ess_init(sb_devc * devc, struct address_info *hw_config)
if ((ess_minor & 0x0f) >= 8) { if ((ess_minor & 0x0f) >= 8) {
if ( !ess_probe (devc, 0x64, (1 << 3)) if ( !ess_probe (devc, 0x64, (1 << 3))
&& ess_probe (devc, 0x70, 0x7f)) { && ess_probe (devc, 0x70, 0x7f)) {
chip = "ES18XX"; chip = "ES188x";
devc->submodel = SUBMDL_ES18XX; devc->submodel = SUBMDL_ES188X;
} else { } else {
chip = "ES1688"; chip = "ES1688";
}; };
...@@ -1035,7 +1036,7 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu) ...@@ -1035,7 +1036,7 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
/* /*
* Mixer access routines * Mixer access routines
* *
* ES18XX modifications: some mixer registers reside in the * ES188x modifications: some mixer registers reside in the
* range above 0xa0. These must be accessed in another way. * range above 0xa0. These must be accessed in another way.
*/ */
......
...@@ -13,25 +13,24 @@ ...@@ -13,25 +13,24 @@
* *
* *
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
* Rolf Fokkens : ES18XX recording level support * Rolf Fokkens : ES188x recording level support
*/ */
/* /*
* About ES18XX support: * About ES188x support:
* *
* The standard ES688 support doesn't take care of the ES18XX recording * The standard ES1688 support doesn't take care of the ES188x recording
* levels very well. Whenever a device is selected (recmask) for recording * levels very well. Whenever a device is selected (recmask) for recording
* it's recording level is loud, and it cannot be changed. * it's recording level is loud, and it cannot be changed.
* *
* The ES18XX has separate registers to controll the recording levels. The * The ES188x has separate registers to control the recording levels. The
* ES18XX specific software makes these level the same as their corresponding * ES188x specific software makes these level the same as their corresponding
* playback levels, unless recmask says they aren't recorded. In tha latter * playback levels, unless recmask says they aren't recorded. In the latter
* case the recording volumens are 0. * case the recording volumes are 0.
* *
* Now recording levels of inputs can be controlled, by changing the playback * Now recording levels of inputs can be controlled, by changing the playback
* levels. * levels. Futhermore several devices can be recorded together (which is not
* Futhermore several devices can be recorded together (which is not possible * possible with the ES1688.
* with the ES688.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -139,13 +138,13 @@ static int common_mixer_set(sb_devc * devc, int dev, int left, int right) ...@@ -139,13 +138,13 @@ static int common_mixer_set(sb_devc * devc, int dev, int left, int right)
} }
/* /*
* Changing input levels at ES18XX means having to take care of recording * Changing playback levels at ES188x means having to take care of recording
* levels of recorded inputs too! * levels of recorded inputs (devc->recmask) too!
*/ */
static int es18XX_mixer_set(sb_devc * devc, int dev, int left, int right) static int es188x_mixer_set(sb_devc * devc, int dev, int left, int right)
{ {
if (devc->recmask & (1 << dev)) { if (devc->recmask & (1 << dev)) {
common_mixer_set(devc, dev + ES18XX_MIXER_RECDIFF, left, right); common_mixer_set(devc, dev + ES188X_MIXER_RECDIFF, left, right);
} }
return common_mixer_set(devc, dev, left, right); return common_mixer_set(devc, dev, left, right);
} }
...@@ -212,8 +211,8 @@ static int sb_mixer_set(sb_devc * devc, int dev, int value) ...@@ -212,8 +211,8 @@ static int sb_mixer_set(sb_devc * devc, int dev, int value)
return smw_mixer_set(devc, dev, left, right); return smw_mixer_set(devc, dev, left, right);
break; break;
case MDL_ESS: case MDL_ESS:
if (devc->submodel == SUBMDL_ES18XX) { if (devc->submodel == SUBMDL_ES188X) {
return es18XX_mixer_set(devc, dev, left, right); return es188x_mixer_set(devc, dev, left, right);
} }
break; break;
} }
...@@ -222,7 +221,7 @@ static int sb_mixer_set(sb_devc * devc, int dev, int value) ...@@ -222,7 +221,7 @@ static int sb_mixer_set(sb_devc * devc, int dev, int value)
} }
/* /*
* set_recsrc doesn't apply to ES18XX * set_recsrc doesn't apply to ES188x
*/ */
static void set_recsrc(sb_devc * devc, int src) static void set_recsrc(sb_devc * devc, int src)
{ {
...@@ -230,12 +229,12 @@ static void set_recsrc(sb_devc * devc, int src) ...@@ -230,12 +229,12 @@ static void set_recsrc(sb_devc * devc, int src)
} }
/* /*
* Changing the recmask on a ES18XX means: * Changing the recmask on a ES188x means:
* (1) Find the differences * (1) Find the differences
* (2) For "turned-on" inputs: make the recording level the playback level * (2) For "turned-on" inputs: make the recording level the playback level
* (3) For "turned-off" inputs: make the recording level zero * (3) For "turned-off" inputs: make the recording level zero
*/ */
static int es18XX_set_recmask(sb_devc * devc, int mask) static int es188x_set_recmask(sb_devc * devc, int mask)
{ {
int i, i_mask, cur_mask, diff_mask; int i, i_mask, cur_mask, diff_mask;
int value, left, right; int value, left, right;
...@@ -245,16 +244,16 @@ static int es18XX_set_recmask(sb_devc * devc, int mask) ...@@ -245,16 +244,16 @@ static int es18XX_set_recmask(sb_devc * devc, int mask)
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
i_mask = (1 << i); i_mask = (1 << i);
if (diff_mask & i_mask) { if (diff_mask & i_mask) { /* Difference? (1) */
if (mask & i_mask) { /* Turn it on (2) */ if (mask & i_mask) { /* Turn it on (2) */
value = devc->levels[i]; value = devc->levels[i];
left = value & 0x000000ff; left = value & 0x000000ff;
right = (value & 0x0000ff00) >> 8; right = (value & 0x0000ff00) >> 8;
} else { /* Turn it off (3) */ } else { /* Turn it off (3) */
left = 0; left = 0;
right = 0; right = 0;
} }
common_mixer_set(devc, i + ES18XX_MIXER_RECDIFF, left, right); common_mixer_set(devc, i + ES188X_MIXER_RECDIFF, left, right);
} }
} }
return mask; return mask;
...@@ -269,14 +268,18 @@ static int set_recmask(sb_devc * devc, int mask) ...@@ -269,14 +268,18 @@ static int set_recmask(sb_devc * devc, int mask)
switch (devc->model) switch (devc->model)
{ {
case MDL_ESS: /* ES18XX needs a separate approach */
if (devc->submodel == SUBMDL_ES18XX) {
devmask = es18XX_set_recmask(devc, devmask);
break;
};
case MDL_SBPRO: case MDL_SBPRO:
case MDL_ESS:
case MDL_JAZZ: case MDL_JAZZ:
case MDL_SMW: case MDL_SMW:
if (devc->model == MDL_ESS &&
devc->submodel == SUBMDL_ES188X) {
/*
* ES188x needs a separate approach
*/
devmask = es188x_set_recmask(devc, devmask);
break;
};
if (devmask != SOUND_MASK_MIC && if (devmask != SOUND_MASK_MIC &&
devmask != SOUND_MASK_LINE && devmask != SOUND_MASK_LINE &&
...@@ -507,12 +510,12 @@ static void sb_mixer_reset(sb_devc * devc) ...@@ -507,12 +510,12 @@ static void sb_mixer_reset(sb_devc * devc)
sb_mixer_set(devc, i, devc->levels[i]); sb_mixer_set(devc, i, devc->levels[i]);
/* /*
* Separate actions for ES18XX: * Separate actions for ES188x:
* Change registers 7a and 1c to make the record mixer the input for * Change registers 7a and 1c to make the record mixer the
* * actual recording source.
* Then call set_recmask twice to do extra ES18XX initializations * Then call set_recmask twice to do extra ES188x initializations
*/ */
if (devc->model == MDL_ESS && devc->submodel == SUBMDL_ES18XX) { if (devc->model == MDL_ESS && devc->submodel == SUBMDL_ES188X) {
regval = sb_getmixer(devc, 0x7a); regval = sb_getmixer(devc, 0x7a);
regval = (regval & 0xe7) | 0x08; regval = (regval & 0xe7) | 0x08;
sb_setmixer(devc, 0x7a, regval); sb_setmixer(devc, 0x7a, regval);
...@@ -520,7 +523,7 @@ static void sb_mixer_reset(sb_devc * devc) ...@@ -520,7 +523,7 @@ static void sb_mixer_reset(sb_devc * devc)
regval = (regval & 0xf8) | 0x07; regval = (regval & 0xf8) | 0x07;
sb_setmixer(devc, 0x1c, regval); sb_setmixer(devc, 0x1c, regval);
set_recmask(devc, ES18XX_RECORDING_DEVICES); set_recmask(devc, ES188X_RECORDING_DEVICES);
set_recmask(devc, 0); set_recmask(devc, 0);
} }
set_recmask(devc, SOUND_MASK_MIC); set_recmask(devc, SOUND_MASK_MIC);
...@@ -554,15 +557,15 @@ int sb_mixer_init(sb_devc * devc) ...@@ -554,15 +557,15 @@ int sb_mixer_init(sb_devc * devc)
devc->mixer_caps = SOUND_CAP_EXCL_INPUT; devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
/* /*
* Take care of ES18XX specifics... * Take care of ES188x specifics...
*/ */
switch (devc->submodel) { switch (devc->submodel) {
case SUBMDL_ES18XX: case SUBMDL_ES188X:
devc->supported_devices devc->supported_devices
= ES18XX_MIXER_DEVICES; = ES188X_MIXER_DEVICES;
devc->supported_rec_devices devc->supported_rec_devices
= ES18XX_RECORDING_DEVICES; = ES188X_RECORDING_DEVICES;
devc->iomap = &es18XX_mix; devc->iomap = &es188x_mix;
break; break;
default: default:
devc->supported_devices devc->supported_devices
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* Added defines for the Sound Galaxy NX Pro mixer. * Added defines for the Sound Galaxy NX Pro mixer.
* *
* Rolf Fokkens Dec 20 1998 * Rolf Fokkens Dec 20 1998
* Added (BETA?) support for ES18XX chips. * Added (BETA?) support for ES188x chips.
* Which means: you can adjust the recording levels. * Which means: you can adjust the recording levels.
* *
*/ */
...@@ -51,9 +51,9 @@ ...@@ -51,9 +51,9 @@
#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES #define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER) #define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER)
#define ES18XX_RECORDING_DEVICES (ES688_RECORDING_DEVICES | SOUND_MASK_LINE2 \ #define ES188X_RECORDING_DEVICES (ES688_RECORDING_DEVICES | SOUND_MASK_LINE2 \
|SOUND_MASK_SYNTH) |SOUND_MASK_SYNTH)
#define ES18XX_MIXER_DEVICES (ES688_MIXER_DEVICES) #define ES188X_MIXER_DEVICES (ES688_MIXER_DEVICES)
#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD | \ SOUND_MASK_CD | \
...@@ -118,29 +118,29 @@ ...@@ -118,29 +118,29 @@
#define RIGHT_CHN 1 #define RIGHT_CHN 1
/* /*
* Mixer registers of ES18XX * Mixer registers of ES188x
* *
* These register specifically take care of recording levels. To make the * These register specifically take care of recording levels. To make the
* mapping from playback devices to recording devices every recording * mapping from playback devices to recording devices every recording
* devices = playback device + ES18XX_MIXER_RECDIFF * devices = playback device + ES188X_MIXER_RECDIFF
*/ */
#define ES18XX_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1) #define ES188X_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1)
#define ES18XX_MIXER_RECDIFF (ES18XX_MIXER_RECBASE - SOUND_MIXER_SYNTH) #define ES188X_MIXER_RECDIFF (ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH)
#define ES18XX_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECPCM (SOUND_MIXER_PCM + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECPCM (SOUND_MIXER_PCM + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECLINE (SOUND_MIXER_LINE + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECLINE (SOUND_MIXER_LINE + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECMIC (SOUND_MIXER_MIC + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECMIC (SOUND_MIXER_MIC + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECCD (SOUND_MIXER_CD + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECCD (SOUND_MIXER_CD + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES188X_MIXER_RECDIFF)
#define ES18XX_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES18XX_MIXER_RECDIFF) #define ES188X_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES188X_MIXER_RECDIFF)
/* /*
* Mixer registers of ALS007 * Mixer registers of ALS007
...@@ -188,13 +188,15 @@ MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0) ...@@ -188,13 +188,15 @@ MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0)
}; };
/* /*
* The ES18XX specifics. * The ES188x specifics.
* Note that de master volume unlike ES688 is now controlled by two * Note that de master volume unlike ES688 is now controlled by two 6 bit
* 6 bit registers. * registers. These seem to work OK on 1868 too, but I have no idea if it's
* Also Note that the recording levels (ES18XX_MIXER_REC...) have own * compatible to 688 or 1688....
* entries as if they were playback devices. They are used internally only! * Also Note that the recording levels (ES188X_MIXER_REC...) have own
* entries as if they were playback devices. They are used internally in the
* driver only!
*/ */
static mixer_tab es18XX_mix = { static mixer_tab es188x_mix = {
MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6), MIX_ENT(SOUND_MIXER_VOLUME, 0x60, 5, 6, 0x62, 5, 6),
MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
...@@ -212,21 +214,21 @@ MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0), ...@@ -212,21 +214,21 @@ MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_LINE1, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4), MIX_ENT(SOUND_MIXER_LINE2, 0x3a, 7, 4, 0x3a, 3, 4),
MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_LINE3, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4), MIX_ENT(ES188X_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),
MIX_ENT(ES18XX_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4), MIX_ENT(ES188X_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4),
MIX_ENT(ES18XX_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4), MIX_ENT(ES188X_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4),
MIX_ENT(ES18XX_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4), MIX_ENT(ES188X_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4),
MIX_ENT(ES18XX_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(ES188X_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(ES18XX_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4), MIX_ENT(ES188X_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),
MIX_ENT(ES18XX_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0) MIX_ENT(ES188X_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
}; };
#ifdef __SGNXPRO__ #ifdef __SGNXPRO__
......
...@@ -103,6 +103,10 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name) ...@@ -103,6 +103,10 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
struct autofs_wait_queue *wq; struct autofs_wait_queue *wq;
int status; int status;
/* In catatonic mode, we don't wait for nobody */
if ( sbi->catatonic )
return -ENOENT;
for ( wq = sbi->queues ; wq ; wq = wq->next ) { for ( wq = sbi->queues ; wq ; wq = wq->next ) {
if ( wq->hash == name->hash && if ( wq->hash == name->hash &&
wq->len == name->len && wq->len == name->len &&
...@@ -138,6 +142,15 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name) ...@@ -138,6 +142,15 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name)
/* wq->name is NULL if and only if the lock is already released */ /* wq->name is NULL if and only if the lock is already released */
if ( sbi->catatonic ) {
/* We might have slept, so check again for catatonic mode */
wq->status = -ENOENT;
if ( wq->name ) {
kfree(wq->name);
wq->name = NULL;
}
}
if ( wq->name ) { if ( wq->name ) {
/* Block all but "shutdown" signals while waiting */ /* Block all but "shutdown" signals while waiting */
sigset_t oldset; sigset_t oldset;
......
...@@ -592,9 +592,10 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) ...@@ -592,9 +592,10 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
struct list_head *head = d_hash(parent,hash); struct list_head *head = d_hash(parent,hash);
struct list_head *tmp = head->next; struct list_head *tmp = head->next;
while (tmp != head) { for (;;) {
struct dentry * dentry = list_entry(tmp, struct dentry, d_hash); struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
if (tmp == head)
break;
tmp = tmp->next; tmp = tmp->next;
if (dentry->d_name.hash != hash) if (dentry->d_name.hash != hash)
continue; continue;
......
...@@ -428,7 +428,7 @@ fat_read_super(struct super_block *sb, void *data, int silent) ...@@ -428,7 +428,7 @@ fat_read_super(struct super_block *sb, void *data, int silent)
MSDOS_SB(sb)->fat_bits,opts.name_check, MSDOS_SB(sb)->fat_bits,opts.name_check,
opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask, opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : ""); MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d," printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
"se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n", "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
b->media,MSDOS_SB(sb)->cluster_size, b->media,MSDOS_SB(sb)->cluster_size,
MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start, MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,
......
...@@ -438,6 +438,7 @@ parent->d_name.name, dentry->d_name.name); ...@@ -438,6 +438,7 @@ parent->d_name.name, dentry->d_name.name);
/* Ok, remeber that we successfully checked it.. */ /* Ok, remeber that we successfully checked it.. */
nfs_renew_times(dentry); nfs_renew_times(dentry);
nfs_refresh_inode(inode, &fattr);
out_valid: out_valid:
return 1; return 1;
......
...@@ -701,12 +701,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); ...@@ -701,12 +701,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
#endif #endif
goto out; goto out;
} }
if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) {
/* Update attrtimeo value */
if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
}
NFS_OLDMTIME(inode) = fattr.mtime.seconds;
dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n", dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
dentry->d_parent->d_name.name, dentry->d_name.name); dentry->d_parent->d_name.name, dentry->d_name.name);
out: out:
...@@ -791,6 +785,14 @@ printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino); ...@@ -791,6 +785,14 @@ printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
if (invalid) if (invalid)
goto out_invalid; goto out_invalid;
/* Update attrtimeo value */
if (fattr->mtime.seconds == NFS_OLDMTIME(inode)) {
if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
}
NFS_OLDMTIME(inode) = fattr->mtime.seconds;
out: out:
return error; return error;
......
...@@ -167,11 +167,11 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) ...@@ -167,11 +167,11 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
* to devices. * to devices.
* *
* For now, "wmb()" doesn't actually do anything, as all * For now, "wmb()" doesn't actually do anything, as all
* intel CPU's follow what intel calls a *Processor Order*, * Intel CPU's follow what Intel calls a *Processor Order*,
* in which all writes are seen in the program order even * in which all writes are seen in the program order even
* outside the CPU. * outside the CPU.
* *
* I expect future intel CPU's to have a weaker ordering, * I expect future Intel CPU's to have a weaker ordering,
* but I'd also expect them to finally get their act together * but I'd also expect them to finally get their act together
* and add some real memory barriers if so. * and add some real memory barriers if so.
*/ */
......
...@@ -15,19 +15,31 @@ ...@@ -15,19 +15,31 @@
/* /*
* Standard way to access the cycle counter on i586+ CPUs. * Standard way to access the cycle counter on i586+ CPUs.
* Currently only used on SMP. * Currently only used on SMP.
*
* If you really have a SMP machine with i486 chips or older,
* compile for that, and this will just always return zero.
* That's ok, it just means that the nicer scheduling heuristics
* won't work for you.
*
* We only use the low 32 bits, and we'd simply better make sure
* that we reschedule before that wraps. Scheduling at least every
* four billion cycles just basically sounds like a good idea,
* regardless of how fast the machine is.
*/ */
typedef unsigned long long cycles_t; typedef unsigned long cycles_t;
extern cycles_t cacheflush_time; extern cycles_t cacheflush_time;
static inline cycles_t get_cycles (void) static inline cycles_t get_cycles (void)
{ {
cycles_t value; #if CPU < 586
return 0;
#else
unsigned long eax, edx;
__asm__("rdtsc" __asm__("rdtsc":"=a" (eax), "=d" (edx));
:"=a" (*(((int *)&value)+0)), return eax;
"=d" (*(((int *)&value)+1))); #endif
return value;
} }
#endif #endif
...@@ -110,12 +110,14 @@ struct solaris_x86_vtoc { ...@@ -110,12 +110,14 @@ struct solaris_x86_vtoc {
* BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il> * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
* updated by Marc Espie <Marc.Espie@openbsd.org> * updated by Marc Espie <Marc.Espie@openbsd.org>
*/ */
#define FREEBSD_PARTITION 0xa5 /* FreeBSD Partition ID */ #define FREEBSD_PARTITION 0xa5 /* FreeBSD Partition ID */
#define OPENBSD_PARTITION 0xa6 /* OpenBSD Partition ID */ #define OPENBSD_PARTITION 0xa6 /* OpenBSD Partition ID */
#define NETBSD_PARTITION 0xa9 /* NetBSD Partition ID */ #define NETBSD_PARTITION 0xa9 /* NetBSD Partition ID */
#define BSDI_PARTITION 0xb7 /* BSDI Partition ID */ #define BSDI_PARTITION 0xb7 /* BSDI Partition ID */
/* Ours is not to wonder why.. */
#define BSD_PARTITION FREEBSD_PARTITION
/* check against BSD src/sys/sys/disklabel.h for consistency */ /* check against BSD src/sys/sys/disklabel.h for consistency */
#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
......
...@@ -166,10 +166,10 @@ static inline void reschedule_idle(struct task_struct * p) ...@@ -166,10 +166,10 @@ static inline void reschedule_idle(struct task_struct * p)
#ifdef __SMP__ #ifdef __SMP__
/* /*
* ("wakeup()" should not be called before we've initialized * ("wakeup()" should not be called before we've initialized
* SMP completely. [Linus, is there any exception to this?] * SMP completely.
* Basically a not-yet initialized SMP subsystem can be * Basically a not-yet initialized SMP subsystem can be
* considered as a not-yet working scheduler, simply dont use * considered as a not-yet working scheduler, simply dont use
* it before it'd up and running ...) * it before it's up and running ...)
* *
* SMP rescheduling is done in 2 passes: * SMP rescheduling is done in 2 passes:
* - pass #1: faster: 'quick decisions' * - pass #1: faster: 'quick decisions'
...@@ -181,9 +181,10 @@ static inline void reschedule_idle(struct task_struct * p) ...@@ -181,9 +181,10 @@ static inline void reschedule_idle(struct task_struct * p)
* *
* There are two metrics here: * There are two metrics here:
* *
* first, a 'cutoff' interval, currently ~250 usecs on * first, a 'cutoff' interval, currently 0-200 usecs on
* x86 CPUs. If the current process has longer average * x86 CPUs, depending on the size of the 'SMP-local cache'.
* timeslices than this, then we utilize the idle CPU. * If the current process has longer average timeslices than
* this, then we utilize the idle CPU.
* *
* second, if the wakeup comes from a process context, * second, if the wakeup comes from a process context,
* then the two processes are 'related'. (they form a * then the two processes are 'related'. (they form a
...@@ -308,8 +309,6 @@ static void process_timeout(unsigned long __data) ...@@ -308,8 +309,6 @@ static void process_timeout(unsigned long __data)
wake_up_process(p); wake_up_process(p);
} }
int _PROC_CHANGE_PENALTY = 13;
/* /*
* This is the function that decides how desirable a process is.. * This is the function that decides how desirable a process is..
* You can weigh different processes against each other depending * You can weigh different processes against each other depending
......
...@@ -41,7 +41,7 @@ static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, in ...@@ -41,7 +41,7 @@ static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, in
struct swap_info_struct * p; struct swap_info_struct * p;
int zones[PAGE_SIZE/512]; int zones[PAGE_SIZE/512];
int zones_used; int zones_used;
kdev_t dev; kdev_t dev = 0;
int block_size; int block_size;
#ifdef DEBUG_SWAP #ifdef DEBUG_SWAP
......
...@@ -2284,7 +2284,6 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) ...@@ -2284,7 +2284,6 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
case SIOCIPXNCPCONN: case SIOCIPXNCPCONN:
{ {
int err;
/* /*
* This socket wants to take care of the NCP connection * This socket wants to take care of the NCP connection
* handed to us in arg. * handed to us in arg.
......
...@@ -52,6 +52,8 @@ ...@@ -52,6 +52,8 @@
#include <net/ax25.h> #include <net/ax25.h>
#include <net/netrom.h> #include <net/netrom.h>
#ifdef CONFIG_INET
/* /*
* Only allow IP over NET/ROM frames through if the netrom device is up. * Only allow IP over NET/ROM frames through if the netrom device is up.
*/ */
...@@ -81,37 +83,6 @@ int nr_rx_ip(struct sk_buff *skb, struct device *dev) ...@@ -81,37 +83,6 @@ int nr_rx_ip(struct sk_buff *skb, struct device *dev)
return 1; return 1;
} }
static int nr_header(struct sk_buff *skb, struct device *dev, unsigned short type,
void *daddr, void *saddr, unsigned len)
{
unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
buff[6] &= ~AX25_CBIT;
buff[6] &= ~AX25_EBIT;
buff[6] |= AX25_SSSID_SPARE;
buff += AX25_ADDR_LEN;
if (daddr != NULL)
memcpy(buff, daddr, dev->addr_len);
buff[6] &= ~AX25_CBIT;
buff[6] |= AX25_EBIT;
buff[6] |= AX25_SSSID_SPARE;
buff += AX25_ADDR_LEN;
*buff++ = sysctl_netrom_network_ttl_initialiser;
*buff++ = NR_PROTO_IP;
*buff++ = NR_PROTO_IP;
*buff++ = 0;
*buff++ = 0;
*buff++ = NR_PROTOEXT;
if (daddr != NULL)
return 37;
return -37;
}
static int nr_rebuild_header(struct sk_buff *skb) static int nr_rebuild_header(struct sk_buff *skb)
{ {
...@@ -121,10 +92,6 @@ static int nr_rebuild_header(struct sk_buff *skb) ...@@ -121,10 +92,6 @@ static int nr_rebuild_header(struct sk_buff *skb)
unsigned char *bp = skb->data; unsigned char *bp = skb->data;
if (arp_find(bp + 7, skb)) { if (arp_find(bp + 7, skb)) {
#if 0
/* BUGGGG! If arp_find returned 1, skb does not exist. --ANK*/
kfree_skb(skb);
#endif
return 1; return 1;
} }
...@@ -158,6 +125,47 @@ static int nr_rebuild_header(struct sk_buff *skb) ...@@ -158,6 +125,47 @@ static int nr_rebuild_header(struct sk_buff *skb)
return 1; return 1;
} }
#else
static int nr_rebuild_header(struct sk_buff *skb)
{
return 1;
}
#endif
static int nr_header(struct sk_buff *skb, struct device *dev, unsigned short type,
void *daddr, void *saddr, unsigned len)
{
unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
buff[6] &= ~AX25_CBIT;
buff[6] &= ~AX25_EBIT;
buff[6] |= AX25_SSSID_SPARE;
buff += AX25_ADDR_LEN;
if (daddr != NULL)
memcpy(buff, daddr, dev->addr_len);
buff[6] &= ~AX25_CBIT;
buff[6] |= AX25_EBIT;
buff[6] |= AX25_SSSID_SPARE;
buff += AX25_ADDR_LEN;
*buff++ = sysctl_netrom_network_ttl_initialiser;
*buff++ = NR_PROTO_IP;
*buff++ = NR_PROTO_IP;
*buff++ = 0;
*buff++ = 0;
*buff++ = NR_PROTOEXT;
if (daddr != NULL)
return 37;
return -37;
}
static int nr_set_mac_address(struct device *dev, void *addr) static int nr_set_mac_address(struct device *dev, void *addr)
{ {
struct sockaddr *sa = addr; struct sockaddr *sa = addr;
......
...@@ -37,9 +37,9 @@ ...@@ -37,9 +37,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> /* support for loadable modules */ #include <linux/module.h> /* support for loadable modules */
#include <linux/malloc.h> /* kmalloc(), kfree() */ #include <linux/malloc.h> /* kmalloc(), kfree() */
#include <linux/vmalloc.h> /* vmalloc(), vfree() */
#include <linux/mm.h> /* verify_area(), etc. */ #include <linux/mm.h> /* verify_area(), etc. */
#include <linux/string.h> /* inline mem*, str* functions */ #include <linux/string.h> /* inline mem*, str* functions */
#include <linux/vmalloc.h> /* vmalloc, vfree */
#include <asm/segment.h> /* kernel <-> user copy */ #include <asm/segment.h> /* kernel <-> user copy */
#include <asm/byteorder.h> /* htons(), etc. */ #include <asm/byteorder.h> /* htons(), etc. */
#include <asm/uaccess.h> /* copy_to/from_user */ #include <asm/uaccess.h> /* copy_to/from_user */
...@@ -104,7 +104,30 @@ static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 }; ...@@ -104,7 +104,30 @@ static unsigned char oui_ether[] = { 0x00, 0x00, 0x00 };
static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 }; static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };
#endif #endif
#ifdef MODULE #ifndef MODULE
int wanrouter_init(void)
{
int err;
extern void wanpipe_init(void);
printk(KERN_INFO "%s v%u.%u %s\n",
fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
err = wanrouter_proc_init();
if (err)
printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname);
/*
* Initialise compiled in boards
*/
#ifdef CONFIG_VENDOR_SANGOMA
wanpipe_init();
#endif
return err;
}
#else
/* /*
* Kernel Loadable Module Entry Points * Kernel Loadable Module Entry Points
...@@ -143,14 +166,6 @@ void cleanup_module (void) ...@@ -143,14 +166,6 @@ void cleanup_module (void)
wanrouter_proc_cleanup(); wanrouter_proc_cleanup();
} }
#else
__initfunc(void wanrouter_init(void))
{
int err = wanrouter_proc_init();
if (err) printk(KERN_ERR
"%s: can't create entry in proc filesystem!\n", modname);
}
#endif #endif
/* /*
...@@ -444,7 +459,7 @@ int wanrouter_ioctl(struct inode* inode, struct file* file, ...@@ -444,7 +459,7 @@ int wanrouter_ioctl(struct inode* inode, struct file* file,
static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf) static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
{ {
void* data; void* data;
wandev_conf_t* conf; wandev_conf_t *conf;
int err= -EINVAL; int err= -EINVAL;
if (wandev->setup == NULL) /* Nothing to do ? */ if (wandev->setup == NULL) /* Nothing to do ? */
...@@ -477,9 +492,13 @@ static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf) ...@@ -477,9 +492,13 @@ static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
err = wandev->setup(wandev,conf); err = wandev->setup(wandev,conf);
} }
else else
err = -ENOBUFS; err = -EFAULT;
vfree(data);
} }
else
err = -ENOBUFS;
if (data)
vfree(data);
} }
bail: bail:
kfree(conf); kfree(conf);
......
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