From 91cd679a976fdc0ba33a7917911d182f8828d50d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:39:38 -0500 Subject: [PATCH] Linux 2.4.0-test10-pre6 pre6 has tons of small fixes, the most noticeable of which are (a) the new compiler requirements (sorry, but it turned out that 2.7.2.3 really is too subtly broken with named structure initializers that are very heavily used these days inside the kernel) Suggested stable compiler: gcc-2.91.66, aka egcs-1.1.2, which is the one most vendors have been shipping for a long time, and while sure to be buggy too has not been found to be seriously so at least yet. Other modern gcc versions may well work too. (b) various PCI fixes that used to make 2.4.0 completely unboot/usable on certain machines (ALI chipsets with certain PIRQ routing tables and laptops with some docking bridges. Oh, and PIIX4 chipsets with USB enabled and certain other magic things going on). Let's hope that there aren't too many more of these. The ALI one in particular was "interesting" to chase down. More interesting than I personally need in my old age. The rest of the changes should be mostly unnoticeable. Still known: the same old "page->mapping = NULL" thing that has not seen an acceptable fix yet. If it wasn't for that, I'd have called this test10 already and be done with it. Super-Al to the rescue (and no, that was not a reference to the current sad state of US politics). Linus - pre6: - Jeremy Fitzhardinge: autofs4 expiry fix - David Miller: sparc driver updates, networking updates - Mathieu Chouquet-Stringer: buffer overflow in sg_proc_dressz_write - Ingo Molnar: wakeup race fix (admittedly the window was basically non-existent, but still..) - Rasmus Andersen: notice that "this_slice" is no longer used for scheduling - delete the code that calculates it. - ALI pirq routing update. It's even uglier than we initially thought.. - Dimitrios Michailidis: fix ipip locking bugs - Various: face it - gcc-2.7.2.3 miscompiles structure initializers. - Paul Cassella: locking comments on dev_base - Trond Myklebust: NFS locking atomicity. refresh inode properly. - Andre Hedrick: Serverworks Chipset driver, IDE-tape fix - Paul Gortmaker: kill unused code from 8390 support. - Andrea Arcangeli: fix nfsv3d wrong truncates over 4G - Maciej W. Rozycki: PIIX4 needs the same USB quirk handling as PIIX3. - Linus: if we cannot figure out the PCI bridge windows, just "inherit" the window from the parent. Better than not booting. - Ching-Ling Lee: ALI 5451 Audio core support update --- CREDITS | 13 +- Documentation/Changes | 36 +- Documentation/Configure.help | 23 + Documentation/pm.txt | 1 - MAINTAINERS | 4 +- README | 10 +- arch/i386/kernel/apm.c | 2 +- arch/i386/kernel/pci-irq.c | 103 ++- drivers/ide/Config.in | 2 + drivers/ide/Makefile | 1 + drivers/ide/ide-pci.c | 16 + drivers/ide/ide-proc.c | 12 + drivers/ide/ide-tape.c | 34 +- drivers/ide/osb4.c | 322 +++++++++ drivers/net/8390.h | 108 +-- drivers/net/Space.c | 19 + drivers/net/pcmcia/3c574_cs.c | 8 +- drivers/net/pcmcia/3c589_cs.c | 29 +- drivers/net/pcmcia/fmvj18x_cs.c | 83 ++- drivers/net/pcmcia/pcnet_cs.c | 45 +- drivers/net/pcmcia/xirc2ps_cs.c | 65 +- drivers/net/sunbmac.c | 16 +- drivers/net/sunhme.c | 20 +- drivers/net/sunlance.c | 13 +- drivers/net/sunqe.c | 13 +- drivers/net/tun.c | 2 +- drivers/pci/pci.c | 21 +- drivers/pci/quirks.c | 7 +- drivers/pcmcia/bulkmem.c | 5 +- drivers/pcmcia/cistpl.c | 13 +- drivers/pcmcia/cs.c | 34 +- drivers/pcmcia/cs_internal.h | 5 +- drivers/scsi/sg.c | 2 +- drivers/sound/trident.c | 1115 +++++++++++++++++++++++++------ drivers/sound/trident.h | 67 +- fs/autofs4/expire.c | 159 ++++- fs/autofs4/root.c | 19 +- fs/nfs/file.c | 4 + fs/nfs/write.c | 9 +- fs/nfsd/nfs3xdr.c | 4 +- fs/open.c | 4 +- include/asm-alpha/unaligned.h | 96 --- include/linux/auto_fs4.h | 2 +- include/linux/in.h | 1 + include/linux/init.h | 10 - include/linux/linkage.h | 2 +- include/linux/pci_ids.h | 3 + include/net/sock.h | 3 +- include/pcmcia/version.h | 6 +- init/main.c | 4 +- kernel/sched.c | 150 +++-- net/Makefile | 2 +- net/bridge/br.c | 4 +- net/core/dev.c | 19 +- net/ipv4/af_inet.c | 5 +- net/ipv4/ip_sockglue.c | 34 +- net/ipv4/ipip.c | 10 +- net/socket.c | 12 - 58 files changed, 1946 insertions(+), 885 deletions(-) create mode 100644 drivers/ide/osb4.c diff --git a/CREDITS b/CREDITS index 1e3563dc2a54..ed2d177df403 100644 --- a/CREDITS +++ b/CREDITS @@ -795,13 +795,16 @@ S: 26506 Norden S: Germany N: Jeremy Fitzhardinge -E: jeremy@zip.com.au +E: jeremy@goop.org +W: http://www.goop.org/~jeremy +D: author of userfs filesystem D: Improved mmap and munmap handling D: General mm minor tidyups -S: 67 Surrey St. -S: Darlinghurst, Sydney -S: New South Wales 2010 -S: Australia +D: autofs v4 filesystem rework +S: 987 Alabama St +S: San Francisco +S: SA, 94110 +S: USA N: Ralf Flaxa E: rfflaxa@immd4.informatik.uni-erlangen.de diff --git a/Documentation/Changes b/Documentation/Changes index 27794adb0f1d..abcb21c6479c 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -31,7 +31,7 @@ al espa Eine deutsche Version dieser Datei finden Sie unter . -Last updated: October 13, 2000 +Last updated: October 25, 2000 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -48,7 +48,7 @@ necessary on all systems; obviously, if you don't have any PCMCIA (PC Card) hardware, for example, you probably needn't concern yourself with pcmcia-cs. -o Gnu C 2.7.2.3 # gcc --version +o Gnu C 2.91.66 # gcc --version o Gnu make 3.77 # make --version o binutils 2.9.1.0.25 # ld -v o util-linux 2.10o # kbdrate -v @@ -64,13 +64,22 @@ Kernel compilation GCC --- -You will need at least gcc 2.7.2 to compile the kernel. You currently -have several options for gcc-derived compilers: gcc 2.7.2.3, various -versions of egcs, the new gcc 2.95 and upcoming gcc 3.0, and experimental -compilers like pgcc. For absolute stability, it is still recommended -that gcc 2.7.2.3 be used to compile your kernel. egcs 1.1.2 should also -work. gcc 2.95 is known to have problems, and using pgcc for your kernel -is just asking for trouble. +The gcc version requirements may vary depending on the type of CPU in your +computer. The next paragraph applies to users of x86 CPUs, but not +necessarily to users of other CPUs. Users of other CPUs should obtain +information about their gcc version requirements from another source. + +The recommended compiler for the kernel is egcs 1.1.2 (gcc 2.91.66), and it +should be used when you need absolute stability. You may use gcc 2.95.2 +instead if you wish, although it may cause problems. Later versions of gcc +have not received much testing for Linux kernel compilation, and there are +almost certainly bugs (mainly, but not exclusively, in the kernel) that +will need to be fixed in order to use these compilers. In any case, using +pgcc instead of egcs or plain gcc is just asking for trouble. + +Note that gcc 2.7.2.3 is no longer a supported kernel compiler. The kernel +no longer works around bugs in gcc 2.7.2.3 and, in fact, will refuse to +be compiled with it. In addition, please pay attention to compiler optimization. Anything greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95 @@ -85,7 +94,7 @@ You will need Gnu make 3.77 or later to build the kernel. Binutils -------- -Linux on IA/32 has recently switched from using as86 to using gas for +Linux on IA-32 has recently switched from using as86 to using gas for assembling the 16-bit boot code, removing the need for as86 to compile your kernel. This change does, however, mean that you need a recent release of binutils. @@ -245,12 +254,7 @@ Getting updated software Compilers ********* -gcc 2.7.2.3 ------------ -o -o - -egcs 1.1.2 +egcs 1.1.2 (gcc 2.91.66) --------- o o diff --git a/Documentation/Configure.help b/Documentation/Configure.help index b32d5508cbd7..cf95280ab839 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -868,6 +868,10 @@ CONFIG_BLK_DEV_OPTI621 This is a driver for the OPTi 82C621 EIDE controller. Please read the comments at the top of drivers/ide/opti621.c. +ServerWorks OSB4 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_OSB4 + This driver adds PIO/DMA support for the Serverworks OSB4 chipset + Intel PIIXn chipsets support CONFIG_BLK_DEV_PIIX This driver adds PIO mode setting and tuning for all PIIX IDE @@ -14330,6 +14334,25 @@ CONFIG_SOUND_TRIDENT for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018. PCI ID 10B9:5451 stands for ALi5451. + This driver supports S/PDIF in/out (record/playback) for ALi 5451 + embedded in ALi M1535+ and M1535D+. Note that they aren't all + enabled by default; you can enable them by saying Y to "/proc file + system support" and "Sysctl support", and after the /proc file + system has been mounted, executing the command + + command what is enabled + + echo 0>/proc/ALi5451 pcm out is also set to S/PDIF out. (Default). + + echo 1>/proc/ALi5451 use S/PDIF out to output pcm data. + + echo 2>/proc/ALi5451 use S/PDIF out to output non-pcm data.(AC3...). + + echo 3>/proc/ALi5451 record from Ac97 in(MIC, Line in...). (Default). + + echo 4>/proc/ALi5451 no matter Ac97 settings, record from S/PDIF in. + + This driver differs slightly from OSS/Free, so PLEASE READ the comments at the top of driver/sound/trident.c diff --git a/Documentation/pm.txt b/Documentation/pm.txt index 1e78926cd017..205f9666f865 100644 --- a/Documentation/pm.txt +++ b/Documentation/pm.txt @@ -261,7 +261,6 @@ Q: Who do I contact for additional information about enabling power management for my specific driver/device? ACPI4Linux mailing list: acpi@phobos.fs.tum.de -Linux ACPI maintainer: andy_henroid@yahoo.com System Interface ---------------- diff --git a/MAINTAINERS b/MAINTAINERS index 0e61213e5ca4..e005128b7438 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -101,8 +101,8 @@ L: linux-net@vger.kernel.org S: Maintained ACPI -P: Andrew Henroid -M: andy_henroid@yahoo.com +P: Andy Grover +M: andrew.grover@intel.com L: acpi@phobos.fs.tum.de W: http://phobos.fs.tum.de/acpi/index.html S: Maintained diff --git a/README b/README index fa9492f80d01..2ccf7190ba32 100644 --- a/README +++ b/README @@ -161,12 +161,10 @@ CONFIGURING the kernel: COMPILING the kernel: - - Make sure you have gcc-2.7.2 or newer available. It seems older gcc - versions can have problems compiling newer versions of Linux. This - is mainly because the older compilers can only generate "a.out"-format - executables. As of Linux 2.1.0, the kernel must be compiled as an - "ELF" binary. If you upgrade your compiler, remember to get the new - binutils package too (for as/ld/nm and company). + - Make sure you have gcc-2.91.66 (egcs-1.1.2) available. gcc 2.95.2 may + also work but is not as safe, and *gcc 2.7.2.3 is no longer supported*. + Also remember to upgrade your binutils package (for as/ld/nm and company) + if necessary. For more information, refer to ./Documentation/Changes. Please note that you can still run a.out user programs with this kernel. diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 9a4084292277..b0aa2a7c3e7f 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1427,7 +1427,7 @@ static int apm(void *unused) atomic_inc(¤t->files->count); daemonize(); - strcpy(current->comm, "kapmd"); + strcpy(current->comm, "kapm-idled"); sigfillset(¤t->blocked); current->tty = NULL; /* get rid of controlling tty */ diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c index b98bf47489d4..c93b22382c22 100644 --- a/arch/i386/kernel/pci-irq.c +++ b/arch/i386/kernel/pci-irq.c @@ -125,35 +125,87 @@ static void eisa_set_level_irq(unsigned int irq) } } +/* + * Common IRQ routing practice: nybbles in config space, + * offset by some magic constant. + */ +static unsigned int read_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr) +{ + u8 x; + unsigned reg = offset + (nr >> 1); + + pci_read_config_byte(router, reg, &x); + return (nr & 1) ? (x >> 4) : (x & 0xf); +} + +static void write_config_nybble(struct pci_dev *router, unsigned offset, unsigned nr, unsigned int val) +{ + u8 x; + unsigned reg = offset + (nr >> 1); + + pci_read_config_byte(router, reg, &x); + x = (nr & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val); + pci_write_config_byte(router, reg, x); +} + +/* + * ALI pirq entries are damn ugly, and completely undocumented. + * This has been figured out from pirq tables, and it's not a pretty + * picture. + */ static int pirq_ali_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { static unsigned char irqmap[16] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; + + switch (pirq) { + case 0x00: + return 0; + default: + return irqmap[read_config_nybble(router, 0x48, pirq-1)]; + case 0xfe: + return irqmap[read_config_nybble(router, 0x44, 0)]; + case 0xff: + return irqmap[read_config_nybble(router, 0x75, 0)]; + } +} + +static void pirq_ali_ide_interrupt(struct pci_dev *router, unsigned reg, unsigned val, unsigned irq) +{ u8 x; - unsigned reg; - pirq--; - reg = 0x48 + (pirq >> 1); pci_read_config_byte(router, reg, &x); - return irqmap[(pirq & 1) ? (x >> 4) : (x & 0x0f)]; + x = (x & 0xe0) | val; /* clear the level->edge transform */ + pci_write_config_byte(router, reg, x); + eisa_set_level_irq(irq); } static int pirq_ali_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { static unsigned char irqmap[16] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; unsigned int val = irqmap[irq]; - pirq--; + if (val) { - u8 x; - unsigned reg = 0x48 + (pirq >> 1); - pci_read_config_byte(router, reg, &x); - x = (pirq & 1) ? ((x & 0x0f) | (val << 4)) : ((x & 0xf0) | val); - pci_write_config_byte(router, reg, x); + switch (pirq) { + default: + write_config_nybble(router, 0x48, pirq-1, val); + break; + case 0xfe: + pirq_ali_ide_interrupt(router, 0x44, val, irq); + break; + case 0xff: + pirq_ali_ide_interrupt(router, 0x75, val, irq); + break; + } eisa_set_level_irq(irq); return 1; } return 0; } +/* + * The Intel PIIX4 pirq rules are very sane, compared to + * the ALI ones (or anything else, for that matter). + */ static int pirq_piix_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { u8 x; @@ -167,39 +219,34 @@ static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, return 1; } +/* + * The VIA pirq rules are nibble-based, like ALI, + * but without the ugly irq number munging or the + * strange special cases.. + */ static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - u8 x; - int reg = 0x55 + (pirq >> 1); - pci_read_config_byte(router, reg, &x); - return (pirq & 1) ? (x >> 4) : (x & 0x0f); + return read_config_nybble(router, 0x55, pirq); } static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - u8 x; - int reg = 0x55 + (pirq >> 1); - pci_read_config_byte(router, reg, &x); - x = (pirq & 1) ? ((x & 0x0f) | (irq << 4)) : ((x & 0xf0) | irq); - pci_write_config_byte(router, reg, x); + write_config_nybble(router, 0x55, pirq, irq); return 1; } +/* + * OPTI: high four bits are nibble pointer.. + * I wonder what the low bits do? + */ static int pirq_opti_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - u8 x; - int reg = 0xb8 + (pirq >> 5); - pci_read_config_byte(router, reg, &x); - return (pirq & 0x10) ? (x >> 4) : (x & 0x0f); + return read_config_nybble(router, 0xb8, pirq >> 4); } static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - u8 x; - int reg = 0xb8 + (pirq >> 5); - pci_read_config_byte(router, reg, &x); - x = (pirq & 0x10) ? ((x & 0x0f) | (irq << 4)) : ((x & 0xf0) | irq); - pci_write_config_byte(router, reg, x); + write_config_nybble(router, 0xb8, pirq >> 4, irq); return 1; } diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in index 2c71d637f6f7..4db04ef96226 100644 --- a/drivers/ide/Config.in +++ b/drivers/ide/Config.in @@ -68,6 +68,7 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL dep_bool ' PROMISE PDC20246/PDC20262/PDC20267 support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX + dep_bool ' ServerWorks OSB4 chipset support' CONFIG_BLK_DEV_OSB4 $CONFIG_BLK_DEV_OSB4 dep_bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI @@ -155,6 +156,7 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_HPT366" = "y" -o \ "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \ "$CONFIG_BLK_DEV_OPTI621" = "y" -o \ + "$CONFIG_BLK_DEV_OSB4" = "y" -o \ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index c4603e734e21..d5b4b637e7e3 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -43,6 +43,7 @@ ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC) += ide-pmac.o ide-obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o ide-obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o ide-obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o +ide-obj-$(CONFIG_BLK_DEV_OSB4) += osb4.o ide-obj-$(CONFIG_BLK_DEV_PDC202XX) += pdc202xx.o ide-obj-$(CONFIG_BLK_DEV_PDC4030) += pdc4030.o ide-obj-$(CONFIG_BLK_DEV_PIIX) += piix.o diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c index 3367d5c1fc0d..f1304a4a0619 100644 --- a/drivers/ide/ide-pci.c +++ b/drivers/ide/ide-pci.c @@ -73,6 +73,7 @@ #define DEVID_AMD7403 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7403}) #define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) #define DEVID_SLC90E66 ((ide_pci_devid_t){PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1}) +#define DEVID_OSB4 ((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE}) #define IDE_IGNORE ((void *)-1) @@ -206,6 +207,19 @@ extern void ide_init_opti621(ide_hwif_t *); #define INIT_OPTI621 NULL #endif +#ifdef CONFIG_BLK_DEV_OSB4 +extern unsigned int pci_init_osb4(struct pci_dev *, const char *); +extern unsigned int ata66_osb4(ide_hwif_t *); +extern void ide_init_osb4(ide_hwif_t *); +#define PCI_OSB4 &pci_init_osb4 +#define ATA66_OSB4 &ata66_osb4 +#define INIT_OSB4 &ide_init_osb4 +#else +#define PCI_OSB4 NULL +#define ATA66_OSB4 NULL +#define INIT_OSB4 NULL +#endif + #ifdef CONFIG_BLK_DEV_PDC202XX extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *); extern unsigned int ata66_pdc202xx(ide_hwif_t *); @@ -366,6 +380,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_AMD7403, "AMD7403", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {DEVID_SLC90E66,"SLC90E66", PCI_SLC90E66, ATA66_SLC90E66, INIT_SLC90E66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_OSB4, "ServerWorks OSB4", PCI_OSB4, ATA66_OSB4, INIT_OSB4, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* @@ -669,6 +684,7 @@ check_if_enabled: IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index f0bf8b3b22bb..56e8a959338a 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -101,6 +101,10 @@ int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL; extern byte hpt366_proc; int (*hpt366_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_OSB4 +extern byte osb4_proc; +int (*osb4_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_OSB4 */ #ifdef CONFIG_BLK_DEV_PDC202XX extern byte pdc202xx_proc; int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL; @@ -833,6 +837,10 @@ void proc_ide_create(void) if ((hpt366_display_info) && (hpt366_proc)) create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info); #endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_OSB4 + if ((osb4_display_info) && (osb4_proc)) + create_proc_info_entry("osb4", 0, proc_ide_root, osb4_display_info); +#endif /* CONFIG_BLK_DEV_OSB4 */ #ifdef CONFIG_BLK_DEV_PDC202XX if ((pdc202xx_display_info) && (pdc202xx_proc)) create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info); @@ -889,6 +897,10 @@ void proc_ide_destroy(void) if ((hpt366_display_info) && (hpt366_proc)) remove_proc_entry("ide/hpt366",0); #endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_OSB4 + if ((osb4_display_info) && (osb4_proc)) + remove_proc_entry("ide/osb4",0); +#endif /* CONFIG_BLK_DEV_OSB4 */ #ifdef CONFIG_BLK_DEV_PDC202XX if ((pdc202xx_display_info) && (pdc202xx_proc)) remove_proc_entry("ide/pdc202xx",0); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index f36dbd8ff5d4..079353425bda 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -3126,8 +3126,11 @@ static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc idetape_init_pc (pc); pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD; pc->c[4] = cmd; - if (tape->onstream) + if (tape->onstream) { pc->c[1] = 1; + if (cmd == !IDETAPE_LU_LOAD_MASK) + pc->c[4] = 4; + } set_bit (PC_WAIT_FOR_DSC, &pc->flags); pc->callback = &idetape_pc_callback; } @@ -3239,12 +3242,18 @@ static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, uns pc->callback = &idetape_pc_callback; } -static void idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent) +static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent) { + idetape_tape_t *tape = drive->driver_data; + + if (!tape->capabilities.lock) + return 0; + idetape_init_pc(pc); pc->c[0] = IDETAPE_PREVENT_CMD; pc->c[4] = prevent; pc->callback = &idetape_pc_callback; + return 1; } static int __idetape_discard_read_pipeline (ide_drive_t *drive) @@ -5017,13 +5026,15 @@ static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count) } } case MTLOCK: - idetape_create_prevent_cmd(drive, &pc, 1); + if (!idetape_create_prevent_cmd(drive, &pc, 1)) + return 0; retval = idetape_queue_pc_tail (drive,&pc); if (retval) return retval; tape->door_locked = DOOR_EXPLICITLY_LOCKED; return 0; case MTUNLOCK: - idetape_create_prevent_cmd(drive, &pc, 0); + if (!idetape_create_prevent_cmd(drive, &pc, 0)) + return 0; retval = idetape_queue_pc_tail (drive,&pc); if (retval) return retval; tape->door_locked = DOOR_UNLOCKED; @@ -5262,10 +5273,11 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); if (tape->chrdev_direction == idetape_direction_none) { - idetape_create_prevent_cmd(drive, &pc, 1); - if (!idetape_queue_pc_tail (drive,&pc)) { - if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) - tape->door_locked = DOOR_LOCKED; + if (idetape_create_prevent_cmd(drive, &pc, 1)) { + if (!idetape_queue_pc_tail (drive,&pc)) { + if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) + tape->door_locked = DOOR_LOCKED; + } } idetape_analyze_headers(drive); } @@ -5320,9 +5332,9 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) (void) idetape_rewind_tape (drive); if (tape->chrdev_direction == idetape_direction_none) { if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) { - idetape_create_prevent_cmd(drive, &pc, 0); - if (!idetape_queue_pc_tail (drive,&pc)) - tape->door_locked = DOOR_UNLOCKED; + if (idetape_create_prevent_cmd(drive, &pc, 0)) + if (!idetape_queue_pc_tail (drive,&pc)) + tape->door_locked = DOOR_UNLOCKED; } } clear_bit (IDETAPE_BUSY, &tape->flags); diff --git a/drivers/ide/osb4.c b/drivers/ide/osb4.c new file mode 100644 index 000000000000..85b6cda9d9a3 --- /dev/null +++ b/drivers/ide/osb4.c @@ -0,0 +1,322 @@ +/* + * linux/drivers/block/osb4.c Version 0.2 17 Oct 2000 + * + * Copyright (C) 2000 Cobalt Networks, Inc. + * May be copied or modified under the terms of the GNU General Public License + * + * interface borrowed from alim15x3.c: + * Copyright (C) 1998-2000 Michel Aubry, Maintainer + * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer + * + * Copyright (C) 1998-2000 Andre Hedrick + * + * IDE support for the ServerWorks OSB4 IDE chipset + * + * here's the default lspci: + * + * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP]) + * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- + * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- SERR- +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" + +#define OSB4_DEBUG_DRIVE_INFO 0 + +#define DISPLAY_OSB4_TIMINGS + +#if defined(DISPLAY_OSB4_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static byte osb4_revision = 0; +static struct pci_dev *bmide_dev; + +static int osb4_get_info(char *, char **, off_t, int, int); +extern int (*osb4_display_info)(char *, char **, off_t, int, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); + +static int osb4_get_info (char *buffer, char **addr, off_t offset, int count, int dummy) +{ + char *p = buffer; + u32 bibma = pci_resource_start(bmide_dev, 4); + u16 reg56; + u8 c0 = 0, c1 = 0, reg54; + + pci_read_config_byte(bmide_dev, 0x54, ®54); + pci_read_config_word(bmide_dev, 0x56, ®56); + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n ServerWorks OSB4 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", + (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", + (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + (reg54 & 0x01) ? "yes" : "no ", + (reg54 & 0x02) ? "yes" : "no ", + (reg54 & 0x04) ? "yes" : "no ", + (reg54 & 0x08) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + (reg56 & 0x0002) ? "2" : ((reg56 & 0x0001) ? "1" : + ((reg56 & 0x000f) ? "X" : "0")), + (reg56 & 0x0020) ? "2" : ((reg56 & 0x0010) ? "1" : + ((reg56 & 0x00f0) ? "X" : "0")), + (reg56 & 0x0200) ? "2" : ((reg56 & 0x0100) ? "1" : + ((reg56 & 0x0f00) ? "X" : "0")), + (reg56 & 0x2000) ? "2" : ((reg56 & 0x1000) ? "1" : + ((reg56 & 0xf000) ? "X" : "0"))); + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_OSB4_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte osb4_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); + +static void osb4_tune_drive (ide_drive_t *drive, byte pio) +{ + /* command/recover widths */ + byte timings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; + int port = HWIF(drive)->index ? 0x42 : 0x40; + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + if (&HWIF(drive)->drives[0] == drive) /* master drive */ + port++; + pci_write_config_byte(HWIF(drive)->pci_dev, port, timings[pio]); +} + +#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_BLK_DEV_OSB4) +static int osb4_tune_chipset (ide_drive_t *drive, byte speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte is_slave = (&HWIF(drive)->drives[1] == drive) ? 1 : 0; + byte bit8, enable; + int err; + + /* clear udma register if we don't want udma */ + if (speed < XFER_UDMA_0) { + enable = 0x1 << (is_slave + (hwif->channel ? 2 : 0)); + pci_read_config_byte(dev, 0x54, &bit8); + pci_write_config_byte(dev, 0x54, bit8 & ~enable); + } + +#ifdef CONFIG_BLK_DEV_IDEDMA + if (speed >= XFER_MW_DMA_0) { + byte channel = hwif->channel ? 0x46 : 0x44; + if (!is_slave) + channel++; + + switch (speed) { + case XFER_MW_DMA_0: + bit8 = 0x77; + break; + case XFER_MW_DMA_1: + bit8 = 0x21; + break; + case XFER_MW_DMA_2: + default: + bit8 = 0x20; + break; + } + pci_write_config_byte(dev, channel, bit8); + } + + if (speed >= XFER_UDMA_0) { + byte channel = hwif->channel ? 0x57 : 0x56; + int slave = is_slave ? 4 : 0; + + pci_read_config_byte(dev, channel, &bit8); + bit8 &= ~(0xf << slave); + switch (speed) { + case XFER_UDMA_0: + break; + case XFER_UDMA_1: + bit8 |= 0x1 << slave; + break; + case XFER_UDMA_2: + default: + bit8 |= 0x2 << slave; + break; + } + pci_write_config_byte(dev, channel, bit8); + + enable = 0x1 << (is_slave + (hwif->channel ? 2 : 0)); + pci_read_config_byte(dev, 0x54, &bit8); + pci_write_config_byte(dev, 0x54, bit8 | enable); + } +#endif + +#if OSB4_DEBUG_DRIVE_INFO + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); +#endif /* OSB4_DEBUG_DRIVE_INFO */ + if (!drive->init_speed) + drive->init_speed = speed; + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; + return err; +} + +static int osb4_config_drive_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + byte speed; + + byte udma_66 = eighty_ninty_three(drive); + /* need specs to figure out if osb4 is capable of ata/66/100 */ + int ultra100 = 0; + int ultra66 = 0; + int ultra = 1; + + if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) { + speed = XFER_UDMA_5; + } else if ((id->dma_ultra & 0x0010) && (ultra)) { + speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0008) && (ultra)) { + speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else { + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + } + + (void) osb4_tune_chipset(drive, speed); + + return ((int) ((id->dma_ultra >> 11) & 7) ? ide_dma_on : + ((id->dma_ultra >> 8) & 7) ? ide_dma_on : + ((id->dma_mword >> 8) & 7) ? ide_dma_on : + ((id->dma_1word >> 8) & 7) ? ide_dma_on : + ide_dma_off_quietly); +} + +static int osb4_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return ide_dmaproc((ide_dma_action_t) osb4_config_drive_for_dma(drive), drive); + default : + break; + } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); +} +#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_BLK_DEV_OSB4) */ + +unsigned int __init pci_init_osb4 (struct pci_dev *dev, const char *name) +{ + u16 word; + byte bit8; + + pci_read_config_byte(dev, PCI_REVISION_ID, &osb4_revision); + + /* setup command register. just make sure that bus master and + * i/o ports are on. */ + pci_read_config_word(dev, PCI_COMMAND, &word); + if ((word & (PCI_COMMAND_MASTER | PCI_COMMAND_IO)) != + (PCI_COMMAND_MASTER | PCI_COMMAND_IO)) + pci_write_config_word(dev, PCI_COMMAND, word | + PCI_COMMAND_MASTER | PCI_COMMAND_IO); + + /* make sure that we're in pci native mode for both the primary + * and secondary channel. */ + pci_read_config_byte(dev, PCI_CLASS_PROG, &bit8); + if ((bit8 & 0x5) != 0x5) + pci_write_config_byte(dev, PCI_CLASS_PROG, bit8 | 0x5); + + /* setup up our latency. the default is 255 which is a bit large. + * set it to 64 instead. */ + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &bit8); + if (bit8 != 0x40) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); + +#if defined(DISPLAY_OSB4_TIMINGS) && defined(CONFIG_PROC_FS) + if (!osb4_proc) { + osb4_proc = 1; + bmide_dev = dev; + osb4_display_info = &osb4_get_info; + } +#endif /* DISPLAY_OSB4_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + +unsigned int __init ata66_osb4 (ide_hwif_t *hwif) +{ + return 0; +} + +void __init ide_init_osb4 (ide_hwif_t *hwif) +{ + if (!hwif->irq) + hwif->irq = hwif->channel ? 15 : 14; + + hwif->tuneproc = &osb4_tune_drive; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + +#ifndef CONFIG_BLK_DEV_IDEDMA + hwif->autodma = 0; +#else /* CONFIG_BLK_DEV_IDEDMA */ +#ifdef CONFIG_BLK_DEV_OSB4 + hwif->autodma = 1; + hwif->dmaproc = &osb4_dmaproc; + hwif->speedproc = &osb4_tune_chipset; +#endif /* CONFIG_BLK_DEV_OSB4 */ +#endif /* !CONFIG_BLK_DEV_IDEDMA */ +} diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 6c8a68ecc8f1..9db9fdb3ca0e 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -1,6 +1,6 @@ /* Generic NS8390 register definitions. */ /* This file is part of Donald Becker's 8390 drivers, and is distributed - under the same license. Auto-loading of 8390.o added by Paul Gortmaker. + under the same license. Auto-loading of 8390.o only in v2.2 - Paul G. Some of these names and comments originated from the Crynwr packet drivers, which are distributed under the GPL. */ @@ -12,11 +12,6 @@ #include #include -/* With kmod, drivers can now load the 8390 module themselves! */ -#if 0 /* def CONFIG_KMOD */ -#define LOAD_8390_BY_KMOD -#endif - #define TX_2X_PAGES 12 #define TX_1X_PAGES 6 @@ -50,113 +45,16 @@ extern void autoirq_setup(int waittime); extern unsigned long autoirq_report(int waittime); #endif -#if defined(LOAD_8390_BY_KMOD) && defined(MODULE) && !defined(NS8390_CORE) - -/* Function pointers to be mapped onto the 8390 core support */ -static int (*S_ethdev_init)(struct net_device *dev); -static void (*S_NS8390_init)(struct net_device *dev, int startp); -static int (*S_ei_open)(struct net_device *dev); -static int (*S_ei_close)(struct net_device *dev); -static void (*S_ei_interrupt)(int irq, void *dev_id, struct pt_regs *regs); - -extern __inline__ void unload_8390_module(void) -{ - if (S_ethdev_init) { - put_module_symbol((unsigned long)S_ethdev_init); - S_ethdev_init = NULL; - } - if (S_NS8390_init) { - put_module_symbol((unsigned long)S_NS8390_init); - S_NS8390_init = NULL; - } - if (S_ei_open) { - put_module_symbol((unsigned long)S_ei_open); - S_ei_open = NULL; - } - if (S_ei_close) { - put_module_symbol((unsigned long)S_ei_close); - S_ei_close = NULL; - } - if (S_ei_interrupt) { - put_module_symbol((unsigned long)S_ei_interrupt); - S_ei_interrupt = NULL; - } -} - -extern __inline__ int load_8390_module(const char *driver) -{ - /* Do we actually need to handle this case? */ - if (S_ethdev_init) { - printk(KERN_DEBUG "%s: load_8390_module called when pointers already present\n", driver); - return 0; - } - - /* Attempt to get the first symbol */ - S_ethdev_init = (void *)get_module_symbol(NULL, "ethdev_init"); - - if (!S_ethdev_init) { - /* It failed. See if we have request_module() */ - int (*request_mod)(const char *module_name); - - if (get_module_symbol("", "request_module") == 0) { - printk("%s: module auto-load (kmod) support not present.\n", driver); - printk("%s: unable to auto-load required 8390 module.\n", driver); - printk("%s: try \"modprobe 8390\" as root 1st.\n", driver); - return -ENOSYS; - } - - /* OK - we have request_module() - try it */ - request_mod = (void*)get_module_symbol("", "request_module"); - if (request_mod("8390")) { - printk("%s: request to load the 8390 module failed.\n", driver); - return -ENOSYS; - } - - printk(KERN_INFO "%s: auto-loaded 8390 module.\n", driver); - - /* Retry getting ethdev_init */ - S_ethdev_init = (void *)get_module_symbol(NULL, "ethdev_init"); - } - - /* Get addresses for the other functions */ - S_NS8390_init = (void*)get_module_symbol(0, "NS8390_init"); - S_ei_open = (void*)get_module_symbol(0, "ei_open"); - S_ei_close = (void*)get_module_symbol(0, "ei_close"); - S_ei_interrupt = (void*)get_module_symbol(0, "ei_interrupt"); - - /* Check if module really loaded and is valid */ - if (!S_ethdev_init || !S_NS8390_init || !S_ei_open || !S_ei_close - || !S_ei_interrupt) { - unload_8390_module(); - printk("%s: 8390.o not found/invalid or failed to load.\n", driver); - return -ENOSYS; -} - - return 0; -} - -/* - * These are last so they only have scope over the driver - * code (wd, ne, 3c503, etc.) and not over the above code. - */ -#define ethdev_init S_ethdev_init -#define NS8390_init S_NS8390_init -#define ei_open S_ei_open -#define ei_close S_ei_close -#define ei_interrupt S_ei_interrupt - -#else /* not a module or kmod support not wanted */ - +/* Currently unused - delete in v2.5.x after purging from drivers */ #define load_8390_module(driver) 0 #define unload_8390_module() do { } while (0) + extern int ethdev_init(struct net_device *dev); extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs); -#endif - /* Most of these entries should be in 'struct net_device' (or most of the things in there should be here!) */ /* You have one of these per-board */ diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 9637bb28cd06..36d7fe9627d5 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -702,6 +702,25 @@ extern int loopback_init(struct net_device *dev); struct net_device loopback_dev = {"lo", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, loopback_init}; +/* + * The @dev_base list is protected by @dev_base_lock and the rtln + * semaphore. + * + * Pure readers hold dev_base_lock for reading. + * + * Writers must hold the rtnl semaphore while they loop through the + * dev_base list, and hold dev_base_lock for writing when they do the + * actual updates. This allows pure readers to access the list even + * while a writer is preparing to update it. + * + * To put it another way, dev_base_lock is held for writing only to + * protect against pure readers; the rtnl semaphore provides the + * protection against other writers. + * + * See, for example usages, register_netdevice() and + * unregister_netdevice(), which must be called with the rtnl + * semaphore held. + */ struct net_device *dev_base = &loopback_dev; rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 1fd7d3445fd9..a5b83887adef 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -511,11 +511,11 @@ static void tc574_config(dev_link_t *link) /* Roadrunner only: Turn on the MII transceiver */ outw(0x8040, ioaddr + Wn3_Options); - udelay(1000); + mdelay(1); outw(0xc040, ioaddr + Wn3_Options); wait_for_completion(dev, TxReset); wait_for_completion(dev, RxReset); - udelay(1000); + mdelay(1); outw(0x8040, ioaddr + Wn3_Options); EL3WINDOW(4); @@ -783,11 +783,11 @@ static void tc574_reset(struct net_device *dev) /* Roadrunner only: Turn on the MII transceiver. */ outw(0x8040, ioaddr + Wn3_Options); - udelay(1000); + mdelay(1); outw(0xc040, ioaddr + Wn3_Options); wait_for_completion(dev, TxReset); wait_for_completion(dev, RxReset); - udelay(1000); + mdelay(1); outw(0x8040, ioaddr + Wn3_Options); /* Switch to the stats window, and clear all stats by reading. */ diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 3cbba20b9050..7ba0c4e18199 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -4,7 +4,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - 3c589_cs.c 1.153 2000/06/12 21:27:25 + 3c589_cs.c 1.154 2000/09/30 17:39:04 The network driver code is based on Donald Becker's 3c589 code: @@ -117,7 +117,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.153 2000/06/12 21:27:25 (David Hinds)"; +"3c589_cs.c 1.154 2000/09/30 17:39:04 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -1007,36 +1007,19 @@ static int el3_rx(struct net_device *dev) return 0; } -/* Set or clear the multicast filter for this adapter. - 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 net_device *dev) { struct el3_private *lp = dev->priv; dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; + u_short opts = SetRxFilter | RxStation | RxBroadcast; if (!(DEV_OK(link))) return; -#ifdef PCMCIA_DEBUG - if (pc_debug > 2) { - static int old = 0; - if (old != dev->mc_count) { - old = dev->mc_count; - DEBUG(0, "%s: setting Rx mode to %d addresses.\n", - dev->name, old); - } - } -#endif if (dev->flags & IFF_PROMISC) - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, - ioaddr + EL3_CMD); + opts |= RxMulticast | RxProm; else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) - outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + opts |= RxMulticast; + outw(opts, ioaddr + EL3_CMD); } static int el3_close(struct net_device *dev) diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 8be4b7a62c31..8bb6d0a04a77 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -1,5 +1,5 @@ /*====================================================================== - fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp + fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp A fmvj18x (and its compatibles) PCMCIA client driver @@ -88,7 +88,7 @@ MODULE_PARM(sram_config, "i"); */ #ifdef PCMCIA_DEBUG static char *version = - "fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp"; + "fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp"; #endif /*====================================================================*/ @@ -122,7 +122,9 @@ static dev_link_t *dev_list = NULL; /* card type */ -typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501 } cardtype_t; +typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN } cardtype_t; + +#define MANFID_UNGERMANN 0x02c0 /* driver specific data structure @@ -169,6 +171,7 @@ typedef struct local_info_t { #define LAN_CTRL 16 /* LAN card control register */ #define MAC_ID 0x1a /* hardware address */ +#define UNGERMANN_MAC_ID 0x18 /* UNGERMANN-BASS hardware address */ /* control bits @@ -237,6 +240,10 @@ typedef struct local_info_t { #define TX_TIMEOUT ((400*HZ)/1000) +#define BANK_0U 0x20 /* bank 0 (CONFIG_1) */ +#define BANK_1U 0x24 /* bank 1 (CONFIG_1) */ +#define BANK_2U 0x28 /* bank 2 (CONFIG_1) */ + /*====================================================================== This bit of code is used to avoid unregistering network devices @@ -388,7 +395,7 @@ static void fmvj18x_config(dev_link_t *link) tuple_t tuple; cisparse_t parse; u_short buf[32]; - int i, last_fn, last_ret; + int i, last_fn, last_ret, ret; ioaddr_t ioaddr; cardtype_t cardtype; char *card_name = "unknown"; @@ -424,9 +431,10 @@ static void fmvj18x_config(dev_link_t *link) CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigIndex = parse.cftable_entry.index; tuple.DesiredTuple = CISTPL_MANFID; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - + if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) + CS_CHECK(GetTupleData, handle, &tuple); + else + buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { case MANFID_TDK: cardtype = TDK; @@ -447,10 +455,39 @@ static void fmvj18x_config(dev_link_t *link) } } else { /* old type card */ - cardtype = MBH10302; - link->conf.ConfigIndex = 1; + tuple.DesiredTuple = CISTPL_MANFID; + if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) + CS_CHECK(GetTupleData, handle, &tuple); + else + buf[0] = 0xffff; + switch (le16_to_cpu(buf[0])) { + case MANFID_UNGERMANN: + cardtype = UNGERMANN; + /* + Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360 + 0x380,0x3c0 only for ioport. + */ + for (link->io.BasePort1 = 0x300; link->io.BasePort1 < 0x3e0; + link->io.BasePort1 += 0x20) { + ret = CardServices(RequestIO, link->handle, &link->io); + if (ret == CS_SUCCESS) { + /* calculate ConfigIndex value */ + link->conf.ConfigIndex = + ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22; + goto req_irq; + } + } + /* if ioport allocation is failed, goto failed */ + printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); + goto failed; + default: + cardtype = MBH10302; + link->conf.ConfigIndex = 1; + } } + CS_CHECK(RequestIO, link->handle, &link->io); +req_irq: CS_CHECK(RequestIRQ, link->handle, &link->irq); CS_CHECK(RequestConfiguration, link->handle, &link->conf); dev->irq = link->irq.AssignedIRQ; @@ -463,7 +500,11 @@ static void fmvj18x_config(dev_link_t *link) ioaddr = dev->base_addr; /* Power On chip and select bank 0 */ - outb(BANK_0, ioaddr + CONFIG_1); + if(cardtype == UNGERMANN) + outb(BANK_0U, ioaddr + CONFIG_1); + else + outb(BANK_0, ioaddr + CONFIG_1); + /* Reset controler */ if( sram_config == 0 ) outb(CONFIG0_RST, ioaddr + CONFIG_0); @@ -503,6 +544,12 @@ static void fmvj18x_config(dev_link_t *link) for (i = 0; i < 6; i++) dev->dev_addr[i] = node_id[i]; break; + case UNGERMANN: + /* Read MACID from register */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i); + card_name = "Access/CARD"; + break; case MBH10302: default: /* Read MACID from register */ @@ -806,7 +853,11 @@ static void fjn_reset(struct net_device *dev) DEBUG(4, "fjn_reset(%s) called.\n",dev->name); /* Power On chip and select bank 0 */ - outb(BANK_0, ioaddr + CONFIG_1); + if( lp->cardtype == UNGERMANN) + outb(BANK_0U, ioaddr + CONFIG_1); + else + outb(BANK_0, ioaddr + CONFIG_1); + /* Reset buffers */ if( sram_config == 0 ) outb(CONFIG0_RST, ioaddr + CONFIG_0); @@ -823,14 +874,20 @@ static void fjn_reset(struct net_device *dev) outb(dev->dev_addr[i], ioaddr + NODE_ID + i); /* Switch to bank 1 */ - outb(BANK_1, ioaddr + CONFIG_1); + if ( lp->cardtype == UNGERMANN ) + outb(BANK_1U, ioaddr + CONFIG_1); + else + outb(BANK_1, ioaddr + CONFIG_1); /* set the multicast table to accept none. */ for (i = 0; i < 6; i++) outb(0x00, ioaddr + MAR_ADR + i); /* Switch to bank 2 (runtime mode) */ - outb(BANK_2, ioaddr + CONFIG_1); + if ( lp->cardtype == UNGERMANN ) + outb(BANK_2U, ioaddr + CONFIG_1); + else + outb(BANK_2, ioaddr + CONFIG_1); /* set 16col ctrl bits */ if( lp->cardtype == TDK ) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 0f95529610da..21ced0318a51 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - pcnet_cs.c 1.124 2000/07/21 19:47:31 + pcnet_cs.c 1.126 2000/10/02 20:38:23 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.124 2000/07/21 19:47:31 (David Hinds)"; +"pcnet_cs.c 1.126 2000/10/02 20:38:23 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -81,39 +81,22 @@ static char *version = /* Parameters that can be set with 'insmod' */ +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") + /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); -/* Transceiver type, for Socket EA and IBM CC cards. */ -static int if_port = 1; - -/* Use 64K packet buffer, for Socket EA cards. */ -static int use_big_buf = 1; - -/* Shared memory speed, in ns */ -static int mem_speed = 0; - -/* Insert a pause in block_output after sending a packet */ -static int delay_output = 0; - -/* Length of delay, in microseconds */ -static int delay_time = 4; - -/* Use shared memory, if available? */ -static int use_shmem = -1; +INT_MODULE_PARM(if_port, 1); /* Transceiver type */ +INT_MODULE_PARM(use_big_buf, 1); /* use 64K packet buffer? */ +INT_MODULE_PARM(mem_speed, 0); /* shared mem speed, in ns */ +INT_MODULE_PARM(delay_output, 0); /* pause after xmit? */ +INT_MODULE_PARM(delay_time, 4); /* in usec */ +INT_MODULE_PARM(use_shmem, -1); /* use shared memory? */ /* Ugh! Let the user hardwire the hardware address for queer cards */ static int hw_addr[6] = { 0, /* ... */ }; - -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(if_port, "i"); -MODULE_PARM(use_big_buf, "i"); -MODULE_PARM(mem_speed, "i"); -MODULE_PARM(delay_output, "i"); -MODULE_PARM(delay_time, "i"); -MODULE_PARM(use_shmem, "i"); MODULE_PARM(hw_addr, "6i"); /*====================================================================*/ @@ -465,7 +448,7 @@ static hw_info_t *get_prom(dev_link_t *link) }; pcnet_reset_8390(dev); - udelay(10000); + mdelay(10); for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); @@ -1046,7 +1029,7 @@ static void pcnet_reset_8390(struct net_device *dev) for (i = 0; i < 100; i++) { if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0) break; - udelay(100L); + udelay(100); } outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */ diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index cf98d7401e46..bf32559785f0 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -247,25 +247,16 @@ static char *version = /*====================================================================*/ /* Parameters that can be set with 'insmod' */ -static int if_port = 0; -MODULE_PARM(if_port, "i"); -/* Bit map of interrupts to choose from */ -/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ -static u_long irq_mask = 0xdeb8; -MODULE_PARM(irq_mask, "i"); +#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") static int irq_list[4] = { -1 }; MODULE_PARM(irq_list, "1-4i"); - -static int do_sound = 1; -MODULE_PARM(do_sound, "i"); - -static int card_type = 0; -MODULE_PARM(card_type, "i"); /* dummy, not used anymore */ - -static int lockup_hack = 0; -MODULE_PARM(lockup_hack, "i"); /* anti lockup hack */ +INT_MODULE_PARM(irq_mask, 0xdeb8); +INT_MODULE_PARM(if_port, 0); +INT_MODULE_PARM(full_duplex, 0); +INT_MODULE_PARM(do_sound, 1); +INT_MODULE_PARM(lockup_hack, 0); /* anti lockup hack */ /*====================================================================*/ @@ -601,29 +592,6 @@ mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len) mii_idle(ioaddr); } -#ifdef PCMCIA_DEBUG -static void -mii_dump(struct net_device *dev) -{ - ioaddr_t ioaddr = dev->base_addr; - int i; - - /* Note that registers 14, 1d,1e and 1f are reserved and should - * not be read according to the DP83840A specs. - */ - printk(KERN_DEBUG "%s: MII register dump:\n", dev->name); - for (i=0; i < 32; i++) { - if (!(i % 8)) { - if (i) - printk("\n"); - printk(KERN_DEBUG "%s:", dev->name); - } - printk(" %04x", mii_rd(ioaddr, 0, i)); - } - printk("\n"); -} -#endif - /*============= Main bulk of functions =========================*/ /**************** @@ -1706,12 +1674,6 @@ do_config(struct net_device *dev, struct ifmap *map) dev->name, if_names[dev->if_port]); do_reset(dev,1); /* not the fine way :-) */ } - #ifdef PCMCIA_DEBUG - else if (local->mohawk) { - /* kludge to print the mii regsiters */ - mii_dump(dev); - } - #endif return 0; } @@ -1903,6 +1865,8 @@ do_reset(struct net_device *dev, int full) PutByte(XIRCREG42_SWC1, 0x80); busy_loop(HZ/25); /* wait 40 msec to let it complete */ } + if (full_duplex) + PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR | FullDuplex)); } else { /* No MII */ SelectPage(0); value = GetByte(XIRCREG_ESR); /* read the ESR */ @@ -1957,12 +1921,6 @@ init_mii(struct net_device *dev) unsigned control, status, linkpartner; int i; - #ifdef PCMCIA_DEBUG - if (pc_debug>1) { - mii_dump(dev); - } - #endif - status = mii_rd(ioaddr, 0, 1); if ((status & 0xff00) != 0x7800) return 0; /* No MII */ @@ -2019,11 +1977,6 @@ init_mii(struct net_device *dev) } } - #ifdef PCMCIA_DEBUG - if (pc_debug) - mii_dump(dev); - #endif - return 1; } @@ -2077,8 +2030,6 @@ init_xirc2ps_cs(void) servinfo_t serv; printk(KERN_INFO "%s\n", version); - if (card_type) - printk(KINF_XIRC "option card_type is obsolete\n"); if (lockup_hack) printk(KINF_XIRC "lockup hack is enabled\n"); CardServices(GetCardServicesInfo, &serv); diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index b89c4ec2e7de..3036684f9835 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.20 2000/07/11 22:35:22 davem Exp $ +/* $Id: sunbmac.c,v 1.21 2000/10/22 16:08:38 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -63,9 +63,7 @@ static char *version = #define DIRQ(x) #endif -#ifdef MODULE static struct bigmac *root_bigmac_dev = NULL; -#endif #define DEFAULT_JAMSIZE 4 /* Toe jam */ @@ -1197,11 +1195,12 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec dev->dma = 0; ether_setup(dev); -#ifdef MODULE - /* Put us into the list of instances attached for later module unloading. */ + /* Put us into the list of instances attached for later driver + * exit. + */ bp->next_module = root_bigmac_dev; root_bigmac_dev = bp; -#endif + return 0; fail_and_cleanup: @@ -1257,9 +1256,7 @@ static int __init bigmac_probe(void) static int called = 0; int cards = 0, v; -#ifdef MODULE root_bigmac_dev = NULL; -#endif if (called) return -ENODEV; @@ -1284,8 +1281,6 @@ static int __init bigmac_probe(void) static void __exit bigmac_cleanup(void) { -#ifdef MODULE - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_bigmac_dev) { struct bigmac *bp = root_bigmac_dev; struct bigmac *bp_nxt = root_bigmac_dev->next_module; @@ -1303,7 +1298,6 @@ static void __exit bigmac_cleanup(void) kfree(bp->dev); root_bigmac_dev = bp_nxt; } -#endif /* MODULE */ } module_init(bigmac_probe); diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 44a759c9f3e2..2f0f46d9593c 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.97 2000/09/05 23:12:36 davem Exp $ +/* $Id: sunhme.c,v 1.98 2000/10/22 16:08:38 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -55,9 +55,7 @@ static char *version = #include "sunhme.h" -#ifdef MODULE static struct happy_meal *root_happy_dev = NULL; -#endif static struct quattro *qfe_sbus_list = NULL; #ifdef CONFIG_PCI @@ -2669,14 +2667,14 @@ static int __init happy_meal_sbus_init(struct net_device *dev, happy_meal_set_initial_advertisement(hp); ether_setup(dev); -#ifdef MODULE + /* We are home free at this point, link us in to the happy - * module device list. + * device list. */ dev->ifindex = dev_new_index(); hp->next_module = root_happy_dev; root_happy_dev = hp; -#endif + return 0; } #endif @@ -2843,14 +2841,13 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd ether_setup(dev); -#ifdef MODULE /* We are home free at this point, link us in to the happy - * module device list. + * device list. */ dev->ifindex = dev_new_index(); hp->next_module = root_happy_dev; root_happy_dev = hp; -#endif + return 0; } #endif @@ -2909,9 +2906,7 @@ static int __init happy_meal_probe(void) static int called = 0; int cards; -#ifdef MODULE root_happy_dev = NULL; -#endif if (called) return -ENODEV; @@ -2934,8 +2929,6 @@ static int __init happy_meal_probe(void) static void __exit happy_meal_cleanup_module(void) { -#ifdef MODULE - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; struct happy_meal *next = root_happy_dev->next_module; @@ -2965,7 +2958,6 @@ static void __exit happy_meal_cleanup_module(void) kfree(hp->dev); root_happy_dev = next; } -#endif /* MODULE */ } module_init(happy_meal_probe); diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 2cf305bc8480..2ce4b750940b 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.104 2000/09/18 05:48:42 davem Exp $ +/* $Id: sunlance.c,v 1.105 2000/10/22 16:08:38 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -291,9 +291,7 @@ int sparc_lance_debug = 2; #define LANCE_ADDR(x) ((long)(x) & ~0xff000000) -#ifdef MODULE static struct lance_private *root_lance_dev = NULL; -#endif /* Load the CSR registers */ static void load_csrs(struct lance_private *lp) @@ -1489,11 +1487,10 @@ no_link_test: lp->multicast_timer.data = (unsigned long) dev; lp->multicast_timer.function = &lance_set_multicast_retry; -#ifdef MODULE dev->ifindex = dev_new_index(); lp->next_module = root_lance_dev; root_lance_dev = lp; -#endif + return 0; fail: @@ -1524,9 +1521,7 @@ static int __init sparc_lance_probe(void) static struct sbus_dev sdev; static int called = 0; -#ifdef MODULE root_lance_dev = NULL; -#endif if (called) return -ENODEV; @@ -1554,9 +1549,7 @@ static int __init sparc_lance_probe(void) static int called = 0; int cards = 0, v; -#ifdef MODULE root_lance_dev = NULL; -#endif if (called) return -ENODEV; @@ -1597,7 +1590,6 @@ static int __init sparc_lance_probe(void) static void __exit sparc_lance_cleanup(void) { -#ifdef MODULE struct lance_private *lp; while (root_lance_dev) { @@ -1608,7 +1600,6 @@ static void __exit sparc_lance_cleanup(void) kfree(root_lance_dev->dev); root_lance_dev = lp; } -#endif /* MODULE */ } module_init(sparc_lance_probe); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index f4ea45189e39..7eb295cd6a92 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.46 2000/06/19 06:24:46 davem Exp $ +/* $Id: sunqe.c,v 1.47 2000/10/22 16:08:38 davem Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed @@ -46,9 +46,7 @@ static char *version = #include "sunqe.h" -#ifdef MODULE static struct sunqec *root_qec_dev = NULL; -#endif static void qe_set_multicast(struct net_device *dev); @@ -917,15 +915,13 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev) printk("\n"); } -#ifdef MODULE /* We are home free at this point, link the qe's into - * the master list for later module unloading. + * the master list for later driver exit. */ for (i = 0; i < 4; i++) qe_devs[i]->ifindex = dev_new_index(); qecp->next_module = root_qec_dev; root_qec_dev = qecp; -#endif return 0; @@ -994,9 +990,7 @@ static int __init qec_probe(void) static int called = 0; int cards = 0, v; -#ifdef MODULE root_qec_dev = NULL; -#endif if (called) return -ENODEV; @@ -1021,11 +1015,9 @@ static int __init qec_probe(void) static void __exit qec_cleanup(void) { -#ifdef MODULE struct sunqec *next_qec; int i; - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_qec_dev) { next_qec = root_qec_dev->next_module; @@ -1049,7 +1041,6 @@ static void __exit qec_cleanup(void) kfree(root_qec_dev); root_qec_dev = next_qec; } -#endif /* MODULE */ } module_init(qec_probe); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 667b9cb6e238..e790c79f1ac8 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -214,7 +214,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, const char *buf, } skb_reserve(skb, 2); - copy_from_user(skb_put(skb, count), ptr, len); + copy_from_user(skb_put(skb, len), ptr, len); skb->dev = &tun->dev; switch (tun->flags & TUN_TYPE_MASK) { diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 41478ea51644..ea13f254d249 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -585,10 +585,17 @@ void __init pci_read_bridge_bases(struct pci_bus *child) base = ((io_base_lo & PCI_IO_RANGE_MASK) << 8) | (io_base_hi << 16); limit = ((io_limit_lo & PCI_IO_RANGE_MASK) << 8) | (io_limit_hi << 16); if (base && base <= limit) { - res->flags |= (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; + res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; res->start = base; res->end = limit + 0xfff; res->name = child->name; + } else { + /* + * Ugh. We don't know enough about this bridge. Just assume + * that it's entirely transparent. + */ + printk("Unknown bridge resource %d: assuming transparent\n", 0); + child->resource[0] = child->parent->resource[0]; } res = child->resource[1]; @@ -597,10 +604,14 @@ void __init pci_read_bridge_bases(struct pci_bus *child) base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; if (base && base <= limit) { - res->flags |= (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; + res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; res->start = base; res->end = limit + 0xfffff; res->name = child->name; + } else { + /* See comment above. Same thing */ + printk("Unknown bridge resource %d: assuming transparent\n", 1); + child->resource[1] = child->parent->resource[1]; } res = child->resource[2]; @@ -620,10 +631,14 @@ void __init pci_read_bridge_bases(struct pci_bus *child) } #endif if (base && base <= limit) { - res->flags |= (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; + res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH; res->start = base; res->end = limit + 0xfffff; res->name = child->name; + } else { + /* See comments above */ + printk("Unknown bridge resource %d: assuming transparent\n", 2); + child->resource[2] = child->parent->resource[2]; } } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 83a4da2d8b23..9913c1998ce9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -209,11 +209,11 @@ static void __init quirk_vt82c686_acpi(struct pci_dev *dev) * * Legacy Support Register (LEGSUP): * bit13: USB PIRQ Enable (USBPIRQDEN), - * bit4: Trap/SMI ON IRQ Enable (USBSMIEN). + * bit4: Trap/SMI On IRQ Enable (USBSMIEN). * * We mask out all r/wc bits, too. */ -static void __init quirk_piix3usb(struct pci_dev *dev) +static void __init quirk_piix3_usb(struct pci_dev *dev) { u16 legsup; @@ -267,7 +267,8 @@ static struct pci_fixup pci_fixups[] __initdata = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3usb }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb }, { 0 } }; diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c index e20918a25002..232ab5ea551c 100644 --- a/drivers/pcmcia/bulkmem.c +++ b/drivers/pcmcia/bulkmem.c @@ -2,7 +2,7 @@ PCMCIA Bulk Memory Services - bulkmem.c 1.37 2000/06/12 21:29:35 + bulkmem.c 1.38 2000/09/25 19:29:51 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -156,8 +156,7 @@ static void retry_erase(erase_busy_t *busy, u_int cause) case MTD_WAITRDY: if (req.Status == MTD_WAITRDY) insert_queue(&s->erase_busy, busy); - busy->timeout.expires = jiffies + req.Timeout*HZ/1000; - add_timer(&busy->timeout); + mod_timer(&busy->timeout, jiffies + req.Timeout*HZ/1000); break; } } else { diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 3f9fb1c7b5ba..a177ca207953 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -2,7 +2,7 @@ PCMCIA Card Information Structure parser - cistpl.c 1.90 2000/08/30 20:23:47 + cistpl.c 1.91 2000/09/16 03:48:28 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -96,6 +96,8 @@ INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ #define IS_ATTR 1 #define IS_INDIRECT 8 +static int setup_cis_mem(socket_info_t *s); + static void set_cis_map(socket_info_t *s, pccard_mem_map *mem) { s->ss_entry->set_mem_map(s->sock, mem); @@ -118,8 +120,7 @@ void read_cis_mem(socket_info_t *s, int attr, u_int addr, memset(ptr, 0xff, len); return; } - mem->flags = MAP_ACTIVE; - if (cis_width) mem->flags |= MAP_16BIT; + mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed @@ -165,8 +166,7 @@ void write_cis_mem(socket_info_t *s, int attr, u_int addr, DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); if (setup_cis_mem(s) != 0) return; - mem->flags = MAP_ACTIVE; - if (cis_width) mem->flags |= MAP_16BIT; + mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed @@ -258,7 +258,7 @@ static int checksum_match(u_long base) return ((a == b) && (a >= 0)); } -int setup_cis_mem(socket_info_t *s) +static int setup_cis_mem(socket_info_t *s) { if (!(s->cap.features & SS_CAP_STATIC_MAP) && (s->cis_mem.sys_start == 0)) { @@ -273,7 +273,6 @@ int setup_cis_mem(socket_info_t *s) return CS_OUT_OF_RESOURCE; } s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1; - s->cis_mem.flags |= MAP_ACTIVE; s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start, s->cap.map_size); } diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 2a6589aae972..92c50c0031ab 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -2,7 +2,7 @@ PCMCIA Card Services -- core services - cs.c 1.267 2000/08/30 22:07:31 + cs.c 1.271 2000/10/02 20:27:49 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -66,7 +66,7 @@ int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"cs.c 1.267 2000/08/30 22:07:31 (David Hinds)"; +"cs.c 1.271 2000/10/02 20:27:49 (David Hinds)"; #endif #ifdef CONFIG_PCI @@ -1711,7 +1711,7 @@ int pcmcia_request_configuration(client_handle_t handle, if (!(c->irq.Attributes & IRQ_FORCED_PULSE)) c->Option |= COR_LEVEL_REQ; write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option); - udelay(40*1000); + mdelay(40); } if (req->Present & PRESENT_STATUS) { c->Status = req->Status; @@ -1726,14 +1726,14 @@ int pcmcia_request_configuration(client_handle_t handle, write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus); } if (req->Present & PRESENT_IOBASE_0) { - i = c->io.BasePort1 & 0xff; - write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &i); - i = (c->io.BasePort1 >> 8) & 0xff; - write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &i); + u_char b = c->io.BasePort1 & 0xff; + write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b); + b = (c->io.BasePort1 >> 8) & 0xff; + write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b); } if (req->Present & PRESENT_IOSIZE) { - i = c->io.NumPorts1 + c->io.NumPorts2 - 1; - write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &i); + u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; + write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); } /* Configure I/O windows */ @@ -1836,12 +1836,11 @@ int pcmcia_request_io(client_handle_t handle, io_req_t *req) ======================================================================*/ -int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) +static int cs_request_irq(client_handle_t handle, irq_req_t *req) { socket_info_t *s; config_t *c; - int try, ret = 0, irq = 0; - u_int mask; + int ret = 0, irq = 0; if (CHECK_HANDLE(handle)) return CS_BAD_HANDLE; @@ -1855,21 +1854,22 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) return CS_IN_USE; /* Short cut: if there are no ISA interrupts, then it is PCI */ - if (!s->cap.irq_mask) + if (!s->cap.irq_mask) { irq = s->cap.pci_irq; + ret = (irq) ? 0 : CS_IN_USE; #ifdef CONFIG_ISA - else if (s->irq.AssignedIRQ != 0) { + } else if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must match */ irq = s->irq.AssignedIRQ; if (req->IRQInfo1 & IRQ_INFO2_VALID) { - mask = req->IRQInfo2 & s->cap.irq_mask; + u_int mask = req->IRQInfo2 & s->cap.irq_mask; ret = ((mask >> irq) & 1) ? 0 : CS_BAD_ARGS; } else ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS; } else { ret = CS_IN_USE; if (req->IRQInfo1 & IRQ_INFO2_VALID) { - mask = req->IRQInfo2 & s->cap.irq_mask; + u_int try, mask = req->IRQInfo2 & s->cap.irq_mask; for (try = 0; try < 2; try++) { for (irq = 0; irq < 32; irq++) if ((mask >> irq) & 1) { @@ -1882,8 +1882,8 @@ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) irq = req->IRQInfo1 & IRQ_MASK; ret = try_irq(req->Attributes, irq, 1); } - } #endif + } if (ret != 0) return ret; if (req->Attributes & IRQ_HANDLE_PRESENT) { diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 47efc86b08d8..1265064313ba 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -1,5 +1,5 @@ /* - * cs_internal.h 1.52 2000/06/12 21:29:37 + * cs_internal.h 1.54 2000/10/26 20:10:55 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -204,14 +204,13 @@ void cb_enable(socket_info_t *s); void cb_disable(socket_info_t *s); void read_cb_mem(socket_info_t *s, u_char fn, int space, u_int addr, u_int len, void *ptr); -void cb_release_cis_mem(socket_info_t * s); +void cb_release_cis_mem(socket_info_t *s); /* In cistpl.c */ void read_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr); void write_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr); -int setup_cis_mem(socket_info_t *s); void release_cis_mem(socket_info_t *s); int verify_cis_cache(socket_info_t *s); void preload_cis_cache(socket_info_t *s); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6d5b92f1fbef..971783407f5e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2578,7 +2578,7 @@ static int sg_proc_dressz_write(struct file * filp, const char * buffer, return -EACCES; num = (count < 10) ? count : 10; copy_from_user(buff, buffer, num); - buff[count] = '\0'; + buff[num] = '\0'; k = simple_strtoul(buff, 0, 10); if (k <= 1048576) { sg_big_buff = k; diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index ac0da7cfa0f5..63c7bb428a2f 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -12,7 +12,7 @@ * Hacked up by: * Aaron Holtzman * Ollie Lho SiS 7018 Audio Core Support - * Ching Ling Lee ALi 5451 Audio Core Support + * Ching-Ling Lee ALi 5451 Audio Core Support * * * This program is free software; you can redistribute it and/or modify @@ -30,6 +30,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.14.6 + * Oct 18 2000 Ching-Ling Lee + * 5.1-channels support for ALi + * June 28 2000 Ching-Ling Lee + * S/PDIF out/in(playback/record) support for ALi 1535+, using /proc to be selected by user + * Simple Power Management support for ALi * v0.14.5 May 23 2000 Ollie Lho * Misc bug fix from the Net * v0.14.4 May 20 2000 Aaron Holtzman @@ -38,10 +44,10 @@ * remove open_wait wq (which appears to be unused) * v0.14.3 May 10 2000 Ollie Lho * fixed a small bug in trident_update_ptr, xmms 1.0.1 no longer uses 100% CPU - * v0.14.2 Mar 29 2000 Ching Ling Lee + * v0.14.2 Mar 29 2000 Ching-Ling Lee * Add clear to silence advance in trident_update_ptr * fix invalid data of the end of the sound - * v0.14.1 Mar 24 2000 Ching Ling Lee + * v0.14.1 Mar 24 2000 Ching-Ling Lee * ALi 5451 support added, playback and recording O.K. * ALi 5451 originally developed and structured based on sonicvibes, and * suggested to merge into this file by Alan Cox. @@ -113,10 +119,14 @@ #include #include #include +#include #include "trident.h" -#define DRIVER_VERSION "0.14.5" +#include + +#define DRIVER_VERSION "0.14.6" +//#define DEBUG /* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ @@ -133,6 +143,13 @@ /* minor number of /dev/swmodem (temporary, experimental) */ #define SND_DEV_SWMODEM 7 +#define seek_offset(dma_ptr, buffer, dma_count, cnt, offset) (dma_ptr) += (offset); \ + (buffer) += (offset); \ + (dma_count) += (offset); \ + (cnt) -= (offset); + +static const unsigned ali_multi_channels[] = { ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL/*, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL*/}; + static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; @@ -215,6 +232,11 @@ struct trident_state { int ossmaxfrags; unsigned subdivision; } dmabuf; + + /* 5.1channels */ + struct trident_state *other_states[4]; + int multi_channels_adjust_count; + unsigned chans_num; }; /* hardware channels */ @@ -308,9 +330,6 @@ static int attr2mask [] = { static struct trident_card *devs; -static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); -static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg); - static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg); @@ -319,6 +338,36 @@ static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned unsigned long arg); static loff_t trident_llseek(struct file *file, loff_t offset, int origin); +static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); +static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg); +void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate); +void ali_enable_special_channel(struct trident_state *stat); +static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card); +static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card); +static int ali_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data); +void ali_restore_regs(struct trident_card *card); +void ali_save_regs(struct trident_card *card); +static int ali_allocate_multi_channels(struct trident_state *state, int chan_nums); +static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel); +static int ali_setup_multi_channels(struct trident_card *card, int chan_nums); +unsigned int ali_get_spdif_in_rate(struct trident_card *card); +void ali_setup_spdif_in(struct trident_card *card); +void ali_disable_spdif_in(struct trident_card *card); +void ali_disable_special_channel(struct trident_card *card, int ch); +void ali_setup_spdif_out(struct trident_card *card, int flag); + +/* save registers for ALi Power Management */ +static struct ali_saved_registers { + unsigned long global_regs[ALI_GLOBAL_REGS]; + unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS]; + unsigned mixer_regs[ALI_MIXER_REGS]; +} ali_registers; + +#define seek_offset(dma_ptr, buffer, dma_count, cnt, offset) (dma_ptr) += (offset); \ + (buffer) += (offset); \ + (dma_count) += (offset); \ + (cnt) -= (offset); + static int trident_enable_loop_interrupts(struct trident_card * card) { u32 global_control; @@ -433,6 +482,7 @@ static void trident_stop_voice(struct trident_card * card, unsigned int channel) #ifdef DEBUG reg = inl(TRID_REG(card, T4D_STOP_B)); + printk("ali:F0h=%lxh\n", inl(TRID_REG(card, 0xf0))); printk("trident: stop voice on channel %d, STOP_B = 0x%08x\n", channel, reg); #endif @@ -496,44 +546,6 @@ static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *c return NULL; } -static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card) -{ - struct trident_pcm_bank *bank; - int idx; - - bank = &card->banks[BANK_A]; - - for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST ; idx++) { - if (!(bank->bitmap & (1 << idx))) { - struct trident_channel *channel = &bank->channels[idx]; - bank->bitmap |= 1 << idx; - channel->num = idx; - return channel; - } - } - - /* no more free channels avaliable */ - printk(KERN_ERR "trident: no more channels available on Bank B.\n"); - return NULL; -} - -static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card) -{ - struct trident_pcm_bank *bank; - int idx = ALI_PCM_IN_CHANNEL; - - bank = &card->banks[BANK_A]; - - if (!(bank->bitmap & (1 << idx))) { - struct trident_channel *channel = &bank->channels[idx]; - bank->bitmap |= 1 << idx; - channel->num = idx; - return channel; - } - return NULL; -} - - static void trident_free_pcm_channel(struct trident_card *card, unsigned int channel) { int bank; @@ -547,20 +559,6 @@ static void trident_free_pcm_channel(struct trident_card *card, unsigned int cha card->banks[bank].bitmap &= ~(1 << (channel)); } -static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel) -{ - int bank; - - if (channel > 31) - return; - - bank = channel >> 5; - channel = channel & 0x1f; - - card->banks[bank].bitmap &= ~(1 << (channel)); -} - - /* called with spin lock held */ static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel) @@ -713,6 +711,16 @@ static void trident_play_setup(struct trident_state *state) if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) { channel->attribute = 0; + if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if ((channel->num == ALI_SPDIF_IN_CHANNEL) || (channel->num == ALI_PCM_IN_CHANNEL)) + ali_disable_special_channel(state->card, channel->num); + else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE) + && (channel->num == ALI_SPDIF_OUT_CHANNEL)) + { + ali_set_spdif_out_rate(state->card, state->dmabuf.rate); + state->dmabuf.channel->delta = 0x1000; + } + } } channel->fm_vol = 0x0; @@ -742,11 +750,14 @@ static void trident_rec_setup(struct trident_state *state) struct trident_card *card = state->card; struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; + unsigned int rate; /* Enable AC-97 ADC (capture) */ switch (card->pci_id) { case PCI_DEVICE_ID_ALI_5451: + ali_enable_special_channel(state); + break; case PCI_DEVICE_ID_SI_7018: /* for 7018, the ac97 is always in playback/record (duplex) mode */ break; @@ -768,7 +779,12 @@ static void trident_rec_setup(struct trident_state *state) channel->lba = virt_to_bus(dmabuf->rawbuf); channel->delta = compute_rate_rec(dmabuf->rate); - + if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) && (channel->num == ALI_SPDIF_IN_CHANNEL)) { + rate = ali_get_spdif_in_rate(card); + if (rate != 48000) + channel->delta = ((rate << 12) / dmabuf->rate) & 0x0000ffff; + } + channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt]; channel->eso -= 1; @@ -882,6 +898,12 @@ extern __inline__ void __stop_dac(struct trident_state *state) dmabuf->enable &= ~DAC_RUNNING; trident_stop_voice(card, chan_num); + if (state->chans_num == 6) { + trident_stop_voice(card, state->other_states[0]->dmabuf.channel->num); + trident_stop_voice(card, state->other_states[1]->dmabuf.channel->num); + trident_stop_voice(card, state->other_states[2]->dmabuf.channel->num); + trident_stop_voice(card, state->other_states[3]->dmabuf.channel->num); + } trident_disable_voice_irq(card, chan_num); } @@ -907,6 +929,16 @@ static void start_dac(struct trident_state *state) dmabuf->enable |= DAC_RUNNING; trident_enable_voice_irq(card, chan_num); trident_start_voice(card, chan_num); + if (state->chans_num == 6) { + trident_enable_voice_irq(card, state->other_states[0]->dmabuf.channel->num); + trident_start_voice(card, state->other_states[0]->dmabuf.channel->num); + trident_enable_voice_irq(card, state->other_states[1]->dmabuf.channel->num); + trident_start_voice(card, state->other_states[1]->dmabuf.channel->num); + trident_enable_voice_irq(card, state->other_states[2]->dmabuf.channel->num); + trident_start_voice(card, state->other_states[2]->dmabuf.channel->num); + trident_enable_voice_irq(card, state->other_states[3]->dmabuf.channel->num); + trident_start_voice(card, state->other_states[3]->dmabuf.channel->num); + } } spin_unlock_irqrestore(&card->lock, flags); } @@ -970,64 +1002,101 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec) { struct dmabuf *dmabuf = &state->dmabuf; unsigned bytepersec; - unsigned bufsize; + struct trident_state *s = state; + unsigned bufsize, dma_nums, default_order; unsigned long flags; - int ret; - - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; - dmabuf->count = dmabuf->error = 0; - spin_unlock_irqrestore(&state->card->lock, flags); - - /* allocate DMA buffer if not allocated yet */ - if (!dmabuf->rawbuf) - if ((ret = alloc_dmabuf(state))) - return ret; - - /* FIXME: figure out all this OSS fragment stuff */ - bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; - bufsize = PAGE_SIZE << dmabuf->buforder; - if (dmabuf->ossfragshift) { - if ((1000 << dmabuf->ossfragshift) < bytepersec) - dmabuf->fragshift = ld2(bytepersec/1000); - else - dmabuf->fragshift = dmabuf->ossfragshift; - } else { - /* lets hand out reasonable big ass buffers by default */ - dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); - } - dmabuf->numfrag = bufsize >> dmabuf->fragshift; - while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { - dmabuf->fragshift--; - dmabuf->numfrag = bufsize >> dmabuf->fragshift; + int ret, i, order; + struct page *page, *pend; + + default_order = DMABUF_DEFAULTORDER; + if (s->chans_num == 6) { + dma_nums = 5; } - dmabuf->fragsize = 1 << dmabuf->fragshift; - if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) - dmabuf->numfrag = dmabuf->ossmaxfrags; - dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; - dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; + else { + dma_nums = 1; + } + + for (i = 0; i < dma_nums; i++) { + if (i > 0) { + s = state->other_states[i - 1]; + dmabuf = &s->dmabuf; + dmabuf->fmt = state->dmabuf.fmt; + dmabuf->rate = state->dmabuf.rate; + } - memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, - dmabuf->dmasize); + spin_lock_irqsave(&s->card->lock, flags); + dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0; + dmabuf->count = dmabuf->error = 0; + spin_unlock_irqrestore(&s->card->lock, flags); - spin_lock_irqsave(&state->card->lock, flags); - if (rec) { - trident_rec_setup(state); - } else { - trident_play_setup(state); - } - spin_unlock_irqrestore(&state->card->lock, flags); + /* allocate DMA buffer if not allocated yet */ + if (!dmabuf->rawbuf) { + if (i == 0) { + if ((ret = alloc_dmabuf(state))) + return ret; + } + else { + if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER) + dmabuf->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order); + if (!dmabuf->rawbuf) { + free_pages((unsigned long)state->dmabuf.rawbuf, state->dmabuf.buforder); + state->dmabuf.rawbuf = NULL; + i-=2; + for (; i >= 0; i--) + free_pages((unsigned long)state->other_states[i]->dmabuf.rawbuf, state->other_states[i]->dmabuf.buforder); + return -ENOMEM; + } + dmabuf->ready = dmabuf->mapped = 0; + dmabuf->buforder = order; + pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << order) - 1); + for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) + mem_map_reserve(page); + } + } + /* FIXME: figure out all this OSS fragment stuff */ + bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; + bufsize = PAGE_SIZE << dmabuf->buforder; + if (dmabuf->ossfragshift) { + if ((1000 << dmabuf->ossfragshift) < bytepersec) + dmabuf->fragshift = ld2(bytepersec/1000); + else + dmabuf->fragshift = dmabuf->ossfragshift; + } else { + /* lets hand out reasonable big ass buffers by default */ + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + } + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { + dmabuf->fragshift--; + dmabuf->numfrag = bufsize >> dmabuf->fragshift; + } + dmabuf->fragsize = 1 << dmabuf->fragshift; + if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag) + dmabuf->numfrag = dmabuf->ossmaxfrags; + dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt]; + dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; + + memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, + dmabuf->dmasize); + + spin_lock_irqsave(&s->card->lock, flags); + if (rec) { + trident_rec_setup(s); + } else { + trident_play_setup(s); + } + spin_unlock_irqrestore(&s->card->lock, flags); - /* set the ready flag for the dma buffer */ - dmabuf->ready = 1; + /* set the ready flag for the dma buffer */ + dmabuf->ready = 1; #ifdef DEBUG - printk("trident: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, " + printk("trident: prog_dmabuf(%d), sample rate = %d, format = %d, numfrag = %d, " "fragsize = %d dmasize = %d\n", - dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, + dmabuf->channel->num, dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize); #endif - + } return 0; } @@ -1151,6 +1220,27 @@ static void trident_update_ptr(struct trident_state *state) __stop_adc(state); dmabuf->error++; } + if (dmabuf->count < (signed)dmabuf->dmasize/2) + wake_up(&dmabuf->wait); + } + } + + /* error handling and process wake up for DAC */ + if (dmabuf->enable == DAC_RUNNING) { + if (dmabuf->mapped) { + dmabuf->count += diff; + if (dmabuf->count >= (signed)dmabuf->fragsize) + wake_up(&dmabuf->wait); + } else { + dmabuf->count -= diff; + + if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { + /* buffer underrun or buffer overrun, we have no way to recover + it here, just stop the machine and let the process force hwptr + and swptr to sync */ + __stop_dac(state); + dmabuf->error++; + } else if (!dmabuf->endcleared) { swptr = dmabuf->swptr; silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80); @@ -1168,7 +1258,18 @@ static void trident_update_ptr(struct trident_state *state) //clear the invalid data memset (dmabuf->rawbuf + swptr, silence, clear_cnt); - + if (state->chans_num == 6) { + clear_cnt = clear_cnt / 2; + swptr = swptr / 2; + memset (state->other_states[0]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset (state->other_states[1]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset (state->other_states[2]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset (state->other_states[3]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + } dmabuf->endcleared = 1; } } else if (dmabuf->count < (signed) dmabuf->fragsize) { @@ -1176,33 +1277,21 @@ static void trident_update_ptr(struct trident_state *state) if ((swptr + clear_cnt) > dmabuf->dmasize) clear_cnt = dmabuf->dmasize - swptr; memset (dmabuf->rawbuf + swptr, silence, clear_cnt); + if (state->chans_num == 6) { + clear_cnt = clear_cnt / 2; + swptr = swptr / 2; + memset (state->other_states[0]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset (state->other_states[1]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset (state->other_states[2]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + memset (state->other_states[3]->dmabuf.rawbuf + swptr, + silence, clear_cnt); + } dmabuf->endcleared = 1; } } - /* trident_update_ptr is called by interrupt handler or by process via - ioctl/poll, we only wake up the waiting process when we have more - than 1/2 buffer of data to process (always true for interrupt handler) */ - if (dmabuf->count > (signed)dmabuf->dmasize/2) - wake_up(&dmabuf->wait); - } - } - - /* error handling and process wake up for DAC */ - if (dmabuf->enable == DAC_RUNNING) { - if (dmabuf->mapped) { - dmabuf->count += diff; - if (dmabuf->count >= (signed)dmabuf->fragsize) - wake_up(&dmabuf->wait); - } else { - dmabuf->count -= diff; - - if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun, we have no way to recover - it here, just stop the machine and let the process force hwptr - and swptr to sync */ - __stop_dac(state); - dmabuf->error++; - } /* trident_update_ptr is called by interrupt handler or by process via ioctl/poll, we only wake up the waiting process when we have more than 1/2 buffer free (always true for interrupt handler) */ @@ -1235,55 +1324,6 @@ static void trident_address_interrupt(struct trident_card *card) } } -static void ali_address_interrupt(struct trident_card *card) -{ - int i; - u32 mask = trident_get_interrupt_mask (card, BANK_A); - -#ifdef DEBUG - /* Sanity check to make sure that every state has a channel - and vice versa. */ - u32 done = 0; - unsigned ns = 0; - unsigned nc = 0; - for (i = 0; i < NR_HW_CH; i++) { - if (card->banks[BANK_A].bitmap & (1<states[i]) { - u32 bit = 1 << card->states[i]->dmabuf.channel->num; - if (bit & done) - printk (KERN_ERR "trident: channel allocated to two states\n"); - ns++; - - done |= bit; - } - } - if (ns != nc) - printk (KERN_ERR "trident: number of states != number of channels\n"); -#endif - - for (i = 0; mask && i < NR_HW_CH; i++) { - struct trident_state *state = card->states[i]; - if (!state) - continue; - - trident_ack_channel_interrupt(card, state->dmabuf.channel->num); - mask &= ~ (1<dmabuf.channel->num); - state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE; - trident_update_ptr(state); - } - - if (mask) - for (i = 0; i < NR_HW_CH; i++) - if (mask & (1<card->pci_id == PCI_DEVICE_ID_ALI_5451) - outl(inl(TRID_REG (state->card, ALI_GLOBAL_CONTROL)) | ALI_PCM_IN_ENABLE, - TRID_REG (state->card, ALI_GLOBAL_CONTROL)); - while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->count > (signed) dmabuf->dmasize) { @@ -1420,15 +1456,15 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; + struct dmabuf *dmabuf_temp; ssize_t ret; unsigned long flags; - unsigned swptr; - int cnt; + unsigned swptr, sample_s; + int cnt, i, other_dma_nums, loop, cnt_for_multi_channel; #ifdef DEBUG printk("trident: trident_write called, count = %d\n", count); #endif - VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; @@ -1440,11 +1476,12 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count return -EFAULT; ret = 0; - if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) - if (dmabuf->channel->num == ALI_PCM_IN_CHANNEL) - outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) & - ALI_PCM_IN_DISABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL)); - + if (state->chans_num == 6) { + outl(ALI_MULTI_CHANNELS_START_STOP, TRID_REG(state->card, T4D_AINT_A)); + other_dma_nums = 4; + sample_s = sample_size[state->dmabuf.fmt] >> 1; + } + while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); if (dmabuf->count < 0) { @@ -1497,21 +1534,100 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count } continue; } - if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { - if (!ret) ret = -EFAULT; - return ret; - } - - swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->swptr = swptr; - dmabuf->count += cnt; + if (state->chans_num == 6) { + cnt_for_multi_channel = cnt; + if ((i = state->multi_channels_adjust_count) > 0) { + if (i == 1) { + copy_from_user(dmabuf->rawbuf + dmabuf->swptr, buffer, sample_s); + seek_offset(dmabuf->swptr, buffer, dmabuf->count, cnt_for_multi_channel, sample_s); + dmabuf->swptr = dmabuf->swptr % dmabuf->dmasize; + i--; + state->multi_channels_adjust_count++; + } + else i = i - (state->chans_num - other_dma_nums); + for (; (i < other_dma_nums) && (cnt_for_multi_channel > 0); i++) { + dmabuf_temp = &state->other_states[i]->dmabuf; + copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s); + seek_offset(dmabuf_temp->swptr, buffer, dmabuf_temp->count, cnt_for_multi_channel, sample_s); + dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize; + } + if (cnt_for_multi_channel == 0) + state->multi_channels_adjust_count += i; + } + if (cnt_for_multi_channel > 0) { + loop = cnt_for_multi_channel / (state->chans_num * sample_s); + for (i = 0; i < loop; i++) { + copy_from_user(dmabuf->rawbuf + dmabuf->swptr, buffer, sample_s * 2); + seek_offset(dmabuf->swptr, buffer, dmabuf->count, cnt_for_multi_channel, sample_s * 2); + dmabuf->swptr = dmabuf->swptr % dmabuf->dmasize; + + dmabuf_temp = &state->other_states[0]->dmabuf; + copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s); + seek_offset(dmabuf_temp->swptr, buffer, dmabuf_temp->count, cnt_for_multi_channel, sample_s); + dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize; + + dmabuf_temp = &state->other_states[1]->dmabuf; + copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s); + + seek_offset(dmabuf_temp->swptr, buffer, dmabuf_temp->count, cnt_for_multi_channel, sample_s); + dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize; + + dmabuf_temp = &state->other_states[2]->dmabuf; + copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s); + + seek_offset(dmabuf_temp->swptr, buffer, dmabuf_temp->count, cnt_for_multi_channel, sample_s); + dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize; + + dmabuf_temp = &state->other_states[3]->dmabuf; + copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s); + + seek_offset(dmabuf_temp->swptr, buffer, dmabuf_temp->count, cnt_for_multi_channel, sample_s); + dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize; + } + + if (cnt_for_multi_channel > 0) { + state->multi_channels_adjust_count = cnt_for_multi_channel / sample_s; + + copy_from_user(dmabuf->rawbuf + dmabuf->swptr, buffer, sample_s); + seek_offset(dmabuf->swptr, buffer, dmabuf->count, cnt_for_multi_channel, sample_s); + dmabuf->swptr = dmabuf->swptr % dmabuf->dmasize; + + if (cnt_for_multi_channel > 0) { + copy_from_user(dmabuf->rawbuf + dmabuf->swptr, buffer, sample_s); + seek_offset(dmabuf->swptr, buffer, dmabuf->count, cnt_for_multi_channel, sample_s); + dmabuf->swptr = dmabuf->swptr % dmabuf->dmasize; + + if (cnt_for_multi_channel > 0) { + loop = state->multi_channels_adjust_count - (state->chans_num - other_dma_nums); + for (i = 0; i < loop; i++) { + dmabuf_temp = &state->other_states[i]->dmabuf; + copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s); + seek_offset(dmabuf_temp->swptr, buffer, dmabuf_temp->count, cnt_for_multi_channel, sample_s); + dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize; + } + } + } + } + else + state->multi_channels_adjust_count = 0; + } + } + else { + if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { + if (!ret) ret = -EFAULT; + return ret; + } + swptr = (swptr + cnt) % dmabuf->dmasize; + dmabuf->swptr = swptr; + dmabuf->count += cnt; + buffer += cnt; + } + dmabuf->endcleared = 0; spin_unlock_irqrestore(&state->card->lock, flags); count -= cnt; - buffer += cnt; ret += cnt; start_dac(state); } @@ -1720,22 +1836,38 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; - if (val >= 2) + if (val >= 2) { dmabuf->fmt |= TRIDENT_FMT_STEREO; + if (val == 6) { + val = ali_setup_multi_channels(state->card, 6); + if (val < 0) + return val; + down(&state->card->open_sem); + val = ali_allocate_multi_channels(state, 6); + up(&state->card->open_sem); + if (val < 0) + return val; + val = 6; + } + else val = 2; + } else dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } if (file->f_mode & FMODE_READ) { stop_adc(state); dmabuf->ready = 0; - if (val >= 2) + if (val >= 2) { + if (val!=6) + val = 2; dmabuf->fmt |= TRIDENT_FMT_STEREO; + } else dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } } - return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, - (int *)arg); + state->chans_num = val; + return put_user(val, (int *)arg); case SNDCTL_DSP_POST: /* FIXME: the same as RESET ?? */ @@ -1982,11 +2114,6 @@ static int trident_open(struct inode *inode, struct file *file) } if (file->f_mode & FMODE_READ) { - if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { - card->states[ALI_PCM_IN_CHANNEL] = state; - card->states[i] = NULL; - state->virt = ALI_PCM_IN_CHANNEL; - } /* FIXME: Trident 4d can only record in signed 16-bits stereo, 48kHz sample, to be dealed with in trident_set_adc_rate() ?? */ dmabuf->fmt &= ~TRIDENT_FMT_MASK; @@ -2036,6 +2163,24 @@ static int trident_release(struct inode *inode, struct file *file) if (file->f_mode & FMODE_WRITE) { stop_dac(state); + if (state->chans_num == 6) { + dealloc_dmabuf(state->other_states[0]); + dealloc_dmabuf(state->other_states[1]); + dealloc_dmabuf(state->other_states[2]); + dealloc_dmabuf(state->other_states[3]); + state->card->free_pcm_channel(state->card, state->other_states[0]->dmabuf.channel->num); + state->card->free_pcm_channel(state->card, state->other_states[1]->dmabuf.channel->num); + state->card->free_pcm_channel(state->card, state->other_states[2]->dmabuf.channel->num); + state->card->free_pcm_channel(state->card, state->other_states[3]->dmabuf.channel->num); + card->states[state->other_states[0]->virt] = NULL; + kfree(state->other_states[0]); + card->states[state->other_states[1]->virt] = NULL; + kfree(state->other_states[1]); + card->states[state->other_states[2]->virt] = NULL; + kfree(state->other_states[2]); + card->states[state->other_states[3]->virt] = NULL; + kfree(state->other_states[3]); + } dealloc_dmabuf(state); state->card->free_pcm_channel(state->card, dmabuf->channel->num); } @@ -2189,7 +2334,7 @@ static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY; if (codec->id) mask |= ALI_AC97_SECONDARY; - if (card->revision == 0x02) + if (card->revision == ALI_5451_V02) mask |= ALI_AC97_WRITE_MIXER_REGISTER; spin_lock_irqsave(&card->lock, flags); @@ -2209,7 +2354,7 @@ static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) spin_unlock_irqrestore(&card->lock, flags); return; //success } - inw(TRID_REG(card, address)); //wait a read cycle + inw(TRID_REG(card, address)); //wait for a read cycle } printk(KERN_ERR "ali: AC97 CODEC write timed out.\n"); @@ -2229,7 +2374,7 @@ static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg) u32 data; address = ALI_AC97_READ; - if (card->revision == 0x02) { + if (card->revision == ALI_5451_V02) { address = ALI_AC97_WRITE; mask &= ALI_AC97_READ_MIXER_REGISTER; } @@ -2267,6 +2412,498 @@ static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg) return 0; } +void ali_enable_special_channel(struct trident_state *stat) +{ + struct trident_card *card = stat->card; + unsigned long s_channels; + + s_channels = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); + s_channels |= (1<dmabuf.channel->num); + outl(s_channels, TRID_REG(card, ALI_GLOBAL_CONTROL)); +} + +/* +flag: ALI_SPDIF_OUT_TO_SPDIF_OUT + ALI_PCM_TO_SPDIF_OUT +*/ +void ali_setup_spdif_out(struct trident_card *card, int flag) +{ + unsigned long spdif; + unsigned char ch; + + ch = inb(TRID_REG(card, ALI_SCTRL)); + outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL)); + ch = inb(TRID_REG(card, ALI_SPDIF_CTRL)); + outb(ch & ALI_SPDIF_OUT_CH_STATUS, TRID_REG(card, ALI_SPDIF_CTRL)); + + if (flag & ALI_SPDIF_OUT_TO_SPDIF_OUT) { + spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif |= ALI_SPDIF_OUT_CH_ENABLE; + spdif &= ALI_SPDIF_OUT_SEL_SPDIF; + outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif = inw(TRID_REG(card, ALI_SPDIF_CS)); + if (flag & ALI_SPDIF_OUT_NON_PCM) + spdif |= 0x0002; + else spdif &= (~0x0002); + outw(spdif, TRID_REG(card, ALI_SPDIF_CS)); + } + else { + spdif = inw(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif |= ALI_SPDIF_OUT_SEL_PCM; + outw(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + } +} + +void ali_disable_special_channel(struct trident_card *card, int ch) +{ + unsigned long sc; + + sc = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); + sc &= ~(1 << ch); + outl(sc, TRID_REG(card, ALI_GLOBAL_CONTROL)); +} + +void ali_disable_spdif_in(struct trident_card *card) +{ + unsigned long spdif; + + spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif &= (~ALI_SPDIF_IN_SUPPORT); + outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + + ali_disable_special_channel(card, ALI_SPDIF_IN_CHANNEL); +} + +void ali_setup_spdif_in(struct trident_card *card) +{ + unsigned long spdif; + + //Set SPDIF IN Supported + spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif |= ALI_SPDIF_IN_SUPPORT; + outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + + spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); + spdif |= ALI_SPDIF_IN_CH_STATUS; + outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); + + //Set SPDIF IN Rec + spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); + spdif |= ALI_SPDIF_IN_CH_ENABLE; + outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); + + spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); + spdif |= ALI_SPDIF_IN_FUNC_ENABLE; + outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); +} + +unsigned int ali_get_spdif_in_rate(struct trident_card *card) +{ + unsigned long spdif, time1, time2; + unsigned count1, count2, count3; + unsigned char R1, R2 = 0; + + outb(0xAA, TRID_REG(card, ALI_SPDIF_CTRL + 1)); + count1 = 0xFFFF; + while(--count1) + { + count2 = 0xffff; + do{ + count3 = 0xffff; + time1 = inl(TRID_REG(card, ALI_STIMER)); + + do{ + time2 = inl(TRID_REG(card, ALI_STIMER)); + }while((count3--) && (time2 <= (time1 + 5))); + if (!count3) { + printk("ali: STimer is stopped! Error!\n"); + return FALSE; + } + R1 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); + }while((count2--) && (!((R1 == 0x0B)||(R1 == 0x0C)||(R1 == 0x0D)||(R1 == 0x0E)||(R1 == 0x12)))); + if (!count2) + continue; + + count2 = 0xffff; + time1 = inl(TRID_REG(card, ALI_STIMER)); + do{ + time2 = inl(TRID_REG(card, ALI_STIMER)); + }while((count2--) && (time2 <= (time1 + 5))); + if (!count2) + continue; + + R2 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); + count2 = 0xffff; + while((--count2) && (R2 != R1)) + { + R1 = R2; + count3 = 0xffff; + time1 = inl(TRID_REG(card, ALI_STIMER)); + do{ + time2 = inl(TRID_REG(card, ALI_STIMER)); + }while((count3--) && (time2 <= (time1 + 5))); + if (!count3) { + printk("ali: STimer is stopped! Error!\n"); + return FALSE; + } + R2 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); + } + if(R2 == R1) + break; + } + + if(!count1) { + printk("ali: Can not Detect the sample rate from SPDIF IN!\n"); + return FALSE; + } + + spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)) | ALI_SPDIF_IN_CH_STATUS; + outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); + + /* SPDIF only supprts 48k, 44.1k, 32k */ + switch(R2) { + case 0x12: + outw(0x0E08, TRID_REG(card, ALI_SPDIF_CTRL + 2)); + return 32000; + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + default: + outw(0x0905, TRID_REG(card, ALI_SPDIF_CTRL + 2)); + break; + } + + spdif = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xf; + if (spdif == 0) + return 44100; + else return 48000; +} + +static int ali_setup_multi_channels(struct trident_card *card, int chan_nums) +{ + unsigned long dwValue; + char temp; + unsigned short codec_value; + struct pci_dev *pci_dev = NULL; + + if (chan_nums == 6) { + dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000; + outl(dwValue, TRID_REG(card, ALI_SCTRL)); + dwValue = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) | 0x07800000; + outl(dwValue, TRID_REG(card, ALI_GLOBAL_CONTROL)); + } + return 1; +} + +static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel) +{ + int bank; + + if (channel > 31) + return; + + bank = channel >> 5; + channel = channel & 0x1f; + + card->banks[bank].bitmap &= ~(1 << (channel)); +} + +static int ali_allocate_multi_channels(struct trident_state *state, int chan_nums) +{ + struct trident_card *card = state->card; + struct trident_state *s; + int i, state_count = 0; + struct trident_pcm_bank *bank; + struct trident_channel *channel; + + bank = &card->banks[BANK_A]; + + if (chan_nums == 6) { + for(i = 0;(i < ALI_CHANNELS) && (state_count != 4); i++) { + if (!card->states[i]) { + if (!(bank->bitmap & (1 << ali_multi_channels[state_count]))) { + bank->bitmap |= (1 << ali_multi_channels[state_count]); + channel = &bank->channels[ali_multi_channels[state_count]]; + channel->num = ali_multi_channels[state_count]; + } + else { + state_count--; + for (; state_count >= 0; state_count--) { + kfree(state->other_states[state_count]); + ali_free_pcm_channel(card, ali_multi_channels[state_count]); + } + return -EBUSY; + } + s = card->states[i] = (struct trident_state *) + kmalloc(sizeof(struct trident_state), GFP_KERNEL); + if (!s) { + ali_free_pcm_channel(card, ali_multi_channels[state_count]); + state_count--; + for (; state_count >= 0; state_count--) { + ali_free_pcm_channel(card, ali_multi_channels[state_count]); + kfree(state->other_states[state_count]); + } + return -ENOMEM; + } + memset(s, 0, sizeof(struct trident_state)); + + s->dmabuf.channel = channel; + s->dmabuf.ossfragshift = s->dmabuf.ossmaxfrags = s->dmabuf.subdivision = 0; + init_waitqueue_head(&s->dmabuf.wait); + s->magic = card->magic; + s->card = card; + s->virt = i; + + state->other_states[state_count++] = s; + } + } + + if (state_count != 4) { + state_count--; + for (; state_count >= 0; state_count--) { + kfree(state->other_states[state_count]); + ali_free_pcm_channel(card, ali_multi_channels[state_count]); + } + return -EBUSY; + } + } + return 0; +} + +void ali_save_regs(struct trident_card *card) +{ + unsigned long flags; + int i, j; + + save_flags(flags); + cli(); + + ali_registers.global_regs[0x2c] = inl(TRID_REG(card,T4D_MISCINT)); + //ali_registers.global_regs[0x20] = inl(TRID_REG(card,T4D_START_A)); + ali_registers.global_regs[0x21] = inl(TRID_REG(card,T4D_STOP_A)); + + //disable all IRQ bits + outl(ALI_DISABLE_ALL_IRQ, TRID_REG(card, T4D_MISCINT)); + + for (i = 1; i < ALI_MIXER_REGS; i++) + ali_registers.mixer_regs[i] = ali_ac97_get (card->ac97_codec[0], i*2); + + for (i = 0; i < ALI_GLOBAL_REGS; i++) + { + if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A)) + continue; + ali_registers.global_regs[i] = inl(TRID_REG(card, i*4)); + } + + for (i = 0; i < ALI_CHANNELS; i++) + { + outb(i,TRID_REG(card, T4D_LFO_GC_CIR)); + for (j = 0; j < ALI_CHANNEL_REGS; j++) + ali_registers.channel_regs[i][j] = inl(TRID_REG(card, j*4 + 0xe0)); + } + + //Stop all HW channel + outl(ALI_STOP_ALL_CHANNELS, TRID_REG(card, T4D_STOP_A)); + + restore_flags(flags); +} + +void ali_restore_regs(struct trident_card *card) +{ + unsigned long flags; + int i, j; + + save_flags(flags); + cli(); + + for (i = 1; i < ALI_MIXER_REGS; i++) + ali_ac97_set(card->ac97_codec[0], i*2, ali_registers.mixer_regs[i]); + + for (i = 0; i < ALI_CHANNELS; i++) + { + outb(i,TRID_REG(card, T4D_LFO_GC_CIR)); + for (j = 0; j < ALI_CHANNEL_REGS; j++) + outl(ali_registers.channel_regs[i][j], TRID_REG(card, j*4 + 0xe0)); + } + + for (i = 0; i < ALI_GLOBAL_REGS; i++) + { + if ((i*4 == T4D_MISCINT) || (i*4 == T4D_STOP_A) || (i*4 == T4D_START_A)) + continue; + ali_registers.global_regs[i] = inl(TRID_REG(card, i*4)); + } + + //start HW channel + outl(ali_registers.global_regs[0x20], TRID_REG(card,T4D_START_A)); + //restore IRQ enable bits + outl(ali_registers.global_regs[0x2c], TRID_REG(card,T4D_MISCINT)); + + restore_flags(flags); +} + +static int ali_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct trident_card *card = (struct trident_card *)dev->data; + + if (card) { + switch (rqst) { + case PM_SUSPEND: + ali_save_regs(card); + break; + case PM_RESUME: + ali_restore_regs(card); + break; + } + } + return 0; +} + +static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card) +{ + struct trident_pcm_bank *bank; + int idx; + + bank = &card->banks[BANK_A]; + + if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) & (ALI_SPDIF_OUT_CH_ENABLE)) { + idx = ALI_SPDIF_OUT_CHANNEL; + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + bank->bitmap |= 1 << idx; + channel->num = idx; + return channel; + } + } + + for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST ; idx++) { + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + bank->bitmap |= 1 << idx; + channel->num = idx; + return channel; + } + } + + /* no more free channels avaliable */ + printk(KERN_ERR "ali: no more channels available on Bank A.\n"); + return NULL; +} + +static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card) +{ + struct trident_pcm_bank *bank; + int idx; + + if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_IN_SUPPORT) + idx = ALI_SPDIF_IN_CHANNEL; + else idx = ALI_PCM_IN_CHANNEL; + + bank = &card->banks[BANK_A]; + + if (!(bank->bitmap & (1 << idx))) { + struct trident_channel *channel = &bank->channels[idx]; + bank->bitmap |= 1 << idx; + channel->num = idx; + return channel; + } + + /* no free recordable channels avaliable */ + printk(KERN_ERR "ali: no recordable channels available on Bank A.\n"); + return NULL; +} + +void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate) +{ + unsigned char ch_st_sel; + unsigned short status_rate; + +#ifdef DEBUG + printk("ali: spdif out rate =%d\n", rate); +#endif + switch(rate) { + case 44100: + status_rate = 0; + break; + case 32000: + status_rate = 0x300; + break; + case 48000: + default: + status_rate = 0x200; + break; + } + + ch_st_sel = inb(TRID_REG(card, ALI_SPDIF_CTRL)) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out + + ch_st_sel |= 0x80; //select right + outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL)); + outb(status_rate | 0x20, TRID_REG(card, ALI_SPDIF_CS + 2)); + + ch_st_sel &= (~0x80); //select left + outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL)); + outw(status_rate | 0x10, TRID_REG(card, ALI_SPDIF_CS + 2)); +#ifdef DEBUG + printk("ali: SPDIF_CS=%lxh\n", inl(TRID_REG(card, ALI_SPDIF_CS))); +#endif +} + +static void ali_address_interrupt(struct trident_card *card) +{ + int i, channel; + struct trident_state *state; + u32 mask, channel_mask; + + mask = trident_get_interrupt_mask (card, 0); + for (i = 0; i < NR_HW_CH; i++) { + if ((state = card->states[i]) == NULL) + continue; + channel = state->dmabuf.channel->num; + if ((channel_mask = 1 << channel) & mask) { + mask &= ~channel_mask; + trident_ack_channel_interrupt(card, channel); + state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE; + trident_update_ptr(state); + } + } + if (mask) { + for (i = 0; i < NR_HW_CH; i++) { + if (mask & (1 << i)) { + printk("ali: spurious channel irq %d.\n", i); + trident_ack_channel_interrupt(card, i); + trident_stop_voice(card, i); + trident_disable_voice_irq(card, i); + } + } + } +} + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *res = NULL; +static int ali_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + struct trident_card *card = (struct trident_card *)data; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + if (*buffer == '0') { //default + ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); + ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); + } + else if (*buffer == '1') + ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT|ALI_SPDIF_OUT_PCM); + else if (*buffer == '2') //AC3 data + ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT|ALI_SPDIF_OUT_NON_PCM); + else if (*buffer == '3') + ali_disable_spdif_in(card); //default + else if (*buffer == '4') + ali_setup_spdif_in(card); + spin_unlock_irqrestore(&card->lock, flags); + + return count; +} +#endif + /* OSS /dev/mixer file operation methods */ static int trident_open_mixdev(struct inode *inode, struct file *file) { @@ -2309,7 +2946,7 @@ static /*const*/ struct file_operations trident_mixer_fops = { static int __init trident_ac97_init(struct trident_card *card) { int num_ac97 = 0; - int ready_2nd = 0; + unsigned long ready_2nd = 0; struct ac97_codec *codec; /* initialize controller side of AC link, and find out if secondary codes @@ -2317,8 +2954,9 @@ static int __init trident_ac97_init(struct trident_card *card) switch (card->pci_id) { case PCI_DEVICE_ID_ALI_5451: - outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL)); - ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL)); + ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); + outl(ready_2nd | PCMOUT | SECONDARY_ID, TRID_REG(card, ALI_SCTRL)); + ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); ready_2nd &= SI_AC97_SECONDARY_READY; break; case PCI_DEVICE_ID_SI_7018: @@ -2435,10 +3073,32 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device card_names[pci_id->driver_data], card->iobase, card->irq); if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + /* ALi Power Management */ + struct pm_dev *pmdev; + + pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), + ali_pm_callback); + if (pmdev) + pmdev->data = card; + + /* ALi channel Management */ card->alloc_pcm_channel = ali_alloc_pcm_channel; card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; card->free_pcm_channel = ali_free_pcm_channel; + card->address_interrupt = ali_address_interrupt; + + /* ALi SPDIF OUT function */ + if(card->revision == ALI_5451_V02) { + ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); +#ifdef CONFIG_PROC_FS + res = create_proc_entry("ALi5451", 0, NULL); + if (res) { + res->write_proc = ali_write_proc; + res->data = card; + } +#endif + } } else { card->alloc_pcm_channel = trident_alloc_pcm_channel; @@ -2477,9 +3137,9 @@ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { /* edited by HMSEO for GT sound */ #ifdef CONFIG_ALPHA_NAUTILUS - u16 ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL); - trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, - ac97_data | ALI_EAPD_POWER_DOWN); + u16 ac97_data; + ac97_data = ali_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL); + ali_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN); #endif /* edited by HMSEO for GT sound*/ } @@ -2498,6 +3158,17 @@ static void __exit trident_remove(struct pci_dev *pci_dev) int i; struct trident_card *card = pci_get_drvdata(pci_dev); + /* ALi S/PDIF and Power Management */ + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); + ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL); + ali_disable_spdif_in(card); +#ifdef CONFIG_PROC_FS + remove_proc_entry("ALi5451", NULL); +#endif + pm_unregister_all(ali_pm_callback); + } + /* Kill interrupts, and SP/DIF */ trident_disable_loop_interrupts(card); diff --git a/drivers/sound/trident.h b/drivers/sound/trident.h index a35563622a22..094910137677 100644 --- a/drivers/sound/trident.h +++ b/drivers/sound/trident.h @@ -52,6 +52,10 @@ #define PCI_DEVICE_ID_ALI_5451 0x5451 #endif +#ifndef PCI_DEVICE_ID_ALI_1533 +#define PCI_DEVICE_ID_ALI_1533 0x1533 +#endif + #ifndef FALSE #define FALSE 0 #define TRUE 1 @@ -90,22 +94,65 @@ enum trident_op_registers { }; enum ali_op_registers { + ALI_SCTRL = 0x48, ALI_GLOBAL_CONTROL = 0xd4, - ALI_STIMER = 0xc8 + ALI_STIMER = 0xc8, + ALI_SPDIF_CS = 0x70, + ALI_SPDIF_CTRL = 0x74 +}; + +enum ali_registers_number { + ALI_GLOBAL_REGS = 56, + ALI_CHANNEL_REGS = 8, + ALI_MIXER_REGS = 20 +}; + +enum ali_sctrl_control_bit { + ALI_SPDIF_OUT_ENABLE = 0x20 }; enum ali_global_control_bit { + ALI_SPDIF_OUT_SEL_PCM = 0x00000400, + ALI_SPDIF_IN_SUPPORT = 0x00000800, + ALI_SPDIF_OUT_CH_ENABLE = 0x00008000, + ALI_SPDIF_IN_CH_ENABLE = 0x00080000, + ALI_PCM_IN_DISABLE = 0x7fffffff, ALI_PCM_IN_ENABLE = 0x80000000, - ALI_PCM_IN_DISABLE = 0x7fffffff + ALI_SPDIF_IN_CH_DISABLE = 0xfff7ffff, + ALI_SPDIF_OUT_CH_DISABLE = 0xffff7fff, + ALI_SPDIF_OUT_SEL_SPDIF = 0xfffffbff + +}; + +enum ali_spdif_control_bit { + ALI_SPDIF_IN_FUNC_ENABLE = 0x02, + ALI_SPDIF_IN_CH_STATUS = 0x40, + ALI_SPDIF_OUT_CH_STATUS = 0xbf + +}; + +enum ali_control_all { + ALI_DISABLE_ALL_IRQ = 0, + ALI_CHANNELS = 32, + ALI_STOP_ALL_CHANNELS = 0xffffffff, + ALI_MULTI_CHANNELS_START_STOP = 0x07800000 + }; enum ali_pcm_in_channel_num { + ALI_NORMAL_CHANNEL = 0, + ALI_SPDIF_OUT_CHANNEL = 15, + ALI_SPDIF_IN_CHANNEL = 19, + ALI_LEF_CHANNEL = 23, + ALI_CENTER_CHANNEL = 24, + ALI_SURR_RIGHT_CHANNEL = 25, + ALI_SURR_LEFT_CHANNEL = 26, ALI_PCM_IN_CHANNEL = 31 }; enum ali_pcm_out_channel_num { - ALI_PCM_OUT_CHANNEL_FIRST = 1, - ALI_PCM_OUT_CHANNEL_LAST = 30 + ALI_PCM_OUT_CHANNEL_FIRST = 0, + ALI_PCM_OUT_CHANNEL_LAST = 31 }; enum ali_ac97_power_control_bit { @@ -116,6 +163,17 @@ enum ali_update_ptr_flags { ALI_ADDRESS_INT_UPDATE = 0x01 }; +enum ali_revision { + ALI_5451_V02 = 0x02 +}; + +enum ali_spdif_out_control { + ALI_PCM_TO_SPDIF_OUT = 0, + ALI_SPDIF_OUT_TO_SPDIF_OUT = 1, + ALI_SPDIF_OUT_PCM = 0, + ALI_SPDIF_OUT_NON_PCM = 2 +}; + /* S/PDIF Operational Registers for 4D-NX */ enum nx_spdif_registers { NX_SPCTRL_SPCSO = 0x24, NX_SPLBA = 0x28, @@ -259,7 +317,6 @@ enum miscint_bits { #define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC) #define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC) - extern __inline__ unsigned ld2(unsigned int x) { unsigned r = 0; diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 9d21624bc1be..9dfde83e8152 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -3,7 +3,7 @@ * linux/fs/autofs/expire.c * * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved - * Copyright 1999 Jeremy Fitzhardinge + * Copyright 1999-2000 Jeremy Fitzhardinge * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -15,46 +15,139 @@ /* * Determine if a subtree of the namespace is busy. + * + * mnt is the mount tree under the autofs mountpoint */ -static int is_tree_busy(struct vfsmount *mnt) +static inline int is_vfsmnt_tree_busy(struct vfsmount *mnt) { struct vfsmount *this_parent = mnt; struct list_head *next; int count; - spin_lock(&dcache_lock); - count = atomic_read(&mnt->mnt_count) - 2; - if (!is_autofs4_dentry(mnt->mnt_mountpoint)) - count--; + count = atomic_read(&mnt->mnt_count) - 1; + repeat: next = this_parent->mnt_mounts.next; + DPRINTK(("is_vfsmnt_tree_busy: mnt=%p, this_parent=%p, next=%p\n", + mnt, this_parent, next)); resume: - while (next != &this_parent->mnt_mounts) { - struct list_head *tmp = next; - struct vfsmount *p = list_entry(tmp, struct vfsmount, + for( ; next != &this_parent->mnt_mounts; next = next->next) { + struct vfsmount *p = list_entry(next, struct vfsmount, mnt_child); - next = tmp->next; - /* Decrement count for unused children */ - count += atomic_read(&p->mnt_count) - 2; + + /* -1 for struct vfs_mount's normal count, + -1 to compensate for child's reference to parent */ + count += atomic_read(&p->mnt_count) - 1 - 1; + + DPRINTK(("is_vfsmnt_tree_busy: p=%p, count now %d\n", + p, count)); + if (!list_empty(&p->mnt_mounts)) { this_parent = p; goto repeat; } /* root is busy if any leaf is busy */ - if (atomic_read(&p->mnt_count) > 1) { - spin_unlock(&dcache_lock); + if (atomic_read(&p->mnt_count) > 1) return 1; - } } - /* - * All done at this level ... ascend and resume the search. - */ + + /* All done at this level ... ascend and resume the search. */ if (this_parent != mnt) { next = this_parent->mnt_child.next; this_parent = this_parent->mnt_parent; goto resume; } - spin_unlock(&dcache_lock); + + DPRINTK(("is_vfsmnt_tree_busy: count=%d\n", count)); + return count != 0; /* remaining users? */ +} + +/* Traverse a dentry's list of vfsmounts and return the number of + non-busy mounts */ +static int check_vfsmnt(struct vfsmount *mnt, struct dentry *dentry) +{ + int ret = 0; + struct list_head *tmp; + + list_for_each(tmp, &dentry->d_vfsmnt) { + struct vfsmount *vfs = list_entry(tmp, struct vfsmount, + mnt_clash); + DPRINTK(("check_vfsmnt: mnt=%p, dentry=%p, tmp=%p, vfs=%p\n", + mnt, dentry, tmp, vfs)); + if (vfs->mnt_parent != mnt || /* don't care about busy-ness of other namespaces */ + !is_vfsmnt_tree_busy(vfs)) + ret++; + } + + DPRINTK(("check_vfsmnt: ret=%d\n", ret)); + return ret; +} + +/* Check dentry tree for busyness. If a dentry appears to be busy + because it is a mountpoint, check to see if the mounted + filesystem is busy. */ +static int is_tree_busy(struct vfsmount *topmnt, struct dentry *top) +{ + struct dentry *this_parent; + struct list_head *next; + int count; + + count = atomic_read(&top->d_count); + + DPRINTK(("is_tree_busy: top=%p initial count=%d\n", + top, count)); + this_parent = top; + + count--; /* top is passed in after being dgot */ + + if (is_autofs4_dentry(top)) { + count--; + DPRINTK(("is_tree_busy: autofs; count=%d\n", count)); + } + + if (d_mountpoint(top)) + count -= check_vfsmnt(topmnt, top); + + repeat: + next = this_parent->d_subdirs.next; + resume: + while (next != &this_parent->d_subdirs) { + int adj = 0; + struct dentry *dentry = list_entry(next, struct dentry, + d_child); + next = next->next; + + count += atomic_read(&dentry->d_count) - 1; + + if (d_mountpoint(dentry)) + adj += check_vfsmnt(topmnt, dentry); + + if (is_autofs4_dentry(dentry)) { + adj++; + DPRINTK(("is_tree_busy: autofs; adj=%d\n", + adj)); + } + + count -= adj; + + if (!list_empty(&dentry->d_subdirs)) { + this_parent = dentry; + goto repeat; + } + + if (atomic_read(&dentry->d_count) != adj) { + DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n", + atomic_read(&dentry->d_count), adj)); + return 1; + } + } + + /* All done at this level ... ascend and resume the search. */ + if (this_parent != top) { + next = this_parent->d_child.next; + this_parent = this_parent->d_parent; + goto resume; + } DPRINTK(("is_tree_busy: count=%d\n", count)); return count != 0; /* remaining users? */ @@ -67,11 +160,11 @@ resume: * - it has been unused for exp_timeout time */ static struct dentry *autofs4_expire(struct super_block *sb, - struct vfsmount *mnt, - struct autofs_sb_info *sbi, - int do_now) + struct vfsmount *mnt, + struct autofs_sb_info *sbi, + int do_now) { - unsigned long now = jiffies; /* snapshot of now */ + unsigned long now = jiffies; unsigned long timeout; struct dentry *root = sb->s_root; struct list_head *tmp; @@ -106,36 +199,32 @@ static struct dentry *autofs4_expire(struct super_block *sb, if (!do_now) { /* Too young to die */ - if (time_after(ino->last_used+timeout, now)) + if (time_after(ino->last_used + timeout, now)) continue; /* update last_used here :- - obviously makes sense if it is in use now - less obviously, prevents rapid-fire expire - attempts if expire fails the first time */ + attempts if expire fails the first time */ ino->last_used = now; } p = mntget(mnt); - d = dget(dentry); - spin_unlock(&dcache_lock); - while(d_mountpoint(d) && follow_down(&p, &d)) - ; + d = dget_locked(dentry); - if (!is_tree_busy(p)) { - dput(d); - mntput(p); + if (!is_tree_busy(p, d)) { DPRINTK(("autofs_expire: returning %p %.*s\n", - dentry, dentry->d_name.len, dentry->d_name.name)); + dentry, (int)dentry->d_name.len, dentry->d_name.name)); /* Start from here next time */ - spin_lock(&dcache_lock); list_del(&root->d_subdirs); list_add(&root->d_subdirs, &dentry->d_child); spin_unlock(&dcache_lock); + + dput(d); + mntput(p); return dentry; } dput(d); mntput(p); - spin_lock(&dcache_lock); } spin_unlock(&dcache_lock); diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 72b5e1b27e1f..6bdc3d358673 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -3,7 +3,7 @@ * linux/fs/autofs/root.c * * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved - * Copyright 1999 Jeremy Fitzhardinge + * Copyright 1999-2000 Jeremy Fitzhardinge * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -115,7 +115,6 @@ static int try_to_fill_dentry(struct dentry *dentry, /* Return a negative dentry, but leave it "pending" */ return 1; } - /* status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT); */ } /* If this is an unused directory that isn't a mount point, @@ -201,30 +200,34 @@ static int autofs4_revalidate(struct dentry *dentry, int flags) static void autofs4_dentry_release(struct dentry *de) { - struct autofs_info *inf = autofs4_dentry_ino(de); + struct autofs_info *inf; + + lock_kernel(); DPRINTK(("autofs4_dentry_release: releasing %p\n", de)); - lock_kernel(); + inf = autofs4_dentry_ino(de); de->d_fsdata = NULL; + if (inf) { inf->dentry = NULL; inf->inode = NULL; autofs4_free_ino(inf); } + unlock_kernel(); } /* For dentries of directories in the root dir */ static struct dentry_operations autofs4_root_dentry_operations = { - d_revalidate: autofs4_root_revalidate, /* d_revalidate */ + d_revalidate: autofs4_root_revalidate, d_release: autofs4_dentry_release, }; /* For other dentries */ static struct dentry_operations autofs4_dentry_operations = { - d_revalidate: autofs4_revalidate, /* d_revalidate */ + d_revalidate: autofs4_revalidate, d_release: autofs4_dentry_release, }; @@ -521,11 +524,11 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp, /* return a single thing to expire */ case AUTOFS_IOC_EXPIRE: return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi, - (struct autofs_packet_expire *)arg); + (struct autofs_packet_expire *)arg); /* same as above, but can send multiple expires through pipe */ case AUTOFS_IOC_EXPIRE_MULTI: return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi, - (int *)arg); + (int *)arg); default: return -ENOSYS; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 21ae090a3ff2..391263c3113e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -281,7 +281,9 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) * Flush all pending writes before doing anything * with locks.. */ + down(&filp->f_dentry->d_inode->i_sem); status = nfs_wb_all(inode); + up(&filp->f_dentry->d_inode->i_sem); if (status < 0) return status; @@ -296,8 +298,10 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) */ out_ok: if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) { + down(&filp->f_dentry->d_inode->i_sem); nfs_wb_all(inode); /* we may have slept */ nfs_zap_caches(inode); + up(&filp->f_dentry->d_inode->i_sem); } return status; } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bf7a4abe4d12..5346e63028d6 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1239,9 +1239,6 @@ nfs_writeback_done(struct rpc_task *task) } #endif - /* Update attributes as result of writeback. */ - nfs_write_attributes(inode, resp->fattr); - while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); @@ -1281,6 +1278,9 @@ nfs_writeback_done(struct rpc_task *task) next: nfs_unlock_request(req); } + /* Update attributes as result of writeback. */ + nfs_write_attributes(inode, resp->fattr); + } @@ -1395,7 +1395,6 @@ nfs_commit_done(struct rpc_task *task) dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); - nfs_refresh_inode(inode, resp->fattr); while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); @@ -1427,6 +1426,8 @@ nfs_commit_done(struct rpc_task *task) next: nfs_unlock_request(req); } + + nfs_write_attributes(inode, resp->fattr); } #endif diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index d97e1717dec3..4cf7c897c1a7 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -144,9 +144,9 @@ decode_sattr3(u32 *p, struct iattr *iap) iap->ia_valid |= ATTR_SIZE; p = dec64(p, &newsize); if (newsize <= NFS_OFFSET_MAX) - iap->ia_size = (u32) newsize; + iap->ia_size = newsize; else - iap->ia_size = ~(size_t) 0; + iap->ia_size = NFS_OFFSET_MAX; } if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_ATIME; diff --git a/fs/open.c b/fs/open.c index ac2077f1f0ba..309aa0667994 100644 --- a/fs/open.c +++ b/fs/open.c @@ -103,7 +103,7 @@ static inline long do_sys_truncate(const char * path, loff_t length) inode = nd.dentry->d_inode; error = -EACCES; - if (S_ISDIR(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) goto dput_and_out; error = permission(inode,MAY_WRITE); @@ -164,7 +164,7 @@ static inline long do_sys_ftruncate(unsigned int fd, loff_t length) dentry = file->f_dentry; inode = dentry->d_inode; error = -EACCES; - if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) goto out_putf; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) diff --git a/include/asm-alpha/unaligned.h b/include/asm-alpha/unaligned.h index 8017f6bfa388..1ec3e969ece0 100644 --- a/include/asm-alpha/unaligned.h +++ b/include/asm-alpha/unaligned.h @@ -31,59 +31,20 @@ struct __una_u16 { __u16 x __attribute__((packed)); }; extern inline unsigned long __uldq(const unsigned long * r11) { -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 const struct __una_u64 *ptr = (const struct __una_u64 *) r11; return ptr->x; -#else - unsigned long r1,r2; - __asm__("ldq_u %0,%3\n\t" - "ldq_u %1,%4\n\t" - "extql %0,%2,%0\n\t" - "extqh %1,%2,%1" - :"=&r" (r1), "=&r" (r2) - :"r" (r11), - "m" (*r11), - "m" (*(const unsigned long *)(7+(char *) r11))); - return r1 | r2; -#endif } extern inline unsigned long __uldl(const unsigned int * r11) { -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 const struct __una_u32 *ptr = (const struct __una_u32 *) r11; return ptr->x; -#else - unsigned long r1,r2; - __asm__("ldq_u %0,%3\n\t" - "ldq_u %1,%4\n\t" - "extll %0,%2,%0\n\t" - "extlh %1,%2,%1" - :"=&r" (r1), "=&r" (r2) - :"r" (r11), - "m" (*r11), - "m" (*(const unsigned long *)(3+(char *) r11))); - return r1 | r2; -#endif } extern inline unsigned long __uldw(const unsigned short * r11) { -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 const struct __una_u16 *ptr = (const struct __una_u16 *) r11; return ptr->x; -#else - unsigned long r1,r2; - __asm__("ldq_u %0,%3\n\t" - "ldq_u %1,%4\n\t" - "extwl %0,%2,%0\n\t" - "extwh %1,%2,%1" - :"=&r" (r1), "=&r" (r2) - :"r" (r11), - "m" (*r11), - "m" (*(const unsigned long *)(1+(char *) r11))); - return r1 | r2; -#endif } /* @@ -92,77 +53,20 @@ extern inline unsigned long __uldw(const unsigned short * r11) extern inline void __ustq(unsigned long r5, unsigned long * r11) { -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 struct __una_u64 *ptr = (struct __una_u64 *) r11; ptr->x = r5; -#else - unsigned long r1,r2,r3,r4; - - __asm__("ldq_u %3,%1\n\t" - "ldq_u %2,%0\n\t" - "insqh %6,%7,%5\n\t" - "insql %6,%7,%4\n\t" - "mskqh %3,%7,%3\n\t" - "mskql %2,%7,%2\n\t" - "bis %3,%5,%3\n\t" - "bis %2,%4,%2\n\t" - "stq_u %3,%1\n\t" - "stq_u %2,%0" - :"=m" (*r11), - "=m" (*(unsigned long *)(7+(char *) r11)), - "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4) - :"r" (r5), "r" (r11)); -#endif } extern inline void __ustl(unsigned long r5, unsigned int * r11) { -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 struct __una_u32 *ptr = (struct __una_u32 *) r11; ptr->x = r5; -#else - unsigned long r1,r2,r3,r4; - - __asm__("ldq_u %3,%1\n\t" - "ldq_u %2,%0\n\t" - "inslh %6,%7,%5\n\t" - "insll %6,%7,%4\n\t" - "msklh %3,%7,%3\n\t" - "mskll %2,%7,%2\n\t" - "bis %3,%5,%3\n\t" - "bis %2,%4,%2\n\t" - "stq_u %3,%1\n\t" - "stq_u %2,%0" - :"=m" (*r11), - "=m" (*(unsigned long *)(3+(char *) r11)), - "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4) - :"r" (r5), "r" (r11)); -#endif } extern inline void __ustw(unsigned long r5, unsigned short * r11) { -#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 struct __una_u16 *ptr = (struct __una_u16 *) r11; ptr->x = r5; -#else - unsigned long r1,r2,r3,r4; - - __asm__("ldq_u %3,%1\n\t" - "ldq_u %2,%0\n\t" - "inswh %6,%7,%5\n\t" - "inswl %6,%7,%4\n\t" - "mskwh %3,%7,%3\n\t" - "mskwl %2,%7,%2\n\t" - "bis %3,%5,%3\n\t" - "bis %2,%4,%2\n\t" - "stq_u %3,%1\n\t" - "stq_u %2,%0" - :"=m" (*r11), - "=m" (*(unsigned long *)(1+(char *) r11)), - "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4) - :"r" (r5), "r" (r11)); -#endif } extern inline unsigned long __get_unaligned(const void *ptr, size_t size) diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h index 52ff6d8a3012..99aa24761db9 100644 --- a/include/linux/auto_fs4.h +++ b/include/linux/auto_fs4.h @@ -1,4 +1,4 @@ -/* -*- c-mode -*- +/* -*- c -*- * linux/include/linux/auto_fs4.h * * Copyright 1999-2000 Jeremy Fitzhardinge diff --git a/include/linux/in.h b/include/linux/in.h index 37db22a9a5b5..1d5f14ad6286 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -66,6 +66,7 @@ struct in_addr { #define IP_RECVTTL 12 #define IP_RECVTOS 13 #define IP_MTU 14 +#define IP_FREEBIND 15 /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS diff --git a/include/linux/init.h b/include/linux/init.h index 0376e7a77b35..91bbb23d77e2 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -102,8 +102,6 @@ extern struct kernel_param __setup_start, __setup_end; #define __FINIT #define __INITDATA -/* Not sure what version aliases were introduced in, but certainly in 2.91.66. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91) /* These macros create a dummy inline: gcc 2.9x does not count alias as usage, hence the `unused function' warning when __init functions are declared static. We use the dummy __*_module_inline functions @@ -119,20 +117,12 @@ typedef void (*__cleanup_module_func_t)(void); void cleanup_module(void) __attribute__((alias(#x))); \ extern inline __cleanup_module_func_t __cleanup_module_inline(void) \ { return x; } -#else -#define module_init(x) int init_module(void) { return x(); } -#define module_exit(x) void cleanup_module(void) { x(); } -#endif #define __setup(str,func) /* nothing */ #endif -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) #define __initlocaldata __initdata -#else -#define __initlocaldata -#endif #ifdef CONFIG_HOTPLUG #define __devinit diff --git a/include/linux/linkage.h b/include/linux/linkage.h index aaf6edf025cf..23b9ae463b67 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -9,7 +9,7 @@ #define CPP_ASMLINKAGE #endif -#if defined __i386__ && (__GNUC__ > 2 || __GNUC_MINOR__ > 7) +#if defined __i386__ #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) #elif defined __ia64__ #define asmlinkage CPP_ASMLINKAGE __attribute__((syscall_linkage)) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index db9260ee53f8..c795440f86a0 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -837,6 +837,9 @@ #define PCI_DEVICE_ID_SERVERWORKS_CIOB30 0x0010 #define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011 #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 +#define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220 #define PCI_VENDOR_ID_SBE 0x1176 #define PCI_DEVICE_ID_SBE_WANXL100 0x0301 diff --git a/include/net/sock.h b/include/net/sock.h index e3527b2f35fc..75aae4d1b2ec 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -202,7 +202,8 @@ struct inet_opt unsigned char hdrincl; /* Include headers ? */ __u8 mc_ttl; /* Multicasting TTL */ __u8 mc_loop; /* Loopback */ - __u8 recverr; + unsigned recverr : 1, + freebind : 1; __u8 pmtudisc; int mc_index; /* Multicast device index */ __u32 mc_addr; diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h index 70f3d8a48804..eb88263fc8d5 100644 --- a/include/pcmcia/version.h +++ b/include/pcmcia/version.h @@ -1,4 +1,4 @@ -/* version.h 1.92 2000/07/21 18:26:56 (David Hinds) */ +/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */ -#define CS_RELEASE "3.1.20" -#define CS_RELEASE_CODE 0x3115 +#define CS_RELEASE "3.1.22" +#define CS_RELEASE_CODE 0x3116 diff --git a/init/main.c b/init/main.c index 91b58e1804ed..6a9fd0494dd7 100644 --- a/init/main.c +++ b/init/main.c @@ -73,8 +73,8 @@ extern void nubus_init(void); * To avoid associated bogus bug reports, we flatly refuse to compile * with a gcc that is known to be too old from the very beginning. */ -#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) -#error sorry, your GCC is too old. It builds incorrect kernels. +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) +#error Sorry, your GCC is too old. It builds incorrect kernels. #endif extern char _stext, _etext; diff --git a/kernel/sched.c b/kernel/sched.c index 361b72491179..927bf47e7297 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -223,16 +223,20 @@ static void reschedule_idle(struct task_struct * p) best_cpu = p->processor; if (can_schedule(p, best_cpu)) { tsk = idle_task(best_cpu); - if (cpu_curr(best_cpu) == tsk) - goto send_now_idle; - - /* - * Maybe this process has enough priority to preempt - * its preferred CPU. (this is a shortcut): - */ - tsk = cpu_curr(best_cpu); - if (preemption_goodness(tsk, p, best_cpu) > 0) - goto preempt_now; + if (cpu_curr(best_cpu) == tsk) { + int need_resched; +send_now_idle: + /* + * If need_resched == -1 then we can skip sending + * the IPI altogether, tsk->need_resched is + * actively watched by the idle thread. + */ + need_resched = tsk->need_resched; + tsk->need_resched = 1; + if ((best_cpu != this_cpu) && !need_resched) + smp_send_reschedule(best_cpu); + return; + } } /* @@ -276,31 +280,13 @@ static void reschedule_idle(struct task_struct * p) if (tsk) { if (oldest_idle != -1ULL) goto send_now_idle; - goto preempt_now; + tsk->need_resched = 1; + if (tsk->processor != this_cpu) + smp_send_reschedule(tsk->processor); } - return; -send_now_idle: - /* - * If need_resched == -1 then we can skip sending the IPI - * altogether, tsk->need_resched is actively watched by the - * idle thread. - */ - if ((tsk->processor != current->processor) && !tsk->need_resched) - smp_send_reschedule(tsk->processor); - tsk->need_resched = 1; - return; -preempt_now: - tsk->need_resched = 1; - /* - * the APIC stuff can go outside of the lock because - * it uses no task information, only CPU#. - */ - if (tsk->processor != this_cpu) - smp_send_reschedule(tsk->processor); - return; #else /* UP */ int this_cpu = smp_processor_id(); struct task_struct *tsk; @@ -444,37 +430,53 @@ signed long schedule_timeout(signed long timeout) static inline void __schedule_tail(struct task_struct *prev) { #ifdef CONFIG_SMP - int yield; - unsigned long flags; + int policy; /* - * fast path falls through. We have to take the runqueue lock - * unconditionally to make sure that the test of prev->state - * and setting has_cpu is atomic wrt. interrupts. It's not - * a big problem in the common case because we recently took - * the runqueue lock so it's likely to be in this processor's - * cache. + * fast path falls through. We have to clear has_cpu before + * checking prev->state to avoid a wakeup race - thus we + * also have to protect against the task exiting early. */ - spin_lock_irqsave(&runqueue_lock, flags); - yield = prev->policy & SCHED_YIELD; - prev->policy &= ~SCHED_YIELD; + task_lock(prev); + policy = prev->policy; + prev->policy = policy & ~SCHED_YIELD; prev->has_cpu = 0; + wmb(); if (prev->state == TASK_RUNNING) - goto running_again; + goto needs_resched; + out_unlock: - spin_unlock_irqrestore(&runqueue_lock, flags); + task_unlock(prev); return; /* * Slow path - we 'push' the previous process and * reschedule_idle() will attempt to find a new * processor for it. (but it might preempt the - * current process as well.) + * current process as well.) We must take the runqueue + * lock and re-check prev->state to be correct. It might + * still happen that this process has a preemption + * 'in progress' already - but this is not a problem and + * might happen in other circumstances as well. */ -running_again: - if ((prev != idle_task(smp_processor_id())) && !yield) - reschedule_idle(prev); - goto out_unlock; +needs_resched: + { + unsigned long flags; + + /* + * Avoid taking the runqueue lock in cases where + * no preemption-check is necessery: + */ + if ((prev == idle_task(smp_processor_id())) || + (policy & SCHED_YIELD)) + goto out_unlock; + + spin_lock_irqsave(&runqueue_lock, flags); + if (prev->state == TASK_RUNNING) + reschedule_idle(prev); + spin_unlock_irqrestore(&runqueue_lock, flags); + goto out_unlock; + } #else prev->policy &= ~SCHED_YIELD; #endif /* CONFIG_SMP */ @@ -588,19 +590,13 @@ still_running_back: #ifdef CONFIG_SMP /* - * maintain the per-process 'average timeslice' value. + * maintain the per-process 'last schedule' value. * (this has to be recalculated even if we reschedule to * the same process) Currently this is only used on SMP, * and it's approximate, so we do not have to maintain * it while holding the runqueue spinlock. */ - { - cycles_t t, this_slice; - - t = get_cycles(); - this_slice = t - sched_data->last_schedule; - sched_data->last_schedule = t; - } + sched_data->last_schedule = get_cycles(); /* * We drop the scheduler lock early (it's a global spinlock), @@ -705,7 +701,7 @@ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, unsigned long flags; int best_cpu, irq; - if (!q) + if (!q || !waitqueue_active(q)) goto out; best_cpu = smp_processor_id(); @@ -759,16 +755,13 @@ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, } } } - if (best_exclusive) - best_exclusive->state = TASK_RUNNING; - wq_write_unlock_irqrestore(&q->lock, flags); - if (best_exclusive) { if (sync) wake_up_process_synchronous(best_exclusive); else wake_up_process(best_exclusive); } + wq_write_unlock_irqrestore(&q->lock, flags); out: return; } @@ -1029,12 +1022,35 @@ out_unlock: asmlinkage long sys_sched_yield(void) { /* - * This process can only be rescheduled by us, - * so this is safe without any locking. + * Trick. sched_yield() first counts the number of truly + * 'pending' runnable processes, then returns if it's + * only the current processes. (This test does not have + * to be atomic.) In threaded applications this optimization + * gets triggered quite often. */ - if (current->policy == SCHED_OTHER) - current->policy |= SCHED_YIELD; - current->need_resched = 1; + + int nr_pending = nr_running; + +#if CONFIG_SMP + int i; + + // Substract non-idle processes running on other CPUs. + for (i = 0; i < smp_num_cpus; i++) + if (aligned_data[i].schedule_data.curr != idle_task(i)) + nr_pending--; +#else + // on UP this process is on the runqueue as well + nr_pending--; +#endif + if (nr_pending) { + /* + * This process can only be rescheduled by us, + * so this is safe without any locking. + */ + if (current->policy == SCHED_OTHER) + current->policy |= SCHED_YIELD; + current->need_resched = 1; + } return 0; } diff --git a/net/Makefile b/net/Makefile index fcccc4e6de43..ff79d8584f2d 100644 --- a/net/Makefile +++ b/net/Makefile @@ -7,7 +7,7 @@ O_TARGET := network.o -mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink export-objs := netsyms.o subdir-y := core ethernet diff --git a/net/bridge/br.c b/net/bridge/br.c index 3c6c9b72de70..cda2e570aa5a 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -5,7 +5,7 @@ * Authors: * Lennert Buytenhek * - * $Id: br.c,v 1.44 2000/08/04 06:08:32 davem Exp $ + * $Id: br.c,v 1.45 2000/10/22 18:26:07 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,7 +38,7 @@ void br_inc_use_count() MOD_INC_USE_COUNT; } -int __init br_init(void) +static int __init br_init(void) { printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n"); diff --git a/net/core/dev.c b/net/core/dev.c index cf40d23ed465..ae04dbcd9bbf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2231,9 +2231,9 @@ int dev_ioctl(unsigned int cmd, void *arg) /** * dev_new_index - allocate an ifindex * - * Returns a suitable unique value for a new device interface number. - * The caller must hold the rtnl semaphore to be sure it remains - * unique. + * Returns a suitable unique value for a new device interface + * number. The caller must hold the rtnl semaphore or the + * dev_base_lock to be sure it remains unique. */ int dev_new_index(void) @@ -2258,6 +2258,10 @@ static int dev_boot_phase = 1; * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate. * + * Callers must hold the rtnl semaphore. See the comment at the + * end of Space.c for details about the locking. You may want + * register_netdev() instead of this. + * * BUGS: * The locking appears insufficient to guarantee two parallel registers * will not get the same name. @@ -2405,6 +2409,10 @@ int netdev_finish_unregister(struct net_device *dev) * This function shuts down a device interface and removes it * from the kernel tables. On success 0 is returned, on a failure * a negative errno code is returned. + * + * Callers must hold the rtnl semaphore. See the comment at the + * end of Space.c for details about the locking. You may want + * unregister_netdev() instead of this. */ int unregister_netdevice(struct net_device *dev) @@ -2538,6 +2546,11 @@ extern void ip_auto_config(void); extern void dv_init(void); #endif /* CONFIG_NET_DIVERT */ + +/* + * Callers must hold the rtnl semaphore. See the comment at the + * end of Space.c for details about the locking. + */ int __init net_dev_init(void) { struct net_device *dev, **dp; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index db4f5d626aa3..d3b3702cd8f2 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.118 2000/10/19 15:51:02 davem Exp $ + * Version: $Id: af_inet.c,v 1.120 2000/10/22 16:06:56 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -474,7 +474,8 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) * (ie. your servers still start up even if your ISDN link * is temporarily down) */ - if (sysctl_ip_nonlocal_bind == 0 && + if (sysctl_ip_nonlocal_bind == 0 && + sk->protinfo.af_inet.freebind == 0 && addr->sin_addr.s_addr != INADDR_ANY && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index a82e4be1fbc1..f87921077dd8 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.52 2000/09/09 08:26:04 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.53 2000/10/22 16:06:56 davem Exp $ * * Authors: see ip.c * @@ -372,21 +372,23 @@ out: /* * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on * an IP socket. - * - * We implement IP_TOS (type of service), IP_TTL (time to live). */ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val=0,err; - if (optname == IP_PKTINFO || optname == IP_RECVTTL || - optname == IP_RECVTOS || optname == IP_RECVOPTS || - optname == IP_RETOPTS || optname == IP_TOS || - optname == IP_TTL || optname == IP_HDRINCL || - optname == IP_MTU_DISCOVER || optname == IP_RECVERR || - optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP || - optname == IP_ROUTER_ALERT) { + if (level != SOL_IP) + return -ENOPROTOOPT; + + if (((1<= sizeof(int)) { if (get_user(val, (int *) optval)) return -EFAULT; @@ -400,9 +402,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt } /* If optlen==0, it is equivalent to val == 0 */ - - if (level != SOL_IP) - return -ENOPROTOOPT; #ifdef CONFIG_IP_MROUTE if (optname >= MRT_BASE && optname <= (MRT_BASE + 10)) @@ -612,6 +611,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_ROUTER_ALERT: err = ip_ra_control(sk, val ? 1 : 0, NULL); break; + + case IP_FREEBIND: + if (optlen<1) + goto e_inval; + sk->protinfo.af_inet.freebind = !!val; + break; default: #ifdef CONFIG_NETFILTER @@ -771,6 +776,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op len -= msg.msg_controllen; return put_user(len, optlen); } + case IP_FREEBIND: + val = sk->protinfo.af_inet.freebind; + break; default: #ifdef CONFIG_NETFILTER val = nf_getsockopt(sk, PF_INET, optname, optval, diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index eae29c0b0751..fbf18ed95fc4 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -183,24 +183,24 @@ static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) static void ipip_tunnel_unlink(struct ip_tunnel *t) { - struct ip_tunnel **tp; + struct ip_tunnel **tp = ipip_bucket(t); - for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) { + write_lock_bh(&ipip_lock); + for ( ; *tp; tp = &(*tp)->next) { if (t == *tp) { - write_lock_bh(&ipip_lock); *tp = t->next; - write_unlock_bh(&ipip_lock); break; } } + write_unlock_bh(&ipip_lock); } static void ipip_tunnel_link(struct ip_tunnel *t) { struct ip_tunnel **tp = ipip_bucket(t); - t->next = *tp; write_lock_bh(&ipip_lock); + t->next = *tp; *tp = t; write_unlock_bh(&ipip_lock); } diff --git a/net/socket.c b/net/socket.c index 4b6ad8ad5fd2..58df6d92e60c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1641,10 +1641,6 @@ int sock_unregister(int family) extern void sk_init(void); -#ifdef CONFIG_BRIDGE -extern int br_init(void); -#endif - #ifdef CONFIG_WAN_ROUTER extern void wanrouter_init(void); #endif @@ -1676,14 +1672,6 @@ void __init sock_init(void) skb_init(); #endif - /* - * Ethernet bridge layer. - */ - -#ifdef CONFIG_BRIDGE - br_init(); -#endif - /* * Wan router layer. */ -- 2.39.5