----------
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
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
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
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
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).
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
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
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.
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
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
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.
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!
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
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
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
"<!--applet-->". If you want to use this, say Y here and read
Documentation/java.txt.
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
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.
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
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
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
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).
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).
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
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
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
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
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"),
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
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
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
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.
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
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).
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
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),
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).
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
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
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
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.
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)
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
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
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).
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
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
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.
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
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.
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
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),
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
/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/<number>. 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/<number>. 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
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.
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/<number>. 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
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
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
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
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
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
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
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
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
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
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,
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
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
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
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
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.
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
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
###
### Please someone fill these in.
###
+
#
# m68k-specific kernel options
# Documented by Chris Lawrence <quango@themall.net> et al.
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
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
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
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
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
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
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
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
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
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),
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
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
# 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:
#
# 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
# 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
# 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
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
This section was rewritten by
Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
using information from several people, including:
- Avery Pennraun <apenwarr@bond.net>
+ Avery Pennraun <apenwarr@worldvisions.ca>
Stephen A. Wood <saw@hallc1.cebaf.gov>
John Paul Morrison <jmorriso@bogomips.ee.ubc.ca>
Joachim Koenig <jojo@repas.de>
PC100, PC110, PC120, PC130 (8-bit cards)
PC500, PC600 (16-bit cards)
---------------------------------
- - mainly from Avery Pennarun <apenwarr@foxnet.net>. Values depicted are
- from Avery's setup.
+ - mainly from Avery Pennarun <apenwarr@worldvisions.ca>. Values depicted
+ are from Avery's setup.
- special thanks to Timo Hilbrink <timoh@xs4all.nl> 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. (?)
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.
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
---------------------------------------------------------------------------
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
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
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
+1998-09-10 Andrew Veliath <andrewtv@usa.net>
+
+ * Update version to 0.8.2
+
+ * Add SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls.
+
+1998-09-09 Andrew Veliath <andrewtv@usa.net>
+
+ * 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 <andrewtv@usa.net>
+
+ * 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 <andrewtv@usa.net>
+
+ * 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 <andrewtv@usa.net>
+
+ * Replaced packed structure accesses with standard C equivalents.
+
+1998-09-01 Andrew Veliath <andrewtv@usa.net>
+
+ * msnd_pinnacle.c: Add non-PnP configuration to driver code, which
+ will facilitate compiled-in operation.
+
+1998-08-29 Andrew Veliath <andrewtv@usa.net>
+
+ * 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 <andrewtv@usa.net>
* Update version to 0.7.2
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
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
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
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)
#include <linux/config.h>
#include <linux/module.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
#include <linux/poll.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/apm_bios.h>
#include <linux/init.h>
-#include "desc.h"
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/desc.h>
EXPORT_SYMBOL(apm_register_callback);
EXPORT_SYMBOL(apm_unregister_callback);
+++ /dev/null
-#ifndef __ARCH_DESC_H
-#define __ARCH_DESC_H
-
-struct desc_struct {
- unsigned long a,b;
-};
-
-extern struct desc_struct gdt_table[];
-extern struct desc_struct *idt, *gdt;
-
-struct Xgt_desc_struct {
- unsigned short size;
- unsigned long address __attribute__((packed));
-};
-
-#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
-#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
-
-/*
- * Entry into gdt where to find first TSS. GDT layout:
- * 0 - null
- * 1 - not used
- * 2 - kernel code segment
- * 3 - kernel data segment
- * 4 - user code segment
- * 5 - user data segment
- * 6 - not used
- * 7 - not used
- * 8 - APM BIOS support
- * 9 - APM BIOS support
- * 10 - APM BIOS support
- * 11 - APM BIOS support
- * 12 - TSS #0
- * 13 - LDT #0
- * 14 - TSS #1
- * 15 - LDT #1
- */
-#define FIRST_TSS_ENTRY 12
-#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
-#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
-#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
-#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
-#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
-#define store_TR(n) \
-__asm__("str %%ax\n\t" \
- "subl %2,%%eax\n\t" \
- "shrl $4,%%eax" \
- :"=a" (n) \
- :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
-
-extern void set_intr_gate(unsigned int irq, void * addr);
-extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
-extern void set_tss_desc(unsigned int n, void *addr);
-
-/*
- * This is the ldt that every process will get unless we need
- * something other than this.
- */
-extern struct desc_struct default_ldt;
-
-#endif
#include <asm/uaccess.h>
#include <asm/pgtable.h>
-
-#include "desc.h"
+#include <asm/desc.h>
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
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();
}
-
#include <asm/smp.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
+#include <asm/desc.h>
#include "irq.h"
-#include "desc.h"
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
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)
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);
}
}
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/ldt.h>
-
-#include "desc.h"
+#include <asm/desc.h>
static int read_ldt(void * ptr, unsigned long bytecount)
{
#include <asm/io.h>
#include <asm/ldt.h>
#include <asm/processor.h>
+#include <asm/desc.h>
#ifdef CONFIG_MATH_EMULATION
#include <asm/math_emu.h>
#endif
#include "irq.h"
-#include "desc.h"
spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
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;
}
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;
}
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;
}
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;
}
switch (edx) {
case 0x40:
cache_size = 0;
+ break;
case 0x41:
cache_size = 128;
&& (cpu_models[i].x86 == 6)
&& (c->x86_model == 5)
&& (c->x86_cache_size == 0)) {
- p = "Celeron";
+ p = "Celeron (Covington)";
}
}
#include <asm/spinlock.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
-
-#include "desc.h"
+#include <asm/desc.h>
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
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;
}
#include <linux/signal.h>
#include <asm/uaccess.h>
+#include <asm/desc.h>
#include "fpu_system.h"
#include "fpu_emu.h"
#include <linux/stddef.h>
#include <asm/uaccess.h>
+#include <asm/desc.h>
#include "fpu_system.h"
#include "exception.h"
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
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;
* 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 <linux/module.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/major.h>
+
#include <linux/init.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_BLK_DEV_LOOP_DES
-# /*nodep*/ include <linux/des.h>
-#endif
-
-#ifdef CONFIG_BLK_DEV_LOOP_IDEA
-# /*nodep*/ include <linux/idea.h>
-#endif
-
-#include <linux/loop.h> /* must follow des.h */
+#include <linux/loop.h>
#define MAJOR_NR LOOP_MAJOR
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
*/
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;
char zero_buf[1] = { 0 };
ssize_t retval;
mm_segment_t old_fs;
+ struct inode *inode;
file = lo->lo_backing_file;
if (file == NULL) {
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) {
lo->lo_dentry = file->f_dentry;
lo->lo_dentry->d_count++;
lo->transfer = NULL;
+ lo->ioctl = NULL;
figure_loop_size(lo);
out_putf:
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;
dput(dentry);
}
+ lo->transfer = NULL;
+ lo->ioctl = NULL;
lo->lo_device = 0;
lo->lo_encrypt_type = 0;
lo->lo_offset = 0;
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;
}
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);
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,
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;
}
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;
static int lo_release(struct inode *inode, struct file *file)
{
struct loop_device *lo;
- int dev;
+ int dev, err = 0;
if (!inode)
return 0;
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 = {
#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)) {
}
#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;
}
#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
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/io.h>
/* 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);
}
end_do_cdu31a_request:
- cli();
+ spin_lock_irq(&io_request_lock);
#if 0
/* After finished, cancel any pending operations. */
abort_read();
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
/* #include <linux/ucdrom.h> */
end_request(0);
continue;
}
+ spin_unlock_irq(&io_request_lock);
error=0;
for (i=0; i<CURRENT->nr_sectors; i++) {
int e1, e2;
debug(("cm206_request: %d %d\n", e1, e2));
}
}
+ spin_lock_irq(&io_request_lock);
end_request(!error);
}
}
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/io.h>
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)
{
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)
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
sbpcd_end_request(req, 1);
+ spin_lock_irq(&io_request_lock); /* FIXME!!!! */
goto request_loop;
}
xnr, req, req->sector, req->nr_sectors, jiffies);
#endif
sbpcd_end_request(req, 1);
+ spin_lock_irq(&io_request_lock); /* FIXME!!!! */
goto request_loop;
}
}
#endif
sbpcd_end_request(req, 0);
sbp_sleep(0); /* wait a bit, try again */
+ spin_lock_irq(&io_request_lock); /* FIXME!!!! */
goto request_loop;
}
/*==========================================================================*/
{
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))
{
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);
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
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)
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))
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.
*/
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;
}
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;
}
#
# 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
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:
#define SETCONF writeb(lp->config,_CONFIG)
static const char *version =
-"arc-rimi.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+"arc-rimi.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
* *
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:
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
*/
static const char *version =
- "arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
#include <linux/module.h>
#include <linux/config.h>
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) {
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
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);
}
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);
}
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:
static const char *version =
- "com20020.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "com20020.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
* *
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:
static const char *version =
- "com90io.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "com90io.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
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:
#define ARCRESET inb(_RESET)
static const char *version =
-"com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+"com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
/****************************************************************************
#include <linux/nubus.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/hwtest.h>
+#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
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);
+
\f
#define WD_START_PG 0x00 /* First page of TX buffer */
#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
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<<scale])==0)
+ if(hwreg_present(&ptr[0x0D<<scale])==0)
return -EIO;
- if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+ if(hwreg_present(&ptr[0x0D<<scale])==0)
return -EIO;
ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
regd=ptr[0x0D<<scale];
return -1;
}
+/*
+ * Memory probe for 8390 cards
+ */
+
+int apple_8390_mem_probe(volatile unsigned short *p)
+{
+ int i, j;
+ /*
+ * Algorithm.
+ * 1. Check each block size of memory doesn't fault
+ * 2. Write a value to it
+ * 3. Check all previous blocks are unaffected
+ */
+
+ for(i=0;i<2;i++)
+ {
+ volatile unsigned short *m=p+4096*i;
+ /* Unwriteable - we have a fully decoded card and the
+ RAM end located */
+
+ if(hwreg_present(m)==0)
+ return 8192*i;
+
+ *m=0xA5A0|i;
+
+ for(j=0;j<i;j++)
+ {
+ /* Partial decode and wrap ? */
+ if(p[4096*j]!=(0xA5A0|j))
+ {
+ /* This is the first misdecode, so it had
+ one less page than we tried */
+ return 8192*i;
+ }
+ j++;
+ }
+ /* Ok it still decodes.. move on 8K */
+ }
+ /*
+ * We don't look past 16K. That should cover most cards
+ * and above 16K there isnt really any gain.
+ */
+ return 16384;
+ }
+
/*
* Probe for 8390 cards.
* The ns8390_probe1() routine initializes the card and fills the
/* Apple, Farallon, Asante */
if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
{
+ int memsize;
+
dev->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)
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;
{
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;
}
}
+
static void sane_block_output(struct device *dev, int count, const unsigned char *buf,
int start_page)
{
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"
/*
- * $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
#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)
{
#include <linux/init.h>
#include <asm/uaccess.h>
-#define dmascc_dev_init NULL
+#define SET_DEV_INIT(x)
#endif
#ifdef MODULE
-MODULE_AUTHOR("Klaus Kudielka <oe1kib@oe1xtu.ampr.org>");
+MODULE_AUTHOR("Klaus Kudielka");
MODULE_DESCRIPTION("Driver for high-speed SCC boards");
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
/* 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;
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;
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;
}
/* 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) */
/* 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 */
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",
#include <asm/setup.h>
#include <asm/system.h>
#include <asm/page.h>
+#include <asm/hwtest.h>
/* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */
#include <asm/macintosh.h>
+#include <linux/proc_fs.h>
+
#undef LCIII_WEIRDNESS
* -- 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
{
unsigned char *p=*ptr;
- if(len>8192)
+ if(len>65536)
printk("rewind of %d!\n", len);
while(len)
{
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)
{
{
rp--;
- if(!nubus_hwreg_present(rp))
+ if(!hwreg_present(rp))
continue;
dp=*rp;
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)
{
/*
nubus_init_via();
printk("Scanning nubus slots.\n");
nubus_probe_bus();
+ proc_register(&proc_root, &proc_nubus);
}
+
+
\ No newline at end of file
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)' \
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
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
-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
#include "AM53C974.h"
#endif
-#ifdef CONFIG_SCSI_PPA
-#include "ppa.h"
-#endif
-
#ifdef CONFIG_SCSI_SUNESP
#include "esp.h"
#endif
#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 $";
*/
#ifdef CONFIG_SCSI_AM53C974
AM53C974,
#endif
-#ifdef CONFIG_SCSI_PPA
- PPA,
-#endif
#ifdef CONFIG_SCSI_SUNESP
SCSI_SPARC_ESP,
#endif
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
--- /dev/null
+/* 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 <linux/config.h>
+
+/* 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 <linux/blk.h>
+#include <asm/io.h>
+#include <linux/parport.h>
+#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;
+}
+
--- /dev/null
+/* 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 <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/tqueue.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#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 */
#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 */
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"
*/
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;
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
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);
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
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);
#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);
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);
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;
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 */
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);
ppa_disconnect(host_no);
return 1; /* Try again in a jiffy */
}
- }
cmd->SCp.phase++;
}
}
/*
- * 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.
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
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)
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;
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;
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");
#ifndef _PPA_H
#define _PPA_H
-#define PPA_VERSION "1.39a"
-
-/* Use the following to enable certain chipset support
- * Default is PEDANTIC = 3
- */
-#include <linux/config.h> /* 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)
*
* [ 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 ----- */
#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)
#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);
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 */
# 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. */
#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
*
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
+# 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
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,
int sound_alloc_mididev(void)
{
+#ifdef CONFIG_MIDI
int i = register_sound_midi(&oss_sound_fops);
if(i==-1)
return i;
if(i>=num_midis)
num_midis = i + 1;
return i;
+#else
+ return (-1);
+#endif
}
int sound_alloc_synthdev(void)
#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
* 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 $
*
********************************************************************/
# include <asm/uaccess.h>
# include <asm/spinlock.h>
#endif
+#include <asm/irq.h>
#include "msnd.h"
#define LOGNAME "msnd"
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)
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))
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;
}
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;
}
int i;
if (len % 3 != 0) {
-
printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");
return -EINVAL;
}
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;
}
{
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
* 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
#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
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;
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);
/* 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 *);
* 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
* 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 $
*
********************************************************************/
#ifndef LINUX20
# include <linux/init.h>
#endif
+#include <asm/irq.h>
#include "sound_config.h"
#include "sound_firmware.h"
#ifdef MSND_CLASSIC
#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
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:
}
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:
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;
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:
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;
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;
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
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
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 */
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)
#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
#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 */
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));
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;
{
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 */
}
#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);
#ifndef LINUX20
err =
#endif
- dsp_close();
+ dsp_release(file);
}
else if (minor == dev.mixer_minor) {
/* nothing */
#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;
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;
{
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;
}
{
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);
wake_up_interruptible(&dev.writeflush);
#endif
}
+ clear_bit(F_WRITING, &dev.flags);
}
if (test_bit(F_WRITEBLOCK, &dev.flags))
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);
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;
(*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;
printk(KERN_ERR LOGNAME ": I/O port conflict\n");
return -ENODEV;
}
-
request_region(dev.io, dev.numio, "probing");
if (reset_dsp() < 0) {
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;
}
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();
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);
}
#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);
}
#endif
-__initfunc(static int initialize(void))
+static int initialize(void)
{
int err, timeout;
reset_proteus();
#endif
-
if ((err = init_sma()) < 0) {
printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
return err;
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) {
}
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);
unregister_sound_dsp(dev.dsp_minor);
msnd_unregister(&dev);
}
+#endif
static void mod_inc_ref(void)
{
#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
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 ||
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;
}
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;
}
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;
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
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;
msnd_fifo_free(&dev.DAPF);
msnd_fifo_free(&dev.DARF);
-
}
#endif
* 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
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)
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);
#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)
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;
MODULE_PARM(pas2, "i");
MODULE_PARM(sm_games, "i");
-static int sbmpu = 0;
-
void *smw_free = NULL;
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
{
}
-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;
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);
}
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:
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)
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;
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))
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 */
void unload_trix_sb(struct address_info *hw_config)
{
#ifdef CONFIG_SBDSP
- sb_dsp_unload(hw_config);
+ sb_dsp_unload(hw_config, mpu);
#endif
}
struct address_info sb_config;
struct address_info mpu_config;
-static int mpu = 0;
static int sb = 0;
static int fw_load;
* 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
/***********************************************************************
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.
**********************************************************************/
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.
*/
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",
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
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
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
/* 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.
*/
{
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) {
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,
entry += (*p++ - '0');
}
}
+
+ if (entry > sbi->max_ptys)
+ return -ENOENT;
dentry->d_inode = sbi->inodes[entry];
if ( dentry->d_inode )
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;
+1998-09-11 a sun <asun@purgatorius.zoology.washington.edu>
+
+ * mdb.c: altered mdb struct to reflect hfs plus usage.
+
+1998-08-27 a sun <asun@purgatorius.zoology.washington.edu>
+
+ * file.c, file_hdr.c, file_cap.c: dealt with the remaining
+ copy_to/from_user() error cases.
+
+1998-08-26 a sun <asun@purgatorius.zoology.washington.edu>
+
+ * 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 <asun@zoology.washington.edu>
* inode.c, sysdep.c
*
* 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 ================*/
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;
}
}
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;
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)) {
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);
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;
/* 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);
}
* 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 */
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 */
* 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);
}
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,
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)
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;
}
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;
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();
/***** 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;
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();
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");
}
/***** 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;
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);
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)
: (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);
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:
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)
: (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;
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);
/* 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 */
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;
}
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,
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,
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);
* 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) {
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");
}
/* 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);
/* 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;
}
/* 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;
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;
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;
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;
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;
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;
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;
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/init.h>
-
+#include <asm/byteorder.h>
#include <asm/uaccess.h>
#if 0
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);
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;
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;
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;
{
struct super_block * sb;
unsigned int i;
- unsigned long * p;
- unsigned long block;
+ u32 * p;
+ u32 block;
struct buffer_head * bh;
int retry = 0;
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;
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;
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;
#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.
* 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,
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);
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
* 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;
* 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.
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)
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) {
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.
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] == '.') {
}
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.
* 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);
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;
}
Printk ((KERN_DEBUG
"UMSDOS_lookup: converting -ENOENT to negative\n"));
d_add (dentry, NULL);
+ dentry->d_op = &umsdos_dentry_operations;
ret = 0;
}
return ret;
* 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;
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;
}
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
{
/* 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;
}
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
-
};
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;
}
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;
}
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;
}
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);
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;
}
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;
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
d->mode = le16_to_cpu (d->mode);
#endif
return ret;
-
}
{
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;
}
/*
* 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)
{
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;
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 "));
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.
}
}
}
+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:
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;
}
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) */
#include <linux/umsdos_fs.h>
#include <linux/list.h>
+extern struct dentry_operations umsdos_dentry_operations;
extern struct inode_operations umsdos_rdir_inode_operations;
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;
,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");
}
}
-/*
- * 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
/*
* 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);
}
-/* #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"));
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);
}
-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
*/
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);
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)) {
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));
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;
}
/* 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;
}
*/
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",
* 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;
* 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;
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;
*
* 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.
*
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)
/* 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;
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);
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 ();
/* 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;
}
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));
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;
}
* 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...
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;
}
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;
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);
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);
}
*/
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);
}
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;
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;
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 */
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;
}
/*
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);
}
/*
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) {
}
}
+ /* 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;
/* 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;
/* 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;
*/
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));
}
/*
/* 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:
* 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
*/
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);
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)) {
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:
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;
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;
extern struct inode *pseudo_root;
+extern struct dentry_operations umsdos_dentry_operations;
struct RDIR_FILLDIR {
void *dirbuf;
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) {
}
}
out:
+ /* always install our dentry ops ... */
+ dentry->d_op = &umsdos_dentry_operations;
PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
return ret;
}
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;
/* 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;
}
* 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
* 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
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;
}
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);
return dentry;
}
-
+/* needed to patch the file structure */
static struct file_operations umsdos_symlink_operations =
{
NULL, /* lseek - default */
struct inode_operations umsdos_symlink_inode_operations =
{
- NULL, /* default file operations */
+ NULL, /* default file operations (none) */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
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 */
-
};
+
--- /dev/null
+#ifndef __ARCH_DESC_H
+#define __ARCH_DESC_H
+
+struct desc_struct {
+ unsigned long a,b;
+};
+
+extern struct desc_struct gdt_table[];
+extern struct desc_struct *idt, *gdt;
+
+struct Xgt_desc_struct {
+ unsigned short size;
+ unsigned long address __attribute__((packed));
+};
+
+#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
+#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
+
+/*
+ * Entry into gdt where to find first TSS. GDT layout:
+ * 0 - null
+ * 1 - not used
+ * 2 - kernel code segment
+ * 3 - kernel data segment
+ * 4 - user code segment
+ * 5 - user data segment
+ * 6 - not used
+ * 7 - not used
+ * 8 - APM BIOS support
+ * 9 - APM BIOS support
+ * 10 - APM BIOS support
+ * 11 - APM BIOS support
+ * 12 - TSS #0
+ * 13 - LDT #0
+ * 14 - TSS #1
+ * 15 - LDT #1
+ */
+#define FIRST_TSS_ENTRY 12
+#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
+#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
+#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
+#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
+#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
+#define store_TR(n) \
+__asm__("str %%ax\n\t" \
+ "subl %2,%%eax\n\t" \
+ "shrl $4,%%eax" \
+ :"=a" (n) \
+ :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
+
+extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
+extern void set_tss_desc(unsigned int n, void *addr);
+
+/*
+ * This is the ldt that every process will get unless we need
+ * something other than this.
+ */
+extern struct desc_struct default_ldt;
+
+#endif
#ifndef _LINUX_LOOP_H
#define _LINUX_LOOP_H
+#include <linux/kdev_t.h>
+
/*
* include/linux/loop.h
*
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 */
};
/*
- * 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')
*/
PROC_CPUINFO,
PROC_PCI,
PROC_MCA,
+ PROC_NUBUS,
PROC_SELF, /* will change inode # */
PROC_NET,
PROC_SCSI,
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.
#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:
/* 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.
/* 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 <linux/stat.h> :
/* 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 */
* 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
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. */
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,
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);
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);
#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
{
#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
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 {
/* 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
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);
}
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);
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;
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)))
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. */
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. */
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);
}
* 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;
flush_tlb_page(vma, address);
return;
}
- do_wp_page(tsk, vma, address, write_access, pte);
+ do_wp_page(tsk, vma, address, pte);
}
/*
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
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;
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));
/* 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
* 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;
*/
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) {
}
} 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);
}
switch (type) {
+ case ICMP_TIME_EXCEEDED:
case ICMP_SOURCE_QUENCH:
return;
case ICMP_PARAMETERPROB:
#include <asm/uaccess.h>
#include <asm/system.h>
+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;
#ifdef MODULE
int ipv6_unload(void)
{
+ if (!unloadable) return 1;
/* We keep internally 3 raw sockets */
return __this_module.usecount - 3;
}
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);
/*
* 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)