VERSION = 2
-PATCHLEVEL = 1
-SUBLEVEL = 133
+PATCHLEVEL = 2
+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/)
ROOT_DEV = CURRENT
+KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
#
# INSTALL_PATH specifies where to place the updated kernel and system map
# images. Uncomment if you want to place them anywhere other than root.
@mv -f .ver $@
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 KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
@mv -f .ver $@
modules_install:
@( \
- MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \
+ MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \
cd modules; \
MODULES=""; \
inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \
} else
lockup = 0;
- if (!last || time_after(jiffies, last + 500)) {
+ if (!last || time_after(jiffies, last + 5*HZ)) {
last = jiffies;
printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
}
printk(".... register #01: %08X\n", *(int *)®_01);
printk("....... : max redirection entries: %04X\n", reg_01.entries);
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();
if (reg_01.entries == 0x0f)
printk("....... : IO APIC version: %04X\n", reg_01.version);
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();
if (reg_01.__reserved_1 || reg_01.__reserved_2)
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 */
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.. */
volatile unsigned long kernel_counter=0; /* Number of times the processor holds the lock */
* we use to track CPUs as they power up.
*/
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+
void __init smp_commence(void)
{
/*
* Lets the callins below out of their loop.
*/
SMP_PRINTK(("Setting commenced=1, go go go\n"));
- smp_commenced=1;
+
+ wmb();
+ atomic_set(&smp_commenced,1);
}
void __init enable_local_APIC(void)
mtrr_init_secondary_cpu ();
#endif
smp_callin();
- while (!smp_commenced)
- barrier();
+ while (!atomic_read(&smp_commenced))
+ /* nothing */ ;
return cpu_idle(NULL);
}
*((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_counter[NR_CPUS];
*/
smp_store_cpu_info(boot_cpu_id); /* Final full version of the data */
+ smp_tune_scheduling();
printk("CPU%d: ", boot_cpu_id);
print_cpu_info(&cpu_data[boot_cpu_id]);
unsigned long cpu_hz; /* Detected as we calibrate the TSC */
-cycles_t cacheflush_time;
-
/* Number of usecs that the last interrupt was delayed */
static int delay_at_last_interrupt;
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 edx asm("dx");
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
* It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
*
* comp.protocols.time.ntp!
*/
-#define TICK_SIZE tick
-
static unsigned long do_slow_gettimeoffset(void)
{
int count;
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+#else
+
+#define do_gettimeoffset() do_fast_gettimeoffset()
+
+#endif
+
/*
* This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC.
* smart. See arch/i386/kernel/apm.c.
*/
if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+#ifndef do_gettimeoffset
do_gettimeoffset = do_fast_gettimeoffset;
+#endif
do_get_fast_time = do_gettimeofday;
use_tsc = 1;
fast_gettimeoffset_quotient = calibrate_tsc();
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);
}
if (bh[i]) {
clear_bit(BH_Dirty, &bh[i]->b_state);
clear_bit(BH_Uptodate, &bh[i]->b_state);
+ bh[i]->b_end_io(bh[i], 0);
}
}
return;
}
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
static int release_aux(struct inode * inode, struct file * file)
{
fasync_aux(-1, file, 0);
return 0;
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);
-#ifdef CONFIG_MCA
- free_irq(AUX_IRQ, inode);
-#else
- free_irq(AUX_IRQ, NULL);
-#endif
+ free_irq(AUX_IRQ, AUX_DEV);
return 0;
}
return 0;
}
queue->head = queue->tail = 0; /* Flush input queue */
-#ifdef CONFIG_MCA
- 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
+ if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) {
aux_count--;
return -EBUSY;
}
68K Macintosh. Support >16bit I/O spaces
Paul Gortmaker : add kmod support for auto-loading of the 8390
module by all drivers that require it.
-
+ Alan Cox : Spinlocking work, added 'BUG_83C690'
Sources:
The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
#define NS8390_CORE
#include "8390.h"
+#define BUG_83C690
+
/* These are the operational function interfaces to board-specific
routines.
void reset_8390(struct device *dev)
static void NS8390_trigger_send(struct device *dev, unsigned int length,
int start_page);
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.
+ */
+
\f
/* Open/initialize the board. This routine goes all-out, setting everything
*/
int ei_open(struct device *dev)
{
+ unsigned long flags;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
/* This can't happen unless somebody forgot to call ethdev_init(). */
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);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
dev->start = 1;
ei_local->irqlock = 0;
return 0;
/* Opposite of above. Only used when "ifconfig <devname> down" is done. */
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);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
dev->start = 0;
return 0;
}
int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
int length, send_length, output_page;
+ unsigned long flags;
/*
* 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
- * 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)
{ /* 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;
+
+ /*
+ * 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)))
+ {
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
return 1;
+ }
ei_local->stat.tx_errors++;
isr = inb(e8390_base+EN0_ISR);
if (dev->start == 0)
{
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name);
return 1;
}
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. */
ei_reset_8390(dev);
NS8390_init(dev, 1);
+
+ spin_unlock(&ei_local->page_lock);
+ enable_irq(dev->irq);
dev->trans_start = jiffies;
}
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);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+
+ /*
+ * Slow phase with lock held.
+ */
+
disable_irq(dev->irq);
synchronize_irq();
+
+ spin_lock(&ei_local->page_lock);
+
if (dev->interrupt)
{
printk(KERN_WARNING "%s: Tx request while isr active.\n",dev->name);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq);
ei_local->stat.tx_errors++;
dev_kfree_skb(skb);
ei_local->irqlock = 0;
dev->tbusy = 1;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq);
ei_local->stat.tx_errors++;
return 1;
/* Turn 8390 interrupts back on. */
ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+
+ spin_unlock(&ei_local->page_lock);
enable_irq(dev->irq);
dev_kfree_skb (skb);
e8390_base = dev->base_addr;
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 1 /* This might just be an interrupt for a PCI device sharing this line */
dev->name, inb_p(e8390_base + EN0_ISR),
inb_p(e8390_base + EN0_IMR));
#endif
+ spin_unlock(&ei_local->page_lock);
return;
}
+
dev->interrupt = 1;
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
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));
/* !!Assumption!! -- we stay in page 0. Don't break this. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
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);
outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
} 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. */
}
}
dev->interrupt = 0;
+ spin_unlock(&ei_local->page_lock);
return;
}
* 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
* an unnecessary card reset.
+ *
+ * Called with lock held
*/
static void ei_tx_err(struct device *dev)
}
/* 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)
{
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)
{
* the updated datasheets, or "the NIC may act in an unpredictable manner."
* This includes causing "the NIC to defer indefinitely when it is stopped
* 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)
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)
{
int ioaddr = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ unsigned long flags;
/* If the card is stopped, just return the present stats. */
if (dev->start == 0)
return &ei_local->stat;
+ spin_lock_irqsave(&ei_local->page_lock,flags);
/* 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_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
return &ei_local->stat;
}
}
/*
- * 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 i;
- unsigned long flags;
struct ei_device *ei_local = (struct ei_device*)dev->priv;
if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
* them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
* Ultra32 EISA) appears to have this bug fixed.
*/
+
if (dev->start)
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
- save_flags(flags);
- cli();
outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
for(i = 0; i < 8; 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])
printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
#endif
}
outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
- restore_flags(flags);
if(dev->flags&IFF_PROMISC)
outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
else
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
* this, as it is used by 8390 based modular drivers too.
*/
+
int ethdev_init(struct device *dev)
{
if (ei_debug > 1)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct ei_device));
ei_local = (struct ei_device *)dev->priv;
+ spin_lock_init(&ei_local->page_lock);
}
dev->hard_start_xmit = &ei_start_xmit;
/* This page of functions should be 8390 generic */
/* Follow National Semi's recommendations for initializing the "NIC". */
+/*
+ * Must be called with lock held.
+ */
+
void NS8390_init(struct device *dev, int startp)
{
int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
int i;
int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
- unsigned long flags;
if(sizeof(struct e8390_pkt_hdr)!=4)
panic("8390.c: header struct mispacked\n");
outb_p(0x00, e8390_base + EN0_IMR);
/* 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 */
for(i = 0; i < 6; i++)
{
outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
- restore_flags(flags);
+
dev->tbusy = 0;
dev->interrupt = 0;
ei_local->tx1 = ei_local->tx2 = 0;
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
/* 3c503 TechMan says rxconfig only after the NIC is started. */
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;
}
-/* 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,
int start_page)
{
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);
if (inb_p(e8390_base) & E8390_TRANS)
things in there should be here!) */
/* You have one of these per-board */
struct ei_device {
- const char *name;
- void (*reset_8390)(struct device *);
- void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
- void (*block_output)(struct device *, int, const unsigned char *, int);
- void (*block_input)(struct device *, int, struct sk_buff *, int);
- unsigned char mcfilter[8];
- unsigned open:1;
- unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
- unsigned txing:1; /* Transmit Active */
- unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
- unsigned dmaing:1; /* Remote DMA Active */
- unsigned char tx_start_page, rx_start_page, stop_page;
- unsigned char current_page; /* Read pointer in buffer */
- unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
- unsigned char txqueue; /* Tx Packet buffer queue length. */
- short tx1, tx2; /* Packet lengths for ping-pong tx. */
- short lasttx; /* Alpha version consistency check. */
- unsigned char reg0; /* Register '0' in a WD8013 */
- unsigned char reg5; /* Register '5' in a WD8013 */
- unsigned char saved_irq; /* Original dev->irq value. */
- /* The new statistics table. */
- struct net_device_stats stat;
- unsigned char *reg_offset; /* Register mapping table */
- unsigned long priv; /* Private field to store bus IDs etc. */
+ const char *name;
+ void (*reset_8390)(struct device *);
+ void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
+ void (*block_output)(struct device *, int, const unsigned char *, int);
+ void (*block_input)(struct device *, int, struct sk_buff *, int);
+ unsigned char mcfilter[8];
+ unsigned open:1;
+ unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
+ unsigned txing:1; /* Transmit Active */
+ unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
+ unsigned dmaing:1; /* Remote DMA Active */
+ unsigned char tx_start_page, rx_start_page, stop_page;
+ unsigned char current_page; /* Read pointer in buffer */
+ unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
+ unsigned char txqueue; /* Tx Packet buffer queue length. */
+ short tx1, tx2; /* Packet lengths for ping-pong tx. */
+ short lasttx; /* Alpha version consistency check. */
+ unsigned char reg0; /* Register '0' in a WD8013 */
+ unsigned char reg5; /* Register '5' in a WD8013 */
+ unsigned char saved_irq; /* Original dev->irq value. */
+ struct net_device_stats stat; /* The new statistics table. */
+ u32 *reg_offset; /* Register mapping table */
+ spinlock_t page_lock; /* Page register locks */
+ unsigned long priv; /* Private field to store bus IDs etc. */
};
/* The maximum number of 8390 interrupt service routines called per IRQ. */
#define ei_status (*(struct ei_device *)(dev->priv))
/* Some generic ethernet register configurations. */
-#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
-#define E8390_RX_IRQ_MASK 0x5
-#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
-#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
-#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
-#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
+#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK 0x5
+#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
+#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
/* Register accessed at EN_CMD, the 8390 base addr. */
#define E8390_STOP 0x01 /* Stop and reset the chip */
#define E8390_PAGE1 0x40 /* using the two high-order bits */
#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) || \
defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE)
#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>
#endif
{
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__
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif
get_user_ret(len, &(d->len), -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;
if ((i=download(cosa, d->code, len, addr)) < 0) {
* separate functions to make it more readable. These functions are inline,
* 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)
{
unsigned long flags, flags1;
#endif
spin_lock_irqsave(&cosa->lock, flags);
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)) {
+ /* flow control */
+ int i=0;
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++;
if (cosa->txchan >= cosa->nchannels)
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;
if (cosa_dma_able(cosa->chan+cosa->txchan,
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>
#define SR_START_ADDR 0x4400 /* SRP microcode start address */
#define COSA_LOAD_ADDR 0x400 /* SRP microcode load address */
-
+#define COSA_MAX_FIRMWARE_SIZE 0x10000
/* ioctls */
struct cosa_download {
static int dma[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 struct device dev_lance[MAX_CARDS] =
{{
{
int *port, result;
- if (high_memory <= 16*1024*1024)
+ if (high_memory <= phys_to_virt(16*1024*1024))
lance_need_isa_bounce_buffers = 0;
#if defined(CONFIG_PCI)
- if (pci_present()) {
+ if (pci_present())
+ {
struct pci_dev *pdev = NULL;
if (lance_debug > 1)
printk("lance.c: PCI bios is present, checking for devices...\n");
* 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/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
* < 0 error.
* Context: process
*/
+
+#ifdef MODULE
int init_module (void)
+#else
+int wanpipe_init(void)
+#endif
{
int cnt, err = 0;
return err;
}
+#ifdef MODULE
/*============================================================================
* Module 'remove' entry point.
* o unregister all adapters from the WAN router
kfree(card_array);
}
+#endif
+
/******* WAN Device Driver Entry Points *************************************/
/*============================================================================
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/version.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
* In case you are wondering what the last line of the asm does...
* <output allocation> : <input allocation> : <trashed registers>
*/
+ register int d0;
+
asm("shr $2,%%ecx\n" \
" jz .no_more_bulk_bo\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".loop_bulk_bo:\n" \
" movl (%%esi),%%ebx\n" \
BYTE_OUT(%%bl) \
BYTE_OUT(%%bh) \
" addl $4,%%esi\n" \
" loop .loop_bulk_bo\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".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" \
" jz .no_more_loose_bo\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".loop_loose_bo:\n" \
BYTE_OUT((%%esi)) \
" incl %%esi\n" \
" loop .loop_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! */
}
* In case you are wondering what the last line of the asm does...
* <output allocation> : <input allocation> : <trashed registers>
*/
+ register int d0;
+
asm("shr $2,%%ecx\n" \
" jz .no_more_bulk_bi\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".loop_bulk_bi:\n" \
BYTE_IN(%%bl) \
BYTE_IN(%%bh) \
" movl %%ebx,(%%esi)\n" \
" addl $4,%%esi\n" \
" loop .loop_bulk_bi\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".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" \
" jz .no_more_loose_bi\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".loop_loose_bi:\n" \
BYTE_IN((%%esi)) \
" incl %%esi\n" \
" loop .loop_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! */
}
* In case you are wondering what the last line of the asm does...
* <output allocation> : <input allocation> : <trashed registers>
*/
+ register int d0;
+
asm("shr $2,%%ecx\n" \
" jz .no_more_bulk_ni\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".loop_bulk_ni:\n" \
NIBBLE_IN(%%bl) \
NIBBLE_IN(%%bh) \
" movl %%ebx,(%%esi)\n" \
" addl $4,%%esi\n" \
" loop .loop_bulk_ni\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".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" \
" jz .no_more_loose_ni\n" \
- " .align 4\n" \
+ " .p2align 4,,7\n" \
".loop_loose_ni:\n" \
NIBBLE_IN((%%esi)) \
" incl %%esi\n" \
" loop .loop_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! */
}
#else /* Old style C routines */
/* --------------------------------------------------------------------- */
-static const struct initvol {
+static struct initvol {
int mixch;
int vol;
} initvol[] __initdata = {
* Improved debugging support. 16-May-1998
* Fixed bug. 16-Jun-1998
*
+ * Torsten Duwe Made Opti924 PnP support non-destructive
+ * 1998-12-23
*/
#include "sound_config.h"
if ((mad_read(MC0_PORT+13) & 0x80) == 0)
return 1;
+#if 0
/* Force off PnP mode. This is not recommended because
* the PnP bios will not recognize the chip on the next
* warm boot and may assignd different resources to other
* PnP/PCI cards.
*/
mad_write(MC0_PORT+17, 0x04);
+#endif
return 1;
}
static int detect_mad16(void)
{
- unsigned char tmp, tmp2;
- int i;
+ unsigned char tmp, tmp2, bit;
+ int i, port;
/*
* Check that reading a register doesn't return bus float (0xff)
DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
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));
return 0;
}
- mad_write(MC1_PORT, tmp); /* Restore */
+ mad_write(port, tmp); /* Restore */
return 1; /* Bingo */
}
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 */
{
- c924pnp=0;
board_type = C928;
DDB(printk("Detect using password = 0xE2\n"));
for (i = 0xf8d; i <= 0xf93; i++)
DDB(printk("port %03x = %02x\n", i, mad_read(i)));
- if (!detect_mad16())
- return 0;
-
- DDB(printk("mad16.c: 82C930 detected\n"));
+ if (!detect_mad16()) {
+ board_type = C924;
+ c924pnp++;
+ 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
DDB(printk("mad16.c: 82C929 detected\n"));
} else {
hw_config->dma,
dma2,
0);
- sound_unload_audiodev(hw_config->slots[0]);
}
void unload_opl3sa_mpu(struct address_info *hw_config)
#define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */
#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 */
/* register assignment */
/*
/*
* Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
* for full duplex support ( only sb16 by now )
- * Rolf Fokkens: Added (BETA?) support for ES18XX chips.
- * Which means: you can adjust the recording levels.
+ * Rolf Fokkens: Added (BETA?) support for ES188x chips.
+ * (fokkensr@vertis.nl) Which means: You can adjust the recording levels.
*/
#include <linux/config.h>
#include <linux/delay.h>
/*
* This the detection heuristic of ESS technology, though somewhat
- * changed to actually make it work :-)
- * This is the most BETA part of the software: Will it work?
+ * changed to actually make it work.
+ * This is the most BETA part of the software: Will the detection
+ * always work?
*/
devc->model = MDL_ESS;
devc->submodel = ess_minor & 0x0f;
if ((ess_minor & 0x0f) >= 8) {
if ( !ess_probe (devc, 0x64, (1 << 3))
&& ess_probe (devc, 0x70, 0x7f)) {
- chip = "ES18XX";
- devc->submodel = SUBMDL_ES18XX;
+ chip = "ES188x";
+ devc->submodel = SUBMDL_ES188X;
} else {
chip = "ES1688";
};
/*
* 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.
*/
*
*
* 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
* it's recording level is loud, and it cannot be changed.
*
- * The ES18XX has separate registers to controll the recording levels. The
- * ES18XX specific software makes these level the same as their corresponding
- * playback levels, unless recmask says they aren't recorded. In tha latter
- * case the recording volumens are 0.
+ * The ES188x has separate registers to control the recording levels. The
+ * ES188x specific software makes these level the same as their corresponding
+ * playback levels, unless recmask says they aren't recorded. In the latter
+ * case the recording volumes are 0.
*
* Now recording levels of inputs can be controlled, by changing the playback
- * levels.
- * Futhermore several devices can be recorded together (which is not possible
- * with the ES688.
+ * levels. Futhermore several devices can be recorded together (which is not
+ * possible with the ES1688.
*/
#include <linux/config.h>
}
/*
- * Changing input levels at ES18XX means having to take care of recording
- * levels of recorded inputs too!
+ * Changing playback levels at ES188x means having to take care of recording
+ * 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)) {
- 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 smw_mixer_set(devc, dev, left, right);
break;
case MDL_ESS:
- if (devc->submodel == SUBMDL_ES18XX) {
- return es18XX_mixer_set(devc, dev, left, right);
+ if (devc->submodel == SUBMDL_ES188X) {
+ return es188x_mixer_set(devc, dev, left, right);
}
break;
}
}
/*
- * set_recsrc doesn't apply to ES18XX
+ * set_recsrc doesn't apply to ES188x
*/
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
* (2) For "turned-on" inputs: make the recording level the playback level
* (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 value, left, right;
for (i = 0; i < 32; i++) {
i_mask = (1 << i);
- if (diff_mask & i_mask) {
- if (mask & i_mask) { /* Turn it on (2) */
+ if (diff_mask & i_mask) { /* Difference? (1) */
+ if (mask & i_mask) { /* Turn it on (2) */
value = devc->levels[i];
left = value & 0x000000ff;
right = (value & 0x0000ff00) >> 8;
- } else { /* Turn it off (3) */
+ } else { /* Turn it off (3) */
left = 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;
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_ESS:
case MDL_JAZZ:
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 &&
devmask != SOUND_MASK_LINE &&
sb_mixer_set(devc, i, devc->levels[i]);
/*
- * Separate actions for ES18XX:
- * Change registers 7a and 1c to make the record mixer the input for
- *
- * Then call set_recmask twice to do extra ES18XX initializations
+ * Separate actions for ES188x:
+ * Change registers 7a and 1c to make the record mixer the
+ * actual recording source.
+ * 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 = (regval & 0xe7) | 0x08;
sb_setmixer(devc, 0x7a, regval);
regval = (regval & 0xf8) | 0x07;
sb_setmixer(devc, 0x1c, regval);
- set_recmask(devc, ES18XX_RECORDING_DEVICES);
+ set_recmask(devc, ES188X_RECORDING_DEVICES);
set_recmask(devc, 0);
}
set_recmask(devc, SOUND_MASK_MIC);
devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
/*
- * Take care of ES18XX specifics...
+ * Take care of ES188x specifics...
*/
switch (devc->submodel) {
- case SUBMDL_ES18XX:
+ case SUBMDL_ES188X:
devc->supported_devices
- = ES18XX_MIXER_DEVICES;
+ = ES188X_MIXER_DEVICES;
devc->supported_rec_devices
- = ES18XX_RECORDING_DEVICES;
- devc->iomap = &es18XX_mix;
+ = ES188X_RECORDING_DEVICES;
+ devc->iomap = &es188x_mix;
break;
default:
devc->supported_devices
* Added defines for the Sound Galaxy NX Pro mixer.
*
* 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.
*
*/
#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
#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)
-#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 | \
SOUND_MASK_CD | \
#define RIGHT_CHN 1
/*
- * Mixer registers of ES18XX
+ * Mixer registers of ES188x
*
* These register specifically take care of recording levels. To make the
* 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 ES18XX_MIXER_RECDIFF (ES18XX_MIXER_RECBASE - SOUND_MIXER_SYNTH)
-
-#define ES18XX_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECPCM (SOUND_MIXER_PCM + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECLINE (SOUND_MIXER_LINE + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECMIC (SOUND_MIXER_MIC + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECCD (SOUND_MIXER_CD + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES18XX_MIXER_RECDIFF)
-#define ES18XX_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES18XX_MIXER_RECDIFF)
+#define ES188X_MIXER_RECBASE (SOUND_MIXER_LINE3 + 1)
+#define ES188X_MIXER_RECDIFF (ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH)
+
+#define ES188X_MIXER_RECSYNTH (SOUND_MIXER_SYNTH + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECPCM (SOUND_MIXER_PCM + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECSPEAKER (SOUND_MIXER_SPEAKER + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE (SOUND_MIXER_LINE + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECMIC (SOUND_MIXER_MIC + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECCD (SOUND_MIXER_CD + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECIMIX (SOUND_MIXER_IMIX + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECRECLEV (SOUND_MIXER_RECLEV + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECIGAIN (SOUND_MIXER_IGAIN + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECOGAIN (SOUND_MIXER_OGAIN + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE1 (SOUND_MIXER_LINE1 + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE2 (SOUND_MIXER_LINE2 + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE3 (SOUND_MIXER_LINE3 + ES188X_MIXER_RECDIFF)
/*
* Mixer registers of ALS007
};
/*
- * The ES18XX specifics.
- * Note that de master volume unlike ES688 is now controlled by two
- * 6 bit registers.
- * Also Note that the recording levels (ES18XX_MIXER_REC...) have own
- * entries as if they were playback devices. They are used internally only!
+ * The ES188x specifics.
+ * Note that de master volume unlike ES688 is now controlled by two 6 bit
+ * registers. These seem to work OK on 1868 too, but I have no idea if it's
+ * compatible to 688 or 1688....
+ * 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_BASS, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 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_LINE3, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),
-MIX_ENT(ES18XX_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4),
-MIX_ENT(ES18XX_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4),
-MIX_ENT(ES18XX_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4),
-
-MIX_ENT(ES18XX_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES18XX_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),
-MIX_ENT(ES18XX_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
+MIX_ENT(ES188X_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),
+MIX_ENT(ES188X_MIXER_RECPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE, 0x6e, 7, 4, 0x6e, 3, 4),
+MIX_ENT(ES188X_MIXER_RECMIC, 0x68, 7, 4, 0x68, 3, 4),
+MIX_ENT(ES188X_MIXER_RECCD, 0x6a, 7, 4, 0x6a, 3, 4),
+
+MIX_ENT(ES188X_MIXER_RECIMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECRECLEV, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),
+MIX_ENT(ES188X_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
};
#ifdef __SGNXPRO__
struct autofs_wait_queue *wq;
int status;
+ /* In catatonic mode, we don't wait for nobody */
+ if ( sbi->catatonic )
+ return -ENOENT;
+
for ( wq = sbi->queues ; wq ; wq = wq->next ) {
if ( wq->hash == name->hash &&
wq->len == name->len &&
/* 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 ) {
/* Block all but "shutdown" signals while waiting */
sigset_t oldset;
struct list_head *head = d_hash(parent,hash);
struct list_head *tmp = head->next;
- while (tmp != head) {
+ for (;;) {
struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
-
+ if (tmp == head)
+ break;
tmp = tmp->next;
if (dentry->d_name.hash != hash)
continue;
MSDOS_SB(sb)->fat_bits,opts.name_check,
opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
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",
b->media,MSDOS_SB(sb)->cluster_size,
MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,
/* Ok, remeber that we successfully checked it.. */
nfs_renew_times(dentry);
+ nfs_refresh_inode(inode, &fattr);
out_valid:
return 1;
#endif
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",
dentry->d_parent->d_name.name, dentry->d_name.name);
out:
if (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:
return error;
* to devices.
*
* 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
* 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
* and add some real memory barriers if so.
*/
/*
* Standard way to access the cycle counter on i586+ CPUs.
* 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;
static inline cycles_t get_cycles (void)
{
- cycles_t value;
+#if CPU < 586
+ return 0;
+#else
+ unsigned long eax, edx;
- __asm__("rdtsc"
- :"=a" (*(((int *)&value)+0)),
- "=d" (*(((int *)&value)+1)));
- return value;
+ __asm__("rdtsc":"=a" (eax), "=d" (edx));
+ return eax;
+#endif
}
#endif
* BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
* updated by Marc Espie <Marc.Espie@openbsd.org>
*/
-
#define FREEBSD_PARTITION 0xa5 /* FreeBSD Partition ID */
#define OPENBSD_PARTITION 0xa6 /* OpenBSD Partition ID */
#define NETBSD_PARTITION 0xa9 /* NetBSD 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 */
#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
#ifdef __SMP__
/*
* ("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
* 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:
* - pass #1: faster: 'quick decisions'
*
* There are two metrics here:
*
- * first, a 'cutoff' interval, currently ~250 usecs on
- * x86 CPUs. If the current process has longer average
- * timeslices than this, then we utilize the idle CPU.
+ * first, a 'cutoff' interval, currently 0-200 usecs on
+ * x86 CPUs, depending on the size of the 'SMP-local cache'.
+ * 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,
* then the two processes are 'related'. (they form a
wake_up_process(p);
}
-int _PROC_CHANGE_PENALTY = 13;
-
/*
* This is the function that decides how desirable a process is..
* You can weigh different processes against each other depending
struct swap_info_struct * p;
int zones[PAGE_SIZE/512];
int zones_used;
- kdev_t dev;
+ kdev_t dev = 0;
int block_size;
#ifdef DEBUG_SWAP
case SIOCIPXNCPCONN:
{
- int err;
/*
* This socket wants to take care of the NCP connection
* handed to us in arg.
#include <net/ax25.h>
#include <net/netrom.h>
+#ifdef CONFIG_INET
+
/*
* Only allow IP over NET/ROM frames through if the netrom device is up.
*/
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)
{
unsigned char *bp = skb->data;
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;
}
+#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)
{
struct sockaddr *sa = addr;
#include <linux/kernel.h>
#include <linux/module.h> /* support for loadable modules */
#include <linux/malloc.h> /* kmalloc(), kfree() */
-#include <linux/vmalloc.h> /* vmalloc(), vfree() */
#include <linux/mm.h> /* verify_area(), etc. */
#include <linux/string.h> /* inline mem*, str* functions */
+#include <linux/vmalloc.h> /* vmalloc, vfree */
#include <asm/segment.h> /* kernel <-> user copy */
#include <asm/byteorder.h> /* htons(), etc. */
#include <asm/uaccess.h> /* copy_to/from_user */
static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };
#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
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
/*
static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
{
void* data;
- wandev_conf_t* conf;
+ wandev_conf_t *conf;
int err= -EINVAL;
if (wandev->setup == NULL) /* Nothing to do ? */
err = wandev->setup(wandev,conf);
}
else
- err = -ENOBUFS;
- vfree(data);
+ err = -EFAULT;
}
+ else
+ err = -ENOBUFS;
+
+ if (data)
+ vfree(data);
}
bail:
kfree(conf);