From 28c24777f0e8211edfff4cf64f59edcc3893202b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:16:41 -0500 Subject: [PATCH] Import 2.1.122pre3 --- CREDITS | 27 +- Documentation/Configure.help | 934 ++++++------ Documentation/networking/arcnet-hardware.txt | 12 +- Documentation/networking/arcnet.txt | 9 +- Documentation/networking/cs89x0.txt | 2 +- Documentation/sound/ChangeLog.multisound | 63 + Documentation/sound/Wavefront | 8 +- MAINTAINERS | 12 +- arch/alpha/kernel/osf_sys.c | 2 + arch/i386/kernel/apm.c | 7 +- arch/i386/kernel/init_task.c | 3 +- arch/i386/kernel/io_apic.c | 24 +- arch/i386/kernel/irq.c | 7 +- arch/i386/kernel/ldt.c | 3 +- arch/i386/kernel/process.c | 2 +- arch/i386/kernel/ptrace.c | 10 +- arch/i386/kernel/setup.c | 3 +- arch/i386/kernel/traps.c | 11 +- arch/i386/math-emu/fpu_entry.c | 1 + arch/i386/math-emu/get_address.c | 1 + drivers/block/Makefile | 4 +- drivers/block/floppy.c | 4 +- drivers/block/loop.c | 263 ++-- drivers/cdrom/cdu31a.c | 5 +- drivers/cdrom/cm206.c | 3 + drivers/cdrom/sbpcd.c | 17 +- drivers/char/Config.in | 2 +- drivers/char/bttv.c | 4 +- drivers/net/3c523.c | 2 +- drivers/net/82596.c | 4 +- drivers/net/Config.in | 8 +- drivers/net/arc-rimi.c | 5 +- drivers/net/arcnet.c | 7 +- drivers/net/ariadne.c | 11 +- drivers/net/com20020.c | 5 +- drivers/net/com90io.c | 5 +- drivers/net/com90xx.c | 5 +- drivers/net/daynaport.c | 158 +- drivers/net/hamradio/dmascc.c | 28 +- drivers/net/hamradio/z8530.h | 6 +- drivers/net/plip.c | 2 +- drivers/nubus/nubus.c | 101 +- drivers/scsi/Config.in | 13 +- drivers/scsi/Makefile | 8 + drivers/scsi/README.ppa | 125 +- drivers/scsi/hosts.c | 28 +- drivers/scsi/imm.c | 1321 +++++++++++++++++ drivers/scsi/imm.h | 166 +++ drivers/scsi/ppa.c | 139 +- drivers/scsi/ppa.h | 97 +- drivers/scsi/scsi.c | 8 - drivers/scsi/scsi.h | 6 + drivers/sound/Config.in | 42 +- drivers/sound/Makefile | 44 + drivers/sound/ad1848.c | 1 - drivers/sound/dev_table.c | 4 + drivers/sound/mad16.c | 2 +- drivers/sound/msnd.c | 63 +- drivers/sound/msnd.h | 48 +- drivers/sound/msnd_classic.h | 2 +- drivers/sound/msnd_pinnacle.c | 976 ++++++------ drivers/sound/msnd_pinnacle.h | 2 +- drivers/sound/pss.c | 2 +- drivers/sound/sb.h | 2 +- drivers/sound/sb_card.c | 8 +- drivers/sound/sb_common.c | 14 +- drivers/sound/sb_midi.c | 2 - drivers/sound/sb_mixer.c | 5 +- drivers/sound/sequencer.c | 4 +- drivers/sound/trix.c | 5 +- drivers/sound/wavfront.c | 118 +- fs/binfmt_elf.c | 2 + fs/devpts/root.c | 3 + fs/fat/inode.c | 4 +- fs/hfs/ChangeLog | 14 + fs/hfs/file.c | 26 +- fs/hfs/file_cap.c | 2 +- fs/hfs/file_hdr.c | 6 +- fs/hfs/mdb.c | 10 +- fs/isofs/namei.c | 4 +- fs/msdos/namei.c | 408 +++-- fs/proc/array.c | 10 +- fs/sysv/balloc.c | 12 +- fs/sysv/fsync.c | 20 +- fs/sysv/inode.c | 35 +- fs/sysv/truncate.c | 18 +- fs/umsdos/dir.c | 362 +++-- fs/umsdos/emd.c | 111 +- fs/umsdos/file.c | 16 +- fs/umsdos/inode.c | 188 +-- fs/umsdos/ioctl.c | 10 +- fs/umsdos/namei.c | 516 ++++--- fs/umsdos/rdir.c | 34 +- fs/umsdos/specs | 2 + fs/umsdos/symlink.c | 86 +- {arch/i386/kernel => include/asm-i386}/desc.h | 0 include/linux/loop.h | 56 +- include/linux/proc_fs.h | 1 + include/linux/sysv_fs.h | 208 +-- include/linux/sysv_fs_i.h | 10 +- include/linux/sysv_fs_sb.h | 26 +- include/linux/umsdos_fs.p | 11 +- include/linux/videodev.h | 1 + include/linux/wavefront.h | 16 +- kernel/exit.c | 4 + kernel/ksyms.c | 1 + kernel/signal.c | 69 +- mm/memory.c | 4 +- net/Config.in | 4 +- net/ax25/af_ax25.c | 10 +- net/core/skbuff.c | 2 +- net/ipv4/tcp_input.c | 15 +- net/ipv4/udp.c | 1 + net/ipv6/af_inet6.c | 10 + net/netsyms.c | 1 + net/sunrpc/svcsock.c | 2 +- 116 files changed, 4757 insertions(+), 2639 deletions(-) create mode 100644 drivers/scsi/imm.c create mode 100644 drivers/scsi/imm.h rename {arch/i386/kernel => include/asm-i386}/desc.h (100%) diff --git a/CREDITS b/CREDITS index f62977ca8326..2d56f8b27603 100644 --- a/CREDITS +++ b/CREDITS @@ -10,11 +10,11 @@ ---------- N: Matti Aarnio -E: mea@utu.fi -D: LILO for AHA1542, modularized several of drivers/net/, -D: dynamic SLIP devices, dynamic /proc/net/, true size /proc/ksyms, -D: and other hacks.. -D: Documenting various parts of network subsystem (kernel side) +E: mea@nic.funet.fi +D: Alpha systems hacking, IPv6 and other network related stuff +D: One of assisting postmasters for vger.rutgers.edu's lists +S: (ask for current address) +S: Finland N: Werner Almesberger E: werner.almesberger@lrc.di.epfl.ch @@ -1403,7 +1403,8 @@ S: Albuquerque, New Mexico 87131 S: USA N: Avery Pennarun -E: apenwarr@bond.net +E: apenwarr@worldvisions.ca +W: http://www.worldvisions.ca/~apenwarr/ D: ARCnet driver D: "make xconfig" improvements D: Various minor hacking @@ -1696,6 +1697,14 @@ S: 22 Irvington Cres. S: Willowdale, Ontario S: Canada M2N 2Z1 +N: Adrian Sun +E: asun@u.washington.edu +D: hfs support +D: alpha rtc port, random appletalk fixes +S: Department of Zoology, University of Washington +S: Seattle, WA 98195-1800 +S: USA + N: Tommy Thorn E: Tommy.Thorn@irisa.fr W: http://www.irisa.fr/prive/thorn/index.html @@ -1883,9 +1892,9 @@ S: The Netherlands N: Tim Waugh E: tim@cyberelk.demon.co.uk D: Co-architect of the parallel-port sharing system -S: 110 Twyford Road -S: EASTLEIGH -S: SO50 4HN +S: 4 Fox Close +S: Bishopstoke +S: SO50 8NB S: United Kingdom N: Juergen Weigert diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 9b1a00fa9d09..b265dbd32378 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -113,14 +113,14 @@ CONFIG_MATH_EMULATION If you are not sure, say Y; apart from resulting in a 45kB bigger kernel, it won't hurt. -Normal floppy disk support +Normal PC floppy disk support CONFIG_BLK_DEV_FD - If you want to use your floppy disk drive(s) under Linux, say - Y. Information about this driver, especially important for IBM + If you want to use the floppy disk drive(s) of your PC under Linux, + say Y. Information about this driver, especially important for IBM Thinkpad users, is contained in drivers/block/README.fd. This file also contains the location of the Floppy driver FAQ as well as location of the fdutils package used to configure additional - parameters of the driver at run time. + parameters of the driver at run time. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -174,12 +174,13 @@ CONFIG_BLK_DEV_LOOP ftp://ftp.replay.com/pub/crypto/linux/all, and then you need to say Y to this option. - Note that alternative ways use encrypted filesystems are provided by - the cfs package, which can be gotten via FTP (user: anonymous) from - ftp://ftp.replay.com/pub/crypto/disk/, and the newer tcfs package, - available at http://tcfs.dia.unisa.it/. These do not require any - kernel support and you can say N here if you want to use one of - them. + Note that alternative ways to use encrypted filesystems are provided + by the cfs package, which can be gotten via FTP (user: anonymous) + from ftp://ftp.replay.com/pub/crypto/disk/, and the newer tcfs + package, available at http://tcfs.dia.unisa.it/. You do not need to + say Y here if you want to use one of these. However, using cfs + requires saying Y to "NFS filesystem support" below while using tcfs + requires applying a kernel patch. To use the loop device, you need the losetup utility and a recent version of the mount program, both contained in the util-linux @@ -199,7 +200,7 @@ CONFIG_BLK_DEV_LOOP Network Block Device support CONFIG_BLK_DEV_NBD Saying Y here will allow your computer to be a client for network - block devices - it will be able to use block devices exported by + block devices -- it will be able to use block devices exported by servers (mount filesystems on them etc.). Communication between client and server works over TCP/IP networking, but to the client program this is hidden: it looks like a regular local file access to @@ -285,7 +286,7 @@ CONFIG_BLK_DEV_IDEDISK Include IDE/ATAPI CDROM support CONFIG_BLK_DEV_IDECD If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is - a new protocol used by IDE CDROM and TAPE drives, similar to the + a newer protocol used by IDE CDROM and TAPE drives, similar to the SCSI protocol. Most new CDROM drives use ATAPI, including the NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI double(2X), quad(4X), and six(6X) speed drives. @@ -311,7 +312,7 @@ CONFIG_BLK_DEV_IDECD Include IDE/ATAPI TAPE support CONFIG_BLK_DEV_IDETAPE If you have an IDE tape drive using the ATAPI protocol, say Y. - ATAPI is a new protocol used by IDE tape and CDROM drives, similar + ATAPI is a newer protocol used by IDE tape and CDROM drives, similar to the SCSI protocol. If you say Y here, the tape drive will be identified at boot time @@ -329,7 +330,7 @@ CONFIG_BLK_DEV_IDETAPE Include IDE/ATAPI FLOPPY support CONFIG_BLK_DEV_IDEFLOPPY If you have an IDE floppy drive which uses the ATAPI protocol, say - Y. ATAPI is a new protocol used by IDE CDROM/tape/floppy drives, + Y. ATAPI is a newer protocol used by IDE CDROM/tape/floppy drives, similar to the SCSI protocol. IDE floppy drives include the LS-120 and the ATAPI ZIP (ATAPI PD-CD/CDR drives are not supported by this driver; support for PD-CD/CDR drives is available if you say Y to @@ -417,11 +418,13 @@ Generic PCI bus-master DMA support CONFIG_BLK_DEV_IDEDMA If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and is capable of bus-master DMA operation (most Pentium PCI systems), - you will want to say Y here to reduce CPU overhead. - You can use the "hdparm" utility to enable DMA for drives which - were not enabled automatically. You can get the latest version of - the hdparm utility via anonymous FTP from - ftp://sunsite.unc.edu/pub/Linux/system/hardware/. + you will want to say Y here to reduce CPU overhead. You can then use + the "hdparm" utility to enable DMA for drives for which it was not + enabled automatically. By default, DMA is not enabled automatically + for these drives, but you can change that by saying Y to the + following question "Use DMA by default when available". You can get + the latest version of the hdparm utility via anonymous FTP from + ftp://sunsite.unc.edu/pub/Linux/system/hardware/. Read the comments at the beginning of drivers/block/idedma.c and the file Documentation/ide.txt for more information. @@ -435,6 +438,7 @@ CONFIG_IDEDMA_AUTO about a couple of cases where buggy hardware may have caused damage, the default is now to NOT use DMA automatically. To revert to the previous behaviour, say Y to this question. + If you suspect your hardware is at all flakey, say N here. Do NOT email the IDE kernel people regarding this issue! @@ -576,7 +580,7 @@ CONFIG_PARIDE etc.). Parallel port IDE disks -CONFIG_PARIDE_PD +CONFIG_PARIDE_PD This option enables the high-level driver for IDE-type disk devices connected through a parallel port. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the @@ -588,7 +592,7 @@ CONFIG_PARIDE_PD hard drives from MicroSolutions. Parallel port ATAPI CD-ROMs -CONFIG_PARIDE_PCD +CONFIG_PARIDE_PCD This option enables the high-level driver for ATAPI CD-ROM devices connected through a parallel port. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the @@ -602,7 +606,7 @@ CONFIG_PARIDE_PCD on CDROMs. Parallel port ATAPI disks -CONFIG_PARIDE_PF +CONFIG_PARIDE_PF This option enables the high-level driver for ATAPI disk devices connected through a parallel port. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the @@ -640,7 +644,7 @@ CONFIG_PARIDE_PG the required patches to cdrecord. ATEN EH-100 protocol -CONFIG_PARIDE_ATEN +CONFIG_PARIDE_ATEN This option enables support for the ATEN EH-100 parallel port IDE protocol. This protocol is used in some inexpensive low performance parallel port kits made in Hong Kong. If you chose to build PARIDE @@ -651,7 +655,7 @@ CONFIG_PARIDE_ATEN support. MicroSolutions backpack protocol -CONFIG_PARIDE_BPCK +CONFIG_PARIDE_BPCK This option enables support for the MicroSolutions backpack parallel port IDE protocol. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the protocol @@ -660,7 +664,7 @@ CONFIG_PARIDE_BPCK a high-level driver for the type of device that you want to support. DataStor Commuter protocol -CONFIG_PARIDE_COMM +CONFIG_PARIDE_COMM This option enables support for the Commuter parallel port IDE protocol from DataStor. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the protocol @@ -669,7 +673,7 @@ CONFIG_PARIDE_COMM a high-level driver for the type of device that you want to support. DataStor EP-2000 protocol -CONFIG_PARIDE_DSTR +CONFIG_PARIDE_DSTR This option enables support for the EP-2000 parallel port IDE protocol from DataStor. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the protocol @@ -678,37 +682,37 @@ CONFIG_PARIDE_DSTR a high-level driver for the type of device that you want to support. Shuttle EPAT/EPEZ protocol -CONFIG_PARIDE_EPAT - This option enables support for the EPAT parallel port IDE - protocol. EPAT is a parallel port IDE adapter manufactured by - Shuttle Technology and widely used in devices from major vendors - such as Hewlett-Packard, SyQuest, Imation and Avatar. If you - chose to build PARIDE support into your kernel, you may answer Y - here to build in the protocol driver, otherwise you should answer M - to build it as a loadable module. The module will be called epat.o. - You must also have a high-level driver for the type of device that - you want to support. +CONFIG_PARIDE_EPAT + This option enables support for the EPAT parallel port IDE protocol. + EPAT is a parallel port IDE adapter manufactured by Shuttle + Technology and widely used in devices from major vendors such as + Hewlett-Packard, SyQuest, Imation and Avatar. If you chose to build + PARIDE support into your kernel, you may answer Y here to build in + the protocol driver, otherwise you should answer M to build it as a + loadable module. The module will be called epat.o. You must also + have a high-level driver for the type of device that you want to + support. Shuttle EPIA protocol -CONFIG_PARIDE_EPIA - This option enables support for the (obsolete) EPIA parallel port - IDE protocol from Shuttle Technology. This adapter can still be found - in some no-name kits. If you chose to build PARIDE support into your - kernel, you may answer Y here to build in the protocol driver, - otherwise you should answer M to build it as a loadable module. - The module will be called epia.o. You must also have a high-level - driver for the type of device that you want to support. +CONFIG_PARIDE_EPIA + This option enables support for the (obsolete) EPIA parallel port + IDE protocol from Shuttle Technology. This adapter can still be + found in some no-name kits. If you chose to build PARIDE support + into your kernel, you may answer Y here to build in the protocol + driver, otherwise you should answer M to build it as a loadable + module. The module will be called epia.o. You must also have a + high-level driver for the type of device that you want to support. FIT TD-2000 protocol CONFIG_PARIDE_FIT2 - This option enables support for the TD-2000 parallel port IDE protocol - from Fidelity International Technology. This is a simple (low speed) - adapter that is used in some portable hard drives. If you chose to - build PARIDE support into your kernel, you may answer Y here to - build in the protocol driver, otherwise you should answer M to - build it as a loadable module. The module will be called ktti.o. - You must also have a high-level driver for the type of device - that you want to support. + This option enables support for the TD-2000 parallel port IDE + protocol from Fidelity International Technology. This is a simple + (low speed) adapter that is used in some portable hard drives. If + you chose to build PARIDE support into your kernel, you may answer Y + here to build in the protocol driver, otherwise you should answer M + to build it as a loadable module. The module will be called ktti.o. + You must also have a high-level driver for the type of device that + you want to support. FIT TD-3000 protocol CONFIG_PARIDE_FIT3 @@ -722,7 +726,7 @@ CONFIG_PARIDE_FIT3 of device that you want to support. FreeCom power protocol -CONFIG_PARIDE_FRPW +CONFIG_PARIDE_FRPW This option enables support for the Freecom power parallel port IDE protocol. If you chose to build PARIDE support into your kernel, you may answer Y here to build in the protocol driver, otherwise you @@ -731,15 +735,15 @@ CONFIG_PARIDE_FRPW of device that you want to support. KingByte KBIC-951A/971A protocols -CONFIG_PARIDE_KBIC - This option enables support for the KBIC-951A and KBIC-971A parallel - port IDE protocols from KingByte Information Corp. KingByte's adapters - appear in many no-name portable disk and CD-ROM products, especially - in Europe. If you chose to build PARIDE support into your kernel, you - may answer Y here to build in the protocol driver, otherwise you should - answer M to build it as a loadable module. The module will be called - kbic.o. You must also have a high-level driver for the type of device - that you want to support. +CONFIG_PARIDE_KBIC + This option enables support for the KBIC-951A and KBIC-971A parallel + port IDE protocols from KingByte Information Corp. KingByte's + adapters appear in many no-name portable disk and CD-ROM products, + especially in Europe. If you chose to build PARIDE support into your + kernel, you may answer Y here to build in the protocol driver, + otherwise you should answer M to build it as a loadable module. The + module will be called kbic.o. You must also have a high-level driver + for the type of device that you want to support. KT PHd protocol CONFIG_PARIDE_KTTI @@ -753,7 +757,7 @@ CONFIG_PARIDE_KTTI support. OnSpec 90c20 protocol -CONFIG_PARIDE_ON20 +CONFIG_PARIDE_ON20 This option enables support for the (obsolete) 90c20 parallel port IDE protocol from OnSpec (often marketed under the ValuStore brand name). If you chose to build PARIDE support into your kernel, you @@ -763,7 +767,7 @@ CONFIG_PARIDE_ON20 type of device that you want to support. OnSpec 90c26 protocol -CONFIG_PARIDE_ON26 +CONFIG_PARIDE_ON26 This option enables support for the 90c26 parallel port IDE protocol from OnSpec Electronics (often marketed under the ValuStore brand name). If you chose to build PARIDE support into your kernel, you @@ -848,24 +852,6 @@ CONFIG_MD_RAID5 want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say Y. -IDE card support -CONFIG_BLK_DEV_IDE_CARDS - On Acorn systems, say Y here if you wish to use an IDE interface - expansion card. If you do not or are unsure, say N. - -ICS IDE interface -CONFIG_BLK_DEV_IDE_ICS - On Acorn systems, say Y here if you wish to use the ICS IDE - interface card. This is not required for ICS partition support. If - you are unsure, say. - -ADFS partition support -CONFIG_BLK_DEV_PART - This allows Linux on Acorn systems to determine its partitions in - the 'non-ADFS' partition area of the hard disk - usually located - after the ADFS partition. You are probably using this system, so - you should say Y here. - Boot support (linear, striped) CONFIG_MD_BOOT To boot with an initial linear or striped md device you have to say @@ -1008,7 +994,7 @@ CONFIG_FIREWALL network think they're talking to a remote computer, while in reality the traffic is redirected by your Linux firewall to a local proxy server). - + Make sure to say N to "Fast switching" below if you intend to say Y here. @@ -1110,7 +1096,7 @@ CONFIG_ALPHA_SRM Non-standard serial port support CONFIG_SERIAL_NONSTANDARD - Say Y here if you have any non-standard serial boards --- boards + Say Y here if you have any non-standard serial boards -- boards which aren't supported using the standard "dumb" serial driver. This includes intelligent serial boards such as Cyclades, Digiboards, etc. These are usually used for systems that need many @@ -1170,26 +1156,6 @@ CONFIG_HUB6 Say Y here to enable support in the dumb serial driver to support the HUB6 card. -Unix98 PTY support -CONFIG_UNIX98_PTYS - Linux traditionally uses BSD-like /dev/ptyxx and /dev/ttyxx names - for pseudo-ttys (PTYs). This scheme has a number or problems. The - GNU C library 2.1 and later, however, supports the Unix98 naming - standard, using a cloning device /dev/ptmx and numbered devices in a - subdirectory /dev/pts/xxx. The device nodes in /dev/pts can be - automatically generated by the devpts virtual filesystem. - - Say Y here if you are uncertain, unless you are very short on memory. - -Maximum number of Unix98 PTYs in use (0-2048) -CONFIG_UNIX98_PTY_COUNT - The maximum number of Unix98 PTYs that can be used at any one time. - The default is 256, and should be enough for desktop systems, - however, server machines which support incoming telnet/rlogin/ssh - connections may want to increase this. When not in use, each - additional set of 256 PTYs occupy approximately 8K of kernel memory - on 32-bit architectures. - TGA Console Support CONFIG_TGA_CONSOLE Many Alpha systems (e.g the Multia) are shipped with a graphics card @@ -1328,7 +1294,7 @@ CONFIG_BINFMT_ELF want to say Y here. Information about ELF is on the WWW at - http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (To browse the + http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (to browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). If you find that after upgrading from Linux kernel 1.2 and saying Y here, you still can't run any ELF @@ -1382,8 +1348,8 @@ CONFIG_BINFMT_JAVA any other Linux program: by simply typing in its name. (You also need to have the JDK installed for this to work). As more and more Java programs become available, the use for this will gradually - increase. You can even execute HTML files containing JAVA applets (= - JAVA binaries) if those files start with the string + increase. You can even execute HTML files containing JAVA applets + (= JAVA binaries) if those files start with the string "". If you want to use this, say Y here and read Documentation/java.txt. @@ -1412,12 +1378,15 @@ CONFIG_BINFMT_EM86 Kernel support for MISC binaries CONFIG_BINFMT_MISC - This enables the possibility to plug wrapper-driven binary formats - into the kernel. You will like this especially when you use programs - that need an interpreter to run like Java, Python or Emacs-Lisp. - Once you have registered such a binary class with the kernel, you - can start such a program simply by typing in its name; Linux will - feed it to the correct interpreter. + If you say Y here, it will be possible to plug wrapper-driven binary + formats into the kernel. You will like this especially when you use + programs that need an interpreter to run like Java, Python or + Emacs-Lisp. It's also useful if you often run DOS executables under + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). Once you have + registered such a binary class with the kernel, you can start one of + those programs simply by typing in its name at a shell prompt; Linux + will automatically feed it to the correct interpreter. If you say Y here, you won't need "Kernel support for JAVA binaries" (CONFIG_BINFMT_JAVA) or "Kernel support for Linux/Intel ELF @@ -1428,10 +1397,10 @@ CONFIG_BINFMT_MISC Documentation/java.txt for information about how to include Java support. - You must enable the "proc filesystem support" (CONFIG_PROC_FS) to + You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to use this part of the kernel. - You may answer M for module support and later load the module when + You may say M here for module support and later load the module when you have use for it; the module is called binfmt_misc.o. If you don't know what to answer at this point, say Y. @@ -1503,20 +1472,26 @@ CONFIG_FB hardware. It represents the frame buffer of some video hardware and allows application software to access the graphics hardware through a well-defined interface, so the software doesn't need to know - anything about the low-level (hardware register) stuff. This works - across the different architectures supported by Linux and makes the - implementation of application programs easier and more portable; at - this point, an X server exists which uses the frame buffer device - exclusively. - + anything about the low-level (hardware register) stuff. + + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + The device is accessed through special device nodes, usually located in the /dev directory, i.e. /dev/fb*. - Please read the file Documentation/fb/framebuffer.txt for more - information. + You need an utility program called fbset to make full use of frame + buffer devices. Please read the file + Documentation/fb/framebuffer.txt for more information. - If you want to play with it, say Y here and to the driver for your - graphics board, below. If unsure, say N. + If you want to play with it, say Y here and also to the driver for + your graphics board, below. If unsure, say N, unless you are + compiling a kernel for a non-X86 architecture, in which case you + should say Y. Acorn VIDC support CONFIG_FB_ACORN @@ -1555,33 +1530,34 @@ CONFIG_FB_AMIGA_AGA Amiga CyberVision support CONFIG_FB_CYBER - This enables support for the Cybervision 64 graphics card from Phase5. - Please note that its use is not all that intuitive (i.e. if you have - any questions, be sure to ask!). Say N unless you have a Cybervision - 64 or plan to get one before you next recompile the kernel. - Please note that this driver DOES NOT support the Cybervision 64 3D - card, as they use incompatible video chips. + This enables support for the Cybervision 64 graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64 or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the + Cybervision 64 3D card, as they use incompatible video chips. Amiga CyberVision3D support (EXPERIMENTAL) CONFIG_FB_VIRGE - This enables support for the Cybervision 64/3D graphics card from Phase5. - Please note that its use is not all that intuitive (i.e. if you have - any questions, be sure to ask!). Say N unless you have a Cybervision - 64/3D or plan to get one before you next recompile the kernel. - Please note that this driver DOES NOT support the older Cybervision 64 - card, as they use incompatible video chips. + This enables support for the Cybervision 64/3D graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64/3D or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the older + Cybervision 64 card, as they use incompatible video chips. Amiga RetinaZ3 support (EXPERIMENTAL) CONFIG_FB_RETINAZ3 - This enables support for the Retina Z3 graphics card. Say N unless you - have a Retina Z3 or plan to get one before you next recompile the kernel. + This enables support for the Retina Z3 graphics card. Say N unless + you have a Retina Z3 or plan to get one before you next recompile + the kernel. Amiga CLgen driver (EXPERIMENTAL) CONFIG_FB_CLGEN - This enables support for Cirrus Logic GD542x/543x based boards on Amiga: - SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. Say N - unless you have such a graphics board or plan to get one before you next - recompile the kernel. + This enables support for Cirrus Logic GD542x/543x based boards on + Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. Atari native chipset support CONFIG_FB_ATARI @@ -1628,8 +1604,10 @@ CONFIG_FB_HP300 VGA chipset support (text only) CONFIG_FB_VGA This is the frame buffer device driver for generic VGA chips. This - driver works only in text mode; if you want graphics mode, say Y to - "VESA VGA graphics console" as well. + driver works only in text mode and is deprecated; it is preferable + to say Y to "VGA text console" instead. For a graphical frame buffer + device driver that works for VGA cards, say Y to "VESA VGA graphics + console" below. TGA frame buffer support' CONFIG_FB_TGA @@ -1638,15 +1616,17 @@ CONFIG_FB_TGA VESA VGA graphics console CONFIG_FB_VESA - This is the frame buffer device driver for generic VESA graphic cards. - Please read Documentation/fb/vesafb.txt. + This is the frame buffer device driver for generic VESA graphic + cards. You will get a boot time penguin logo at no additional cost. + Please read Documentation/fb/vesafb.txt. If unsure, say Y. MDA dual-headed support CONFIG_FB_MDA Say Y here if you have an old MDA or monochrome Hercules graphics - adapter in your system acting as a second head ( = video card). Do - not enable this driver if your MDA card is the primary card in your - system; the normal VGA driver will handle it. + adapter in your system acting as a second head ( = video card). You + will then be able to use two monitors with your Linux system. Do not + say Y here if your MDA card is the primary card in your system; the + normal VGA driver will handle it. This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). @@ -1683,13 +1663,14 @@ CONFIG_FB_TCX Virtual Frame Buffer support (ONLY FOR TESTING!) CONFIG_FB_VIRTUAL - This is a `virtual' frame buffer device. It operates on a chunk of - unswapable kernel memory instead of on the memory of a graphics board. - This means you cannot see any output sent to this frame buffer device, - while it does consume precious memory. The main use of this frame - buffer device is testing and debugging the frame buffer subsystem. Do - NOT enable it for normal systems! To protect the innocent, it has to - be enabled explicitly on boot time using the kernel option `video=vfb:'. + This is a `virtual' frame buffer device. It operates on a chunk of + unswapable kernel memory instead of on the memory of a graphics + board. This means you cannot see any output sent to this frame + buffer device, while it does consume precious memory. The main use + of this frame buffer device is testing and debugging the frame + buffer subsystem. Do NOT enable it for normal systems! To protect + the innocent, it has to be enabled explicitly at boot time using the + kernel option `video=vfb:'. This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). @@ -1706,12 +1687,12 @@ CONFIG_FBCON_ADVANCED drivers. Note that they are used for text console output only; they are NOT needed for graphical applications. - If you do not enable this option, the needed low level drivers are - automatically enabled, depending on what frame buffer devices you - selected. This is recommended for most users. + If you say N here, the needed low level drivers are automatically + enabled, depending on what frame buffer devices you selected above. + This is recommended for most users. - If you enable this option, you have more fine-grained control over which - low level drivers are enabled. You can e.g. leave out low level drivers + If you say Y here, you have more fine-grained control over which low + level drivers are enabled. You can e.g. leave out low level drivers for color depths you do not intend to use for text consoles. Low level frame buffer console drivers can be modules ( = code which @@ -1785,13 +1766,13 @@ CONFIG_FBCON_IPLAN2P8 Mac variable bpp packed pixels support CONFIG_FBCON_MAC This is the low level frame buffer console driver for 1/2/4/8/16/32 - bits per pixel packed pixels on Mac. It supports variable fontwidths + bits per pixel packed pixels on Mac. It supports variable font widths for low resolution screens. VGA characters/attributes support CONFIG_FBCON_VGA - This is the low level frame buffer console driver for VGA text mode, as - used by vgafb. + This is the low level frame buffer console driver for VGA text mode; + it is used if you said Y to "VGA chipset support (text only)" above. Parallel-port support CONFIG_PARPORT @@ -1809,8 +1790,8 @@ CONFIG_PARPORT It is possible to share a single parallel port among several devices and it is safe to compile all the corresponding drivers into the - kernel. If you want to compile parallel port support as a module ( = - code which can be inserted in and removed from the running kernel + kernel. If you want to compile parallel port support as a module + ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called parport.o. If you have more than one parallel port and want to specify which port and IRQ to be used by @@ -1851,8 +1832,8 @@ CONFIG_CPU_LITTLE_ENDIAN Plug and Play support CONFIG_PNP - Plug and Play support allows the kernel to automatically configure some - peripheral devices. Say Y to enable PnP. + Plug and Play support allows the kernel to automatically configure + some peripheral devices. Say Y to enable PnP. Auto-probe for parallel devices CONFIG_PNP_PARPORT @@ -2088,11 +2069,10 @@ CONFIG_IP_FIREWALL IP: firewall packet netlink device CONFIG_IP_FIREWALL_NETLINK - If you say Y here and then packets hit your Linux firewall and are - blocked, the first 128 bytes of each such packet are passed on to - optional user space monitoring software that can then look for - attacks and take actions such as paging the administrator of the - site. + If you say Y here, then the first 128 bytes of each packet that hit + your Linux firewall and was blocked are passed on to optional user + space monitoring software that can then look for attacks and take + actions such as paging the administrator of the site. To use this, you need to create a character special file under /dev with major number 36 and minor number 3 using mknod ("man mknod"), @@ -2218,13 +2198,14 @@ CONFIG_IP_MASQUERADE http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. If you say Y here, you should also say Y to "IP: always defragment", - below. If you say Y here, then the modules ip_masq_ftp.o (for ftp - transfers through the firewall), ip_masq_irc.o (for irc chats - through the firewall), and ip_masq_raudio.o (for RealAudio downloads - through the firewall) will automatically be compiled. Modules are - pieces of code which can be inserted in and removed from the running - kernel whenever you want; read Documentation/modules.txt for - details. + below. + + If you say Y here, then the modules ip_masq_ftp.o (for ftp transfers + through the firewall), ip_masq_irc.o (for irc chats through the + firewall), and ip_masq_raudio.o (for RealAudio downloads through the + firewall) will automatically be compiled. Modules are pieces of code + which can be inserted in and removed from the running kernel + whenever you want; read Documentation/modules.txt for details. IP: ICMP masquerading CONFIG_IP_MASQUERADE_ICMP @@ -2441,16 +2422,16 @@ CONFIG_IP_NOSR IP: Allow large windows (not recommended if <16Mb of memory) CONFIG_SKB_LARGE - On high speed, long distance networks the performance limit on + On high speed, long distance networks the performance limit on networking becomes the amount of data a machine can buffer until the other end confirms its reception. (At 45Mbit/second there are a lot - of bits between New York and London ..). This option allows larger - amounts of data to be "in flight" at a given time. It also means a user - process can require a lot more memory for network buffers and thus this - option is best only used on machines with 16Mb of memory or higher. - Unless you are using long links with end to end speeds of over 2Mbit - a second or satellite links this option will make no difference to - performance. + of bits between New York and London ...). This option allows larger + amounts of data to be "in flight" at a given time. It also means a + user process can require a lot more memory for network buffers and + thus this option is best used only on machines with 16Mb of memory + or higher. Unless you are using long links with end to end speeds of + over 2Mbit a second or satellite links this option will make no + difference to performance. Unix domain sockets CONFIG_UNIX @@ -2484,13 +2465,10 @@ CONFIG_IPV6 and the file net/ipv6/README in the kernel source. If you want to use IPv6, please upgrade to the newest net-tools as - given in Documentation/Changes. + given in Documentation/Changes. You will still be able to do regular + IPv4 networking as well. - The IPv6 support is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called ipv6.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. It's safe to - say N for now. + It is safe to say N here for now. IPv6: enable EUI-64 token format CONFIG_IPV6_EUI64 @@ -2522,7 +2500,7 @@ CONFIG_IPX to access Novell NetWare file or print servers using the Linux Novell client ncpfs (available via FTP (user: anonymous) from ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within - the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the former, you'll also have to say Y to "NCP filesystem support", below. @@ -2533,9 +2511,9 @@ CONFIG_IPX To turn your Linux box into a fully featured NetWare file server and IPX router, say Y here and fetch either lwared from - ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from - ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the - IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. + ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe + from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, + read the IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. General information about how to connect Linux, Windows machines and Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to @@ -2774,9 +2752,9 @@ CONFIG_ROSE A comprehensive listing of all the software for Linux amateur radio users as well as information about how to configure an AX.25 port is contained in the AX25-HOWTO, available via FTP (user: anonymous) in - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You also might want to check - out the file Documentation/networking/ax25.txt. More information - about digital amateur radio in general is on the WWW at + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You also might want to + check out the file Documentation/networking/ax25.txt. More + information about digital amateur radio in general is on the WWW at http://www.tapr.org/tapr/html/pkthome.html (To browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). @@ -2836,9 +2814,9 @@ CONFIG_DMASCC Currently, this driver supports Ottawa PI/PI2 (http://hydra.carleton.ca/info/pi2.html) and Gracilis PackeTwin - (http://www.paccomm.com/) boards. They are detected automatically. - If you have one of these cards, say Y here and read the HAM-HOWTO, - available via FTP (user: anonymous) in + (http://www.paccomm.com/gracilis.html) boards. They are detected + automatically. If you have one of these cards, say Y here and read + the AX25-HOWTO, available via FTP (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/. This driver can operate multiple boards simultaneously. If you compile @@ -2862,11 +2840,11 @@ CONFIG_DMASCC Z8530 SCC driver for AX.25 CONFIG_SCC These cards are used to connect your Linux box to an amateur radio - in order to communicate with other computers. If you want to use + in order to communicate with other computers. If you want to use this, read Documentation/networking/z8530drv.txt and the - AX.25-HOWTO, available via FTP (user: anonymous) at - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y to - "Amateur Radio AX.25 Level 2" support. + AX25-HOWTO, available via FTP (user: anonymous) at + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y + to "Amateur Radio AX.25 Level 2" support. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -3383,7 +3361,7 @@ CONFIG_OVERRIDE_CMDS Maximum number of commands per LUN CONFIG_AIC7XXX_CMDS_PER_LUN Specify the maximum number of commands you would like to allocate - per LUN (a LUN is a Logical Unit Number - some physical SCSI devices, + per LUN (a LUN is a Logical Unit Number -- some physical SCSI devices, e.g. CD jukeboxes, act logically as several separate units, each of which gets its own number). @@ -3618,7 +3596,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are respectively the maximum data transfer rates in mega-transfers per second for each class. For example, a FAST-20 Wide 16 device is able - to transfer data at 40 million 16 bit packets per second for a total + to transfer data at 20 million 16 bit packets per second for a total rate of 40 MB/s. You may specify 0 if you want to only use asynchronous data @@ -3753,26 +3731,27 @@ Standard SCSI-order CONFIG_IBMMCA_SCSI_ORDER_STANDARD In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks are assigned to the drive letters, starting with the lowest SCSI-id - (physical number - pun) to be drive C:, as seen from DOS and similar - operating systems. When looking into papers describing the + (physical number -- pun) to be drive C:, as seen from DOS and + similar operating systems. When looking into papers describing the ANSI-SCSI-standard, this assignment of drives appears to be wrong. - The SCSI-standard follows a hardware-hierarchy which says that - id 7 has the highest priority and id 0 the lowest. Therefore, the - host adapters are still today everywhere placed as SCSI-id 7 by - default. In the SCSI-standard, the drive letters express the priority - of the disk. C: should be the hard disk, or a partition on it, with the + The SCSI-standard follows a hardware-hierarchy which says that id 7 + has the highest priority and id 0 the lowest. Therefore, the host + adapters are still today everywhere placed as SCSI-id 7 by default. + In the SCSI-standard, the drive letters express the priority of the + disk. C: should be the hard disk, or a partition on it, with the highest priority. This must therefore be the disk with the highest SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the original definition of the SCSI-standard as also industrial- and process-control-machines, like VME-CPUs running under realtime-OSs (e.g. LynxOS, OS9) do. - If you like to run Linux on your MCA-machine with the same assignment - of hard disks as seen from e.g. DOS or OS/2 on your machine, which - is in addition conformant to the SCSI-standard, you must say Y here. - This is also necessary for MCA-Linux-users who want to keep downward- - compatibility to older releases of the IBM-MCA-SCSI-driver (older than - driver-release 2.00 and older than June 1997). + If you like to run Linux on your MCA-machine with the same + assignment of hard disks as seen from e.g. DOS or OS/2 on your + machine, which is in addition conformant to the SCSI-standard, you + must say Y here. This is also necessary for MCA-Linux users who want + to keep downward- compatibility to older releases of the + IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than + June 1997). If you like to have the lowest SCSI-id assigned as drive C:, as modern SCSI-BIOSes do, which does not conform to the standard, but @@ -4073,6 +4052,7 @@ CONFIG_FC4 support, as well as the drivers for the storage array itself and for the interface adapter such as SOC. This subsystem could even serve for IP networking, with some code extensions. + If unsure, say N. Sun SOC @@ -4124,7 +4104,7 @@ CONFIG_SCSI_CUMANA_2 EcoSCSI support CONFIG_SCSI_ECOSCSI - This enables support for the EcoSCSI card - a small card that sits in + This enables support for the EcoSCSI card -- a small card that sits in the Econet socket. If you have an Acorn system with one of these, say Y. If unsure, say N. @@ -4354,58 +4334,6 @@ CONFIG_WAVELAN module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. -AIMSlab RadioTrack (aka RadioReveal) support -CONFIG_RADIO_RTRACK - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - In order to control your radio card, you will need to use programs - that are compatible with the Video for Linux API. Information on - this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, - you need to have access to a machine on the Internet that has a - program like lynx or netscape. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called radio-aimslab.o. - -RadioTrack i/o port -CONFIG_RADIO_RTRACK_PORT - Enter either 0x30f or 0x20f here. The card default is 0x30f, if you - haven't changed the jumper setting on the card. - -Aztech/Packard Bell Radio -CONFIG_RADIO_AZTECH - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called radio-aztech.o. - -Aztech/Packard Bell radio card i/o port -CONFIG_RADIO_AZTECH_PORT - Enter either 0x350 or 0x358 here. The card default is 0x350, if you - haven't changed the setting of jumper JP3 on the card. Removing the - jumper sets the card to 0x358. - -SF16FMI Radio -CONFIG_RADIO_SF16FMI - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called radio-sf16fmi.o - -SF16FMI I/O port (0x284 or 0x384) -CONFIG_RADIO_SF16FMI_PORT - Enter the I/O port of your SF16FMI radio card. - LAPB over Ethernet driver CONFIG_LAPBETHER This is a driver for a pseudo device (typically called /dev/lapb0) @@ -4645,7 +4573,7 @@ Forwarding between high speed interfaces CONFIG_NET_HW_FLOWCONTROL This option enables NIC (Network Interface Card) hardware throttling during periods of extremal congestion. At the moment only a couple - of device drivers support it (really only one ---tulip, modified + of device drivers support it (really only one -- tulip, modified 8390 can be found at ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). Really, this option is applicable to any machine attached to a fast enough @@ -4827,11 +4755,17 @@ CONFIG_NET_PROFILE performance will be written to /proc/net/profile. If you don't know what it is about, you don't need it: say N. +#Comtrol Hostess SV-11 support +#CONFIG_HOSTESS_SV11 +### +### I don't know what this is. +### + WAN Drivers CONFIG_WAN_DRIVERS Say Y to this option if your Linux box contains a WAN card and you - are planning to use the box as a WAN ( = Wide Area Network) router ( - = device used to interconnect local area networks over wide area + are planning to use the box as a WAN ( = Wide Area Network) router + ( = device used to interconnect local area networks over wide area communication links, such as leased lines and public data networks, e.g. X.25 and frame relay) and you will be offered a list of drivers for WAN cards currently available. For more information, read @@ -5650,7 +5584,7 @@ CONFIG_TLAN Devices currently supported by this driver are Compaq Netelligent, Compaq NetFlex and Olicom cards. Please read the file - Documentation/tlan.txt for details. + Documentation/networking/tlan.txt for more details. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -5974,8 +5908,8 @@ Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support CONFIG_AZTCD This is your driver if you have an Aztech CDA268-01A, Orchid CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCDROM CR520 or - CR540 CDROM drive. This driver - just like all these CDROM drivers - - is NOT for CDROM drives with IDE/ATAPI interfaces, such as Aztech + CR540 CDROM drive. This driver -- just like all these CDROM drivers + -- is NOT for CDROM drives with IDE/ATAPI interfaces, such as Aztech CDA269-031SE. Please read the file Documentation/cdrom/aztcd. If you say Y here, you should also say Y or M to "ISO 9660 CDROM @@ -6143,8 +6077,10 @@ CONFIG_EXT2_FS directories on ext2 filesystems, use chattr ("man chattr"). Ext2fs partitions can be read from within DOS using the ext2tool - package available via FTP (user: anonymous) from - ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2. + package (available via FTP (user: anonymous) from + ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2) and from + within Windows 95 and Windows NT using the ex2fs explorer available + from http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm. If you want to compile this filesystem as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -6198,7 +6134,7 @@ CONFIG_FAT_FS want), say M here and read Documentation/modules.txt. The module will be called fat.o. Note that if you compile the FAT support as a module, you cannot compile any of the FAT-based filesystems into the - kernel - they will have to be modules as well. The filesystem of + kernel -- they will have to be modules as well. The filesystem of your root partition cannot be a module, so don't say M here if you intend to use UMSDOS as your root filesystem. @@ -6288,7 +6224,7 @@ CONFIG_PROC_FS It's totally cool; for example, "cat /proc/interrupts" gives information about what the different IRQs are used for at the moment (there is a small number of Interrupt ReQuest lines in your computer - that are used by the attached devices to gain the CPU's attention - + that are used by the attached devices to gain the CPU's attention -- often a source of trouble if two devices are mistakenly configured to use the same IRQ). This option will enlarge your kernel by about 18 kB. Several programs depend on this, so everyone should say Y @@ -6308,8 +6244,8 @@ CONFIG_NFS_FS ftp://sunsite.unc.edu/pub/Linux/docs/LDP, on its man page: "man nfs", and in the NFS-HOWTO. - An alternative to NFS is provided by the Coda filesystem; see "Coda - filesystem support" below. + An superior but less widely used alternative to NFS is provided by + the Coda filesystem; see "Coda filesystem support" below. If you say Y here, you should have said Y to TCP/IP networking also. This option would enlarge your kernel by about 27 kB. @@ -6480,8 +6416,8 @@ CONFIG_ROMFS_FS QNX filesystem support (EXPERIMENTAL) CONFIG_QNX4FS_FS - This is the filesystem used by QNX 4. Say Y if you intend to mount - QNX hard disks and floppies. + This is the filesystem used by the operating system QNX 4. Say Y if + you intend to mount QNX hard disks or floppies. This filesystem support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -6498,8 +6434,8 @@ CONFIG_AUTOFS_FS automounter (amd), which is a pure user space daemon. To use the automounter you need the user-space tools from - ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say Y to - "NFS filesystem support", above. + ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say + Y to "NFS filesystem support", above. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -6509,31 +6445,33 @@ CONFIG_AUTOFS_FS If you are not a part of a fairly large, distributed network, you probably do not need an automounter, and can say N here. -UFS filesystem support (read only) +UFS filesystem support CONFIG_UFS_FS BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, OpenBSD and NeXTstep) use a filesystem called UFS. Some System V Unixes can create and mount hard disk partitions and diskettes using this filesystem as well. Saying Y here allows you to mount these - partitions and diskettes read-only. + partitions and diskettes. If you only intend to mount files from some other Unix over the network using NFS, you don't need the UFS filesystem support (but - you need NFS filesystem support obviously). Note that this option is - generally not needed for floppies, since a good portable way to - transport files and directories between unixes (and even other - operating systems) is given by the tar program ("man tar" or - preferably "info tar"). + you need NFS filesystem support obviously). + + Note that this option is generally not needed for floppies, since a + good portable way to transport files and directories between unixes + (and even other operating systems) is given by the tar program ("man + tar" or preferably "info tar"). When accessing NeXTstep files, you may need to convert them from the NeXT character set to the Latin1 character set; use the program recode ("info recode") for this purpose. - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called ufs.o. If you haven't heard about all of this before, it's - safe to say N. + If you want to compile the UFS filesystem support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called ufs.o. + + If you haven't heard about all of this before, it's safe to say N. BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL @@ -6588,18 +6526,22 @@ CONFIG_ADFS_FS /dev/pts filesystem (experimental) CONFIG_DEVPTS_FS - If you say Y here, you'll get a virtual filesystem which can be - mounted on /dev/pts with "mount -t devpts". This, together with the - pseudo terminal master multiplexer /dev/ptmx, is used for pseudo - terminal support as described in the Open Group's Unix98 standard: - in order to acquire a pseudo terminal, a process opens /dev/ptmx; - the number of the pseudo terminal is then made available to the - process and the pseudo terminal slave can be accessed as - /dev/pts/. What was traditionally /dev/ttyp2 will then be - /dev/pts/2, for example. The GNU C library glibc 2.1 contains the - requisite support for this mode of operation. - - Say Y here if you have enabled support for Unix98 PTYs. + You should say Y here if you said Y to "Unix98 PTY support" above. + You'll then get a virtual filesystem which can be mounted on + /dev/pts with "mount -t devpts". This, together with the pseudo + terminal master multiplexer /dev/ptmx, is used for pseudo terminal + support as described in the Open Group's Unix98 standard: in order + to acquire a pseudo terminal, a process opens /dev/ptmx; the number + of the pseudo terminal is then made available to the process and the + pseudo terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. The + GNU C library glibc 2.1 contains the requisite support for this mode + of operation. + + This code is also available as a module called devpts.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. Macintosh partition map support CONFIG_MAC_PARTITION @@ -6804,7 +6746,7 @@ CONFIG_NLS_CODEPAGE_850 DOS/Windows partitions correctly. This does apply to the filenames only, not to the file contents. You can include several codepages; say Y here if you want to include the DOS codepage that is used for - much of Europe--United Kingdom, Germany, Spain, Italy, and [add more + much of Europe -- United Kingdom, Germany, Spain, Italy, and [add more countries here]. It has some characters useful to many European languages that are not part of the US codepage 437. If unsure, say Y. @@ -7235,6 +7177,42 @@ CONFIG_ESPSERIAL and read Documentation/modules.txt. The module will be called esp.o. If unsure, say N. +Unix98 PTY support +CONFIG_UNIX98_PTYS + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are xterm and telnet + servers. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + The entries in /dev/pts/ are created on the fly by a virtual + filesystem; therefore, if you say Y here you should say Y to + "/dev/pts filesystem for Unix98 PTYs" as well. + + Say Y here if you are uncertain, unless you are very short on + memory. + +Maximum number of Unix98 PTYs in use (0-2048) +CONFIG_UNIX98_PTY_COUNT + The maximum number of Unix98 PTYs that can be used at any one time. + The default is 256, and should be enough for desktop systems. Server + machines which support incoming telnet/rlogin/ssh connections and/or + serve several X terminals may want to increase this: every incoming + connection and every xterm uses up one PTY. + + When not in use, each additional set of 256 PTYs occupy + approximately 8K of kernel memory on 32-bit architectures. + Parallel printer support CONFIG_PRINTER If you intend to attach a printer to the parallel port of your Linux @@ -7355,7 +7333,7 @@ CONFIG_MS_BUSMOUSE If you are unsure, say N and read the HOWTO nevertheless: it will tell you what you have. Also be aware that several vendors talk - about 'Microsoft busmouse' and actually mean PS/2 busmouse - so + about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so count the pins on the connector. If you want to compile this as a module ( = code which can be @@ -7807,12 +7785,12 @@ CONFIG_APM_DO_ENABLE Do CPU IDLE calls CONFIG_APM_CPU_IDLE Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop. - On some machines, this can activate improved power savings, such as a - slowed CPU clock rate, when the machine is idle. These idle calls are - made after the idle loop has run for some length of time (e.g., 333 - mS). On some machines, this will cause a hang at boot time or whenever - the CPU becomes idle. (On machines with more than one CPU, this option - does nothing.) + On some machines, this can activate improved power savings, such as + a slowed CPU clock rate, when the machine is idle. These idle calls + are made after the idle loop has run for some length of time (e.g., + 333 mS). On some machines, this will cause a hang at boot time or + whenever the CPU becomes idle. (On machines with more than one CPU, + this option does nothing.) Enable console blanking using APM CONFIG_APM_DISPLAY_BLANK @@ -7899,8 +7877,8 @@ CONFIG_WDT_501 Fan Tachometer CONFIG_WDT_501_FAN - Enable the Fan Tachometer on the WDT501. Only do this if you have a fan - tachometer actually set up. + Enable the Fan Tachometer on the WDT501. Only do this if you have a + fan tachometer actually set up. Software Watchdog CONFIG_SOFT_WATCHDOG @@ -8027,7 +8005,7 @@ CONFIG_SOUND from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. There is also some information in various README files in drivers/sound, esp. in Readme.cards which you should read first to find out whether your - card is supported by Linux. + card is supported by Linux, and, if yes, which driver to use. If you have a PnP sound card and you want to configure it at boot time using the ISA PnP tools (read @@ -8046,11 +8024,25 @@ CONFIG_SOUND ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ . +OSS sound modules +CONFIG_SOUND_OSS + OSS is the Open Sound System suite of sound card drivers. They make + sound programming easier since they provide a common API. Say Y or M + here (the module will be called sound.o) if you haven't found a + driver for your sound card above, then pick your driver from the + list below. + Support for Aztech Sound Galaxy (non-PnP) cards CONFIG_SOUND_SGALAXY - This module initializes the older non Plug and Play sound galaxy cards - from Aztech. It supports the Waverider Pro 32 - 3D and the Galaxy - Washington 16. + This module initializes the older non Plug and Play sound galaxy + cards from Aztech. It supports the Waverider Pro 32 - 3D and the + Galaxy Washington 16. + +Yamaha OPL3-SA1 audio controller +CONFIG_SOUND_OPL3SA1 + Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is + usually built into motherboards. Read Documentation/sound/OPL3-SA + for details. ProAudioSpectrum 16 support CONFIG_SOUND_PAS @@ -8065,15 +8057,21 @@ CONFIG_SOUND_SB Creative Labs or a 100% hardware compatible clone (like the Thunderboard or SM Games). If your card was in the list of supported cards look at the card specific instructions in the - drivers/sound/Readme.cards file before answering this question. For + drivers/sound/Readme.cards file before answering this question. For an unknown card you may answer Y if the card claims to be Sound Blaster-compatible. - Please read Documentation/sound/Soundblaster. + You can say M here to compile this driver as a module; the module is + called sb.o. - If you have an SB AWE 32 or SB AWE 64, say - Y here and to "Additional lowlevel drivers" and to "SB32/AWE - support" below. + You should also say Y here for cards based on the Avance Logic + ALS-007 chip (read Documentation/sound/ALS007) and for ESS1688 and + ESS1868 cards (read Documentation/sound/ESS1868). If you have an SB + AWE 32 or SB AWE 64, say Y here and also to "Additional lowlevel + drivers" and to "SB32/AWE support" below. If you have an IBM Mwave + card, say Y here and read Documentation/sound/mwave. + + Please read Documentation/sound/Soundblaster. Generic OPL2/OPL3 FM synthesizer support CONFIG_SOUND_ADLIB @@ -8081,7 +8079,13 @@ CONFIG_SOUND_ADLIB Answering Y is usually a safe and recommended choice, however some cards may have software (TSR) FM emulation. Enabling FM support with these cards may cause trouble (I don't currently know of any such - cards, however). If unsure, say Y. + cards, however). + + Please read the file Documentation/sound/OPL3 if your card has an + OPL3 chip. + + If unsure, say Y. + #Loopback MIDI device support #CONFIG_SOUND_VMIDI @@ -8114,24 +8118,33 @@ CONFIG_SOUND_UART6850 PSS (AD1848, ADSP-2115, ESC614) support CONFIG_SOUND_PSS - Answer Y only if you have Orchid SW32, Cardinal DSP16 or some other - card based on the PSS chipset (AD1848 codec + ADSP-2115 DSP chip + - Echo ESC614 ASIC CHIP). + Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven + ADSP-16 or some other card based on the PSS chipset (AD1848 codec + + ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on + how to compile it into the kernel or as a module see the file + Documentation/sound/PSS. + +Enable PSS mixer (Beethoven ADSP-16 and other compatible) +CONFIG_PSS_MIXER + Answer Y for Beethoven ADSP-16. You may try to say Y also for other + cards if they have master volume, bass, treble, and you can't + control it under Linux. If you answer N for Beethoven ADSP-16, you + can't control master volume, bass, treble and synth volume. + + If you said M to "PSS support" above, you may enable or disable this + PSS mixer with the module parameter pss_mixer. For more information + see the file Documentation/sound/PSS. -#Enable PSS mixer (Beethoven ADSP-16 and other compatible) -#CONFIG_PSS_MIXER -### -### Don't know what this is -### -# Have DSPxxx.LD firmware file CONFIG_PSS_HAVE_BOOT - If you want to emulate the Sound Blaster card and you have a DSPxxx.LD - file, then answer Y here to include this file. + If you have the DSPxxx.LD file or SYNTH.LD file for you card, answer + Y to include this file. Without this file the synth device (OPL) may + not work. Full pathname of DSPxxx.LD firmware file CONFIG_PSS_BOOT_FILE - Enter the full pathname of your DSPxxx.LD file, starting from /. + Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file, + starting from /. 16 bit sampling option of GUS (_NOT_ GUS MAX) CONFIG_SOUND_GUS16 @@ -8200,9 +8213,19 @@ CONFIG_SOUND_MAD16 quite common so it's possible that many no-name cards have one of them. In addition the MAD16 chip is used in some cards made by known manufacturers such as Turtle Beach (Tropez), Reveal (some models) - and Diamond (latest ones). See also Documentation/sound/Opti for + and Diamond (latest ones). Note however that the Tropez sound cards + have their own driver; if you have one of those, say N here and Y or + M to "Full support for Turtle Beach WaveFront", below. + + See also Documentation/sound/Opti and Documentation/sound/MAD16 for more information on setting these cards up as modules. +Full support for Turtle Beach WaveFront synth/sound cards +CONFIG_SOUND_WAVEFRONT + Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card + and read the files Documentation/sound/Wavefront and + Documentation/sound/Tropez+. + Support MIDI in older MAD16 based cards (requires SB) CONFIG_MAD16_OLDCARD Answer Y (or M) if you have an older card based on the C928 @@ -8272,7 +8295,15 @@ CONFIG_MSNDPIN_PERM_FILE obtained from Turtle Beach. See Documentation/sound/MultiSound for information on how to obtain this. -MSND Pinnacle Non-PnP Mode +MSND Pinnacle have S/PDIF I/O +CONFIG_MSNDPIN_DIGITAL + If you have the S/PDIF daughterboard for the Pinnacle or Fiji, say Y + here; otherwise, say N. If you have this, you will be able to play + and record from the S/PDIF port (digital signal). See + Documentation/sound/MultiSound for information on how to make use of + this capability. + +MSND Pinnacle non-PnP Mode CONFIG_MSNDPIN_NONPNP The Pinnacle and Fiji card resources can be configured either with PnP, or through a configuration port. For the Pinnacle, @@ -8283,13 +8314,20 @@ CONFIG_MSNDPIN_NONPNP you must say N here and use isapnptools to configure the card's resources. -MSND Pinnacle Config Port +MSND Pinnacle config port CONFIG_MSNDPIN_CFG This is the port which the Pinnacle and Fiji uses to configure the card's resources when not in PnP mode. If your card is in PnP mode, then be sure to say N to the previous option, CONFIG_MSNDPIN_NONPNP. +MSND buffer size (kB) +CONFIG_MSND_FIFOSIZE + Configures the size of each audio buffer, in kilobytes, for + recording and playing in the MultiSound drivers (both the Classic + and Pinnacle). Larger values reduce the chance of data overruns at + the expense of overall latency. If unsure, use the default. + /dev/dsp and /dev/audio support CONFIG_SOUND_AUDIO Answering N disables /dev/dsp and /dev/audio, the A/D and D/A @@ -8339,18 +8377,22 @@ CONFIG_AWE32_SYNTH Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600) CONFIG_AEDSP16 - Answer Y if you have a Gallant's Audio Excel DSP 16 card. This card - can emulate either an SBPro or a Microsoft Sound System card, so you - should have said Y to either "Sound Blaster (SB, SBPro, SB16, clones) - support" or "Microsoft Sound System support", above, and you need to - answer the "MSS emulation" and "SBPro emulation" questions below + Answer Y if you have a Gallant's Audio Excel DSP 16 card. This + driver supports Audio Excel DSP 16 but not the III nor PnP versions + of this card. + + The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or + a Microsoft Sound System card, so you should have said Y to either + "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" + or "Microsoft Sound System support", above, and you need to answer + the "MSS emulation" and "SBPro emulation" questions below accordingly. You should say Y to one and only one of these two - questions. Read the drivers/sound/lowlevel/README.aedsp16 file and - the head of drivers/sound/lowlevel/aedsp16.c to get more information - about this driver and its configuration. This driver supports Audio - Excel DSP 16 but not the III nor PnP versions of this card. Read - drivers/sound/lowlevel/README.aedsp16 if you want to know something - more on how to use the III version with this sound driver. + questions. + + Read the drivers/sound/lowlevel/README.aedsp16 file and the head of + drivers/sound/lowlevel/aedsp16.c as well as + Documentation/sound/AudioExcelDSP16 to get more information about + this driver and its configuration. SC-6600 based audio cards (new Audio Excel DSP 16) CONFIG_SC6600 @@ -8367,8 +8409,9 @@ CONFIG_AEDSP16_MSS Audio Excel DSP 16 (SBPro emulation) CONFIG_AEDSP16_SBPRO Answer Y if you want your audio card to emulate Sound Blaster Pro. - You should then say Y to "Sound Blaster (SB, SBPro, SB16, clones) - support" and N to "Audio Excel DSP 16 (MSS emulation)". + You should then say Y to "100% Sound Blaster compatibles + (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS + emulation)". Ensoniq ES1370 based PCI sound cards CONFIG_SOUND_ES1370 @@ -8404,11 +8447,11 @@ Magic System Request Key support CONFIG_MAGIC_SYSRQ If you say Y here, you will have some control over the system even if the system crashes for example during kernel debugging (e.g., you - will be able to flush the disks, reboot the system immediately or - dump some status information). This is accomplished by pressing - various keys while holding SysRq (Alt+PrintScreen). The keys are - documented in Documentation/sysrq.txt. Don't say Y unless you really - know what this hack does. + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). The + keys are documented in Documentation/sysrq.txt. Don't say Y unless + you really know what this hack does. ISDN subsystem CONFIG_ISDN @@ -8640,8 +8683,8 @@ Support for German tariff info CONFIG_DE_AOC If you want that the HiSax hardware driver sends messages to the upper level of the isdn code on each AOCD (Advice Of Charge, During - the call - transmission of the fee information during a call) and on - each AOCE (Advice Of Charge, at the End of the call - transmission + the call -- transmission of the fee information during a call) and on + each AOCE (Advice Of Charge, at the End of the call -- transmission of fee information at the end of the call), say Y here. This works only in Germany. @@ -8719,9 +8762,9 @@ IBM Active 2000 support (EXPERIMENTAL) CONFIG_ISDN_DRV_ACT2000 Say Y here if you have an IBM Active 2000 ISDN card. In order to use this card, additional firmware is necessary, which has to be loaded - into the card using a utility which is part of the latest isdn4k-utils - package. Please read the file Documentation/isdn/README.act2000 for - more information. + into the card using a utility which is part of the latest + isdn4k-utils package. Please read the file + Documentation/isdn/README.act2000 for more information. Support for AP1000 multicomputer CONFIG_AP1000 @@ -8733,9 +8776,9 @@ CONFIG_AP1000 Support for Sun4 architecture CONFIG_SUN4 - Use this option if, and only if, your machine is sun4. Note that - kernel compiled with this option will run on sun4 only. - (And in current version, it will probably work on sun4/330, only.) + Say Y here if, and only if, your machine is a Sun4. Note that + a kernel compiled with this option will run only on Sun4. + (And the current version will probably work only on sun4/330.) SPARC ESP SCSI support CONFIG_SCSI_SUNESP @@ -8760,6 +8803,7 @@ CONFIG_SUN_OPENPROMIO ### ### Please someone fill these in. ### + # # m68k-specific kernel options # Documented by Chris Lawrence et al. @@ -8844,14 +8888,14 @@ Use read-modify-write instructions CONFIG_RMW_INSNS This allows to use certain instructions that work with indivisible read-modify-write bus cycles. While this is faster than the - workaround of disabling interrupts, it can conflict with DMA (= - direct memory access) on many Amiga systems, and it is also said to - destabilize other machines. It is very likely that this will cause - serious problems on any Amiga or Atari Medusa if set. The only + workaround of disabling interrupts, it can conflict with DMA + ( = direct memory access) on many Amiga systems, and it is also said + to destabilize other machines. It is very likely that this will + cause serious problems on any Amiga or Atari Medusa if set. The only configuration where it should work are 68030-based Ataris, where it apparently improves performance. But you've been warned! Unless you - really know what you are doing, say N. Try Y only if you're - quite adventurous. + really know what you are doing, say N. Try Y only if you're quite + adventurous. Amiga AutoConfig Identification CONFIG_ZORRO @@ -8885,15 +8929,6 @@ CONFIG_AMIFB_AGA and CD32. If you intend to run Linux on any of these systems, say Y; otherwise say N. -Amiga Cybervision support -CONFIG_FB_CYBER - This enables support for the Cybervision 64 graphics card from Phase5. - Please note that its use is not all that intuitive (i.e. if you have - any questions, be sure to ask!). Say N unless you have a Cybervision - 64 or plan to get one before you next recompile the kernel. - Please note that this driver DOES NOT support the Cybervision 64 3D - card at present, as they use incompatible video chips. - Amiga GSP (TMS340x0) support CONFIG_AMIGA_GSP Include support for Amiga graphics cards that use the Texas @@ -8915,17 +8950,17 @@ Amiga Zorro II ramdisk support CONFIG_AMIGA_Z2RAM This enables support for using Chip RAM and Zorro II RAM as a ramdisk or as a swap partition. Say Y if you want to include this - driver in the kernel. This driver is also available as a module ( = - code which can be inserted in and removed from the running kernel - whenever you want). The module is called z2ram.o. If you want to - compile it as a module, say M here and read + driver in the kernel. This driver is also available as a module + ( = code which can be inserted in and removed from the running + kernel whenever you want). The module is called z2ram.o. If you want + to compile it as a module, say M here and read Documentation/modules.txt. Atari ST-RAM swap support CONFIG_STRAM_SWAP This enables support for using (parts of) ST-RAM as swap space, instead of as normal system memory. This can first enhance system - performace if you have lots of alternate RAM (compared to the size + performance if you have lots of alternate RAM (compared to the size of ST-RAM), because executable code always will reside in faster memory. ST-RAM will remain as ultra-fast swap space. On the other hand, it allows much improved dynamic allocations of ST-RAM buffers @@ -9006,12 +9041,13 @@ CONFIG_CYBERSTORM_SCSI Cyberstorm II SCSI support CONFIG_CYBERSTORMII_SCSI If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board - and the optional Cyberstorm SCSI controller, say Y. Otherwise, say N. + and the optional Cyberstorm SCSI controller, say Y. Otherwise, say + N. Blizzard 2060 SCSI support CONFIG_BLZ2060_SCSI If you have an Amiga with a Phase5 Blizzard 2060 accelerator board - and want to use the onboard SCSI controller, say Y. Otherwise, say + and want to use the onboard SCSI controller, say Y. Otherwise, say N. Blizzard 1230IV/1260 SCSI support @@ -9235,17 +9271,6 @@ CONFIG_MSDOS_PARTITION Say Y if you need this feature; users who are only using their system-native partitioning scheme can say N here. -Board Type -CONFIG_PMAC - There are currently several different kinds of PowerPC-based machines - available: Apple Power Macintoshes and clones (such as the Motorola - Starmax series, PReP (PowerPC Reference Platform) machines such - as the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the - embedded MBX boards from Motorola. Currently, a single kernel binary - only supports one type or the other. However, there is very early work - on support CHRP, PReP and PowerMac's from a single binary. - - Processor Type CONFIG_6xx There are two types of PowerPC chips supported. The more common @@ -9253,6 +9278,17 @@ CONFIG_6xx Unless you are building a kernel for one of the embedded boards using the 821 or 860 choose 6xx. +Machine Type +CONFIG_PMAC + Linux currently supports several different kinds of PowerPC-based + machines: Apple Power Macintoshes and clones (such as the + Motorola Starmax series), PReP (PowerPC Reference Platform) machines + such as the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP + and the embedded MBX boards from Motorola. Currently, a single + kernel binary only supports one type or the other. However, there is + very early work on support for CHRP, PReP and PowerMac's from a + single binary. + Support for Open Firmware device tree in /proc CONFIG_PROC_DEVICETREE This option adds a device-tree directory under /proc which contains @@ -9275,10 +9311,10 @@ CONFIG_SCSI_MESH Many Power Macintoshes and clones have a MESH (Macintosh Enhanced SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the other Power Macintoshes do). Say Y to include support for this SCSI - adaptor. This driver is also available as a module called mesh.o ( - = code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read Documentation/modules.txt. + adaptor. This driver is also available as a module called mesh.o + ( = code which can be inserted in and removed from the running + kernel whenever you want). If you want to compile it as a module, + say M here and read Documentation/modules.txt. Maximum synchronous transfer rate CONFIG_SCSI_MESH_SYNC_RATE @@ -9309,6 +9345,11 @@ CONFIG_MACE motherboard will usually use a MACE (Medium Access Control for Ethernet) interface. Say Y to include support for the MACE chip. +BMAC (G3 ethernet) support +CONFIG_BMAC + Say Y for support of BMAC Ethernet interfaces. These are used on G3 + computers. + Video For Linux CONFIG_VIDEO_DEV Support for audio/video capture and overlay devices and FM radio @@ -9316,6 +9357,10 @@ CONFIG_VIDEO_DEV this are available from ftp://ftp.uk.linux.org/pub/linux/video4linux. + If you are interested in writing a driver for such an audio/video + device or user software interacting with such a driver, please read + the file Documentation/video4linux/API.html. + This driver is also available as a module called videodev.o ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M @@ -9326,16 +9371,17 @@ CONFIG_RADIO_RTRACK Choose Y here if you have one of these FM radio cards, and then fill in the port address below. - Note that newer AIMSlab RadioTrack cards have a different chipset, - not supported by this driver. For these cards, use the RadioTrack II - driver below. + Note that newer AIMSlab RadioTrack cards have a different chipset + and are not supported by this driver. For these cards, use the + RadioTrack II driver below. In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, you need to have access to a machine on the Internet that has a - program like lynx or netscape. + program like lynx or netscape. More information is contained in the + file Documentation/video4linux/radiotrack.txt. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9434,10 +9480,28 @@ ZOLTRIX I/O port (0x20c or 0x30c) CONFIG_RADIO_ZOLTRIX_PORT Enter the I/O port of your Zoltrix radio card. +Miro PCM20 Radio +CONFIG_RADIO_MIROPCM20 + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-miropcm20.o + BT848 Video For Linux CONFIG_VIDEO_BT848 Support for BT848 based frame grabber/overlay boards. This includes - the Miro, Hauppauge and STB boards. + the Miro, Hauppauge and STB boards. Please read the material in + Documentation/video4linux/bttv for more information. This driver is also available as a module called bttv.o ( = code which can be inserted in and removed from the running kernel @@ -9497,13 +9561,15 @@ CONFIG_ARCH_ARC Build Tools Selection CONFIG_BINUTILS_NEW - Say Y here if you're using GCC 2.8.1/EGCS with a binutils - version >= 2.8.1 to compile the kernel. Otherwise, say N. + Say Y here if and only if you're using GCC 2.8.1/EGCS with a + binutils version >= 2.8.1 to compile the kernel (check with "gcc + --version" and "ld -v"). Compile kernel with frame pointer CONFIG_FRAME_POINTER - In order to give useful debugging/error results, say Y here, otherwise - say N. + If you say Y here, the resulting kernel will be slightly larger, but + it will give useful debugging/error results. If you don't debug the + kernel, you can say N. VIDC Sound CONFIG_VIDC_SOUND @@ -9515,7 +9581,7 @@ CONFIG_VIDC_SOUND # capitalize: AppleTalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, # Linux, NetWare, NFS, PCI, SCSI, SPARC # two words: hard drive, hard disk, sound card, home page -# other: it's safe to save; daemon +# other: it's safe to save; daemon; use --, not - or --- # # This is used by Emacs' spell checker ispell.el: # @@ -9605,7 +9671,7 @@ CONFIG_VIDC_SOUND # LocalWords: YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc # LocalWords: traduc Bourgin dbourgin menuconfig kfill READMEs HOWTOs Virge WA # LocalWords: IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti -# LocalWords: SVGATextMode vga svga Xterminal Xkernel syr jmwobus comfaqs dhcp +# LocalWords: SVGATextMode vga svga Xkernel syr jmwobus comfaqs dhcp flakey GD # LocalWords: IPv IPng interoperability ipng ipv radio's tapr pkthome PLP nano # LocalWords: Ses Mhz sethdlc SOUNDMODEM WindowsSoundSystem smdiag pcf inka ES # LocalWords: smmixer ptt circ soundmodem MKISS FDDI DEFEA DEFPA DEFXX redhat @@ -9646,7 +9712,7 @@ CONFIG_VIDC_SOUND # LocalWords: hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid # LocalWords: transname filespace adm Nodename hostname uname Kernelname bootp # LocalWords: KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb -# LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop +# LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS # LocalWords: nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY # LocalWords: HFMODEM shortwave Sitor Amtor Pactor GTOR hfmodem hayes TX TMOUT # LocalWords: IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu @@ -9693,10 +9759,16 @@ CONFIG_VIDC_SOUND # LocalWords: AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF # LocalWords: RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis # LocalWords: Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs -# LocalWords: EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson +# LocalWords: EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson CT # LocalWords: SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT CFB DSY kbps # LocalWords: tuwien kkudielk LVD mega lun MAXTAGS Gbps arcnet Olicom SKTR SNA -# LocalWords: SysKonnect sktr sna etherboot ufs NetBEUI MultiSound MSNDCLAS -# LocalWords: MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's -# LocalWords: AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner +# LocalWords: SysKonnect sktr sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX +# LocalWords: MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's RetinaZ SS +# LocalWords: AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA # LocalWords: swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs +# LocalWords: CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS +# LocalWords: CGthree TCX unswapable vfb fbcon hicolor truecolor AFB ILBM SOC +# LocalWords: IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx +# LocalWords: PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss +# LocalWords: synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX +# LocalWords: PowerMac's BMAC radiotrack rtrack miropcm diff --git a/Documentation/networking/arcnet-hardware.txt b/Documentation/networking/arcnet-hardware.txt index ce623ed5cb8a..ffebd188e9be 100644 --- a/Documentation/networking/arcnet-hardware.txt +++ b/Documentation/networking/arcnet-hardware.txt @@ -10,8 +10,8 @@ Because so many people (myself included) seem to have obtained ARCnet cards without manuals, this file contains a quick introduction to ARCnet hardware, some cabling tips, and a listing of all jumper settings I can find. Please -e-mail apenwarr@bond.net with any settings for your particular card, or any -other information you have! +e-mail apenwarr@worldvisions.ca with any settings for your particular card, +or any other information you have! INTRODUCTION TO ARCNET @@ -80,7 +80,7 @@ CABLING ARCNET NETWORKS This section was rewritten by Vojtech Pavlik using information from several people, including: - Avery Pennraun + Avery Pennraun Stephen A. Wood John Paul Morrison Joachim Koenig @@ -438,8 +438,8 @@ Unclassified Stuff PC100, PC110, PC120, PC130 (8-bit cards) PC500, PC600 (16-bit cards) --------------------------------- - - mainly from Avery Pennarun . Values depicted are - from Avery's setup. + - mainly from Avery Pennarun . Values depicted + are from Avery's setup. - special thanks to Timo Hilbrink for noting that PC120, 130, 500, and 600 all have the same switches as Avery's PC100. PC500/600 have several extra, undocumented pins though. (?) @@ -3129,6 +3129,6 @@ Other Cards I have no information on other models of ARCnet cards at the moment. Please send any and all info to: - apenwarr@bond.net + apenwarr@worldvisions.ca Thanks. diff --git a/Documentation/networking/arcnet.txt b/Documentation/networking/arcnet.txt index 17f40fb5332c..3bb2f6d96193 100644 --- a/Documentation/networking/arcnet.txt +++ b/Documentation/networking/arcnet.txt @@ -37,7 +37,7 @@ If you think so, why not flame me in a quick little e-mail? Please also include the type of card(s) you're using, software, size of network, and whether it's working or not.) -My e-mail address is: apenwarr@bond.net +My e-mail address is: apenwarr@worldvisions.ca --------------------------------------------------------------------------- @@ -79,9 +79,8 @@ may not work right in the first place. Other Drivers and Info ---------------------- -You can (could - foxnet.net is no more - DW.) try my ARCNET page on the -World Wide Web at: - http://www.foxnet.net/~apenwarr/arcnet/ +You can try my ARCNET page on the World Wide Web at: + http://www.worldvisions.ca/~apenwarr/arcnet/ Also, SMC (one of the companies that makes ARCnet cards) has a WWW site you might be interested in, which includes several drivers for various cards @@ -494,7 +493,7 @@ It works: what now? Send mail describing your setup, preferably including driver version, kernel version, ARCnet card model, CPU type, number of systems on your network, and list of software in use to me at the following address: - apenwarr@bond.net + apenwarr@worldvisions.ca I do send (sometimes automated) replies to all messages I receive. My email can be weird (and also usually gets forwarded all over the place along the diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt index 78561b9f4fff..839db8eceb5b 100644 --- a/Documentation/networking/cs89x0.txt +++ b/Documentation/networking/cs89x0.txt @@ -612,7 +612,7 @@ software-update notification. 6.3.1 CRYSTAL'S WEB SITE Crystal Semiconductor maintains a web page at http://www.crystal.com with the -the latest drivers and technical publications. +latest drivers and technical publications. 6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE diff --git a/Documentation/sound/ChangeLog.multisound b/Documentation/sound/ChangeLog.multisound index a25f465b71a3..bd329565214e 100644 --- a/Documentation/sound/ChangeLog.multisound +++ b/Documentation/sound/ChangeLog.multisound @@ -1,3 +1,66 @@ +1998-09-10 Andrew Veliath + + * Update version to 0.8.2 + + * Add SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls. + +1998-09-09 Andrew Veliath + + * Update version to 0.8.1 + + * msnd_pinnacle.c: Fix resetting of default audio parameters. Turn + flush code from dsp_halt into dsp_write_flush, and use that for + SNDCTL_DSP_SYNC. + +1998-09-07 Andrew Veliath + + * Update version to 0.8.0 + + * Provide separate signal parameters for play and record. + + * Cleanups to locking and interrupt handling, change default + fifosize to 128kB. + + * Update version to 0.7.15 + + * Interprocess full-duplex support (ie `cat /dev/dsp > /dev/dsp'). + + * More mutex sections for read and write fifos (read + write locks + added). + +1998-09-05 Andrew Veliath + + * msnd_pinnacle.c: (chk_send_dsp_cmd) Do full DSP reset upon DSP + timeout (when not in interrupt; maintains mixer settings). Fixes + to flushing and IRQ ref counting. Rewrote queuing for smoother + playback and fixed initial playback cutoff problem. + +1998-09-03 Andrew Veliath + + * Replaced packed structure accesses with standard C equivalents. + +1998-09-01 Andrew Veliath + + * msnd_pinnacle.c: Add non-PnP configuration to driver code, which + will facilitate compiled-in operation. + +1998-08-29 Andrew Veliath + + * Update version to 0.7.6 + + * msnd_pinnacle.c (dsp_ioctl): Add DSP_GETFMTS, change SAMPLESIZE + to DSP_SETFMT. + + * Update version to 0.7.5 + + * Create pinnaclecfg.c and turn MultiSound doc into a shell + archive with pinnaclecfg.c included. pinnaclecfg.c can + now fully configure the card in non-PnP mode, including the + joystick and IDE controller. Also add an isapnp conf + example. + + * Reduce DSP reset timeout from 20000 to 100 + 1998-08-06 Andrew Veliath * Update version to 0.7.2 diff --git a/Documentation/sound/Wavefront b/Documentation/sound/Wavefront index aadbfd23ff43..58cd7f14fe30 100644 --- a/Documentation/sound/Wavefront +++ b/Documentation/sound/Wavefront @@ -3,15 +3,15 @@ Paul Barton-Davis, July 1998 - VERSION 0.2.4 + VERSION 0.2.5 Driver Status ------------- -Requires: Kernel 2.1.106 or later (a version of the driver is included -with kernels 2.1.109 and above) +Requires: Kernel 2.1.106 or later (the driver is included with kernels +2.1.109 and above) -As of 7/20/1998, this driver is currently in *BETA* state. This means +As of 7/22/1998, this driver is currently in *BETA* state. This means that it compiles and runs, and that I use it on my system (Linux 2.1.106) with some reasonably demanding applications and uses. I believe the code is approaching an initial "finished" state that diff --git a/MAINTAINERS b/MAINTAINERS index 322063663e67..b14429d6bb69 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -292,6 +292,12 @@ L: linux-kernel@vger.rutgers.edu W: http://www.nyx.net/~arobinso S: Maintainted +HFS FILESYSTEM +P: Adrian Sun +M: asun@u.washington.edu +L: linux-kernel@vger.rutgers.edu +S: Maintained + HIGH-SPEED SCC DRIVER FOR AX.25 P: Klaus Kudielka M: oe1kib@oe1kib.ampr.org @@ -593,12 +599,6 @@ M: Jay.Schulist@spacs.k12.wi.us L: linux-net@vger.rutgers.edu S: Supported -SPX NETWORK LAYER -P: Jay Schulist -M: Jay.Schulist@spacs.k12.wi.us -L: linux-net@vger.rutgers.edu -S: Supported - STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS P: Greg Ungerer M: support@stallion.oz.au diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index a8e2f8761112..eea674aa68ef 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -253,9 +253,11 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, unsigned long ret = -EBADF; lock_kernel(); +#if 0 if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags); +#endif if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); if (!file) diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 65b26ffc4930..d2be68e5761e 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -78,9 +78,6 @@ #include #include -#include -#include - #include #include #include @@ -96,7 +93,9 @@ #include #include -#include "desc.h" +#include +#include +#include EXPORT_SYMBOL(apm_register_callback); EXPORT_SYMBOL(apm_unregister_callback); diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c index 4381719ae8e1..d3b395732c54 100644 --- a/arch/i386/kernel/init_task.c +++ b/arch/i386/kernel/init_task.c @@ -3,8 +3,7 @@ #include #include - -#include "desc.h" +#include static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index e2e107c9e84e..1c61c8841a52 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1224,7 +1224,27 @@ void __init setup_IO_APIC(void) setup_IO_APIC_irqs(); init_IRQ_SMP(); check_timer(); - + + /* + * Get rid of any pending interrupt sources by just blindly + * ACK'ing the IO-APIC. There is apparently no other way to + * remove stale bits in the ISR. + * + * I'd love to be proven wrong, please tell me how to clear + * the ISR bit for specific interrupts.. + * + * Oh, how do we clear the IRR bit? I'd like to be able to + * make sure that we get one interrupt for something that + * is pending when we enable it, even if it is edge-triggered. + * How to fool the IO-APIC to think it got an edge when + * enabled? + */ + { + int i = 10; + do { + ack_APIC_irq(); + } while (--i); + } + print_IO_APIC(); } - diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index e5bc7e8d21e6..2ec0dffc959c 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -37,9 +37,9 @@ #include #include #include +#include #include "irq.h" -#include "desc.h" unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; @@ -683,7 +683,8 @@ void disable_irq(unsigned int irq) irq_desc[irq].handler->disable(irq); spin_unlock_irqrestore(&irq_controller_lock, flags); - synchronize_irq(); + if (irq_desc[irq].status & IRQ_INPROGRESS) + synchronize_irq(); } void enable_irq(unsigned int irq) @@ -886,7 +887,7 @@ unsigned long probe_irq_on(void) for (i = NR_IRQS-1; i > 0; i--) { if (!irq_desc[i].action) { unsigned int status = irq_desc[i].status | IRQ_AUTODETECT; - irq_desc[i].status = status & ~(IRQ_INPROGRESS | IRQ_PENDING); + irq_desc[i].status = status & ~IRQ_INPROGRESS; irq_desc[i].handler->enable(i); } } diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index 4f41b8a330cd..25e8deec44e8 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -15,8 +15,7 @@ #include #include #include - -#include "desc.h" +#include static int read_ldt(void * ptr, unsigned long bytecount) { diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index bd6113cbb46b..039a9e559085 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -41,12 +41,12 @@ #include #include #include +#include #ifdef CONFIG_MATH_EMULATION #include #endif #include "irq.h" -#include "desc.h" spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index dfa3b9848a64..8968b334e1f7 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -507,10 +507,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) else child->flags &= ~PF_TRACESYS; child->exit_code = data; - wake_up_process(child); /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET,tmp); + wake_up_process(child); ret = 0; goto out; } @@ -526,11 +526,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = 0; if (child->state == TASK_ZOMBIE) /* already dead */ goto out; - wake_up_process(child); child->exit_code = SIGKILL; /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + wake_up_process(child); goto out; } @@ -543,9 +543,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) child->flags &= ~PF_TRACESYS; tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); - wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ + wake_up_process(child); ret = 0; goto out; } @@ -558,16 +558,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if ((unsigned long) data > _NSIG) goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); - wake_up_process(child); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); write_unlock_irqrestore(&tasklist_lock, flags); - /* make sure the single step bit is not set. */ + /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); + wake_up_process(child); ret = 0; goto out; } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 498820ec8caa..7db4f3fb3bf8 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -493,6 +493,7 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c)) switch (edx) { case 0x40: cache_size = 0; + break; case 0x41: cache_size = 128; @@ -532,7 +533,7 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c)) && (cpu_models[i].x86 == 6) && (c->x86_model == 5) && (c->x86_cache_size == 0)) { - p = "Celeron"; + p = "Celeron (Covington)"; } } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 6d60aeb40be9..d919ba06dcf4 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -27,8 +27,7 @@ #include #include #include - -#include "desc.h" +#include asmlinkage int system_call(void); asmlinkage void lcall7(void); @@ -205,6 +204,14 @@ static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) unsigned long fixup; fixup = search_exception_table(regs->eip); if (fixup) { + /* + * The GP fault might have been due to + * bad segments, so clean up the ones + * we care about here.. + */ + regs->xds = __KERNEL_DS; + regs->xes = __KERNEL_DS; + regs->xss = __KERNEL_DS; regs->eip = fixup; return; } diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c index 9be6cc0fcaaa..1c5d30e1db39 100644 --- a/arch/i386/math-emu/fpu_entry.c +++ b/arch/i386/math-emu/fpu_entry.c @@ -27,6 +27,7 @@ #include #include +#include #include "fpu_system.h" #include "fpu_emu.h" diff --git a/arch/i386/math-emu/get_address.c b/arch/i386/math-emu/get_address.c index 1e7009a23158..6462f0fa2415 100644 --- a/arch/i386/math-emu/get_address.c +++ b/arch/i386/math-emu/get_address.c @@ -21,6 +21,7 @@ #include #include +#include #include "fpu_system.h" #include "exception.h" diff --git a/drivers/block/Makefile b/drivers/block/Makefile index fa943cc48048..82bfb0474952 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -87,10 +87,10 @@ else endif ifeq ($(CONFIG_BLK_DEV_LOOP),y) -L_OBJS += loop.o +LX_OBJS += loop.o else ifeq ($(CONFIG_BLK_DEV_LOOP),m) - M_OBJS += loop.o + MX_OBJS += loop.o endif endif diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 7425bf25131c..6ba340cb326c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4115,7 +4115,9 @@ __initfunc(int floppy_init(void)) for (drive = 0; drive < N_DRIVE; drive++) { CLEARSTRUCT(UDRS); CLEARSTRUCT(UDRWE); - UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED; + USETF(FD_DISK_NEWCHANGE); + USETF(FD_DISK_CHANGED); + USETF(FD_VERIFY); UDRS->fd_device = -1; floppy_track_buffer = NULL; max_buffer_sectors = 0; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 5a936899fd1d..196f6dc4ca6d 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -15,6 +15,12 @@ * Fixed do_loop_request() re-entrancy - Vincent.Renardias@waw.com Mar 20, 1997 * * Handle sparse backing files correctly - Kenn Humborg, Jun 28, 1998 + * + * Loadable modules and other fixes by AK, 1998 + * + * Still To Fix: + * - Advisory locking is ignored here. + * - Should use an own CAP_* category instead of CAP_SYS_ADMIN */ #include @@ -26,19 +32,12 @@ #include #include #include + #include #include -#ifdef CONFIG_BLK_DEV_LOOP_DES -# /*nodep*/ include -#endif - -#ifdef CONFIG_BLK_DEV_LOOP_IDEA -# /*nodep*/ include -#endif - -#include /* must follow des.h */ +#include #define MAJOR_NR LOOP_MAJOR @@ -63,7 +62,6 @@ static int loop_blksizes[MAX_LOOP]; backing file (can happen if the backing file is sparse) */ static int create_missing_block(struct loop_device *lo, int block, int blksize); - /* * Transfer functions */ @@ -97,80 +95,38 @@ static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf, return 0; } -#ifdef DES_AVAILABLE -static int transfer_des(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size) +static int none_status(struct loop_device *lo, struct loop_info *info) { - unsigned long tmp[2]; - unsigned long x0,x1,p0,p1; + return 0; +} - if (size & 7) +static int xor_status(struct loop_device *lo, struct loop_info *info) +{ + if (info->lo_encrypt_key_size < 0) return -EINVAL; - x0 = lo->lo_des_init[0]; - x1 = lo->lo_des_init[1]; - while (size) { - if (cmd == READ) { - tmp[0] = (p0 = ((unsigned long *) raw_buf)[0])^x0; - tmp[1] = (p1 = ((unsigned long *) raw_buf)[1])^x1; - des_ecb_encrypt((des_cblock *) tmp,(des_cblock *) - loop_buf,lo->lo_des_key,DES_ENCRYPT); - x0 = p0^((unsigned long *) loop_buf)[0]; - x1 = p1^((unsigned long *) loop_buf)[1]; - } - else { - p0 = ((unsigned long *) loop_buf)[0]; - p1 = ((unsigned long *) loop_buf)[1]; - des_ecb_encrypt((des_cblock *) loop_buf,(des_cblock *) - raw_buf,lo->lo_des_key,DES_DECRYPT); - ((unsigned long *) raw_buf)[0] ^= x0; - ((unsigned long *) raw_buf)[1] ^= x1; - x0 = p0^((unsigned long *) raw_buf)[0]; - x1 = p1^((unsigned long *) raw_buf)[1]; - } - size -= 8; - raw_buf += 8; - loop_buf += 8; - } return 0; } -#endif - -#ifdef IDEA_AVAILABLE -extern void idea_encrypt_block(idea_key,char *,char *,int); - -static int transfer_idea(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size) -{ - if (cmd==READ) { - idea_encrypt_block(lo->lo_idea_en_key,raw_buf,loop_buf,size); - } - else { - idea_encrypt_block(lo->lo_idea_de_key,loop_buf,raw_buf,size); - } - return 0; -} -#endif - -static transfer_proc_t xfer_funcs[MAX_LOOP] = { - transfer_none, /* LO_CRYPT_NONE */ - transfer_xor, /* LO_CRYPT_XOR */ -#ifdef DES_AVAILABLE - transfer_des, /* LO_CRYPT_DES */ -#else - NULL, /* LO_CRYPT_DES */ -#endif -#ifdef IDEA_AVAILABLE /* LO_CRYPT_IDEA */ - transfer_idea -#else - NULL -#endif +struct loop_func_table none_funcs = { + number: LO_CRYPT_NONE, + transfer: transfer_none, + init: none_status +}; + +struct loop_func_table xor_funcs = { + number: LO_CRYPT_XOR, + transfer: transfer_xor, + init: xor_status +}; + +/* xfer_funcs[0] is special - its release function is never called */ +struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { + &none_funcs, + &xor_funcs }; - #define MAX_DISK_SIZE 1024*1024*1024 - static void figure_loop_size(struct loop_device *lo) { int size; @@ -326,6 +282,7 @@ static int create_missing_block(struct loop_device *lo, int block, int blksize) char zero_buf[1] = { 0 }; ssize_t retval; mm_segment_t old_fs; + struct inode *inode; file = lo->lo_backing_file; if (file == NULL) { @@ -349,16 +306,19 @@ static int create_missing_block(struct loop_device *lo, int block, int blksize) file->f_version = ++event; } - if (file->f_op->write == NULL) { - printk(KERN_WARNING "loop: cannot create block - no write file op\n"); + if ((file->f_mode & FMODE_WRITE) == 0 || file->f_op->write == NULL) { + printk(KERN_WARNING "loop: cannot create block - file not writeable\n"); return FALSE; } old_fs = get_fs(); set_fs(get_ds()); + inode = file->f_dentry->d_inode; + down(&inode->i_sem); retval = file->f_op->write(file, zero_buf, 1, &file->f_pos); - + up(&inode->i_sem); + set_fs(old_fs); if (retval < 0) { @@ -447,6 +407,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) lo->lo_dentry = file->f_dentry; lo->lo_dentry->d_count++; lo->transfer = NULL; + lo->ioctl = NULL; figure_loop_size(lo); out_putf: @@ -457,6 +418,19 @@ out: return error; } +static int loop_release_xfer(struct loop_device *lo) +{ + int err = 0; + if (lo->lo_encrypt_type) { + if (xfer_funcs[lo->lo_encrypt_type] && + xfer_funcs[lo->lo_encrypt_type]->release) { + err = xfer_funcs[lo->lo_encrypt_type]->release(lo); + } + lo->lo_encrypt_type = 0; + } + return err; +} + static int loop_clr_fd(struct loop_device *lo, kdev_t dev) { struct dentry *dentry = lo->lo_dentry; @@ -477,6 +451,8 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev) dput(dentry); } + lo->transfer = NULL; + lo->ioctl = NULL; lo->lo_device = 0; lo->lo_encrypt_type = 0; lo->lo_offset = 0; @@ -491,60 +467,44 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev) static int loop_set_status(struct loop_device *lo, struct loop_info *arg) { - struct loop_info info; + struct loop_info info; int err; + unsigned int type; + if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && + !capable(CAP_SYS_ADMIN)) + return -EPERM; if (!lo->lo_dentry) return -ENXIO; - if (!arg) - return -EINVAL; - err = verify_area(VERIFY_READ, arg, sizeof(info)); - if (err) - return err; - copy_from_user(&info, arg, sizeof(info)); + if (copy_from_user(&info, arg, sizeof (struct loop_info))) + return -EFAULT; if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; - switch (info.lo_encrypt_type) { - case LO_CRYPT_NONE: - break; - case LO_CRYPT_XOR: - if (info.lo_encrypt_key_size < 0) - return -EINVAL; - break; -#ifdef DES_AVAILABLE - case LO_CRYPT_DES: - if (info.lo_encrypt_key_size != 8) - return -EINVAL; - des_set_key((des_cblock *) lo->lo_encrypt_key, - lo->lo_des_key); - memcpy(lo->lo_des_init,info.lo_init,8); - break; -#endif -#ifdef IDEA_AVAILABLE - case LO_CRYPT_IDEA: - { - uint16 tmpkey[8]; - - if (info.lo_encrypt_key_size != IDEAKEYSIZE) - return -EINVAL; - /* create key in lo-> from info.lo_encrypt_key */ - memcpy(tmpkey,info.lo_encrypt_key,sizeof(tmpkey)); - en_key_idea(tmpkey,lo->lo_idea_en_key); - de_key_idea(lo->lo_idea_en_key,lo->lo_idea_de_key); - break; - } -#endif - default: + type = info.lo_encrypt_type; + if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; - } + err = loop_release_xfer(lo); + if (err) + return err; + if (xfer_funcs[type]->init) + err = xfer_funcs[type]->init(lo, &info); + if (err) + return err; + lo->lo_offset = info.lo_offset; strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE); - lo->lo_encrypt_type = info.lo_encrypt_type; - lo->transfer = xfer_funcs[lo->lo_encrypt_type]; + lo->lo_encrypt_type = type; + + lo->transfer = xfer_funcs[type]->transfer; + lo->ioctl = xfer_funcs[type]->ioctl; lo->lo_encrypt_key_size = info.lo_encrypt_key_size; - if (info.lo_encrypt_key_size) - memcpy(lo->lo_encrypt_key, info.lo_encrypt_key, + lo->lo_init[0] = info.lo_init[0]; + lo->lo_init[1] = info.lo_init[1]; + if (info.lo_encrypt_key_size) { + memcpy(lo->lo_encrypt_key, info.lo_encrypt_key, info.lo_encrypt_key_size); + lo->lo_key_owner = current->uid; + } figure_loop_size(lo); return 0; } @@ -552,15 +512,11 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg) static int loop_get_status(struct loop_device *lo, struct loop_info *arg) { struct loop_info info; - int err; - + if (!lo->lo_dentry) return -ENXIO; if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE, arg, sizeof(info)); - if (err) - return err; memset(&info, 0, sizeof(info)); info.lo_number = lo->lo_number; info.lo_device = kdev_t_to_nr(lo->lo_dentry->d_inode->i_dev); @@ -575,8 +531,7 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg) memcpy(info.lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); } - copy_to_user(arg, &info, sizeof(info)); - return 0; + return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0; } static int lo_ioctl(struct inode * inode, struct file * file, @@ -611,7 +566,7 @@ static int lo_ioctl(struct inode * inode, struct file * file, return -EINVAL; return put_user(loop_sizes[lo->lo_number] << 1, (long *) arg); default: - return -EINVAL; + return lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } return 0; } @@ -628,8 +583,9 @@ static int lo_open(struct inode *inode, struct file *file) return -ENODEV; } dev = MINOR(inode->i_rdev); - if (dev >= MAX_LOOP) + if (dev >= MAX_LOOP) { return -ENODEV; + } lo = &loop_dev[dev]; lo->lo_refcnt++; MOD_INC_USE_COUNT; @@ -639,7 +595,7 @@ static int lo_open(struct inode *inode, struct file *file) static int lo_release(struct inode *inode, struct file *file) { struct loop_device *lo; - int dev; + int dev, err = 0; if (!inode) return 0; @@ -650,15 +606,18 @@ static int lo_release(struct inode *inode, struct file *file) dev = MINOR(inode->i_rdev); if (dev >= MAX_LOOP) return 0; - fsync_dev(inode->i_rdev); + err = fsync_dev(inode->i_rdev); + if (err < 0) + return err; lo = &loop_dev[dev]; if (lo->lo_refcnt <= 0) printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt); else { - lo->lo_refcnt--; + if (--lo->lo_refcnt == 0) + err = loop_release_xfer(lo); MOD_DEC_USE_COUNT; } - return 0; + return err; } static struct file_operations lo_fops = { @@ -681,8 +640,28 @@ static struct file_operations lo_fops = { #define loop_init init_module #endif -__initfunc(int -loop_init( void )) { +int loop_register_transfer(struct loop_func_table *funcs) +{ + if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number]) + return -EINVAL; + xfer_funcs[funcs->number] = funcs; + return 0; +} + +/* Usage checking must be done by the caller - usually with MOD_INC/DEC_* */ +int loop_unregister_transfer(int number) +{ + if ((unsigned)number >= MAX_LO_CRYPT) + return -EINVAL; + xfer_funcs[number] = NULL; + return 0; +} + +EXPORT_SYMBOL(loop_register_transfer); +EXPORT_SYMBOL(loop_unregister_transfer); + +int __init loop_init(void) +{ int i; if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) { @@ -692,12 +671,6 @@ loop_init( void )) { } #ifndef MODULE printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR); -#ifdef DES_AVAILABLE - printk(KERN_INFO "loop: DES encryption available\n"); -#endif -#ifdef IDEA_AVAILABLE - printk(KERN_INFO "loop: IDEA encryption available\n"); -#endif #endif blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; @@ -714,9 +687,9 @@ loop_init( void )) { } #ifdef MODULE -void -cleanup_module( void ) { - if (unregister_blkdev(MAJOR_NR, "loop") != 0) - printk(KERN_WARNING "loop: cleanup_module failed\n"); +void cleanup_module(void) +{ + if (unregister_blkdev(MAJOR_NR, "loop") != 0) + printk(KERN_WARNING "loop: cannot unregister blkdev\n"); } #endif diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 465d245454b0..ba5fbf53d3f4 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -160,6 +160,7 @@ #include #include #include +#include #include #include @@ -1690,7 +1691,7 @@ do_cdu31a_request(void) /* Make sure we have a valid TOC. */ sony_get_toc(); - sti(); + spin_unlock_irq(&io_request_lock); /* Make sure the timer is cancelled. */ del_timer(&cdu31a_abort_timer); @@ -1849,7 +1850,7 @@ try_read_again: } end_do_cdu31a_request: - cli(); + spin_lock_irq(&io_request_lock); #if 0 /* After finished, cancel any pending operations. */ abort_read(); diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index d1e114301396..f5fdc65db005 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -186,6 +186,7 @@ History: #include #include #include +#include /* #include */ @@ -816,6 +817,7 @@ static void do_cm206_request(void) end_request(0); continue; } + spin_unlock_irq(&io_request_lock); error=0; for (i=0; inr_sectors; i++) { int e1, e2; @@ -838,6 +840,7 @@ static void do_cm206_request(void) debug(("cm206_request: %d %d\n", e1, e2)); } } + spin_lock_irq(&io_request_lock); end_request(!error); } } diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 11b99e645aac..de9009a8c0a1 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -336,6 +336,7 @@ #include #include #include +#include #include #include @@ -1487,13 +1488,14 @@ static int cmd_out(void) if (flags_cmd_out&f_putcmd) { + unsigned long flags; for (i=0;i<7;i++) sprintf(&msgbuf[i*3], " %02X", drvcmd[i]); msgbuf[i*3]=0; msg(DBG_CMD,"cmd_out:%s\n", msgbuf); - cli(); + save_flags(flags); cli(); for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); - sti(); + restore_flags(flags); } if (response_count!=0) { @@ -4824,7 +4826,7 @@ static void DO_SBPCD_REQUEST(void) INIT_REQUEST; req=CURRENT; /* take out our request so no other */ CURRENT=req->next; /* task can fuck it up GTL */ - sti(); + spin_unlock_irq(&io_request_lock); /* FIXME!!!! */ down(&ioctl_read_sem); if (req->rq_status == RQ_INACTIVE) @@ -4869,6 +4871,7 @@ static void DO_SBPCD_REQUEST(void) xnr, req, req->sector, req->nr_sectors, jiffies); #endif sbpcd_end_request(req, 1); + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ goto request_loop; } @@ -4908,6 +4911,7 @@ static void DO_SBPCD_REQUEST(void) xnr, req, req->sector, req->nr_sectors, jiffies); #endif sbpcd_end_request(req, 1); + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ goto request_loop; } } @@ -4922,6 +4926,7 @@ static void DO_SBPCD_REQUEST(void) #endif sbpcd_end_request(req, 0); sbp_sleep(0); /* wait a bit, try again */ + spin_lock_irq(&io_request_lock); /* FIXME!!!! */ goto request_loop; } /*==========================================================================*/ @@ -5098,13 +5103,11 @@ static int sbp_data(struct request *req) { msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j); error_flag++; - break; } if (try==0) { msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j); error_flag++; - break; } if (!(j&s_not_result_ready)) { @@ -5119,10 +5122,10 @@ static int sbp_data(struct request *req) msg(DBG_INF, "CD contains no data tracks.\n"); else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j); error_flag++; - break; } SBPCD_STI; - error_flag=0; + if (error_flag) break; + msg(DBG_000, "sbp_data: beginning to read.\n"); p = D_S[d].sbp_buf + frame * CD_FRAMESIZE; if (sbpro_type==1) OUT(CDo_sel_i_d,1); diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 5c5ea7b1b442..a2a9139cbb16 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -125,7 +125,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 fi dep_tristate 'Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV - if [ "$CONFIG_RADIO_ZOLTRIX" != "n" ]; then + if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi fi diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index 19c30d6fdb36..f6667efb003c 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -684,7 +684,7 @@ int palette2fmt[] = { BT848_COLOR_FMT_YCrCb422, BT848_COLOR_FMT_YCrCb411, }; -#define PALETTEFMT_MAX 11 +#define PALETTEFMT_MAX 15 static int make_rawrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, unsigned int *vbuf) @@ -2924,7 +2924,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) printk("memory: 0x%08x.\n", btv->bt848_adr); btv->pll.pll_ifreq=0; - btv->pll.pll_ifreq=0; + btv->pll.pll_ofreq=0; btv->pll.pll_crystal=0; if(pll[btv->nr]) if (!(btv->id==848 && btv->revision==0x11)) diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 9a818d4d43c7..6a65c8cfad8c 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -474,7 +474,7 @@ elmc_probe(struct device *dev)) { to use. I suspect that whoever sets the thing up initially would prefer we don't screw with those things. - Note we we read the status info when we found the card... + Note that we read the status info when we found the card... See 3c523.h for more details. */ diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 43db9bc8deb0..6a9c0990c004 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -1194,7 +1194,7 @@ static int i596_close(struct device *dev) while (lp->scb.command) if (--boguscnt == 0) { - printk("%s: close1 timed timed out with status %4.4x, cmd %4.4x.\n", + printk("%s: close1 timed out with status %4.4x, cmd %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } @@ -1205,7 +1205,7 @@ static int i596_close(struct device *dev) while (lp->scb.command) if (--boguscnt == 0) { - printk("%s: close2 timed timed out with status %4.4x, cmd %4.4x.\n", + printk("%s: close2 timed out with status %4.4x, cmd %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } diff --git a/drivers/net/Config.in b/drivers/net/Config.in index b7f36ee144e2..b51140858776 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -152,12 +152,12 @@ fi # # AppleTalk # -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +if [ "$CONFIG_ATALK" != "n" ]; then dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK - dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS + dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK if [ "$CONFIG_COPS" != "n" ]; then - bool 'Dayna firmware support' CONFIG_COPS_DAYNA - bool 'Tangent firmware support' CONFIG_COPS_TANGENT + bool 'Dayna firmware support' CONFIG_COPS_DAYNA + bool 'Tangent firmware support' CONFIG_COPS_TANGENT fi dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK if [ "$CONFIG_IPDDP" != "n" ]; then diff --git a/drivers/net/arc-rimi.c b/drivers/net/arc-rimi.c index e260d0e58410..d27fbee7cb74 100644 --- a/drivers/net/arc-rimi.c +++ b/drivers/net/arc-rimi.c @@ -4,9 +4,6 @@ Written 1994-1996 by Avery Pennarun, which was in turn derived from skeleton.c by Donald Becker. - Contact Avery at: apenwarr@bond.net or - RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9 - ********************** The original copyright of skeleton.c was as follows: @@ -130,7 +127,7 @@ extern int arcnet_num_devs; #define SETCONF writeb(lp->config,_CONFIG) static const char *version = -"arc-rimi.c: v3.00 97/11/09 Avery Pennarun et al.\n"; +"arc-rimi.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** * * diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index 8926902a5cd7..1111e19c73ee 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -3,9 +3,6 @@ Written 1994-1996 by Avery Pennarun, derived from skeleton.c by Donald Becker. - Contact Avery at: apenwarr@bond.net or - RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9 - ********************** The original copyright was as follows: @@ -88,7 +85,7 @@ The following has been SUMMARIZED. The complete ChangeLog is available in the full Linux-ARCnet package at - http://www.foxnet.net/~apenwarr/arcnet + http://www.worldvisions.ca/~apenwarr/arcnet v2.50 (96/02/24) - Massively improved autoprobe routines; they now work even as a @@ -181,7 +178,7 @@ */ static const char *version = - "arcnet.c: v3.02 98/06/07 Avery Pennarun et al.\n"; + "arcnet.c: v3.02 98/06/07 Avery Pennarun et al.\n"; #include #include diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 232b714a8822..baaa5969298d 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -545,6 +545,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) struct ariadne_private *priv = (struct ariadne_private *)dev->priv; struct AriadneBoard *board = priv->board; int entry; + unsigned long flags; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { @@ -625,6 +626,9 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); #endif + save_flags(flags); + cli(); + entry = priv->cur_tx % TX_RING_SIZE; /* Caution: the write order is important here, set the base address with @@ -675,13 +679,12 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev) dev->trans_start = jiffies; - cli(); priv->lock = 0; if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) == 0) dev->tbusy = 0; else priv->tx_full = 1; - sti(); + restore_flags(flags); return(0); } @@ -780,13 +783,15 @@ static struct net_device_stats *ariadne_get_stats(struct device *dev) struct ariadne_private *priv = (struct ariadne_private *)dev->priv; struct AriadneBoard *board = priv->board; short saved_addr; + unsigned long flags; + save_flags(flags); cli(); saved_addr = board->Lance.RAP; board->Lance.RAP = CSR112; /* Missed Frame Count */ priv->stats.rx_missed_errors = swapw(board->Lance.RDP); board->Lance.RAP = saved_addr; - sti(); + restore_flags(flags); return(&priv->stats); } diff --git a/drivers/net/com20020.c b/drivers/net/com20020.c index 5c9ac32ab5a7..093a5acf00c8 100644 --- a/drivers/net/com20020.c +++ b/drivers/net/com20020.c @@ -6,9 +6,6 @@ Written 1994-1996 by Avery Pennarun, which was in turn derived from skeleton.c by Donald Becker. - Contact Avery at: apenwarr@bond.net or - RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9 - ********************** The original copyright of skeleton.c was as follows: @@ -214,7 +211,7 @@ void put_whole_buffer (struct device *dev, unsigned offset, unsigned length, cha static const char *version = - "com20020.c: v3.00 97/11/09 Avery Pennarun et al.\n"; + "com20020.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** * * diff --git a/drivers/net/com90io.c b/drivers/net/com90io.c index 46f5d6f2ec57..3096544602b3 100644 --- a/drivers/net/com90io.c +++ b/drivers/net/com90io.c @@ -6,9 +6,6 @@ Written 1994-1996 by Avery Pennarun, which was in turn derived from skeleton.c by Donald Becker. - Contact Avery at: apenwarr@bond.net or - RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9 - ********************** The original copyright of skeleton.c was as follows: @@ -183,7 +180,7 @@ void put_whole_buffer (struct device *dev, unsigned offset, unsigned length, cha static const char *version = - "com90io.c: v3.00 97/11/09 Avery Pennarun et al.\n"; + "com90io.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** diff --git a/drivers/net/com90xx.c b/drivers/net/com90xx.c index f605ce20b3f5..3ca5a5ef88f6 100644 --- a/drivers/net/com90xx.c +++ b/drivers/net/com90xx.c @@ -4,9 +4,6 @@ Written 1994-1996 by Avery Pennarun, which was in turn derived from skeleton.c by Donald Becker. - Contact Avery at: apenwarr@bond.net or - RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9 - ********************** The original copyright of skeleton.c was as follows: @@ -153,7 +150,7 @@ extern int arcnet_num_devs; #define ARCRESET inb(_RESET) static const char *version = -"com90xx.c: v3.00 97/11/09 Avery Pennarun et al.\n"; +"com90xx.c: v3.00 97/11/09 Avery Pennarun et al.\n"; /**************************************************************************** diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c index 0b550fd570d9..1c563cce9b3d 100644 --- a/drivers/net/daynaport.c +++ b/drivers/net/daynaport.c @@ -30,6 +30,8 @@ static const char *version = #include #include #include +#include +#include #include #include @@ -57,6 +59,13 @@ static void sane_block_input(struct device *dev, int count, static void sane_block_output(struct device *dev, int count, const unsigned char *buf, const start_page); +static void slow_sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void slow_sane_block_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void slow_sane_block_output(struct device *dev, int count, + const unsigned char *buf, const int start_page); + #define WD_START_PG 0x00 /* First page of TX buffer */ #define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ @@ -81,11 +90,11 @@ static int test_8390(volatile char *ptr, int scale) int regd; int v; - if(nubus_hwreg_present(&ptr[0x00])==0) + if(hwreg_present(&ptr[0x00])==0) return -EIO; - if(nubus_hwreg_present(&ptr[0x0D<base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE); dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM); - dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ + + memsize = apple_8390_mem_probe((void *)dev->mem_start); + + dev->mem_end=dev->mem_start+memsize; dev->irq=slot; printk("apple/clone: testing board: "); - printk("memory - "); + printk("%dK memory - ", memsize>>10); i=(void *)dev->mem_start; - memset((void *)i,0xAA, DAYNA_MEMSIZE); + memset((void *)i,0xAA, memsize); while(i<(volatile unsigned short *)dev->mem_end) { if(*i!=0xAAAA) @@ -366,8 +425,15 @@ int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, in ei_status.get_8390_hdr = &dayna_get_8390_hdr; ei_status.reg_offset = fwrd4_offsets; break; - case NS8390_APPLE: /* Apple/Asante/Farallon */ case NS8390_FARALLON: + case NS8390_APPLE: /* Apple/Asante/Farallon */ + /* 16 bit card, register map is reversed */ + ei_status.reset_8390 = &ns8390_no_reset; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; case NS8390_ASANTE: /* 16 bit card, register map is reversed */ ei_status.reset_8390 = &ns8390_no_reset; @@ -442,7 +508,7 @@ static void interlan_reset(struct device *dev) { unsigned char *target=nubus_slot_addr(dev->irq); if (ei_debug > 1) - printk("Need to reset the NS8390 t=%lu...", jiffies); + printk("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; /* This write resets the card */ target[0xC0000]=0; @@ -585,6 +651,7 @@ static void sane_block_input(struct device *dev, int count, struct sk_buff *skb, } } + static void sane_block_output(struct device *dev, int count, const unsigned char *buf, int start_page) { @@ -593,6 +660,81 @@ static void sane_block_output(struct device *dev, int count, const unsigned char memcpy((char *)dev->mem_start+shmem, buf, count); } +static void word_memcpy_tocard(void *tp, const void *fp, int count) +{ + volatile unsigned short *to = tp; + const unsigned short *from = fp; + + count++; + count/=2; + + while(count--) + *to++=*from++; +} + +static void word_memcpy_fromcard(void *tp, const void *fp, int count) +{ + unsigned short *to = tp; + const volatile unsigned short *from = fp; + + count++; + count/=2; + + while(count--) + *to++=*from++; +} + +static void slow_sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4); + /* Register endianism - fix here rather than 8390.c */ + hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); +} + +static void slow_sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base+dev->mem_start; + + if (xfer_start + count > dev->rmem_end) + { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count); + count -= semi_count; + word_memcpy_fromcard(skb->data + semi_count, + (char *)dev->rmem_start, count); + } + else + { + word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, count); + } +} + +static void slow_sane_block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + word_memcpy_tocard((char *)dev->mem_start+shmem, buf, count); +#if 0 + long shmem = (start_page - WD_START_PG)<<8; + volatile unsigned short *to=(unsigned short *)(dev->mem_start+shmem); + volatile int p; + unsigned short *bp=(unsigned short *)buf; + + count=(count+1)/2; + + while(count--) + { + *to++=*bp++; + for(p=0;p<10;p++) + p++; + } +#endif +} + /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c" diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index bf453dc53c58..fd257f11f2a4 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -1,5 +1,5 @@ /* - * $Id: dmascc.c,v 1.2.1.4 1998/06/10 02:24:11 kudielka Exp $ + * $Id: dmascc.c,v 1.3 1998/09/07 04:41:56 kudielka Exp $ * * Driver for high-speed SCC boards (those with DMA support) * Copyright (C) 1997 Klaus Kudielka @@ -62,6 +62,14 @@ #define test_and_set_bit(x,y) set_bit(x,y) #define register_netdevice(x) register_netdev(x) #define unregister_netdevice(x) unregister_netdev(x) +#define dev_kfree_skb(x) dev_kfree_skb(x,FREE_WRITE) +#define SET_DEV_INIT(x) (x=dmascc_dev_init) + +#define SHDLCE 0x01 /* WR15 */ + +#define AUTOEOM 0x02 /* WR7' */ +#define RXFIFOH 0x08 +#define TXFIFOE 0x20 static int dmascc_dev_init(struct device *dev) { @@ -83,7 +91,7 @@ static void dev_init_buffers(struct device *dev) #include #include -#define dmascc_dev_init NULL +#define SET_DEV_INIT(x) #endif @@ -286,7 +294,7 @@ static unsigned long rand; #ifdef MODULE -MODULE_AUTHOR("Klaus Kudielka "); +MODULE_AUTHOR("Klaus Kudielka"); MODULE_DESCRIPTION("Driver for high-speed SCC boards"); MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); @@ -462,8 +470,8 @@ __initfunc(int setup_adapter(int io, int h, int n)) /* Reset 8530 */ write_scc(cmd, R9, FHWRES | MIE | NV); - /* Determine type of chip */ - write_scc(cmd, R15, 1); + /* Determine type of chip by enabling SDLC/HDLC enhancements */ + write_scc(cmd, R15, SHDLCE); if (!read_scc(cmd, R15)) { /* WR7' not present. This is an ordinary Z8530 SCC. */ chip = Z8530; @@ -575,7 +583,7 @@ __initfunc(int setup_adapter(int io, int h, int n)) dev->hard_header = ax25_encapsulate; dev->rebuild_header = ax25_rebuild_header; dev->set_mac_address = scc_set_mac_address; - dev->init = dmascc_dev_init; + SET_DEV_INIT(dev->init); dev->type = ARPHRD_AX25; dev->hard_header_len = 73; dev->mtu = 1500; @@ -662,17 +670,17 @@ static int scc_open(struct device *dev) switch (info->chip) { case Z85C30: /* Select WR7' */ - write_scc(cmd, R15, 1); + write_scc(cmd, R15, SHDLCE); /* Auto EOM reset */ - write_scc(cmd, R7, 0x02); + write_scc(cmd, R7, AUTOEOM); write_scc(cmd, R15, 0); break; case Z85230: /* Select WR7' */ - write_scc(cmd, R15, 1); + write_scc(cmd, R15, SHDLCE); /* RX FIFO half full (interrupt only), Auto EOM reset, TX FIFO empty (DMA only) */ - write_scc(cmd, R7, dev->dma ? 0x22 : 0x0a); + write_scc(cmd, R7, AUTOEOM | (dev->dma ? TXFIFOE : RXFIFOH)); write_scc(cmd, R15, 0); break; } diff --git a/drivers/net/hamradio/z8530.h b/drivers/net/hamradio/z8530.h index 3d4a918d7d7b..8bef548572aa 100644 --- a/drivers/net/hamradio/z8530.h +++ b/drivers/net/hamradio/z8530.h @@ -219,15 +219,17 @@ /* Read Register 15 (value of WR 15) */ -/* 8580/85180/85280 Enhanced SCC register definitions */ +/* Z85C30/Z85230 Enhanced SCC register definitions */ /* Write Register 7' (SDLC/HDLC Programmable Enhancements) */ #define AUTOTXF 0x01 /* Auto Tx Flag */ #define AUTOEOM 0x02 /* Auto EOM Latch Reset */ #define AUTORTS 0x04 /* Auto RTS */ #define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */ +#define RXFIFOH 0x08 /* Z85230: Int on RX FIFO half full */ #define FASTDTR 0x10 /* Fast DTR/REQ Mode */ #define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */ +#define TXFIFOE 0x20 /* Z85230: Int on TX FIFO completely empty */ #define EXTRDEN 0x40 /* Extended Read Enabled */ /* Write Register 15 (external/status interrupt control) */ @@ -240,4 +242,4 @@ /* Read Register 7 (frame status FIFO) */ #define BCMSB 0x3f /* MSB of 14 bits count */ #define FDA 0x40 /* FIFO Data Available Status */ -#define FOY 0x80 /* FIFO Overflow Status */ +#define FOS 0x80 /* FIFO Overflow Status */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 5dd8d1d54f01..89193380683b 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1175,7 +1175,7 @@ void plip_setup(char *str, int *ints) timid = 1; } else { if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "parport=" or "parport=0" */ + /* disable driver on "plip=" or "plip=0" */ parport[0] = -2; } else { printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n", diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index d266c64b76e9..84bfe9863559 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -14,8 +14,11 @@ #include #include #include +#include /* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */ #include +#include + #undef LCIII_WEIRDNESS @@ -26,49 +29,6 @@ static struct nubus_slot nubus_slots[16]; * -- Alan */ - - -/* This function tests for the presence of an address, specially a - * hardware register address. It is called very early in the kernel - * initialization process, when the VBR register isn't set up yet. On - * an Atari, it still points to address 0, which is unmapped. So a bus - * error would cause another bus error while fetching the exception - * vector, and the CPU would do nothing at all. So we needed to set up - * a temporary VBR and a vector table for the duration of the test. - * - * See the atari/config.c code we nicked it from for more clues. - */ - -int nubus_hwreg_present( volatile void *regp ) -{ - int ret = 0; - long save_sp, save_vbr; - long tmp_vectors[3]; - unsigned long flags; - - save_flags(flags); - cli(); - - __asm__ __volatile__ - ( "movec %/vbr,%2\n\t" - "movel #Lberr1,%4@(8)\n\t" - "movec %4,%/vbr\n\t" - "movel %/sp,%1\n\t" - "moveq #0,%0\n\t" - "tstb %3@\n\t" - "nop\n\t" - "moveq #1,%0\n" - "Lberr1:\n\t" - "movel %1,%/sp\n\t" - "movec %2,%/vbr" - : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) - : "a" (regp), "a" (tmp_vectors) - ); - restore_flags(flags); - return( ret ); -} - - /* * Yes this sucks. The ROM can appear on arbitary bytes of the long @@ -104,7 +64,7 @@ static void nubus_rewind(unsigned char **ptr, int len, int map) { unsigned char *p=*ptr; - if(len>8192) + if(len>65536) printk("rewind of %d!\n", len); while(len) { @@ -121,7 +81,7 @@ static void nubus_rewind(unsigned char **ptr, int len, int map) static void nubus_advance(unsigned char **ptr, int len, int map) { unsigned char *p=*ptr; - if(len>8192) + if(len>65536) printk("advance of %d!\n", len); while(len) { @@ -375,7 +335,7 @@ void nubus_probe_slot(int slot, int mode) { rp--; - if(!nubus_hwreg_present(rp)) + if(!hwreg_present(rp)) continue; dp=*rp; @@ -596,6 +556,52 @@ int nubus_ethernet_addr(int slot, unsigned char *addr) return ng; } +#ifdef CONFIG_PROC_FS + +/* + * /proc for Nubus devices + */ + +static int sprint_nubus_config(int slot, char *ptr, int len) +{ + if(len<150) + return -1; + sprintf(ptr, "Device: %s %s\n", nubus_slots[slot].slot_cardname, + (nubus_slots[slot].slot_flags&NUBUS_DEVICE_ACTIVE)? + "[active]":"[unused]"); + return strlen(ptr); +} + +int get_nubus_list(char *buf) +{ + int nprinted, len, size; + int slot; +#define MSG "\nwarning: page-size limit reached!\n" + + /* reserve same for truncation warning message: */ + size = PAGE_SIZE - (strlen(MSG) + 1); + len = sprintf(buf, "Nubus devices found:\n"); + + for (slot=0; slot< 16; slot++) + { + if(!(nubus_slots[slot].slot_flags&NUBUS_DEVICE_PRESENT)) + continue; + nprinted = sprint_nubus_config(slot, buf + len, size - len); + if (nprinted < 0) { + return len + sprintf(buf + len, MSG); + } + len += nprinted; + } + return len; +} + +static struct proc_dir_entry proc_nubus = { + PROC_NUBUS, 5, "nubus", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations +}; +#endif + void nubus_init(void) { /* @@ -626,4 +632,7 @@ void nubus_init(void) nubus_init_via(); printk("Scanning nubus slots.\n"); nubus_probe_bus(); + proc_register(&proc_root, &proc_nubus); } + + \ No newline at end of file diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index ad397c1206be..61d35daeb065 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -50,6 +50,13 @@ dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) supp dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT + if [ "$CONFIG_SCSI_PPA" != "n" ]; then + int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3 + fi + dep_tristate 'IOMEGA ZIP Plus drive SCSI support' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT +fi if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then bool ' Enable NCR53c400 extensions' CONFIG_SCSI_GENERIC_NCR53C400 choice 'NCR5380/53c400 mapping method (use Port for T130B)' \ @@ -88,12 +95,6 @@ if [ "$CONFIG_MCA" = "y" ]; then bool ' Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET fi fi -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT - if [ "$CONFIG_SCSI_PPA" != "n" ]; then - int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3 - fi -fi dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI dep_tristate 'PCI2000 support' CONFIG_SCSI_PCI2000 $CONFIG_SCSI dep_tristate 'PCI2220i support' CONFIG_SCSI_PCI2220I $CONFIG_SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 6441113acc8d..7caa67ed333c 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -243,6 +243,14 @@ else endif endif +ifeq ($(CONFIG_SCSI_IMM),y) +L_OBJS += imm.o +else + ifeq ($(CONFIG_SCSI_IMM),m) + M_OBJS += imm.o + endif +endif + ifeq ($(CONFIG_SCSI_QLOGIC_FAS),y) L_OBJS += qlogicfas.o else diff --git a/drivers/scsi/README.ppa b/drivers/scsi/README.ppa index 509541d7a8fb..0dac88d86d87 100644 --- a/drivers/scsi/README.ppa +++ b/drivers/scsi/README.ppa @@ -1,119 +1,16 @@ -README.ppa (c) 1996 Grant R. Guenther, grant@torque.net +-------- Terse where to get ZIP Drive help info -------- +General Iomega ZIP drive page for Linux: +http://www.torque.net/~campbell/ - The IOMEGA PPA3 parallel port SCSI Host Bus Adapter +Driver achive for old drivers: +http://www.torque.net/~campbell/ppa/ - as embedded in the ZIP drive +Linux Parport page (parallel port) +http://www.torque.net/parport/ +Email list for Linux Parport +linux-parport@torque.net -This README documents the Linux support for the parallel port version of -IOMEGA's ZIP100. The ZIP100 is an inexpensive and popular, but relatively -low performance, removable medium disk device. The drive is also available -as a regular SCSI device, but the driver documented here is for the -parallel port version. IOMEGA implemented the parallel port version by -integrating (or emulating ?) their PPA3 parallel to SCSI converter into -the ZIP drive. - -I have implemented a low-level driver, ppa.c, for this parallel port -host bus adapter, thereby supporting the parallel port ZIP drive as a -regular SCSI device under Linux. - -It is possible that this driver will also work with the original PPA3 -device (to access a CDrom, for instance). But, the PPA3 is hard to find -and costs as much as the ZIP drive itself, so no-one has actually tried -this, to the best of my knowledge. - -The driver was developed without the benefit of any technical specifications -for the interface. Instead, a modified version of DOSemu was used to -monitor the protocol used by the DOS driver, 'guest.exe', for this adapter. -I have no idea how my programming model relates to IOMEGA's design. -(One technical consequence of this method: I have never observed a -SCSI message byte in the protocol transactions between guest.exe and -the ZIP drive, so I do not know how they are delivered. My working -hypothesis is that we don't have to worry about them if we don't -send linked commands to the drive.) - -I'd like to thank Byron Jeff (byron@cc.gatech.edu) for publishing his -observation that the 'guest' driver loads under DOSemu. His remark was -the stimulus that began this project. - -The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but -there is currently no support for EPP or ECP ports, as I have been unable -to make the DOS drivers work in these modes on my test rig. - -The driver may be built in to the kernel, or loaded as a module. It -may be configured on the command line in both cases, although the syntax -is different. It may also be configured by editing the source file. - -Built-in drivers accept parameters using this LILO/LOADLIN command line -syntax (omitted parameters retain their default values): - - ppa=base[,speed_high[,speed_low[,nybble]]] - -For example: ppa=0x378,0,3 - -If a driver is loaded as a module the parameters may be set on the -insmod command line, but each one must be specified by name: - -For example: insmod ppa.o ppa_base=0x378 ppa_nybble=1 - -(Notice the ppa_ prefix on each of the parameters in the insmod form.) - -Here are the parameters and their functions: - -Variable Default Description - -ppa_base 0x378 The base address of PPA's parallel port. -ppa_speed_high 1 Microsecond i/o delay used in data transfers -ppa_speed_low 6 Microsecond delay used in other operations -ppa_nybble 0 1 to force the driver to use 4-bit mode. - -A word about the timing parameters: the ppa_speed_low parameter controls -the widths of a large number of pulses that are sent over the parallel bus, -the narrower the pulses, the faster things go, but the greater the risk of -distortion by noise damping circuits in the parallel ports. The -ppa_speed_high parameter controls the same delays, but during the data -transfer phase only. In this phase, there is a lot of handshaking going -on and the pulse shaping should not be so much of an issue, but if you -see data corruption, you can increase this parameter as well. - -You might also want to reduce the timing values to attempt to increase -the transfer rates on your system. Please be careful to watch for -SCSI timeout errors in your log files. If you are getting timeouts, you -have set these parameters too low. The default values appear to be -safe on most machines. - -If you have both the lp and ppa drivers in your kernel, you must ensure -that they access different parallel ports. By default, the lp driver is -initialised early in the booting process, and it claims all parallel -ports that it can find. You may control this behaviour with a LILO or -LOADLIN command line argument of the form: - - lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]] - -For example: lp=0x278,7 - -If you use this method, only the ports named will be adopted by the lp -driver. You can disable them all with lp=0 . - -So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would -give the following options on your boot command: - - lp=0x3bc ppa=0x278 - -In this case lp would use the polling driver, since an interrupt was not -specified. - -If you want to share the same parallel port between a ZIP drive and a -printer, you should build both the lp and ppa drivers as modules and -load and unload one or the other as required. This is clumsy but we -currently have no protocol for synchronising access to shared parallel -ports. - -For information about using the ZIP drive, please read the generic -instructions in the SCSI-HOWTO and the man pages for the normal disk -management tools, fdisk, mkfs, mount, umount, etc. There is a mini-HOWTO -circulating concerning the use of the normal SCSI version of the ZIP -drive, most of its comments will apply to disks connected through the -ppa driver as well. - +Email for problems with ZIP or ZIP Plus drivers +campbell@torque.net diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 276930d52e26..2567195895b8 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -197,10 +197,6 @@ #include "AM53C974.h" #endif -#ifdef CONFIG_SCSI_PPA -#include "ppa.h" -#endif - #ifdef CONFIG_SCSI_SUNESP #include "esp.h" #endif @@ -273,6 +269,20 @@ #include "jazz_esp.h" #endif +/* + * Moved ppa driver to the end of the probe list + * since it is a removable host adapter. + * This means the parallel ZIP drive will not bump + * the order of the /dev/sd devices - campbell@torque.net + */ +#ifdef CONFIG_SCSI_PPA +#include "ppa.h" +#endif + +#ifdef CONFIG_SCSI_IMM +#include "imm.h" +#endif + /* static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $"; */ @@ -441,9 +451,6 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #ifdef CONFIG_SCSI_AM53C974 AM53C974, #endif -#ifdef CONFIG_SCSI_PPA - PPA, -#endif #ifdef CONFIG_SCSI_SUNESP SCSI_SPARC_ESP, #endif @@ -485,6 +492,13 @@ static Scsi_Host_Template builtin_scsi_hosts[] = POWERTECSCSI, #endif #endif +/* "Removable host adapters" below this line (Parallel Port/USB/other) */ +#ifdef CONFIG_SCSI_PPA + PPA, +#endif +#ifdef CONFIG_SCSI_IMM + IMM, +#endif #ifdef CONFIG_SCSI_DEBUG SCSI_DEBUG, #endif diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c new file mode 100644 index 000000000000..eedd71bdcbb9 --- /dev/null +++ b/drivers/scsi/imm.c @@ -0,0 +1,1321 @@ +/* imm.c -- low level driver for the IOMEGA MatchMaker + * parallel port SCSI host adapter. + * + * (The IMM is the embedded controller in the ZIP Plus drive.) + * + * Current Maintainer: David Campbell (Perth, Western Australia) + * campbell@gear.torque.net + * dcampbel@p01.as17.honeywell.com.au + * + * My unoffical company acronym list is 21 pages long: + * FLA: Four letter acronym with built in facility for + * future expansion to five letters. + */ + +#include + +/* The following #define is to avoid a clash with hosts.c */ +#define IMM_CODE 1 +#define IMM_PROBE_SPP 0x0001 +#define IMM_PROBE_PS2 0x0002 +#define IMM_PROBE_ECR 0x0010 +#define IMM_PROBE_EPP17 0x0100 +#define IMM_PROBE_EPP19 0x0200 + +void imm_reset_pulse(unsigned int base); +static int device_check(int host_no); + +#include +#include +#include +#include "sd.h" +#include "hosts.h" +typedef struct { + struct pardevice *dev; /* Parport device entry */ + int base; /* Actual port address */ + int mode; /* Transfer mode */ + int host; /* Host number (for proc) */ + Scsi_Cmnd *cur_cmd; /* Current queued command */ + struct tq_struct imm_tq; /* Polling interupt stuff */ + unsigned long jstart; /* Jiffies at start */ + unsigned failed:1; /* Failure flag */ + unsigned dp:1; /* Data phase present */ + unsigned rd:1; /* Read data in data phase */ + unsigned p_busy:1; /* Parport sharing busy flag */ +} imm_struct; + +#define IMM_EMPTY \ +{ dev: NULL, \ + base: -1, \ + mode: IMM_AUTODETECT, \ + host: -1, \ + cur_cmd: NULL, \ + imm_tq: {0, 0, imm_interrupt, NULL}, \ + jstart: 0, \ + failed: 0, \ + dp: 0, \ + rd: 0, \ + p_busy: 0 \ +} + +#include "imm.h" +#define NO_HOSTS 4 +static imm_struct imm_hosts[NO_HOSTS] = +{IMM_EMPTY, IMM_EMPTY, IMM_EMPTY, IMM_EMPTY}; + +#define IMM_BASE(x) imm_hosts[(x)].base + +int base[NO_HOSTS] = +{0x03bc, 0x0378, 0x0278, 0x0000}; + +void imm_wakeup(void *ref) +{ + imm_struct *imm_dev = (imm_struct *) ref; + + if (!imm_dev->p_busy) + return; + + if (parport_claim(imm_dev->dev)) { + printk("imm: bug in imm_wakeup\n"); + return; + } + imm_dev->p_busy = 0; + imm_dev->base = imm_dev->dev->port->base; + if (imm_dev->cur_cmd) + imm_dev->cur_cmd->SCp.phase++; + return; +} + +int imm_release(struct Scsi_Host *host) +{ + int host_no = host->unique_id; + + printk("Releasing imm%i\n", host_no); + parport_unregister_device(imm_hosts[host_no].dev); + return 0; +} + +static int imm_pb_claim(int host_no) +{ + if (parport_claim(imm_hosts[host_no].dev)) { + imm_hosts[host_no].p_busy = 1; + return 1; + } + + if (imm_hosts[host_no].cur_cmd) + imm_hosts[host_no].cur_cmd->SCp.phase++; + return 0; +} + +#define imm_pb_release(x) parport_release(imm_hosts[(x)].dev) + +/*************************************************************************** + * Parallel port probing routines * + ***************************************************************************/ + +#ifndef MODULE +/* + * Command line parameters (for built-in driver): + * + * Syntax: imm=base[,mode[,use_sg]] + * + * For example: imm=0x378 or imm=0x378,0,3 + * + */ + +void imm_setup(char *str, int *ints) +{ + static int x = 0; + + if (x == 0) { /* Disable ALL known ports */ + int i; + + for (i = 0; i < NO_HOSTS; i++) + parbus_base[i] = 0x0000; + } + switch (ints[0]) { + case 3: + imm_sg = ints[3]; + case 2: + imm_hosts[x].mode = ints[2]; + parbus_base[x] = ints[1]; + break; + default: + printk("IMM: I only use between 2 to 3 parameters.\n"); + break; + } + x++; +} +#else +Scsi_Host_Template driver_template = IMM; +#include "scsi_module.c" +#endif + +int imm_detect(Scsi_Host_Template * host) +{ + struct Scsi_Host *hreg; + int ports; + int i, nhosts, try_again; + struct parport *pb = parport_enumerate(); + + printk("imm: Version %s\n", IMM_VERSION); + nhosts = 0; + try_again = 0; + + if (!pb) { + printk("imm: parport reports no devices.\n"); + return 0; + } + + retry_entry: + for (i = 0; pb; i++, pb = pb->next) { + int modes, ppb; + + imm_hosts[i].dev = + parport_register_device(pb, "imm", NULL, imm_wakeup, + NULL, PARPORT_DEV_TRAN, (void *) &imm_hosts[i]); + + /* Claim the bus so it remembers what we do to the control + * registers. [ CTR and ECP ] + */ + if (imm_pb_claim(i)) + while (imm_hosts[i].p_busy) + schedule(); /* We are safe to schedule here */ + + ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base; + w_ctr(ppb, 0x0c); + modes = imm_hosts[i].dev->port->modes; + + /* Mode detection works up the chain of speed + * This avoids a nasty if-then-else-if-... tree + */ + imm_hosts[i].mode = IMM_NIBBLE; + + if (modes & PARPORT_MODE_PCPS2) + imm_hosts[i].mode = IMM_PS2; + + if (modes & PARPORT_MODE_PCECPPS2) { + w_ecr(ppb, 0x20); + imm_hosts[i].mode = IMM_PS2; + } + if (modes & PARPORT_MODE_PCECPEPP) + w_ecr(ppb, 0x80); + + /* Done configuration */ + imm_pb_release(i); + + if (imm_init(i)) { + parport_unregister_device(imm_hosts[i].dev); + continue; + } + /* now the glue ... */ + switch (imm_hosts[i].mode) { + case IMM_NIBBLE: + ports = 3; + break; + case IMM_PS2: + ports = 3; + break; + case IMM_EPP_8: + case IMM_EPP_16: + case IMM_EPP_32: + ports = 8; + break; + default: /* Never gets here */ + continue; + } + + host->can_queue = IMM_CAN_QUEUE; + host->sg_tablesize = imm_sg; + hreg = scsi_register(host, 0); + hreg->io_port = pb->base; + hreg->n_io_port = ports; + hreg->dma_channel = -1; + hreg->unique_id = i; + imm_hosts[i].host = hreg->host_no; + nhosts++; + } + if (nhosts == 0) { + if (try_again == 1) + return 0; + try_again = 1; + goto retry_entry; + } else + return 1; /* return number of hosts detected */ +} + +/* This is to give the imm driver a way to modify the timings (and other + * parameters) by writing to the /proc/scsi/imm/0 file. + * Very simple method really... (To simple, no error checking :( ) + * Reason: Kernel hackers HATE having to unload and reload modules for + * testing... + * Also gives a method to use a script to obtain optimum timings (TODO) + */ + +static inline int imm_strncmp(const char *a, const char *b, int len) +{ + int loop; + for (loop = 0; loop < len; loop++) + if (a[loop] != b[loop]) + return 1; + + return 0; +} + +static inline int imm_proc_write(int hostno, char *buffer, int length) +{ + unsigned long x; + + if ((length > 5) && (imm_strncmp(buffer, "mode=", 5) == 0)) { + x = simple_strtoul(buffer + 5, NULL, 0); + imm_hosts[hostno].mode = x; + return length; + } + printk("imm /proc: invalid variable\n"); + return (-EINVAL); +} + +int imm_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + int i; + int len = 0; + + for (i = 0; i < 4; i++) + if (imm_hosts[i].host == hostno) + break; + + if (inout) + return imm_proc_write(i, buffer, length); + + len += sprintf(buffer + len, "Version : %s\n", IMM_VERSION); + len += sprintf(buffer + len, "Parport : %s\n", imm_hosts[i].dev->port->name); + len += sprintf(buffer + len, "Mode : %s\n", IMM_MODE_STRING[imm_hosts[i].mode]); + + /* Request for beyond end of buffer */ + if (offset > len) + return 0; + + *start = buffer + offset; + len -= offset; + if (len > length) + len = length; + return len; +} + +#if IMM_DEBUG > 0 +#define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\ + y, __FUNCTION__, __LINE__); imm_fail_func(x,y); +static inline void imm_fail_func(int host_no, int error_code) +#else +static inline void imm_fail(int host_no, int error_code) +#endif +{ + /* If we fail a device then we trash status / message bytes */ + if (imm_hosts[host_no].cur_cmd) { + imm_hosts[host_no].cur_cmd->result = error_code << 16; + imm_hosts[host_no].failed = 1; + } +} + +/* + * Wait for the high bit to be set. + * + * In principle, this could be tied to an interrupt, but the adapter + * doesn't appear to be designed to support interrupts. We spin on + * the 0x80 ready bit. + */ +static unsigned char imm_wait(int host_no) +{ + int k; + unsigned short ppb = IMM_BASE(host_no); + unsigned char r; + + w_ctr(ppb, 0x0c); + + k = IMM_SPIN_TMO; + do { + r = r_str(ppb); + k--; + udelay(1); + } + while (!(r & 0x80) && (k)); + + /* + * STR register (LPT base+1) to SCSI mapping: + * + * STR imm imm + * =================================== + * 0x80 S_REQ S_REQ + * 0x40 !S_BSY (????) + * 0x20 !S_CD !S_CD + * 0x10 !S_IO !S_IO + * 0x08 (????) !S_BSY + * + * imm imm meaning + * ================================== + * 0xf0 0xb8 Bit mask + * 0xc0 0x88 ZIP wants more data + * 0xd0 0x98 ZIP wants to send more data + * 0xe0 0xa8 ZIP is expecting SCSI command data + * 0xf0 0xb8 end of transfer, ZIP is sending status + */ + w_ctr(ppb, 0x04); + if (k) + return (r & 0xb8); + + /* Counter expired - Time out occured */ + imm_fail(host_no, DID_TIME_OUT); + printk("imm timeout in imm_wait\n"); + return 0; /* command timed out */ +} + +static int imm_negotiate(imm_struct * tmp) +{ + /* + * The following is supposedly the IEEE 1248-1994 negotiate + * sequence. I have yet to obtain a copy of the above standard + * so this is a bit of a guess... + * + * A fair chunk of this is based on the Linux parport implementation + * of IEEE 1284. + * + * Return 0 if data available + * 1 if no data available + */ + + unsigned short base = tmp->base; + unsigned char a, mode; + + switch (tmp->mode) { + case IMM_NIBBLE: + mode = 0x00; + break; + case IMM_PS2: + mode = 0x01; + break; + default: + return 0; + } + + w_ctr(base, 0x04); + udelay(5); + w_dtr(base, mode); + udelay(100); + w_ctr(base, 0x06); + udelay(5); + a = (r_str(base) & 0x20) ? 0 : 1; + udelay(5); + w_ctr(base, 0x07); + udelay(5); + w_ctr(base, 0x06); + + if (a) { + printk("IMM: IEEE1284 negotiate indicates no data available.\n"); + imm_fail(tmp->host, DID_ERROR); + } + return a; +} + +static inline void epp_reset(unsigned short ppb) +{ + int i; + + i = r_str(ppb); + w_str(ppb, i); + w_str(ppb, i & 0xfe); +} + +static inline void ecp_sync(unsigned short ppb) +{ + int i; + + if ((r_ecr(ppb) & 0xe0) != 0x80) + return; + + for (i = 0; i < 100; i++) { + if (r_ecr(ppb) & 0x01) + return; + udelay(5); + } + printk("imm: ECP sync failed as data still present in FIFO.\n"); +} + +static inline int imm_byte_out(unsigned short base, const char *buffer, int len) +{ + int i; + + w_ctr(base, 0x4); /* aimmrently a sane mode */ + for (i = len >> 1; i; i--) { + w_dtr(base, *buffer++); + w_ctr(base, 0x5); /* Drop STROBE low */ + w_dtr(base, *buffer++); + w_ctr(base, 0x0); /* STROBE high + INIT low */ + } + w_ctr(base, 0x4); /* aimmrently a sane mode */ + return 1; /* All went well - we hope! */ +} + +static inline int imm_epp_out(unsigned short base, char *buffer, int len) +{ + int i; + for (i = len; i; i--) + w_epp(base, *buffer++); + return 1; +} + +static inline int imm_nibble_in(unsigned short base, char *buffer, int len) +{ + unsigned char h, l; + int i; + + /* + * The following is based on documented timing signals + */ + w_ctr(base, 0x4); + for (i = len; i; i--) { + w_ctr(base, 0x6); + l = r_str(base); + w_ctr(base, 0x5); + h = r_str(base); + w_ctr(base, 0x4); + *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4); + } + return 1; /* All went well - we hope! */ +} + +static inline int imm_byte_in(unsigned short base, char *buffer, int len) +{ + int i; + + /* + * The following is based on documented timing signals + */ + w_ctr(base, 0x4); + for (i = len; i; i--) { + w_ctr(base, 0x26); + *buffer++ = r_dtr(base); + w_ctr(base, 0x25); + } + return 1; /* All went well - we hope! */ +} + +static inline int imm_epp_in(unsigned short base, char *buffer, int len) +{ + int i; + for (i = len; i; i--) + *buffer++ = r_epp(base); + return 1; +} + +static int imm_out(int host_no, char *buffer, int len) +{ + int r; + unsigned short ppb = IMM_BASE(host_no); + + r = imm_wait(host_no); + + /* + * Make sure that: + * a) the SCSI bus is BUSY (device still listening) + * b) the device is listening + */ + if ((r & 0x18) != 0x08) { + imm_fail(host_no, DID_ERROR); + printk("IMM: returned SCSI status %2x\n", r); + return 0; + } + switch (imm_hosts[host_no].mode) { + case IMM_EPP_32: + case IMM_EPP_16: + case IMM_EPP_8: + epp_reset(ppb); + w_ctr(ppb, 0x4); + r = imm_epp_out(ppb, buffer, len); + w_ctr(ppb, 0xc); + ecp_sync(ppb); + break; + + case IMM_NIBBLE: + case IMM_PS2: + /* 8 bit output, with a loop */ + r = imm_byte_out(ppb, buffer, len); + break; + + default: + printk("IMM: bug in imm_out()\n"); + r = 0; + } + return r; +} + +static int imm_in(int host_no, char *buffer, int len) +{ + int r; + unsigned short ppb = IMM_BASE(host_no); + + r = imm_wait(host_no); + + /* + * Make sure that: + * a) the SCSI bus is BUSY (device still listening) + * b) the device is sending data + */ + if ((r & 0x18) != 0x18) { + imm_fail(host_no, DID_ERROR); + return 0; + } + switch (imm_hosts[host_no].mode) { + case IMM_NIBBLE: + /* 4 bit input, with a loop */ + r = imm_nibble_in(ppb, buffer, len); + w_ctr(ppb, 0xc); + break; + + case IMM_PS2: + /* 8 bit input, with a loop */ + r = imm_byte_in(ppb, buffer, len); + w_ctr(ppb, 0xc); + break; + + case IMM_EPP_32: + case IMM_EPP_16: + case IMM_EPP_8: + epp_reset(ppb); + w_ctr(ppb, 0x24); + r = imm_epp_in(ppb, buffer, len); + w_ctr(ppb, 0x2c); + ecp_sync(ppb); + break; + + default: + printk("IMM: bug in imm_ins()\n"); + r = 0; + break; + } + return r; +} + +static int imm_cpp(unsigned short ppb, unsigned char b) +{ + /* + * Comments on udelay values refer to the + * Command Packet Protocol (CPP) timing diagram. + */ + + unsigned char s1, s2, s3; + w_ctr(ppb, 0x0c); + udelay(2); /* 1 usec - infinite */ + w_dtr(ppb, 0xaa); + udelay(10); /* 7 usec - infinite */ + w_dtr(ppb, 0x55); + udelay(10); /* 7 usec - infinite */ + w_dtr(ppb, 0x00); + udelay(10); /* 7 usec - infinite */ + w_dtr(ppb, 0xff); + udelay(10); /* 7 usec - infinite */ + s1 = r_str(ppb) & 0xb8; + w_dtr(ppb, 0x87); + udelay(10); /* 7 usec - infinite */ + s2 = r_str(ppb) & 0xb8; + w_dtr(ppb, 0x78); + udelay(10); /* 7 usec - infinite */ + s3 = r_str(ppb) & 0x38; + /* + * Values for b are: + * 0000 00aa Assign address aa to current device + * 0010 00aa Select device aa in EPP Winbond mode + * 0010 10aa Select device aa in EPP mode + * 0011 xxxx Deselect all devices + * 0110 00aa Test device aa + * 1101 00aa Select device aa in ECP mode + * 1110 00aa Select device aa in Compatible mode + */ + w_dtr(ppb, b); + udelay(2); /* 1 usec - infinite */ + w_ctr(ppb, 0x0c); + udelay(10); /* 7 usec - infinite */ + w_ctr(ppb, 0x0d); + udelay(2); /* 1 usec - infinite */ + w_ctr(ppb, 0x0c); + udelay(10); /* 7 usec - infinite */ + w_dtr(ppb, 0xff); + udelay(10); /* 7 usec - infinite */ + + /* + * The following table is electrical pin values. + * (BSY is inverted at the CTR register) + * + * BSY ACK POut SEL Fault + * S1 0 X 1 1 1 + * S2 1 X 0 1 1 + * S3 L X 1 1 S + * + * L => Last device in chain + * S => Selected + * + * Observered values for S1,S2,S3 are: + * Disconnect => f8/58/78 + * Connect => f8/58/70 + */ + if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30)) + return 1; /* Connected */ + if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38)) + return 0; /* Disconnected */ + + return -1; /* No device present */ +} + +static inline int imm_connect(int host_no, int flag) +{ + unsigned short ppb = IMM_BASE(host_no); + + imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */ + imm_cpp(ppb, 0x30); /* Disconnect all devices */ + + if ((imm_hosts[host_no].mode == IMM_EPP_8) || + (imm_hosts[host_no].mode == IMM_EPP_16) || + (imm_hosts[host_no].mode == IMM_EPP_32)) + return imm_cpp(ppb, 0x28); /* Select device 0 in EPP mode */ + return imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */ +} + +static void imm_disconnect(int host_no) +{ + unsigned short ppb = IMM_BASE(host_no); + + imm_cpp(ppb, 0x30); /* Disconnect all devices */ +} + +static int imm_select(int host_no, int target) +{ + int k; + unsigned short ppb = IMM_BASE(host_no); + + /* + * Firstly we want to make sure there is nothing + * holding onto the SCSI bus. + */ + w_ctr(ppb, 0xc); + + k = IMM_SELECT_TMO; + do { + k--; + } while ((r_str(ppb) & 0x08) && (k)); + + if (!k) + return 0; + + /* + * Now assert the SCSI ID (HOST and TARGET) on the data bus + */ + w_ctr(ppb, 0x4); + w_dtr(ppb, 0x80 | (1 << target)); + udelay(1); + + /* + * Deassert SELIN first followed by STROBE + */ + w_ctr(ppb, 0xc); + w_ctr(ppb, 0xd); + + /* + * ACK should drop low while SELIN is deasserted. + * FAULT should drop low when the SCSI device latches the bus. + */ + k = IMM_SELECT_TMO; + do { + k--; + } + while (!(r_str(ppb) & 0x08) && (k)); + + /* + * Place the interface back into a sane state (status mode) + */ + w_ctr(ppb, 0xc); + return (k) ? 1 : 0; +} + +static int imm_init(int host_no) +{ + int retv; + +#if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE) + if (imm_pb_claim(host_no)) + while (imm_hosts[host_no].p_busy) + schedule(); /* We can safe schedule here */ +#endif + retv = imm_connect(host_no, 0); + + if (retv == 1) { + imm_reset_pulse(IMM_BASE(host_no)); + udelay(1000); /* Delay to allow devices to settle */ + imm_disconnect(host_no); + udelay(1000); /* Another delay to allow devices to settle */ + retv = device_check(host_no); + imm_pb_release(host_no); + return retv; + } + + imm_pb_release(host_no); + return 1; +} + +static inline int imm_send_command(Scsi_Cmnd * cmd) +{ + int host_no = cmd->host->unique_id; + int k; + + /* NOTE: IMM uses byte pairs */ + for (k = 0; k < cmd->cmd_len; k += 2) + if (!imm_out(host_no, &cmd->cmnd[k], 2)) + return 0; + return 1; +} + +/* + * The bulk flag enables some optimisations in the data transfer loops, + * it should be true for any command that transfers data in integral + * numbers of sectors. + * + * The driver appears to remain stable if we speed up the parallel port + * i/o in this function, but not elsewhere. + */ +static int imm_completion(Scsi_Cmnd * cmd) +{ + /* Return codes: + * -1 Error + * 0 Told to schedule + * 1 Finished data transfer + */ + int host_no = cmd->host->unique_id; + unsigned short ppb = IMM_BASE(host_no); + unsigned long start_jiffies = jiffies; + + unsigned char r, v; + int fast, bulk, status; + + v = cmd->cmnd[0]; + bulk = ((v == READ_6) || + (v == READ_10) || + (v == WRITE_6) || + (v == WRITE_10)); + + /* + * We only get here if the drive is ready to comunicate, + * hence no need for a full imm_wait. + */ + w_ctr(ppb, 0x0c); + r = (r_str(ppb) & 0xb8); + + /* + * while (device is not ready to send status byte) + * loop; + */ + while (r != (unsigned char) 0xb8) { + /* + * If we have been running for more than a full timer tick + * then take a rest. + */ + if (jiffies > start_jiffies + 1) + return 0; + + /* + * FAIL if: + * a) Drive status is screwy (!ready && !present) + * b) Drive is requesting/sending more data than expected + */ + if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) { + imm_fail(host_no, DID_ERROR); + return -1; /* ERROR_RETURN */ + } + /* determine if we should use burst I/O */ + if (imm_hosts[host_no].rd == 0) { + fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2; + status = imm_out(host_no, cmd->SCp.ptr, fast); + } else { + fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1; + status = imm_in(host_no, cmd->SCp.ptr, fast); + } + + cmd->SCp.ptr += fast; + cmd->SCp.this_residual -= fast; + + if (!status) { + imm_fail(host_no, DID_BUS_BUSY); + return -1; /* ERROR_RETURN */ + } + if (cmd->SCp.buffer && !cmd->SCp.this_residual) { + /* if scatter/gather, advance to the next segment */ + if (cmd->SCp.buffers_residual--) { + cmd->SCp.buffer++; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + + /* + * Make sure that we transfer even number of bytes + * otherwise it makes imm_byte_out() messy. + */ + if (cmd->SCp.this_residual & 0x01) { + cmd->SCp.this_residual++; + printk("IMM: adjusted buffer for 16 bit transfer\n"); + } + } + } + /* Now check to see if the drive is ready to comunicate */ + w_ctr(ppb, 0x0c); + r = (r_str(ppb) & 0xb8); + + /* If not, drop back down to the scheduler and wait a timer tick */ + if (!(r & 0x80)) + return 0; + } + return 1; /* FINISH_RETURN */ +} + +/* deprecated synchronous interface */ +int imm_command(Scsi_Cmnd * cmd) +{ + static int first_pass = 1; + int host_no = cmd->host->unique_id; + + if (first_pass) { + printk("imm: using non-queuing interface\n"); + first_pass = 0; + } + if (imm_hosts[host_no].cur_cmd) { + printk("IMM: bug in imm_command\n"); + return 0; + } + imm_hosts[host_no].failed = 0; + imm_hosts[host_no].jstart = jiffies; + imm_hosts[host_no].cur_cmd = cmd; + cmd->result = DID_ERROR << 16; /* default return code */ + cmd->SCp.phase = 0; + + imm_pb_claim(host_no); + + while (imm_engine(&imm_hosts[host_no], cmd)) + schedule(); + + if (cmd->SCp.phase) /* Only disconnect if we have connected */ + imm_disconnect(cmd->host->unique_id); + + imm_pb_release(host_no); + imm_hosts[host_no].cur_cmd = 0; + return cmd->result; +} + +/* + * Since the IMM itself doesn't generate interrupts, we use + * the scheduler's task queue to generate a stream of call-backs and + * complete the request when the drive is ready. + */ +static void imm_interrupt(void *data) +{ + imm_struct *tmp = (imm_struct *) data; + Scsi_Cmnd *cmd = tmp->cur_cmd; + + if (!cmd) { + printk("IMM: bug in imm_interrupt\n"); + return; + } + if (imm_engine(tmp, cmd)) { + tmp->imm_tq.data = (void *) tmp; + tmp->imm_tq.sync = 0; + queue_task(&tmp->imm_tq, &tq_timer); + return; + } + /* Command must of completed hence it is safe to let go... */ +#if IMM_DEBUG > 0 + switch ((cmd->result >> 16) & 0xff) { + case DID_OK: + break; + case DID_NO_CONNECT: + printk("imm: no device at SCSI ID %i\n", cmd->target); + break; + case DID_BUS_BUSY: + printk("imm: BUS BUSY - EPP timeout detected\n"); + break; + case DID_TIME_OUT: + printk("imm: unknown timeout\n"); + break; + case DID_ABORT: + printk("imm: told to abort\n"); + break; + case DID_PARITY: + printk("imm: parity error (???)\n"); + break; + case DID_ERROR: + printk("imm: internal driver error\n"); + break; + case DID_RESET: + printk("imm: told to reset device\n"); + break; + case DID_BAD_INTR: + printk("imm: bad interrupt (???)\n"); + break; + default: + printk("imm: bad return code (%02x)\n", (cmd->result >> 16) & 0xff); + } +#endif + + if (cmd->SCp.phase > 1) + imm_disconnect(cmd->host->unique_id); + if (cmd->SCp.phase > 0) + imm_pb_release(cmd->host->unique_id); + + tmp->cur_cmd = 0; + cmd->scsi_done(cmd); + return; +} + +static int imm_engine(imm_struct * tmp, Scsi_Cmnd * cmd) +{ + int host_no = cmd->host->unique_id; + unsigned short ppb = IMM_BASE(host_no); + unsigned char l = 0, h = 0; + int retv, x; + + /* First check for any errors that may of occured + * Here we check for internal errors + */ + if (tmp->failed) + return 0; + + switch (cmd->SCp.phase) { + case 0: /* Phase 0 - Waiting for parport */ + if ((jiffies - tmp->jstart) > HZ) { + /* + * We waited more than a second + * for parport to call us + */ + imm_fail(host_no, DID_BUS_BUSY); + return 0; + } + return 1; /* wait until imm_wakeup claims parport */ + /* Phase 1 - Connected */ + case 1: + imm_connect(host_no, CONNECT_EPP_MAYBE); + cmd->SCp.phase++; + + /* Phase 2 - We are now talking to the scsi bus */ + case 2: + if (!imm_select(host_no, cmd->target)) { + imm_fail(host_no, DID_NO_CONNECT); + return 0; + } + cmd->SCp.phase++; + + /* Phase 3 - Ready to accept a command */ + case 3: + w_ctr(ppb, 0x0c); + if (!(r_str(ppb) & 0x80)) + return 1; + + if (!imm_send_command(cmd)) + return 0; + cmd->SCp.phase++; + + /* Phase 4 - Setup scatter/gather buffers */ + case 4: + if (cmd->use_sg) { + /* if many buffers are available, start filling the first */ + cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + } else { + /* else fill the only available buffer */ + cmd->SCp.buffer = NULL; + cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = cmd->request_buffer; + } + cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.phase++; + if (cmd->SCp.this_residual & 0x01) { + cmd->SCp.this_residual++; + printk("IMM: adjusted buffer for 16 bit transfer\n"); + } + /* Phase 5 - Pre-Data transfer stage */ + case 5: + /* Spin lock for BUSY */ + w_ctr(ppb, 0x0c); + if (!(r_str(ppb) & 0x80)) + return 1; + + /* Require negotiation for read requests */ + x = (r_str(ppb) & 0xb8); + tmp->rd = (x & 0x10) ? 1 : 0; + tmp->dp = (x & 0x20) ? 0 : 1; + + if ((tmp->dp) && (tmp->rd)) + if (imm_negotiate(tmp)) + return 0; + cmd->SCp.phase++; + + /* Phase 6 - Data transfer stage */ + case 6: + /* Spin lock for BUSY */ + w_ctr(ppb, 0x0c); + if (!(r_str(ppb) & 0x80)) + return 1; + + if (tmp->dp) { + retv = imm_completion(cmd); + if (retv == -1) + return 0; + if (retv == 0) + return 1; + } + cmd->SCp.phase++; + + /* Phase 7 - Post data transfer stage */ + case 7: + if ((tmp->dp) && (tmp->rd)) { + if ((tmp->mode == IMM_NIBBLE) || (tmp->mode == IMM_PS2)) { + w_ctr(ppb, 0x4); + w_ctr(ppb, 0xc); + w_ctr(ppb, 0xe); + w_ctr(ppb, 0x4); + } + } + cmd->SCp.phase++; + + /* Phase 8 - Read status/message */ + case 8: + /* Check for data overrun */ + if (imm_wait(host_no) != (unsigned char) 0xb8) { + imm_fail(host_no, DID_ERROR); + return 0; + } + if (imm_negotiate(tmp)) + return 0; + if (imm_in(host_no, &l, 1)) { /* read status byte */ + /* Check for optional message byte */ + if (imm_wait(host_no) == (unsigned char) 0xb8) + imm_in(host_no, &h, 1); + cmd->result = (DID_OK << 16) + (l & STATUS_MASK); + } + if ((tmp->mode == IMM_NIBBLE) || (tmp->mode == IMM_PS2)) { + w_ctr(ppb, 0x4); + w_ctr(ppb, 0xc); + w_ctr(ppb, 0xe); + w_ctr(ppb, 0x4); + } + return 0; /* Finished */ + break; + + default: + printk("imm: Invalid scsi phase\n"); + } + return 0; +} + +int imm_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + int host_no = cmd->host->unique_id; + + if (imm_hosts[host_no].cur_cmd) { + printk("IMM: bug in imm_queuecommand\n"); + return 0; + } + imm_hosts[host_no].failed = 0; + imm_hosts[host_no].jstart = jiffies; + imm_hosts[host_no].cur_cmd = cmd; + cmd->scsi_done = done; + cmd->result = DID_ERROR << 16; /* default return code */ + cmd->SCp.phase = 0; /* bus free */ + + imm_pb_claim(host_no); + + imm_hosts[host_no].imm_tq.data = imm_hosts + host_no; + imm_hosts[host_no].imm_tq.sync = 0; + queue_task(&imm_hosts[host_no].imm_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return 0; +} + +/* + * Aimmrently the the disk->capacity attribute is off by 1 sector + * for all disk drives. We add the one here, but it should really + * be done in sd.c. Even if it gets fixed there, this will still + * work. + */ +int imm_biosparam(Disk * disk, kdev_t dev, int ip[]) +{ + ip[0] = 0x40; + ip[1] = 0x20; + ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; + ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } + return 0; +} + +int imm_abort(Scsi_Cmnd * cmd) +{ + /* + * There is no method for aborting commands since Iomega + * have tied the SCSI_MESSAGE line high in the interface + */ + + switch (cmd->SCp.phase) { + case 0: /* Do not have access to parport */ + case 1: /* Have not connected to interface */ + cmd->result = DID_ABORT; + cmd->done(cmd); + return SCSI_ABORT_SUCCESS; + break; + default: /* SCSI command sent, can not abort */ + return SCSI_ABORT_BUSY; + break; + } +} + +void imm_reset_pulse(unsigned int base) +{ + w_ctr(base, 0x04); + w_dtr(base, 0x40); + udelay(1); + w_ctr(base, 0x0c); + w_ctr(base, 0x0d); + udelay(50); + w_ctr(base, 0x0c); + w_ctr(base, 0x04); +} + +int imm_reset(Scsi_Cmnd * cmd, unsigned int x) +{ + int host_no = cmd->host->unique_id; + + /* + * PHASE1: + * Bring the interface crashing down on whatever is running + * hopefully this will kill the request. + * Bring back up the interface, reset the drive (and anything + * attached for that manner) + */ + if (cmd) + if (cmd->SCp.phase) + imm_disconnect(cmd->host->unique_id); + + imm_connect(host_no, CONNECT_NORMAL); + imm_reset_pulse(IMM_BASE(host_no)); + udelay(1000); /* delay for devices to settle down */ + imm_disconnect(host_no); + udelay(1000); /* Additional delay to allow devices to settle down */ + + /* + * PHASE2: + * Sanity check for the sake of mid-level driver + */ + if (!cmd) { + printk("imm bus reset called for invalid command.\n"); + return SCSI_RESET_NOT_RUNNING; + } + /* + * PHASE3: + * Flag the current command as having died due to reset + */ + imm_connect(host_no, CONNECT_NORMAL); + imm_fail(host_no, DID_RESET); + + /* Since the command was already on the timer queue imm_interrupt + * will be called shortly. + */ + return SCSI_RESET_PENDING; +} + +static int device_check(int host_no) +{ + /* This routine looks for a device and then attempts to use EPP + to send a command. If all goes as planned then EPP is available. */ + + static char cmd[6] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + int loop, old_mode, status, k, ppb = IMM_BASE(host_no); + unsigned char l; + + old_mode = imm_hosts[host_no].mode; + for (loop = 0; loop < 8; loop++) { + /* Attempt to use EPP for Test Unit Ready */ + if ((ppb & 0x0007) == 0x0000) + imm_hosts[host_no].mode = IMM_EPP_32; + + second_pass: + imm_connect(host_no, CONNECT_EPP_MAYBE); + /* Select SCSI device */ + if (!imm_select(host_no, loop)) { + imm_disconnect(host_no); + continue; + } + printk("imm: Found device at ID %i, Attempting to use %s\n", loop, + IMM_MODE_STRING[imm_hosts[host_no].mode]); + + /* Send SCSI command */ + status = 1; + w_ctr(ppb, 0x0c); + for (l = 0; (l < 3) && (status); l++) + status = imm_out(host_no, &cmd[l<<1], 2); + + if (!status) { + imm_disconnect(host_no); + imm_connect(host_no, CONNECT_EPP_MAYBE); + w_dtr(ppb, 0x40); + w_ctr(ppb, 0x08); + udelay(30); + w_ctr(ppb, 0x0c); + udelay(1000); + imm_disconnect(host_no); + udelay(1000); + if (imm_hosts[host_no].mode == IMM_EPP_32) { + imm_hosts[host_no].mode = old_mode; + goto second_pass; + } + printk("imm: Unable to establish communication, aborting driver load.\n"); + return 1; + } + w_ctr(ppb, 0x0c); + + k = 1000000; /* 1 Second */ + do { + l = r_str(ppb); + k--; + udelay(1); + } while (!(l & 0x80) && (k)); + + l &= 0xb8; + + if (l != 0xb8) { + imm_disconnect(host_no); + imm_connect(host_no, CONNECT_EPP_MAYBE); + imm_reset_pulse(IMM_BASE(host_no)); + udelay(1000); + imm_disconnect(host_no); + udelay(1000); + if (imm_hosts[host_no].mode == IMM_EPP_32) { + imm_hosts[host_no].mode = old_mode; + goto second_pass; + } + printk("imm: Unable to establish communication, aborting driver load.\n"); + return 1; + } + imm_disconnect(host_no); + printk("imm: Communication established with ID %i using %s\n", loop, + IMM_MODE_STRING[imm_hosts[host_no].mode]); + imm_connect(host_no, CONNECT_EPP_MAYBE); + imm_reset_pulse(IMM_BASE(host_no)); + udelay(1000); + imm_disconnect(host_no); + udelay(1000); + return 0; + } + printk("imm: No devices found, aborting driver load.\n"); + return 1; +} + diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h new file mode 100644 index 000000000000..2818603dda32 --- /dev/null +++ b/drivers/scsi/imm.h @@ -0,0 +1,166 @@ +/* Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in + * the Iomega ZIP Plus drive + * + * (c) 1998 David Campbell campbell@torque.net + * + * Please note that I live in Perth, Western Australia. GMT+0800 + */ + +#ifndef _IMM_H +#define _IMM_H + +#define IMM_VERSION "2.00" + +/* + * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega. + * Scarry thing is the level of support from one of their managers. + * The onus is now on us (the developers) to shut up and start coding. + * 11Apr98 [ 0.10 ] + * + * --- SNIP --- + * + * It manages to find the drive which is a good start. Writing data during + * data phase is known to be broken (due to requirements of two byte writes). + * Removing "Phase" debug messages. + * + * PS: Took four hours of coding after I bought a drive. + * ANZAC Day (Aus "War Veterans Holiday") 25Apr98 [ 0.14 ] + * + * Ten minutes later after a few fixes.... (LITERALLY!!!) + * Have mounted disk, copied file, dismounted disk, remount disk, diff file + * ----- It actually works!!! ----- + * 25Apr98 [ 0.15 ] + * + * Twenty minutes of mucking around, rearanged the IEEE negotiate mechanism. + * Now have byte mode working (only EPP and ECP to go now... :=) + * 26Apr98 [ 0.16 ] + * + * Thirty minutes of further coding results in EPP working on my machine. + * 27Apr98 [ 0.17 ] + * + * Due to work commitments and inability to get a "true" ECP mode functioning + * I have decided to code the parport support into imm. + * 09Jun98 [ 0.18 ] + * + * Driver is now out of beta testing. + * Support for parport has been added. + * Now distributed with the ppa driver. + * 12Jun98 [ 2.00 ] + * + * Err.. It appears that imm-2.00 was broken.... + * 18Jun98 [ 2.01 ] + * + * Patch applied to sync this against the Linux 2.1.x kernel code + * Included qboot_zip.sh + * 21Jun98 [ 2.02 ] + */ +/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ + +#ifdef IMM_CODE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "sd.h" +#include "hosts.h" +/* batteries not included :-) */ + +/* + * modes in which the driver can operate + */ +#define IMM_AUTODETECT 0 /* Autodetect mode */ +#define IMM_NIBBLE 1 /* work in standard 4 bit mode */ +#define IMM_PS2 2 /* PS/2 byte mode */ +#define IMM_EPP_8 3 /* EPP mode, 8 bit */ +#define IMM_EPP_16 4 /* EPP mode, 16 bit */ +#define IMM_EPP_32 5 /* EPP mode, 32 bit */ +#define IMM_UNKNOWN 6 /* Just in case... */ + +static char *IMM_MODE_STRING[] = +{ + "Autodetect", + "SPP", + "PS/2", + "EPP 8 bit", + "EPP 16 bit", + "EPP 32 bit", + "Unknown"}; + +/* This is a global option */ +int imm_sg = SG_ALL; /* enable/disable scatter-gather. */ + +/* other options */ +#define IMM_CAN_QUEUE 1 /* use "queueing" interface */ +#define IMM_BURST_SIZE 512 /* data burst size */ +#define IMM_SELECT_TMO 500 /* 500 how long to wait for target ? */ +#define IMM_SPIN_TMO 5000 /* 50000 imm_wait loop limiter */ +#define IMM_DEBUG 0 /* debuging option */ +#define IN_EPP_MODE(x) (x == IMM_EPP_8 || x == IMM_EPP_16 || x == IMM_EPP_32) + +/* args to imm_connect */ +#define CONNECT_EPP_MAYBE 1 +#define CONNECT_NORMAL 0 + +#define inb_x inb +#define r_dtr(x) (unsigned char)inb_x((x)) +#define r_str(x) (unsigned char)inb_x((x)+1) +#define r_ctr(x) (unsigned char)inb_x((x)+2) +#define r_epp(x) (unsigned char)inb_x((x)+4) +#define r_fifo(x) (unsigned char)inb_x((x)+0x400) +#define r_ecr(x) (unsigned char)inb_x((x)+0x402) + +#define outb_x outb +#define w_dtr(x,y) outb_x(y, (x)) +#define w_str(x,y) outb_x(y, (x)+1) +#define w_ctr(x,y) outb_x(y, (x)+2) +#define w_epp(x,y) outb_x(y, (x)+4) +#define w_fifo(x,y) outb_x(y, (x)+0x400) +#define w_ecr(x,y) outb_x(y, (x)+0x402) + +static int imm_engine(imm_struct *, Scsi_Cmnd *); +static int imm_in(int, char *, int); +static int imm_init(int); +static void imm_interrupt(void *); +static int imm_out(int, char *, int); + +struct proc_dir_entry proc_scsi_imm = +{PROC_SCSI_PPA, 3, "imm", S_IFDIR | S_IRUGO | S_IXUGO, 2}; +#else +extern struct proc_dir_entry proc_scsi_imm; +#define imm_release 0 +#endif + +int imm_detect(Scsi_Host_Template *); +const char *imm_info(struct Scsi_Host *); +int imm_command(Scsi_Cmnd *); +int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +int imm_abort(Scsi_Cmnd *); +int imm_reset(Scsi_Cmnd *, unsigned int); +int imm_proc_info(char *, char **, off_t, int, int, int); +int imm_biosparam(Disk *, kdev_t, int *); + +#define IMM { proc_dir: &proc_scsi_imm, \ + proc_info: imm_proc_info, \ + name: "Iomega ZIP Plus drive", \ + detect: imm_detect, \ + release: imm_release, \ + command: imm_command, \ + queuecommand: imm_queuecommand, \ + abort: imm_abort, \ + reset: imm_reset, \ + bios_param: imm_biosparam, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + use_clustering: ENABLE_CLUSTERING \ +} +#endif /* _IMM_H */ diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 854f9e539e10..8ca70d46a91a 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -22,6 +22,7 @@ #include "sd.h" #include "hosts.h" int ppa_release(struct Scsi_Host *); +static void ppa_reset_pulse(unsigned int base); typedef struct { struct pardevice *dev; /* Parport device entry */ @@ -35,16 +36,16 @@ typedef struct { unsigned int p_busy:1; /* Parport sharing busy flag */ } ppa_struct; -#define PPA_EMPTY \ -{NULL, /* dev */ \ --1, /* base */ \ -PPA_AUTODETECT, /* mode */ \ --1, /* host */ \ -NULL, /* cur_cmd */ \ -{0, 0, ppa_interrupt, NULL}, \ -0, /* jstart */ \ -0, /* failed */ \ -0 /* p_busy */ \ +#define PPA_EMPTY \ +{ dev: NULL, \ + base: -1, \ + mode: PPA_AUTODETECT, \ + host: -1, \ + cur_cmd: NULL, \ + ppa_tq: {0, 0, ppa_interrupt, NULL}, \ + jstart: 0, \ + failed: 0, \ + p_busy: 0 \ } #include "ppa.h" @@ -139,7 +140,8 @@ int ppa_detect(Scsi_Host_Template * host) */ if (ppa_pb_claim(i)) while (ppa_hosts[i].p_busy) - schedule(); /* Whe can safe schedule() here */ + schedule(); /* We are safe to schedule here */ + ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base; w_ctr(ppb, 0x0c); modes = ppa_hosts[i].dev->port->modes; @@ -557,7 +559,7 @@ static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const int i; for (i = len; i; i--) { outb(*buffer++, epp_p); -#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 2 +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC if (inb(str_p) & 0x01) return 0; #endif @@ -588,14 +590,12 @@ static int ppa_out(int host_no, char *buffer, int len) case PPA_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x4); -#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 1 +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len); #else -#if CONFIG_SCSI_PPA_HAVE_PEDANTIC == 0 if (!(((long) buffer | len) & 0x03)) outsl(ppb + 4, buffer, len >> 2); else -#endif outsb(ppb + 4, buffer, len); w_ctr(ppb, 0xc); r = !(r_str(ppb) & 0x01); @@ -616,7 +616,7 @@ static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len) int i; for (i = len; i; i--) { *buffer++ = inb(epp_p); -#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 2 +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC if (inb(str_p) & 0x01) return 0; #endif @@ -655,14 +655,12 @@ static int ppa_in(int host_no, char *buffer, int len) case PPA_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x24); -#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 1 +#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len); #else -#if CONFIG_SCSI_PPA_HAVE_PEDANTIC == 0 if (!(((long) buffer | len) & 0x03)) insl(ppb + 4, buffer, len >> 2); else -#endif insb(ppb + 4, buffer, len); w_ctr(ppb, 0x2c); r = !(r_str(ppb) & 0x01); @@ -773,7 +771,7 @@ static int ppa_init(int host_no) #if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE) if (ppa_pb_claim(host_no)) while (ppa_hosts[host_no].p_busy) - schedule(); /* Whe can safe schedule() here */ + schedule(); /* We can safe schedule here */ #endif ppa_disconnect(host_no); @@ -789,16 +787,11 @@ static int ppa_init(int host_no) if ((r_str(ppb) & 0x08) == 0x00) retv--; - /* This is a SCSI BUS reset signal */ - if (!retv) { - w_dtr(ppb, 0x40); - w_ctr(ppb, 0x08); - udelay(30); - w_ctr(ppb, 0x0c); - mdelay(1); /* Allow devices to settle down */ - } + if (!retv) + ppa_reset_pulse(ppb); + udelay(1000); /* Allow devices to settle down */ ppa_disconnect(host_no); - mdelay(1); /* Another delay to allow devices to settle */ + udelay(1000); /* Another delay to allow devices to settle */ if (!retv) retv = device_check(host_no); @@ -989,6 +982,7 @@ static void ppa_interrupt(void *data) ppa_disconnect(cmd->host->unique_id); if (cmd->SCp.phase > 0) ppa_pb_release(cmd->host->unique_id); + tmp->cur_cmd = 0; cmd->scsi_done(cmd); return; @@ -1017,7 +1011,7 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd) ppa_fail(host_no, DID_BUS_BUSY); return 0; } - return 1; /* wait that ppa_wakeup claims parport */ + return 1; /* wait until ppa_wakeup claims parport */ case 1: /* Phase 1 - Connected */ { /* Perform a sanity check for cable unplugged */ int retv = 2; /* Failed */ @@ -1032,7 +1026,7 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd) if ((r_str(ppb) & 0x08) == 0x00) retv--; - if (retv) { + if (retv) if ((jiffies - tmp->jstart) > (1 * HZ)) { printk("ppa: Parallel port cable is unplugged!!\n"); ppa_fail(host_no, DID_BUS_BUSY); @@ -1041,7 +1035,6 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd) ppa_disconnect(host_no); return 1; /* Try again in a jiffy */ } - } cmd->SCp.phase++; } @@ -1136,7 +1129,7 @@ int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) } /* - * Apparently the disk->capacity attribute is off by 1 sector + * Apparently the the disk->capacity attribute is off by 1 sector * for all disk drives. We add the one here, but it should really * be done in sd.c. Even if it gets fixed there, this will still * work. @@ -1158,6 +1151,7 @@ int ppa_biosparam(Disk * disk, kdev_t dev, int ip[]) int ppa_abort(Scsi_Cmnd * cmd) { + int host_no = cmd->host->unique_id; /* * There is no method for aborting commands since Iomega * have tied the SCSI_MESSAGE line high in the interface @@ -1166,60 +1160,37 @@ int ppa_abort(Scsi_Cmnd * cmd) switch (cmd->SCp.phase) { case 0: /* Do not have access to parport */ case 1: /* Have not connected to interface */ - cmd->result = DID_ABORT; - cmd->done(cmd); - return SCSI_ABORT_SUCCESS; + ppa_hosts[host_no].cur_cmd = NULL; /* Forget the problem */ + return SUCCESS; break; default: /* SCSI command sent, can not abort */ - return SCSI_ABORT_BUSY; + return FAILED; break; } } -int ppa_reset(Scsi_Cmnd * cmd, unsigned int x) +static void ppa_reset_pulse(unsigned int base) +{ + w_dtr(base, 0x40); + w_ctr(base, 0x8); + udelay(30); + w_ctr(base, 0xc); +} + +int ppa_reset(Scsi_Cmnd * cmd) { int host_no = cmd->host->unique_id; - int ppb = PPA_BASE(host_no); - /* - * PHASE1: - * Bring the interface crashing down on whatever is running - * hopefully this will kill the request. - * Bring back up the interface, reset the drive (and anything - * attached for that manner) - */ - if (cmd) - if (cmd->SCp.phase) - ppa_disconnect(cmd->host->unique_id); + if (cmd->SCp.phase) + ppa_disconnect(host_no); + ppa_hosts[host_no].cur_cmd = NULL; /* Forget the problem */ ppa_connect(host_no, CONNECT_NORMAL); - w_dtr(ppb, 0x40); - w_ctr(ppb, 0x8); - udelay(30); - w_ctr(ppb, 0xc); - mdelay(1); /* delay for devices to settle down */ + ppa_reset_pulse(PPA_BASE(host_no)); + udelay(1000); /* device settle delay */ ppa_disconnect(host_no); - mdelay(1); /* Additional delay to allow devices to settle down */ - - /* - * PHASE2: - * Sanity check for the sake of mid-level driver - */ - if (!cmd) { - printk("ppa bus reset called for invalid command.\n"); - return SCSI_RESET_NOT_RUNNING; - } - /* - * PHASE3: - * Flag the current command as having died due to reset - */ - ppa_connect(host_no, CONNECT_NORMAL); - ppa_fail(host_no, DID_RESET); - - /* Since the command was already on the timer queue ppa_interrupt - * will be called shortly. - */ - return SCSI_RESET_PENDING; + udelay(1000); /* device settle delay */ + return SUCCESS; } static int device_check(int host_no) @@ -1261,9 +1232,9 @@ static int device_check(int host_no) w_ctr(ppb, 0x08); udelay(30); w_ctr(ppb, 0x0c); - mdelay(1); + udelay(1000); ppa_disconnect(host_no); - mdelay(1); + udelay(1000); if (ppa_hosts[host_no].mode == PPA_EPP_32) { ppa_hosts[host_no].mode = old_mode; goto second_pass; @@ -1284,13 +1255,10 @@ static int device_check(int host_no) if (l != 0xf0) { ppa_disconnect(host_no); ppa_connect(host_no, CONNECT_EPP_MAYBE); - w_dtr(ppb, 0x40); - w_ctr(ppb, 0x08); - udelay(30); - w_ctr(ppb, 0x0c); - mdelay(1); + ppa_reset_pulse(ppb); + udelay(1000); ppa_disconnect(host_no); - mdelay(1); + udelay(1000); if (ppa_hosts[host_no].mode == PPA_EPP_32) { ppa_hosts[host_no].mode = old_mode; goto second_pass; @@ -1301,6 +1269,11 @@ static int device_check(int host_no) ppa_disconnect(host_no); printk("ppa: Communication established with ID %i using %s\n", loop, PPA_MODE_STRING[ppa_hosts[host_no].mode]); + ppa_connect(host_no, CONNECT_EPP_MAYBE); + ppa_reset_pulse(ppb); + udelay(1000); + ppa_disconnect(host_no); + udelay(1000); return 0; } printk("ppa: No devices found, aborting driver load.\n"); diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index 41f03585548d..c58dd39b2abd 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -10,15 +10,7 @@ #ifndef _PPA_H #define _PPA_H -#define PPA_VERSION "1.39a" - -/* Use the following to enable certain chipset support - * Default is PEDANTIC = 3 - */ -#include /* for CONFIG_SCSI_PPA_HAVE_PEDANTIC */ -#ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC -#define CONFIG_SCSI_PPA_HAVE_PEDANTIC 3 -#endif +#define PPA_VERSION "2.01" /* * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) @@ -32,34 +24,23 @@ * * [ Stuff removed ] * - * Compiled against 2.1.53. - * Rebuilt ppa_abort() function, should handle unplugged cable. - * [1.35s] - * - * PPA now auto probes for EPP on base address which are aligned on - * 8 byte boundaries (0x278 & 0x378) using the attached devices. - * This hopefully avoids the nasty problem of trying to detect EPP. - * Tested on 2.1.53 [1.36] + * Corrected ppa.h for 2.1.x kernels (>=2.1.85) + * Modified "Nat Semi Kludge" for extended chipsets + * [1.41] * - * The id_probe utility no longer performs read/write tests. - * Additional code included for checking the Intel ECP bug - * (Bit 0 of STR stuck low which fools the EPP detection routine) - * [1.37] + * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7) + * [1.42] * - * Oops! Got the bit sign mixed up for the Intel bug check. - * Found that an additional delay is required during SCSI resets - * to allow devices to settle down. - * [1.38] + * Development solely for 2.1.x kernels from now on! + * [2.00] * - * Fixed all problems in the parport sharing scheme. Now ppa can be safe - * used with lp or other parport devices on the same parallel port. - * 1997 by Andrea Arcangeli - * [1.39] + * Hack and slash at the init code (EPP device check routine) + * Added INSANE option. + * [2.01] * - * Little fix in ppa engine to ensure that ppa don' t release parport - * or disconnect in wrong cases. - * 1997 by Andrea Arcangeli - * [1.39a] + * Patch applied to sync against the 2.1.x kernel code + * Included qboot_zip.sh + * [2.02] */ /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ @@ -117,6 +98,23 @@ int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */ #define CONNECT_EPP_MAYBE 1 #define CONNECT_NORMAL 0 +/* INSANE code */ +#define PPA_INSANE 0 +#if PPA_INSANE > 0 +#define r_dtr(x) (unsigned char)inb_p((x)) +#define r_str(x) (unsigned char)inb_p((x)+1) +#define r_ctr(x) (unsigned char)inb_p((x)+2) +#define r_epp(x) (unsigned char)inb_p((x)+4) +#define r_fifo(x) (unsigned char)inb_p((x)+0x400) +#define r_ecr(x) (unsigned char)inb_p((x)+0x402) + +#define w_dtr(x,y) outb_p(y, (x)) +#define w_str(x,y) outb_p(y, (x)+1) +#define w_ctr(x,y) outb_p(y, (x)+2) +#define w_epp(x,y) outb_p(y, (x)+4) +#define w_fifo(x,y) outb_p(y, (x)+0x400) +#define w_ecr(x,y) outb_p(y, (x)+0x402) +#else /* PPA_INSANE */ #define r_dtr(x) (unsigned char)inb((x)) #define r_str(x) (unsigned char)inb((x)+1) #define r_ctr(x) (unsigned char)inb((x)+2) @@ -130,6 +128,7 @@ int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */ #define w_epp(x,y) outb(y, (x)+4) #define w_fifo(x,y) outb(y, (x)+0x400) #define w_ecr(x,y) outb(y, (x)+0x402) +#endif /* PPA_INSANE */ static int ppa_engine(ppa_struct *, Scsi_Cmnd *); static int ppa_in(int, char *, int); @@ -149,23 +148,25 @@ const char *ppa_info(struct Scsi_Host *); int ppa_command(Scsi_Cmnd *); int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int ppa_abort(Scsi_Cmnd *); -int ppa_reset(Scsi_Cmnd *, unsigned int); +int ppa_reset(Scsi_Cmnd *); int ppa_proc_info(char *, char **, off_t, int, int, int); int ppa_biosparam(Disk *, kdev_t, int *); -#define PPA { proc_dir: &proc_scsi_ppa, \ - proc_info: ppa_proc_info, \ - name: "Iomega parport ZIP drive", \ - detect: ppa_detect, \ - release: ppa_release, \ - command: ppa_command, \ - queuecommand: ppa_queuecommand, \ - abort: ppa_abort, \ - reset: ppa_reset, \ - bios_param: ppa_biosparam, \ - this_id: -1, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 1, \ - use_clustering: ENABLE_CLUSTERING \ +#define PPA { proc_dir: &proc_scsi_ppa, \ + proc_info: ppa_proc_info, \ + name: "Iomega parport ZIP drive",\ + detect: ppa_detect, \ + release: ppa_release, \ + command: ppa_command, \ + queuecommand: ppa_queuecommand, \ + eh_abort_handler: ppa_abort, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: ppa_reset, \ + eh_host_reset_handler: ppa_reset, \ + bios_param: ppa_biosparam, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + use_clustering: ENABLE_CLUSTERING \ } #endif /* _PPA_H */ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index da56b84efc6a..5c45e1e7348e 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -90,14 +90,6 @@ static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1 # error You lose. #endif -#define MAX_SCSI_DEVICE_CODE 10 - -#ifdef DEBUG - #define SCSI_TIMEOUT (5*HZ) -#else - #define SCSI_TIMEOUT (2*HZ) -#endif - #define MIN_RESET_DELAY (2*HZ) /* Do not call reset on error if we just did a reset within 15 sec. */ diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 7824dff31f58..045ec15da7df 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -42,6 +42,12 @@ #define MAX_SCSI_DEVICE_CODE 10 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; +#ifdef DEBUG + #define SCSI_TIMEOUT (5*HZ) +#else + #define SCSI_TIMEOUT (2*HZ) +#endif + /* * Use these to separate status msg and our bytes * diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index b23a61f74153..b43addc1b923 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -17,37 +17,53 @@ fi dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then - string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin" - string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin" + if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then + comment 'Compiled-in MSND Classic support requires firmware during compilation.' + define_bool CONFIG_MSNDCLAS_HAVE_BOOT y + string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin" + string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin" + else + define_bool CONFIG_MSNDCLAS_HAVE_BOOT n + fi fi if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then int 'MSND Classic IRQ 5,7,9,10,11,12' CONFIG_MSNDCLAS_IRQ 5 - hex 'MSND Classic Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000 + hex 'MSND Classic memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000 hex 'MSND Classic I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDCLAS_IO 290 fi dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDPIN" = "m" ]; then - string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin" - string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin" + if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then + comment 'Compiled-in MSND Pinnacle support requires firmware during compilation.' + string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin" + string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin" + define_bool CONFIG_MSNDPIN_HAVE_BOOT y + else + define_bool CONFIG_MSNDPIN_HAVE_BOOT n + fi fi if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then int 'MSND Pinnacle IRQ 5,7,9,10,11,12' CONFIG_MSNDPIN_IRQ 5 - hex 'MSND Pinnacle Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000 + hex 'MSND Pinnacle memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000 hex 'MSND Pinnacle I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290 + bool 'MSND Pinnacle has S/PDIF I/O' CONFIG_MSNDPIN_DIGITAL bool 'MSND Pinnacle Non-PnP Mode' CONFIG_MSNDPIN_NONPNP if [ "$CONFIG_MSNDPIN_NONPNP" = "y" ]; then comment 'MSND Pinnacle DSP section will be configured to above parameters.' - hex 'MSDN Pinnacle Config Port 250,260,270' CONFIG_MSNDPIN_CFG 250 + hex 'MSDN Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250 comment 'Pinnacle-specific Device Configuration (0 disables)' - hex 'MSDN Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0 - int 'MSDN Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0 - hex 'MSDN Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0 - hex 'MSDN Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0 - int 'MSDN Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0 - hex 'MSDN Pinnacle Joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0 + hex 'MSND Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0 + int 'MSND Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0 + hex 'MSND Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0 + hex 'MSND Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0 + int 'MSND Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0 + hex 'MSDN Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0 fi fi +if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then + int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128 +fi dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index f072b7fad391..5ca95dd5f804 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -235,6 +235,50 @@ endif +# Turtle Beach MultiSound + +ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y) + msnd_classic.o: msndperm.c msndinit.c + + msndperm.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_PERM_FILE)) bin2hex + ./bin2hex msndperm < $(CONFIG_MSNDCLAS_PERM_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_PERM_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_PERM_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot + + msndinit.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_INIT_FILE)) bin2hex + ./bin2hex msndinit < $(CONFIG_MSNDCLAS_INIT_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_INIT_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_INIT_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot +endif + +ifeq ($(CONFIG_MSNDPIN_HAVE_BOOT),y) + msnd_pinnacle.o: pndsperm.c pndspini.c + + pndsperm.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_PERM_FILE)) bin2hex + ./bin2hex pndsperm < $(CONFIG_MSNDPIN_PERM_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_PERM_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_PERM_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot + + pndspini.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_INIT_FILE)) bin2hex + ./bin2hex pndspini < $(CONFIG_MSNDPIN_INIT_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_INIT_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_INIT_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot +endif + + + # PSS (ECHO-ADI2111) pss.o: pss_boot.h diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 34148d990877..684456c590e4 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -2401,7 +2401,6 @@ void attach_ms_sound(struct address_info *hw_config) void unload_ms_sound(struct address_info *hw_config) { - int mixer = audio_devs[hw_config->slots[0]]->mixer_dev; ad1848_unload(hw_config->io_base + 4, hw_config->irq, hw_config->dma, diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 99e15cb22514..6ffa1d19d85e 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -534,6 +534,7 @@ int sound_alloc_audiodev(void) int sound_alloc_mididev(void) { +#ifdef CONFIG_MIDI int i = register_sound_midi(&oss_sound_fops); if(i==-1) return i; @@ -541,6 +542,9 @@ int sound_alloc_mididev(void) if(i>=num_midis) num_midis = i + 1; return i; +#else + return (-1); +#endif } int sound_alloc_synthdev(void) diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 607955d23bdc..e1af44cef399 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -849,7 +849,7 @@ unload_mad16_mpu(struct address_info *hw_config) #if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { - sb_dsp_unload(hw_config); + sb_dsp_unload(hw_config, 0); return; } #endif diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c index ad7ceaa489c4..a3f73ededff3 100644 --- a/drivers/sound/msnd.c +++ b/drivers/sound/msnd.c @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.c,v 1.9 1998/09/04 18:41:27 andrewtv Exp $ + * $Id: msnd.c,v 1.16 1998/09/08 04:05:56 andrewtv Exp $ * ********************************************************************/ @@ -46,6 +46,7 @@ # include # include #endif +#include #include "msnd.h" #define LOGNAME "msnd" @@ -224,7 +225,7 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) int msnd_wait_TXDE(multisound_dev_t *dev) { register unsigned int io = dev->io; - register int timeout = 100; + register int timeout = 1000; while(timeout-- > 0) if (inb(io + HP_ISR) & HPISR_TXDE) @@ -236,7 +237,7 @@ int msnd_wait_TXDE(multisound_dev_t *dev) int msnd_wait_HC0(multisound_dev_t *dev) { register unsigned int io = dev->io; - register int timeout = 100; + register int timeout = 1000; while(timeout-- > 0) if (!(inb(io + HP_CVR) & HPCVR_HC)) @@ -248,17 +249,16 @@ int msnd_wait_HC0(multisound_dev_t *dev) int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd) { unsigned long flags; - + spin_lock_irqsave(&dev->lock, flags); if (msnd_wait_HC0(dev) == 0) { - outb(cmd, dev->io + HP_CVR); spin_unlock_irqrestore(&dev->lock, flags); return 0; } spin_unlock_irqrestore(&dev->lock, flags); - printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n"); + printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n"); return -EIO; } @@ -269,14 +269,13 @@ int msnd_send_word(multisound_dev_t *dev, unsigned char high, register unsigned int io = dev->io; if (msnd_wait_TXDE(dev) == 0) { - outb(high, io + HP_TXH); outb(mid, io + HP_TXM); outb(low, io + HP_TXL); return 0; } - printk(KERN_WARNING LOGNAME ": Send host word timeout\n"); + printk(KERN_DEBUG LOGNAME ": Send host word timeout\n"); return -EIO; } @@ -286,7 +285,6 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len) int i; if (len % 3 != 0) { - printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n"); return -EINVAL; } @@ -303,31 +301,27 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len) int msnd_enable_irq(multisound_dev_t *dev) { - printk(KERN_DEBUG LOGNAME ": enable_irq: count %d\n", dev->irq_ref); + unsigned long flags; - if (dev->irq_ref++ != 0) + if (dev->irq_ref++) return 0; printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n"); - + + spin_lock_irqsave(&dev->lock, flags); if (msnd_wait_TXDE(dev) == 0) { - - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); - if (dev->type == msndClassic) outb(dev->irqid, dev->io + HP_IRQM); - outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR); outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR); - + enable_irq(dev->irq); spin_unlock_irqrestore(&dev->lock, flags); - return 0; } + spin_unlock_irqrestore(&dev->lock, flags); + + printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n"); return -EIO; } @@ -336,29 +330,28 @@ int msnd_disable_irq(multisound_dev_t *dev) { unsigned long flags; - printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref); - if (--dev->irq_ref > 0) return 0; - if (dev->irq_ref < 0) { - printk(KERN_WARNING LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); -/* dev->irq_ref = 0; */ - } + if (dev->irq_ref < 0) + printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n"); - - udelay(50); spin_lock_irqsave(&dev->lock, flags); - outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); - - if (dev->type == msndClassic) - outb(HPIRQ_NONE, dev->io + HP_IRQM); - + if (msnd_wait_TXDE(dev) == 0) { + outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); + if (dev->type == msndClassic) + outb(HPIRQ_NONE, dev->io + HP_IRQM); + disable_irq(dev->irq); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; + } spin_unlock_irqrestore(&dev->lock, flags); - return 0; + printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n"); + + return -EIO; } #ifndef LINUX20 diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index 804cff425c45..871a3a9652e3 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -24,19 +24,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.h,v 1.18 1998/09/04 18:43:40 andrewtv Exp $ + * $Id: msnd.h,v 1.31 1998/09/10 14:02:58 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_H #define __MSND_H -#define VERSION "0.7.13" +#define VERSION "0.8.2" #define DEFSAMPLERATE DSP_DEFAULT_SPEED #define DEFSAMPLESIZE AFMT_U8 #define DEFCHANNELS 1 -#define DEFFIFOSIZE 64 +#define DEFFIFOSIZE 128 #define SNDCARD_MSND 38 @@ -151,6 +151,7 @@ #define PCTODSP_OFFSET(w) (USHORT)((w)/2) #define PCTODSP_BASED(w) (USHORT)(((w)/2) + DSP_BASE_ADDR) +#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2) #ifdef SLOWIO # undef outb @@ -207,14 +208,10 @@ typedef struct multisound_dev { int memid, irqid; int irq, irq_ref; unsigned char info; - char *base; -#ifndef LINUX20 - spinlock_t lock; -#endif + volatile BYTE *base; /* Motorola 56k DSP SMA */ volatile BYTE *SMA; - volatile BYTE *CurDAQD, *CurDARQD; volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ; volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData; @@ -222,27 +219,32 @@ typedef struct multisound_dev { enum { msndClassic, msndPinnacle } type; mode_t mode; unsigned long flags; -#define F_BANKONE 0 -#define F_INTERRUPT 1 -#define F_WRITING 2 -#define F_WRITEBLOCK 3 -#define F_READING 4 -#define F_READBLOCK 5 -#define F_AUDIO_INUSE 6 -#define F_EXT_MIDI_INUSE 7 -#define F_INT_MIDI_INUSE 8 -#define F_WRITEFLUSH 9 -#define F_HAVEDIGITAL 10 +#define F_RESETTING 0 +#define F_HAVEDIGITAL 1 +#define F_AUDIO_WRITE_INUSE 2 +#define F_WRITING 3 +#define F_WRITEBLOCK 4 +#define F_WRITEFLUSH 5 +#define F_AUDIO_READ_INUSE 6 +#define F_READING 7 +#define F_READBLOCK 8 +#define F_EXT_MIDI_INUSE 9 +#define F_INT_MIDI_INUSE 10 struct wait_queue *writeblock, *readblock; struct wait_queue *writeflush; +#ifndef LINUX20 + spinlock_t lock; +#endif + int nresets; unsigned long recsrc; int left_levels[16]; int right_levels[16]; int mixer_mod_count; int calibrate_signal; - int sample_size; - int sample_rate; - int channels; + int play_sample_size, play_sample_rate, play_channels; + int play_ndelay; + int rec_sample_size, rec_sample_rate, rec_channels; + int rec_ndelay; BYTE bCurrentMidiPatch; void (*inc_ref)(void); void (*dec_ref)(void); @@ -250,7 +252,7 @@ typedef struct multisound_dev { /* Digital audio FIFOs */ msnd_fifo DAPF, DARF; int fifosize; - int lastbank; + int last_playbank, last_recbank; /* MIDI in callback */ void (*midi_in_interrupt)(struct multisound_dev *); diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h index bdc28ffd087e..25898f8e0744 100644 --- a/drivers/sound/msnd_classic.h +++ b/drivers/sound/msnd_classic.h @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_classic.h,v 1.7 1998/09/03 06:39:47 andrewtv Exp $ + * $Id: msnd_classic.h,v 1.9 1998/09/10 04:11:18 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_CLASSIC_H diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index bebb5d49c7c1..03e6a177e0d9 100644 --- a/drivers/sound/msnd_pinnacle.c +++ b/drivers/sound/msnd_pinnacle.c @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.c,v 1.17 1998/09/04 18:41:27 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.63 1998/09/10 18:37:19 andrewtv Exp $ * ********************************************************************/ @@ -45,6 +45,7 @@ #ifndef LINUX20 # include #endif +#include #include "sound_config.h" #include "sound_firmware.h" #ifdef MSND_CLASSIC @@ -52,13 +53,29 @@ #endif #include "msnd.h" #ifdef MSND_CLASSIC +# ifdef CONFIG_MSNDCLAS_HAVE_BOOT +# define HAVE_DSPCODEH +# endif # include "msnd_classic.h" # define LOGNAME "msnd_classic" #else +# ifdef CONFIG_MSNDPIN_HAVE_BOOT +# define HAVE_DSPCODEH +# endif # include "msnd_pinnacle.h" # define LOGNAME "msnd_pinnacle" #endif +#define get_play_delay_jiffies(size) ((size) * HZ * \ + dev.play_sample_size / 8 / \ + dev.play_sample_rate / \ + dev.play_channels) + +#define get_rec_delay_jiffies(size) ((size) * HZ * \ + dev.rec_sample_size / 8 / \ + dev.rec_sample_rate / \ + dev.rec_channels) + static multisound_dev_t dev; #ifndef HAVE_DSPCODEH @@ -66,71 +83,86 @@ static char *dspini, *permini; static int sizeof_dspini, sizeof_permini; #endif +static int dsp_full_reset(void); +static void dsp_write_flush(void); + +static __inline__ int chk_send_dsp_cmd(multisound_dev_t *dev, register BYTE cmd) +{ + if (msnd_send_dsp_cmd(dev, cmd) == 0) + return 0; + dsp_full_reset(); + return msnd_send_dsp_cmd(dev, cmd); +} + static void reset_play_queue(void) { int n; LPDAQD lpDAQ; - msnd_fifo_make_empty(&dev.DAPF); - writew(0, dev.DAPQ + JQS_wHead); - writew(PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE), dev.DAPQ + JQS_wTail); - dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF); - outb(HPBLKSEL_0, dev.io + HP_BLKS); - memset_io(dev.base, 0, DAP_BUFF_SIZE * 3); + dev.last_playbank = -1; + writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead); + writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail); - for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) { + for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart); - writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize); + writew(0, lpDAQ + DAQDS_wSize); writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); + writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize); + writew(dev.play_channels, lpDAQ + DAQDS_wChannels); + writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate); writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); + writew(n, lpDAQ + DAQDS_wFlags); } - dev.lastbank = -1; } static void reset_record_queue(void) { int n; LPDAQD lpDAQ; + unsigned long flags; - msnd_fifo_make_empty(&dev.DARF); - writew(0, dev.DARQ + JQS_wHead); - writew(PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE), dev.DARQ + JQS_wTail); - dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF); + dev.last_recbank = 2; + writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead); + writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail); + + /* Critical section: bank 1 access */ + spin_lock_irqsave(&dev.lock, flags); outb(HPBLKSEL_1, dev.io + HP_BLKS); memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); outb(HPBLKSEL_0, dev.io + HP_BLKS); + spin_unlock_irqrestore(&dev.lock, flags); - for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) { + for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart); writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize); writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); + writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize); + writew(dev.rec_channels, lpDAQ + DAQDS_wChannels); + writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate); writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); + writew(n, lpDAQ + DAQDS_wFlags); } } static void reset_queues(void) { - writew(0, dev.DSPQ + JQS_wHead); - writew(0, dev.DSPQ + JQS_wTail); - reset_play_queue(); - reset_record_queue(); + if (dev.mode & FMODE_WRITE) { + msnd_fifo_make_empty(&dev.DAPF); + reset_play_queue(); + } + if (dev.mode & FMODE_READ) { + msnd_fifo_make_empty(&dev.DARF); + reset_record_queue(); + } } -static int dsp_set_format(int val) +static int dsp_set_format(struct file *file, int val) { int data, i; LPDAQD lpDAQ, lpDARQ; - lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF); + lpDAQ = dev.base + DAPQ_DATA_BUFF; + lpDARQ = dev.base + DARQ_DATA_BUFF; switch (val) { case AFMT_U8: @@ -143,28 +175,43 @@ static int dsp_set_format(int val) } for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wSampleSize); - writew(data, lpDARQ + DAQDS_wSampleSize); + if (file->f_mode & FMODE_WRITE) + writew(data, lpDAQ + DAQDS_wSampleSize); + if (file->f_mode & FMODE_READ) + writew(data, lpDARQ + DAQDS_wSampleSize); } - - dev.sample_size = data; + if (file->f_mode & FMODE_WRITE) + dev.play_sample_size = data; + if (file->f_mode & FMODE_READ) + dev.rec_sample_size = data; return data; } -static int dsp_ioctl(unsigned int cmd, unsigned long arg) +static int dsp_get_frag_size(void) +{ + int size; + size = dev.fifosize / 4; + if (size > 32 * 1024) + size = 32 * 1024; + return size; +} + +static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int val, i, data, tmp; LPDAQD lpDAQ, lpDARQ; + audio_buf_info abinfo; + unsigned long flags; - lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF); + lpDAQ = dev.base + DAPQ_DATA_BUFF; + lpDARQ = dev.base + DARQ_DATA_BUFF; switch (cmd) { case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: case SNDCTL_DSP_SETDUPLEX: + case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETIPTR: @@ -173,14 +220,39 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) case SNDCTL_DSP_MAPOUTBUF: return -EINVAL; - case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&dev.lock, flags); + abinfo.fragsize = dsp_get_frag_size(); + abinfo.bytes = dev.DAPF.n - dev.DAPF.len; + abinfo.fragstotal = dev.DAPF.n / abinfo.fragsize; + abinfo.fragments = abinfo.bytes / abinfo.fragsize; + spin_unlock_irqrestore(&dev.lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&dev.lock, flags); + abinfo.fragsize = dsp_get_frag_size(); + abinfo.bytes = dev.DARF.n - dev.DARF.len; + abinfo.fragstotal = dev.DARF.n / abinfo.fragsize; + abinfo.fragments = abinfo.bytes / abinfo.fragsize; + spin_unlock_irqrestore(&dev.lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_RESET: - reset_play_queue(); - reset_record_queue(); + dev.nresets = 0; + reset_queues(); + return 0; + + case SNDCTL_DSP_SYNC: + dsp_write_flush(); return 0; case SNDCTL_DSP_GETBLKSIZE: - tmp = dev.fifosize / 4; + tmp = dsp_get_frag_size(); if (put_user(tmp, (int *)arg)) return -EFAULT; return 0; @@ -195,14 +267,24 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) if (get_user(val, (int *)arg)) return -EFAULT; - data = (val == AFMT_QUERY) ? dev.sample_size : dsp_set_format(val); + if (file->f_mode & FMODE_WRITE) + data = val == AFMT_QUERY + ? dev.play_sample_size + : dsp_set_format(file, val); + else + data = val == AFMT_QUERY + ? dev.rec_sample_size + : dsp_set_format(file, val); if (put_user(data, (int *)arg)) return -EFAULT; return 0; case SNDCTL_DSP_NONBLOCK: - dev.mode |= O_NONBLOCK; + if (file->f_mode & FMODE_WRITE) + dev.play_ndelay = 1; + if (file->f_mode & FMODE_READ) + dev.rec_ndelay = 1; return 0; case SNDCTL_DSP_GETCAPS: @@ -224,65 +306,58 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) data = val; for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wSampleRate); - writew(data, lpDARQ + DAQDS_wSampleRate); + if (file->f_mode & FMODE_WRITE) + writew(data, lpDAQ + DAQDS_wSampleRate); + if (file->f_mode & FMODE_READ) + writew(data, lpDARQ + DAQDS_wSampleRate); } - - dev.sample_rate = data; + if (file->f_mode & FMODE_WRITE) + dev.play_sample_rate = data; + if (file->f_mode & FMODE_READ) + dev.rec_sample_rate = data; if (put_user(data, (int *)arg)) return -EFAULT; return 0; case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - return -EFAULT; - - switch (val) { - case 1: - case 2: - data = val; - break; - default: - val = data = 2; - break; - } - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wChannels); - writew(data, lpDARQ + DAQDS_wChannels); - } - - dev.channels = data; - - if (put_user(val, (int *)arg)) - return -EFAULT; - return 0; - case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; - - switch (val) { - case 0: - data = 1; - break; - default: - val = 1; - case 1: - data = 2; - break; + + if (cmd == SNDCTL_DSP_CHANNELS) { + switch (val) { + case 1: + case 2: + data = val; + break; + default: + val = data = 2; + break; + } + } else { + switch (val) { + case 0: + data = 1; + break; + default: + val = 1; + case 1: + data = 2; + break; + } } for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wChannels); - writew(data, lpDARQ + DAQDS_wChannels); + if (file->f_mode & FMODE_WRITE) + writew(data, lpDAQ + DAQDS_wChannels); + if (file->f_mode & FMODE_READ) + writew(data, lpDARQ + DAQDS_wChannels); } - - dev.channels = data; + if (file->f_mode & FMODE_WRITE) + dev.play_channels = data; + if (file->f_mode & FMODE_READ) + dev.rec_channels = data; if (put_user(val, (int *)arg)) return -EFAULT; @@ -320,6 +395,12 @@ static int mixer_get(int d) writew(dev.right_levels[a] * readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff / s, \ dev.SMA + SMA_##b##Right); +#define update_pot(d,s,ar) \ + writeb(dev.left_levels[d] >> 8, dev.SMA + SMA_##s##Left); \ + writeb(dev.right_levels[d] >> 8, dev.SMA + SMA_##s##Right); \ + if (msnd_send_word(&dev, 0, 0, ar) == 0) \ + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); + static int mixer_set(int d, int value) { int left = value & 0x000000ff; @@ -350,7 +431,7 @@ static int mixer_set(int d, int value) writeb(bLeft, dev.SMA + SMA_bInPotPosLeft); writeb(bRight, dev.SMA + SMA_bInPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; #ifndef MSND_CLASSIC @@ -358,7 +439,7 @@ static int mixer_set(int d, int value) writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft); writeb(bRight, dev.SMA + SMA_bMicPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; #endif @@ -366,7 +447,7 @@ static int mixer_set(int d, int value) writeb(bLeft, dev.SMA + SMA_bAuxPotPosLeft); writeb(bRight, dev.SMA + SMA_bAuxPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; /* digital controls */ @@ -389,6 +470,20 @@ static int mixer_set(int d, int value) return mixer_get(d); } +static void mixer_setup(void) +{ + update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS); +#ifndef MSND_CLASSIC + update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS); +#endif + update_pot(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); + update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1); + update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1); +#ifndef MSND_CLASSIC + update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1); +#endif +} + static unsigned long set_recsrc(unsigned long recsrc) { if (dev.recsrc == recsrc) @@ -403,17 +498,15 @@ static unsigned long set_recsrc(unsigned long recsrc) #ifndef MSND_CLASSIC if (dev.recsrc & SOUND_MASK_LINE) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else if (dev.recsrc & SOUND_MASK_SYNTH) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) { - udelay(50); - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } + if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else { #ifdef HAVE_NORECSRC @@ -422,7 +515,7 @@ static unsigned long set_recsrc(unsigned long recsrc) #else dev.recsrc = SOUND_MASK_LINE; if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); #endif } #endif /* MSND_CLASSIC */ @@ -430,6 +523,12 @@ static unsigned long set_recsrc(unsigned long recsrc) return dev.recsrc; } +static unsigned long force_recsrc(unsigned long recsrc) +{ + dev.recsrc = 0; + return set_recsrc(recsrc); +} + #define set_mixer_info() \ strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \ strncpy(info.name, "MultiSound Mixer", sizeof(info.name)); @@ -447,10 +546,6 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) set_mixer_info(); return copy_to_user((void *)arg, &info, sizeof(info)); } - else if (cmd == OSS_GETVERSION) { - int sound_version = SOUND_VERSION; - return put_user(sound_version, (int *)arg); - } else if (((cmd >> 8) & 0xff) == 'M') { int val = 0; @@ -521,77 +616,139 @@ static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u { int minor = MINOR(inode->i_rdev); + if (cmd == OSS_GETVERSION) { + int sound_version = SOUND_VERSION; + return put_user(sound_version, (int *)arg); + } + if (minor == dev.dsp_minor) - return dsp_ioctl(cmd, arg); + return dsp_ioctl(file, cmd, arg); else if (minor == dev.mixer_minor) return mixer_ioctl(cmd, arg); return -EINVAL; } -static void dsp_halt(void) +static void dsp_write_flush(void) { - mdelay(1); -#ifdef LINUX20 - if (test_bit(F_READING, &dev.flags)) { - clear_bit(F_READING, &dev.flags); -#else - if (test_and_clear_bit(F_READING, &dev.flags)) { -#endif - msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP); - msnd_disable_irq(&dev); - - } - mdelay(1); -#ifdef LINUX20 - if (test_bit(F_WRITING, &dev.flags)) { - clear_bit(F_WRITING, &dev.flags); -#else - if (test_and_clear_bit(F_WRITING, &dev.flags)) { -#endif - set_bit(F_WRITEFLUSH, &dev.flags); - interruptible_sleep_on(&dev.writeflush); + if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) + return; + set_bit(F_WRITEFLUSH, &dev.flags); + current->timeout = jiffies + get_play_delay_jiffies(dev.DAPF.len) + HZ / 8; + interruptible_sleep_on(&dev.writeflush); + clear_bit(F_WRITEFLUSH, &dev.flags); + if (!signal_pending(current)) { current->state = TASK_INTERRUPTIBLE; - current->timeout = - jiffies + DAP_BUFF_SIZE / 2 * HZ / - dev.sample_rate / dev.channels; + current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE); schedule(); current->timeout = 0; - msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP); - msnd_disable_irq(&dev); - memset_io(dev.base, 0, DAP_BUFF_SIZE * 3); + } else + current->timeout = 0; + clear_bit(F_WRITING, &dev.flags); +} +static void dsp_halt(struct file *file) +{ + if ((file ? file->f_mode : dev.mode) & FMODE_READ) { + clear_bit(F_READING, &dev.flags); + chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP); + msnd_disable_irq(&dev); + if (file) { + printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file); + dev.mode &= ~FMODE_READ; + } + clear_bit(F_AUDIO_READ_INUSE, &dev.flags); + } + if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { + if (test_bit(F_WRITING, &dev.flags)) { + dsp_write_flush(); + chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP); + } + msnd_disable_irq(&dev); + if (file) { + printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file); + dev.mode &= ~FMODE_WRITE; + } + clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags); } - mdelay(1); - reset_queues(); } -static int dsp_open(struct file *file) +static int dsp_release(struct file *file) { - dev.mode = file->f_mode; - set_bit(F_AUDIO_INUSE, &dev.flags); - reset_queues(); + dsp_halt(file); return 0; } -static int dsp_close(void) +static int dsp_open(struct file *file) { - dsp_halt(); - clear_bit(F_AUDIO_INUSE, &dev.flags); + if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { + set_bit(F_AUDIO_WRITE_INUSE, &dev.flags); + clear_bit(F_WRITING, &dev.flags); + msnd_fifo_make_empty(&dev.DAPF); + reset_play_queue(); + if (file) { + printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file); + dev.mode |= FMODE_WRITE; + } + msnd_enable_irq(&dev); + } + if ((file ? file->f_mode : dev.mode) & FMODE_READ) { + set_bit(F_AUDIO_READ_INUSE, &dev.flags); + clear_bit(F_READING, &dev.flags); + msnd_fifo_make_empty(&dev.DARF); + reset_record_queue(); + if (file) { + printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file); + dev.mode |= FMODE_READ; + } + msnd_enable_irq(&dev); + } return 0; } +static void set_default_play_audio_parameters(void) +{ + dev.play_sample_size = DEFSAMPLESIZE; + dev.play_sample_rate = DEFSAMPLERATE; + dev.play_channels = DEFCHANNELS; +} + +static void set_default_rec_audio_parameters(void) +{ + dev.rec_sample_size = DEFSAMPLESIZE; + dev.rec_sample_rate = DEFSAMPLERATE; + dev.rec_channels = DEFCHANNELS; +} + +static void set_default_audio_parameters(void) +{ + set_default_play_audio_parameters(); + set_default_rec_audio_parameters(); +} + static int dev_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); int err = 0; if (minor == dev.dsp_minor) { - - if (test_bit(F_AUDIO_INUSE, &dev.flags)) + if ((file->f_mode & FMODE_WRITE && + test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || + (file->f_mode & FMODE_READ && + test_bit(F_AUDIO_READ_INUSE, &dev.flags))) return -EBUSY; - err = dsp_open(file); + if ((err = dsp_open(file)) >= 0) { + dev.nresets = 0; + if (file->f_mode & FMODE_WRITE) { + set_default_play_audio_parameters(); + dev.play_ndelay = (file->f_mode & O_NDELAY) ? 1 : 0; + } + if (file->f_mode & FMODE_READ) { + set_default_rec_audio_parameters(); + dev.rec_ndelay = (file->f_mode & O_NDELAY) ? 1 : 0; + } + } } else if (minor == dev.mixer_minor) { /* nothing */ @@ -605,9 +762,9 @@ static int dev_open(struct inode *inode, struct file *file) } #ifdef LINUX20 -static void dev_close(struct inode *inode, struct file *file) +static void dev_release(struct inode *inode, struct file *file) #else -static int dev_close(struct inode *inode, struct file *file) +static int dev_release(struct inode *inode, struct file *file) #endif { int minor = MINOR(inode->i_rdev); @@ -619,7 +776,7 @@ static int dev_close(struct inode *inode, struct file *file) #ifndef LINUX20 err = #endif - dsp_close(); + dsp_release(file); } else if (minor == dev.mixer_minor) { /* nothing */ @@ -637,62 +794,137 @@ static int dev_close(struct inode *inode, struct file *file) #endif } -static int DAPF_to_bank(int bank) +static __inline__ int pack_DARQ_to_DARF(register int bank) { - return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0); + register int size, n, timeout = 3; + register WORD wTmp; + LPDAQD DAQD; + + /* Increment the tail and check for queue wrap */ + wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size); + if (wTmp > readw(dev.DARQ + JQS_wSize)) + wTmp = 0; + while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--) + udelay(1); + writew(wTmp, dev.DARQ + JQS_wTail); + + /* Get our digital audio queue struct */ + DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF; + + /* Get length of data */ + size = readw(DAQD + DAQDS_wSize); + + /* Read data from the head (unprotected bank 1 access okay + since this is only called inside an interrupt) */ + outb(HPBLKSEL_1, dev.io + HP_BLKS); + if ((n = msnd_fifo_write( + &dev.DARF, + (char *)(dev.base + bank * DAR_BUFF_SIZE), + size, 0)) < 0) { + outb(HPBLKSEL_0, dev.io + HP_BLKS); + return n; + } + outb(HPBLKSEL_0, dev.io + HP_BLKS); + + return 1; } -static int bank_to_DARF(int bank) +static __inline__ int pack_DAPF_to_DAPQ(register int start) { - return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0); + register WORD DAPQ_tail; + register int protect = start, nbanks = 0; + LPDAQD DAQD; + + DAPQ_tail = readw(dev.DAPQ + JQS_wTail); + while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) { + register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); + register int n; + unsigned long flags; + + /* Write the data to the new tail */ + if (protect) { + /* Critical section: protect fifo in non-interrupt */ + spin_lock_irqsave(&dev.lock, flags); + if ((n = msnd_fifo_read( + &dev.DAPF, + (char *)(dev.base + bank_num * DAP_BUFF_SIZE), + DAP_BUFF_SIZE, 0)) < 0) { + spin_unlock_irqrestore(&dev.lock, flags); + return n; + } + spin_unlock_irqrestore(&dev.lock, flags); + } else { + if ((n = msnd_fifo_read( + &dev.DAPF, + (char *)(dev.base + bank_num * DAP_BUFF_SIZE), + DAP_BUFF_SIZE, 0)) < 0) { + return n; + } + } + if (!n) + break; + + if (start) + start = 0; + + /* Get our digital audio queue struct */ + DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF; + + /* Write size of this bank */ + writew(n, DAQD + DAQDS_wSize); + ++nbanks; + + /* Then advance the tail */ + DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); + writew(DAPQ_tail, dev.DAPQ + JQS_wTail); + + /* Tell the DSP to play the bank */ + msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); + } + + return nbanks; } static int dsp_read(char *buf, size_t len) { - int err = 0; int count = len; while (count > 0) { - int n; + unsigned long flags; + /* Critical section: protect fifo in non-interrupt */ + spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) { - printk(KERN_WARNING LOGNAME ": FIFO read error\n"); + spin_unlock_irqrestore(&dev.lock, flags); return n; } - + spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; -#ifdef LINUX20 - if (!test_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) { - set_bit(F_READING, &dev.flags); -#else - if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) { -#endif - reset_record_queue(); - msnd_enable_irq(&dev); - msnd_send_dsp_cmd(&dev, HDEX_RECORD_START); - + if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { + dev.last_recbank = -1; + if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) + set_bit(F_READING, &dev.flags); } - if (dev.mode & O_NONBLOCK) + if (dev.rec_ndelay) return count == len ? -EAGAIN : len - count; if (count > 0) { - set_bit(F_READBLOCK, &dev.flags); + current->timeout = jiffies + get_rec_delay_jiffies(DAR_BUFF_SIZE); interruptible_sleep_on(&dev.readblock); + if (current->timeout == 0) + clear_bit(F_READING, &dev.flags); + else + current->timeout = 0; clear_bit(F_READBLOCK, &dev.flags); - if (signal_pending(current)) - err = -EINTR; - + return -EINTR; } - - if (err != 0) - return err; } return len - count; @@ -700,50 +932,41 @@ static int dsp_read(char *buf, size_t len) static int dsp_write(const char *buf, size_t len) { - int err = 0; int count = len; while (count > 0) { - int n; + unsigned long flags; + /* Critical section: protect fifo in non-interrupt */ + spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) { - printk(KERN_WARNING LOGNAME ": FIFO write error\n"); + spin_unlock_irqrestore(&dev.lock, flags); return n; } - + spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; -#ifdef LINUX20 if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { - set_bit(F_WRITING, &dev.flags); -#else - if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { -#endif - reset_play_queue(); - msnd_enable_irq(&dev); - msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); - + dev.last_playbank = -1; + if (pack_DAPF_to_DAPQ(1) > 0) + set_bit(F_WRITING, &dev.flags); } - if (dev.mode & O_NONBLOCK) + if (dev.play_ndelay) return count == len ? -EAGAIN : len - count; if (count > 0) { - set_bit(F_WRITEBLOCK, &dev.flags); + current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE); interruptible_sleep_on(&dev.writeblock); + current->timeout = 0; clear_bit(F_WRITEBLOCK, &dev.flags); - if (signal_pending(current)) - err = -EINTR; - + return -EINTR; } - - if (err != 0) - return err; } return len - count; @@ -758,12 +981,9 @@ static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off) { int minor = MINOR(file->f_dentry->d_inode->i_rdev); #endif - - if (minor == dev.dsp_minor) { - + if (minor == dev.dsp_minor) return dsp_read(buf, count); - - } else + else return -EINVAL; } @@ -776,44 +996,22 @@ static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_ { int minor = MINOR(file->f_dentry->d_inode->i_rdev); #endif - - if (minor == dev.dsp_minor) { - + if (minor == dev.dsp_minor) return dsp_write(buf, count); - - } else + else return -EINVAL; } -static void eval_dsp_msg(WORD wMessage) +static __inline__ void eval_dsp_msg(register WORD wMessage) { - WORD wTmp; - switch (HIBYTE(wMessage)) { case HIMT_PLAY_DONE: - if (dev.lastbank == LOBYTE(wMessage)) + if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags)) break; - - dev.lastbank = LOBYTE(wMessage); - - writew(DAP_BUFF_SIZE, dev.CurDAQD + DAQDS_wSize); + dev.last_playbank = LOBYTE(wMessage); - wTmp = readw(dev.DAPQ + JQS_wTail) + PCTODSP_OFFSET(DAPQ_STRUCT_SIZE); - if (wTmp > readw(dev.DAPQ + JQS_wSize)) - writew(0, dev.DAPQ + JQS_wTail); - else - writew(wTmp, dev.DAPQ + JQS_wTail); - - if ((dev.CurDAQD += DAQDS__size) > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE)) - dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - - if (dev.lastbank < 3) { - if (DAPF_to_bank(dev.lastbank) > 0) { - mdelay(1); - msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); - } - else if (!test_bit(F_WRITEBLOCK, &dev.flags)) { - clear_bit(F_WRITING, &dev.flags); + if (pack_DAPF_to_DAPQ(0) <= 0) { + if (!test_bit(F_WRITEBLOCK, &dev.flags)) { #ifdef LINUX20 if (test_bit(F_WRITEFLUSH, &dev.flags)) { clear_bit(F_WRITEFLUSH, &dev.flags); @@ -824,6 +1022,7 @@ static void eval_dsp_msg(WORD wMessage) wake_up_interruptible(&dev.writeflush); #endif } + clear_bit(F_WRITING, &dev.flags); } if (test_bit(F_WRITEBLOCK, &dev.flags)) @@ -831,21 +1030,11 @@ static void eval_dsp_msg(WORD wMessage) break; case HIMT_RECORD_DONE: - wTmp = readw(dev.DARQ + JQS_wTail) + DARQ_STRUCT_SIZE / 2; - - if (wTmp > readw(dev.DARQ + JQS_wSize)) - wTmp = 0; - - while (wTmp == readw(dev.DARQ + JQS_wHead)); + if (dev.last_recbank == LOBYTE(wMessage)) + break; + dev.last_recbank = LOBYTE(wMessage); - writew(wTmp, dev.DARQ + JQS_wTail); - - outb(HPBLKSEL_1, dev.io + HP_BLKS); - if (bank_to_DARF(LOBYTE(wMessage)) == 0 && !test_bit(F_READBLOCK, &dev.flags)) { - memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); - clear_bit(F_READING, &dev.flags); - } - outb(HPBLKSEL_0, dev.io + HP_BLKS); + pack_DARQ_to_DARF(dev.last_recbank); if (test_bit(F_READBLOCK, &dev.flags)) wake_up_interruptible(&dev.readblock); @@ -857,17 +1046,17 @@ static void eval_dsp_msg(WORD wMessage) case HIDSP_PLAY_UNDER: #endif case HIDSP_INT_PLAY_UNDER: -/* printk(KERN_INFO LOGNAME ": Write underflow\n"); */ - reset_play_queue(); +/* printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */ + clear_bit(F_WRITING, &dev.flags); break; case HIDSP_INT_RECORD_OVER: -/* printk(KERN_INFO LOGNAME ": Read overflow\n"); */ - reset_record_queue(); +/* printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */ + clear_bit(F_READING, &dev.flags); break; default: - printk(KERN_DEBUG LOGNAME ": DSP message %u\n", LOBYTE(wMessage)); +/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", LOBYTE(wMessage), LOBYTE(wMessage)); */ break; } break; @@ -877,85 +1066,66 @@ static void eval_dsp_msg(WORD wMessage) (*dev.midi_in_interrupt)(&dev); break; - case HIMT_MIDI_OUT: - printk(KERN_DEBUG LOGNAME ": MIDI out event\n"); - break; - default: - printk(KERN_DEBUG LOGNAME ": HIMT message %u\n", HIBYTE(wMessage)); +/* printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */ break; } } static void intr(int irq, void *dev_id, struct pt_regs *regs) { - if (test_bit(F_INTERRUPT, &dev.flags)) - return; - - set_bit(F_INTERRUPT, &dev.flags); - - if (test_bit(F_BANKONE, &dev.flags)) - outb(HPBLKSEL_0, dev.io + HP_BLKS); - + /* Send ack to DSP */ inb(dev.io + HP_RXL); - + + /* Evaluate queued DSP messages */ while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) { - WORD wTmp; + register WORD wTmp; - eval_dsp_msg(*(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead))); - - wTmp = readw(dev.DSPQ + JQS_wHead) + 1; - if (wTmp > readw(dev.DSPQ + JQS_wSize)) + eval_dsp_msg(readw(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead))); + + if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize)) writew(0, dev.DSPQ + JQS_wHead); else writew(wTmp, dev.DSPQ + JQS_wHead); } - - if (test_bit(F_BANKONE, &dev.flags)) - outb(HPBLKSEL_1, dev.io + HP_BLKS); - - clear_bit(F_INTERRUPT, &dev.flags); } static struct file_operations dev_fileops = { - NULL, - dev_read, - dev_write, - NULL, - NULL, - dev_ioctl, - NULL, - dev_open, + NULL, /* llseek */ + dev_read, /* read */ + dev_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + dev_ioctl, /* ioctl */ + NULL, /* mmap */ + dev_open, /* open */ + NULL, /* flush */ + dev_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ #ifndef LINUX20 -# if LINUX_VERSION_CODE >= 0x020100 + 118 - NULL, -# endif /* >= 2.1.118 */ + NULL, /* lock */ #endif - dev_close, }; -__initfunc(static int reset_dsp(void)) +static int reset_dsp(void) { int timeout = 100; outb(HPDSPRESET_ON, dev.io + HP_DSPR); - mdelay(1); - +#ifndef MSND_CLASSIC dev.info = inb(dev.io + HP_INFO); - +#endif outb(HPDSPRESET_OFF, dev.io + HP_DSPR); - mdelay(1); - while (timeout-- > 0) { - if (inb(dev.io + HP_CVR) == HP_CVR_DEF) return 0; - mdelay(1); } - printk(KERN_ERR LOGNAME ": Cannot reset DSP\n"); return -EIO; @@ -973,7 +1143,6 @@ __initfunc(static int probe_multisound(void)) printk(KERN_ERR LOGNAME ": I/O port conflict\n"); return -ENODEV; } - request_region(dev.io, dev.numio, "probing"); if (reset_dsp() < 0) { @@ -1024,127 +1193,82 @@ __initfunc(static int probe_multisound(void)) return 0; } -__initfunc(static int init_sma(void)) +static void msnd_init_queue(volatile BYTE *base, int start, int size) { - int n; - LPDAQD lpDAQ; + writew(PCTODSP_BASED(start), base + JQS_wStart); + writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); + writew(0, base + JQS_wHead); + writew(0, base + JQS_wTail); +} + +static int init_sma(void) +{ + static int initted; + WORD mastVolLeft, mastVolRight; + unsigned long flags; #ifdef MSND_CLASSIC outb(dev.memid, dev.io + HP_MEMM); #endif outb(HPBLKSEL_0, dev.io + HP_BLKS); + if (initted) { + mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft); + mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight); + } else + mastVolLeft = mastVolRight = 0; memset_io(dev.base, 0, 0x8000); - + + /* Critical section: bank 1 access */ + spin_lock_irqsave(&dev.lock, flags); outb(HPBLKSEL_1, dev.io + HP_BLKS); memset_io(dev.base, 0, 0x8000); - outb(HPBLKSEL_0, dev.io + HP_BLKS); + spin_unlock_irqrestore(&dev.lock, flags); - dev.DAPQ = (BYTE *)(dev.base + DAPQ_OFFSET); - dev.DARQ = (BYTE *)(dev.base + DARQ_OFFSET); - dev.MODQ = (BYTE *)(dev.base + MODQ_OFFSET); - dev.MIDQ = (BYTE *)(dev.base + MIDQ_OFFSET); - dev.DSPQ = (BYTE *)(dev.base + DSPQ_OFFSET); - dev.SMA = (BYTE *)(dev.base + SMA_STRUCT_START); - - dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF); - - dev.sample_size = DEFSAMPLESIZE; - dev.sample_rate = DEFSAMPLERATE; - dev.channels = DEFCHANNELS; - - for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) { - - writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart); - writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); - } - - for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) { - - writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart); - writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); - - } + dev.pwDSPQData = (volatile WORD *)(dev.base + DSPQ_DATA_BUFF); + dev.pwMODQData = (volatile WORD *)(dev.base + MODQ_DATA_BUFF); + dev.pwMIDQData = (volatile WORD *)(dev.base + MIDQ_DATA_BUFF); - dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF); - dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF); - dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF); + /* Motorola 56k shared memory base */ + dev.SMA = dev.base + SMA_STRUCT_START; - writew(PCTODSP_BASED(MIDQ_DATA_BUFF), dev.MIDQ + JQS_wStart); - writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, dev.MIDQ + JQS_wSize); - writew(0, dev.MIDQ + JQS_wHead); - writew(0, dev.MIDQ + JQS_wTail); + /* Digital audio play queue */ + dev.DAPQ = dev.base + DAPQ_OFFSET; + msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE); - writew(PCTODSP_BASED(MODQ_DATA_BUFF), dev.MODQ + JQS_wStart); - writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, dev.MODQ + JQS_wSize); - writew(0, dev.MODQ + JQS_wHead); - writew(0, dev.MODQ + JQS_wTail); + /* Digital audio record queue */ + dev.DARQ = dev.base + DARQ_OFFSET; + msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); - writew(PCTODSP_BASED(DAPQ_DATA_BUFF), dev.DAPQ + JQS_wStart); - writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, dev.DAPQ + JQS_wSize); - writew(0, dev.DAPQ + JQS_wHead); - writew(0, dev.DAPQ + JQS_wTail); + /* MIDI out queue */ + dev.MODQ = dev.base + MODQ_OFFSET; + msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE); - writew(PCTODSP_BASED(DARQ_DATA_BUFF), dev.DARQ + JQS_wStart); - writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, dev.DARQ + JQS_wSize); - writew(0, dev.DARQ + JQS_wHead); - writew(0, dev.DARQ + JQS_wTail); + /* MIDI in queue */ + dev.MIDQ = dev.base + MIDQ_OFFSET; + msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE); - writew(PCTODSP_BASED(DSPQ_DATA_BUFF), dev.DSPQ + JQS_wStart); - writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, dev.DSPQ + JQS_wSize); - writew(0, dev.DSPQ + JQS_wHead); - writew(0, dev.DSPQ + JQS_wTail); - - writew(0, dev.SMA + SMA_wCurrPlayBytes); - writew(0, dev.SMA + SMA_wCurrRecordBytes); - - writew(0, dev.SMA + SMA_wCurrPlayVolLeft); - writew(0, dev.SMA + SMA_wCurrPlayVolRight); - - writew(0, dev.SMA + SMA_wCurrInVolLeft); - writew(0, dev.SMA + SMA_wCurrInVolRight); - - writew(0, dev.SMA + SMA_wCurrMastVolLeft); - writew(0, dev.SMA + SMA_wCurrMastVolRight); + /* DSP -> host message queue */ + dev.DSPQ = dev.base + DSPQ_OFFSET; + msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE); + /* Setup some DSP values */ +#ifndef MSND_CLASSIC + writew(1, dev.SMA + SMA_wCurrPlayFormat); + writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize); + writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels); + writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate); +#endif + writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD); + writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft); + writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight); #ifndef MSND_CLASSIC writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch); writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate); #endif - - writew(0x0000, dev.SMA + SMA_wCurrDSPStatusFlags); - writew(0x0000, dev.SMA + SMA_wCurrHostStatusFlags); - writew(0x303, dev.SMA + SMA_wCurrInputTagBits); - writew(0, dev.SMA + SMA_wCurrLeftPeak); - writew(0, dev.SMA + SMA_wCurrRightPeak); - writeb(0, dev.SMA + SMA_bInPotPosRight); - writeb(0, dev.SMA + SMA_bInPotPosLeft); - - writeb(0, dev.SMA + SMA_bAuxPotPosRight); - writeb(0, dev.SMA + SMA_bAuxPotPosLeft); - -#ifndef MSND_CLASSIC - writew(1, dev.SMA + SMA_wCurrPlayFormat); - writew(dev.sample_size, dev.SMA + SMA_wCurrPlaySampleSize); - writew(dev.channels, dev.SMA + SMA_wCurrPlayChannels); - writew(dev.sample_rate, dev.SMA + SMA_wCurrPlaySampleRate); -#endif - writew(dev.sample_rate, dev.SMA + SMA_wCalFreqAtoD); + initted = 1; return 0; } @@ -1164,7 +1288,7 @@ __initfunc(static int calibrate_adc(WORD srate)) writew(srate, dev.SMA + SMA_wCalFreqAtoD); if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + HZ / 3; schedule(); @@ -1172,13 +1296,12 @@ __initfunc(static int calibrate_adc(WORD srate)) printk("successful\n"); return 0; } - printk("failed\n"); return -EIO; } -__initfunc(static int upload_dsp_code(void)) +static int upload_dsp_code(void) { outb(HPBLKSEL_0, dev.io + HP_BLKS); @@ -1214,7 +1337,7 @@ __initfunc(static int upload_dsp_code(void)) } #ifdef MSND_CLASSIC -__initfunc(static void reset_proteus(void)) +static void reset_proteus(void) { outb(HPPRORESET_ON, dev.io + HP_PROR); mdelay(TIME_PRO_RESET); @@ -1223,7 +1346,7 @@ __initfunc(static void reset_proteus(void)) } #endif -__initfunc(static int initialize(void)) +static int initialize(void) { int err, timeout; @@ -1233,7 +1356,6 @@ __initfunc(static int initialize(void)) reset_proteus(); #endif - if ((err = init_sma()) < 0) { printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n"); return err; @@ -1250,36 +1372,52 @@ __initfunc(static int initialize(void)) printk(KERN_INFO LOGNAME ": DSP upload successful\n"); timeout = 200; - while (readw(dev.base)) { mdelay(1); - if (--timeout < 0) + if (!timeout--) { + printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n"); return -EIO; + } } + mixer_setup(); + return 0; } +static int dsp_full_reset(void) +{ + int rv; + + if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10) + return 0; + + printk(KERN_INFO LOGNAME ": Resetting DSP\n"); + set_bit(F_RESETTING, &dev.flags); + dsp_halt(NULL); /* Unconditionally halt */ + if ((rv = initialize())) + printk(KERN_WARNING LOGNAME ": DSP reset failed\n"); + force_recsrc(dev.recsrc); + dsp_open(NULL); + clear_bit(F_RESETTING, &dev.flags); + + return rv; +} + __initfunc(static int attach_multisound(void)) { int err; - printk(KERN_DEBUG LOGNAME ": Intializing DSP\n"); - - if ((err = request_irq(dev.irq, intr, SA_SHIRQ, dev.name, &dev)) < 0) { + if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) { printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); return err; - } - request_region(dev.io, dev.numio, dev.name); - if ((err = initialize()) < 0) { - printk(KERN_WARNING LOGNAME ": Initialization failure\n"); + if ((err = dsp_full_reset()) < 0) { release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return err; - } if ((err = msnd_register(&dev)) < 0) { @@ -1307,15 +1445,17 @@ __initfunc(static int attach_multisound(void)) } printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", dev.dsp_minor, dev.mixer_minor); - calibrate_adc(dev.sample_rate); + disable_irq(dev.irq); + calibrate_adc(dev.play_sample_rate); #ifndef MSND_CLASSIC printk(KERN_INFO LOGNAME ": Setting initial recording source to Line In\n"); - set_recsrc(SOUND_MASK_LINE); + force_recsrc(SOUND_MASK_LINE); #endif return 0; } +#ifdef MODULE static void unload_multisound(void) { release_region(dev.io, dev.numio); @@ -1324,6 +1464,7 @@ static void unload_multisound(void) unregister_sound_dsp(dev.dsp_minor); msnd_unregister(&dev); } +#endif static void mod_inc_ref(void) { @@ -1558,7 +1699,7 @@ static int mem __initdata = CONFIG_MSNDPIN_MEM; #endif static int cfg __initdata = CONFIG_MSNDPIN_CFG; /* If not a module, we don't need to bother with reset=1 */ -static int reset __initdata; +static int reset; /* Extra Peripheral Configuration (Default: Disable) */ #ifndef CONFIG_MSNDPIN_MPU_IO @@ -1626,10 +1767,8 @@ __initfunc(int msnd_pinnacle_init(void)) printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version " VERSION ", Copyright (C) 1998 Andrew Veliath\n"); - if (io == -1 || irq == -1 || mem == -1) { - + if (io == -1 || irq == -1 || mem == -1) printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n"); - } if (io == -1 || !(io == 0x290 || @@ -1640,7 +1779,6 @@ __initfunc(int msnd_pinnacle_init(void)) io == 0x220 || io == 0x210 || io == 0x3e0)) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n"); return -EINVAL; } @@ -1652,7 +1790,6 @@ __initfunc(int msnd_pinnacle_init(void)) irq == 10 || irq == 11 || irq == 12)) { - printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n"); return -EINVAL; } @@ -1664,7 +1801,6 @@ __initfunc(int msnd_pinnacle_init(void)) mem == 0xd8000 || mem == 0xe0000 || mem == 0xe8000)) { - printk(KERN_ERR LOGNAME ": \"mem\" - must be set to " "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); return -EINVAL; @@ -1734,9 +1870,10 @@ __initfunc(int msnd_pinnacle_init(void)) if (fifosize < 16) fifosize = 16; - if (fifosize > 768) - fifosize = 768; + if (fifosize > 1024) + fifosize = 1024; + set_default_audio_parameters(); #ifdef MSND_CLASSIC dev.type = msndClassic; #else @@ -1771,34 +1908,28 @@ __initfunc(int msnd_pinnacle_init(void)) printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize); if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n"); return err; } if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n"); msnd_fifo_free(&dev.DAPF); return err; } if ((err = probe_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Probe failed\n"); msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); return err; - } if ((err = attach_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Attach failed\n"); msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); return err; - } return 0; @@ -1813,6 +1944,5 @@ void cleanup_module(void) msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); - } #endif diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h index 0ae9a1026627..2f572af2c723 100644 --- a/drivers/sound/msnd_pinnacle.h +++ b/drivers/sound/msnd_pinnacle.h @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.h,v 1.8 1998/09/03 06:39:47 andrewtv Exp $ + * $Id: msnd_pinnacle.h,v 1.10 1998/09/10 04:11:18 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_PINNACLE_H diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index fd6e0b6f5f7d..701be528918e 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -796,7 +796,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l data = (unsigned short *)mbuf->data; save_flags(flags); cli(); - for (i = 0; i < mbuf->len; i++) { + for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) { mbuf->len = i; /* feed back number of WORDs read */ if (!pss_get_dspword(devc, data++)) { if (i == 0) diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 19f8ee825836..f3d99cff41b5 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -122,7 +122,7 @@ void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); int sb_dsp_detect (struct address_info *hw_config); int sb_dsp_init (struct address_info *hw_config); -void sb_dsp_unload(struct address_info *hw_config); +void sb_dsp_unload(struct address_info *hw_config, int sbmpu); int sb_mixer_init(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); void smw_mixer_init(sb_devc *devc); diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 2fc88cb24e08..7977f3ed970a 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -22,6 +22,8 @@ #include "sb_mixer.h" #include "sb.h" +static int sbmpu = 0; + void attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) @@ -43,7 +45,7 @@ int probe_sb(struct address_info *hw_config) void unload_sb(struct address_info *hw_config) { if(hw_config->slots[0]!=-1) - sb_dsp_unload(hw_config); + sb_dsp_unload(hw_config, sbmpu); } int sb_be_quiet=0; @@ -82,8 +84,6 @@ MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); -static int sbmpu = 0; - void *smw_free = NULL; int init_module(void) @@ -113,8 +113,6 @@ int init_module(void) config_mpu.io_base = mpu_io; if (mpu_io && probe_sbmpu(&config_mpu)) sbmpu = 1; -#endif -#ifdef CONFIG_MIDI if (sbmpu) attach_sbmpu(&config_mpu); #endif diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 04b3d785414b..f1a24cc109c2 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -932,7 +932,10 @@ void sb_dsp_disable_recording(int io_base) { } -void sb_dsp_unload(struct address_info *hw_config) +/* if (sbmpu) below we allow mpu401 to manage the midi devs + otherwise we have to unload them. (Andrzej Krzysztofowicz) */ + +void sb_dsp_unload(struct address_info *hw_config, int sbmpu) { sb_devc *devc; @@ -951,10 +954,13 @@ void sb_dsp_unload(struct address_info *hw_config) if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0) { free_irq(devc->irq, devc); - sound_unload_mixerdev(devc->my_mixerdev); + if (devc->my_mixerdev) + sound_unload_mixerdev(devc->my_mixerdev); /* We don't have to do this bit any more the UART401 is its own master -- Krzysztof Halasa */ - /* sound_unload_mididev(devc->my_mididev); */ + /* But we have to do it, if UART401 is not detected */ + if (!sbmpu && devc->my_mididev) + sound_unload_mididev(devc->my_mididev); sound_unload_audiodev(devc->my_dev); } kfree(devc); @@ -1301,10 +1307,8 @@ int probe_sbmpu(struct address_info *hw_config) } hw_config->name = "Sound Blaster 16"; hw_config->irq = -devc->irq; -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) if (devc->minor > 12) /* What is Vibra's version??? */ sb16_set_mpu_port(devc, hw_config); -#endif break; case MDL_ESS: diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 970ec4a0bc85..31a299a96b40 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -182,8 +182,6 @@ void sb_dsp_midi_init(sb_devc * devc) printk(KERN_ERR "sb_midi: too many MIDI devices detected\n"); return; } - std_midi_synth.midi_dev = dev; - devc->my_mididev = dev; std_midi_synth.midi_dev = devc->my_mididev = dev; midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL); if (midi_devs[dev] == NULL) diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 7c4af3d0313a..693433b1bd3a 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -337,7 +337,10 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) case SOUND_MIXER_STEREODEVS: ret = devc->supported_devices; - if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) + /* The ESS seems to have stereo mic controls */ + if (devc->model == MDL_ESS) + ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); + else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); break; diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 514333512207..3220de1297ab 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -1540,12 +1540,12 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) return 0; case SNDCTL_MIDI_INFO: - if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device)))) + if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device)))) return -EFAULT; if (dev < 0 || dev >= max_mididev) return -ENXIO; midi_devs[dev]->info.device = dev; - return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct synth_info))?-EFAULT:0; + return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; case SNDCTL_SEQ_THRESHOLD: if (get_user(val, (int *)arg)) diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 1ed1b8d7855a..97113a838b71 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -39,6 +39,8 @@ static int mpu_initialized = 0; static int *trix_osp = NULL; +static int mpu = 0; + static unsigned char trix_read(int addr) { outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ @@ -445,7 +447,7 @@ void unload_trix_mpu(struct address_info *hw_config) void unload_trix_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP - sb_dsp_unload(hw_config); + sb_dsp_unload(hw_config, mpu); #endif } @@ -479,7 +481,6 @@ struct address_info config; struct address_info sb_config; struct address_info mpu_config; -static int mpu = 0; static int sb = 0; static int fw_load; diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index 3740dd263ce2..e1b092a7e031 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -49,7 +49,7 @@ * aspects of configuring a WaveFront soundcard, particularly the * effects processor. * - * $Id: wavfront.c,v 0.4 1998/07/22 02:12:11 pbd Exp $ + * $Id: wavfront.c,v 0.5 1998/07/22 16:16:41 pbd Exp $ * * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software @@ -667,16 +667,16 @@ wavefront_cmd (wf_config *hw, int cmd, /*********************************************************************** WaveFront: data munging -Things here are weird. All data written to the board cannot -have its most significant bit set. Any data item with values +Things here are wierd. All data written to the board cannot +have its most significant bit set. Any data item with values potentially > 0x7F (127) must be split across multiple bytes. Sometimes, we need to munge numeric values that are represented on -the x86 side as 8- to 32-bit values. Sometimes, we need to munge data -that is represented on the x86 side as an array of bytes. The most +the x86 side as 8-32 bit values. Sometimes, we need to munge data +that is represented on the x86 side as an array of bytes. The most efficient approach to handling both cases seems to be to use 2 -different functions for munging and 2 for de-munging. This avoids -weird casting and worrying about bit-level offsets. +different functions for munging and 2 for de-munging. This avoids +wierd casting and worrying about bit-level offsets. **********************************************************************/ @@ -1198,14 +1198,14 @@ wavefront_send_sample (wf_config *hw, shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), shptr, 4); - /* This one is truly weird. What kind of weirdo decided that in - a system dominated by 16- and 32-bit integers, they would use - just 12 bits ? + /* This one is truly wierd. What kind of wierdo decided that in + a system dominated by 16 and 32 bit integers, they would use + a just 12 bits ? */ shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); - /* Why is this nybblified, when the MSB is *always* zero? + /* Why is this nybblified, when the MSB is *always* zero ? Anyway, we can't take address of bitfield, so make a good-faith guess at where it starts. */ @@ -2278,6 +2278,12 @@ wavefront_hw_reset (wf_config *hw) int bits; int hwv[2]; + /* Check IRQ is legal */ + + if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) { + return 1; + } + if (request_irq (hw->irq, wavefrontintr, 0, "WaveFront", (void *) hw) < 0) { printk (KERN_WARNING "WaveFront: IRQ %d not available!\n", @@ -2325,10 +2331,6 @@ wavefront_hw_reset (wf_config *hw) plus external 9-pin MIDI interface selected */ - if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) { - return 1; - } - outb (0x80 | 0x40 | bits, hw->data_port); /* CONTROL REGISTER @@ -2350,7 +2352,6 @@ wavefront_hw_reset (wf_config *hw) wait till it gets back to use. After a cold boot, this can take some time. - I think this is because its only after a cold boot that the onboard ROM does its memory check, which can take "up to 4 seconds" according to the WaveFront SDK. So, since sleeping @@ -2797,51 +2798,50 @@ wavefront_do_reset (wf_config *hw, int atboot) if (hw->israw || wf_raw) { if (wavefront_download_firmware (hw, ospath)) { goto gone_bad; - return 1; } - } - if (fx_raw) { - wffx_init (hw); - } - - /* If we loaded the OS, we now have to wait for it to be ready - to roll. We can't guarantee that interrupts are enabled, - because we might be reloading the module without forcing a - reset/reload of the firmware. - - Rather than busy-wait, lets just turn interrupts on. - */ - - outb (0x80|0x40|0x10|0x1, hw->control_port); + /* Wait for the OS to get running. The protocol for + this is non-obvious, and was determined by + using port-IO tracing in DOSemu and some + experimentation here. + + Rather than busy-wait, use interrupts creatively. + */ - wavefront_should_cause_interrupt (hw, WFC_NOOP, + wavefront_should_cause_interrupt (hw, WFC_NOOP, hw->data_port, (10*HZ)); - - if (!hw->irq_ok) { - printk (KERN_WARNING "WaveFront: no post-OS interrupt.\n"); - goto gone_bad; - } - - /* Now, do it again ! */ + + if (!hw->irq_ok) { + printk (KERN_WARNING + "WaveFront: no post-OS interrupt.\n"); + goto gone_bad; + } + + /* Now, do it again ! */ + + wavefront_should_cause_interrupt (hw, WFC_NOOP, + hw->data_port, (10*HZ)); + + if (!hw->irq_ok) { + printk (KERN_WARNING + "WaveFront: no post-OS interrupt(2).\n"); + goto gone_bad; + } - wavefront_should_cause_interrupt (hw, WFC_NOOP, - hw->data_port, (10*HZ)); - - if (!hw->irq_ok) { - printk (KERN_WARNING "WaveFront: no post-OS interrupt(2).\n"); - goto gone_bad; + /* OK, no (RX/TX) interrupts any more, but leave mute + on. Master interrupts get enabled when we're done here. + */ + + outb (0x80, hw->control_port); + + /* No need for the IRQ anymore */ + + free_irq (hw->irq, hw); } - - /* OK, no (RX/TX) interrupts any more, but leave mute - on. Master interrupts get enabled when we're done here. - */ - - outb (0x80, hw->control_port); - - /* No need for the IRQ anymore */ - free_irq (hw->irq, hw); + if (/*XXX has_fx_device() && */ fx_raw) { + wffx_init (hw); + } /* SETUPSND.EXE asks for sample memory config here, but since i have no idea how to interpret the result, we'll forget @@ -3109,14 +3109,14 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r) /* YSS225 initialization. - This code was developed using DOSEmu. The Turtle Beach SETUPSND - utility was run with I/O tracing in DOSEmu enabled, and a reconstruction + This code was developed using DOSEMU. The Turtle Beach SETUPSND + utility was run with I/O tracing in DOSEMU enabled, and a reconstruction of the port I/O done, using the Yamaha faxback document as a guide - to add more logic to the code. It's really pretty weird. + to add more logic to the code. Its really pretty wierd. There was an alternative approach of just dumping the whole I/O sequence as a series of port/value pairs and a simple loop - that output it. However, I hope that eventually I'll get more + that output it. However, I hope that eventually I'll get more control over what this code does, and so I tried to stick with a somewhat "algorithmic" approach. */ @@ -3592,7 +3592,7 @@ int init_module (void) { printk ("Turtle Beach WaveFront Driver\n" - "Copyright (C) by Hannu Savolainen, " + "Copyright (C) by Hannu Solvainen, " "Paul Barton-Davis 1993-1998.\n"); if (io == -1 || irq == -1) { diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 976eec39056f..5664f22e31cf 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -379,6 +379,8 @@ static unsigned long load_aout_interp(struct exec * interp_ex, retval = read_exec(interpreter_dentry, offset, addr, text_data, 0); if (retval < 0) goto out; + flush_icache_range((unsigned long)addr, + (unsigned long)addr + text_data); do_mmap(NULL, ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1), interp_ex->a_bss, diff --git a/fs/devpts/root.c b/fs/devpts/root.c index 04215ad40e9c..2c8a3cf8257e 100644 --- a/fs/devpts/root.c +++ b/fs/devpts/root.c @@ -160,6 +160,9 @@ static int devpts_root_lookup(struct inode * dir, struct dentry * dentry) entry += (*p++ - '0'); } } + + if (entry > sbi->max_ptys) + return -ENOENT; dentry->d_inode = sbi->inodes[entry]; if ( dentry->d_inode ) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 25194e9a399b..748b9e9336e2 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -221,13 +221,13 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug, if (value) ret = 0; else opts->sys_immutable = 1; } - else if (!strcmp(this_char,"codepage")) { + else if (!strcmp(this_char,"codepage") && value) { opts->codepage = simple_strtoul(value,&value,0); if (*value) ret = 0; else printk ("MSDOS FS: Using codepage %d\n", opts->codepage); } - else if (!strcmp(this_char,"iocharset")) { + else if (!strcmp(this_char,"iocharset") && value) { p = value; while (*value && *value != ',') value++; len = value - p; diff --git a/fs/hfs/ChangeLog b/fs/hfs/ChangeLog index 423f86e67510..9bcf33dae6d6 100644 --- a/fs/hfs/ChangeLog +++ b/fs/hfs/ChangeLog @@ -1,3 +1,17 @@ +1998-09-11 a sun + + * mdb.c: altered mdb struct to reflect hfs plus usage. + +1998-08-27 a sun + + * file.c, file_hdr.c, file_cap.c: dealt with the remaining + copy_to/from_user() error cases. + +1998-08-26 a sun + + * super.c (hfs_read_super): fixed to deal with cdroms. why doesn't + the cdrom layer call the partition table code? + Wed Jan 21 14:04:26 1998 a sun * inode.c, sysdep.c diff --git a/fs/hfs/file.c b/fs/hfs/file.c index 6157afb4730a..0fe16a7386a8 100644 --- a/fs/hfs/file.c +++ b/fs/hfs/file.c @@ -267,15 +267,19 @@ static inline void xlate_to_user(char *buf, const char *data, int count) * * Like copy_from_user() while translating NL->CR; */ -static inline void xlate_from_user(char *data, const char *buf, int count) +static inline int xlate_from_user(char *data, const char *buf, int count) { - count -= copy_from_user(data, buf, count); + int i; + + i = copy_from_user(data, buf, count); + count -= i; while (count--) { if (*data == '\n') { *data = '\r'; } ++data; } + return i; } /*================ Global functions ================*/ @@ -404,6 +408,13 @@ hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, xlate_to_user(buf, p, chars); } else { chars -= copy_to_user(buf, p, chars); + if (!chars) { + brelse(*bhe); + count = 0; + if (!read) + read = -EFAULT; + break; + } } brelse(*bhe); count -= chars; @@ -477,10 +488,13 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, } } p = (pos % HFS_SECTOR_SIZE) + bh->b_data; - if (convert) { - xlate_from_user(p, buf, c); - } else { - c -= copy_from_user(p, buf, c); + c -= convert ? xlate_from_user(p, buf, c) : + copy_from_user(p, buf, c); + if (!c) { + brelse(bh); + if (!written) + written = -EFAULT; + break; } update_vm_cache(inode,pos,p,c); pos += c; diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c index 4fbd1f0908ed..554624d25203 100644 --- a/fs/hfs/file_cap.c +++ b/fs/hfs/file_cap.c @@ -236,7 +236,7 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, end = pos + mem_count; cap_build_meta(&meta, entry); - copy_from_user(((char *)&meta) + pos, buf, mem_count); + mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count); /* Update finder attributes if changed */ if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) { diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c index b12a4606b3d5..13035e05632b 100644 --- a/fs/hfs/file_hdr.c +++ b/fs/hfs/file_hdr.c @@ -610,7 +610,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf, left = count; } - copy_from_user(((char *)&meta) + pos, buf, left); + left -= copy_from_user(((char *)&meta) + pos, buf, left); layout->magic = hfs_get_nl(meta.magic); layout->version = hfs_get_nl(meta.version); layout->entries = hfs_get_hs(meta.entries); @@ -642,7 +642,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf, left = count; } - copy_from_user(((char *)&meta) + pos, buf, left); + left -= copy_from_user(((char *)&meta) + pos, buf, left); init_layout(layout, meta.descrs); count -= left; @@ -782,7 +782,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf, /* transfer the data from user space */ if (p) { - copy_from_user(p + offset, buf, left); + left -= copy_from_user(p + offset, buf, left); } else if (fork) { left = hfs_do_write(inode, fork, offset, buf, left); } diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 45ad05022c7a..7f66e4ee617c 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c @@ -29,6 +29,8 @@ * the HFS equivalent of a superblock. * * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62 + * + * modified for HFS Extended */ struct raw_mdb { hfs_word_t drSigWord; /* Signature word indicating fs type */ @@ -60,9 +62,11 @@ struct raw_mdb { hfs_lword_t drFilCnt; /* number of files in the fs */ hfs_lword_t drDirCnt; /* number of directories in the fs */ hfs_byte_t drFndrInfo[32]; /* data used by the Finder */ - hfs_word_t drVCSize; /* MacOS caching parameter */ - hfs_word_t drVCBMSize; /* MacOS caching parameter */ - hfs_word_t drCtlCSize; /* MacOS caching parameter */ + hfs_word_t drEmbedSigWord; /* embedded volume signature */ + hfs_lword_t drEmbedExtent; /* starting block number (xdrStABN) + and number of allocation blocks + (xdrNumABlks) occupied by embedded + volume */ hfs_lword_t drXTFlSize; /* bytes in the extents B-tree */ hfs_byte_t drXTExtRec[12]; /* extents B-tree's first 3 extents */ hfs_lword_t drCTFlSize; /* bytes in the catalog B-tree */ diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index d59340f1095f..5891b493e997 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -201,8 +201,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) * Skip hidden or associated files unless unhide is set */ match = 0; - if( !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5) - || dir->i_sb->u.isofs_sb.s_unhide == 'y' ) + if ((!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5) + || dir->i_sb->u.isofs_sb.s_unhide == 'y') && dlen) { match = (isofs_cmp(dentry,dpnt,dlen) == 0); } diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 87c62e4c9cd3..d4b5c5bb0ebd 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -149,10 +149,10 @@ static int msdos_format_name(char conv,const char *name,int len, static int msdos_find(struct inode *dir,const char *name,int len, struct buffer_head **bh,struct msdos_dir_entry **de,int *ino) { - char msdos_name[MSDOS_NAME]; int res; char dotsOK; char scantype; + char msdos_name[MSDOS_NAME]; dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK; res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check, @@ -225,7 +225,9 @@ static struct dentry_operations msdos_dentry_operations = { NULL, /* d_revalidate */ msdos_hash, msdos_cmp, - NULL /* d_delete */ + NULL, /* d_delete */ + NULL, + NULL }; struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent) @@ -253,49 +255,45 @@ out_fail: int msdos_lookup(struct inode *dir,struct dentry *dentry) { struct super_block *sb = dir->i_sb; - int ino,res; + struct inode *inode = NULL; struct msdos_dir_entry *de; struct buffer_head *bh; - struct inode *inode; + int ino,res; PRINTK (("msdos_lookup\n")); dentry->d_op = &msdos_dentry_operations; - if(!dir) { /* N.B. This test is bogus -- should never happen */ - d_add(dentry, NULL); - return 0; - } - - if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,&bh,&de,&ino)) < 0) { - if(res == -ENOENT) { - d_add(dentry, NULL); - res = 0; - } - return res; - } - PRINTK (("msdos_lookup 4\n")); + res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh, + &de, &ino); + if (res == -ENOENT) + goto add; + if (res < 0) + goto out; if (bh) fat_brelse(sb, bh); - PRINTK (("msdos_lookup 4.5\n")); - if (!(inode = iget(dir->i_sb,ino))) - return -EACCES; - PRINTK (("msdos_lookup 5\n")); + + /* try to get the inode */ + res = -EACCES; + inode = iget(dir->i_sb, ino); + if (!inode) + goto out; if (!inode->i_sb || - (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { - /* crossed a mount point into a non-msdos fs */ - d_add(dentry, inode); - return 0; + (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { + printk(KERN_WARNING "msdos_lookup: foreign inode??\n"); } - if (MSDOS_I(inode)->i_busy) { /* mkdir in progress */ + /* mkdir in progress? */ + if (MSDOS_I(inode)->i_busy) { + printk(KERN_WARNING "msdos_lookup: %s/%s busy\n", + dentry->d_parent->d_name.name, dentry->d_name.name); iput(inode); - d_add(dentry, NULL); /* N.B. Do we really want a negative? */ - return 0; + goto out; } - PRINTK (("msdos_lookup 6\n")); + res = 0; +add: d_add(dentry, inode); - PRINTK (("msdos_lookup 7\n")); - return 0; +out: + return res; } @@ -308,9 +306,6 @@ static int msdos_create_entry(struct inode *dir, const char *name, struct msdos_dir_entry *de; int res,ino; - if(!dir) - return -ENOENT; - *result = NULL; if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) { if (res != -ENOENT) return res; @@ -350,14 +345,14 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode) struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode; - char msdos_name[MSDOS_NAME]; int ino,res,is_hid; + char msdos_name[MSDOS_NAME]; - if (!dir) return -ENOENT; - if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check, - dentry->d_name.name,dentry->d_name.len, - msdos_name,0, - MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) + res = msdos_format_name(MSDOS_SB(sb)->options.name_check, + dentry->d_name.name,dentry->d_name.len, + msdos_name,0, + MSDOS_SB(sb)->options.dotsOK); + if (res < 0) return res; is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); fat_lock_creation(); @@ -434,8 +429,8 @@ static int msdos_empty(struct inode *dir) /***** Remove a directory */ int msdos_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *inode = dentry->d_inode; struct super_block *sb = dir->i_sb; + struct inode *inode = dentry->d_inode; int res,ino; struct buffer_head *bh; struct msdos_dir_entry *de; @@ -493,13 +488,14 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode,*dot; - char msdos_name[MSDOS_NAME]; int ino,res,is_hid; + char msdos_name[MSDOS_NAME]; - if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check, - dentry->d_name.name,dentry->d_name.len, - msdos_name,0, - MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0) + res = msdos_format_name(MSDOS_SB(sb)->options.name_check, + dentry->d_name.name,dentry->d_name.len, + msdos_name,0, + MSDOS_SB(sb)->options.dotsOK); + if (res < 0) return res; is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); fat_lock_creation(); @@ -537,6 +533,7 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode) iput(dot); d_instantiate(dentry, inode); return 0; + mkdir_error: if (msdos_rmdir(dir,dentry) < 0) fat_fs_panic(dir->i_sb,"rmdir in mkdir failed"); @@ -546,10 +543,7 @@ out_unlock: } /***** Unlink a file */ -static int msdos_unlinkx( - struct inode *dir, - struct dentry *dentry, - int nospc) /* Flag special file ? */ +static int msdos_unlinkx( struct inode *dir, struct dentry *dentry, int nospc) { struct super_block *sb = dir->i_sb; struct inode *inode = dentry->d_inode; @@ -558,22 +552,25 @@ static int msdos_unlinkx( struct msdos_dir_entry *de; bh = NULL; - if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len, - &bh,&de,&ino)) < 0) + res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, + &bh, &de, &ino); + if (res < 0) goto unlink_done; res = -EPERM; if (!S_ISREG(inode->i_mode) && nospc) goto unlink_done; if (IS_IMMUTABLE(inode)) goto unlink_done; + /* N.B. check for busy files? */ + inode->i_nlink = 0; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; MSDOS_I(inode)->i_busy = 1; mark_inode_dirty(inode); mark_inode_dirty(dir); + d_delete(dentry); /* This also frees the inode */ de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh, 1); - d_delete(dentry); /* This also frees the inode */ res = 0; unlink_done: fat_brelse(sb, bh); @@ -592,28 +589,40 @@ int msdos_unlink_umsdos(struct inode *dir,struct dentry *dentry) return msdos_unlinkx (dir,dentry,0); } +#define MSDOS_CHECK_BUSY 1 + /***** Rename within a directory */ -static int rename_same_dir(struct inode *old_dir,char *old_name, +static int msdos_rename_same(struct inode *old_dir,char *old_name, struct dentry *old_dentry, struct inode *new_dir,char *new_name,struct dentry *new_dentry, struct buffer_head *old_bh, - struct msdos_dir_entry *old_de,int old_ino,int is_hid) + struct msdos_dir_entry *old_de, int old_ino, int is_hid) { struct super_block *sb = old_dir->i_sb; struct buffer_head *new_bh; struct msdos_dir_entry *new_de; struct inode *new_inode,*old_inode; - int new_ino,exists,error; + int new_ino, exists, error; + + if (!strncmp(old_name, new_name, MSDOS_NAME)) + goto set_hid; + error = -ENOENT; + if (*(unsigned char *) old_de->name == DELETED_FLAG) + goto out; - if (!strncmp(old_name,new_name,MSDOS_NAME)) goto set_hid; exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0; - if (*(unsigned char *) old_de->name == DELETED_FLAG) { - if (exists) - fat_brelse(sb, new_bh); - return -ENOENT; - } if (exists) { + error = -EIO; new_inode = new_dentry->d_inode; + /* Make sure it really exists ... */ + if (!new_inode) { + printk(KERN_ERR + "msdos_rename_same: %s/%s inode NULL, ino=%d\n", + new_dentry->d_parent->d_name.name, + new_dentry->d_name.name, new_ino); + d_drop(new_dentry); + goto out_error; + } error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ? msdos_empty(new_inode) @@ -621,11 +630,26 @@ static int rename_same_dir(struct inode *old_dir,char *old_name, : (old_de->attr & ATTR_DIR) ? -EPERM : 0; - if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM; - if (error) { - fat_brelse(sb, new_bh); - return error; + if (error) + goto out_error; + error = -EPERM; + if ((old_de->attr & ATTR_SYS)) + goto out_error; + +#ifdef MSDOS_CHECK_BUSY + /* check for a busy dentry */ + error = -EBUSY; + if (new_dentry->d_count > 1) { + shrink_dcache_parent(new_dentry); + if (new_dentry->d_count > 1) { +printk("msdos_rename_same: %s/%s busy, count=%d\n", +new_dentry->d_parent->d_name.name, new_dentry->d_name.name, +new_dentry->d_count); + goto out_error; + } } +#endif + if (S_ISDIR(new_inode->i_mode)) { new_dir->i_nlink--; mark_inode_dirty(new_dir); @@ -633,11 +657,16 @@ static int rename_same_dir(struct inode *old_dir,char *old_name, new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; mark_inode_dirty(new_inode); +#ifdef MSDOS_CHECK_BUSY + /* d_delete the dentry, as we killed its inode */ + d_delete(new_dentry); +#endif + new_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, new_bh, 1); fat_brelse(sb, new_bh); } - memcpy(old_de->name,new_name,MSDOS_NAME); + memcpy(old_de->name, new_name, MSDOS_NAME); /* Update the dcache */ d_move(old_dentry, new_dentry); set_hid: @@ -650,51 +679,63 @@ set_hid: MSDOS_I(old_inode)->i_attrs = is_hid ? (MSDOS_I(old_inode)->i_attrs | ATTR_HIDDEN) : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN); - return 0; + error = 0; +out: + return error; + +out_error: + fat_brelse(sb, new_bh); + goto out; } /***** Rename across directories - a nonphysical move */ -static int rename_diff_dir(struct inode *old_dir,char *old_name, +static int msdos_rename_diff(struct inode *old_dir, char *old_name, struct dentry *old_dentry, - struct inode *new_dir,char *new_name,struct dentry *new_dentry, + struct inode *new_dir,char *new_name, struct dentry *new_dentry, struct buffer_head *old_bh, - struct msdos_dir_entry *old_de,int old_ino,int is_hid) + struct msdos_dir_entry *old_de, int old_ino, int is_hid) { struct super_block *sb = old_dir->i_sb; struct buffer_head *new_bh,*free_bh,*dotdot_bh; struct msdos_dir_entry *new_de,*free_de,*dotdot_de; struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode; - struct dentry *walk; int new_ino,free_ino,dotdot_ino; - int error,exists; + int error, exists; - if (old_dir->i_dev != new_dir->i_dev) return -EINVAL; - if (old_ino == new_dir->i_ino) return -EINVAL; - walk = new_dentry; + error = -EINVAL; + if (old_ino == new_dir->i_ino) + goto out; /* prevent moving directory below itself */ - for (;;) { - if (walk == old_dentry) return -EINVAL; - if (walk == walk->d_parent) break; - walk = walk->d_parent; - } + if (is_subdir(new_dentry, old_dentry)) + goto out; + + error = -ENOENT; + if (*(unsigned char *) old_de->name == DELETED_FLAG) + goto out; + /* find free spot */ - while ((error = fat_scan(new_dir,NULL,&free_bh,&free_de,&free_ino, - SCAN_ANY)) < 0) { - if (error != -ENOENT) return error; + while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de, &free_ino, + SCAN_ANY)) < 0) { + if (error != -ENOENT) + goto out; error = fat_add_cluster(new_dir); - if (error) return error; + if (error) + goto out; } + exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0; - old_inode = old_dentry->d_inode; - if (*(unsigned char *) old_de->name == DELETED_FLAG) { - fat_brelse(sb, free_bh); - if (exists) - fat_brelse(sb, new_bh); - return -ENOENT; - } - new_inode = NULL; /* to make GCC happy */ if (exists) { /* Trash the old file! */ + error = -EIO; new_inode = new_dentry->d_inode; + /* Make sure it really exists ... */ + if (!new_inode) { + printk(KERN_ERR + "msdos_rename_diff: %s/%s inode NULL, ino=%d\n", + new_dentry->d_parent->d_name.name, + new_dentry->d_name.name, new_ino); + d_drop(new_dentry); + goto out_new; + } error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ? msdos_empty(new_inode) @@ -702,39 +743,87 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name, : (old_de->attr & ATTR_DIR) ? -EPERM : 0; - if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM; - if (error) { - fat_brelse(sb, new_bh); - return error; + if (error) + goto out_new; + error = -EPERM; + if ((old_de->attr & ATTR_SYS)) + goto out_new; + +#ifdef MSDOS_CHECK_BUSY + /* check for a busy dentry */ + error = -EBUSY; + if (new_dentry->d_count > 1) { + shrink_dcache_parent(new_dentry); + if (new_dentry->d_count > 1) { +printk("msdos_rename_diff: target %s/%s busy, count=%d\n", +new_dentry->d_parent->d_name.name, new_dentry->d_name.name, +new_dentry->d_count); + goto out_new; + } + } +#endif + if (S_ISDIR(new_inode->i_mode)) { + new_dir->i_nlink--; + mark_inode_dirty(new_dir); } new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; mark_inode_dirty(new_inode); +#ifdef MSDOS_CHECK_BUSY + /* d_delete the dentry, as we killed its inode */ + d_delete(new_dentry); +#endif new_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, new_bh, 1); + fat_brelse(sb, new_bh); } - memcpy(free_de,old_de,sizeof(struct msdos_dir_entry)); - memcpy(free_de->name,new_name,MSDOS_NAME); + + old_inode = old_dentry->d_inode; + /* Get the dotdot inode if we'll need it ... */ + dotdot_bh = NULL; + dotdot_inode = NULL; + if (S_ISDIR(old_inode->i_mode)) { + error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh, + &dotdot_de, &dotdot_ino, SCAN_ANY); + if (error < 0) + goto rename_done; + error = -EIO; + dotdot_inode = iget(sb, dotdot_ino); + if (!dotdot_inode) + goto out_dotdot; + } + + /* get an inode for the new name */ + memcpy(free_de, old_de, sizeof(struct msdos_dir_entry)); + memcpy(free_de->name, new_name, MSDOS_NAME); free_de->attr = is_hid ? (free_de->attr|ATTR_HIDDEN) : (free_de->attr&~ATTR_HIDDEN); - if (!(free_inode = iget(new_dir->i_sb,free_ino))) { - free_de->name[0] = DELETED_FLAG; - /* - * Don't mark free_bh as dirty. Both states - * are supposed to be equivalent. - */ - fat_brelse(sb, free_bh); - if (exists) - fat_brelse(sb, new_bh); - return -EIO; - } - if (exists && S_ISDIR(new_inode->i_mode)) { - new_dir->i_nlink--; - mark_inode_dirty(new_dir); - } + + error = -EIO; + free_inode = iget(sb, free_ino); + if (!free_inode) + goto out_iput; msdos_read_inode(free_inode); + /* + * Make sure the old dentry isn't busy, + * as we need to change inodes ... + */ + if (old_dentry->d_count > 1) { + shrink_dcache_parent(old_dentry); + if (old_dentry->d_count > 1) { +printk("msdos_rename_diff: source %s/%s busy, count=%d\n", +old_dentry->d_parent->d_name.name, old_dentry->d_name.name, +old_dentry->d_count); + goto out_iput; + } + } + + /* keep the inode for a bit ... */ + old_inode->i_count++; + d_delete(old_dentry); + free_inode->i_mode = old_inode->i_mode; free_inode->i_size = old_inode->i_size; free_inode->i_blocks = old_inode->i_blocks; @@ -747,29 +836,20 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name, MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart; MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs; - /* Detach d_alias from old inode and attach to new inode */ - list_del(&old_dentry->d_alias); + /* + * Install the new inode ... + */ d_instantiate(old_dentry, free_inode); - iput(old_inode); fat_cache_inval_inode(old_inode); mark_inode_dirty(old_inode); old_de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, old_bh, 1); fat_mark_buffer_dirty(sb, free_bh, 1); + iput(old_inode); - if (exists) { - /* free_inode is put after putting new_inode and old_inode */ - fat_brelse(sb, new_bh); - } - if (S_ISDIR(old_inode->i_mode)) { - if ((error = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, - &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done; - if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) { - fat_brelse(sb, dotdot_bh); - error = -EIO; - goto rename_done; - } + /* a directory? */ + if (dotdot_bh) { MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start; MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart; dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart); @@ -787,9 +867,26 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name, /* Update the dcache */ d_move(old_dentry, new_dentry); error = 0; + rename_done: fat_brelse(sb, free_bh); +out: return error; + +out_iput: + free_de->name[0] = DELETED_FLAG; + /* + * Don't mark free_bh as dirty. Both states + * are supposed to be equivalent. + */ + iput(free_inode); /* may be NULL */ + iput(dotdot_inode); +out_dotdot: + fat_brelse(sb, dotdot_bh); + goto rename_done; +out_new: + fat_brelse(sb, new_bh); + goto rename_done; } /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */ @@ -797,36 +894,45 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry, struct inode *new_dir,struct dentry *new_dentry) { struct super_block *sb = old_dir->i_sb; - char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME]; struct buffer_head *old_bh; struct msdos_dir_entry *old_de; - int old_ino,error; + int old_ino, error; int is_hid,old_hid; /* if new file and old file are hidden */ - - if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->options.name_check, - old_dentry->d_name.name, - old_dentry->d_name.len,old_msdos_name,1, - MSDOS_SB(old_dir->i_sb)->options.dotsOK)) - < 0) goto rename_done; - if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->options.name_check, - new_dentry->d_name.name, - new_dentry->d_name.len,new_msdos_name,0, - MSDOS_SB(new_dir->i_sb)->options.dotsOK)) - < 0) goto rename_done; - is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.'); + char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME]; + + error = -EINVAL; + if (sb != new_dir->i_sb) + goto rename_done; + error = msdos_format_name(MSDOS_SB(sb)->options.name_check, + old_dentry->d_name.name, old_dentry->d_name.len, + old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK); + if (error < 0) + goto rename_done; + error = msdos_format_name(MSDOS_SB(sb)->options.name_check, + new_dentry->d_name.name, new_dentry->d_name.len, + new_msdos_name, 0,MSDOS_SB(sb)->options.dotsOK); + if (error < 0) + goto rename_done; + + is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.'); old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.'); - if ((error = fat_scan(old_dir,old_msdos_name,&old_bh,&old_de, - &old_ino,old_hid?SCAN_HID:SCAN_NOTHID)) < 0) goto rename_done; + error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, + &old_ino, old_hid?SCAN_HID:SCAN_NOTHID); + if (error < 0) + goto rename_done; + fat_lock_creation(); if (old_dir == new_dir) - error = rename_same_dir(old_dir,old_msdos_name,old_dentry, - new_dir,new_msdos_name,new_dentry, - old_bh,old_de,old_ino,is_hid); - else error = rename_diff_dir(old_dir,old_msdos_name,old_dentry, - new_dir,new_msdos_name,new_dentry, - old_bh,old_de,old_ino,is_hid); + error = msdos_rename_same(old_dir, old_msdos_name, old_dentry, + new_dir, new_msdos_name, new_dentry, + old_bh, old_de, (ino_t)old_ino, is_hid); + else + error = msdos_rename_diff(old_dir, old_msdos_name, old_dentry, + new_dir, new_msdos_name, new_dentry, + old_bh, old_de, (ino_t)old_ino, is_hid); fat_unlock_creation(); fat_brelse(sb, old_bh); + rename_done: return error; } diff --git a/fs/proc/array.c b/fs/proc/array.c index 4b28aec2e6fb..f61e49e57266 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -844,7 +844,7 @@ static int get_stat(int pid, char * buffer) return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ -%lu %lu %lu %lu %lu %lu %lu %lu\n", +%lu %lu %lu %lu %lu %lu %lu %lu %d\n", pid, tsk->comm, state, @@ -885,7 +885,8 @@ static int get_stat(int pid, char * buffer) sigcatch .sig[0] & 0x7fffffffUL, wchan, tsk->nswap, - tsk->cnswap); + tsk->cnswap, + tsk->exit_signal); } static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, @@ -1224,6 +1225,11 @@ static long get_root_array(char * page, int type, char **start, case PROC_PCI: return get_pci_list(page); #endif + +#ifdef CONFIG_NUBUS + case PROC_NUBUS: + return get_nubus_list(page); +#endif case PROC_CPUINFO: return get_cpuinfo(page); diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c index 5fa82929ba0d..375ff6f75a7d 100644 --- a/fs/sysv/balloc.c +++ b/fs/sysv/balloc.c @@ -52,8 +52,8 @@ void sysv_free_block(struct super_block * sb, unsigned int block) * into this block being freed: */ if (*sb->sv_sb_flc_count == sb->sv_flc_size) { - unsigned short * flc_count; - unsigned long * flc_blocks; + u16 * flc_count; + u32 * flc_blocks; bh = sv_getblk(sb, sb->s_dev, block); if (!bh) { @@ -154,8 +154,8 @@ int sysv_new_block(struct super_block * sb) return 0; } if (*sb->sv_sb_flc_count == 0) { /* the last block continues the free list */ - unsigned short * flc_count; - unsigned long * flc_blocks; + u16 * flc_count; + u32 * flc_blocks; if (!(bh = sv_bread(sb, sb->s_dev, block))) { printk("sysv_new_block: cannot read free-list block\n"); @@ -247,8 +247,8 @@ unsigned long sysv_count_free_blocks(struct super_block * sb) } /* block = sb->sv_sb_flc_blocks[0], the last block continues the free list */ while (1) { - unsigned short * flc_count; - unsigned long * flc_blocks; + u16 * flc_count; + u32 * flc_blocks; if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { printk("sysv_count_free_blocks: new block %d is not in data zone\n",block); diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c index 96b0649a4b01..ddffd7de26ba 100644 --- a/fs/sysv/fsync.c +++ b/fs/sysv/fsync.c @@ -26,10 +26,10 @@ /* Sync one block. The block number is * from_coh_ulong(*blockp) if convert=1, *blockp if convert=0. */ -static int sync_block (struct inode * inode, unsigned long * blockp, int convert, int wait) +static int sync_block (struct inode * inode, u32 *blockp, int convert, int wait) { struct buffer_head * bh; - unsigned long tmp, block; + u32 tmp, block; struct super_block * sb; block = tmp = *blockp; @@ -59,11 +59,11 @@ static int sync_block (struct inode * inode, unsigned long * blockp, int convert } /* Sync one block full of indirect pointers and read it because we'll need it. */ -static int sync_iblock (struct inode * inode, unsigned long * iblockp, int convert, +static int sync_iblock (struct inode * inode, u32 * iblockp, int convert, struct buffer_head * *bh, int wait) { int rc; - unsigned long tmp, block; + u32 tmp, block; *bh = NULL; block = tmp = *iblockp; @@ -101,7 +101,7 @@ static int sync_direct(struct inode *inode, int wait) return err; } -static int sync_indirect(struct inode *inode, unsigned long *iblockp, int convert, int wait) +static int sync_indirect(struct inode *inode, u32 *iblockp, int convert, int wait) { int i; struct buffer_head * ind_bh; @@ -115,7 +115,7 @@ static int sync_indirect(struct inode *inode, unsigned long *iblockp, int conver sb = inode->i_sb; for (i = 0; i < sb->sv_ind_per_block; i++) { rc = sync_block (inode, - ((unsigned long *) ind_bh->b_data) + i, sb->sv_convert, + ((u32 *) ind_bh->b_data) + i, sb->sv_convert, wait); if (rc > 0) break; @@ -126,7 +126,7 @@ static int sync_indirect(struct inode *inode, unsigned long *iblockp, int conver return err; } -static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int convert, +static int sync_dindirect(struct inode *inode, u32 *diblockp, int convert, int wait) { int i; @@ -141,7 +141,7 @@ static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int conv sb = inode->i_sb; for (i = 0; i < sb->sv_ind_per_block; i++) { rc = sync_indirect (inode, - ((unsigned long *) dind_bh->b_data) + i, sb->sv_convert, + ((u32 *) dind_bh->b_data) + i, sb->sv_convert, wait); if (rc > 0) break; @@ -152,7 +152,7 @@ static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int conv return err; } -static int sync_tindirect(struct inode *inode, unsigned long *tiblockp, int convert, +static int sync_tindirect(struct inode *inode, u32 *tiblockp, int convert, int wait) { int i; @@ -167,7 +167,7 @@ static int sync_tindirect(struct inode *inode, unsigned long *tiblockp, int conv sb = inode->i_sb; for (i = 0; i < sb->sv_ind_per_block; i++) { rc = sync_dindirect (inode, - ((unsigned long *) tind_bh->b_data) + i, sb->sv_convert, + ((u32 *) tind_bh->b_data) + i, sb->sv_convert, wait); if (rc > 0) break; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 583b94c256b6..f2cf52087475 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -30,7 +30,7 @@ #include #include #include - +#include #include #if 0 @@ -532,7 +532,7 @@ void sysv_write_super (struct super_block *sb) void sysv_put_super(struct super_block *sb) { - /* we can assume sysv_write_super() has already been called, and + /* we can assume sysv_write_super() has already been called, and that the superblock is locked */ brelse(sb->sv_bh1); if (sb->sv_bh1 != sb->sv_bh2) brelse(sb->sv_bh2); @@ -648,8 +648,8 @@ int sysv_bmap(struct inode * inode,int block_nr) static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create) { struct super_block *sb; - unsigned long tmp; - unsigned long *p; + u32 tmp; + u32 *p; struct buffer_head * result; sb = inode->i_sb; @@ -684,7 +684,7 @@ static struct buffer_head * block_getblk(struct inode * inode, struct buffer_head * bh, int nr, int create) { struct super_block *sb; - unsigned long tmp, block; + u32 tmp, block; sysv_zone_t *p; struct buffer_head * result; @@ -782,26 +782,43 @@ struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create return NULL; } +#ifdef __BIG_ENDIAN + +static inline unsigned long read3byte (unsigned char * p) +{ + return (p[2] | (p[1]<<8) | (p[0]<<16)); +} + +static inline void write3byte (unsigned char *p , unsigned long val) +{ + p[2]=val&0xFF; + p[1]=(val>>8)&0xFF; + p[0]=(val>>16)&0xFF; +} + +#else -static inline unsigned long read3byte (char * p) +static inline unsigned long read3byte (unsigned char * p) { return (unsigned long)(*(unsigned short *)p) | (unsigned long)(*(unsigned char *)(p+2)) << 16; } -static inline void write3byte (char * p, unsigned long val) +static inline void write3byte (unsigned char * p, unsigned long val) { *(unsigned short *)p = (unsigned short) val; *(unsigned char *)(p+2) = val >> 16; } -static inline unsigned long coh_read3byte (char * p) +#endif + +static inline unsigned long coh_read3byte (unsigned char * p) { return (unsigned long)(*(unsigned char *)p) << 16 | (unsigned long)(*(unsigned short *)(p+1)); } -static inline void coh_write3byte (char * p, unsigned long val) +static inline void coh_write3byte (unsigned char * p, unsigned long val) { *(unsigned char *)p = val >> 16; *(unsigned short *)(p+1) = (unsigned short) val; diff --git a/fs/sysv/truncate.c b/fs/sysv/truncate.c index 7c919caff637..c318648a99bf 100644 --- a/fs/sysv/truncate.c +++ b/fs/sysv/truncate.c @@ -41,8 +41,8 @@ static int trunc_direct(struct inode * inode) { struct super_block * sb; unsigned int i; - unsigned long * p; - unsigned long block; + u32 * p; + u32 block; struct buffer_head * bh; int retry = 0; @@ -71,7 +71,7 @@ repeat: return retry; } -static int trunc_indirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) +static int trunc_indirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) { unsigned long indtmp, indblock; struct super_block * sb; @@ -140,14 +140,14 @@ done: return retry; } -static int trunc_dindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) +static int trunc_dindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) { - unsigned long indtmp, indblock; + u32 indtmp, indblock; struct super_block * sb; struct buffer_head * indbh; unsigned int i; sysv_zone_t * ind; - unsigned long tmp, block; + u32 tmp, block; int retry = 0; indblock = indtmp = *p; @@ -197,14 +197,14 @@ done: return retry; } -static int trunc_tindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) +static int trunc_tindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt) { - unsigned long indtmp, indblock; + u32 indtmp, indblock; struct super_block * sb; struct buffer_head * indbh; unsigned int i; sysv_zone_t * ind; - unsigned long tmp, block; + u32 tmp, block; int retry = 0; indblock = indtmp = *p; diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index 5a7bcd854066..11c8040821a5 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -22,7 +22,36 @@ #define UMSDOS_SPECIAL_DIRFPOS 3 extern struct inode *pseudo_root; +/* #define UMSDOS_DEBUG_VERBOSE 1 */ +/* + * Dentry operations routines + */ + +/* nothing for now ... */ +static int umsdos_dentry_validate(struct dentry *dentry) +{ + return 1; +} + +/* for now, drop everything to force lookups ... */ +static void umsdos_dentry_dput(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + if (inode) { + d_drop(dentry); + } +} + +static struct dentry_operations umsdos_dentry_operations = +{ + umsdos_dentry_validate, /* d_validate(struct dentry *) */ + NULL, /* d_hash */ + NULL, /* d_compare */ + umsdos_dentry_dput, /* d_delete(struct dentry *) */ + NULL, + NULL, +}; /* * This needs to have the parent dentry passed to it. @@ -109,9 +138,9 @@ static int umsdos_dir_once ( void *buf, * Return a negative value from linux/errno.h. * Return > 0 if success (the number of bytes written by filldir). * - * This function is used by the normal readdir VFS entry point and by - * some function who try to find out info on a file from a pure MSDOS - * inode. See umsdos_locate_ancestor() below. + * This function is used by the normal readdir VFS entry point, + * and in order to get the directory entry from a file's dentry. + * See umsdos_dentry_to_entry() below. */ static int umsdos_readdir_x (struct inode *dir, struct file *filp, @@ -175,8 +204,10 @@ Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n")); if (IS_ERR(demd)) goto out_end; ret = 0; - if (!demd->d_inode) + if (!demd->d_inode) { +printk("no EMD file??\n"); goto out_dput; + } /* set up our private filp ... */ fill_new_filp(&new_filp, demd); @@ -189,33 +220,56 @@ Printk (("f_pos %Ld i_size %ld\n", new_filp.f_pos, demd->d_inode->i_size)); ret = 0; while (new_filp.f_pos < demd->d_inode->i_size) { off_t cur_f_pos = new_filp.f_pos; - struct umsdos_info info; struct dentry *dret; + struct inode *inode; struct umsdos_dirent entry; + struct umsdos_info info; ret = -EIO; if (umsdos_emd_dir_readentry (&new_filp, &entry) != 0) break; - if (entry.name_len == 0) - goto remove_name; + continue; umsdos_parse (entry.name, entry.name_len, &info); info.f_pos = cur_f_pos; umsdos_manglename (&info); + /* + * Do a real lookup on the short name. + */ dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname, - info.fake.len); + info.fake.len, 1); ret = PTR_ERR(dret); if (IS_ERR(dret)) break; + /* + * If the file wasn't found, remove it from the EMD. + */ + if (!dret->d_inode) + goto remove_name; -Printk (("Looking for inode of %s/%s, flags=%x\n", -dret->d_parent->d_name.name, info.fake.fname, entry.flags)); +Printk (("Found %s/%s, ino=%ld, flags=%x\n", +dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino, +entry.flags)); + /* check whether to resolve a hard-link */ if ((entry.flags & UMSDOS_HLINK) && follow_hlink) { dret = umsdos_solve_hlink (dret); ret = PTR_ERR(dret); if (IS_ERR(dret)) break; +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_readdir_x: link is %s/%s, ino=%ld\n", +dret->d_parent->d_name.name, dret->d_name.name, +(dret->d_inode ? dret->d_inode->i_ino : 0)); +#endif + } + + /* save the inode ptr and number, then free the dentry */ + inode = dret->d_inode; + if (!inode) { +printk("umsdos_readdir_x: %s/%s negative after link\n", +dret->d_parent->d_name.name, dret->d_name.name); + goto clean_up; } /* #Specification: pseudo root / reading real root @@ -225,20 +279,21 @@ dret->d_parent->d_name.name, info.fake.fname, entry.flags)); * infinite recursion (/DOS/linux/DOS/linux/...) while * walking the file system. */ - if (dret->d_inode != pseudo_root && + if (inode != pseudo_root && (internal_read || !(entry.flags & UMSDOS_HIDDEN))) { - Printk ((KERN_DEBUG "filldir now\n")); if (filldir (dirbuf, entry.name, entry.name_len, - cur_f_pos, dret->d_inode->i_ino) < 0) { + cur_f_pos, inode->i_ino) < 0) { new_filp.f_pos = cur_f_pos; } -Printk (("Found %s/%s(%ld)\n", -dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino)); +Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n", +dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino)); if (u_entry != NULL) *u_entry = entry; dput(dret); + ret = 0; break; } + clean_up: dput(dret); continue; @@ -248,11 +303,17 @@ dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino)); * in the MS-DOS directory any more, the entry is * removed from the EMD file silently. */ - Printk (("'Silently' removing EMD for file\n")); - ret = umsdos_delentry(filp->f_dentry, &info, 1); +#ifdef UMSDOS_PARANOIA +printk("umsdos_readdir_x: %s/%s out of sync, erased\n", +filp->f_dentry->d_name.name, info.entry.name); +#endif + ret = umsdos_delentry(filp->f_dentry, &info, + S_ISDIR(info.entry.mode)); if (ret) - break; - continue; + printk(KERN_WARNING + "umsdos_readdir_x: delentry %s, err=%d\n", + info.entry.name, ret); + goto clean_up; } /* * If the fillbuf has failed, f_pos is back to 0. @@ -296,8 +357,6 @@ static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir) struct umsdos_dirent entry; bufk.count = 0; - PRINTK (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n", - dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once)); ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once); if (bufk.count == 0) @@ -509,8 +568,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name); err = umsdos_readdir_x (parent->d_inode, &filp, &bufk, 1, entry, 0, umsdos_filldir_k); if (err < 0) { - printk ("UMSDOS: can't locate inode %ld in EMD??\n", - inode->i_ino); + printk ("umsdos_dentry_to_entry: ino=%ld, err=%d\n", + inode->i_ino, err); break; } if (bufk.ino == inode->i_ino) { @@ -523,73 +582,6 @@ out: return ret; } -/* - * Deprecated. Try to get rid of this soon! - */ -int umsdos_inode2entry (struct inode *dir, struct inode *inode, - struct umsdos_dirent *entry) -{ - int ret = -ENOENT; - struct inode *emddir; - struct dentry *i2e; - struct file filp; - struct UMSDOS_DIR_SEARCH bufsrch; - struct UMSDOS_DIRENT_K bufk; - - if (pseudo_root && inode == pseudo_root) { - /* - * Quick way to find the name. - * Also umsdos_readdir_x won't show /linux anyway - */ - memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1); - entry->name_len = UMSDOS_PSDROOT_LEN; - ret = 0; - goto out; - } - - emddir = umsdos_emd_dir_lookup (dir, 0); - if (emddir == NULL) { - /* This is a DOS directory. */ - i2e = creat_dentry ("@i2e.nul@", 9, dir, NULL); - fill_new_filp (&filp, i2e); - filp.f_reada = 1; - filp.f_pos = 0; - bufsrch.entry = entry; - bufsrch.search_ino = inode->i_ino; - fat_readdir (&filp, &bufsrch, umsdos_dir_search); - if (bufsrch.found) { - ret = 0; - inode->u.umsdos_i.i_dir_owner = dir->i_ino; - inode->u.umsdos_i.i_emd_owner = 0; - umsdos_setup_dir_inode (inode); - } - goto out; - } - - /* skip . and .. see umsdos_readdir_x() */ - - i2e = creat_dentry ("@i2e.nn@", 8, dir, NULL); - fill_new_filp (&filp, i2e); - filp.f_reada = 1; - filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; - while (1) { - if (umsdos_readdir_x (dir, &filp, &bufk, 1, - entry, 0, umsdos_filldir_k) < 0) { - printk ("UMSDOS: can't locate inode %ld in EMD??\n", - inode->i_ino); - break; - } - if (bufk.ino == inode->i_ino) { - ret = 0; - umsdos_lookup_patch (dir, inode, entry, bufk.f_pos); - break; - } - } - iput (emddir); -out: - return ret; -} - /* * Return != 0 if an entry is the pseudo DOS entry in the pseudo root. @@ -638,6 +630,11 @@ int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) int ret = -ENOENT; struct umsdos_info info; +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_lookup_x: looking for %s/%s\n", +dentry->d_parent->d_name.name, dentry->d_name.name); +#endif + umsdos_startlookup (dir); /* this shouldn't happen ... */ if (len == 1 && name[0] == '.') { @@ -664,38 +661,53 @@ int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) } ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - if (ret) + if (ret) { +printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, ret); goto out; + } + ret = umsdos_findentry (dentry->d_parent, &info, 0); + if (ret) { +if (ret != -ENOENT) +printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, ret); + goto out; + } Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len)); - if (ret) - goto out; - + /* do a real lookup to get the short name ... */ dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len); + info.fake.len, 1); ret = PTR_ERR(dret); if (IS_ERR(dret)) goto out; if (!dret->d_inode) goto out_remove; - umsdos_lookup_patch_new(dret, &info.entry, info.f_pos); +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_lookup_x: found %s/%s, ino=%ld\n", +dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino); +#endif /* Check for a hard link */ if (info.entry.flags & UMSDOS_HLINK) { -Printk (("checking hard link %s/%s, ino=%ld, flags=%x\n", -dret->d_parent->d_name.name, dret->d_name.name, -dret->d_inode->i_ino, info.entry.flags)); dret = umsdos_solve_hlink (dret); ret = PTR_ERR(dret); if (IS_ERR(dret)) goto out; } - /* N.B. can dentry be negative after resolving hlinks? */ - if (pseudo_root && dret->d_inode == pseudo_root && !nopseudo) { + ret = -ENOENT; + inode = dret->d_inode; + if (!inode) { +printk("umsdos_lookup_x: %s/%s negative after link\n", +dret->d_parent->d_name.name, dret->d_name.name); + goto out_dput; + } + + if (inode == pseudo_root && !nopseudo) { /* #Specification: pseudo root / dir lookup * For the same reason as readdir, a lookup in /DOS for * the pseudo root directory (linux) will fail. @@ -705,23 +717,22 @@ dret->d_inode->i_ino, info.entry.flags)); * which are recorded independently of the pseudo-root * mode. */ - Printk (("umsdos_lookup_x: untested Pseudo_root\n")); - ret = -ENOENT; +printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n"); goto out_dput; - } else { - /* We've found it OK. Now put inode in dentry. */ - inode = dret->d_inode; } /* - * Hash the dentry with the inode. + * We've found it OK. Now hash the dentry with the inode. */ out_add: inode->i_count++; d_add (dentry, inode); + dentry->d_op = &umsdos_dentry_operations; ret = 0; out_dput: + if (dret != dentry) + d_drop(dret); dput(dret); out: umsdos_endlookup (dir); @@ -729,10 +740,10 @@ out: out_remove: printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n", - dentry->d_name.name, info.fake.fname); + dentry->d_parent->d_name.name, dentry->d_name.name); umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); ret = -ENOENT; - goto out; + goto out_dput; } @@ -756,6 +767,7 @@ int UMSDOS_lookup (struct inode *dir, struct dentry *dentry) Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative\n")); d_add (dentry, NULL); + dentry->d_op = &umsdos_dentry_operations; ret = 0; } return ret; @@ -768,7 +780,8 @@ int UMSDOS_lookup (struct inode *dir, struct dentry *dentry) * We need to use this instead of lookup_dentry, as the * directory semaphore lock is already held. */ -struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len) +struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len, + int real) { struct dentry *result, *dentry; int error; @@ -783,7 +796,9 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len) dentry = d_alloc(parent, &qstr); if (dentry) { result = dentry; - error = umsdos_real_lookup(parent->d_inode, result); + error = real ? + UMSDOS_rlookup(parent->d_inode, result) : + UMSDOS_lookup(parent->d_inode, result); if (error) goto out_fail; } @@ -797,6 +812,21 @@ out_fail: goto out; } +/* + * Return a path relative to our root. + */ +char * umsdos_d_path(struct dentry *dentry, char * buffer, int len) +{ + struct dentry * old_root = current->fs->root; + char * path; + + /* N.B. not safe -- fix this soon! */ + current->fs->root = dentry->d_sb->s_root; + path = d_path(dentry, buffer, len); + current->fs->root = old_root; + return path; +} + /* * gets dentry which points to pseudo-hardlink @@ -812,96 +842,99 @@ struct dentry *umsdos_solve_hlink (struct dentry *hlink) { /* root is our root for resolving pseudo-hardlink */ struct dentry *base = hlink->d_sb->s_root; - struct dentry *final, *dir, *dentry_dst; + struct dentry *dentry_dst; char *path, *pt; - unsigned long len; - int ret = -EIO; + int len; struct file filp; - check_dentry_path (hlink, "HLINK BEGIN hlink"); +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_solve_hlink: following %s/%s\n", +hlink->d_parent->d_name.name, hlink->d_name.name); +#endif - final = ERR_PTR (-ENOMEM); + dentry_dst = ERR_PTR (-ENOMEM); path = (char *) kmalloc (PATH_MAX, GFP_KERNEL); if (path == NULL) goto out; fill_new_filp (&filp, hlink); filp.f_flags = O_RDONLY; - filp.f_pos = 0; - Printk (("hlink2inode ")); len = umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size); if (len != hlink->d_inode->i_size) goto out_noread; +#ifdef UMSDOS_DEBUG_VERBOSE +printk ("umsdos_solve_hlink: %s/%s is path %s\n", +hlink->d_parent->d_name.name, hlink->d_name.name, path); +#endif /* start at root dentry */ - dir = dget(base); - path[hlink->d_inode->i_size] = '\0'; - pt = path; + dentry_dst = dget(base); + path[len] = '\0'; + pt = path + 1; /* skip leading '/' */ while (1) { + struct dentry *dir = dentry_dst, *demd; char *start = pt; - int len; + int real; while (*pt != '\0' && *pt != '/') pt++; len = (int) (pt - start); if (*pt == '/') *pt++ = '\0'; - dentry_dst = umsdos_lookup_dentry(dir, start, len); + real = (dir->d_inode->u.umsdos_i.i_emd_dir == 0); + /* + * Hack alert! inode->u.umsdos_i.i_emd_dir isn't reliable, + * so just check whether there's an EMD file ... + */ + real = 1; + demd = umsdos_get_emd_dentry(dir); + if (!IS_ERR(demd)) { + if (demd->d_inode) + real = 0; + dput(demd); + } + +#ifdef UMSDOS_DEBUG_VERBOSE +printk ("umsdos_solve_hlink: dir %s/%s, name=%s, emd_dir=%ld, real=%d\n", +dir->d_parent->d_name.name, dir->d_name.name, start, +dir->d_inode->u.umsdos_i.i_emd_dir, real); +#endif + dentry_dst = umsdos_lookup_dentry(dir, start, len, real); + if (real) + d_drop(dir); + dput (dir); if (IS_ERR(dentry_dst)) break; - if (dir->d_inode->u.umsdos_i.i_emd_dir == 0) { - /* This is a DOS directory */ - ret = umsdos_rlookup_x (dir->d_inode, dentry_dst, 1); - } else { - ret = umsdos_lookup_x (dir->d_inode, dentry_dst, 1); - } - Printk ((" returned %d\n", ret)); - dput (dir); /* dir no longer needed */ - dir = dentry_dst; - - Printk (("h2n lookup :%s: -> %d ", start, ret)); - final = ERR_PTR (ret); - if (ret != 0) { - /* path component not found! */ + /* not found? stop search ... */ + if (!dentry_dst->d_inode) { break; } - if (*pt == '\0') { /* we're finished! */ - final = umsdos_lookup_dentry(hlink->d_parent, - (char *) hlink->d_name.name, - hlink->d_name.len); + if (*pt == '\0') /* we're finished! */ break; - } } /* end while */ - /* - * See whether we found the path ... - */ - if (!IS_ERR(final)) { - if (!final->d_inode) { - d_instantiate(final, dir->d_inode); - /* we need inode to survive. */ - dir->d_inode->i_count++; - } else { - printk ("umsdos_solve_hlink: %s/%s already exists\n", - final->d_parent->d_name.name, - final->d_name.name); - } -printk ("umsdos_solve_hlink: ret = %d, %s/%s -> %s/%s\n", -ret, hlink->d_parent->d_name.name, hlink->d_name.name, -final->d_parent->d_name.name, final->d_name.name); - } - dput(dir); + + if (IS_ERR(dentry_dst)) + printk ("umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst)); +#ifdef UMSDOS_DEBUG_VERBOSE + else if (!dentry_dst->d_inode) + printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n", + dentry_dst->d_parent->d_name.name, + dentry_dst->d_name.name); + else + printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n", + dentry_dst->d_parent->d_name.name, + dentry_dst->d_name.name, dentry_dst->d_inode->i_ino); +#endif out_free: kfree (path); out: dput(hlink); /* original hlink no longer needed */ - check_dentry_path (hlink, "HLINK FIN hlink"); - check_dentry_path (final, "HLINK RET final"); - return final; + return dentry_dst; out_noread: - printk("umsdos_solve_hlink: failed reading pseudolink!\n"); + printk(KERN_WARNING "umsdos_solve_hlink: failed reading pseudolink!\n"); goto out_free; } @@ -943,5 +976,4 @@ struct inode_operations umsdos_dir_inode_operations = NULL, /* smap */ NULL, /* updatepage */ NULL, /* revalidate */ - }; diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 2f56b040445c..21c20360693d 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -30,46 +30,12 @@ ssize_t umsdos_file_read_kmem ( struct file *filp, char *buf, size_t count) { - int ret; - + ssize_t ret; mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); - - PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d\n", filp, buf, count)); - PRINTK ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); - PRINTK ((KERN_DEBUG " f_pos=%Lu\n", filp->f_pos)); - PRINTK ((KERN_DEBUG " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); - PRINTK ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary)); - PRINTK ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); - PRINTK ((KERN_DEBUG " f_owner=%d\n", filp->f_owner.uid)); - PRINTK ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); - PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); - MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2; - ret = fat_file_read (filp, buf, count, &filp->f_pos); - PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret)); - - PRINTK ((KERN_DEBUG " (ret) inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); - PRINTK ((KERN_DEBUG " (ret) f_pos=%Lu\n", filp->f_pos)); - PRINTK ((KERN_DEBUG " (ret) name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); - PRINTK ((KERN_DEBUG " (ret) i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary)); - PRINTK ((KERN_DEBUG " (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); - PRINTK ((KERN_DEBUG " (ret) f_owner=%d\n", filp->f_owner.uid)); - PRINTK ((KERN_DEBUG " (ret) f_version=%ld\n", filp->f_version)); - PRINTK ((KERN_DEBUG " (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); - -#if 0 - { - struct umsdos_dirent *mydirent = buf; - - Printk ((KERN_DEBUG " (DDD) uid=%d\n", mydirent->uid)); - Printk ((KERN_DEBUG " (DDD) gid=%d\n", mydirent->gid)); - Printk ((KERN_DEBUG " (DDD) name=>%.20s<\n", mydirent->name)); - } -#endif - set_fs (old_fs); return ret; } @@ -90,28 +56,22 @@ ssize_t umsdos_file_write_kmem_real (struct file * filp, set_fs (KERNEL_DS); - PRINTK ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d\n", filp, buf, count)); - PRINTK ((KERN_DEBUG " struct dentry=%p\n", filp->f_dentry)); - PRINTK ((KERN_DEBUG " struct inode=%p\n", filp->f_dentry->d_inode)); - PRINTK ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); - PRINTK ((KERN_DEBUG " f_pos=%Lu\n", filp->f_pos)); - PRINTK ((KERN_DEBUG " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); - PRINTK ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary)); - PRINTK ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); - PRINTK ((KERN_DEBUG " f_owner=%d\n", filp->f_owner.uid)); - PRINTK ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); - PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); - /* note: i_binary=2 is for CVF-FAT. We put it here, instead of - * umsdos_file_write_kmem, since it is also wise not to compress symlinks - * (in the unlikely event that they are > 512 bytes and can be compressed - * FIXME: should we set it when reading symlinks too? */ + * umsdos_file_write_kmem, since it is also wise not to compress + * symlinks (in the unlikely event that they are > 512 bytes and + * can be compressed. + * FIXME: should we set it when reading symlinks too? + */ MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2; ret = fat_file_write (filp, buf, count, &filp->f_pos); - Printk ((KERN_DEBUG "fat_file_write returned with %ld!\n", (long int) ret)); - +#ifdef UMSDOS_PARANOIA + if (ret != count) { + printk(KERN_WARNING "umsdos_file_write: count=%u, ret=%u\n", + count, ret); + } +#endif set_fs (old_fs); return ret; } @@ -125,9 +85,8 @@ ssize_t umsdos_file_write_kmem (struct file *filp, const char *buf, size_t count) { - int ret; + ssize_t ret; - Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n")); ret = umsdos_file_write_kmem_real (filp, buf, count); return ret; } @@ -166,7 +125,6 @@ ssize_t umsdos_emd_dir_write ( struct file *filp, Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n", filp, buf, count, filp->f_pos)); written = umsdos_file_write_kmem (filp, buf, count); - Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n")); #ifdef __BIG_ENDIAN d->nlink = le16_to_cpu (d->nlink); @@ -179,13 +137,13 @@ filp, buf, count, filp->f_pos)); d->mode = le16_to_cpu (d->mode); #endif -#if UMS_DEBUG +#ifdef UMSDOS_PARANOIA if (written != count) printk(KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count); #endif - return written != count ? -EIO : 0; + return (written != count) ? -EIO : 0; } @@ -199,9 +157,7 @@ written, count); ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count) { - long int ret = 0; - int sizeread; - + ssize_t sizeread, ret = 0; #ifdef __BIG_ENDIAN struct umsdos_dirent *d = (struct umsdos_dirent *) buf; @@ -211,8 +167,9 @@ ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count) filp->f_flags = 0; sizeread = umsdos_file_read_kmem (filp, buf, count); if (sizeread != count) { -printk ("UMSDOS: problem with EMD file: can't read pos = %Ld (%d != %d)\n", -filp->f_pos, sizeread, count); + printk (KERN_WARNING + "UMSDOS: EMD problem, pos=%Ld, count=%d, read=%d\n", + filp->f_pos, count, sizeread); ret = -EIO; } #ifdef __BIG_ENDIAN @@ -226,7 +183,6 @@ filp->f_pos, sizeread, count); d->mode = le16_to_cpu (d->mode); #endif return ret; - } @@ -237,8 +193,8 @@ struct dentry *umsdos_get_emd_dentry(struct dentry *parent) { struct dentry *demd; - demd = umsdos_lookup_dentry (parent, UMSDOS_EMD_FILE, - UMSDOS_EMD_NAMELEN); + demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE, + UMSDOS_EMD_NAMELEN, 1); return demd; } @@ -260,7 +216,7 @@ int umsdos_have_emd(struct dentry *dir) /* * Create the EMD file for a directory if it doesn't - * already exist. Returns 0 or and error code. + * already exist. Returns 0 or an error code. */ int umsdos_make_emd(struct dentry *parent) { @@ -272,22 +228,23 @@ int umsdos_make_emd(struct dentry *parent) goto out; /* already created? */ + err = 0; inode = demd->d_inode; - if (inode) { - parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino; - err = 0; - goto out_dput; - } + if (inode) + goto out_set; -printk("umsdos_make_emd: creating %s/%s\n", -parent->d_name.name, demd->d_name.name); +Printk(("umsdos_make_emd: creating %s/%s\n", +parent->d_name.name, demd->d_name.name)); err = msdos_create(parent->d_inode, demd, S_IFREG | 0777); if (err) { - printk (KERN_WARNING "UMSDOS: Can't create EMD file\n"); + printk (KERN_WARNING + "UMSDOS: Can't create EMD file %s/%s\n", + parent->d_name.name, demd->d_name.name); goto out_dput; } inode = demd->d_inode; +out_set: parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino; /* Disable UMSDOS_notify_change() for EMD file */ inode->u.umsdos_i.i_emd_owner = 0xffffffff; @@ -338,7 +295,7 @@ printk("UMSDOS: flaky i_dentry hack failed\n"); dlook = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, d_dir); if (!dlook) goto out; - rv = umsdos_real_lookup (dir, dlook); + rv = msdos_lookup (dir, dlook); PRINTK ((KERN_DEBUG "-returned %d\n", rv)); Printk ((KERN_INFO "emd_dir_lookup ")); @@ -450,7 +407,7 @@ parent->d_parent->d_name.name, parent->d_name.name); if (free_entry) { /* #Specification: EMD file / empty entries - * Unused entry in the EMD file are identified + * Unused entries in the EMD file are identified * by the name_len field equal to 0. However to * help future extension (or bug correction :-( ), * empty entries are filled with 0. @@ -662,6 +619,8 @@ demd->d_parent->d_name.name, demd->d_name.name, emd_dir)); } } } +Printk(("umsdos_find: ready to mangle %s, len=%d, pos=%ld\n", +entry->name, entry->name_len, (long)info->f_pos)); umsdos_manglename (info); out_dput: diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c index 5277c95481b0..339d828011f2 100644 --- a/fs/umsdos/file.c +++ b/fs/umsdos/file.c @@ -32,15 +32,12 @@ static ssize_t UMSDOS_file_read ( struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - /* We have to set the access time because msdos don't care */ - /* FIXME */ int ret = fat_file_read (filp, buf, count, ppos); + /* We have to set the access time because msdos don't care */ if (!IS_RDONLY (inode)) { inode->i_atime = CURRENT_TIME; - /* FIXME - * inode->i_dirt = 1; - */ + mark_inode_dirty(inode); } return ret; } @@ -65,10 +62,11 @@ static ssize_t UMSDOS_file_write ( static void UMSDOS_truncate (struct inode *inode) { Printk (("UMSDOS_truncate\n")); - fat_truncate (inode); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - - /*FIXME inode->i_dirt = 1; */ + if (!IS_RDONLY (inode)) { + fat_truncate (inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); + } } /* Function for normal file system (512 bytes hardware sector size) */ diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index ca20bb8c30d0..c15a243695f5 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -19,6 +19,7 @@ #include #include +extern struct dentry_operations umsdos_dentry_operations; extern struct inode_operations umsdos_rdir_inode_operations; @@ -59,7 +60,7 @@ struct dentry *geti_dentry (struct inode *inode) void fill_new_filp (struct file *filp, struct dentry *dentry) { if (!dentry) - printk("fill_new_filp: NULL dentry!\n"); + printk(KERN_ERR "fill_new_filp: NULL dentry!\n"); memset (filp, 0, sizeof (struct file)); filp->f_reada = 1; @@ -133,7 +134,7 @@ void UMSDOS_put_inode (struct inode *inode) ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos ,inode->u.umsdos_i.i_emd_dir, inode->i_count)); - if (inode && pseudo_root && inode == pseudo_root) { + if (inode == pseudo_root) { printk (KERN_ERR "Umsdos: Oops releasing pseudo_root." " Notify jacques@solucorp.qc.ca\n"); } @@ -150,23 +151,6 @@ void UMSDOS_put_super (struct super_block *sb) } -/* - * Call msdos_lookup, but set back the original msdos function table. - * Return 0 if OK, or a negative error code if not. - * Dentry will hold inode of the file, if successful - */ -int umsdos_real_lookup (struct inode *dir, struct dentry *dentry) -{ - int ret; - - PRINTK ((KERN_DEBUG "umsdos_real_lookup: looking for %s/%s /", - dentry->d_parent->d_name.name, dentry->d_name.name)); - ret = msdos_lookup (dir, dentry); - PRINTK (("/ returned %d\n", ret)); - - return ret; -} - /* * Complete the setup of an directory dentry. * First, it completes the function pointers, then @@ -230,6 +214,34 @@ void umsdos_setup_dir_inode (struct inode *inode) /* * Add some info into an inode so it can find its owner quickly */ +void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos) +{ + struct inode *inode = dentry->d_inode; + struct inode *dir = dentry->d_parent->d_inode; + struct dentry *demd; + + inode->u.umsdos_i.i_dir_owner = dir->i_ino; + inode->u.umsdos_i.i_emd_owner = 0; + inode->u.umsdos_i.pos = f_pos; + + /* now check the EMD file */ + demd = umsdos_get_emd_dentry(dentry->d_parent); + if (IS_ERR(demd)) { + goto out; + } + if (demd->d_inode) { + inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino; + } + dput (demd); +out: + return; +} + + +/* + * Add some info into an inode so it can find its owner quickly + * Note: Deprecated; use above function if possible. + */ void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, off_t f_pos) { struct inode *emd_owner = umsdos_emd_dir_lookup (dir, 1); @@ -405,15 +417,14 @@ void UMSDOS_read_inode (struct inode *inode) } -/* #Specification: notify_change / i_nlink > 0 - * notify change is only done for inode with nlink > 0. An inode - * with nlink == 0 is no longer associated with any entry in - * the EMD file, so there is nothing to update. - */ -static int internal_notify_change (struct inode *inode, struct iattr *attr) +int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) { + struct inode *inode = dentry->d_inode; unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner; + struct dentry *demd; int ret; + struct file filp; + struct umsdos_dirent entry; Printk ((KERN_DEBUG "UMSDOS_notify_change: entering\n")); @@ -425,62 +436,61 @@ static int internal_notify_change (struct inode *inode, struct iattr *attr) if (inode->i_ino == UMSDOS_ROOT_INO) goto out_nolink; + if (i_emd_owner != 0) + goto out_nolink; - if (i_emd_owner != 0xffffffff && i_emd_owner != 0) { - /* This inode is not a EMD file nor an inode used internally - * by MSDOS, so we can update its status. - * See emd.c - */ - struct inode *emd_owner; - struct file filp; - struct umsdos_dirent entry; - struct dentry *emd_dentry; - - Printk (("notify change %p ", inode)); - ret = -EPERM; - emd_owner = iget (inode->i_sb, i_emd_owner); - if (!emd_owner) { - printk ("UMSDOS: emd_owner = NULL ???"); - goto out_nolink; - } - emd_dentry = geti_dentry (emd_owner); /* FIXME? */ - fill_new_filp (&filp, emd_dentry); + /* get the EMD file dentry */ + demd = umsdos_get_emd_dentry(dentry->d_parent); + ret = PTR_ERR(demd); + if (IS_ERR(demd)) + goto out_nolink; + ret = -EPERM; + if (!demd->d_inode) + goto out_dput; + + ret = 0; + if (inode == demd->d_inode) + goto out_dput; + /* This inode is not a EMD file nor an inode used internally + * by MSDOS, so we can update its status. + * See emd.c + */ + Printk (("notify change %p ", inode)); + fill_new_filp (&filp, demd); + filp.f_pos = inode->u.umsdos_i.pos; + + Printk (("pos = %Lu ", filp.f_pos)); + /* Read only the start of the entry since we don't touch the name */ + ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE); + if (!ret) { + if (attr->ia_valid & ATTR_UID) + entry.uid = attr->ia_uid; + if (attr->ia_valid & ATTR_GID) + entry.gid = attr->ia_gid; + if (attr->ia_valid & ATTR_MODE) + entry.mode = attr->ia_mode; + if (attr->ia_valid & ATTR_ATIME) + entry.atime = attr->ia_atime; + if (attr->ia_valid & ATTR_MTIME) + entry.mtime = attr->ia_mtime; + if (attr->ia_valid & ATTR_CTIME) + entry.ctime = attr->ia_ctime; + + entry.nlink = inode->i_nlink; filp.f_pos = inode->u.umsdos_i.pos; - filp.f_reada = 0; - Printk (("pos = %Lu ", filp.f_pos)); - /* Read only the start of the entry since we don't touch */ - /* the name */ - ret = umsdos_emd_dir_read (&filp, (char *) &entry, - UMSDOS_REC_SIZE); - if (!ret) { - if (attr->ia_valid & ATTR_UID) - entry.uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - entry.gid = attr->ia_gid; - if (attr->ia_valid & ATTR_MODE) - entry.mode = attr->ia_mode; - if (attr->ia_valid & ATTR_ATIME) - entry.atime = attr->ia_atime; - if (attr->ia_valid & ATTR_MTIME) - entry.mtime = attr->ia_mtime; - if (attr->ia_valid & ATTR_CTIME) - entry.ctime = attr->ia_ctime; - - entry.nlink = inode->i_nlink; - filp.f_pos = inode->u.umsdos_i.pos; - ret = umsdos_emd_dir_write (&filp, (char *) &entry, - UMSDOS_REC_SIZE); - - Printk (("notify pos %lu ret %d nlink %d ", - inode->u.umsdos_i.pos, ret, entry.nlink)); - /* #Specification: notify_change / msdos fs - * notify_change operation are done only on the - * EMD file. The msdos fs is not even called. - */ - } - iput(emd_owner); + ret = umsdos_emd_dir_write (&filp, (char *) &entry, + UMSDOS_REC_SIZE); + + Printk (("notify pos %lu ret %d nlink %d ", + inode->u.umsdos_i.pos, ret, entry.nlink)); + /* #Specification: notify_change / msdos fs + * notify_change operation are done only on the + * EMD file. The msdos fs is not even called. + */ } +out_dput: + dput(demd); out_nolink: if (ret == 0) inode_setattr (inode, attr); @@ -489,11 +499,6 @@ out: } -int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr) -{ - return internal_notify_change (dentry->d_inode, attr); -} - /* * Update the disk with the inode content */ @@ -558,9 +563,8 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data, sb->s_op = &umsdos_sops; MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */ - /* FIXME:?? clear d_op on root so it will not be inherited */ - sb->s_root->d_op = NULL; - + /* install our dentry operations ... */ + sb->s_root->d_op = &umsdos_dentry_operations; pseudo = sb->s_root->d_inode; umsdos_setup_dir(sb->s_root); @@ -599,7 +603,7 @@ void pseudo_root_stuff(void) sbin = creat_dentry ("sbin", 4, NULL, root); Printk ((KERN_DEBUG "Mounting root\n")); - if (umsdos_real_lookup (pseudo, root) == 0 + if (msdos_lookup (pseudo, root) == 0 && (root->d_inode != NULL) && S_ISDIR (root->d_inode->i_mode)) { @@ -609,7 +613,7 @@ Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME)); etc = creat_dentry ("etc", 3, NULL, root); - if (umsdos_real_lookup (pseudo, etc) == 0 + if (msdos_lookup (pseudo, etc) == 0 && S_ISDIR (etc->d_inode->i_mode)) { Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME)); @@ -617,9 +621,9 @@ Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME)); init = creat_dentry ("init", 4, NULL, etc); etc_rc = creat_dentry ("rc", 2, NULL, etc); - if ((umsdos_real_lookup (pseudo, init) == 0 + if ((msdos_lookup (pseudo, init) == 0 && S_ISREG (init->d_inode->i_mode)) - || (umsdos_real_lookup (pseudo, etc_rc) == 0 + || (msdos_lookup (pseudo, etc_rc) == 0 && S_ISREG (etc_rc->d_inode->i_mode))) { pseudo_ok = 1; } @@ -629,12 +633,12 @@ Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME)); /* iput(rc); */ } if (!pseudo_ok - /* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0 */ - && umsdos_real_lookup (pseudo, sbin) == 0 + /* && msdos_lookup (pseudo, "sbin", 4, sbin)==0 */ + && msdos_lookup (pseudo, sbin) == 0 && S_ISDIR (sbin->d_inode->i_mode)) { Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME)); - if (umsdos_real_lookup (pseudo, init) == 0 + if (msdos_lookup (pseudo, init) == 0 && S_ISREG (init->d_inode->i_mode)) { pseudo_ok = 1; } diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c index 84e1f503424e..22f8f0645b9b 100644 --- a/fs/umsdos/ioctl.c +++ b/fs/umsdos/ioctl.c @@ -262,13 +262,13 @@ int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd, */ old_dentry = umsdos_lookup_dentry (dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen); + data.dos_dirent.d_reclen ,1); ret = PTR_ERR(old_dentry); if (IS_ERR(old_dentry)) goto out; new_dentry = umsdos_lookup_dentry (dentry, data.umsdos_dirent.name, - data.umsdos_dirent.name_len); + data.umsdos_dirent.name_len, 1); ret = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { printk("umsdos_ioctl: renaming %s/%s to %s/%s\n", @@ -314,7 +314,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); * Return 0 if success. */ temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen); + data.dos_dirent.d_reclen, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out; @@ -336,7 +336,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); * Return 0 if success. */ temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen); + data.dos_dirent.d_reclen, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out; @@ -362,7 +362,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name); struct inode *inode; dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name, - data.dos_dirent.d_reclen); + data.dos_dirent.d_reclen, 1); ret = PTR_ERR(dret); if (IS_ERR(dret)) goto out; diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index b365fbf04600..2ec793db79b6 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -224,8 +224,8 @@ static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry, * * Return the status of the operation. 0 mean success. * - * #Specification: create / file exist in DOS - * Here is a situation. Trying to create a file with + * #Specification: create / file exists in DOS + * Here is a situation: we are trying to create a file with * UMSDOS. The file is unknown to UMSDOS but already * exists in the DOS directory. * @@ -254,19 +254,9 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry, int ret; struct umsdos_info info; -if (dentry->d_inode) -printk("umsdos_create_any: %s/%s not negative!\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - -Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", -(int) dentry->d_name.len, dentry->d_name.name, dir->i_ino)); - - check_dentry_path (dentry, "umsdos_create_any"); ret = umsdos_nevercreat (dir, dentry, -EEXIST); - if (ret) { -Printk (("%d/\n", ret)); + if (ret) goto out; - } ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); if (ret) @@ -286,7 +276,7 @@ Printk (("%d/\n", ret)); /* create short name dentry */ fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len); + info.fake.len, 1); ret = PTR_ERR(fake); if (IS_ERR(fake)) goto out_unlock; @@ -300,39 +290,26 @@ Printk (("%d/\n", ret)); if (ret) goto out_remove; - inode = fake->d_inode; - umsdos_lookup_patch_new(fake, &info.entry, info.f_pos); - -Printk (("inode %p[%lu], count=%d ", inode, inode->i_ino, inode->i_count)); -Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", -dir->i_ino, info.fake.len, info.fake.fname, current->pid, info.f_pos)); - - check_dentry_path (dentry, "umsdos_create_any: BEG dentry"); - check_dentry_path (fake, "umsdos_create_any: BEG fake"); - /* * Note! The long and short name might be the same, * so check first before doing the instantiate ... */ if (dentry != fake) { + inode = fake->d_inode; /* long name also gets inode info */ inode->i_count++; d_instantiate (dentry, inode); } - - check_dentry_path (dentry, "umsdos_create_any: END dentry"); - check_dentry_path (fake, "umsdos_create_any: END fake"); + umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos); goto out_dput; out_remove: -if (ret == -EEXIST) -printk("UMSDOS: out of sync, error [%ld], deleting %.*s %d %d pos %ld\n", -dir->i_ino ,info.fake.len, info.fake.fname, -ret, current->pid, info.f_pos); - umsdos_delentry (dentry->d_parent, &info, 0); + if (ret == -EEXIST) + printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n", + dentry->d_parent->d_name.name, info.fake.fname); + umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode)); out_dput: -Printk (("umsdos_create %.*s ret = %d pos %ld\n", -info.fake.len, info.fake.fname, ret, info.f_pos)); /* N.B. any value in keeping short name dentries? */ if (dentry != fake) d_drop(fake); @@ -382,27 +359,21 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, int flags) { - int old_ret, new_ret; - struct dentry *old, *new, *dret; - struct inode *oldid = NULL; - int ret = -EPERM; + struct dentry *old, *new, *new_target = NULL; + int err, ret = -EPERM; struct umsdos_info old_info; struct umsdos_info new_info; - old_ret = umsdos_parse (old_dentry->d_name.name, + err = umsdos_parse (old_dentry->d_name.name, old_dentry->d_name.len, &old_info); - if (old_ret) + if (err) goto out; - new_ret = umsdos_parse (new_dentry->d_name.name, + err = umsdos_parse (new_dentry->d_name.name, new_dentry->d_name.len, &new_info); - if (new_ret) + if (err) goto out; - check_dentry_path (old_dentry, "umsdos_rename_f OLD"); - check_dentry_path (new_dentry, "umsdos_rename_f OLD"); - chkstk (); -Printk (("umsdos_rename %d %d ", old_ret, new_ret)); umsdos_lockcreate2 (old_dir, new_dir); chkstk (); @@ -415,16 +386,16 @@ Printk (("ret %d ", ret)); /* check sticky bit on old_dir */ ret = -EPERM; - if (is_sticky(old_dir, old_info.entry.uid)) { - Printk (("sticky set on old ")); + if (is_sticky(old_dir, old_info.entry.uid)) goto out_unlock; - } - /* Does new_name already exist? */ - new_ret = umsdos_findentry(new_dentry->d_parent, &new_info, 0); - /* if destination file exists, are we allowed to replace it ? */ - if (new_ret == 0 && is_sticky(new_dir, new_info.entry.uid)) { - Printk (("sticky set on new ")); + /* + * Check whether the new_name already exists, and + * if so whether we're allowed to replace it. + */ + err = umsdos_findentry(new_dentry->d_parent, &new_info, 0); + if (err == 0 && is_sticky(new_dir, new_info.entry.uid)) { +Printk (("sticky set on new ")); goto out_unlock; } @@ -433,37 +404,50 @@ Printk (("ret %d ", ret)); ret = umsdos_newentry (new_dentry->d_parent, &new_info); chkstk (); if (ret) { -Printk (("ret %d %d ", ret, new_info.fake.len)); + printk("umsdos_rename_f: new name failed, ret=%d\n", ret); goto out_unlock; } - dret = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname, - old_info.fake.len); - ret = PTR_ERR(dret); - if (IS_ERR(dret)) + old = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname, + old_info.fake.len, 1); + ret = PTR_ERR(old); + if (IS_ERR(old)) goto out_unlock; -#if 0 - /* This is the same as dret */ - oldid = dret->d_inode; - old = creat_dentry (old_info.fake.fname, old_info.fake.len, - oldid, old_dentry->d_parent); -#endif - old = dret; + /* short and long name dentries match? */ + if (old == old_dentry) + dput(old); + new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname, - new_info.fake.len); + new_info.fake.len, 1); ret = PTR_ERR(new); if (IS_ERR(new)) goto out_dput; + /* + * Note! If the short and long name dentries match, + * the target name will be destroyed by the msdos + * rename. So we make a copy in case it's needed. + */ + if (new == new_dentry) { + dput(new); + /* make a copy of the target dentry */ + ret = -ENOMEM; + new_target = d_alloc(new_dentry->d_parent, + &new_dentry->d_name); + if (!new_target) + goto out_dput; + } Printk (("msdos_rename ")); - check_dentry_path (old, "umsdos_rename_f OLD2"); - check_dentry_path (new, "umsdos_rename_f NEW2"); ret = msdos_rename (old_dir, old, new_dir, new); chkstk (); -printk("after m_rename ret %d ", ret); - /* dput(old); */ - dput(new); +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_rename_f: now %s/%s, ret=%d\n", +old->d_parent->d_name.name, old->d_name.name, ret); +#endif + if (new != new_dentry) + dput(new); + /* If the rename failed, remove the new EMD entry */ if (ret != 0) { umsdos_delentry (new_dentry->d_parent, &new_info, S_ISDIR (new_info.entry.mode)); @@ -471,35 +455,47 @@ printk("after m_rename ret %d ", ret); goto out_dput; } + /* Rename successful ... remove old name from EMD */ ret = umsdos_delentry (old_dentry->d_parent, &old_info, S_ISDIR (old_info.entry.mode)); chkstk (); + + /* dput() the dentry if we haven't already */ +out_dput: + if (old_dentry != old) + dput(old); if (ret) - goto out_dput; -#if 0 + goto out_unlock; + /* + * Check whether to update the dcache ... if both + * old and new dentries match, it's already correct. + */ + if (new_dentry != new) { + d_move(old_dentry, new_dentry); + } else if (old_dentry != old) { + /* new dentry was destroyed ... */ + d_drop(new_dentry); + d_add(new_target, NULL); + d_move(old_dentry, new_target); + } + /* * Update f_pos so notify_change will succeed * if the file was already in use. */ - umsdos_set_dirinfo (new_dentry->d_inode, new_dir, new_info.f_pos); +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_rename_f: %s/%s dirinfo, old=%d, new=%d\n", +old_dentry->d_parent->d_name.name, old_dentry->d_name.name, +old_info.f_pos, new_info.f_pos); #endif - if (old_dentry == dret) { -printk("umsdos_rename_f: old dentries match -- skipping d_move\n"); - goto out_dput; - } - d_move (old_dentry, new_dentry); - -out_dput: - dput(dret); + umsdos_set_dirinfo_new(old_dentry, new_info.f_pos); out_unlock: - Printk ((KERN_DEBUG "umsdos_rename_f: unlocking dirs...\n")); + dput(new_target); umsdos_unlockcreate (old_dir); umsdos_unlockcreate (new_dir); out: - check_dentry_path (old_dentry, "umsdos_rename_f OLD3"); - check_dentry_path (new_dentry, "umsdos_rename_f NEW3"); Printk ((" _ret=%d\n", ret)); return ret; } @@ -509,11 +505,11 @@ out: * Return a negative error code or 0 if OK. */ /* #Specification: symbolic links / strategy - * A symbolic link is simply a file which hold a path. It is + * A symbolic link is simply a file which holds a path. It is * implemented as a normal MSDOS file (not very space efficient :-() * - * I see 2 different way to do it. One is to place the link data - * in unused entry of the EMD file. The other is to have a separate + * I see two different ways to do this: One is to place the link data + * in unused entries of the EMD file; the other is to have a separate * file dedicated to hold all symbolic links data. * * Let's go for simplicity... @@ -525,37 +521,33 @@ static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry, int ret, len; struct file filp; +Printk(("umsdos_symlink: %s/%s to %s\n", +dentry->d_parent->d_name.name, dentry->d_name.name, symname)); + ret = umsdos_create_any (dir, dentry, mode, 0, flags); if (ret) { -Printk (("umsdos_symlink ret %d ", ret)); +printk("umsdos_symlink: create failed, ret=%d\n", ret); goto out; } - len = strlen (symname); - fill_new_filp (&filp, dentry); - filp.f_pos = 0; - - /* Make the inode acceptable to MSDOS FIXME */ -Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", -symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino)); + len = strlen (symname); ret = umsdos_file_write_kmem_real (&filp, symname, len); - if (ret >= 0) { if (ret != len) { ret = -EIO; - printk ("UMSDOS: " - "Can't write symbolic link data\n"); + printk (KERN_WARNING + "UMSDOS: Can't write symbolic link data\n"); } else { ret = 0; } } if (ret != 0) { +printk("umsdos_symlink: write failed, unlinking\n"); UMSDOS_unlink (dir, dentry); } out: - Printk (("\n")); return ret; } @@ -583,6 +575,12 @@ int UMSDOS_link (struct dentry *olddentry, struct inode *dir, int ret; struct umsdos_dirent entry; +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_link: new %s%s -> %s/%s\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +olddentry->d_parent->d_name.name, olddentry->d_name.name); +#endif + ret = -EPERM; if (S_ISDIR (oldinode->i_mode)) goto out; @@ -599,45 +597,78 @@ int UMSDOS_link (struct dentry *olddentry, struct inode *dir, olddir = olddentry->d_parent->d_inode; umsdos_lockcreate2 (dir, olddir); - /* get the entry for the old name */ + /* get the directory entry for the old name */ ret = umsdos_dentry_to_entry(olddentry, &entry); if (ret) goto out_unlock; -Printk (("umsdos_link :%.*s: ino %lu flags %d ", -entry.name_len, entry.name ,oldinode->i_ino, entry.flags)); +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_link: have old entry %s, ino=%lu, flags=%x\n", +entry.name, oldinode->i_ino, entry.flags); +#endif if (!(entry.flags & UMSDOS_HIDDEN)) { struct umsdos_info info; + /* get a hidden link name */ ret = umsdos_newhidden (olddentry->d_parent, &info); if (ret) goto out_unlock; +Printk(("umsdos_link: made hidden %s\n", info.entry.name)); + + /* + * Make a dentry and rename the original file ... + */ + temp = umsdos_lookup_dentry(dentry->d_parent, info.entry.name, + info.entry.name_len, 0); + if (IS_ERR(temp)) + goto out_unlock; - ret = umsdos_rename_f (olddentry->d_inode, olddentry, - dir, dentry, UMSDOS_HIDDEN); + /* rename the link to the hidden location ... */ + ret = umsdos_rename_f (olddir, olddentry, dir, temp, + UMSDOS_HIDDEN); + dput(temp); if (ret) goto out_unlock; - path = d_path(olddentry, (char *) buffer, PAGE_SIZE); +#ifdef UMSDOS_DEBUG_VERBOSE +printk("umsdos_link: renamed to %s%s\n", +olddentry->d_parent->d_name.name, olddentry->d_name.name); +#endif + + /* + * Capture the path to the hidden link. + */ + path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE); if (!path) goto out_unlock; +Printk(("umsdos_link: hidden link path=%s\n", path)); + + /* + * Recreate a dentry for the original name and symlink it. + * Note: this counts as the "original" reference, so we + * don't increment i_nlink for this one. + */ temp = umsdos_lookup_dentry(olddentry->d_parent, entry.name, - entry.name_len); + entry.name_len, 0); if (IS_ERR(temp)) goto out_unlock; ret = umsdos_symlink_x (olddir, temp, path, S_IFREG | 0777, UMSDOS_HLINK); - if (ret == 0) { - ret = umsdos_symlink_x (dir, dentry, path, - S_IFREG | 0777, UMSDOS_HLINK); - } dput(temp); + if (ret) + goto out_unlock; + + /* This symlink increments i_nlink (see below.) */ + ret = umsdos_symlink_x (dir, dentry, path, + S_IFREG | 0777, UMSDOS_HLINK); goto out_unlock; } - path = d_path(olddentry, (char *) buffer, PAGE_SIZE); - if (path) { - ret = umsdos_symlink_x (dir, dentry, path, + + path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE); + if (!path) + goto out_unlock; +Printk(("umsdos_link: already hidden, path=%s\n", path)); + ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK); - } out_unlock: umsdos_unlockcreate (olddir); @@ -648,6 +679,8 @@ out: struct iattr newattrs; oldinode->i_nlink++; +printk("UMSDOS_link: linked %s/%s, nlink=%d\n", +olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_nlink); newattrs.ia_valid = 0; ret = UMSDOS_notify_change (olddentry, &newattrs); } @@ -665,12 +698,7 @@ out: */ int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode) { - int ret; - Printk ((KERN_ERR "UMSDOS_create: entering\n")); - check_dentry_path (dentry, "UMSDOS_create START"); - ret = umsdos_create_any (dir, dentry, mode, 0, 0); - check_dentry_path (dentry, "UMSDOS_create END"); - return ret; + return umsdos_create_any (dir, dentry, mode, 0, 0); } @@ -699,10 +727,8 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode) goto out; ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); - if (ret) { -Printk (("umsdos_mkdir %d\n", ret)); + if (ret) goto out; - } umsdos_lockcreate (dir); info.entry.mode = mode | S_IFDIR; @@ -713,14 +739,12 @@ Printk (("umsdos_mkdir %d\n", ret)); info.entry.flags = 0; info.entry.nlink = 1; ret = umsdos_newentry (dentry->d_parent, &info); - if (ret) { -Printk (("newentry %d ", ret)); + if (ret) goto out_unlock; - } /* lookup the short name dentry */ temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len); + info.fake.len, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; @@ -737,36 +761,27 @@ dentry->d_parent->d_name.name, info.fake.fname); if (ret) goto out_remove; - inode = temp->d_inode; - umsdos_lookup_patch_new(temp, &info.entry, info.f_pos); - /* * Note! The long and short name might be the same, * so check first before doing the instantiate ... */ if (dentry != temp) { - if (!dentry->d_inode) { - inode->i_count++; - d_instantiate(dentry, inode); - } else { - printk("umsdos_mkdir: not negative??\n"); - } - } else { - printk("umsdos_mkdir: dentries match, skipping inst\n"); +if (dentry->d_inode) +printk("umsdos_mkdir: dentry not negative!\n"); + inode = temp->d_inode; + inode->i_count++; + d_instantiate(dentry, inode); } - - /* create the EMD file */ - err = umsdos_make_emd(dentry); + umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos); /* - * set up the dir so it is promoted to EMD, - * with the EMD file invisible inside it. + * Create the EMD file, and set up the dir so it is + * promoted to EMD with the EMD file invisible. + * + * N.B. error return if EMD fails? */ - umsdos_setup_dir(temp); - goto out_dput; - -out_remove: - umsdos_delentry (dentry->d_parent, &info, 1); + err = umsdos_make_emd(dentry); + umsdos_setup_dir(dentry); out_dput: /* kill off the short name dentry */ @@ -776,9 +791,14 @@ out_dput: out_unlock: umsdos_unlockcreate (dir); - Printk (("umsdos_mkdir %d\n", ret)); out: + Printk (("umsdos_mkdir %d\n", ret)); return ret; + + /* an error occurred ... remove EMD entry. */ +out_remove: + umsdos_delentry (dentry->d_parent, &info, 1); + goto out_dput; } /* @@ -801,11 +821,7 @@ out: int UMSDOS_mknod (struct inode *dir, struct dentry *dentry, int mode, int rdev) { - int ret; - check_dentry_path (dentry, "UMSDOS_mknod START"); - ret = umsdos_create_any (dir, dentry, mode, rdev, 0); - check_dentry_path (dentry, "UMSDOS_mknod END"); - return ret; + return umsdos_create_any (dir, dentry, mode, rdev, 0); } /* @@ -821,13 +837,6 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry) if (ret) goto out; -#if 0 /* no need for lookup ... we have a dentry ... */ - ret = umsdos_lookup_x (dir, dentry, 0); - Printk (("rmdir lookup %d ", ret)); - if (ret != 0) - goto out; -#endif - umsdos_lockcreate (dir); ret = -EBUSY; if (dentry->d_count > 1) { @@ -839,6 +848,14 @@ dentry->d_parent->d_name.name, dentry->d_name.name); } } + /* check the sticky bit */ + ret = -EPERM; + if (is_sticky(dir, dentry->d_inode->i_uid)) { +printk("umsdos_rmdir: %s/%s is sticky\n", +dentry->d_parent->d_name.name, dentry->d_name.name); + goto out_unlock; + } + /* check whether the EMD is empty */ empty = umsdos_isempty (dentry); ret = -ENOTEMPTY; @@ -848,24 +865,21 @@ dentry->d_parent->d_name.name, dentry->d_name.name); /* Have to remove the EMD file? */ if (empty == 1) { struct dentry *demd; - /* check sticky bit */ - ret = -EPERM; - if (is_sticky(dir, dentry->d_inode->i_uid)) { -printk("umsdos_rmdir: %s/%s is sticky\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - goto out_unlock; - } + +Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); ret = -ENOTEMPTY; /* see if there's an EMD file ... */ demd = umsdos_get_emd_dentry(dentry); if (IS_ERR(demd)) goto out_unlock; -printk("umsdos_rmdir: got EMD dentry %s/%s, inode=%p\n", -demd->d_parent->d_name.name, demd->d_name.name, demd->d_inode); err = msdos_unlink (dentry->d_inode, demd); -Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); +#ifdef UMSDOS_PARANOIA +if (err) +printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n", +demd->d_parent->d_name.name, demd->d_name.name, err); +#endif dput(demd); if (err) goto out_unlock; @@ -875,7 +889,7 @@ Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); /* Call findentry to complete the mangling */ umsdos_findentry (dentry->d_parent, &info, 2); temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len); + info.fake.len, 1); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; @@ -884,8 +898,8 @@ Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); */ if (temp == dentry) { dput(temp); -printk("umsdos_rmdir: %s/%s, short matches long\n", -dentry->d_parent->d_name.name, dentry->d_name.name); +Printk(("umsdos_rmdir: %s/%s, short matches long\n", +dentry->d_parent->d_name.name, dentry->d_name.name)); } /* @@ -897,16 +911,18 @@ dentry->d_parent->d_name.name, dentry->d_name.name); /* OK so far ... remove the name from the EMD */ ret = umsdos_delentry (dentry->d_parent, &info, 1); +#ifdef UMSDOS_PARANOIA +if (ret) +printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret); +#endif -out_dput: /* dput() temp if we didn't do it above */ +out_dput: if (temp != dentry) { d_drop(temp); dput(temp); if (!ret) d_delete (dentry); -printk("umsdos_rmdir: %s/%s, short=%s dput\n", -dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname); } out_unlock: @@ -922,8 +938,8 @@ out: * Remove a file from the directory. * * #Specification: hard link / deleting a link - * When we delete a file, and this file is a link - * we must subtract 1 to the nlink field of the + * When we delete a file and this file is a link, + * we must subtract 1 from the nlink field of the * hidden link. * * If the count goes to 0, we delete this hidden @@ -931,12 +947,12 @@ out: */ int UMSDOS_unlink (struct inode *dir, struct dentry *dentry) { - struct dentry *temp; + struct dentry *temp, *link = NULL; struct inode *inode; int ret; struct umsdos_info info; -Printk (("UMSDOS_unlink: entering %s/%s\n", +Printk(("UMSDOS_unlink: entering %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name)); ret = umsdos_nevercreat (dir, dentry, -EPERM); @@ -950,11 +966,13 @@ dentry->d_parent->d_name.name, dentry->d_name.name)); umsdos_lockcreate (dir); ret = umsdos_findentry (dentry->d_parent, &info, 1); if (ret) { -printk("UMSDOS_unlink: findentry returned %d\n", ret); +printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, ret); goto out_unlock; } Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname)); + ret = -EPERM; /* check sticky bit */ if (is_sticky(dir, info.entry.uid)) { @@ -963,65 +981,55 @@ dentry->d_parent->d_name.name, dentry->d_name.name); goto out_unlock; } - ret = 0; + /* + * Note! If this is a hardlink and the names are aliased, + * the short-name lookup will return the hardlink dentry. + * In order to get the correct (real) inode, we just drop + * the original dentry. + */ if (info.entry.flags & UMSDOS_HLINK) { -printk("UMSDOS_unlink: hard link %s/%s, fake=%s\n", + d_drop(dentry); +#ifdef UMSDOS_PARANOIA +printk("UMSDOS_unlink: hard link %s/%s, fake=%s, dropping\n", dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname); - /* - * First, get the inode of the hidden link - * using the standard lookup function. - */ - - ret = umsdos_lookup_x (dir, dentry, 0); - inode = dentry->d_inode; - if (ret) - goto out_unlock; - - Printk (("unlink nlink = %d ", inode->i_nlink)); - inode->i_nlink--; - if (inode->i_nlink == 0) { - struct umsdos_dirent entry; - - ret = umsdos_dentry_to_entry (dentry, &entry); - if (ret == 0) { - ret = UMSDOS_unlink (dentry->d_parent->d_inode, - dentry); - } - } else { - struct iattr newattrs; - newattrs.ia_valid = 0; - ret = UMSDOS_notify_change (dentry, &newattrs); - } +#endif } - if (ret) - goto out_unlock; /* get the short name dentry */ temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len); + info.fake.len, 1); + ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; /* - * If the short name matches the long, - * dput() it now so it's not busy. + * Resolve hardlinks now, but defer processing until later. */ - if (temp == dentry) { -printk("UMSDOS_unlink: %s/%s, short matches long\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - dput(temp); + if (info.entry.flags & UMSDOS_HLINK) { + link = umsdos_solve_hlink(dget(temp)); } + /* + * If the short and long names are aliased, + * dput() it now so the dentry isn't busy. + */ + if (temp == dentry) + dput(temp); + + /* Delete the EMD entry */ ret = umsdos_delentry (dentry->d_parent, &info, 0); - if (ret && ret != -ENOENT) + if (ret && ret != -ENOENT) { + printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n", + info.entry.name, ret); goto out_dput; + } -printk("UMSDOS: Before msdos_unlink %.*s ", -info.fake.len, info.fake.fname); ret = msdos_unlink_umsdos (dir, temp); - -Printk (("msdos_unlink %.*s %o ret %d ", -info.fake.len, info.fake.fname ,info.entry.mode, ret)); +#ifdef UMSDOS_PARANOIA +if (ret) +printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n", +temp->d_parent->d_name.name, temp->d_name.name, ret); +#endif /* dput() temp if we didn't do it above */ out_dput: @@ -1030,12 +1038,56 @@ out_dput: dput(temp); if (!ret) d_delete (dentry); -printk("umsdos_unlink: %s/%s, short=%s dput\n", -dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname); } out_unlock: umsdos_unlockcreate (dir); + + /* + * Now check for deferred handling of a hardlink. + */ + if (!link) + goto out; + + if (IS_ERR(link)) { +printk("umsdos_unlink: failed to resolve %s/%s\n", +dentry->d_parent->d_name.name, dentry->d_name.name); + if (!ret) + ret = PTR_ERR(link); + goto out; + } + +Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n", +link->d_parent->d_name.name, link->d_name.name, ret)); + + /* already have an error? */ + if (ret) + goto out_cleanup; + + /* make sure the link exists ... */ + inode = link->d_inode; + if (!inode) { + printk(KERN_WARNING "umsdos_unlink: hard link not found\n"); + goto out_cleanup; + } + + /* + * If this was the last linked references, delete it now. + */ + if (inode->i_nlink <= 1) { + ret = UMSDOS_unlink (link->d_parent->d_inode, link); +printk("umsdos_unlink: nlink -> 0, unlinked, ret=%d\n", ret); + } else { + struct iattr newattrs; + inode->i_nlink--; + newattrs.ia_valid = 0; + ret = UMSDOS_notify_change (link, &newattrs); + } + +out_cleanup: + d_drop(link); + dput(link); + out: Printk (("umsdos_unlink %d\n", ret)); return ret; @@ -1059,14 +1111,10 @@ int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry, goto out; /* This is not terribly efficient but should work. */ - ret = UMSDOS_unlink (new_dir, new_dentry); - chkstk (); - Printk (("rename unlink ret %d -- ", ret)); - if (ret == -EISDIR) { + if (S_ISDIR(new_dentry->d_inode->i_mode)) ret = UMSDOS_rmdir (new_dir, new_dentry); - chkstk (); - Printk (("rename rmdir ret %d -- ", ret)); - } + else + ret = UMSDOS_unlink (new_dir, new_dentry); if (ret) goto out; diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index 39605218d7b5..7101655e3b2b 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -20,6 +20,7 @@ extern struct inode *pseudo_root; +extern struct dentry_operations umsdos_dentry_operations; struct RDIR_FILLDIR { void *dirbuf; @@ -96,7 +97,7 @@ printk (KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"); goto out; } - ret = umsdos_real_lookup (dir, dentry); + ret = msdos_lookup (dir, dentry); inode = dentry->d_inode; if ((ret == 0) && inode) { if (inode == pseudo_root && !nopseudo) { @@ -119,6 +120,8 @@ inode->i_ino)); } } out: + /* always install our dentry ops ... */ + dentry->d_op = &umsdos_dentry_operations; PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); return ret; } @@ -170,28 +173,19 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) ret = msdos_rmdir (dir, dentry); if (ret != -ENOTEMPTY) - goto out_check; - -#if 0 /* why do this? we have the dentry ... */ - ret = UMSDOS_rlookup (dir, dentry); - PRINTK (("rrmdir lookup %d ", ret)); - if (ret) goto out_unlock; - ret = -ENOTEMPTY; -#endif empty = umsdos_isempty (dentry); if (empty == 1) { - struct dentry *temp; + struct dentry *demd; /* We have to remove the EMD file. */ - temp = umsdos_lookup_dentry(dentry, UMSDOS_EMD_FILE, - UMSDOS_EMD_NAMELEN); - ret = PTR_ERR(temp); - if (!IS_ERR(temp)) { + demd = umsdos_get_emd_dentry(dentry); + ret = PTR_ERR(demd); + if (!IS_ERR(demd)) { ret = 0; - if (temp->d_inode) - ret = msdos_unlink (dentry->d_inode, temp); - dput(temp); + if (demd->d_inode) + ret = msdos_unlink (dentry->d_inode, demd); + dput(demd); } if (ret) goto out_unlock; @@ -199,15 +193,9 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry) /* now retry the original ... */ ret = msdos_rmdir (dir, dentry); -out_check: - /* Check whether we succeeded ... */ - if (!ret) - d_delete(dentry); - out_unlock: umsdos_unlockcreate (dir); out: - check_inode (dir); return ret; } diff --git a/fs/umsdos/specs b/fs/umsdos/specs index 7b88a78e425b..0f7d68c0aef6 100644 --- a/fs/umsdos/specs +++ b/fs/umsdos/specs @@ -147,6 +147,7 @@ * same target at the same time. Again, I am not sure it * is a problem at all. */ + /* #Specification: hard link / strategy * Hard links are difficult to implement on top of an MS-DOS FAT file * system. Unlike Unix file systems, there are no inodes. A directory @@ -180,6 +181,7 @@ * The entry -LINK1 will be hidden. It will hold a link count. * When all link are erased, the hidden file is erased too. */ + /* #Specification: weakness / hard link * The strategy for hard link introduces a side effect that * may or may not be acceptable. Here is the sequence diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c index dc639a7a4420..cc739cfa5118 100644 --- a/fs/umsdos/symlink.c +++ b/fs/umsdos/symlink.c @@ -32,52 +32,26 @@ int umsdos_readlink_x ( struct dentry *dentry, char *buffer, int bufsiz) { - int ret; + size_t size = dentry->d_inode->i_size; loff_t loffs = 0; + ssize_t ret; struct file filp; - ret = dentry->d_inode->i_size; - - if (!(dentry->d_inode)) { - return -EBADF; - } +Printk((KERN_DEBUG "UMSDOS_read: %s/%s, size=%u\n", +dentry->d_parent->d_name.name, dentry->d_name.name, size)); fill_new_filp (&filp, dentry); - filp.f_reada = 0; filp.f_flags = O_RDONLY; - filp.f_op = &umsdos_symlink_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ - - if (ret > bufsiz) - ret = bufsiz; - - PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs)); - PRINTK ((KERN_DEBUG " f_op=%p\n", filp.f_op)); - PRINTK ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp.f_dentry->d_inode->i_ino, filp.f_dentry->d_inode->i_size)); - PRINTK ((KERN_DEBUG " f_pos=%Lu\n", filp.f_pos)); - PRINTK ((KERN_DEBUG " name=%.*s\n", (int) filp.f_dentry->d_name.len, filp.f_dentry->d_name.name)); - PRINTK ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I (filp.f_dentry->d_inode)->i_binary)); - PRINTK ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags)); - PRINTK ((KERN_DEBUG " f_owner=%d\n", filp.f_owner.uid)); - PRINTK ((KERN_DEBUG " f_version=%ld\n", filp.f_version)); - PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin)); + filp.f_op = &umsdos_symlink_operations; + if (size > bufsiz) + size = bufsiz; - PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs)); - if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret) { + ret = fat_file_read (&filp, buffer, size, &loffs); + if (ret != size) { ret = -EIO; } -#if 0 - { - struct umsdos_dirent *mydirent = buffer; - - PRINTK ((KERN_DEBUG " (DDD) uid=%d\n", mydirent->uid)); - PRINTK ((KERN_DEBUG " (DDD) gid=%d\n", mydirent->gid)); - PRINTK ((KERN_DEBUG " (DDD) name=>%.20s<\n", mydirent->name)); - } -#endif - - PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%Lu ret=%d\n", loffs, ret)); return ret; } @@ -85,48 +59,38 @@ int umsdos_readlink_x ( struct dentry *dentry, static int UMSDOS_readlink (struct dentry *dentry, char *buffer, int buflen) { - int ret; - - PRINTK ((KERN_DEBUG "UMSDOS_readlink: calling umsdos_readlink_x for %.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); - - ret = umsdos_readlink_x (dentry, buffer, buflen); - PRINTK ((KERN_DEBUG "readlink %d bufsiz %d\n", ret, buflen)); - /* dput(dentry); / * FIXME /mn/? It seems it is unneeded. d_count is not changed by umsdos_readlink_x */ - - Printk ((KERN_WARNING "UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret)); - return ret; - + return umsdos_readlink_x (dentry, buffer, buflen); } /* this one mostly stolen from romfs :) */ -static struct dentry *UMSDOS_followlink (struct dentry *dentry, struct dentry *base) +static struct dentry *UMSDOS_followlink (struct dentry *dentry, + struct dentry *base) { struct inode *inode = dentry->d_inode; - char *symname = NULL; + char *symname; int len, cnt; mm_segment_t old_fs = get_fs (); - Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: (%.*s/%.*s)\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, (int) dentry->d_name.len, dentry->d_name.name)); +Printk((KERN_DEBUG "UMSDOS_followlink /mn/: (%s/%s)\n", +dentry->d_parent->d_name.name, dentry->d_name.name)); len = inode->i_size; if (!(symname = kmalloc (len + 1, GFP_KERNEL))) { - dentry = ERR_PTR (-EAGAIN); /* correct? */ + dentry = ERR_PTR (-ENOMEM); goto outnobuf; } + set_fs (KERNEL_DS); /* we read into kernel space this time */ - PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: Here goes umsdos_readlink_x %p, %p, %d\n", dentry, symname, len)); cnt = umsdos_readlink_x (dentry, symname, len); - PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: back from umsdos_readlink_x %p, %p, %d!\n", dentry, symname, len)); set_fs (old_fs); - Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: link name is %.*s with len %d\n", cnt, symname, cnt)); if (len != cnt) { dentry = ERR_PTR (-EIO); goto out; - } else - symname[len] = 0; + } + symname[len] = 0; dentry = lookup_dentry (symname, base, 1); kfree (symname); @@ -139,7 +103,7 @@ static struct dentry *UMSDOS_followlink (struct dentry *dentry, struct dentry *b return dentry; } - +/* needed to patch the file structure */ static struct file_operations umsdos_symlink_operations = { NULL, /* lseek - default */ @@ -158,7 +122,7 @@ static struct file_operations umsdos_symlink_operations = struct inode_operations umsdos_symlink_inode_operations = { - NULL, /* default file operations */ + NULL, /* default file operations (none) */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ @@ -169,14 +133,14 @@ struct inode_operations umsdos_symlink_inode_operations = NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ - UMSDOS_followlink, /* followlink *//* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */ - generic_readpage, /* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */ + UMSDOS_followlink, /* followlink */ + generic_readpage, /* readpage */ NULL, /* writepage */ - fat_bmap, /* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */ + fat_bmap, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ NULL, /* updatepage */ NULL /* revalidate */ - }; + diff --git a/arch/i386/kernel/desc.h b/include/asm-i386/desc.h similarity index 100% rename from arch/i386/kernel/desc.h rename to include/asm-i386/desc.h diff --git a/include/linux/loop.h b/include/linux/loop.h index 75f6cc704662..41bd00856b82 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -1,6 +1,8 @@ #ifndef _LINUX_LOOP_H #define _LINUX_LOOP_H +#include + /* * include/linux/loop.h * @@ -28,27 +30,41 @@ struct loop_device { char *raw_buf, char *loop_buf, int size); char lo_name[LO_NAME_SIZE]; char lo_encrypt_key[LO_KEY_SIZE]; -#ifdef DES_AVAILABLE - des_key_schedule lo_des_key; - unsigned long lo_des_init[2]; -#endif -#ifdef IDEA_AVAILABLE - idea_key lo_idea_en_key; - idea_key lo_idea_de_key; -#endif + __u32 lo_init[2]; + uid_t lo_key_owner; /* Who set the key */ + int (*ioctl)(struct loop_device *, int cmd, + unsigned long arg); + struct file * lo_backing_file; + void *key_data; + char key_reserved[48]; /* for use by the filter modules */ }; typedef int (* transfer_proc_t)(struct loop_device *, int cmd, char *raw_buf, char *loop_buf, int size); +#endif /* __KERNEL__ */ + /* * Loop flags */ #define LO_FLAGS_DO_BMAP 0x00000001 #define LO_FLAGS_READ_ONLY 0x00000002 -#endif /* __KERNEL__ */ +/* + * Note that this structure gets the wrong offsets when directly used + * from a glibc program, because glibc has a 32bit dev_t. + * Prevent people from shooting in their own foot. + */ +#if __GLIBC__ >= 2 && !defined(dev_t) +#error "Wrong dev_t in loop.h" +#endif + +/* + * This uses kdev_t because glibc currently has no appropiate + * conversion version for the loop ioctls. + * The situation is very unpleasant + */ struct loop_info { int lo_number; /* ioctl r/o */ @@ -66,15 +82,31 @@ struct loop_info { }; /* - * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet + * Loop filter types */ #define LO_CRYPT_NONE 0 #define LO_CRYPT_XOR 1 #define LO_CRYPT_DES 2 -#define LO_CRYPT_IDEA 3 -#define MAX_LO_CRYPT 4 +#define LO_CRYPT_DUMMY 9 +#define LO_CRYPT_SKIPJACK 10 +#define MAX_LO_CRYPT 20 +#ifdef __KERNEL__ +/* Support for loadable transfer modules */ +struct loop_func_table { + int number; /* filter type */ + int (*transfer)(struct loop_device *lo, int cmd, + char *raw_buf, char *loop_buf, int size); + int (*init)(struct loop_device *, struct loop_info *); + int (*release)(struct loop_device *); + int (*ioctl)(struct loop_device *, int cmd, unsigned long arg); +}; + +int loop_register_transfer(struct loop_func_table *funcs); +int loop_unregister_transfer(int number); + +#endif /* * IOCTL commands --- we will commandeer 0x4C ('L') */ diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 1e912ae53edd..ef7649b1e254 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -23,6 +23,7 @@ enum root_directory_inos { PROC_CPUINFO, PROC_PCI, PROC_MCA, + PROC_NUBUS, PROC_SELF, /* will change inode # */ PROC_NET, PROC_SCSI, diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h index 00d40adcac62..76dab1072bd6 100644 --- a/include/linux/sysv_fs.h +++ b/include/linux/sysv_fs.h @@ -37,28 +37,28 @@ as { byte2, byte3, byte0, byte1 }. We need conversions. */ -typedef unsigned long coh_ulong; +typedef u32 coh_ulong; -static inline coh_ulong to_coh_ulong (unsigned long x) +static inline coh_ulong to_coh_ulong (u32 x) { return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16); } -static inline unsigned long from_coh_ulong (coh_ulong x) +static inline u32 from_coh_ulong (coh_ulong x) { return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16); } /* inode numbers are 16 bit */ -typedef unsigned short sysv_ino_t; +typedef u16 sysv_ino_t; /* Block numbers are 24 bit, sometimes stored in 32 bit. On Coherent FS, they are always stored in PDP-11 manner: the least significant 16 bits come last. */ -typedef unsigned long sysv_zone_t; +typedef u32 sysv_zone_t; /* Among the blocks ... */ /* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block. @@ -75,36 +75,36 @@ typedef unsigned long sysv_zone_t; #define XENIX_NICINOD 100 /* number of inode cache entries */ #define XENIX_NICFREE 100 /* number of free block list chunk entries */ struct xenix_super_block { - unsigned short s_isize; /* index of first data zone */ - unsigned long s_fsize __packed2__; /* total number of zones of this fs */ + u16 s_isize; /* index of first data zone */ + u32 s_fsize __packed2__; /* total number of zones of this fs */ /* the start of the free block list: */ - unsigned short s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */ - unsigned long s_free[XENIX_NICFREE]; /* first free block list chunk */ + u16 s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */ + u32 s_free[XENIX_NICFREE]; /* first free block list chunk */ /* the cache of free inodes: */ - unsigned short s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */ - sysv_ino_t s_inode[XENIX_NICINOD]; /* some free inodes */ + u16 s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */ + sysv_ino_t s_inode[XENIX_NICINOD]; /* some free inodes */ /* locks, not used by Linux: */ - char s_flock; /* lock during free block list manipulation */ - char s_ilock; /* lock during inode cache manipulation */ - char s_fmod; /* super-block modified flag */ - char s_ronly; /* flag whether fs is mounted read-only */ - unsigned long s_time __packed2__; /* time of last super block update */ - unsigned long s_tfree __packed2__; /* total number of free zones */ - unsigned short s_tinode; /* total number of free inodes */ - short s_dinfo[4]; /* device information ?? */ - char s_fname[6]; /* file system volume name */ - char s_fpack[6]; /* file system pack name */ - char s_clean; /* set to 0x46 when filesystem is properly unmounted */ - char s_fill[371]; - long s_magic; /* version of file system */ - long s_type; /* type of file system: 1 for 512 byte blocks + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + u32 s_time __packed2__; /* time of last super block update */ + u32 s_tfree __packed2__; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + s16 s_dinfo[4]; /* device information ?? */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + char s_clean; /* set to 0x46 when filesystem is properly unmounted */ + char s_fill[371]; + s32 s_magic; /* version of file system */ + s32 s_type; /* type of file system: 1 for 512 byte blocks 2 for 1024 byte blocks */ }; /* Xenix free list block on disk */ struct xenix_freelist_chunk { - unsigned short fl_nfree; /* number of free blocks in fl_free, <= XENIX_NICFREE] */ - unsigned long fl_free[XENIX_NICFREE] __packed2__; + u16 fl_nfree; /* number of free blocks in fl_free, <= XENIX_NICFREE] */ + u32 fl_free[XENIX_NICFREE] __packed2__; }; /* SystemV FS comes in two variants: @@ -116,116 +116,120 @@ struct xenix_freelist_chunk { /* SystemV4 super-block data on disk */ struct sysv4_super_block { - unsigned short s_isize; /* index of first data zone */ - unsigned long s_fsize; /* total number of zones of this fs */ + u16 s_isize; /* index of first data zone */ + u16 s_pad0; + u32 s_fsize; /* total number of zones of this fs */ /* the start of the free block list: */ - unsigned short s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ - unsigned long s_free[SYSV_NICFREE]; /* first free block list chunk */ + u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ + u16 s_pad1; + u32 s_free[SYSV_NICFREE]; /* first free block list chunk */ /* the cache of free inodes: */ - unsigned short s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ + u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ + u16 s_pad2; sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */ /* locks, not used by Linux: */ - char s_flock; /* lock during free block list manipulation */ - char s_ilock; /* lock during inode cache manipulation */ - char s_fmod; /* super-block modified flag */ - char s_ronly; /* flag whether fs is mounted read-only */ - unsigned long s_time; /* time of last super block update */ - short s_dinfo[4]; /* device information ?? */ - unsigned long s_tfree; /* total number of free zones */ - unsigned short s_tinode; /* total number of free inodes */ - char s_fname[6]; /* file system volume name */ - char s_fpack[6]; /* file system pack name */ - long s_fill[12]; - long s_state; /* file system state: 0x7c269d38-s_time means clean */ - long s_magic; /* version of file system */ - long s_type; /* type of file system: 1 for 512 byte blocks + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + u32 s_time; /* time of last super block update */ + s16 s_dinfo[4]; /* device information ?? */ + u32 s_tfree; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + u16 s_pad3; + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + s32 s_fill[12]; + s32 s_state; /* file system state: 0x7c269d38-s_time means clean */ + s32 s_magic; /* version of file system */ + s32 s_type; /* type of file system: 1 for 512 byte blocks 2 for 1024 byte blocks */ }; /* SystemV4 free list block on disk */ struct sysv4_freelist_chunk { - unsigned short fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ - unsigned long fl_free[SYSV_NICFREE]; + u16 fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ + u32 fl_free[SYSV_NICFREE]; }; /* SystemV2 super-block data on disk */ struct sysv2_super_block { - unsigned short s_isize; /* index of first data zone */ - unsigned long s_fsize __packed2__; /* total number of zones of this fs */ + u16 s_isize; /* index of first data zone */ + u32 s_fsize __packed2__; /* total number of zones of this fs */ /* the start of the free block list: */ - unsigned short s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ - unsigned long s_free[SYSV_NICFREE]; /* first free block list chunk */ + u16 s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ + u32 s_free[SYSV_NICFREE]; /* first free block list chunk */ /* the cache of free inodes: */ - unsigned short s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ + u16 s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */ /* locks, not used by Linux: */ - char s_flock; /* lock during free block list manipulation */ - char s_ilock; /* lock during inode cache manipulation */ - char s_fmod; /* super-block modified flag */ - char s_ronly; /* flag whether fs is mounted read-only */ - unsigned long s_time __packed2__; /* time of last super block update */ - short s_dinfo[4]; /* device information ?? */ - unsigned long s_tfree __packed2__; /* total number of free zones */ - unsigned short s_tinode; /* total number of free inodes */ - char s_fname[6]; /* file system volume name */ - char s_fpack[6]; /* file system pack name */ - long s_fill[14]; - long s_state; /* file system state: 0xcb096f43 means clean */ - long s_magic; /* version of file system */ - long s_type; /* type of file system: 1 for 512 byte blocks + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + u32 s_time __packed2__; /* time of last super block update */ + s16 s_dinfo[4]; /* device information ?? */ + u32 s_tfree __packed2__; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + s32 s_fill[14]; + s32 s_state; /* file system state: 0xcb096f43 means clean */ + s32 s_magic; /* version of file system */ + s32 s_type; /* type of file system: 1 for 512 byte blocks 2 for 1024 byte blocks */ }; /* SystemV2 free list block on disk */ struct sysv2_freelist_chunk { - unsigned short fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ - unsigned long fl_free[SYSV_NICFREE] __packed2__; + u16 fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ + u32 fl_free[SYSV_NICFREE] __packed2__; }; /* Coherent super-block data on disk */ #define COH_NICINOD 100 /* number of inode cache entries */ #define COH_NICFREE 64 /* number of free block list chunk entries */ struct coh_super_block { - unsigned short s_isize; /* index of first data zone */ - coh_ulong s_fsize __packed2__; /* total number of zones of this fs */ + u16 s_isize; /* index of first data zone */ + coh_ulong s_fsize __packed2__; /* total number of zones of this fs */ /* the start of the free block list: */ - unsigned short s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */ - coh_ulong s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ + u16 s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */ + coh_ulong s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ /* the cache of free inodes: */ - unsigned short s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */ - sysv_ino_t s_inode[COH_NICINOD]; /* some free inodes */ + u16 s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */ + sysv_ino_t s_inode[COH_NICINOD]; /* some free inodes */ /* locks, not used by Linux: */ - char s_flock; /* lock during free block list manipulation */ - char s_ilock; /* lock during inode cache manipulation */ - char s_fmod; /* super-block modified flag */ - char s_ronly; /* flag whether fs is mounted read-only */ - coh_ulong s_time __packed2__; /* time of last super block update */ - coh_ulong s_tfree __packed2__; /* total number of free zones */ - unsigned short s_tinode; /* total number of free inodes */ - unsigned short s_interleave_m; /* interleave factor */ - unsigned short s_interleave_n; - char s_fname[6]; /* file system volume name */ - char s_fpack[6]; /* file system pack name */ - unsigned long s_unique; /* zero, not used */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + coh_ulong s_time __packed2__; /* time of last super block update */ + coh_ulong s_tfree __packed2__; /* total number of free zones */ + u16 s_tinode; /* total number of free inodes */ + u16 s_interleave_m; /* interleave factor */ + u16 s_interleave_n; + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + u32 s_unique; /* zero, not used */ }; /* Coherent free list block on disk */ struct coh_freelist_chunk { - unsigned short fl_nfree; /* number of free blocks in fl_free, <= COH_NICFREE] */ - unsigned long fl_free[COH_NICFREE] __packed2__; + u16 fl_nfree; /* number of free blocks in fl_free, <= COH_NICFREE] */ + u32 fl_free[COH_NICFREE] __packed2__; }; /* SystemV/Coherent inode data on disk */ struct sysv_inode { - unsigned short i_mode; - unsigned short i_nlink; - unsigned short i_uid; - unsigned short i_gid; - unsigned long i_size; + u16 i_mode; + u16 i_nlink; + u16 i_uid; + u16 i_gid; + u32 i_size; union { /* directories, regular files, ... */ - char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks, + unsigned char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks, * then 1 indirection block, * then 1 double indirection block, * then 1 triple indirection block. @@ -236,14 +240,14 @@ struct sysv_inode { /* named pipes on Coherent */ struct { char p_addp[30]; - short p_pnc; - short p_prx; - short p_pwx; + s16 p_pnc; + s16 p_prx; + s16 p_pwx; } i_p; } i_a; - unsigned long i_atime; /* time of last access */ - unsigned long i_mtime; /* time of last modification */ - unsigned long i_ctime; /* time of creation */ + u32 i_atime; /* time of last access */ + u32 i_mtime; /* time of last modification */ + u32 i_ctime; /* time of creation */ }; /* The admissible values for i_mode are listed in : @@ -301,7 +305,7 @@ extern inline unsigned short to_coh_imode(mode_t mode) /* The number of inodes per block is sb->sv_inodes_per_block = block_size / sizeof(struct sysv_inode) */ /* The number of indirect pointers per block is - sb->sv_ind_per_block = block_size / sizeof(unsigned long) */ + sb->sv_ind_per_block = block_size / sizeof(u32) */ /* SystemV/Coherent directory entry on disk */ diff --git a/include/linux/sysv_fs_i.h b/include/linux/sysv_fs_i.h index 56a63f1ef9a3..990b3543fdcd 100644 --- a/include/linux/sysv_fs_i.h +++ b/include/linux/sysv_fs_i.h @@ -5,11 +5,11 @@ * SystemV/Coherent FS inode data in memory */ struct sysv_inode_info { - unsigned long i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks, - * then 1 indirection block, - * then 1 double indirection block, - * then 1 triple indirection block. - */ + u32 i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks, + * then 1 indirection block, + * then 1 double indirection block, + * then 1 triple indirection block. + */ }; #endif diff --git a/include/linux/sysv_fs_sb.h b/include/linux/sysv_fs_sb.h index 99a7c125d981..df886f651c02 100644 --- a/include/linux/sysv_fs_sb.h +++ b/include/linux/sysv_fs_sb.h @@ -50,21 +50,21 @@ struct sysv_sb_info { different superblock layout. */ char * s_sbd1; /* entire superblock data, for part 1 */ char * s_sbd2; /* entire superblock data, for part 2 */ - unsigned short *s_sb_fic_count; /* pointer to s_sbd->s_ninode */ - unsigned short *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */ - unsigned short *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */ - unsigned short *s_sb_flc_count; /* pointer to s_sbd->s_nfree */ - unsigned long *s_sb_flc_blocks; /* pointer to s_sbd->s_free */ - unsigned long *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */ - unsigned long *s_sb_time; /* pointer to s_sbd->s_time */ - unsigned long *s_sb_state; /* pointer to s_sbd->s_state, only FSTYPE_SYSV */ + u16 *s_sb_fic_count; /* pointer to s_sbd->s_ninode */ + u16 *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */ + u16 *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */ + u16 *s_sb_flc_count; /* pointer to s_sbd->s_nfree */ + u32 *s_sb_flc_blocks; /* pointer to s_sbd->s_free */ + u32 *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */ + u32 *s_sb_time; /* pointer to s_sbd->s_time */ + u32 *s_sb_state; /* pointer to s_sbd->s_state, only FSTYPE_SYSV */ /* We keep those superblock entities that don't change here; this saves us an indirection and perhaps a conversion. */ - unsigned long s_firstinodezone; /* index of first inode zone */ - unsigned long s_firstdatazone; /* same as s_sbd->s_isize */ - unsigned long s_ninodes; /* total number of inodes */ - unsigned long s_ndatazones; /* total number of data zones */ - unsigned long s_nzones; /* same as s_sbd->s_fsize */ + u32 s_firstinodezone; /* index of first inode zone */ + u32 s_firstdatazone; /* same as s_sbd->s_isize */ + u32 s_ninodes; /* total number of inodes */ + u32 s_ndatazones; /* total number of data zones */ + u32 s_nzones; /* same as s_sbd->s_fsize */ }; /* The fields s_ind_per_block_2_1, s_toobig_block are currently unused. */ diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p index 44a6eec2b34d..ed049fca2ca4 100644 --- a/include/linux/umsdos_fs.p +++ b/include/linux/umsdos_fs.p @@ -11,6 +11,7 @@ int dummy_dir_read ( struct file *filp, char *buf, size_t size, loff_t *count); +char * umsdos_d_path(struct dentry *, char *, int); void umsdos_lookup_patch_new(struct dentry *, struct umsdos_dirent *, off_t); void umsdos_lookup_patch (struct inode *dir, struct inode *inode, @@ -27,7 +28,7 @@ int umsdos_lookup_x ( struct dentry *dentry, int nopseudo); int UMSDOS_lookup(struct inode *, struct dentry *); -struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int); +struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int); struct dentry *umsdos_solve_hlink (struct dentry *hlink); @@ -80,15 +81,11 @@ int UMSDOS_statfs (struct super_block *, struct statfs *, int); struct super_block *UMSDOS_read_super (struct super_block *, void *, int); void UMSDOS_put_super (struct super_block *); -struct dentry *compat_umsdos_real_lookup (struct dentry *d_dir, - const char *name, - int len); int umsdos_real_lookup(struct inode *, struct dentry *); void umsdos_setup_dir(struct dentry *); void umsdos_setup_dir_inode (struct inode *inode); -void umsdos_set_dirinfo (struct inode *inode, - struct inode *dir, - off_t f_pos); +void umsdos_set_dirinfo_new(struct dentry *, off_t); +void umsdos_set_dirinfo (struct inode *, struct inode *, off_t); int umsdos_isinit (struct inode *inode); void umsdos_patch_dentry_inode (struct dentry *, off_t); void umsdos_patch_inode (struct inode *, struct inode *, off_t); diff --git a/include/linux/videodev.h b/include/linux/videodev.h index e089d607ef5f..043d4c9e2bd5 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -48,6 +48,7 @@ extern void video_unregister_device(struct video_device *); #define VID_TYPE_SCALES 128 /* Scalable */ #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ #define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ +#define VID_TYPE_OUTPUT 1024 /* Can output video data */ struct video_capability { diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h index 736fc2747d5b..f5f4052d665b 100644 --- a/include/linux/wavefront.h +++ b/include/linux/wavefront.h @@ -150,10 +150,6 @@ typedef unsigned char UCHAR8; #define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2 #define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4 -/* See wavefront.c for details */ - -#define WAVEFRONT_MAX_DEVICES 1 /* How many WaveFront cards we can handle */ - /* slot indexes for struct address_info: makes code a little more mnemonic */ #define WF_SYNTH_SLOT 0 @@ -502,11 +498,11 @@ typedef union wf_any { wavefront_drum d; } wavefront_any; -/* Hannu Savolainen hoped that his "patch_info" struct in soundcard.h - might work for other wavetable-based patch-loading situations. - Alas, his fears were correct. The WaveFront doesn't even come with - just "patches", but several different kinds of structures that - control the process of generating sound. +/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h + might work for other wave-table based patch loading situations. + Alas, his fears were correct. The WaveFront doesn't even come with + just "patches", but several different kind of structures that + control the sound generation process. */ typedef struct wf_patch_info { @@ -662,7 +658,7 @@ typedef struct wf_fx_info { /* Allow direct user-space control over FX memory/coefficient data. In theory this could be used to download the FX microprogram, - but it would be a little slower, and involve some weird code. + but it would be a little slower, and involve some wierd code. */ #define WFFX_MEMSET 69 diff --git a/kernel/exit.c b/kernel/exit.c index 6f6b281ea582..72ecd910df3c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -239,7 +239,11 @@ static inline void __exit_sighand(struct task_struct *tsk) struct signal_struct * sig = tsk->sig; if (sig) { + unsigned long flags; + + spin_lock_irqsave(&tsk->sigmask_lock, flags); tsk->sig = NULL; + spin_unlock_irqrestore(&tsk->sigmask_lock, flags); if (atomic_dec_and_test(&sig->count)) kfree(sig); } diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 9f4014ae9ce3..1b3fb7fc94a0 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -146,6 +146,7 @@ EXPORT_SYMBOL(d_move); EXPORT_SYMBOL(d_instantiate); EXPORT_SYMBOL(d_alloc); EXPORT_SYMBOL(d_lookup); +EXPORT_SYMBOL(d_path); EXPORT_SYMBOL(__mark_inode_dirty); EXPORT_SYMBOL(get_empty_filp); EXPORT_SYMBOL(init_private_file); diff --git a/kernel/signal.c b/kernel/signal.c index 7469c0d08243..130e6371a285 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -213,10 +213,50 @@ printk(" %d -> %d\n", signal_pending(current), sig); return sig; } +/* + * Determine whether a signal should be posted or not. + * + * Signals with SIG_IGN can be ignored, except for the + * special case of a SIGCHLD. + * + * Some signals with SIG_DFL default to a non-action. + */ +static int ignored_signal(int sig, struct task_struct *t) +{ + struct signal_struct *signals; + struct k_sigaction *ka; + + /* Don't ignore traced or blocked signals */ + if ((t->flags & PF_PTRACED) || sigismember(&t->blocked, sig)) + return 0; + + signals = t->sig; + if (!signals) + return 1; + + ka = &signals->action[sig-1]; + switch ((unsigned long) ka->sa.sa_handler) { + case (unsigned long) SIG_DFL: + if (sig == SIGCONT || + sig == SIGWINCH || + sig == SIGCHLD || + sig == SIGURG) + break; + return 0; + + case (unsigned long) SIG_IGN: + if (sig != SIGCHLD) + break; + /* fallthrough */ + default: + return 0; + } + return 1; +} + int send_sig_info(int sig, struct siginfo *info, struct task_struct *t) { - struct k_sigaction *ka; unsigned long flags; int ret; @@ -227,13 +267,6 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); ret = -EINVAL; if (sig < 0 || sig > _NSIG) goto out_nolock; - - /* If t->sig is gone, we must be trying to kill the task. So - pretend that it doesn't exist anymore. */ - ret = -ESRCH; - if (t->sig == NULL) - goto out_nolock; - /* The somewhat baroque permissions check... */ ret = -EPERM; if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info))) @@ -249,9 +282,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); if (!sig) goto out_nolock; - ka = &t->sig->action[sig-1]; spin_lock_irqsave(&t->sigmask_lock, flags); - switch (sig) { case SIGKILL: case SIGCONT: /* Wake up the process if stopped. */ @@ -277,16 +308,8 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); handled immediately (ie non-blocked and untraced) and that is ignored (either explicitly or by default). */ - if (!(t->flags & PF_PTRACED) && !sigismember(&t->blocked, sig) - /* Don't bother with ignored sigs (SIGCHLD is special) */ - && ((ka->sa.sa_handler == SIG_IGN && sig != SIGCHLD) - /* Some signals are ignored by default.. (but SIGCONT - already did its deed) */ - || (ka->sa.sa_handler == SIG_DFL - && (sig == SIGCONT || sig == SIGCHLD - || sig == SIGWINCH || sig == SIGURG)))) { + if (ignored_signal(sig, t)) goto out; - } if (sig < SIGRTMIN) { /* Non-real-time signals are not queued. */ @@ -372,12 +395,18 @@ printk(" %d -> %d\n", signal_pending(t), ret); int force_sig_info(int sig, struct siginfo *info, struct task_struct *t) { - if (t->sig == NULL) + unsigned long int flags; + + spin_lock_irqsave(&t->sigmask_lock, flags); + if (t->sig == NULL) { + spin_unlock_irqrestore(&t->sigmask_lock, flags); return -ESRCH; + } if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN) t->sig->action[sig-1].sa.sa_handler = SIG_DFL; sigdelset(&t->blocked, sig); + spin_unlock_irqrestore(&t->sigmask_lock, flags); return send_sig_info(sig, info, t); } diff --git a/mm/memory.c b/mm/memory.c index fb70baa3030c..b666c0191a9c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -634,7 +634,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig * and potentially makes it more efficient. */ static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long address, int write_access, pte_t *page_table) + unsigned long address, pte_t *page_table) { pte_t pte; unsigned long old_page, new_page; @@ -914,7 +914,7 @@ static inline void handle_pte_fault(struct task_struct *tsk, flush_tlb_page(vma, address); return; } - do_wp_page(tsk, vma, address, write_access, pte); + do_wp_page(tsk, vma, address, pte); } /* diff --git a/net/Config.in b/net/Config.in index b64570308213..43e0e1705899 100644 --- a/net/Config.in +++ b/net/Config.in @@ -18,8 +18,8 @@ if [ "$CONFIG_INET" = "y" ]; then source net/ipv4/Config.in if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then # Sorry, but IPv6 as module is still invalid. -# tristate 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6 - bool 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6 + tristate 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6 +# bool 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6 if [ "$CONFIG_IPV6" != "n" ]; then source net/ipv6/Config.in fi diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index cd84989a602d..77cb218d30fb 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1290,10 +1290,12 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_ fsa.fsa_ax25.sax25_call = sk->protinfo.ax25->dest_addr; fsa.fsa_ax25.sax25_ndigis = 0; - ndigi = sk->protinfo.ax25->digipeat->ndigi; - fsa.fsa_ax25.sax25_ndigis = ndigi; - for (i = 0; i < ndigi; i++) - fsa.fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i]; + if (sk->protinfo.ax25->digipeat != NULL) { + ndigi = sk->protinfo.ax25->digipeat->ndigi; + fsa.fsa_ax25.sax25_ndigis = ndigi; + for (i = 0; i < ndigi; i++) + fsa.fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i]; + } } else { fsa.fsa_ax25.sax25_family = AF_AX25; fsa.fsa_ax25.sax25_call = sk->protinfo.ax25->source_addr; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index fb13b5e16ec4..7ee9f8744fe4 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -192,7 +192,7 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache, skb->ip_summed = 0; skb->security = 0; /* By default packets are insecure */ skb->dst = NULL; -#ifdef CONFIG_IP_FIREWALL_CHAINS +#ifdef CONFIG_IP_FIREWALL skb->fwmark = 0; #endif memset(skb->cb, 0, sizeof(skb->cb)); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6a3ae17bf589..d27720cdce23 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -292,7 +292,7 @@ static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp, /* The retransmission queue is always in order, so * we can short-circuit the walk early. */ - if(after(TCP_SKB_CB(skb)->end_seq, end_seq)) + if(!before(start_seq, TCP_SKB_CB(skb)->end_seq)) break; /* We play conservative, we don't allow SACKS to partially @@ -471,8 +471,8 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup) * to one half the current congestion window, but no less * than two segments. Retransmit the missing segment. */ - tp->dup_acks++; if (tp->high_seq == 0 || after(ack, tp->high_seq)) { + tp->dup_acks++; if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) { tp->snd_ssthresh = max(tp->snd_cwnd >> (TCP_CWND_SHIFT + 1), 2); tp->snd_cwnd = (tp->snd_ssthresh + 3) << TCP_CWND_SHIFT; @@ -1711,10 +1711,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, */ if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { - if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) { - tcp_send_ack(sk); - goto discard; - } if (len <= th->doff*4) { /* Bulk data transfer: sender */ if (len == th->doff*4) { @@ -1729,8 +1725,13 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, } } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) { /* Bulk data transfer: receiver */ - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) + if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) { + /* We must send an ACK for zero window probes. */ + if (!before(TCP_SKB_CB(skb)->seq, + tp->rcv_wup + tp->rcv_wnd)) + tcp_send_ack(sk); goto discard; + } __skb_pull(skb,th->doff*4); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index eab552c365d9..e6c9033ead24 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -500,6 +500,7 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len) } switch (type) { + case ICMP_TIME_EXCEEDED: case ICMP_SOURCE_QUENCH: return; case ICMP_PARAMETERPROB: diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a9ee64925cee..04a9e4b8b03c 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -54,6 +54,15 @@ #include #include +static int unloadable = 0; /* XX: Turn to one when all is ok within the + module for allowing unload */ + +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Cast of dozens"); +MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); +MODULE_PARM(unloadable, "i"); +#endif + extern struct proto_ops inet6_stream_ops; extern struct proto_ops inet6_dgram_ops; @@ -463,6 +472,7 @@ static struct proc_dir_entry proc_net_snmp6 = { #ifdef MODULE int ipv6_unload(void) { + if (!unloadable) return 1; /* We keep internally 3 raw sockets */ return __this_module.usecount - 3; } diff --git a/net/netsyms.c b/net/netsyms.c index f987d942513a..1af563472902 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -305,6 +305,7 @@ EXPORT_SYMBOL(tcp_transmit_skb); EXPORT_SYMBOL(tcp_connect); EXPORT_SYMBOL(tcp_make_synack); EXPORT_SYMBOL(tcp_tw_death_row_slot); +EXPORT_SYMBOL(tcp_sync_mss); EXPORT_SYMBOL(net_statistics); EXPORT_SYMBOL(xrlim_allow); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index e97d339b3ed0..dd6d593355dd 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -677,7 +677,7 @@ error: /* * Send out data on TCP socket. * FIXME: Make the sendto call non-blocking in order not to hang - * a daemon on a a dead client. Requires write queue maintenance. + * a daemon on a dead client. Requires write queue maintenance. */ static int svc_tcp_sendto(struct svc_rqst *rqstp) -- 2.39.5