E: philipg@onsett.com
D: Kernel / timekeeping stuff
+N: Grant Guenther
+E: grant@torque.net
+D: Iomega PPA / ZIP driver
+S: 906-1001 Bay St.
+S: Toronto, Ontario, M5S 3A6
+S: Canada
+
N: Miquel van Smoorenburg
E: miquels@cistron.nl
D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
PC/TCP compatibility mode
CONFIG_INET_PCTCP
If you have been having difficulties telneting to your Linux machine
- from a DOS system that uses (broken) PC/TCP networking software, try
- enabling this option. Everyone else says N. As of later 1.3.x kernels
- nobody should need this option. Please report if it solves problems.
+ from a DOS system that uses (broken) PC/TCP networking software (all
+ versions up to OnNet 2.0), try enabling this option. Everyone else
+ says N.
Reverse ARP
CONFIG_INET_RARP
SCSI generic support
CONFIG_CHR_DEV_SG
If you want to use SCSI scanners, synthesizers or CD-writers or just
- about anything having "SCSI" in its name, say Y here. Those won't be
- supported by the kernel directly, so you need some additional
- software which knows how to talk to these things using the SCSI
- protocol. Chances are that you'll have to write that software
- yourself, so have a look at the SCSI-HOWTO and at the
- SCSI-Programming-HOWTO, both available via ftp (user: anonymous) in
- sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this
- as a module ( = code which can be inserted in and removed from the
- running kernel whenever you want), say M here and read
- Documentation/modules.txt and Documentation/scsi.txt.
+ about anything having "SCSI" in its name other than disks, CDROMs or
+ tapes, say Y here. Those won't be supported by the kernel directly,
+ so you need some additional software which knows how to talk to
+ these things using the SCSI protocol. Chances are that you'll have
+ to write that software yourself, so have a look at the SCSI-HOWTO
+ and at the SCSI-Programming-HOWTO, both available via ftp (user:
+ anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to
+ compile this as a module ( = code which can be inserted in and
+ removed from the running kernel whenever you want), say M here and
+ read Documentation/modules.txt and Documentation/scsi.txt.
Probe all LUNs on each SCSI device
CONFIG_SCSI_MULTI_LUN
available via ftp (user: anonymous) at
sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
+IOMEGA Parallel Port ZIP drive SCSI support
+CONFIG_SCSI_PPA
+ This driver supports the parallel port version of IOMEGA's ZIP
+ drive (a 100Mb removable media device). For more infomation
+ about this driver and how to use it you should read the file
+ drivers/scsi/README.ppa. You should also read the SCSI-HOWTO,
+ which is available via anonymous ftp from sunsite.unc.edu in
+ the directory /pub/Linux/docs/HOWTO. This driver is also available
+ as a module which can be inserted in and removed from the
+ running kernel whenever you want. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
Network device support?
CONFIG_NETDEVICES
You can say N here in case you don't intend to connect to any other
SMC 9194 Support
CONFIG_SMC9194
- This has support for the SMC9xxx based Ethernet cards. Choose this option
- if you have a DELL laptop with the docking station, or another SMC9192/9194
- based chipset. Say Y if you want it compiled into the kernel, and read
+ This is support for the SMC9xxx based Ethernet cards. Choose this
+ option if you have a DELL laptop with the docking station, or
+ another SMC9192/9194 based chipset. Say Y if you want it compiled
+ into the kernel, and read the the file drivers/net/README.smc9 and
the Ethernet-HOWTO, available via ftp (user: anonymous) in
sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also
available as a module ( = code which can be inserted in and removed
Documentation/networking/net-modules.txt. If you plan to use more
than one network card under linux, read the
Multiple-Ethernet-mini-HOWTO, available from
- sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your card is not working
- you may need to use the DOS setup disk to disable Plug & Play mode, and
- to select the default media type.
+ sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your card is not
+ working you may need to use the DOS setup disk to disable Plug &
+ Play mode, and to select the default media type.
3c590 series (592/595/597) "Vortex" support
CONFIG_VORTEX
DE425, DE434, DE435 support
CONFIG_DE4X5
- If you have a network (ethernet) card of this type, say Y and read
+ This is support for the DIGITAL series of PCI/EISA ethernet
+ cards. These include the DE425, DE434, DE435, DE450 and DE500
+ models. If you have a network card of this type, say Y and read
the Ethernet-HOWTO, available via ftp (user: anonymous) in
sunsite.unc.edu:/pub/Linux/docs/HOWTO. More specific information is
contained in drivers/net/README.de4x5. This driver is also available
partitions. It does not support Windows'95 compressed filesystems.
You cannot use the VFAT filesystem for your root partition; use
UMSDOS instead. This option enlarges your kernel by about 10 kB and
- it only works if you enabled the "fat fs support" above.
+ it only works if you enabled the "fat fs support" above. Please read
+ the file Documentation/filesystems/vfat.txt for details.
If unsure, say N. If you want to compile this as a module ( = code
which can be inserted in and removed from the running kernel whenever
you want), say M here and read Documentation/modules.txt.
(and their companion controller) is also supported. If you have a
special controller (such as the CMS FC-10, FC-20, Iomega Mach-II, or
Ditto Dash), you must configure it by editing the file
- drivers/char/ftape/Makefile. This driver is also available as a
+ drivers/char/ftape/Makefile. If you want to use such a tape drive on
+ a PCI-bus based system, please read the file
+ drivers/char/ftape/README.PCI. This driver is also available as a
runtime loadable module ( = code which can be inserted in and
removed from the running kernel whenever you want). If you want to
compile it as a module, say M here and read
# LocalWords: NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco
# LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
# LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
+# LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
+# LocalWords: FC
VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 73
+SUBLEVEL = 74
ARCH = i386
start_mem += PAGE_SIZE;
}
for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
+ if (tmp >= 16*1024*1024)
+ mem_map[MAP_NR(tmp)].dma = 0;
if (mem_map[MAP_NR(tmp)].reserved) {
if (tmp >= 0xA0000 && tmp < 0x100000)
reservedpages++;
{
unsigned long pages;
- pages = __get_free_pages(GFP_KERNEL, 1, ~0UL);
+ pages = __get_free_pages(GFP_KERNEL, 1, 0);
if(!pages)
return 0;
memset((void *) pages, 0, (PAGE_SIZE << 1));
/* Dma Memory related stuff */
/* Pure 2^n version of get_order */
-static inline int __get_order (int size)
+static inline int __get_order(unsigned long size)
{
int order;
-#ifdef _ASM_IO_H2
- __asm__ __volatile__("bsr %1,%0"
- : "=r" (order)
- : "r" (size / PAGE_SIZE));
-#else
- for (order = 0; order < NR_MEM_LISTS; ++order)
- if (size <= (PAGE_SIZE << order))
- return order;
-#endif
- return NR_MEM_LISTS;
+ size >>= (PAGE_SHIFT-1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
}
static unsigned long dma_mem_alloc(int size)
{
int order = __get_order(size);
- if (order >= NR_MEM_LISTS)
- return(0);
return __get_dma_pages(GFP_KERNEL,order);
}
*/
static void init_gendisk (ide_hwif_t *hwif)
{
- struct gendisk *gd, **gdp;
+ struct gendisk *gd;
unsigned int unit, units, minors;
int *bs;
gd->init = ide_geninit; /* initialization function */
gd->real_devices= hwif; /* ptr to internal data */
- for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ;
- gd->next = NULL; /* link to tail of list */
- hwif->gd = *gdp = gd;
+ gd->next = gendisk_head; /* link new major into list */
+ hwif->gd = gendisk_head = gd;
}
static void do_reset1 (ide_drive_t *, int); /* needed below */
}
}
/*
- * Check for serialization with ide1.
- * This code depends on us having already taken care of ide1.
+ * Check for serialization with ide0.
+ * This code depends on us having already taken care of ide0.
*/
- if (hwif->serialized && hwif->index == 0 && ide_hwifs[1].present)
- hwgroup = ide_hwifs[1].hwgroup;
+ if (hwif->index == 1 && ide_hwifs[0].serialized && ide_hwifs[0].present)
+ hwgroup = ide_hwifs[0].hwgroup;
/*
* If this is the first interface in a group,
* then we need to create the hwgroup structure
# This enables some (most?) 2Mbps controllers:
#FDC_OPT = -DFDC_BASE=0x3E0 -DFDC_IRQ=6 -DFDC_DMA=2
-EXTRA_CFLAGS := $(FTAPE_OPT) $(FDC_OPT) -D__NO_VERSION__
+EXTRA_CFLAGS := $(FTAPE_OPT) $(FDC_OPT)
O_TARGET := ftape.o
O_OBJS = kernel-interface.o tracing.o fdc-io.o fdc-isr.o \
+===== Release notes for ftape-2.07a, 14/03/96 =====
+
+Bugfixes by Marcin Dalecki <dalecki@namu03.gwdg.de>:
+- In the last release it just compiled against 1.3.70;
+ now the params to request_irq() and free_irq are() are fixed, so it also
+ works in 1.3.73 :-)
+- Support for modules is now correct for newer kernels.
+
===== Release notes for ftape-2.07, 04/03/96 =====
* functions.
*/
-#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/ftape.h>
* for the QIC-40/80 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/ftape.h>
#include <stdio.h>
#include <sys/errno.h>
* This file contains code for the CMS FC-10/FC-20 card.
*/
-#include <linux/module.h>
#include <linux/ftape.h>
#include <asm/io.h>
* for the QIC-40/80 tape streamer device driver.
*/
-#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/ioport.h>
static byte fdc_drv_spec[4]; /* drive specification bytes for i82078 */
static int perpend_mode; /* true if fdc is in perpendicular mode */
+static char ftape_id[] = "ftape"; /* used by request irq and free irq */
+
void fdc_catch_stray_interrupts(unsigned count)
{
unsigned long flags;
{
TRACE_FUN(8, "fdc_grab_irq_and_dma");
int result = 0;
- static char ftape_id[] = "ftape";
if (fdc.hook == &do_ftape) {
/* Get fast interrupt handler.
result = request_dma(fdc.dma, ftape_id);
if (result) {
TRACEx1(-1, "Unable to grab DMA%d for ftape driver", fdc.dma);
- free_irq(fdc.irq, NULL);
+ free_irq(fdc.irq, ftape_id);
result = -EIO;
} else {
enable_irq(fdc.irq);
disable_dma(fdc.dma); /* just in case... */
free_dma(fdc.dma);
disable_irq(fdc.irq);
- free_irq(fdc.irq, NULL);
+ free_irq(fdc.irq, ftape_id);
}
#ifdef FDC_DMA
if (result == 0 && FDC_DMA == 2) {
* code for the QIC-40/80 tape streamer device driver.
*/
-#include <linux/module.h>
#include <linux/ftape.h>
#include <asm/io.h>
#include <asm/dma.h>
* QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
*/
-#include <linux/module.h>
#include <linux/ftape.h>
#include <linux/string.h>
* for the QIC-40/80 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/ftape.h>
* for the QIC-40/80 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/ftape.h>
#include <linux/string.h>
#include <linux/errno.h>
* for the QIC-40/80 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/mm.h>
* write routines for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ftape.h>
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/mm.h>
byte *tape_buffer[NR_BUFFERS] =
{NULL};
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-#endif
-
/* Local vars.
*/
static int busy_flag = 0;
* for the QIC-117 floppy-tape driver for Linux.
*/
-#include <linux/module.h>
#include <linux/ftape.h>
#include "tracing.h"
* Copyright (C) 1994 by Alan Cox (Modularised it)
* LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu
* Statistics and support for slow printers by Rob Janssen, rob@knoware.nl
+ * "lp=" command line parameters added by Grant Guenther, grant@torque.net
*/
#include <linux/module.h>
unsigned int testvalue;
base = LP_B(offset);
+ if (base == 0)
+ return -1; /* de-configured by command line */
+ if (LP_IRQ(offset) > 15)
+ return -1; /* bogus interrupt value */
size = (base == 0x3bc)? 3 : 8;
if (check_region(base, size) < 0)
return -1;
return 0;
}
+/* Command line parameters:
+
+ When the lp driver is built in to the kernel, you may use the
+ LILO/LOADLIN command line to set the port addresses and interrupts
+ that the driver will use.
+
+ Syntax: lp=port0[,irq0[,port1[,irq1[,port2[,irq2]]]]]
+
+ For example: lp=0x378,0 or lp=0x278,5,0x378,7
+
+ Note that if this feature is used, you must specify *all* the ports
+ you want considered, there are no defaults. You can disable a
+ built-in driver with lp=0 .
+
+*/
+
+void lp_setup(char *str, int *ints)
+
+{
+ LP_B(0) = ((ints[0] > 0) ? ints[1] : 0 );
+ LP_IRQ(0) = ((ints[0] > 1) ? ints[2] : 0 );
+ LP_B(1) = ((ints[0] > 2) ? ints[3] : 0 );
+ LP_IRQ(1) = ((ints[0] > 3) ? ints[4] : 0 );
+ LP_B(2) = ((ints[0] > 4) ? ints[5] : 0 );
+ LP_IRQ(2) = ((ints[0] > 5) ? ints[6] : 0 );
+}
+
#ifdef MODULE
static int io[] = {0, 0, 0};
static int irq[] = {0, 0, 0};
printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
#endif
- ptr = (struct Pages *) __get_free_pages(priority,bp->pageorder,~0);
+ ptr = (struct Pages *) __get_free_pages(priority,bp->pageorder,0);
if (!ptr) {
printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
return (-1);
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool 'SEEQ8005 support' CONFIG_SEEQ8005
tristate 'AT1700 support' CONFIG_AT1700
+ tristate 'FMV-181/182 support' CONFIG_FMV18X
tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
tristate 'EtherExpress support' CONFIG_EEXPRESS
tristate 'NI5210 support' CONFIG_NI52
endif
endif
+ifeq ($(CONFIG_FMV18X),y)
+L_OBJS += fmv18x.o
+else
+ ifeq ($(CONFIG_FMV18X),m)
+ M_OBJS += fmv18x.o
+ endif
+endif
+
ifeq ($(CONFIG_EL1),y)
L_OBJS += 3c501.o
else
extern int el3_probe(struct device *);
extern int at1500_probe(struct device *);
extern int at1700_probe(struct device *);
+extern int fmv18x_probe(struct device *);
extern int eth16i_probe(struct device *);
extern int depca_probe(struct device *);
extern int apricot_probe(struct device *);
#ifdef CONFIG_AT1700
&& at1700_probe(dev)
#endif
+#ifdef CONFIG_FMV18X /* Fujitsu FMV-181/182 */
+ && fmv18x_probe(dev)
+#endif
#ifdef CONFIG_ETH16I
&& eth16i_probe(dev) /* ICL EtherTeam 16i/32 */
#endif
0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe
};
-int irq[MAX_EEXP_CARDS] = {0, };
-int io[MAX_EEXP_CARDS] = {0, };
+int irq[EEXP_MAX_CARDS] = {0, };
+int io[EEXP_MAX_CARDS] = {0, };
/* Ideally the user would give us io=, irq= for every card. If any parameters
* are specified, we verify and then use them. If no parameters are given, we
for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
struct device *dev = &dev_eexp[this_dev];
if (dev->priv != NULL) {
- kfree_s(dev->priv. sizeof(struct net_local));
+ kfree(dev->priv);
dev->priv = NULL;
release_region(dev->base_addr, EEXP_IO_EXTENT);
unregister_netdev(dev);
--- /dev/null
+/* fmv18x.c: A network device driver for the Fujitsu FMV-181/182.
+
+ Original: at1700.c (1993-94 by Donald Becker).
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Modified by Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)
+ Copyright 1994 Fujitsu Laboratories Ltd.
+ Special thanks to:
+ Masayoshi UTAKA (utaka@ace.yk.fujitsu.co.jp)
+ for testing this driver.
+ H. NEGISHI (agy, negishi@sun45.psd.cs.fujitsu.co.jp)
+ for sugestion of some program modification.
+ Masahiro SEKIGUCHI <seki@sysrap.cs.fujitsu.co.jp>
+ for sugestion of some program modification.
+ Kazutoshi MORIOKA (morioka@aurora.oaks.cs.fujitsu.co.jp)
+ for testing this driver.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ This is a device driver for the Fujitsu FMV-181/182, which is a
+ straight-forward Fujitsu MB86965 implementation.
+
+ Sources:
+ at1700.c
+ The Fujitsu MB86965 datasheet.
+ The Fujitsu FMV-181/182 user's guide
+*/
+
+static const char *version =
+ "fmv18x.c:v1.3.71e 03/04/96 Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+static int fmv18x_probe_list[] =
+{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 1
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+typedef unsigned char uchar;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+ struct enet_statistics stats;
+ long open_time; /* Useless example local info. */
+ uint tx_started:1; /* Number of packet on the Tx queue. */
+ uchar tx_queue; /* Number of packet on the Tx queue. */
+ ushort tx_queue_len; /* Current length of the Tx queue. */
+};
+
+
+/* Offsets from the base address. */
+#define STATUS 0
+#define TX_STATUS 0
+#define RX_STATUS 1
+#define TX_INTR 2 /* Bit-mapped interrupt enable registers. */
+#define RX_INTR 3
+#define TX_MODE 4
+#define RX_MODE 5
+#define CONFIG_0 6 /* Misc. configuration settings. */
+#define CONFIG_1 7
+/* Run-time register bank 2 definitions. */
+#define DATAPORT 8 /* Word-wide DMA or programmed-I/O dataport. */
+#define TX_START 10
+#define COL16CNTL 11
+#define MODE13 13
+/* Fujitsu FMV-18x Card Configuration */
+#define FJ_STATUS0 0x10
+#define FJ_STATUS1 0x11
+#define FJ_CONFIG0 0x12
+#define FJ_CONFIG1 0x13
+#define FJ_MACADDR 0x14 /* 0x14 - 0x19 */
+#define FJ_BUFCNTL 0x1A
+#define FJ_BUFDATA 0x1C
+#define FMV18X_IO_EXTENT 32
+
+/* Index to functions, as function prototypes. */
+
+extern int fmv18x_probe(struct device *dev);
+
+static int fmv18x_probe1(struct device *dev, short ioaddr);
+static int net_open(struct device *dev);
+static int net_send_packet(struct sk_buff *skb, struct device *dev);
+static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void net_rx(struct device *dev);
+static int net_close(struct device *dev);
+static struct enet_statistics *net_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev);
+
+\f
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+ If dev->base_addr == 2, allocate space for the device and return success
+ (detachable devices only).
+ */
+#ifdef HAVE_DEVLIST
+/* Support for a alternate probe manager, which will eliminate the
+ boilerplate below. */
+struct netdev_entry fmv18x_drv =
+{"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};
+#else
+int
+fmv18x_probe(struct device *dev)
+{
+ int i;
+ int base_addr = dev ? dev->base_addr : 0;
+
+ if (base_addr > 0x1ff) /* Check a single specified location. */
+ return fmv18x_probe1(dev, base_addr);
+ else if (base_addr != 0) /* Don't probe at all. */
+ return ENXIO;
+
+ for (i = 0; fmv18x_probe_list[i]; i++) {
+ int ioaddr = fmv18x_probe_list[i];
+ if (check_region(ioaddr, FMV18X_IO_EXTENT))
+ continue;
+ if (fmv18x_probe1(dev, ioaddr) == 0)
+ return 0;
+ }
+
+ return ENODEV;
+}
+#endif
+
+/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
+ "signature", the default bit pattern after a reset. This *doesn't* work --
+ there is no way to reset the bus interface without a complete power-cycle!
+
+ It turns out that ATI came to the same conclusion I did: the only thing
+ that can be done is checking a few bits and then diving right into MAC
+ address check. */
+
+int fmv18x_probe1(struct device *dev, short ioaddr)
+{
+ char irqmap[4] = {3, 7, 10, 15};
+ unsigned int i, irq;
+
+ /* Resetting the chip doesn't reset the ISA interface, so don't bother.
+ That means we have to be careful with the register values we probe for.
+ */
+
+ /* Check I/O address configuration and Fujitsu vendor code */
+ if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr
+ || inb(ioaddr+FJ_MACADDR ) != 0x00
+ || inb(ioaddr+FJ_MACADDR+1) != 0x00
+ || inb(ioaddr+FJ_MACADDR+2) != 0x0e)
+ return -ENODEV;
+
+ irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03];
+
+ /* Snarf the interrupt vector now. */
+ if (request_irq(irq, &net_interrupt, 0, "fmv18x", NULL)) {
+ printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on"
+ "IRQ %d.\n", ioaddr, irq);
+ return EAGAIN;
+ }
+
+ /* Allocate a new 'dev' if needed. */
+ if (dev == NULL)
+ dev = init_etherdev(0, sizeof(struct net_local));
+
+ /* Grab the region so that we can find another board if the IRQ request
+ fails. */
+ request_region(ioaddr, FMV18X_IO_EXTENT, "fmv18x");
+
+ printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name,
+ ioaddr, irq);
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ irq2dev_map[irq] = dev;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char val = inb(ioaddr + FJ_MACADDR + i);
+ printk("%02x", val);
+ dev->dev_addr[i] = val;
+ }
+
+ /* "FJ_STATUS0" 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
+ rather than 150 ohm shielded twisted pair compensation.
+ 0x0000 == auto-sense the interface
+ 0x0800 == use TP interface
+ 0x1800 == use coax interface
+ */
+ {
+ const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2/5"};
+ ushort setup_value = inb(ioaddr + FJ_STATUS0);
+
+ switch( setup_value & 0x07 ){
+ case 0x01 /* 10base5 */:
+ case 0x02 /* 10base2 */: dev->if_port = 0x18; break;
+ case 0x04 /* 10baseT */: dev->if_port = 0x08; break;
+ default /* auto-sense*/: dev->if_port = 0x00; break;
+ }
+ printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]);
+ }
+
+ /* Initialize LAN Controller and LAN Card */
+ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */
+ outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */
+ outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
+ outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure (TAMIYA) */
+
+ /* wait for a while */
+ udelay(200);
+
+ /* Set the station address in bank zero. */
+ outb(0x00, ioaddr + CONFIG_1);
+ for (i = 0; i < 6; i++)
+ outb(dev->dev_addr[i], ioaddr + 8 + i);
+
+ /* Switch to bank 1 and set the multicast table to accept none. */
+ outb(0x04, ioaddr + CONFIG_1);
+ for (i = 0; i < 8; i++)
+ outb(0x00, ioaddr + 8 + i);
+
+ /* Switch to bank 2 and lock our I/O address. */
+ outb(0x08, ioaddr + CONFIG_1);
+ outb(dev->if_port, ioaddr + MODE13);
+
+ if (net_debug)
+ printk(version);
+
+ /* Initialize the device structure. */
+ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct net_local));
+
+ dev->open = net_open;
+ dev->stop = net_close;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+
+ /* Fill in the fields of 'dev' with ethernet-generic values. */
+
+ ether_setup(dev);
+ return 0;
+}
+\f
+
+static int net_open(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ /* Set the configuration register 0 to 32K 100ns. byte-wide memory,
+ 16 bit bus access, and two 4K Tx, enable the Rx and Tx. */
+ outb(0x5a, ioaddr + CONFIG_0);
+
+ /* Powerup and switch to register bank 2 for the run-time registers. */
+ outb(0xe8, ioaddr + CONFIG_1);
+
+ lp->tx_started = 0;
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+
+ /* Clear Tx and Rx Status */
+ outb(0xff, ioaddr + TX_STATUS);
+ outb(0xff, ioaddr + RX_STATUS);
+ lp->open_time = jiffies;
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ /* Enable the IRQ of the LAN Card */
+ outb(0x80, ioaddr + FJ_CONFIG1);
+
+ /* Enable both Tx and Rx interrupts */
+ outw(0x8182, ioaddr+TX_INTR);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if (dev->tbusy) {
+ /* If we get here, some higher level has decided we are broken.
+ There should really be a "kick me" function call instead. */
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 10)
+ return 1;
+ printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
+ htons(inw(ioaddr + TX_STATUS)),
+ inb(ioaddr + TX_STATUS) & 0x80
+ ? "IRQ conflict" : "network cable problem");
+ printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
+ dev->name, htons(inw(ioaddr + 0)),
+ htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
+ htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
+ htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
+ htons(inw(ioaddr +14)));
+ printk("eth card: %04x %04x\n",
+ htons(inw(ioaddr+FJ_STATUS0)),
+ htons(inw(ioaddr+FJ_CONFIG0)));
+ lp->stats.tx_errors++;
+ /* ToDo: We should try to restart the adaptor... */
+ cli();
+
+ /* Initialize LAN Controller and LAN Card */
+ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */
+ outb(0x00, ioaddr + CONFIG_1); /* Stand by mode */
+ outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
+ outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */
+ net_open(dev);
+
+ sti();
+ }
+
+ /* If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself. */
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
+ }
+
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ if (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else {
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+
+ if (length > ETH_FRAME_LEN) {
+ if (net_debug)
+ printk("%s: Attempting to send a large packet (%d bytes).\n",
+ dev->name, length);
+ return 1;
+ }
+
+ if (net_debug > 4)
+ printk("%s: Transmitting a packet of length %lu.\n", dev->name,
+ (unsigned long)skb->len);
+
+ /* Disable both interrupts. */
+ outw(0x0000, ioaddr + TX_INTR);
+
+ outw(length, ioaddr + DATAPORT);
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+
+ if (lp->tx_started == 0) {
+ /* If the Tx is idle, always trigger a transmit. */
+ outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ lp->tx_started = 1;
+ dev->tbusy = 0;
+ } else if (lp->tx_queue_len < 4096 - 1502)
+ /* Yes, there is room for one more packet. */
+ dev->tbusy = 0;
+
+ /* Re-enable interrupts */
+ outw(0x8182, ioaddr + TX_INTR);
+ }
+ dev_kfree_skb (skb, FREE_WRITE);
+
+ return 0;
+}
+\f
+/* The typical workload of the driver:
+ Handle the network interface interrupts. */
+static void
+net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ struct net_local *lp;
+ int ioaddr, status;
+
+ if (dev == NULL) {
+ printk ("fmv18x_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ lp = (struct net_local *)dev->priv;
+
+ /* Avoid multiple interrupts. */
+ outw(0x0000, ioaddr + TX_INTR);
+
+ status = inw(ioaddr + TX_STATUS);
+ outw(status, ioaddr + TX_STATUS);
+
+ if (net_debug > 4)
+ printk("%s: Interrupt with status %04x.\n", dev->name, status);
+ if (status & 0xff00
+ || (inb(ioaddr + RX_MODE) & 0x40) == 0) { /* Got a packet(s). */
+ net_rx(dev);
+ }
+ if (status & 0x00ff) {
+ if (status & 0x80) {
+ lp->stats.tx_packets++;
+ if (lp->tx_queue) {
+ outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ dev->tbusy = 0;
+ mark_bh(NET_BH); /* Inform upper layers. */
+ } else {
+ lp->tx_started = 0;
+ dev->tbusy = 0;
+ mark_bh(NET_BH); /* Inform upper layers. */
+ }
+ }
+ if (status & 0x02 ) {
+ if (net_debug > 4)
+ printk("%s: 16 Collision occur during Txing.\n", dev->name);
+ /* Retry to send the packet */
+ outb(0x02, ioaddr + COL16CNTL);
+ }
+ }
+
+ dev->interrupt = 0;
+ outw(0x8182, ioaddr + TX_INTR);
+ return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int boguscount = 10; /* 5 -> 10: by agy 19940922 */
+
+ while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
+ /* Clear PKT_RDY bit: by agy 19940922 */
+ /* outb(0x80, ioaddr + RX_STATUS); */
+ ushort status = inw(ioaddr + DATAPORT);
+
+ if (net_debug > 4)
+ printk("%s: Rxing packet mode %02x status %04x.\n",
+ dev->name, inb(ioaddr + RX_MODE), status);
+#ifndef final_version
+ if (status == 0) {
+ outb(0x05, ioaddr + 14);
+ break;
+ }
+#endif
+
+ if ((status & 0xF0) != 0x20) { /* There was an error. */
+ lp->stats.rx_errors++;
+ if (status & 0x08) lp->stats.rx_length_errors++;
+ if (status & 0x04) lp->stats.rx_frame_errors++;
+ if (status & 0x02) lp->stats.rx_crc_errors++;
+ if (status & 0x01) lp->stats.rx_over_errors++;
+ } else {
+ ushort pkt_len = inw(ioaddr + DATAPORT);
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
+
+ if (pkt_len > 1550) {
+ printk("%s: The FMV-18x claimed a very large packet, size %d.\n",
+ dev->name, pkt_len);
+ outb(0x05, ioaddr + 14);
+ lp->stats.rx_errors++;
+ break;
+ }
+ skb = dev_alloc_skb(pkt_len+3);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet (len %d).\n",
+ dev->name, pkt_len);
+ outb(0x05, ioaddr + 14);
+ lp->stats.rx_dropped++;
+ break;
+ }
+ skb->dev = dev;
+ skb_reserve(skb,2);
+
+ insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
+
+ if (net_debug > 5) {
+ int i;
+ printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);
+ for (i = 0; i < 14; i++)
+ printk(" %02x", skb->data[i]);
+ printk(".\n");
+ }
+
+ skb->protocol=eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ }
+ if (--boguscount <= 0)
+ break;
+ }
+
+ /* If any worth-while packets have been received, dev_rint()
+ has done a mark_bh(NET_BH) for us and will work on them
+ when we get to the bottom-half routine. */
+ {
+ int i;
+ for (i = 0; i < 20; i++) {
+ if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
+ break;
+ (void)inw(ioaddr + DATAPORT); /* dummy status read */
+ outb(0x05, ioaddr + 14);
+ }
+
+ if (net_debug > 5 && i > 0)
+ printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
+ dev->name, inb(ioaddr + RX_MODE), i);
+ }
+
+ return;
+}
+
+/* The inverse routine to net_open(). */
+static int net_close(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ ((struct net_local *)dev->priv)->open_time = 0;
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ /* Set configuration register 0 to disable Tx and Rx. */
+ outb(0xda, ioaddr + CONFIG_0);
+
+ /* Update the statistics -- ToDo. */
+
+ /* Power-down the chip. Green, green, green! */
+ outb(0x00, ioaddr + CONFIG_1);
+
+ MOD_DEC_USE_COUNT;
+
+ /* Set the ethernet adaptor disable IRQ */
+ outb(0x00, ioaddr + FJ_CONFIG1);
+
+ return 0;
+}
+
+/* Get the current statistics. This may be called with the card open or
+ closed. */
+static struct enet_statistics *
+net_get_stats(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+
+ cli();
+ /* ToDo: Update the statistics from the device registers. */
+ sti();
+
+ return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev)
+{
+ short ioaddr = dev->base_addr;
+ if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
+ {
+ /*
+ * We must make the kernel realise we had to move
+ * into promisc mode or we start all out war on
+ * the cable. - AC
+ */
+ dev->flags|=IFF_PROMISC;
+
+ outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
+ }
+ else
+ outb(2, ioaddr + RX_MODE); /* Disable promiscuous, use normal mode */
+}
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+static struct device dev_fmv18x = {
+ devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+ 0, 0, 0, 0,
+ 0, 0,
+ 0, 0, 0, NULL, fmv18x_probe };
+
+static int io = 0x220;
+static int irq = 0;
+
+int init_module(void)
+{
+ if (io == 0)
+ printk("fmv18x: You should not use auto-probing with insmod!\n");
+ dev_fmv18x.base_addr = io;
+ dev_fmv18x.irq = irq;
+ if (register_netdev(&dev_fmv18x) != 0) {
+ printk("fmv18x: register_netdev() returned non-zero.\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ unregister_netdev(&dev_fmv18x);
+ kfree(dev_fmv18x.priv);
+ dev_fmv18x.priv = NULL;
+
+ /* If we don't do this, we can't re-insmod it later. */
+ free_irq(dev_fmv18x.irq, NULL);
+ irq2dev_map[dev_fmv18x.irq] = NULL;
+ release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT);
+}
+#endif /* MODULE */
+\f
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c fmv18x.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * tab-width: 4
+ * c-indent-level: 4
+ * End:
+ */
dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
+dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI
bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
endmenu
endif
endif
+ifeq ($(CONFIG_SCSI_PPA),y)
+L_OBJS += ppa.o
+else
+ ifeq ($(CONFIG_SCSI_PPA),m)
+ M_OBJS += ppa.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_QLOGIC),y)
L_OBJS += qlogic.o
else
--- /dev/null
+README.ppa (c) 1996 Grant R. Guenther, grant@torque.net
+
+
+ The IOMEGA PPA3 parallel port SCSI Host Bus Adapter
+
+ as embedded in the ZIP drive
+
+
+This README documents the Linux support for the parallel port version of
+IOMEGA's ZIP100. The ZIP100 is an inexpensive and popular, but relatively
+low performance, removable medium disk device. The drive is also available
+as a regular SCSI device, but the driver documented here is for the
+parallel port version. IOMEGA implemented the parallel port version by
+integrating (or emulating ?) their PPA3 parallel to SCSI converter into
+the ZIP drive.
+
+I have implemented a low-level driver, ppa.c, for this parallel port
+host bus adapter, thereby supporting the parallel port ZIP drive as a
+regular SCSI device under Linux.
+
+It is possible that this driver will also work with the original PPA3
+device (to access a CDrom, for instance). But, the PPA3 is hard to find
+and costs as much as the ZIP drive itself, so no-one has actually tried
+this, to the best of my knowledge.
+
+The driver was developed without the benefit of any technical specifications
+for the interface. Instead, a modified version of DOSemu was used to
+monitor the protocol used by the DOS driver, 'guest.exe', for this adapter.
+I have no idea how my programming model relates to IOMEGA's design.
+(One technical consequence of this method: I have never observed a
+SCSI message byte in the protocol transactions between guest.exe and
+the ZIP drive, so I do not know how they are delivered. My working
+hypothesis is that we don't have to worry about them if we don't
+send linked commands to the drive.)
+
+I'd like to thank Byron Jeff (byron@cc.gatech.edu) for publishing his
+observation that the 'guest' driver loads under DOSemu. His remark was
+the stimulus that began this project.
+
+The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but
+there is currently no support for EPP or ECP ports, as I have been unable
+to make the DOS drivers work in these modes on my test rig.
+
+The driver may be built in to the kernel, or loaded as a module. It
+may be configured on the command line in both cases, although the syntax
+is different. It may also be configured by editing the source file.
+
+Built-in drivers accept parameters using this LILO/LOADLIN command line
+syntax (omitted parameters retain their default values):
+
+ ppa=base[,speed_high[,speed_low[,call_sched[,nybble]]]]
+
+For example: ppa=0x378,0,3
+
+If a driver is loaded as a module the parameters may be set on the
+insmod command line, but each one must be specified by name:
+
+For example: insmod ppa.o ppa_base=0x378 ppa_nybble=1
+
+(Notice the ppa_ prefix on each of the parameters in the insmod form.)
+
+Here are the parameters and their functions:
+
+Variable Default Description
+
+ppa_base 0x378 The base address of PPA's parallel port.
+ppa_speed_high 1 Microsecond i/o delay used in data transfers
+ppa_speed_low 6 Microsecond delay used in other operations
+ppa_call_sched 1 1 to give up CPU during busy waits
+ppa_nybble 0 1 to force the driver to use 4-bit mode.
+
+A word about the timing parameters: the ppa_speed_low parameter controls
+the widths of a large number of pulses that are sent over the parallel bus,
+the narrower the pulses, the faster things go, but the greater the risk of
+distortion by noise damping circuits in the parallel ports. The
+ppa_speed_high parameter controls the same delays, but during the data
+transfer phase only. In this phase, there is a lot of handshaking going
+on and the pulse shaping should not be so much of an issue, but if you
+see data corruption, you can increase this parameter as well.
+
+You might also want to reduce the timing values to attempt to increase
+the transfer rates on your system. Please be careful to watch for
+SCSI timeout errors in your log files. If you are getting timeouts, you
+have set these parameters too low. The default values appear to be
+safe on most machines.
+
+The ppa_call_sched parameter controls the 'friendliness' of this driver
+to the rest of your system. When it is set to zero, the driver waits for
+events on the drive by continuously reading a port until the 0x80 bit is
+asserted. Since it is in a tight loop inside the kernel, the rest of the
+system becomes very sluggish. If you set ppa_call_sched to one, then
+ppa will call the scheduler in such circumstances, voluntarily giving up the
+CPU to other processes. This appears to reduce the ZIP drive's
+responsiveness, however.
+
+If you have both the lp and ppa drivers in your kernel, you must ensure
+that they access different parallel ports. By default, the lp driver is
+initialised early in the booting process, and it claims all parallel
+ports that it can find. You may control this behaviour with a LILO or
+LOADLIN command line argument of the form:
+
+ lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]]
+
+For example: lp=0x278,7
+
+If you use this method, only the ports named will be adopted by the lp
+driver. You can disable them all with lp=0 .
+
+So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would
+give the following options on your boot command:
+
+ lp=0x3bc ppa=0x278
+
+In this case lp would use the polling driver, since an interrupt was not
+specified.
+
+For information about using the ZIP drive, please read the generic
+instructions in the SCSI-HOWTO and the man pages for the normal disk
+management tools, fdisk, mkfs, mount, umount, etc. There is a mini-HOWTO
+circulating concerning the use of the normal SCSI version of the ZIP
+drive, most of its comments will apply to disks connected through the
+ppa driver as well.
+
#include "AM53C974.h"
#endif
+#ifdef CONFIG_SCSI_PPA
+#include "ppa.h"
+#endif
+
#ifdef CONFIG_SCSI_DEBUG
#include "scsi_debug.h"
#endif
#ifdef CONFIG_SCSI_AM53C974
AM53C974,
#endif
+#ifdef CONFIG_SCSI_PPA
+ PPA,
+#endif
#ifdef CONFIG_SCSI_DEBUG
SCSI_DEBUG,
#endif
--- /dev/null
+/* ppa.c -- low level driver for the IOMEGA PPA3
+ parallel port SCSI host adapter.
+
+ (The PPA3 is the embedded controller in the ZIP drive.)
+
+ (c) 1995,1996 Grant R. Guenther, grant@torque.net,
+ under the terms of the GNU Public License.
+
+ THIS IS BETA SOFTWARE - PLEASE TAKE ALL NECESSARY PRECAUTIONS
+
+*/
+
+/* This driver was developed without the benefit of any technical
+ specifications for the interface. Instead, a modified version of
+ DOSemu was used to monitor the protocol used by the DOS driver
+ for this adapter. I have no idea how my programming model relates
+ to IOMEGA's design.
+
+ IOMEGA's driver does not generate linked commands. I've never
+ observed a SCSI message byte in the protocol transactions, so
+ I am assuming that as long as linked commands are not used
+ we won't see any.
+
+ So far, this driver has been tested with the embedded PPA3 in the
+ ZIP drive, only. It can detect and adapt to 4- and 8-bit parallel
+ ports, but there is currently no support for EPP or ECP ports, as
+ I have been unable to make the DOS drivers work in these modes on
+ my test rig.
+
+ For more information, see the file drivers/scsi/README.ppa.
+
+*/
+
+#define PPA_VERSION "0.20"
+
+/* Change these variables here or with insmod or with a LILO or LOADLIN
+ command line argument
+*/
+
+static int ppa_base = 0x378; /* parallel port address */
+static int ppa_speed_high = 1; /* port delay in data phase */
+static int ppa_speed_low = 6; /* port delay otherwise */
+static int ppa_call_sched = 1; /* give up the CPU ? */
+static int ppa_nybble = 0; /* don't force nybble mode */
+
+
+#define PPA_CAN_QUEUE 1 /* use "queueing" interface */
+#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */
+#define PPA_SPIN_TMO 5000000 /* ppa_wait loop limiter */
+#define PPA_SECTOR_SIZE 512 /* for a performance hack only */
+
+#include <unistd.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <asm/io.h>
+#include "sd.h"
+#include "hosts.h"
+#include "ppa.h"
+
+struct proc_dir_entry proc_scsi_ppa =
+ { PROC_SCSI_PPA, 3, "ppa", S_IFDIR|S_IRUGO|S_IXUGO, 2 };
+
+static int ppa_abort_flag = 0;
+static int ppa_error_code = DID_OK;
+static char ppa_info_string[132];
+static Scsi_Cmnd *ppa_current = 0;
+static void (*ppa_done) (Scsi_Cmnd *);
+static int ppa_busy = 0;
+static int ppa_port_delay;
+
+
+void out_p( short port, char byte)
+
+{ outb(byte,ppa_base+port);
+ udelay(ppa_port_delay);
+}
+
+char in_p( short port)
+
+{ return inb(ppa_base+port);
+ udelay(ppa_port_delay);
+}
+
+void ppa_d_pulse( char b )
+
+{ out_p(0,b);
+ out_p(2,0xc); out_p(2,0xe); out_p(2,0xc); out_p(2,0x4); out_p(2,0xc);
+}
+
+void ppa_disconnect( void )
+
+{ ppa_d_pulse(0);
+ ppa_d_pulse(0x3c);
+ ppa_d_pulse(0x20);
+ ppa_d_pulse(0xf);
+}
+
+void ppa_c_pulse( char b )
+
+{ out_p(0,b);
+ out_p(2,0x4); out_p(2,0x6); out_p(2,0x4); out_p(2,0xc);
+}
+
+void ppa_connect( void )
+
+{ ppa_c_pulse(0);
+ ppa_c_pulse(0x3c);
+ ppa_c_pulse(0x20);
+ ppa_c_pulse(0x8f);
+}
+
+void ppa_do_reset( void )
+
+{ out_p(2,0); /* This is really just a guess */
+ udelay(100);
+}
+
+char ppa_select( int initiator, int target )
+
+{ char r;
+ int k;
+
+ r = in_p(1);
+ out_p(0,(1<<target)); out_p(2,0xe); out_p(2,0xc);
+ out_p(0,(1<<initiator)); out_p(2,0x8);
+
+ k = 0;
+ while ( !(r = (in_p(1) & 0xf0)) && (k++ < PPA_SELECT_TMO)) barrier();
+ return r;
+}
+
+char ppa_wait( void )
+
+/* Wait for the high bit to be set.
+
+ In principle, this could be tied to an interrupt, but the adapter
+ doesn't appear to be designed to support interrupts. We spin on
+ the 0x80 ready bit. If ppa_call_sched is 1, we call the scheduler
+ to allow other processes to run while we are waiting, just like
+ the lp driver does in polling mode. The performance hit is
+ significant, so this behaviour is configurable.
+
+*/
+
+{ int k;
+ char r;
+
+ ppa_error_code = DID_OK;
+ k = 0;
+ while (!((r = in_p(1)) & 0x80)
+ && (k++ < PPA_SPIN_TMO) && !ppa_abort_flag )
+ if (need_resched && ppa_call_sched) schedule();
+ if (ppa_abort_flag) {
+ if (ppa_abort_flag == 1) ppa_error_code = DID_ABORT;
+ else { ppa_do_reset();
+ ppa_error_code = DID_RESET;
+ }
+ ppa_disconnect();
+ return 0;
+ }
+ if (k >= PPA_SPIN_TMO) {
+ ppa_error_code = DID_TIME_OUT;
+ ppa_disconnect();
+ return 0; /* command timed out */
+ }
+ return (r & 0xf0);
+}
+
+int ppa_init( void )
+
+/* This is based on a trace of what the Iomega DOS 'guest' driver does.
+ I've tried several different kinds of parallel ports with guest and
+ coded this to react in the same ways that it does.
+
+ The return value from this function is just a hint about where the
+ handshaking failed.
+
+*/
+
+{ char r, s;
+
+ out_p(0,0xaa);
+ if (in_p(0) != (char) 0xaa) return 1;
+ ppa_disconnect();
+ ppa_connect();
+ out_p(2,0x6);
+ if ((in_p(1) & 0xf0) != 0xf0) return 2;
+ out_p(2,0x4);
+ if ((in_p(1) & 0xf0) != 0x80) return 3;
+ ppa_disconnect();
+ s = in_p(2);
+ out_p(2,0xec);
+ out_p(0,0x55);
+ r = in_p(0);
+ if (r != (char) 0xff) {
+ ppa_nybble = 1;
+ if (r != (char) 0x55) return 4;
+ out_p(0,0xaa); if (in_p(0) != (char) 0xaa) return 5;
+ }
+ out_p(2,s);
+ ppa_connect();
+ out_p(0,0x40); out_p(2,0x8); out_p(2,0xc);
+ ppa_disconnect();
+
+ return 0;
+}
+
+int ppa_start( Scsi_Cmnd * cmd )
+
+{ int k;
+
+ ppa_error_code = DID_OK;
+ ppa_abort_flag = 0;
+
+ if (cmd->target == PPA_INITIATOR) {
+ ppa_error_code = DID_BAD_TARGET;
+ return 0;
+ }
+ ppa_connect();
+ if (!ppa_select(PPA_INITIATOR,cmd->target)) {
+ ppa_disconnect();
+ ppa_error_code = DID_NO_CONNECT;
+ return 0;
+ }
+ out_p(2,0xc);
+
+ for (k=0; k < cmd->cmd_len; k++) { /* send the command */
+ if (!ppa_wait()) return 0;
+ out_p(0,cmd->cmnd[k]);
+ out_p(2,0xe);
+ out_p(2,0xc);
+ }
+
+#ifdef PPA_DEBUG
+ printk("PPA: command out: ");
+ for (k=0; k < cmd->cmd_len; k++)
+ printk("%3x",(cmd->cmnd[k]) & 0xff );
+ printk("\n");
+#endif
+
+ return 1;
+}
+
+int ppa_completion( Scsi_Cmnd * cmd )
+
+/* The bulk flag enables some optimisations in the data transfer loops,
+ it should be true for any command that transfers data in integral
+ numbers of sectors.
+
+ The driver appears to remain stable if we speed up the parallel port
+ i/o in this function, but not elsewhere.
+*/
+
+{ char r, l, h, v;
+ int dir, cnt, blen, fast, bulk;
+ char *buffer;
+
+#ifdef PPA_DEBUG
+ int k;
+#endif
+
+ if (!(r = ppa_wait())) return 0;
+ v = cmd->cmnd[0];
+ bulk = ((v==READ_6)||(v==READ_10)||(v==WRITE_6)||(v==WRITE_10));
+ buffer = cmd->request_buffer;
+ blen = cmd->request_bufflen;
+ cnt = 0; dir = 0;
+ if (r == (char) 0xc0) dir = 1; /* d0 = read c0 = write f0 = status */
+
+ ppa_port_delay = ppa_speed_high;
+
+ while (r != (char) 0xf0) {
+ if (((r & 0xc0) != 0xc0 ) || (cnt >= blen)) {
+ ppa_disconnect();
+ ppa_error_code = DID_ERROR;
+ return 0;
+ }
+ fast = bulk && ((blen - cnt) >= PPA_SECTOR_SIZE);
+ if (dir) do {
+ out_p(0,buffer[cnt++]);
+ out_p(2,0xe); out_p(2,0xc);
+ if (!fast) break;
+ } while (cnt % PPA_SECTOR_SIZE);
+ else {
+ if (ppa_nybble) do {
+ out_p(2,0x4); h = in_p(1);
+ out_p(2,0x6); l = in_p(1);
+ v = ((l >> 4) & 0x0f) + (h & 0xf0);
+ buffer[cnt++] = v;
+ if (!fast) break;
+ } while (cnt % PPA_SECTOR_SIZE);
+ else do {
+ out_p(2,0x25); v = in_p(0); out_p(2,0x27);
+ buffer[cnt++] = v;
+ if (!fast) break;
+ } while (cnt % PPA_SECTOR_SIZE);
+ if (!ppa_nybble) {
+ out_p(2,0x5); out_p(2,0x4);
+ }
+ out_p(2,0xc);
+ }
+ if (!(r = ppa_wait())) return 0;
+ }
+
+ ppa_port_delay = ppa_speed_low;
+
+ out_p(2,0x4); /* now read status byte */
+ h = in_p(1);
+ out_p(2,0x6);
+ l = in_p(1);
+ out_p(2,0xc);
+ r = ((l >> 4) & 0x0f) + (h & 0xf0);
+
+ out_p(2,0xe); out_p(2,0xc);
+ ppa_disconnect();
+
+#ifdef PPA_DEBUG
+ printk("PPA: status: %x, data[%d]: ",r & STATUS_MASK,cnt);
+ if (cnt > 12) cnt = 12;
+ for (k=0; k < cnt; k++)
+ printk("%3x",buffer[k] & 0xff );
+ printk("\n");
+#endif
+
+ return (r & STATUS_MASK);
+}
+
+int ppa_command( Scsi_Cmnd * cmd )
+
+{ int s;
+
+ s = 0;
+ if (ppa_start(cmd))
+ if (ppa_wait())
+ s = ppa_completion(cmd);
+ return s + (ppa_error_code << 16);
+}
+
+int ppa_queuecommand( Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+
+/* This is not really a queued interface at all, but apparently there may
+ be some bugs in the mid-level support for the non-queued interface.
+ This function is re-entrant, but only to one level.
+*/
+
+{ int s;
+
+ ppa_current = cmd; ppa_done = done;
+ if (ppa_busy) return 0;
+ ppa_busy = 1;
+ while (ppa_current) {
+ cmd = ppa_current; done = ppa_done;
+ s = 0;
+ if (ppa_start(cmd))
+ if (ppa_wait())
+ s = ppa_completion(cmd);
+ cmd->result = s + (ppa_error_code << 16);
+ ppa_current = 0;
+ done(cmd); /* can reenter this function */
+ }
+ ppa_busy = 0;
+ return 0;
+}
+
+int ppa_detect( Scsi_Host_Template * host )
+
+{ struct Scsi_Host *hreg;
+ int rs;
+
+ /* can we have the ports ? */
+
+ if (check_region(ppa_base,3)) {
+ printk("PPA: ports at 0x%3x are not available\n",ppa_base);
+ return 0;
+ }
+
+ /* attempt to initialise the controller */
+
+ ppa_port_delay = ppa_speed_low;
+
+ rs = ppa_init();
+ if (rs) {
+ printk("PPA: unable to initialise controller at 0x%x, error %d\n",
+ ppa_base,rs);
+ return 0;
+ }
+
+ /* now the glue ... */
+
+ host->proc_dir = &proc_scsi_ppa;
+
+ request_region(ppa_base,3,"ppa");
+
+ host->can_queue = PPA_CAN_QUEUE;
+
+ hreg = scsi_register(host,0);
+ hreg->io_port = ppa_base;
+ hreg->n_io_port = 3;
+ hreg->dma_channel = -1;
+
+ sprintf(ppa_info_string,
+ "PPA driver version %s using %d-bit mode on port 0x%x.",
+ PPA_VERSION,8-ppa_nybble*4,ppa_base);
+ host->name = ppa_info_string;
+
+ return 1; /* 1 host detected */
+}
+
+int ppa_biosparam( Disk * disk, kdev_t dev, int ip[])
+
+/* Apparently the the disk->capacity attribute is off by 1 sector
+ for all disk drives. We add the one here, but it should really
+ be done in sd.c. Even if it gets fixed there, this will still
+ work.
+*/
+
+{ ip[0] = 0x40;
+ ip[1] = 0x20;
+ ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
+ if (ip[2] > 1024) {
+ ip[0] = 0xff;
+ ip[1] = 0x3f;
+ ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
+ if (ip[2] > 1023)
+ ip[2] = 1023;
+ }
+ return 0;
+}
+
+int ppa_abort( Scsi_Cmnd * cmd )
+
+{ ppa_abort_flag = 1;
+ return SCSI_ABORT_SNOOZE;
+}
+
+int ppa_reset( Scsi_Cmnd * cmd )
+
+{ ppa_abort_flag = 2;
+ return SCSI_RESET_PUNT;
+}
+
+const char *ppa_info( struct Scsi_Host * host )
+
+{ return ppa_info_string;
+}
+
+#ifndef MODULE
+
+/* Command line parameters (for built-in driver):
+
+ Syntax: ppa=base[,speed_high[,speed_low[,call_sched[,nybble]]]]
+
+ For example: ppa=0x378 or ppa=0x378,0,3
+
+*/
+
+void ppa_setup(char *str, int *ints)
+
+{ if (ints[0] > 0) ppa_base = ints[1];
+ if (ints[0] > 1) ppa_speed_high = ints[2];
+ if (ints[0] > 2) ppa_speed_low = ints[3];
+ if (ints[0] > 3) ppa_call_sched = ints[4];
+ if (ints[0] > 4) ppa_nybble = ints[5];
+}
+
+#else
+
+Scsi_Host_Template driver_template = PPA;
+
+#include "scsi_module.c"
+
+#endif
+
+/* end of ppa.c */
--- /dev/null
+#ifndef _PPA_H
+#define _PPA_H
+
+/* Driver for the PPA3 parallel port SCSI HBA embedded in
+ the Iomega ZIP drive
+
+ (c) 1996 Grant R. Guenther grant@torque.net
+*/
+
+#define PPA_INITIATOR 7
+
+int ppa_detect(Scsi_Host_Template * );
+const char * ppa_info(struct Scsi_Host *);
+int ppa_command(Scsi_Cmnd *);
+int ppa_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int ppa_abort(Scsi_Cmnd *);
+int ppa_reset(Scsi_Cmnd *);
+int ppa_biosparam(Disk *, kdev_t, int[]);
+
+#define PPA { \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ ppa_detect, \
+ 0, \
+ ppa_info, \
+ ppa_command, \
+ ppa_queuecommand, \
+ ppa_abort, \
+ ppa_reset, \
+ 0, \
+ ppa_biosparam, \
+ 0, \
+ PPA_INITIATOR, \
+ SG_NONE, \
+ 1, \
+ 0, \
+ 0, \
+ DISABLE_CLUSTERING \
+}
+
+#endif /* _PPA_H */
{
if(SDp->type != TYPE_TAPE) return 0;
- printk(KERN_NOTICE "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
+ printk("Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
st_template.dev_noticed++,
SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
*********************************************************
* Readme.cards (this directory) contains some card *
* specific instructions. *
+* See http://personal.eunet.fi/pp/voxware for most up *
+* to date info. *
* *
* DON'T USE PROGRAMS FROM SND_UTIL PACKAGE EARLIER THAN *
* snd-util-3.5 WITH THIS SOUND DRIVER VERSION. *
-3.5-beta10
-0x030505
+3.5
+0x030500
-Changelog for version 3.5-beta10
---------------------------------
+Changelog for version 3.5
+-------------------------
-Since 3.5-beta8
+Since 3.5
+- Improved handling of playback underrunt situations.
+
+Since 3.5-beta10
+- Bug fixing
+
+Since 3.5-beta9
- Fixed for compatibility with Linux 1.3.70 and later.
- Changed boot time passing of 16 bit DMA channel number to SB driver.
clean:
rm -f core core.* *.o *.a tmp_make *~ x y z *%
- rm -f configure sound_stub.c objects/*.o
+ rm -f configure sound_stub.c objects/*.o
indent:
for n in *.c;do echo indent $$n;indent $$n;done
-Version 3.5-beta10 release notes
+Version 3.5-beta11 release notes
--------------------------------
Most up to date information about this driver is available from
-----------------------------------------------
There are currently many cards that work with this driver. Some of the cards
-have native support while the others work since they emulate some other
-cards (usually SB, MSS/WSS and/or MPU401). The following cards have native
+have native support while others work since they emulate some other
+card (usually SB, MSS/WSS and/or MPU401). The following cards have native
support in the driver. Detailed instructions for configuring these cards
will be given later in this document.
SB 1.0 to 2.0
SB Pro
SB 16
- NOTE! The ASP chip and the EMU synth of the AWE32 is not supported
+ NOTE! The ASP chip and the EMU synth of AWE32 are not supported
since their manufacturer doesn't release information about
- the card. However both the AB16ASP and the AWE32 work with
+ the card. However, both SB16ASP and AWE32 work with
the driver just like a SB16. Also see the comment about some
unsupported cards at the end of this file.
+ (The OPL3 FM chip of SB32/AWE works but you cannot hear it).
SB16 compatible cards by other manufacturers than Creative.
You have been fooled since there are no SB16 compatible
- cards in the market (July95). It's likely that your card
- is compatible just with SB Pro but there is also a non SB
- compatible 16 bit mode. Usually it's MSS/WSS but could also
+ cards on the market (Feb 96). It's likely that your card
+ is compatible just with SB Pro but there is also a non-SB-
+ compatible 16 bit mode. Usually it's MSS/WSS but it could also
be a proprietary one like MV Jazz16 or ESS ES688.
Gravis Ultrasound (GUS)
The driver works both with the full (intelligent mode) MPU-401
cards (such as MPU IPC-T and MQX-32M) and with the UART only
dumb MIDI ports. MPU-401 is currently the most common MIDI
- interface. Most soundcards are compatible with it. However
- don't enable MPU401 mode blindly. Many cards having native support
+ interface. Most soundcards are compatible with it. However,
+ don't enable MPU401 mode blindly. Many cards with native support
in the driver have their own MPU401 driver. Enabling the standard one
- will cause a conflict with these cards. So look if your card is
+ will cause a conflict with these cards. So check if your card is
in the list of supported cards before enabling MPU401.
Windows Sound System (MSS/WSS)
- Even Microsoft has discontinued their own Sound System card, they
- managed to make a standard. MSS compatible cards are based on a
- codec chip which is easily available from at least two manufacturers
+ Even when Microsoft has discontinued their own Sound System card
+ they managed to make it a standard. MSS compatible cards are based on
+ a codec chip which is easily available from at least two manufacturers
(AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor).
Currently most soundcards are based on one of the MSS compatible codec
- chip. The CS4231 is used in the high quality cards such as GUS MAX,
+ chips. The CS4231 is used in the high quality cards such as GUS MAX,
MediaTriX AudioTriX Pro and TB Tropez (GUS MAX is not MSS compatible).
Having a AD1848, CS4248 or CS4231 codec chip on the card is a good
sign. Even if the card is not MSS compatible, it could be easy to write
support for it. Note also that most MSS compatible cards
require special boot time initialization which may not be present
- in in the driver. Also some MSS compatible cards have native support.
+ in the driver. Also, some MSS compatible cards have native support.
Enabling the MSS support with these cards is likely to
cause a conflict. So check if your card is listed in this file before
enabling the MSS support.
operator chip used in the original AdLib card. Currently it's used
only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator
FM chip which provides better sound quality and/or more available
- voices than the OPL2. The OPL4 is a new chip which has a OPL3 and
- a wave table synthesizer packed on the same chip. The driver supports
- just the OPL3 mode directly. Most cards having a OPL4 (like
+ voices than the OPL2. The OPL4 is a new chip that has an OPL3 and
+ a wave table synthesizer packed onto the same chip. The driver supports
+ just the OPL3 mode directly. Most cards with an OPL4 (like
SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401
emulation. Writing a native OPL4 support is difficult
since Yamaha doesn't give information about their sample ROM chip.
The driver supports downloading DSP algorithms to these cards.
MediaTriX AudioTriX Pro
- The ATP card is built around a CS4231 codec and a OPL4 synthesizer
+ The ATP card is built around a CS4231 codec and an OPL4 synthesizer
chips. The OPL4 mode is supported by a microcontroller running a
General MIDI emulator. There is also a SB 1.5 compatible playback mode.
MAD16 and Mozart based cards
The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface
chips are used in many different soundcards, including some
- cards by Reveal and Turtle Beach (Tropez). Purpose of these
+ cards by Reveal and Turtle Beach (Tropez). The purpose of these
chips is to connect other audio components to the PC bus. The
interface chip performs address decoding for the other chips.
+ NOTE! Tropez Plus is not MAD16 but CS4232 based.
Audio Excell DSP16
- Support for this card is made by Riccardo Faccetti
+ Support for this card was written by Riccardo Faccetti
(riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
+ (This driver is not functional in version 3.5 of this driver).
-Crystal CS4232 based cards such as AcerMagic S23 and many PC motherboards
- (Compaq, HP, Intel, ...).
+Crystal CS4232 based cards such as AcerMagic S23, TB Tropez _Plus_ and
+ many PC motherboards (Compaq, HP, Intel, ...)
CS4232 is a PnP multimedia chip which contains a CS3231A codec,
SB and MPU401 emulations. There is support for OPL3 too.
This is a temporary driver which uses the chip in non PnP mode
(The final driver should be included in version 3.6 of the driver).
- Unfortunately the MPU401 mode doesn't work. The chip may also stop
- working after it has been used few times (only cold boot resets it).
+ Unfortunately the MPU401 mode doesn't work (I don't know how to
+ initialize it).
Turtle Beach Maui and Tropez
This driver version supports sample, patch and program loading commands
described in the Maui/Tropez User's manual. There is no initialization
- code for Maui so it must be initialized using DOS. Audio side of Tropez
- is based on the MAD16 chip (see above).
+ code for Maui so it must be initialized with DOS. The audio side of
+ the Tropez is based on the MAD16 chip (see above).
Jumpers and software configuration
----------------------------------
you read the above list correctly). Don't answer 'y' if you
have some other card made by Media Vision or Logitech since they
are not PAS16 compatible.
+ NOTE! Since 3.5-beta10 you need to enable SB support (next question)
+ if you want to use the SB emulation of PAS16. It's also possible to
+ the emulation if you want to use a true SB card together with PAS16
+ (there is another question about this that is asked later).
"SoundBlaster support",
- Answer 'y' if you have an original SB card made by Creative Labs
or a full 100% hardware compatible clone (like Thunderboard or
please look at the card specific instructions later in this file
before answering this question. For an unknown card you may answer
'y' if the card claims to be SB compatible.
+ Enable this option also with PAS16 (changed since v3.5-beta9).
Don't enable SB if you have a MAD16 or Mozart compatible card.
ProAudioSpectrum 16 and compatibles
-----------------------------------
-There are nothing special with these cards. Just don't enable any
-other cards in case you don't have them also. The PAS16 has
-a SB mode so the driver config program will prompt for the SB settings
-do. Use I/O 0x220 and DMA1 for the SB mode. Ensure that you assign different
-IRQ numbers for the SB and PAS16 modes.
+PAS16 has a SB emulation chip which can be used together with the native
+(16 bit) mode of the card. To enable this emulation you should configure
+the driver to have SB support too (this has been changed since version
+3.5-beta9 of this driver).
+
+With current driver versions it's also possible to use PAS16 together with
+another SB compatible card. In this case you should configure SB support
+for the other card and to disable the SB emulation of PAS16 (there is a
+separate questions about this).
With PAS16 you can use two audio device files at the same time. /dev/dsp (and
/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
There are some new Sound Galaxies in the market. I have no experience with
them so read the card's manual carefully.
-ESS ES1688 'AudioDrive' based cards
------------------------------------
+ESS ES1688 and ES688 'AudioDrive' based cards
+---------------------------------------------
Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port'
-if you want to use MIDI features of the card.
+if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
+so you don't need to enable it (the driver uses normal SB MIDI automaticly
+with ES688).
+
+NOTE! ESS cards are not compatible with MSS/WSS.
Reveal cards
------------
mknod -m 666 /dev/dsp0 c 14 3
ln -s /dev/dsp0 /dev/dsp
+#
+# DSPW (14, 5)
+#
+if [ -e /dev/dspW ]; then
+ rm -f /dev/dspW
+fi
+if [ -e /dev/dspW0 ]; then
+ rm -f /dev/dspW0
+fi
+mknod -m 666 /dev/dspW0 c 14 5
+ln -s /dev/dspW0 /dev/dspW
+
+if [ -e /dev/dspW1 ]; then
+ rm -f /dev/dspW1
+fi
+mknod -m 666 /dev/dspW1 c 14 37
+
#
# SPARC compatible /dev/audio (14, 4)
#
if (!(ad_read (devc, 11) & 0x20))
return;
- timeout = 40000;
+ timeout = 80000;
while (timeout > 0 && ad_read (devc, 11) & 0x20)
timeout--;
if (ad_read (devc, 11) & 0x20)
static void
ad_mute (ad1848_info * devc)
{
+ int i;
+ unsigned char prev;
+
+ if (devc->mode != MD_1848)
+ return;
+ /*
+ * Save old register settings and mute output channels
+ */
+ for (i = 6; i < 8; i++)
+ {
+ prev = devc->saved_regs[i] = ad_read (devc, i);
+ ad_write (devc, i, prev | 0x80);
+ }
}
static void
ad_unmute (ad1848_info * devc)
{
+ int i;
+
+ /*
+ * Restore back old volume registers (unmute)
+ */
+ for (i = 6; i < 8; i++)
+ {
+ ad_write (devc, i, devc->saved_regs[i] & ~0x80);
+ }
}
static void
ad1848_prepare_for_IO (int dev, int bsize, int bcount)
{
int timeout;
- unsigned char fs, old_fs;
+ unsigned char fs, old_fs, tmp = 0;
unsigned long flags;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
old_fs = ad_read (devc, 8);
- if (fs == old_fs) /* No change */
- {
- restore_flags (flags);
- devc->xfer_count = 0;
- return 0;
- }
+ if (devc->mode != MD_4232)
+ if (fs == old_fs) /* No change */
+ {
+ restore_flags (flags);
+ devc->xfer_count = 0;
+ return 0;
+ }
ad_enter_MCE (devc); /* Enables changes to the format select reg */
+ if (devc->mode == MD_4232)
+ {
+ tmp = ad_read (devc, 16);
+ ad_write (devc, 16, tmp | 0x30);
+ }
+
ad_write (devc, 8, fs);
/*
* Write to I8 starts resyncronization. Wait until it completes.
}
+ if (devc->mode == MD_4232)
+ ad_write (devc, 16, tmp & ~0x30);
+
ad_leave_MCE (devc); /*
* Starts the calibration process.
*/
ad1848_halt (int dev)
{
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- unsigned long flags;
- int timeout;
-
-
- save_flags (flags);
- cli ();
-
- ad_mute (devc);
- ad_enter_MCE (devc);
- ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */
- ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */
- ad_write (devc, 15, 4); /* Clear DMA counter */
- ad_write (devc, 14, 0); /* Clear DMA counter */
+ unsigned char bits = ad_read (devc, 9);
- if (devc->mode != MD_1848)
- {
- ad_write (devc, 30, 4); /* Clear DMA counter */
- ad_write (devc, 31, 0); /* Clear DMA counter */
- }
+ if (bits & 0x01)
+ ad1848_halt_output (dev);
- for (timeout = 0; timeout < 10000 && !(inb (io_Status (devc)) & 0x80);
- timeout++); /* Wait for interrupt */
-
- ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */
- outb (0, io_Status (devc)); /* Clear interrupt status */
- outb (0, io_Status (devc)); /* Clear interrupt status */
- devc->irq_mode = 0;
- ad_leave_MCE (devc);
-
- /* DMAbuf_reset_dma (dev); */
- restore_flags (flags);
+ if (bits & 0x02)
+ ad1848_halt_input (dev);
}
static void
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
- if (devc->mode == MD_1848)
- {
- ad1848_halt (dev);
- return;
- }
-
save_flags (flags);
cli ();
ad_mute (devc);
+
+ if (devc->mode == MD_4232) /* Use applied black magic */
+ {
+ int tmout;
+
+ disable_dma (audio_devs[dev]->dmachan1);
+
+ for (tmout = 0; tmout < 100000; tmout++)
+ if (ad_read (devc, 11) & 0x10)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+
+ enable_dma (audio_devs[dev]->dmachan1);
+ restore_flags (flags);
+ return;
+ }
ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
- if (devc->mode == MD_1848)
- {
- ad1848_halt (dev);
- return;
- }
-
save_flags (flags);
cli ();
ad_mute (devc);
+ if (devc->mode == MD_4232) /* Use applied black magic */
+ {
+ int tmout;
+
+ disable_dma (audio_devs[dev]->dmachan1);
+
+ for (tmout = 0; tmout < 100000; tmout++)
+ if (ad_read (devc, 11) & 0x10)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+
+ enable_dma (audio_devs[dev]->dmachan1);
+ restore_flags (flags);
+ return;
+ }
ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
nr_ad1848_devs++;
#ifdef CONFIG_SEQUENCER
- if (devc->mode != MD_1848 && devc->irq_ok)
+ if (devc->mode != MD_1848 && devc->mode != MD_1845 && devc->irq_ok)
ad1848_tmr_install (my_dev);
#endif
if (irq > 15)
{
- printk ("ad1848.c: Bogus interrupt %d\n", irq);
+ /* printk ("ad1848.c: Bogus interrupt %d\n", irq); */
return;
}
/*
* PnP soundcard support is not included in this version.
*
- * AEDSP16 will not work without significant changes.
- *
- * SB Pro and SB16 drivers are always enabled together with SB.
+ * AEDSP16 will not work without significant changes.
*/
-#define DISABLED_OPTIONS (B(OPT_PNP)|B(OPT_AEDSP16)|B(OPT_SBPRO)|B(OPT_SB16))
+#define DISABLED_OPTIONS (B(OPT_PNP)|B(OPT_AEDSP16)|B(OPT_UNUSED1)|B(OPT_UNUSED2))
/*
* sound/configure.c - Configuration program for the Linux Sound Driver
*/
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
+#define COPYING2
#include <stdio.h>
#include <unistd.h>
#define OPT_PNP 15
#define OPT_HIGHLEVEL 16 /* This must be same than the next one */
-#define OPT_SBPRO 16
-#define OPT_SB16 17
+#define OPT_UNUSED1 16
+#define OPT_UNUSED2 17
#define OPT_AEDSP16 18
#define OPT_AUDIO 19
#define OPT_MIDI_AUTO 20
#define OPT_MIDI 21
#define OPT_YM3812_AUTO 22
#define OPT_YM3812 23
-#define OPT_SEQUENCER 24
-#define OPT_LAST 24 /* Last defined OPT number */
+#define OPT_LAST 23 /* Last defined OPT number */
#define DUMMY_OPTS (B(OPT_MIDI_AUTO)|B(OPT_YM3812_AUTO))
-#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
+#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_GUS)| \
B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \
B(OPT_MSS)|B(OPT_SSCAPE)|B(OPT_UART6850)|B(OPT_TRIX)| \
B(OPT_MAD16)|B(OPT_CS4232)|B(OPT_MAUI))
#define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\
B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\
B(OPT_PNP))
+#define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS)
/*
* Options that have been disabled for some reason (incompletely implemented
* and/or tested). Don't remove from this list before looking at file
{0, 0, "MAUI", 1, 0, 0},
{0, 0, "PNP", 1, 0, 0},
- {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
- {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
- {B (OPT_SBPRO) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0},
+ {B (OPT_SB), B (OPT_PAS), "UNUSED1", 1, 0, 1},
+ {B (OPT_SB) | B (OPT_UNUSED1), B (OPT_PAS), "UNUSED2", 1, 0, 1},
+ {B (OPT_UNUSED1) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0},
{AUDIO_CARDS, 0, "AUDIO", 1, 0, 1},
{B (OPT_MPU401) | B (OPT_MAUI), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
{MIDI_CARDS, 0, "MIDI", 1, 0, 1},
{B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
- {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
- {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
+ {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}
};
char *questions[] =
"Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers",
"Support for PnP sound cards (_EXPERIMENTAL_)",
- "SoundBlaster Pro support",
- "SoundBlaster 16 support",
+ "*** Unused option 1 ***",
+ "*** Unused option 2 ***",
"Audio Excel DSP 16 initialization support",
"/dev/dsp and /dev/audio support",
"This should not be asked",
"MIDI interface support",
"This should not be asked",
"FM synthesizer (YM3812/OPL-3) support",
- "/dev/sequencer support",
"Is the sky really falling"
};
"them. In addition the MAD16 chip is used in some cards made by known\n"
"manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n"
"Diamond (latest ones).\n",
-
+
"Enable this if you have a card based on the Crystal CS4232 chip set.\n",
"Enable this option if you have a Turtle Beach Wave Front, Maui,\n"
"This enables the dev/midixx devices and access to any MIDI ports\n"
"using /dev/sequencer and /dev/music. This option also affects any\n"
"MPU401 and/or General MIDI compatible devices.\n",
-
+
"This should not be asked",
"This enables the Yamaha FM synthesizer chip used on many sound\n"
"cards.\n",
- "This enables the /dev/sequencer and /dev/music devices used for\n"
- "playing computer music.\n",
-
"Is the sky really falling"
};
"AD1848", AD1848_DEVS
}
,
+ {
+ "SEQUENCER", SEQUENCER_DEVS
+ }
+ ,
{
NULL, 0
}
int
can_select_option (int nr)
{
+#if 0
+ switch (nr)
+ {
+ case OPT_LAST_MUTUAL + 1:
+ fprintf (stderr, "\nThe following cards should work with any other cards.\n"
+ "CAUTION! Don't enable MPU-401 if you don't have it.\n");
+ break;
+
+ case OPT_HIGHLEVEL:
+ fprintf (stderr, "\nSelect one or more of the following options\n");
+ break;
+
+
+ }
+#endif
if (hw_table[nr].conditions)
if (!(hw_table[nr].conditions & selected_options))
char answ[512];
int len;
-response:
- fprintf (stderr, prompt);
+ response:
+ fprintf(stderr, prompt);
if (def_answ)
- fprintf (stderr, " [Y/n/?] ");
+ fprintf(stderr, " [Y/n/?] ");
else
- fprintf (stderr, " [N/y/?] ");
+ fprintf(stderr, " [N/y/?] ");
if ((len = read (0, answ, sizeof (answ))) < 1)
{
*/
return def_answ;
- if (answ[0] == '?')
- { /* display help message */
- fprintf (stderr, "\n");
- fprintf (stderr, help);
- fprintf (stderr, "\n");
- goto response;
- }
+ if (answ[0] == '?') { /* display help message */
+ fprintf(stderr, "\n");
+ fprintf(stderr, help);
+ fprintf(stderr, "\n");
+ goto response;
+ }
answ[len - 1] = 0;
for (i = 0; i < OPT_LAST; i++)
if (mask == B (i))
{
- unsigned int j;
+ unsigned int j;
for (j = 0; j < strlen (choices); j++)
if (choices[j] == '\'')
return;
fprintf (stderr, "\n%s\n", question);
- if (strcmp (choices, ""))
+ if (strcmp(choices, ""))
fprintf (stderr, "Possible values are: %s\n", choices);
if (format == FMT_INT)
continue;
if (strcmp (tmp, "JAZZ_DMA16") == 0) /* Rename it (hack) */
- {
- printf ("#define SB_DMA2 %s\n",
- &buf[18]);
- continue;
- }
+ {
+ printf("#define SB_DMA2 %s\n",
+ &buf[18]);
+ continue;
+ }
if (strcmp (tmp, "SB16_DMA") == 0) /* Rename it (hack) */
- {
- printf ("#define SB_DMA2 %s\n",
- &buf[16]);
- continue;
- }
+ {
+ printf("#define SB_DMA2 %s\n",
+ &buf[16]);
+ continue;
+ }
tmp[8] = 0; /* Truncate the string */
if (strcmp (tmp, "EXCLUDE_") == 0)
printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
fprintf (stderr, "Old configuration copied.\n");
+#ifdef linux
build_defines ();
+#endif
old_config_used = 1;
return 1;
}
+#ifdef linux
void
build_defines (void)
{
if (!hw_table[i].alias)
if (selected_options & B (i))
fprintf (optf, "CONFIG_%s=y\n", hw_table[i].macro);
+#if 0
+ else
+ fprintf (optf, "CONFIG_%s=n\n", hw_table[i].macro);
+#endif
fprintf (optf, "\n");
{
if (selected_options & extra_options[i].mask)
fprintf (optf, "CONFIG_%s=y\n", extra_options[i].name);
+#if 0
+ else
+ fprintf (optf, "CONFIG_%s=n\n", extra_options[i].name);
+#endif
i++;
}
fprintf (optf, "\n");
fclose (optf);
}
+#endif
void
ask_parameters (void)
{
+#ifdef linux
int num;
build_defines ();
"0, 1 or 3");
ask_int_choice (B (OPT_SB), "SB_DMA2",
- "SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
+ "SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
FMT_INT,
5,
"5, 6 or 7");
if (selected_options & B (OPT_PAS))
{
if (think_positively ("Enable Joystick port on ProAudioSpectrum", 0,
- "Enable this option if you want to use the joystick port provided\n"
- "on the PAS sound card.\n"));
-
- printf ("#define PAS_JOYSTICK_ENABLE\n");
+ "Enable this option if you want to use the joystick port provided\n"
+ "on the PAS sound card.\n"))
+ printf ("#define PAS_JOYSTICK_ENABLE\n");
if (think_positively ("Enable PAS16 bus clock option", 0,
- "The PAS16 can be noisy with some motherboards. There is a command\n"
- "line switch (:T?) in the DOS driver for PAS16 which solves this.\n"
+ "The PAS16 can be noisy with some motherboards. There is a command\n"
+ "line switch (:T?) in the DOS driver for PAS16 which solves this.\n"
"Don't enable this feature unless you have problems and have to use\n"
- "this switch with DOS\n"))
+ "this switch with DOS\n"))
printf ("#define BROKEN_BUS_CLOCK\n");
+
+ if (think_positively ("Disable SB mode of PAS16", 0,
+ "You should disable SB emulation of PAS16 if you want to use\n"
+ "Another SB compatible card in the same system\n"))
+ printf ("#define DISABLE_SB_EMULATION\n");
}
ask_int_choice (B (OPT_GUS), "GUS_BASE",
int reveal_spea;
reveal_spea = think_positively (
- "Is your SoundScape card made/marketed by Reveal or Spea",
- 0,
- "Enable if you have a SoundScape card with the Reveal or\n"
- "Spea name on it.\n");
+ "Is your SoundScape card made/marketed by Reveal or Spea",
+ 0,
+ "Enable if you have a SoundScape card with the Reveal or\n"
+ "Spea name on it.\n");
if (reveal_spea)
printf ("#define REVEAL_SPEA\n");
FMT_INT,
9,
"5, 7, 9 or 10");
+#endif
ask_int_choice (B (OPT_AUDIO), "DSP_BUFFSIZE",
"Audio DMA buffer size",
FMT_INT,
printf ("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro);
}
+/*
+ * Some "hardcoded" options
+ */
+ printf ("bool 'Support for SM Wave' CONFIG_SMWAVE\n");
+
dump_only = 1;
selected_options = 0;
ask_parameters ();
+#if 1
printf ("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n");
+#endif
}
void
if (access (oldconf, R_OK) == 0)
{
- char str[255];
-
- sprintf (str, "Old configuration exists in `%s'. Use it", oldconf);
+ char str[255];
+ sprintf(str, "Old configuration exists in `%s'. Use it", oldconf);
if (think_positively (str, 1,
- "Enable this option to load the previously saved configuration file\n"
- "for all of the sound driver parameters.\n"))
+"Enable this option to load the previously saved configuration file\n"
+"for all of the sound driver parameters.\n"))
if (use_old_config (oldconf))
exit (0);
}
}
}
- if (selected_options & B (OPT_SBPRO))
+ if (selected_options & B (OPT_SB))
{
if (think_positively (
- "Support for the SG NX Pro mixer", 0,
- "Enable this if you want to support the additional mixer functions\n"
- "provided on Sound Galaxy NX Pro sound cards.\n"))
+ "Support for the SG NX Pro mixer", 0,
+ "Enable this if you want to support the additional mixer functions\n"
+ "provided on Sound Galaxy NX Pro sound cards.\n"))
printf ("#define __SGNXPRO__\n");
}
if (selected_options & B (OPT_SB))
{
if (think_positively ("Support for the MV Jazz16 (ProSonic etc.)", 0,
- "Enable this if you have an MV Jazz16 or ProSonic sound card.\n"))
+ "Enable this if you have an MV Jazz16 or ProSonic sound card.\n"))
{
if (think_positively ("Do you have SoundMan Wave", 0,
- "Enable this option of you have the Logitech SoundMan Wave sound card.\n"))
+ "Enable this option of you have the Logitech SoundMan Wave sound card.\n"))
{
printf ("#define SM_WAVE\n");
midi0001_again:
if (think_positively (
- "Do you have access to the MIDI0001.BIN file", 1,
- "The Logitech SoundMan Wave has a microcontroller which must be\n"
- "initialized before MIDI emulation works. This is possible only if the\n"
- "microcode file is compiled into the driver.\n"))
+"Do you have access to the MIDI0001.BIN file", 1,
+"The Logitech SoundMan Wave has a microcontroller which must be\n"
+"initialized before MIDI emulation works. This is possible only if the\n"
+"microcode file is compiled into the driver.\n"))
{
char path[512];
fprintf (stderr, "Couldn't open file %s\n",
path);
if (think_positively ("Try again with correct path", 1,
- "The specified file could not be opened. Enter the correct path to the\n"
- "file.\n"))
+"The specified file could not be opened. Enter the correct path to the\n"
+"file.\n"))
goto midi0001_again;
}
else
if (selected_options & B (OPT_SB))
{
if (think_positively ("Do you have a Logitech SoundMan Games", 0,
- "The Logitech SoundMan Games supports 44 kHz in stereo while the\n"
- "standard SB Pro supports just 22 kHz stereo. You have the option of\n"
- "enabling SM Games mode. However, enable it only if you are sure that\n"
- "your card is an SM Games. Enabling this feature with a plain old SB\n"
- "Pro will cause troubles with stereo mode.\n\n"
- "DANGER! Read the above once again before answering 'y'\n"
- "Answer 'n' if you are unsure what to do!\n"))
+"The Logitech SoundMan Games supports 44 kHz in stereo while the\n"
+"standard SB Pro supports just 22 kHz stereo. You have the option of\n"
+"enabling SM Games mode. However, enable it only if you are sure that\n"
+"your card is an SM Games. Enabling this feature with a plain old SB\n"
+"Pro will cause troubles with stereo mode.\n\n"
+"DANGER! Read the above once again before answering 'y'\n"
+"Answer 'n' if you are unsure what to do!\n"))
printf ("#define SM_GAMES\n");
}
- if (selected_options & B (OPT_SB16))
- selected_options |= B (OPT_SBPRO);
-
if (selected_options & B (OPT_AEDSP16))
{
int sel1 = 0;
- if (selected_options & B (OPT_SBPRO))
+ if (selected_options & B (OPT_SB))
{
if (think_positively (
- "Do you want support for the Audio Excel SoundBlaster Pro mode",
- 1,
- "Enable this option if you want the Audio Excel sound card to operate\n"
- "in SoundBlaster Pro mode.\n"))
+"Do you want support for the Audio Excel SoundBlaster Pro mode",
+1,
+"Enable this option if you want the Audio Excel sound card to operate\n"
+"in SoundBlaster Pro mode.\n"))
{
printf ("#define AEDSP16_SBPRO\n");
sel1 = 1;
if ((selected_options & B (OPT_MSS)) && (sel1 == 0))
{
-
+
if (think_positively (
- "Do you want support for the Audio Excel Microsoft Sound System mode",
- 1,
- "Enable this option if you want the Audio Excel sound card to operate\n"
- "in Microsoft Sound System mode.\n"))
+"Do you want support for the Audio Excel Microsoft Sound System mode",
+1,
+"Enable this option if you want the Audio Excel sound card to operate\n"
+"in Microsoft Sound System mode.\n"))
{
printf ("#define AEDSP16_MSS\n");
sel1 = 1;
{
genld_again:
if (think_positively ("Do you wish to include an LD file", 1,
- "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
- "file then you must include the LD in the kernel.\n"))
+ "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
+ "file then you must include the LD in the kernel.\n"))
{
char path[512];
if (!bin2hex (path, "synth-ld.h", "pss_synth"))
{
- fprintf (stderr, "couldn't open `%s' as the LD file\n", path);
+ fprintf (stderr, "couldn't open `%s' as the LD file\n", path);
if (think_positively ("try again with correct path", 1,
- "The given LD file could not opened.\n"))
+ "The given LD file could not opened.\n"))
goto genld_again;
}
else
hex2hex_again:
if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
- 1,
- "The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
- "needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
- "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
- "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
- "Pro will not work without this file!\n"))
+ 1,
+"The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
+"needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
+"in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
+"you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
+"Pro will not work without this file!\n"))
{
char path[512];
if (!(selected_options & ANY_DEVS))
{
printf ("invalid_configuration__run_make_config_again\n");
- fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device ***\n\n");
+ fprintf (stderr,"\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device ***\n\n");
exit (0);
}
if (!old_config_used)
{
- char str[255];
-
- sprintf (str, "Save copy of this configuration to `%s'", oldconf);
- if (think_positively (str, 1,
- "If you enable this option then the sound driver configuration is\n"
- "saved to a file. If you later need to recompile the kernel you have\n"
- "the option of using the saved configuration.\n"))
+ char str[255];
+ sprintf(str, "Save copy of this configuration to `%s'", oldconf);
+ if (think_positively (str, 1,
+"If you enable this option then the sound driver configuration is\n"
+"saved to a file. If you later need to recompile the kernel you have\n"
+"the option of using the saved configuration.\n"))
{
char cmd[200];
#endif
#ifdef CONFIG_GUS
{"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus},
+ {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus},
#endif
#ifdef CONFIG_SSCAPE
{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape, unload_sscape},
dmap->dma_mode = DMODE_NONE;
dmap->flags &= ~DMA_BUSY;
+ disable_dma (chan);
sound_free_dmap (dev, dmap);
}
polish_buffers (struct dma_buffparms *dmap)
{
int i;
+ int p, l;
- if (dmap->cfrag < 0)
+ i = dmap->qhead;
+
+ p = dmap->fragment_size * i;
+
+ if (i == dmap->cfrag)
{
- memset (dmap->raw_buf,
- dmap->neutral_byte,
- dmap->bytes_in_use);
- return;
+ l = dmap->fragment_size - dmap->counts[i];
}
+ else
+ l = dmap->fragment_size;
- for (i = 0; i < dmap->nbufs; i++)
+ if (l)
{
- int p, l;
-
- p = dmap->fragment_size * i;
+ memset (dmap->raw_buf + p,
+ dmap->neutral_byte,
+ l);
+ }
+}
- if (i == dmap->cfrag)
- {
- l = dmap->fragment_size - dmap->counts[i];
- }
- else
- l = dmap->fragment_size;
+static void
+force_restart (int dev, struct dma_buffparms *dmap)
+{
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_output)
+ audio_devs[dev]->halt_output (dev);
+ else
+ audio_devs[dev]->halt_xfer (dev);
- if (l)
- {
- memset (dmap->raw_buf + p,
- dmap->neutral_byte,
- l);
- }
- }
+ dmap->flags &= ~DMA_ACTIVE;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
}
void
if (event_type == 1 && dmap->qlen < 1)
{
dmap->underrun_count++;
- /* Ignore underrun. Just move the tail pointer forward and go */
+
+ if (dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)
+ {
+ dmap->qlen = 0;
+ force_restart (dev, dmap);
+ }
+ else
+ /* Ignore underrun. Just move the tail pointer forward and go */
if (dmap->closing)
{
polish_buffers (dmap);
if (audio_devs[dev]->flags & DMA_AUTOMODE)
{
- /* Force restart on next write */
+ /* Force restart on next read */
if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
audio_devs[dev]->halt_input)
audio_devs[dev]->halt_input (dev);
extern int gus_wave_volume;
extern int gus_pcm_volume;
extern int have_gus_max;
+int gus_pnp_flag = 0;
int *gus_osp;
gus_osp = hw_config->osp;
+ if (hw_config->card_subtype == 1)
+ gus_pnp_flag = 1;
+
irq = hw_config->irq;
if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */
return 0;
}
- if (!check_region (hw_config->io_base, 16))
- if (!check_region (hw_config->io_base + 0x100, 16))
- if (gus_wave_detect (hw_config->io_base))
- return 1;
+ if (check_region (hw_config->io_base, 16))
+ printk ("GUS: I/O range conflict (1)\n");
+ else if (check_region (hw_config->io_base + 0x100, 16))
+ printk ("GUS: I/O range conflict (2)\n");
+ else if (gus_wave_detect (hw_config->io_base))
+ return 1;
#ifndef EXCLUDE_GUS_IODETECT
extern int gus_base;
extern int gus_irq, gus_dma;
+extern int gus_pnp_flag;
static int gus_dma2 = -1;
static int dual_dma_mode = 0;
static long gus_mem_size = 0;
int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
- if (irq < 0 || irq > 15)
- {
- printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return mem_start;
- }
+ if (!gus_pnp_flag)
+ if (irq < 0 || irq > 15)
+ {
+ printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+ return mem_start;
+ }
- if (dma < 0 || dma > 7)
+ if (dma < 0 || dma > 7 || dma == 4)
{
printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
return mem_start;
val = inb (gus_base + 0x0f);
restore_flags (flags);
- if (val != 0xff && (val & 0x06)) /* Should be 0x02?? */
+#ifndef GUSPNP_NO_AUTODETECT
+ gus_pnp_flag = (val == 1);
+#endif
+
+ if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */
{
/*
* It has the digital ASIC so the card is at least v3.4.
* Next try to detect the true model.
*/
- val = inb (u_MixSelect);
+ if (gus_pnp_flag) /* Hack hack hack */
+ val = 10;
+ else
+ val = inb (u_MixSelect);
/*
* Value 255 means pre-3.7 which don't have mixer.
if (hw_config->name)
{
- strncpy (gus_info.name, hw_config->name, sizeof (gus_info.name));
+ char tmp[20];
+
+ strncpy (tmp, hw_config->name, 20);
+ tmp[19] = 0;
+ sprintf (gus_info.name, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
gus_info.name[sizeof (gus_info.name) - 1] = 0;
}
else
if (pcm_qlen == 0)
flag = 1; /* Underrun */
dma_active = 0;
- DMAbuf_outputintr (gus_devnum, flag);
+ if (gus_busy)
+ DMAbuf_outputintr (gus_devnum, flag);
}
break;
#undef PSEUDO_DMA_AUTOINIT
#define ALLOW_BUFFER_MAPPING
+
pas_write (irq_dma, EMULATION_CONFIGURATION);
}
+ else
+ pas_write (0x00, COMPATIBILITY_ENABLE);
}
#else
pas_write (0x00, COMPATIBILITY_ENABLE);
}
break;
+ case SNDCTL_COPR_SENDMSG:
+ {
+ copr_msg *buf;
+ unsigned long flags;
+ unsigned short *data;
+ unsigned short tmp;
+ int i;
+
+ buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOSPC;
+
+ memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+
+ data = (unsigned short *) (buf->data);
+
+ /* printk( "SNDCTL_COPR_SENDMSG: data = %d", data ); */
+
+ save_flags (flags);
+ cli ();
+
+ for (i = 0; i < buf->len; i++)
+ {
+ tmp = *data++;
+ if (!pss_put_dspword (devc, tmp))
+ {
+ restore_flags (flags);
+ buf->len = i; /* feed back number of WORDs sent */
+ memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf));
+ kfree (buf);
+ return -EIO;
+ }
+ }
+
+ restore_flags (flags);
+ kfree (buf);
+
+ return 0;
+ }
+ break;
+
+
+ case SNDCTL_COPR_RCVMSG:
+ {
+ copr_msg *buf;
+ unsigned long flags;
+ unsigned short *data;
+ unsigned int i;
+ int err = 0;
+
+ buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOSPC;
+
+ memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+
+ data = (unsigned short *) buf->data;
+
+ save_flags (flags);
+ cli ();
+
+ for (i = 0; i < buf->len; i++)
+ {
+ if (!pss_get_dspword (devc, data++))
+ {
+ buf->len = i; /* feed back number of WORDs read */
+ err = -EIO;
+ break;
+ }
+ }
+
+ restore_flags (flags);
+
+ memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf));
+ kfree (buf);
+
+ return err;
+ }
+ break;
+
+
case SNDCTL_COPR_RDATA:
{
copr_debug_buf buf;
return -EIO;
}
- tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
+ tmp = (unsigned int) buf.parm2 & 0x00ff;
if (!pss_put_dspword (devc, tmp))
{
restore_flags (flags);
return -EIO;
}
- tmp = (unsigned int) buf.parm2 & 0x00ff;
+ tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
if (!pss_put_dspword (devc, tmp))
{
restore_flags (flags);
DEB (printk ("sb16_dsp_close()\n"));
sb_dsp_command01 (0xd9);
sb_dsp_command01 (0xd5);
+ sb_reset_dsp ();
save_flags (flags);
cli ();
return -EBUSY;
}
- reset_sb16midi ();
while (input_avail ())
sb16midi_read ();
int sbc_major = 0, sbc_minor = 0;
static int dsp_stereo = 0;
static int dsp_current_speed = DSP_DEFAULT_SPEED;
+static int dsp_requested_speed = DSP_DEFAULT_SPEED;
static int sb16 = 0;
static int irq_verified = 0;
unsigned long flags;
int max_speed = 44100;
+ dsp_requested_speed = speed;
+
if (AudioDrive)
return ess_speed (speed);
}
dsp_stereo = !!mode;
+ dsp_speed (dsp_requested_speed);
return dsp_stereo;
}
unsigned long flags;
int count = nr_bytes;
- if (!sb_irq_mode)
- dsp_speaker (ON);
-
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
sb_irq_mode = 0;
* Start a DMA input to the buffer pointed by dmaqtail
*/
- if (!sb_irq_mode)
- dsp_speaker (OFF);
-
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
sb_irq_mode = 0;
dsp_cleanup ();
dsp_speaker (OFF);
+ dsp_speed (dsp_requested_speed);
if (sbc_major == 3) /*
* SB Pro
else
sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
- dsp_speed (dsp_current_speed);
} /* !AudioDrive */
}
trigger_bits = 0;
{
dsp_cleanup ();
dsp_speaker (OFF);
+ dsp_speed (dsp_requested_speed);
if (sbc_major == 3) /* SB Pro (at least ) */
{
return -ENXIO;
}
+ if (!sb_midi_busy)
+ sb_reset_dsp ();
+
if (sb_no_recording && mode & OPEN_READ)
{
printk ("SB Warning: Recording not supported by this device\n");
*/
-#include "os.h"
#include "local.h"
+#include "os.h"
#include "soundvers.h"
#if defined(ISC) || defined(SCO) || defined(SVR42)
{
int dev;
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
+
files[dev].flags = file_get_flags (file);
return sound_read_sw (dev, &files[dev], buf, count);
{
int dev;
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
+
files[dev].flags = file_get_flags (file);
return sound_write_sw (dev, &files[dev], buf, count);
return -EBUSY;
}
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
{
{
int dev;
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
files[dev].flags = file_get_flags (file);
{
int dev, err;
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
+
files[dev].flags = file_get_flags (file);
if (_IOC_DIR (cmd) != _IOC_NONE)
{
int dev;
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
+
files[dev].flags = file_get_flags (file);
DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
unsigned long size;
struct dma_buffparms *dmap = NULL;
- dev = inode_get_rdev (inode);
- dev = MINOR (dev);
+ dev = MINOR (inode_get_rdev (inode));
+
files[dev].flags = file_get_flags (file);
dev_class = dev & 0x0f;
void
cleanup_module (void)
{
- if (MOD_IN_USE)
- printk ("sound: module busy -- remove delayed\n");
- else
- {
- int i;
+ int i;
- if (chrdev_registered)
- module_unregister_chrdev (sound_major, "sound");
+ if (chrdev_registered)
+ module_unregister_chrdev (sound_major, "sound");
#ifdef CONFIG_SEQUENCER
- sound_stop_timer ();
+ sound_stop_timer ();
#endif
- sound_unload_drivers ();
+ sound_unload_drivers ();
- for (i = 0; i < sound_num_blocks; i++)
- kfree (sound_mem_blocks[i]);
+ for (i = 0; i < sound_num_blocks; i++)
+ kfree (sound_mem_blocks[i]);
- free_all_irqs (); /* If something was left allocated by accident */
+ free_all_irqs (); /* If something was left allocated by accident */
- for (i = 0; i < 8; i++)
- if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
- {
- printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i);
- sound_free_dma (i);
- }
- }
+ for (i = 0; i < 8; i++)
+ if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
+ {
+ printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i);
+ sound_free_dma (i);
+ }
}
#endif
void
snd_release_irq (int vect)
{
+ if (!(irqs & (1ul << vect)))
+ return;
+
irqs &= ~(1ul << vect);
free_irq (vect, NULL);
}
audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
- if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL)
+ if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, 1)) == NULL)
audio_devs[dev]->buffsize /= 2;
}
dmap->raw_buf = start_addr;
dmap->raw_buf_phys = virt_to_bus (start_addr);
- memset (dmap->raw_buf, 0x00, audio_devs[dev]->buffsize);
-
for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
{
mem_map_reserve (i);
-#define SOUND_VERSION_STRING "3.5-beta10-960301"
-#define SOUND_INTERNAL_VERSION 0x030505
+#define SOUND_VERSION_STRING "3.5-960313"
+#define SOUND_INTERNAL_VERSION 0x030500
static int nr_hash = 0; /* Size of hash table */
static struct buffer_head ** hash_table;
-struct buffer_head ** buffer_pages;
static struct buffer_head * lru_list[NR_LIST] = {NULL, };
/* next_to_age is an array of pointers into the lru lists, used to
cycle through the buffers aging their contents when deciding which
break;
}
free_list[isize] = bh;
- buffer_pages[MAP_NR(page)] = bh;
+ mem_map[MAP_NR(page)].buffers = bh;
tmp->b_this_page = bh;
buffermem += PAGE_SIZE;
return 1;
put_unused_buffer_head(p);
} while (tmp != bh);
buffermem -= PAGE_SIZE;
- buffer_pages[MAP_NR(page)] = NULL;
+ mem_map[MAP_NR(page)].buffers = NULL;
free_page(page);
return !mem_map[MAP_NR(page)].count;
}
break;
}
buffermem += PAGE_SIZE;
- buffer_pages[MAP_NR(page)] = bh;
+ mem_map[MAP_NR(page)].buffers = bh;
bh->b_this_page = tmp;
while (nblock-- > 0)
brelse(arr[nblock]);
sizeof(struct buffer_head *));
- buffer_pages = (struct buffer_head **) vmalloc(MAP_NR(high_memory) *
- sizeof(struct buffer_head *));
- for (i = 0 ; i < MAP_NR(high_memory) ; i++)
- buffer_pages[i] = NULL;
-
for (i = 0 ; i < nr_hash ; i++)
hash_table[i] = NULL;
lru_list[BUF_CLEAN] = 0;
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
-extern inline void pte_reuse(pte_t * ptep)
-{
- if (!mem_map[MAP_NR(ptep)].reserved)
- mem_map[MAP_NR(ptep)].count++;
-}
extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || pmd_page(pmd) > high_memory; }
extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_VALID; }
-extern inline int pmd_inuse(pmd_t *pmdp) { return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; }
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)
-{
- if (!mem_map[MAP_NR(pmdp)].reserved)
- mem_map[MAP_NR(pmdp)].count++;
-}
extern inline int pgd_none(pgd_t pgd) { return !pgd_val(pgd); }
extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) & _PAGE_VALID; }
-extern inline int pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; }
extern inline void pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; }
/*
/*
* Allocate and free page tables. The xxx_kernel() versions are
* used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
+ * if any.
*/
extern inline void pte_free_kernel(pte_t * pte)
{
- mem_map[MAP_NR(pte)].reserved = 0;
free_page((unsigned long) pte);
}
if (pmd_none(*pmd)) {
if (page) {
pmd_set(pmd, page);
- mem_map[MAP_NR(page)].reserved = 1;
return page + address;
}
pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
extern inline void pmd_free_kernel(pmd_t * pmd)
{
- mem_map[MAP_NR(pmd)].reserved = 0;
free_page((unsigned long) pmd);
}
if (pgd_none(*pgd)) {
if (page) {
pgd_set(pgd, page);
- mem_map[MAP_NR(page)].reserved = 1;
return page + address;
}
pgd_set(pgd, BAD_PAGETABLE);
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
-extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
-extern inline void pte_reuse(pte_t * ptep)
-{
- if (!mem_map[MAP_NR(ptep)].reserved)
- mem_map[MAP_NR(ptep)].count++;
-}
extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; }
-#ifdef USE_PENTIUM_MM
-extern inline int pmd_inuse(pmd_t *pmdp) { return (pmd_val(*pmdp) & _PAGE_4M) != 0; }
-#else
-extern inline int pmd_inuse(pmd_t *pmdp) { return 0; }
-#endif
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp) { }
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
extern inline int pgd_none(pgd_t pgd) { return 0; }
extern inline int pgd_bad(pgd_t pgd) { return 0; }
extern inline int pgd_present(pgd_t pgd) { return 1; }
-extern inline int pgd_inuse(pgd_t * pgdp) { return mem_map[MAP_NR(pgdp)].reserved; }
extern inline void pgd_clear(pgd_t * pgdp) { }
/*
/*
* Allocate and free page tables. The xxx_kernel() versions are
* used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
+ * if any.
*/
extern inline void pte_free_kernel(pte_t * pte)
{
- mem_map[MAP_NR(pte)].reserved = 0;
free_page((unsigned long) pte);
}
if (pmd_none(*pmd)) {
if (page) {
pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
- mem_map[MAP_NR(page)].reserved = 1;
return page + address;
}
pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
/*
* DMA memory allocation - formerly in include/linux/mm.h
*/
-#define __get_dma_pages(priority, order) __get_free_pages((priority),(order), \
- 0x80000000 + MAX_DMA_ADDRESS)
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order), 1)
#endif /* __ASM_MIPS_DMA_H */
extern struct inode_operations chrdev_inode_operations;
extern void init_fifo(struct inode * inode);
-struct inode_operations fifo_inode_operations;
+extern struct inode_operations fifo_inode_operations;
extern struct file_operations connecting_fifo_fops;
extern struct file_operations read_fifo_fops;
extern void refill_freelist(int size);
extern int try_to_free_buffer(struct buffer_head*, struct buffer_head**, int);
-extern struct buffer_head ** buffer_pages;
extern int nr_buffers;
extern int buffermem;
extern int nr_buffer_heads;
referenced:1,
locked:1,
free_after:1,
- unused:2,
+ dma:1,
+ unused:1,
reserved:1;
struct wait_queue *wait;
struct page *next;
struct page *prev;
struct page *prev_hash;
+ struct buffer_head * buffers;
} mem_map_t;
extern mem_map_t * mem_map;
-/*
- * Free area management
- */
-
-#define NR_MEM_LISTS 6
-
-struct mem_list {
- struct mem_list * next;
- struct mem_list * prev;
-};
-
-extern struct mem_list free_area_list[NR_MEM_LISTS];
-extern unsigned int * free_area_map[NR_MEM_LISTS];
-
/*
* This is timing-critical - most of the time in getting a new page
* goes to clearing the page. If you want a page without the clearing
* overhead, just use __get_free_page() directly..
*/
-#define __get_free_page(priority) __get_free_pages((priority),0,~0UL)
-#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),MAX_DMA_ADDRESS)
-extern unsigned long __get_free_pages(int priority, unsigned long gfporder, unsigned long max_addr);
+#define __get_free_page(priority) __get_free_pages((priority),0,0)
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),1)
+extern unsigned long __get_free_pages(int priority, unsigned long gfporder, int dma);
extern inline unsigned long get_free_page(int priority)
{
/* filemap.c */
extern unsigned long page_unuse(unsigned long);
-extern int shrink_mmap(int, unsigned long);
+extern int shrink_mmap(int, int);
extern void truncate_inode_pages(struct inode *, unsigned long);
#define GFP_BUFFER 0x00
PROC_SCSI_AM53C974,
PROC_SCSI_SSC,
PROC_SCSI_NCR53C406A,
+ PROC_SCSI_PPA,
PROC_SCSI_SCSI_DEBUG,
PROC_SCSI_NOT_PRESENT,
PROC_SCSI_FILE, /* I'm asuming here that we */
#define SNDCARD_CS4232_MPU 22
#define SNDCARD_MAUI 23
#define SNDCARD_PSEUDO_MSS 24
+#define SNDCARD_GUSPNP 25
/***********************************
* IOCTL Commands for /dev/sequencer
#define SNDCTL_DSP_GETOPTR _IOR ('P',18, count_info)
typedef struct buffmem_desc {
- caddr_t buffer;
+ unsigned *buffer;
int size;
} buffmem_desc;
#define SNDCTL_DSP_MAPINBUF _IOR ('P', 19, buffmem_desc)
#define SNDCTL_DSP_MAPOUTBUF _IOR ('P', 20, buffmem_desc)
#define SNDCTL_DSP_SETSYNCRO _IO ('P', 21)
+#define SNDCTL_DSP_SETDUPLEX _IO ('P', 22)
#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
struct sysinfo;
/* linux/ipc/shm.c */
-extern int shm_swap (int, unsigned long);
+extern int shm_swap (int, int);
/* linux/mm/vmscan.c */
-extern int try_to_free_page(int, unsigned long, int);
+extern int try_to_free_page(int, int, int);
/* linux/mm/page_io.c */
extern void rw_swap_page(int, unsigned long, char *, int);
extern unsigned long swap_cache_find_success;
#endif
-extern inline unsigned long in_swap_cache(unsigned long addr)
+extern inline unsigned long in_swap_cache(unsigned long index)
{
- return swap_cache[MAP_NR(addr)];
+ return swap_cache[index];
}
-extern inline long find_in_swap_cache (unsigned long addr)
+extern inline long find_in_swap_cache(unsigned long index)
{
unsigned long entry;
#ifdef SWAP_CACHE_INFO
swap_cache_find_total++;
#endif
- entry = xchg(swap_cache + MAP_NR(addr), 0);
+ entry = xchg(swap_cache + index, 0);
#ifdef SWAP_CACHE_INFO
if (entry)
swap_cache_find_success++;
return entry;
}
-extern inline int delete_from_swap_cache(unsigned long addr)
+extern inline int delete_from_swap_cache(unsigned long index)
{
unsigned long entry;
#ifdef SWAP_CACHE_INFO
swap_cache_del_total++;
#endif
- entry= xchg(swap_cache + MAP_NR(addr), 0);
+ entry = xchg(swap_cache + index, 0);
if (entry) {
#ifdef SWAP_CACHE_INFO
swap_cache_del_success++;
extern void buff_setup(char *str, int *ints);
extern void panic_setup(char *str, int *ints);
extern void bmouse_setup(char *str, int *ints);
+extern void lp_setup(char *str, int *ints);
extern void eth_setup(char *str, int *ints);
extern void xd_setup(char *str, int *ints);
extern void floppy_setup(char *str, int *ints);
extern void BusLogic_Setup(char *str, int *ints);
extern void fdomain_setup(char *str, int *ints);
extern void NCR53c406a_setup(char *str, int *ints);
+extern void ppa_setup(char *str, int *ints);
extern void scsi_luns_setup(char *str, int *ints);
extern void sound_setup(char *str, int *ints);
#ifdef CONFIG_CDU31A
#ifdef CONFIG_INET
{ "ether=", eth_setup },
#endif
+#ifdef CONFIG_PRINTER
+ { "lp=", lp_setup },
+#endif
#ifdef CONFIG_SCSI
{ "max_scsi_luns=", scsi_luns_setup },
#endif
#ifdef CONFIG_SCSI_FUTURE_DOMAIN
{ "fdomain=", fdomain_setup},
#endif
+#ifdef CONFIG_SCSI_PPA
+ { "ppa=", ppa_setup },
+#endif
#ifdef CONFIG_BLK_DEV_XD
{ "xd=", xd_setup },
#endif
static unsigned long swap_id = 0; /* currently being swapped */
static unsigned long swap_idx = 0; /* next to swap */
-int shm_swap (int prio, unsigned long limit)
+int shm_swap (int prio, int dma)
{
pte_t page;
struct shmid_ds *shp;
pte_val(page) = shp->shm_pages[idx];
if (!pte_present(page))
goto check_table;
- if (pte_page(page) >= limit)
+ if (dma && !mem_map[MAP_NR(pte_page(page))].dma)
goto check_table;
swap_attempts++;
if (acct_active) {
strncpy(ac.ac_comm, current->comm, ACCT_COMM);
- ac.ac_comm[ACCT_COMM] = '\0';
+ ac.ac_comm[ACCT_COMM-1] = '\0';
ac.ac_utime = current->utime;
ac.ac_stime = current->stime;
ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
}
}
-int shrink_mmap(int priority, unsigned long limit)
+int shrink_mmap(int priority, int dma)
{
static int clock = 0;
struct page * page;
+ unsigned long limit = MAP_NR(high_memory);
struct buffer_head *tmp, *bh;
- if (limit > high_memory)
- limit = high_memory;
- limit = MAP_NR(limit);
- if (clock >= limit)
- clock = 0;
priority = (limit<<2) >> priority;
page = mem_map + clock;
while (priority-- > 0) {
if (page->locked)
- goto next;
+ goto next;
+ if (dma && !page->dma)
+ goto next;
/* First of all, regenerate the page's referenced bit
from any buffers in the page */
- bh = buffer_pages[MAP_NR(page_address(page))];
+ bh = page->buffers;
if (bh) {
tmp = bh;
do {
struct inode * inode;
struct buffer_head * bh;
- bh = buffer_pages[MAP_NR(page)];
+ bh = mem_map[MAP_NR(page)].buffers;
if (bh) {
/* whee.. just mark the buffer heads dirty */
struct buffer_head * tmp = bh;
void *kmalloc(size_t size, int priority)
{
unsigned long flags;
- unsigned long max_addr, type;
+ unsigned long type;
int order, i, sz;
struct block_header *p;
struct page_descriptor *page, **pg;
return (NULL);
}
- max_addr = ~0UL;
type = MF_USED;
pg = &sizes[order].firstfree;
if (priority & GFP_DMA) {
- max_addr = MAX_DMA_ADDRESS;
type = MF_DMA;
pg = &sizes[order].dmafree;
}
sz = BLOCKSIZE(order);
page = (struct page_descriptor *) __get_free_pages(priority,
- sizes[order].gfporder, max_addr);
+ sizes[order].gfporder, priority & GFP_DMA);
if (!page) {
static unsigned long last = 0;
unsigned long high_memory = 0;
-/*
- * The free_area_list arrays point to the queue heads of the free areas
- * of different sizes
- */
-int nr_swap_pages = 0;
-int nr_free_pages = 0;
-struct mem_list free_area_list[NR_MEM_LISTS];
-unsigned int * free_area_map[NR_MEM_LISTS];
-
/*
* We special-case the C-O-W ZERO_PAGE, because it's such
* a common occurrence (no need to read the page to know
static inline void free_one_pgd(pgd_t * dir)
{
+ int j;
pmd_t * pmd;
if (pgd_none(*dir))
}
pmd = pmd_offset(dir, 0);
pgd_clear(dir);
- if (!pmd_inuse(pmd)) {
- int j;
- for (j = 0; j < PTRS_PER_PMD ; j++)
- free_one_pmd(pmd+j);
- }
+ for (j = 0; j < PTRS_PER_PMD ; j++)
+ free_one_pmd(pmd+j);
pmd_free(pmd);
}
invalidate_mm(tsk->mm);
SET_PAGE_DIR(tsk, swapper_pg_dir);
tsk->mm->pgd = swapper_pg_dir; /* or else... */
- for (i = 0 ; i < PTRS_PER_PGD ; i++)
+ for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
free_one_pgd(page_dir + i);
pgd_free(page_dir);
}
static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)
{
pte_t pte = *old_pte;
+ unsigned long page_nr;
if (pte_none(pte))
return;
set_pte(new_pte, pte);
return;
}
- if (pte_page(pte) > high_memory || mem_map[MAP_NR(pte_page(pte))].reserved) {
+ page_nr = MAP_NR(pte_page(pte));
+ if (page_nr >= MAP_NR(high_memory) || mem_map[page_nr].reserved) {
set_pte(new_pte, pte);
return;
}
if (cow)
pte = pte_wrprotect(pte);
- if (delete_from_swap_cache(pte_page(pte)))
+ if (delete_from_swap_cache(page_nr))
pte = pte_mkdirty(pte);
set_pte(new_pte, pte_mkold(pte));
set_pte(old_pte, pte);
- mem_map[MAP_NR(pte_page(pte))].count++;
+ mem_map[page_nr].count++;
}
static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long address, unsigned long size, int cow)
#include <asm/bitops.h>
#include <asm/pgtable.h>
-static inline void add_mem_queue(struct mem_list * head, struct mem_list * entry)
+int nr_swap_pages = 0;
+int nr_free_pages = 0;
+
+/*
+ * Free area management
+ *
+ * The free_area_list arrays point to the queue heads of the free areas
+ * of different sizes
+ */
+
+#define NR_MEM_LISTS 6
+
+struct free_area_struct {
+ struct page list;
+ unsigned int * map;
+};
+
+static struct free_area_struct free_area[NR_MEM_LISTS];
+
+static inline void init_mem_queue(struct page * head)
{
+ head->next = head;
+ head->prev = head;
+}
+
+static inline void add_mem_queue(struct page * head, struct page * entry)
+{
+ struct page * next = head->next;
+
entry->prev = head;
- (entry->next = head->next)->prev = entry;
+ entry->next = next;
+ next->prev = entry;
head->next = entry;
}
-static inline void remove_mem_queue(struct mem_list * head, struct mem_list * entry)
+static inline void remove_mem_queue(struct page * head, struct page * entry)
{
- struct mem_list * next = entry->next;
- (next->prev = entry->prev)->next = next;
+ struct page * next = entry->next;
+ struct page * prev = entry->prev;
+ next->prev = prev;
+ prev->next = next;
}
/*
/*
* Buddy system. Hairy. You really aren't expected to understand this
*/
-static inline void free_pages_ok(unsigned long addr, unsigned long order)
+static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
{
- unsigned long index = MAP_NR(addr) >> (1 + order);
- unsigned long mask = PAGE_MASK << order;
+ unsigned long index = map_nr >> (1 + order);
+ unsigned long mask = (~0UL) << order;
+
+#define list(x) (mem_map+(x))
- addr &= mask;
+ map_nr &= mask;
nr_free_pages += 1 << order;
while (order < NR_MEM_LISTS-1) {
- if (!change_bit(index, free_area_map[order]))
+ if (!change_bit(index, free_area[order].map))
break;
- remove_mem_queue(free_area_list+order, (struct mem_list *) (addr ^ (1+~mask)));
+ remove_mem_queue(&free_area[order].list, list(map_nr ^ (1+~mask)));
+ mask <<= 1;
order++;
index >>= 1;
- mask <<= 1;
- addr &= mask;
+ map_nr &= mask;
}
- add_mem_queue(free_area_list+order, (struct mem_list *) addr);
+ add_mem_queue(&free_area[order].list, list(map_nr));
+#undef list
}
-static inline void check_free_buffers(unsigned long addr)
+static inline void check_free_buffers(mem_map_t * map)
{
struct buffer_head * bh;
- bh = buffer_pages[MAP_NR(addr)];
+ bh = map->buffers;
if (bh) {
struct buffer_head *tmp = bh;
do {
void free_pages(unsigned long addr, unsigned long order)
{
- if (MAP_NR(addr) < MAP_NR(high_memory)) {
- unsigned long flag;
- mem_map_t * map = mem_map + MAP_NR(addr);
+ unsigned long map_nr = MAP_NR(addr);
+
+ if (map_nr < MAP_NR(high_memory)) {
+ mem_map_t * map = mem_map + map_nr;
if (map->reserved)
return;
if (map->count) {
+ unsigned long flag;
save_flags(flag);
cli();
if (!--map->count) {
- free_pages_ok(addr, order);
- delete_from_swap_cache(addr);
+ free_pages_ok(map_nr, order);
+ delete_from_swap_cache(map_nr);
}
restore_flags(flag);
if (map->count == 1)
- check_free_buffers(addr);
+ check_free_buffers(map);
return;
}
printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
/*
* Some ugly macros to speed up __get_free_pages()..
*/
-#define RMQUEUE(order, limit) \
-do { struct mem_list * queue = free_area_list+order; \
+#define MARK_USED(index, order, area) \
+ change_bit((index) >> (1+(order)), (area)->map)
+#define CAN_DMA(x) ((x)->dma)
+#define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
+#define RMQUEUE(order, dma) \
+do { struct free_area_struct * area = free_area+order; \
unsigned long new_order = order; \
- do { struct mem_list *prev = queue, *ret; \
- while (queue != (ret = prev->next)) { \
- if ((unsigned long) ret < (limit)) { \
+ do { struct page *prev = &area->list, *ret; \
+ while (&area->list != (ret = prev->next)) { \
+ if (!dma || CAN_DMA(ret)) { \
+ unsigned long map_nr = ret - mem_map; \
(prev->next = ret->next)->prev = prev; \
- mark_used((unsigned long) ret, new_order); \
+ MARK_USED(map_nr, new_order, area); \
nr_free_pages -= 1 << order; \
+ EXPAND(ret, map_nr, order, new_order, area); \
restore_flags(flags); \
- EXPAND(ret, order, new_order); \
- return (unsigned long) ret; \
+ return ADDRESS(map_nr); \
} \
prev = ret; \
} \
- new_order++; queue++; \
+ new_order++; area++; \
} while (new_order < NR_MEM_LISTS); \
} while (0)
-static inline int mark_used(unsigned long addr, unsigned long order)
-{
- return change_bit(MAP_NR(addr) >> (1+order), free_area_map[order]);
-}
-
-#define EXPAND(addr,low,high) \
-do { unsigned long size = PAGE_SIZE << high; \
+#define EXPAND(map,index,low,high,area) \
+do { unsigned long size = 1 << high; \
while (high > low) { \
- high--; size >>= 1; cli(); \
- add_mem_queue(free_area_list+high, addr); \
- mark_used((unsigned long) addr, high); \
- restore_flags(flags); \
- addr = (struct mem_list *) (size + (unsigned long) addr); \
- } mem_map[MAP_NR((unsigned long) addr)].count = 1; \
- mem_map[MAP_NR((unsigned long) addr)].age = PAGE_INITIAL_AGE; \
+ area--; high--; size >>= 1; \
+ add_mem_queue(&area->list, map); \
+ MARK_USED(index, high, area); \
+ index += size; \
+ map += size; \
+ } \
+ map->count = 1; \
+ map->age = PAGE_INITIAL_AGE; \
} while (0)
-unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
+unsigned long __get_free_pages(int priority, unsigned long order, int dma)
{
unsigned long flags;
int reserved_pages;
repeat:
cli();
if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
- RMQUEUE(order, limit);
+ RMQUEUE(order, dma);
restore_flags(flags);
return 0;
}
restore_flags(flags);
- if (priority != GFP_BUFFER && try_to_free_page(priority, limit, 1))
+ if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
goto repeat;
return 0;
}
save_flags(flags);
cli();
for (order=0 ; order < NR_MEM_LISTS; order++) {
- struct mem_list * tmp;
+ struct page * tmp;
unsigned long nr = 0;
- for (tmp = free_area_list[order].next ; tmp != free_area_list + order ; tmp = tmp->next) {
+ for (tmp = free_area[order].list.next ; tmp != &free_area[order].list ; tmp = tmp->next) {
nr ++;
}
total += nr * ((PAGE_SIZE>>10) << order);
memset(mem_map, 0, start_mem - (unsigned long) mem_map);
do {
--p;
+ p->dma = 1;
p->reserved = 1;
} while (p > mem_map);
for (i = 0 ; i < NR_MEM_LISTS ; i++) {
unsigned long bitmap_size;
- free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
+ init_mem_queue(&free_area[i].list);
mask += mask;
end_mem = (end_mem + ~mask) & mask;
bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i);
bitmap_size = (bitmap_size + 7) >> 3;
bitmap_size = LONG_ALIGN(bitmap_size);
- free_area_map[i] = (unsigned int *) start_mem;
+ free_area[i].map = (unsigned int *) start_mem;
memset((void *) start_mem, 0, bitmap_size);
start_mem += bitmap_size;
}
}
vma->vm_mm->rss++;
tsk->maj_flt++;
- if (!write_access && add_to_swap_cache(page, entry)) {
+ if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
set_pte(page_table, mk_pte(page, vma->vm_page_prot));
return;
}
}
#endif
-int add_to_swap_cache(unsigned long addr, unsigned long entry)
+int add_to_swap_cache(unsigned long index, unsigned long entry)
{
struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
swap_cache_add_total++;
#endif
if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
- entry = xchg(swap_cache + MAP_NR(addr), entry);
+ entry = xchg(swap_cache + index, entry);
if (entry) {
printk("swap_cache: replacing non-NULL entry\n");
}
if (pte_none(pte))
return 0;
if (pte_present(pte)) {
- unsigned long page = pte_page(pte);
- if (page >= high_memory)
+ unsigned long page_nr = MAP_NR(pte_page(pte));
+ if (page_nr >= MAP_NR(high_memory))
return 0;
- if (!in_swap_cache(page))
+ if (!in_swap_cache(page_nr))
return 0;
- if (SWP_TYPE(in_swap_cache(page)) != type)
+ if (SWP_TYPE(in_swap_cache(page_nr)) != type)
return 0;
- delete_from_swap_cache(page);
+ delete_from_swap_cache(page_nr);
set_pte(dir, pte_mkdirty(pte));
return 0;
}
return 0;
}
-static int unuse_process(struct task_struct * p, unsigned int type, unsigned long page)
+static int unuse_process(struct mm_struct * mm, unsigned int type, unsigned long page)
{
struct vm_area_struct* vma;
/*
* Go through process' page directory.
*/
- if (!p->mm || pgd_inuse(p->mm->pgd))
+ if (!mm)
return 0;
- vma = p->mm->mmap;
+ vma = mm->mmap;
while (vma) {
- pgd_t * pgd = pgd_offset(p->mm, vma->vm_start);
+ pgd_t * pgd = pgd_offset(mm, vma->vm_start);
if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
return 1;
vma = vma->vm_next;
return -ENOMEM;
nr = 0;
while (nr < NR_TASKS) {
- if (task[nr]) {
- if (unuse_process(task[nr], type, page)) {
+ struct task_struct * p = task[nr];
+ if (p) {
+ if (unuse_process(p->mm, type, page)) {
page = get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
* have died while we slept).
*/
static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
- unsigned long address, pte_t * page_table, unsigned long limit, int wait)
+ unsigned long address, pte_t * page_table, int dma, int wait)
{
pte_t pte;
unsigned long entry;
page = pte_page(pte);
if (MAP_NR(page) >= MAP_NR(high_memory))
return 0;
- if (page >= limit)
- return 0;
page_map = mem_map + MAP_NR(page);
- if (page_map->reserved || page_map->locked)
+ if (page_map->reserved || page_map->locked ||
+ (dma && !page_map->dma))
return 0;
/* Deal with page aging. Pages age from being unused; they
* rejuvinate on being accessed. Only swap old pages (age==0
* is oldest). */
- if ((pte_dirty(pte) && delete_from_swap_cache(page))
+ if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page)))
|| pte_young(pte)) {
set_pte(page_table, pte_mkold(pte));
touch_page(page_map);
free_page(page);
return 1; /* we slept: the process may not exist any more */
}
- if ((entry = find_in_swap_cache(page))) {
+ if ((entry = find_in_swap_cache(MAP_NR(page)))) {
if (page_map->count != 1) {
set_pte(page_table, pte_mkdirty(pte));
printk("Aiee.. duplicated cached swap-cache entry\n");
*/
static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
- pmd_t *dir, unsigned long address, unsigned long end, unsigned long limit, int wait)
+ pmd_t *dir, unsigned long address, unsigned long end, int dma, int wait)
{
pte_t * pte;
unsigned long pmd_end;
do {
int result;
tsk->swap_address = address + PAGE_SIZE;
- result = try_to_swap_out(tsk, vma, address, pte, limit, wait);
+ result = try_to_swap_out(tsk, vma, address, pte, dma, wait);
if (result)
return result;
address += PAGE_SIZE;
}
static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
- pgd_t *dir, unsigned long address, unsigned long end, unsigned long limit, int wait)
+ pgd_t *dir, unsigned long address, unsigned long end, int dma, int wait)
{
pmd_t * pmd;
unsigned long pgd_end;
end = pgd_end;
do {
- int result = swap_out_pmd(tsk, vma, pmd, address, end, limit, wait);
+ int result = swap_out_pmd(tsk, vma, pmd, address, end, dma, wait);
if (result)
return result;
address = (address + PMD_SIZE) & PMD_MASK;
}
static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
- pgd_t *pgdir, unsigned long start, unsigned long limit, int wait)
+ pgd_t *pgdir, unsigned long start, int dma, int wait)
{
unsigned long end;
end = vma->vm_end;
while (start < end) {
- int result = swap_out_pgd(tsk, vma, pgdir, start, end, limit, wait);
+ int result = swap_out_pgd(tsk, vma, pgdir, start, end, dma, wait);
if (result)
return result;
start = (start + PGDIR_SIZE) & PGDIR_MASK;
return 0;
}
-static int swap_out_process(struct task_struct * p, unsigned long limit, int wait)
+static int swap_out_process(struct task_struct * p, int dma, int wait)
{
unsigned long address;
struct vm_area_struct* vma;
address = vma->vm_start;
for (;;) {
- int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, limit, wait);
+ int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, dma, wait);
if (result)
return result;
vma = vma->vm_next;
return 0;
}
-static int swap_out(unsigned int priority, unsigned long limit, int wait)
+static int swap_out(unsigned int priority, int dma, int wait)
{
static int swap_task;
int loop, counter;
}
if (!--p->swap_cnt)
swap_task++;
- switch (swap_out_process(p, limit, wait)) {
+ switch (swap_out_process(p, dma, wait)) {
case 0:
if (p->swap_cnt)
swap_task++;
* to be. This works out OK, because we now do proper aging on page
* contents.
*/
-int try_to_free_page(int priority, unsigned long limit, int wait)
+int try_to_free_page(int priority, int dma, int wait)
{
static int state = 0;
int i=6;
switch (state) {
do {
case 0:
- if (shrink_mmap(i, limit))
+ if (shrink_mmap(i, dma))
return 1;
state = 1;
case 1:
- if (shm_swap(i, limit))
+ if (shm_swap(i, dma))
return 1;
state = 2;
default:
- if (swap_out(i, limit, wait))
+ if (swap_out(i, dma, wait))
return 1;
state = 0;
} while (i--);
swapstats.wakeups++;
/* Do the background pageout: */
for (i=0; i < kswapd_ctl.maxpages; i++)
- try_to_free_page(GFP_KERNEL, ~0UL, 0);
+ try_to_free_page(GFP_KERNEL, 0, 0);
}
}
static void unix_destroy_socket(unix_socket *sk)
{
struct sk_buff *skb;
+
unix_remove_socket(sk);
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
}
else
{
-/* unix_kill_credentials(skb); *//* Throw out any passed fd's */
+ /* passed fds are erased where?? */
kfree_skb(skb,FREE_WRITE);
}
}
* but how the old code did it - or like this...
*/
-int unix_files_free(void)
+static int unix_files_free(void)
{
int i;
int n=0;
static void unix_detach_fds(struct sk_buff *skb, struct cmsghdr *cmsg)
{
int i;
+ /* count of space in parent for fds */
int cmnum;
struct file **fp;
struct file **ufp;
int *cmfptr=NULL; /* =NULL To keep gcc happy */
+ /* number of fds actually passed */
int fdnum;
int ffree;
int ufn=0;
+
if(cmsg==NULL)
cmnum=0;
else
}
kfree(skb->h.filp);
skb->h.filp=NULL;
-
+
+ /* no need to use destructor */
+ skb->destructor = NULL;
}
static void unix_destruct_fds(struct sk_buff *skb)
/*
* Attach the file descriptor array to an sk_buff
*/
-
static void unix_attach_fds(int fpnum,struct file **fp,struct sk_buff *skb)
{
+
skb->h.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *),
GFP_KERNEL);
+ /* number of descriptors starts block */
memcpy(skb->h.filp,&fpnum,sizeof(int));
+ /* actual descriptors */
memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *));
- skb->destructor=unix_destruct_fds;
+ skb->destructor = unix_destruct_fds;
}
/*
int limit=0;
int sent=0;
struct file *fp[UNIX_MAX_FD];
+ /* number of fds waiting to be passed, 0 means either
+ * no fds to pass or they've already been passed
+ */
int fpnum=0;
- int fp_attached=0;
if(sk->err)
return sock_error(sk);
cm->cmsg_level!=SOL_SOCKET ||
msg->msg_accrightslen!=cm->cmsg_len)
{
-#if 0
- printk("Sendmsg: bad access rights\n");
-#endif
kfree(cm);
return -EINVAL;
}
fpnum=unix_fd_copy(sk,cm,fp);
kfree(cm);
if(fpnum<0) {
-#if 0
- printk("Sendmsg error = %d\n", fpnum);
-#endif
return fpnum;
}
}
skb->sk=sk;
skb->free=1;
- if(fpnum && !fp_attached)
+ if(fpnum)
{
- fp_attached=1;
unix_attach_fds(fpnum,fp,skb);
fpnum=0;
}
else
skb->h.filp=NULL;
+
memcpy_fromiovec(skb_put(skb,size),msg->msg_iov, size);
cli();
if(msg->msg_accrights)
{
- printk("recvmsg with accrights\n");
cm=unix_copyrights(msg->msg_accrights,
msg->msg_accrightslen);
if(msg->msg_accrightslen<sizeof(struct cmsghdr)
menu_instructions="\
Arrow keys navigate the menu. \
-Highlighted letters are hotkeys. \
-Select an item with <Space Bar> or <Enter>. \
+Highlighted letters are hotkeys. \
+Select an item with <Space Bar> or <Enter>. \
When finished press <Esc><Esc> or <X>. \
-(*) indicates an option will be compiled into the kernel. \
-(M) indicates an option will be compiled as a module."
+A (*) marks an option to be compiled into the kernel. \
+An (M) marks an option to be compiled as a module."
radiolist_instructions="\
Use the arrow keys to navigate this window or \
EOM
else
clear
- echo -e "Your kernel configuration changes where NOT saved.\n"
+ echo -e "Your kernel configuration changes were NOT saved.\n"
fi
/^$varname\[ \]*\$/ {
start=1;
printf(\"%s:\\n\\n\",\$0);
- continue;
+ next;
}
!/^\[ \]/ {
start=0;
/*
* Print a string of text in a window, automatically wrap around to the
- * next line if the string is too long to fit on one line. Note that the
- * string may contain "\n" to represent a newline character or the real
- * newline '\n', but in that case, auto wrap around will be disabled.
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces. We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
*/
void
print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x)
{
- int first = 1, cur_x, cur_y;
- int i, prompt_len;
- char tempstr[MAX_LEN + 1], *word /*, *tempptr, *tempptr1*/;
+ int newl, cur_x, cur_y;
+ int i, prompt_len, room, wlen;
+ char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
strcpy (tempstr, prompt);
if(tempstr[i] == '\n') tempstr[i] = ' ';
}
- if (strlen (tempstr) <= width - x * 2) { /* If prompt is short */
- wmove (win, y, (width - strlen (tempstr)) / 2);
+ if (prompt_len <= width - x * 2) { /* If prompt is short */
+ wmove (win, y, (width - prompt_len) / 2);
waddstr (win, tempstr);
} else {
cur_x = x;
cur_y = y;
- /* Print prompt word by word, wrap around if necessary */
- while ((word = strtok (first ? tempstr : NULL, " ")) != NULL) {
- if (first) /* First iteration */
- first = 0;
- if (cur_x + strlen (word) > width) {
- cur_y++; /* wrap to next line */
+ newl = 1;
+ word = tempstr;
+ while (word && *word) {
+ sp = index(word, ' ');
+ if (sp)
+ *sp++ = 0;
+
+ /* Wrap to next line if either the word does not fit,
+ or it is the first word of a new sentence, and it is
+ short, and the next word does not fit. */
+ room = width - cur_x;
+ wlen = strlen(word);
+ if (wlen > room ||
+ (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room
+ && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) {
+ cur_y++;
cur_x = x;
}
wmove (win, cur_y, cur_x);
waddstr (win, word);
getyx (win, cur_y, cur_x);
cur_x++;
+ if (sp && *sp == ' ') {
+ cur_x++; /* double space */
+ while (*++sp == ' ');
+ newl = 1;
+ } else
+ newl = 0;
+ word = sp;
}
}
}