From 497898b98a10115b8755555577809f543d3d1a84 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:40 -0500 Subject: [PATCH] Import 1.3.74 --- CREDITS | 7 + Documentation/Configure.help | 64 ++- Makefile | 2 +- arch/i386/mm/init.c | 2 + arch/sparc/mm/srmmu.c | 2 +- drivers/block/floppy.c | 21 +- drivers/block/ide.c | 15 +- drivers/char/ftape/Makefile | 2 +- drivers/char/ftape/RELEASE-NOTES | 8 + drivers/char/ftape/calibr.c | 1 - drivers/char/ftape/ecc.c | 1 - drivers/char/ftape/fc-10.c | 1 - drivers/char/ftape/fdc-io.c | 8 +- drivers/char/ftape/fdc-isr.c | 1 - drivers/char/ftape/ftape-bsm.c | 1 - drivers/char/ftape/ftape-ctl.c | 1 - drivers/char/ftape/ftape-eof.c | 1 - drivers/char/ftape/ftape-io.c | 1 - drivers/char/ftape/ftape-read.c | 1 - drivers/char/ftape/ftape-rw.c | 1 - drivers/char/ftape/ftape-write.c | 1 - drivers/char/ftape/kernel-interface.c | 4 - drivers/char/ftape/tracing.c | 1 - drivers/char/lp.c | 32 ++ drivers/isdn/teles/buffers.c | 2 +- drivers/net/Config.in | 1 + drivers/net/Makefile | 8 + drivers/net/Space.c | 4 + drivers/net/eexpress.c | 6 +- drivers/net/fmv18x.c | 664 ++++++++++++++++++++++++++ drivers/scsi/Config.in | 1 + drivers/scsi/Makefile | 8 + drivers/scsi/README.ppa | 123 +++++ drivers/scsi/hosts.c | 7 + drivers/scsi/ppa.c | 479 +++++++++++++++++++ drivers/scsi/ppa.h | 44 ++ drivers/scsi/st.c | 2 +- drivers/sound/.blurb | 2 + drivers/sound/.version | 4 +- drivers/sound/CHANGELOG | 12 +- drivers/sound/Makefile | 2 +- drivers/sound/Readme | 2 +- drivers/sound/Readme.cards | 86 ++-- drivers/sound/Readme.linux | 17 + drivers/sound/ad1848.c | 129 +++-- drivers/sound/configure.c | 280 +++++------ drivers/sound/dev_table.h | 1 + drivers/sound/dmabuf.c | 62 ++- drivers/sound/gus_card.c | 14 +- drivers/sound/gus_wave.c | 34 +- drivers/sound/os.h | 1 + drivers/sound/pas2_card.c | 2 + drivers/sound/pss.c | 85 +++- drivers/sound/sb16_dsp.c | 1 + drivers/sound/sb16_midi.c | 1 - drivers/sound/sb_dsp.c | 16 +- drivers/sound/sound_config.h | 2 +- drivers/sound/soundcard.c | 66 ++- drivers/sound/soundvers.h | 4 +- fs/buffer.c | 12 +- include/asm-alpha/pgtable.h | 19 +- include/asm-i386/pgtable.h | 17 +- include/asm-mips/dma.h | 3 +- include/linux/fs.h | 3 +- include/linux/mm.h | 26 +- include/linux/proc_fs.h | 1 + include/linux/soundcard.h | 4 +- include/linux/swap.h | 16 +- init/main.c | 8 + ipc/shm.c | 4 +- kernel/sys.c | 2 +- mm/filemap.c | 16 +- mm/kmalloc.c | 6 +- mm/memory.c | 27 +- mm/page_alloc.c | 143 ++++-- mm/swap_state.c | 4 +- mm/swapfile.c | 23 +- mm/vmscan.c | 41 +- net/unix/af_unix.c | 33 +- scripts/Menuconfig | 10 +- scripts/header.tk | 2 +- scripts/lxdialog/util.c | 45 +- 82 files changed, 2198 insertions(+), 618 deletions(-) create mode 100644 drivers/net/fmv18x.c create mode 100644 drivers/scsi/README.ppa create mode 100644 drivers/scsi/ppa.c create mode 100644 drivers/scsi/ppa.h diff --git a/CREDITS b/CREDITS index 0d0563b0b3d0..a46010d1e3f6 100644 --- a/CREDITS +++ b/CREDITS @@ -394,6 +394,13 @@ N: Philip Gladstone 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. diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 6aab81e29e0e..6c1dc4ef4f0c 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -815,9 +815,9 @@ CONFIG_IP_MROUTE 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 @@ -1054,16 +1054,16 @@ CONFIG_BLK_DEV_SR 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 @@ -1341,6 +1341,18 @@ CONFIG_SCSI_AM53C974 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 @@ -1583,9 +1595,10 @@ CONFIG_ULTRA 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 @@ -1682,9 +1695,9 @@ CONFIG_EL3 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 @@ -2006,7 +2019,9 @@ CONFIG_APRICOT 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 @@ -2383,7 +2398,8 @@ CONFIG_VFAT_FS 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. @@ -2699,7 +2715,9 @@ CONFIG_FTAPE (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 @@ -2962,3 +2980,5 @@ CONFIG_ISDN_DRV_TELES # 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 diff --git a/Makefile b/Makefile index e8ebce75f01f..383523f62102 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 73 +SUBLEVEL = 74 ARCH = i386 diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 5c4c6860d8c6..883d8dcf01fa 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -236,6 +236,8 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) 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++; diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 0bd67118e60c..b5385e5b8d7a 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -902,7 +902,7 @@ unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk) { 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)); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 15c07e19d0d0..2aab361ca9ca 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -171,28 +171,23 @@ struct old_floppy_raw_cmd { /* 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); } diff --git a/drivers/block/ide.c b/drivers/block/ide.c index c324a16fc419..7d9cfdfb7967 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -524,7 +524,7 @@ static void ide_geninit (struct gendisk *gd) */ static void init_gendisk (ide_hwif_t *hwif) { - struct gendisk *gd, **gdp; + struct gendisk *gd; unsigned int unit, units, minors; int *bs; @@ -556,9 +556,8 @@ static void init_gendisk (ide_hwif_t *hwif) 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 */ @@ -2900,11 +2899,11 @@ static int init_irq (ide_hwif_t *hwif) } } /* - * 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 diff --git a/drivers/char/ftape/Makefile b/drivers/char/ftape/Makefile index 638b6c914e15..899fe200717d 100644 --- a/drivers/char/ftape/Makefile +++ b/drivers/char/ftape/Makefile @@ -54,7 +54,7 @@ FTAPE_OPT = -DVERIFY_HEADERS -DNR_BUFFERS=3 -DCLK_48MHZ=1 \ # 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 \ diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES index a1fabc9ac5b5..3848dc31e24c 100644 --- a/drivers/char/ftape/RELEASE-NOTES +++ b/drivers/char/ftape/RELEASE-NOTES @@ -1,3 +1,11 @@ +===== Release notes for ftape-2.07a, 14/03/96 ===== + +Bugfixes by Marcin Dalecki : +- 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 ===== diff --git a/drivers/char/ftape/calibr.c b/drivers/char/ftape/calibr.c index a725944d3d00..bd41bddb8436 100644 --- a/drivers/char/ftape/calibr.c +++ b/drivers/char/ftape/calibr.c @@ -20,7 +20,6 @@ * functions. */ -#include #include #include #include diff --git a/drivers/char/ftape/ecc.c b/drivers/char/ftape/ecc.c index 7f94f11229c2..5c7d86bd606a 100644 --- a/drivers/char/ftape/ecc.c +++ b/drivers/char/ftape/ecc.c @@ -32,7 +32,6 @@ * for the QIC-40/80 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/fc-10.c b/drivers/char/ftape/fc-10.c index aa8619638dac..c079aa92fb61 100644 --- a/drivers/char/ftape/fc-10.c +++ b/drivers/char/ftape/fc-10.c @@ -41,7 +41,6 @@ * This file contains code for the CMS FC-10/FC-20 card. */ -#include #include #include diff --git a/drivers/char/ftape/fdc-io.c b/drivers/char/ftape/fdc-io.c index 2194cd3e44dc..0159f8786781 100644 --- a/drivers/char/ftape/fdc-io.c +++ b/drivers/char/ftape/fdc-io.c @@ -21,7 +21,6 @@ * for the QIC-40/80 tape streamer device driver. */ -#include #include #include #include @@ -69,6 +68,8 @@ static byte fdc_precomp = 0; /* sets fdc to default precomp. value */ 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; @@ -1179,7 +1180,6 @@ int fdc_grab_irq_and_dma(void) { 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. @@ -1193,7 +1193,7 @@ int fdc_grab_irq_and_dma(void) 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); @@ -1224,7 +1224,7 @@ int fdc_release_irq_and_dma(void) 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) { diff --git a/drivers/char/ftape/fdc-isr.c b/drivers/char/ftape/fdc-isr.c index 4f2f02ba1b63..7c9056c9b5a4 100644 --- a/drivers/char/ftape/fdc-isr.c +++ b/drivers/char/ftape/fdc-isr.c @@ -26,7 +26,6 @@ * code for the QIC-40/80 tape streamer device driver. */ -#include #include #include #include diff --git a/drivers/char/ftape/ftape-bsm.c b/drivers/char/ftape/ftape-bsm.c index 57e87d78e881..6e86b065e091 100644 --- a/drivers/char/ftape/ftape-bsm.c +++ b/drivers/char/ftape/ftape-bsm.c @@ -27,7 +27,6 @@ * QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented. */ -#include #include #include diff --git a/drivers/char/ftape/ftape-ctl.c b/drivers/char/ftape/ftape-ctl.c index 07fe806f8249..d4e86ebf10d8 100644 --- a/drivers/char/ftape/ftape-ctl.c +++ b/drivers/char/ftape/ftape-ctl.c @@ -20,7 +20,6 @@ * for the QIC-40/80 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/ftape-eof.c b/drivers/char/ftape/ftape-eof.c index 5151db5f1bd4..75c4cbd7639c 100644 --- a/drivers/char/ftape/ftape-eof.c +++ b/drivers/char/ftape/ftape-eof.c @@ -27,7 +27,6 @@ * for the QIC-40/80 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/ftape-io.c b/drivers/char/ftape/ftape-io.c index feea796839b7..822a32394b2b 100644 --- a/drivers/char/ftape/ftape-io.c +++ b/drivers/char/ftape/ftape-io.c @@ -26,7 +26,6 @@ * for the QIC-40/80 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/ftape-read.c b/drivers/char/ftape/ftape-read.c index 019d52530282..51615264f4dc 100644 --- a/drivers/char/ftape/ftape-read.c +++ b/drivers/char/ftape/ftape-read.c @@ -26,7 +26,6 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/ftape-rw.c b/drivers/char/ftape/ftape-rw.c index e2d12eb2e6fe..2a539a2500e5 100644 --- a/drivers/char/ftape/ftape-rw.c +++ b/drivers/char/ftape/ftape-rw.c @@ -26,7 +26,6 @@ * write routines for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/ftape-write.c b/drivers/char/ftape/ftape-write.c index abf0170a1db1..fc8f9629bd1e 100644 --- a/drivers/char/ftape/ftape-write.c +++ b/drivers/char/ftape/ftape-write.c @@ -29,7 +29,6 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include #include diff --git a/drivers/char/ftape/kernel-interface.c b/drivers/char/ftape/kernel-interface.c index 6c1c2d914137..7f490d67a833 100644 --- a/drivers/char/ftape/kernel-interface.c +++ b/drivers/char/ftape/kernel-interface.c @@ -53,10 +53,6 @@ byte *tape_buffer[NR_BUFFERS] = {NULL}; -#ifdef MODULE -char kernel_version[] = UTS_RELEASE; -#endif - /* Local vars. */ static int busy_flag = 0; diff --git a/drivers/char/ftape/tracing.c b/drivers/char/ftape/tracing.c index be69861b6c6a..a2d1a4268fe7 100644 --- a/drivers/char/ftape/tracing.c +++ b/drivers/char/ftape/tracing.c @@ -21,7 +21,6 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include "tracing.h" diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 77c105732023..c34d28a3a31c 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -7,6 +7,7 @@ * 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 @@ -538,6 +539,10 @@ static int lp_probe(int offset) 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; @@ -559,6 +564,33 @@ static int lp_probe(int offset) 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}; diff --git a/drivers/isdn/teles/buffers.c b/drivers/isdn/teles/buffers.c index 3d571428227e..96a214ed6483 100644 --- a/drivers/isdn/teles/buffers.c +++ b/drivers/isdn/teles/buffers.c @@ -39,7 +39,7 @@ BufPoolAdd(struct BufPool *bp, int priority) 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); diff --git a/drivers/net/Config.in b/drivers/net/Config.in index afd9be8802f2..6160448c73e3 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -41,6 +41,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then 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 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 2ad25197932e..1768c3270b37 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -223,6 +223,14 @@ else 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 diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 8e7971e08cc5..f6a7c17dd91b 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -51,6 +51,7 @@ extern int eepro_probe(struct device *); 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 *); @@ -127,6 +128,9 @@ ethif_probe(struct device *dev) #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 diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index a50f8a79165a..705383dc4f51 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -1224,8 +1224,8 @@ static struct device dev_eexp[EEXP_MAX_CARDS] = 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 @@ -1261,7 +1261,7 @@ void cleanup_module(void) 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); diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c new file mode 100644 index 000000000000..4ef82e7d50af --- /dev/null +++ b/drivers/net/fmv18x.c @@ -0,0 +1,664 @@ +/* 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 + 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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); + + +/* 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; +} + + +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; +} + +/* 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 */ + +/* + * 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: + */ diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 95b1492c42fc..ca8ae6e13d01 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -45,6 +45,7 @@ dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI 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 diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index eccc0156b8c0..c7af6042fd11 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -84,6 +84,14 @@ else 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 diff --git a/drivers/scsi/README.ppa b/drivers/scsi/README.ppa new file mode 100644 index 000000000000..728d59e2c117 --- /dev/null +++ b/drivers/scsi/README.ppa @@ -0,0 +1,123 @@ +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. + diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 2a4eed3ecb43..bbf340101e2c 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -129,6 +129,10 @@ #include "AM53C974.h" #endif +#ifdef CONFIG_SCSI_PPA +#include "ppa.h" +#endif + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif @@ -233,6 +237,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #ifdef CONFIG_SCSI_AM53C974 AM53C974, #endif +#ifdef CONFIG_SCSI_PPA + PPA, +#endif #ifdef CONFIG_SCSI_DEBUG SCSI_DEBUG, #endif diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c new file mode 100644 index 000000000000..1fb59bc1a34e --- /dev/null +++ b/drivers/scsi/ppa.c @@ -0,0 +1,479 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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<= 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 */ diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h new file mode 100644 index 000000000000..9dbfe7e63c20 --- /dev/null +++ b/drivers/scsi/ppa.h @@ -0,0 +1,44 @@ +#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 */ diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 21e6749529f8..14a009dc4d11 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -2143,7 +2143,7 @@ static int st_detect(Scsi_Device * SDp) { 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); diff --git a/drivers/sound/.blurb b/drivers/sound/.blurb index 66852d4827ae..da9386a92a2c 100644 --- a/drivers/sound/.blurb +++ b/drivers/sound/.blurb @@ -1,6 +1,8 @@ ********************************************************* * 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. * diff --git a/drivers/sound/.version b/drivers/sound/.version index 5d3bc2d53b8b..8a3d0c91117f 100644 --- a/drivers/sound/.version +++ b/drivers/sound/.version @@ -1,2 +1,2 @@ -3.5-beta10 -0x030505 +3.5 +0x030500 diff --git a/drivers/sound/CHANGELOG b/drivers/sound/CHANGELOG index abfc426dede1..421c2719c575 100644 --- a/drivers/sound/CHANGELOG +++ b/drivers/sound/CHANGELOG @@ -1,7 +1,13 @@ -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. diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 50d8969cf4f2..c9d1fec52f81 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -70,7 +70,7 @@ sound.a: $(OBJS) 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 diff --git a/drivers/sound/Readme b/drivers/sound/Readme index 807177dfc653..1c65fb427ab6 100644 --- a/drivers/sound/Readme +++ b/drivers/sound/Readme @@ -1,4 +1,4 @@ -Version 3.5-beta10 release notes +Version 3.5-beta11 release notes -------------------------------- Most up to date information about this driver is available from diff --git a/drivers/sound/Readme.cards b/drivers/sound/Readme.cards index 02217f2bde70..17f58e2f2635 100644 --- a/drivers/sound/Readme.cards +++ b/drivers/sound/Readme.cards @@ -43,8 +43,8 @@ Read this before trying to configure the driver ----------------------------------------------- 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. @@ -65,16 +65,17 @@ Sound Blasters 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) @@ -88,26 +89,26 @@ MPU-401 and compatibles 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. @@ -121,9 +122,9 @@ Yamaha FM synthesizers (OPL2, OPL3 and OPL4) 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. @@ -143,7 +144,7 @@ PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC) 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. @@ -158,28 +159,30 @@ Ensoniq SoundScape and compatibles 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 ---------------------------------- @@ -310,6 +313,10 @@ select some options automaticly as well. 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 @@ -317,6 +324,7 @@ select some options automaticly as well. 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. @@ -477,11 +485,15 @@ simultaneously. Using the MSS mode provides 16 bit recording and playback. 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 @@ -773,11 +785,15 @@ SG NX Pro. Answer 'y' to these questions if you have one of the above 8 or 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 ------------ diff --git a/drivers/sound/Readme.linux b/drivers/sound/Readme.linux index a37ab3515dd4..c429d196c946 100644 --- a/drivers/sound/Readme.linux +++ b/drivers/sound/Readme.linux @@ -164,6 +164,23 @@ fi 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) # diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 1d6009bf293b..0939d8de3172 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -192,7 +192,7 @@ wait_for_calibration (ad1848_info * devc) 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) @@ -202,11 +202,33 @@ wait_for_calibration (ad1848_info * devc) 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 @@ -928,7 +950,7 @@ static int 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; @@ -952,15 +974,22 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount) 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. @@ -985,6 +1014,9 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount) } + if (devc->mode == MD_4232) + ad_write (devc, 16, tmp & ~0x30); + ad_leave_MCE (devc); /* * Starts the calibration process. */ @@ -1011,38 +1043,14 @@ static void 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 @@ -1051,16 +1059,26 @@ ad1848_halt_input (int dev) 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 */ @@ -1078,16 +1096,25 @@ ad1848_halt_output (int dev) 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 */ @@ -1503,7 +1530,7 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture 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 @@ -1592,7 +1619,7 @@ ad1848_interrupt (int irq, void *dev_id, struct pt_regs *dummy) if (irq > 15) { - printk ("ad1848.c: Bogus interrupt %d\n", irq); + /* printk ("ad1848.c: Bogus interrupt %d\n", irq); */ return; } diff --git a/drivers/sound/configure.c b/drivers/sound/configure.c index e10831eecd14..9c6ba0d45ecf 100644 --- a/drivers/sound/configure.c +++ b/drivers/sound/configure.c @@ -1,38 +1,13 @@ /* * 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 #include @@ -66,20 +41,19 @@ #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)) @@ -94,6 +68,7 @@ #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 @@ -150,15 +125,14 @@ hw_entry hw_table[] = {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[] = @@ -180,15 +154,14 @@ 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" }; @@ -248,7 +221,7 @@ char *help[] = "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" @@ -273,15 +246,12 @@ char *help[] = "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" }; @@ -300,6 +270,10 @@ extra_options[] = "AD1848", AD1848_DEVS } , + { + "SEQUENCER", SEQUENCER_DEVS + } + , { NULL, 0 } @@ -323,6 +297,21 @@ int bin2hex (char *path, char *target, char *varname); 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)) @@ -344,12 +333,12 @@ think_positively (char *prompt, int def_answ, char *help) 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) { @@ -365,13 +354,12 @@ response: */ 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; @@ -432,7 +420,7 @@ ask_int_choice (int mask, char *macro, 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] == '\'') @@ -453,7 +441,7 @@ ask_int_choice (int mask, char *macro, 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) @@ -591,18 +579,18 @@ use_old_config (char *filename) 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) @@ -690,11 +678,14 @@ use_old_config (char *filename) 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) { @@ -712,6 +703,10 @@ 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"); @@ -722,16 +717,22 @@ build_defines (void) { 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 (); @@ -764,7 +765,7 @@ ask_parameters (void) "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"); @@ -796,17 +797,21 @@ ask_parameters (void) 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", @@ -984,10 +989,10 @@ ask_parameters (void) 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"); @@ -1118,6 +1123,7 @@ ask_parameters (void) FMT_INT, 9, "5, 7, 9 or 10"); +#endif ask_int_choice (B (OPT_AUDIO), "DSP_BUFFSIZE", "Audio DMA buffer size", FMT_INT, @@ -1137,11 +1143,18 @@ dump_script (void) 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 @@ -1245,12 +1258,11 @@ main (int argc, char *argv[]) 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); } @@ -1293,31 +1305,31 @@ main (int argc, char *argv[]) } } - 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]; @@ -1331,8 +1343,8 @@ main (int argc, char *argv[]) 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 @@ -1348,31 +1360,28 @@ main (int argc, char *argv[]) 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; @@ -1381,12 +1390,12 @@ main (int argc, char *argv[]) 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; @@ -1407,8 +1416,8 @@ main (int argc, char *argv[]) { 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]; @@ -1419,9 +1428,9 @@ main (int argc, char *argv[]) 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 @@ -1446,12 +1455,12 @@ main (int argc, char *argv[]) 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]; @@ -1470,7 +1479,7 @@ main (int argc, char *argv[]) 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); } @@ -1507,13 +1516,12 @@ main (int argc, char *argv[]) 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]; diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 7f65ea82c694..bb853f1085c1 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -334,6 +334,7 @@ struct sound_timer_operations { #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}, diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 6c434807cc21..a26eb8264854 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -234,6 +234,7 @@ close_dmap (int dev, struct dma_buffparms *dmap, int chan) dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; + disable_dma (chan); sound_free_dmap (dev, dmap); } @@ -1303,35 +1304,41 @@ static void 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 @@ -1393,7 +1400,14 @@ DMAbuf_outputintr (int dev, int event_type) 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); @@ -1482,7 +1496,7 @@ DMAbuf_inputintr (int dev) 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); diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index f2b621ce40b2..87d0b7544885 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -41,6 +41,7 @@ int gus_base, gus_irq, gus_dma; extern int gus_wave_volume; extern int gus_pcm_volume; extern int have_gus_max; +int gus_pnp_flag = 0; int *gus_osp; @@ -115,6 +116,9 @@ probe_gus (struct address_info *hw_config) 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 */ @@ -125,10 +129,12 @@ probe_gus (struct address_info *hw_config) 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 diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 84fbc5c3d21b..06849f1c07d8 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -80,6 +80,7 @@ static struct voice_alloc_info *voice_alloc; 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; @@ -2991,13 +2992,14 @@ gus_wave_init (long mem_start, struct address_info *hw_config) 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; @@ -3022,14 +3024,21 @@ gus_wave_init (long mem_start, struct address_info *hw_config) 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. @@ -3103,7 +3112,11 @@ gus_wave_init (long mem_start, struct address_info *hw_config) 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 @@ -3420,7 +3433,8 @@ guswave_dma_irq (void) if (pcm_qlen == 0) flag = 1; /* Underrun */ dma_active = 0; - DMAbuf_outputintr (gus_devnum, flag); + if (gus_busy) + DMAbuf_outputintr (gus_devnum, flag); } break; diff --git a/drivers/sound/os.h b/drivers/sound/os.h index 853937f03a6f..32e81f34543f 100644 --- a/drivers/sound/os.h +++ b/drivers/sound/os.h @@ -55,3 +55,4 @@ extern int sound_num_blocks; #undef PSEUDO_DMA_AUTOINIT #define ALLOW_BUFFER_MAPPING + diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index 78e1f29bd9bc..be17a73f8d6b 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -299,6 +299,8 @@ config_pas_hw (struct address_info *hw_config) pas_write (irq_dma, EMULATION_CONFIGURATION); } + else + pas_write (0x00, COMPATIBILITY_ENABLE); } #else pas_write (0x00, COMPATIBILITY_ENABLE); diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 721720af35ab..f6c5991c62ba 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -518,6 +518,87 @@ pss_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) } 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; @@ -610,14 +691,14 @@ pss_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) 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); diff --git a/drivers/sound/sb16_dsp.c b/drivers/sound/sb16_dsp.c index d7290006788f..0106b40e261b 100644 --- a/drivers/sound/sb16_dsp.c +++ b/drivers/sound/sb16_dsp.c @@ -246,6 +246,7 @@ sb16_dsp_close (int dev) DEB (printk ("sb16_dsp_close()\n")); sb_dsp_command01 (0xd9); sb_dsp_command01 (0xd5); + sb_reset_dsp (); save_flags (flags); cli (); diff --git a/drivers/sound/sb16_midi.c b/drivers/sound/sb16_midi.c index 33ea1fa15628..547ea2c6fcc7 100644 --- a/drivers/sound/sb16_midi.c +++ b/drivers/sound/sb16_midi.c @@ -125,7 +125,6 @@ sb16midi_open (int dev, int mode, return -EBUSY; } - reset_sb16midi (); while (input_avail ()) sb16midi_read (); diff --git a/drivers/sound/sb_dsp.c b/drivers/sound/sb_dsp.c index 9113afa277df..43b4c4c964e7 100644 --- a/drivers/sound/sb_dsp.c +++ b/drivers/sound/sb_dsp.c @@ -75,6 +75,7 @@ int sb_dsp_highspeed = 0; 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; @@ -334,6 +335,8 @@ dsp_speed (int speed) unsigned long flags; int max_speed = 44100; + dsp_requested_speed = speed; + if (AudioDrive) return ess_speed (speed); @@ -447,6 +450,7 @@ dsp_set_stereo (int mode) } dsp_stereo = !!mode; + dsp_speed (dsp_requested_speed); return dsp_stereo; } @@ -473,9 +477,6 @@ actually_output_block (int dev, unsigned long buf, int nr_bytes, 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; @@ -564,9 +565,6 @@ actually_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, * 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; @@ -665,6 +663,7 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount) dsp_cleanup (); dsp_speaker (OFF); + dsp_speed (dsp_requested_speed); if (sbc_major == 3) /* * SB Pro @@ -722,7 +721,6 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount) else sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); - dsp_speed (dsp_current_speed); } /* !AudioDrive */ } trigger_bits = 0; @@ -734,6 +732,7 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount) { dsp_cleanup (); dsp_speaker (OFF); + dsp_speed (dsp_requested_speed); if (sbc_major == 3) /* SB Pro (at least ) */ { @@ -828,6 +827,9 @@ sb_dsp_open (int dev, int mode) 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"); diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index ae08a8e5a2e4..e49f4b002bdc 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -27,8 +27,8 @@ */ -#include "os.h" #include "local.h" +#include "os.h" #include "soundvers.h" #if defined(ISC) || defined(SCO) || defined(SVR42) diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index c24ce38d077f..9da8c50d0455 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -70,8 +70,8 @@ sound_read (inode_handle * inode, file_handle * file, char *buf, int 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_read_sw (dev, &files[dev], buf, count); @@ -82,8 +82,8 @@ sound_write (inode_handle * inode, file_handle * file, const char *buf, int coun { 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); @@ -107,8 +107,7 @@ sound_open (inode_handle * inode, file_handle * file) 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) { @@ -142,8 +141,7 @@ sound_release (inode_handle * inode, file_handle * file) { int dev; - dev = inode_get_rdev (inode); - dev = MINOR (dev); + dev = MINOR (inode_get_rdev (inode)); files[dev].flags = file_get_flags (file); @@ -159,8 +157,8 @@ sound_ioctl (inode_handle * inode, file_handle * 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) @@ -196,8 +194,8 @@ sound_select (inode_handle * inode, file_handle * file, int sel_type, select_tab { 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)); @@ -239,8 +237,8 @@ sound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma) 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; @@ -442,32 +440,27 @@ init_module (void) 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 @@ -499,6 +492,9 @@ snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, void *, struct pt_ void snd_release_irq (int vect) { + if (!(irqs & (1ul << vect))) + return; + irqs &= ~(1ul << vect); free_irq (vect, NULL); } @@ -651,7 +647,7 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) 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; } @@ -685,8 +681,6 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) 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); diff --git a/drivers/sound/soundvers.h b/drivers/sound/soundvers.h index d6f30766b0df..67e3554faa1a 100644 --- a/drivers/sound/soundvers.h +++ b/drivers/sound/soundvers.h @@ -1,2 +1,2 @@ -#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 diff --git a/fs/buffer.c b/fs/buffer.c index 4251b6eae42e..1b475df21b42 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -49,7 +49,6 @@ static int maybe_shrink_lav_buffers(int); 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 @@ -1327,7 +1326,7 @@ static int grow_buffers(int pri, int size) 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; @@ -1377,7 +1376,7 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp, 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; } @@ -1728,7 +1727,7 @@ static unsigned long try_to_generate_cluster(kdev_t dev, int block, int size) 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]); @@ -1797,11 +1796,6 @@ void buffer_init(void) 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; diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h index be964872bae6..2903c6db1984 100644 --- a/include/asm-alpha/pgtable.h +++ b/include/asm-alpha/pgtable.h @@ -238,29 +238,16 @@ extern inline unsigned long pgd_page(pgd_t pgd) 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; } /* @@ -328,11 +315,10 @@ extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address) /* * 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); } @@ -344,7 +330,6 @@ extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address) 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); @@ -362,7 +347,6 @@ extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address) extern inline void pmd_free_kernel(pmd_t * pmd) { - mem_map[MAP_NR(pmd)].reserved = 0; free_page((unsigned long) pmd); } @@ -374,7 +358,6 @@ extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address) 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); diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index c09ba31aa59f..158171956d6b 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -288,24 +288,12 @@ do { \ 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 @@ -315,7 +303,6 @@ extern inline void pmd_reuse(pmd_t * pmdp) { } 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) { } /* @@ -376,11 +363,10 @@ extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address) /* * 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); } @@ -392,7 +378,6 @@ extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) 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; diff --git a/include/asm-mips/dma.h b/include/asm-mips/dma.h index bae845dd4cda..826e86607951 100644 --- a/include/asm-mips/dma.h +++ b/include/asm-mips/dma.h @@ -279,7 +279,6 @@ extern void free_dma(unsigned int dmanr); /* release it again */ /* * 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 */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 59e08e34e3e3..669768503f9c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -491,7 +491,7 @@ extern struct file_operations def_chr_fops; 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; @@ -515,7 +515,6 @@ extern void set_writetime(struct buffer_head * buf, int flag); 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; diff --git a/include/linux/mm.h b/include/linux/mm.h index cdf1aa6248dd..6ff1e97b5d95 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -123,7 +123,8 @@ typedef struct page { referenced:1, locked:1, free_after:1, - unused:2, + dma:1, + unused:1, reserved:1; struct wait_queue *wait; struct page *next; @@ -135,32 +136,19 @@ typedef struct page { 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) { @@ -222,7 +210,7 @@ extern unsigned long get_unmapped_area(unsigned long, unsigned long); /* 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 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 973d460bdc51..c7ce8635664c 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -128,6 +128,7 @@ enum scsi_directory_inos { 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 */ diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h index dfdc05aa60f5..18ba26c284b6 100644 --- a/include/linux/soundcard.h +++ b/include/linux/soundcard.h @@ -57,6 +57,7 @@ #define SNDCARD_CS4232_MPU 22 #define SNDCARD_MAUI 23 #define SNDCARD_PSEUDO_MSS 24 +#define SNDCARD_GUSPNP 25 /*********************************** * IOCTL Commands for /dev/sequencer @@ -614,12 +615,13 @@ typedef struct count_info { #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) diff --git a/include/linux/swap.h b/include/linux/swap.h index d58fe447ec4b..41a1f14e5bfc 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -43,10 +43,10 @@ struct vm_area_struct; 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); @@ -97,19 +97,19 @@ extern unsigned long swap_cache_find_total; 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++; @@ -117,14 +117,14 @@ extern inline long find_in_swap_cache (unsigned long addr) 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++; diff --git a/init/main.c b/init/main.c index bb3f98f686c7..decc36c0484d 100644 --- a/init/main.c +++ b/init/main.c @@ -64,6 +64,7 @@ extern void swap_setup(char *str, int *ints); 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); @@ -82,6 +83,7 @@ extern void AM53C974_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 @@ -227,6 +229,9 @@ struct { #ifdef CONFIG_INET { "ether=", eth_setup }, #endif +#ifdef CONFIG_PRINTER + { "lp=", lp_setup }, +#endif #ifdef CONFIG_SCSI { "max_scsi_luns=", scsi_luns_setup }, #endif @@ -277,6 +282,9 @@ struct { #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 diff --git a/ipc/shm.c b/ipc/shm.c index ef25cb1b951a..90303641e5ce 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -674,7 +674,7 @@ done: /* pte_val(pte) == shp->shm_pages[idx] */ 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; @@ -711,7 +711,7 @@ int shm_swap (int prio, unsigned long limit) 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++; diff --git a/kernel/sys.c b/kernel/sys.c index 277c26813535..c9bbf1455154 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -290,7 +290,7 @@ int acct_process(long exitcode) 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)); diff --git a/mm/filemap.c b/mm/filemap.c index 87129f6e2a58..2c2f665f8886 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -109,25 +109,23 @@ repeat: } } -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 { @@ -505,7 +503,7 @@ static int filemap_write_page(struct vm_area_struct * vma, 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; diff --git a/mm/kmalloc.c b/mm/kmalloc.c index 72cd486b0569..dae0dd963715 100644 --- a/mm/kmalloc.c +++ b/mm/kmalloc.c @@ -176,7 +176,7 @@ int get_order(int size) 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; @@ -187,11 +187,9 @@ void *kmalloc(size_t size, int priority) 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; } @@ -229,7 +227,7 @@ void *kmalloc(size_t size, int priority) 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; diff --git a/mm/memory.c b/mm/memory.c index 51234e0f1ba8..82965a7ff6be 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -52,15 +52,6 @@ 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 @@ -113,6 +104,7 @@ static inline void free_one_pmd(pmd_t * dir) static inline void free_one_pgd(pgd_t * dir) { + int j; pmd_t * pmd; if (pgd_none(*dir)) @@ -124,11 +116,8 @@ static inline void free_one_pgd(pgd_t * 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); } @@ -170,7 +159,7 @@ void free_page_tables(struct task_struct * tsk) 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); } @@ -193,6 +182,7 @@ int new_page_tables(struct task_struct * tsk) 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; @@ -201,17 +191,18 @@ static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow) 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) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index e34fd7be185b..5dfe9db92afd 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -23,17 +23,47 @@ #include #include -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; } /* @@ -55,30 +85,33 @@ static inline void remove_mem_queue(struct mem_list * head, struct mem_list * en /* * 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 { @@ -92,21 +125,23 @@ static inline void check_free_buffers(unsigned long addr) 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); @@ -118,43 +153,44 @@ void free_pages(unsigned long addr, unsigned long order) /* * 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; @@ -176,12 +212,12 @@ unsigned long __get_free_pages(int priority, unsigned long order, unsigned long 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; } @@ -200,9 +236,9 @@ void show_free_areas(void) 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); @@ -246,18 +282,19 @@ unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem) 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; } @@ -293,7 +330,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, } 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; } diff --git a/mm/swap_state.c b/mm/swap_state.c index c4b1210c1fdf..9ca40ff9a7f5 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -49,7 +49,7 @@ void show_swap_cache_info(void) } #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)]; @@ -57,7 +57,7 @@ int add_to_swap_cache(unsigned long addr, unsigned long 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"); } diff --git a/mm/swapfile.c b/mm/swapfile.c index 1e20da9ebd7b..1dab57ceaad1 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -168,14 +168,14 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address, 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; } @@ -263,18 +263,18 @@ static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, 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; @@ -296,8 +296,9 @@ static int try_to_unuse(unsigned int type) 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; diff --git a/mm/vmscan.c b/mm/vmscan.c index e17476e00dc3..98d57c77cf6e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -68,7 +68,7 @@ static void init_swap_timer(void); * 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; @@ -81,16 +81,15 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc 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); @@ -119,7 +118,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc 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"); @@ -154,7 +153,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc */ 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; @@ -176,7 +175,7 @@ static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * 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; @@ -186,7 +185,7 @@ static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * } 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; @@ -206,7 +205,7 @@ static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * 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; @@ -216,7 +215,7 @@ static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * } 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; @@ -227,7 +226,7 @@ static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma, 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; @@ -236,7 +235,7 @@ static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma, 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; @@ -257,7 +256,7 @@ static int swap_out_process(struct task_struct * p, unsigned long limit, int wai 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; @@ -269,7 +268,7 @@ static int swap_out_process(struct task_struct * p, unsigned long limit, int wai 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; @@ -308,7 +307,7 @@ static int swap_out(unsigned int priority, unsigned long limit, int wait) } 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++; @@ -327,7 +326,7 @@ static int swap_out(unsigned int priority, unsigned long limit, int wait) * 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; @@ -335,15 +334,15 @@ int try_to_free_page(int priority, unsigned long limit, int wait) 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--); @@ -400,7 +399,7 @@ int kswapd(void *unused) 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); } } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ac7a6838262a..9355f21015ee 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -170,6 +170,7 @@ static void unix_delayed_delete(unix_socket *sk) static void unix_destroy_socket(unix_socket *sk) { struct sk_buff *skb; + unix_remove_socket(sk); while((skb=skb_dequeue(&sk->receive_queue))!=NULL) @@ -184,7 +185,7 @@ static void unix_destroy_socket(unix_socket *sk) } else { -/* unix_kill_credentials(skb); *//* Throw out any passed fd's */ + /* passed fds are erased where?? */ kfree_skb(skb,FREE_WRITE); } } @@ -782,7 +783,7 @@ static void unix_fd_free(struct sock *sk, struct file **fp, int num) * 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; @@ -808,13 +809,16 @@ int unix_files_free(void) 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 @@ -858,7 +862,9 @@ static void unix_detach_fds(struct sk_buff *skb, struct cmsghdr *cmsg) } 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) @@ -869,14 +875,16 @@ 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; } /* @@ -893,8 +901,10 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no 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); @@ -935,18 +945,12 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no 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; } } @@ -1001,14 +1005,14 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no 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(); @@ -1090,7 +1094,6 @@ static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int n if(msg->msg_accrights) { - printk("recvmsg with accrights\n"); cm=unix_copyrights(msg->msg_accrights, msg->msg_accrightslen); if(msg->msg_accrightslen 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; } } } -- 2.39.5