D: Initial implementation of VC's, pty's and select()
N: James B. MacLean
-E: jmaclean@fox.nstn.ns.ca
+E: macleajb@ednet.ns.ca
+W: http://www.ednet.ns.ca/~macleajb/dosemu.html
D: Coordinator of DOSEMU releases
D: Program in DOSEMU
S: PO BOX 220, HFX. CENTRAL
N: Stefan Reinauer
E: stepan@home.culture.mipt.ru
W: http://home.culture.mipt.ru/~stepan
-D: Modulized affs and ufs. Minor fixes.
+D: Modularized affs and ufs. Minor fixes.
S: Rebmannsweg 34h
S: 79539 Loerrach
S: Germany
testing is not yet high enough for general use. This is usually
known as the "alpha-test" phase amongst developers. If a feature is
currently in alpha-test, then the developers usually discourage
- widespread use of this feature by the general public to avoid
- "Why doesn't this work?" type mail messages. However, active testing
- and and detailed bug reports from people familiar with the kernel's
- internals are usually welcomed by the developers. Unless you intend
- to help test and develop a feature or driver that falls into this
- category, you should probably say N here, which will cause this
+ uninformed widespread use of this feature by the general public to
+ avoid "Why doesn't this work?" type mail messages. However, active
+ testing and use of these systems is welcomed. Just be aware that it
+ may not meet the normal level of reliability or it may fail to work
+ in some special cases. Detailed bug reports from people familiar with
+ the kernel internals are usually welcomed by the developers.
+
+ Unless you intend to help test and develop a feature or driver that
+ falls into this category, or you have a situation that requires using
+ these features you should probably say N here, which will cause this
configure script to present you with fewer choices. If you say Y here,
you will be offered the choice of using features or drivers that are
currently considered to be in the alpha-test phase.
net is inspected by the firewall first. If you want to configure
your Linux box as a firewall for a local network, say Y here. If
your local network is TCP/IP based, you will have to say Y to "IP:
- firewalling", below. Chances are that you don't want this, so say N.
+ firewalling", below. Chances are that you should use this on any
+ machine being run as a router and not on a host.
Sun floppy controller support
CONFIG_BLK_DEV_SUNFD
option to the kernel 3) passing the "mem=4M" option to the kernel
(thereby disabling all but the first 4M of RAM) 4) disabling the
cache from your BIOS settings 5) exchanging RAM chips 6) exchanging
- the motherboard 7) committing suicide.
+ the motherboard.
Using SRM as bootloader
CONFIG_ALPHA_SRM
IP: multicasting
CONFIG_IP_MULTICAST
This is code for addressing several networked computers at once,
- enlarging your kernel by about 2 kB. Some versions of gated, the
- program which constantly updates a networked computer's routing
- tables, require that this option be compiled in. You also need
+ enlarging your kernel by about 2 kB. If you are using gated, the
+ to update your computer's routing tables and are using RIP2 or OSPF
+ you will need to have this option compiled in. You also need
multicasting if you intend to participate in the MBONE, a high
bandwidth network on top of the internet which carries audio and
video broadcasts. More information about the MBONE is on the WWW at
Some Linux network drivers use a technique called copy and checksum
to optimize host performance. For a machine which is forwarding most
packets to another host this is however a loss. This parameter turns
- off copy and checksum from devices. It may also do other changes in
+ off copy and checksum from devices. It may make other changes in the
future.
IP: firewalling
CONFIG_IP_FIREWALL
- A firewall is a computer which protects a local network from the
- rest of the internet: all traffic to and from computers on the local
- net is inspected by the firewall first. If you want to configure
- your Linux box as a firewall for a local TCP/IP based network, say Y
- here. This will enlarge your kernel by about 2kB. You will need to
- read the FIREWALL-HOWTO, available via ftp (user: anonymous) in
- sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will have to use
- the ipfw tool from the net-tools package, available via ftp (user:
- anonymous) from
- ftp.linux.org.uk:/pub/linux/Networking/PROGRAMS/NetTools, or
- preferably ipfwadm from ftp.xos.nl:/pub/linux/ipfwadm/. These
- programs allow selective blocking of internet traffic based on type,
- origin and destination. You need to enable IP firewalling in order
- to be able to use IP masquerading (i.e. local computers can chat
- with an outside host, but that outside host is made to think that it
- is talking to the firewall box. Makes the local network completely
- invisible). Chances are that you don't want this, so say N.
+ If you want to configure your Linux box as a firewall for a local
+ TCP/IP based network, say Y here. This will enlarge your kernel by
+ about 2kB. You may need to read the FIREWALL-HOWTO, available via
+ ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also,
+ you will need the ipfwadm tool to allow selective blocking of internet
+ traffic based on type, origin and destination. You need to enable IP
+ firewalling in order to be able to use IP masquerading (i.e. local
+ computers can chat with an outside host, but that outside host is
+ made to think that it is talking to the firewall box. Makes the local
+ network completely invisible) or to use the ip packet accounting to see
+ what is using all your network bandwidth.
IP: accounting
CONFIG_IP_ACCT
firewalling. The data is accessible with "cat /proc/net/ip_acct", so
you want to say Y to the /proc filesystem below, if you say Y
here. To specify what exactly should be recorded, you need the tool
- ipfw from the net-tools package, available via ftp (user:
- anonymous) from
- ftp.linux.org.uk:/pub/Linux/Networking/PROGRAMS/NetTools. Also, you
- might want to have a look at the net-acct package, available via ftp
- (user: anonymous) from
- sunsite.unc.edu:/pub/Linux/system/Network/management. Most people
- say N, however.
+ ipfwadm (available from ftp.xos.nl if you don't have a copy already).
IP: tunneling
CONFIG_NET_IPIP
mobile IP facilities (which effectively are doing that). Enabling this
option will produce two modules ( = code which can be inserted in
and removed from the running kernel whenever you want), one
- encapsulator and one decapsulator. This is still alpha code, which
- means that it need not be completely stable. You can read details in
+ encapsulator and one decapsulator. You can read details in
drivers/net/README.tunnel. Most people can say N.
IP: firewall packet logging
CONFIG_INET_PCTCP
If you have been having difficulties telneting to your Linux machine
from a DOS system that uses (broken) PC/TCP networking software (all
- versions up to OnNet 2.0), try enabling this option. Everyone else
- says N.
+ versions up to OnNet 2.0) over your local ethernet try enabling this
+ option. Everyone else says N. People having problems with NCSA telnet
+ should see the file linux/Documentation/networking/ncsa-telnet.
Reverse ARP
CONFIG_INET_RARP
we adjust to a smaller size. This is good, so most people say
N. However, some versions of DOS NCSA telnet (and other software)
are broken and can only connect to your Linux machine if you say Y
- here.
+ here. See also Documentation/networking/ncsa-telnet for the location
+ of fixed NCSA telnet clients.
Disable NAGLE algorithm (normally enabled)
CONFIG_TCP_NAGLE_OFF
decide how to forward the frame. However, there is a feature of the
IP protocol that allows to specify the full route for a given frame
already at its origin. A frame with such a fully specified route is
- called "source routed". The question now is whether we should honor
+ called "source routed". The question now is whether we should honour
these route requests when such frames arrive, or if we should
- drop all those frames instead. Honoring can introduce security
- problems (and is not required by the IP specification), and hence it
- is recommended to say Y here unless you really know what you're
- doing.
+ drop all those frames instead. Honouring them can introduce security
+ problems (and is rarely a useful feature), and hence it is recommended
+ that you say Y here unless you really know what you're doing.
IP: Allow large windows (not recommend if <16Mb of memory)
CONFIG_SKB_LARGE
- This option can speed up network performance. It works by increasing
- the size of socket buffers, thereby reducing overhead but increasing
- memory usage. Say N if you have less than 16Mb of RAM, otherwise Y.
- Note for machines with more that 64MB of RAM: in order for the kernel
- to be able to use the memory above 64MB, pass the command line option
- "mem=XXXM" (where XXX is the memory size in megabytes) to your
- kernel. See the documentation of your boot loader (lilo or loadlin)
- about how to pass options to the kernel. The lilo procedure is also
- explained in the SCSI-HOWTO, available via ftp (user: anonymous) in
- sunsite.unc.edu:/pub/Linux/docs/HOWTO. You also need at least 512kB
- of RAM cache if you have more than 64MB of RAM.
+ 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.
The IPX protocol
CONFIG_IPX
Appletalk DDP
CONFIG_ATALK
- Appletalk is the way Apple computers speak to each other on an
- Ethernet (Apple calls it EtherTalk) network. If your linux box is
- connected to such a network and you want to join the conversation,
+ Appletalk is the way Apple computers speak to each other on a
+ network. EtherTalk is the name used for appletalk over ethernet and
+ Localtalk is appletalk over the apple serial links. If your linux box
+ is connected to such a network and you want to join the conversation,
say Y. You will need to use the netatalk package so that your Linux
box can act as a print and file server for macs as well as access
appletalk printers. Check out
want). If you want to compile it as a module, say M here and read
Documentation/modules.txt. I hear that the GNU boycott of Apple is
over, so even politically correct people are allowed to say Y here.
+ At the time the kernel is released the localtalk drivers are not
+ yet ready to ship. The kernel however supports localtalk and when
+ such drivers become available all you will need to do is download
+ and install the localtalk driver.
Amateur Radio AX.25 Level 2
CONFIG_AX25
use a low speed TNC (a Terminal Node Controller acts as a kind of
modem connecting your computer's serial port to your radio's
microphone input and speaker output) supporting the KISS protocol or
- the much faster Ottawa PI card (to enable support for this card,
- you'll have to answer Y to the question about ALPHA test drivers,
- below) or the Z8530 SCC cards; the latter two require an additional
- radio modem. In order to use AX.25, you need to get a set of
- supporting software tools via ftp (user: anonymous) from
- sunacm.swan.ac.uk:/pub/misc/Linux/Radio/. 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
- HAM-HOWTO, available via ftp (user: anonymous) in
- sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also want to check
- out the file Documentation/networking/ax25.txt in the kernel
- source. More information about digital amateur radio in general is
- on the WWW at
+ the various SCC cards that are supported by the Ottowa PI, the
+ Gracilis Packetwin and the generic Z8530 driver.
+ At the moment there is no driver for the Baycom modem serial and parallel
+ port hacks although one is being written (see the HAM-HOWTO). The other
+ baycom cards (SCC) are supported by the Z8530 driver.
+ In order to use AX.25, you need to get a set 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 HAM-HOWTO, available via
+ ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You
+ might also want to check out the file Documentation/networking/ax25.txt
+ in the kernel source. More information about digital amateur radio
+ in general is on the WWW at
http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
(To browse the WWW, you need to have access to a machine on the
Internet that has one of the programs lynx, netscape or
- Mosaic). AX.25 support is actively being developed, so it's best to
- get the very latest 1.3 kernel if you intend to use this.
+ Mosaic).
Amateur Radio NET/ROM
CONFIG_NETROM
http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
(To browse the WWW, you need to have access to a machine on the
Internet that has one of the programs lynx, netscape or
- Mosaic). Amateur radio support is actively being developed, so you
- might want to get the very latest 1.3 kernel if you intend to use
- this.
+ Mosaic).
AX.25 over Ethernet
CONFIG_BPQETHER
ethernet bridge, which means that the different ethernet segments it
is connected to will appear as one ethernet to the
participants. Several such bridges can work together to create even
- larger networks of ethernets using a cool spanning tree
- algorithm. Note that if your box acts as a bridge, it probably
- contains several ethernet devices, but the kernel is not able to
- recognize more than one at boot time without help; for details read
- the Multiple-Ethernet-mini-HOWTO, available via ftp (user:
+ larger networks of ethernets using the IEEE802.1 spanning tree
+ algorithm. As this is a standard Linux bridges will interwork properly
+ with other third party bridge products. Note that if your box acts as
+ a bridge, it probably contains several ethernet devices, but the kernel
+ is not able to recognize more than one at boot time without help; for
+ details read the Multiple-Ethernet-mini-HOWTO, available via ftp (user:
anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The
Bridging code is still in test. If unsure, say N.
The bridge configuration tools are available via ftp from shadow.cabi.net.
Dummy net driver support
CONFIG_DUMMY
- This is essentially a loopback device (i.e. traffic you send to this
- device is immediately returned back to you) with a configurable IP
+ This is essentially a bit-bucket device (i.e. traffic you send to
+ this device is consigned into oblivion) with a configurable IP
address different from the usual 127.0.0.1. It is most commonly used
in order to make your currently inactive SLIP address seem like a
real address for local programs. If you use SLIP or PPP, you might
RELCOM line fill and keepalive monitoring. Ideal on poor quality
analogue lines.
+Six bit SLIP encapsulation
+CONFIG_SLIP_MODE_SLIP6
+ Just occasionally you may need to run IP over hostile serial networks that
+ don't pass all control characters or are only seven bit. This adds an
+ extra mode you can use with SLIP "slip6" which contains only the normal
+ ascii symbols. Its good enough, for example, to run IP over the async
+ ports of a Camtec JNT Pad.
+
Radio network interfaces
CONFIG_NET_RADIO
Radio based interfaces for Linux. Both amateur radio (AX.25) and other
WIC (Radio IP bridge)
CONFIG_WIC
- Don't know what this is; has something to do with the parallel
- port. Say N and that's that. But if you want to compile it 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. :-)
+ Support for the WIC parallel port radio bridge. You'll probably want
+ to say N.
-Z8530 SCC kiss emulation driver for AX.2
+Z8530 SCC kiss emulation driver for AX.25
CONFIG_SCC
These cards are used to connect your Linux box to an amateur radio
and communicate with other computers. If you want to use this, read
from the running kernel whenever you want). If you want to compile
it as a module, say M here and read Documentation/modules.txt.
+Ethernet (10 or 100Mbit)
+CONFIG_NET_ETHERNET
+ Say yes if you want to select support for ethernet cards.
+
Sun LANCE Ethernet support
CONFIG_SUN_LANCE
This is support for lance ethernet cards on Sun workstations such as
more than one network card under linux, read the
Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+ Important: There have been many reports that, with some motherboards
+ mixing an SMC Ultra and an Adaptec AHA1542 SCSI card causes corruption
+ problems with many operating systems.
SMC 9194 Support
CONFIG_SMC9194
If you have a network (ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available via ftp (user: anonymous) in
sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, consider buying a new
- card, since the 3c501 is buggy and obsolete and the driver is
- unsupported. This driver is also available as a module ( = code
- which can be inserted in and removed from the running kernel
- whenever you want). If you want to compile it as a module, say M
- here and read Documentation/modules.txt as well as
- Documentation/networking/net-modules.txt. If you plan to use more
- than one network card under linux, read the
- Multiple-Ethernet-mini-HOWTO, available from
- sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+ card, since the 3c501 is slow and obsolete. This driver is also
+ available as a module ( = code which can be inserted in and removed
+ from the running kernel whenever you want). If you want to compile
+ it as a module, say M here and read Documentation/modules.txt as well
+ as Documentation/networking/net-modules.txt. If you plan to use more
+ than one network card under linux, read the
+ Multiple-Ethernet-mini-HOWTO, available from
+ sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini - and don't use 3c501s.
3c503 support
CONFIG_EL2
use it. Probably this is only useful for multi user systems. If
unsure, say N.
+Mandatory lock support
+CONFIG_LOCK_MANDATORY
+ Mandatory locking is used by some System 5 style database applications.
+ To use this option safely you must have newer NFS daemons, new samba,
+ new netatalk, new mars-nwe and other file servers. At the time of
+ writing none of these are available. Unless you need this feature say
+ N.
+
Standard (minix) fs support
CONFIG_MINIX_FS
Minix is a simple operating system used in many classes about
\documentclass{article}
-\def\version{$Id: cdrom-standard.tex,v 0.4 1996/04/17 20:46:34 david Exp $}
+\def\version{$Id: cdrom-standard.tex,v 0.5 1996/05/12 22:00:00 emoenke Exp $}
\evensidemargin=0pt
\oddsidemargin=0pt
\item The large list of different hardware devices available for the popular
IBM PC-architecture,
\item The open design of the operating system, such that everybody can
-write a driver for Linux.
+write a driver for Linux (source code examples).
\end{itemize}
The vast choice and openness has lead not only to a wide support of
-hardware devices, but also to a certain divergence in
-behavior. Especially for \cdrom\ devices, the way a particular drive
-reacts to a `standard' $ioctl()$ call varies a lot from one brand
-to another.
-
-Undoubtedly, this has a reason. Since the beginning of the \cdrom,
-many different interfaces developed. Most of them had proprietary
-interfaces, which means that a separate driver had to be written for
-each new type of interface. Nowadays, all new \cdrom\ types are either
-ATAPI/IDE or SCSI. But history has delivered us \cdrom\ support for
-some 10 or so different interfaces. Not all drives have the same
-capabilities, and all different interfaces use different i/o formats
-for the data. For the interfacing with the \linux\ operating system
-and software, this has lead to a rather wild set of commands and data
-formats. Presumably, every \cdrom\ device drive author has added his
-own set of ioctl commands and used a format reminiscent of the
-underlying hardware. Any structure is lost.
+hardware devices, but also to a certain divergence in behavior. Especially
+for \cdrom\ devices, the way a particular drive reacts to a `standard'
+$ioctl()$ call varies a lot from one brand to another; until today, the
+\linux \cdrom\ driver writers kept away from wilderness by a good practice:
+to evolve a new driver by copying, understanding and changing an existing
+one.
+
+Since the beginning of the \cdrom, many different interfaces developed.
+Some of them had their own proprietary design (Sony, Mitsumi, Panasonic),
+other manufacturers adopted an existing electrical interface and changed
+the functionality (CreativeLabs/SoundBlaster, Teac, Funai) or simply adapted
+their drives to one or more of the already existing electrical interfaces
+(Aztech, Sanyo, Funai, Vertos, Longshine, Optics Storage and most of the
+`NoName' manufacturers).
+In cases where a new drive really brought his own interface or used his
+own command set and flow control scheme, either a separate driver had to
+be written, or an existing driver had to get enhanced.
+
+Nowadays, almost all new \cdrom\ types are either ATAPI/IDE or SCSI;
+it is very unlikely that any manufacturer still will create a new
+interface, and new drives for the existing proprietary interfaces are
+getting rare.
+But history has delivered us \cdrom\ support for many different interfaces.
+
+Some of the \linux\ \cdrom\ driver writers look at the existing standard
+which is expressed through <linux/cdrom.h> as to a rather wild set of
+commands and data formats and feel that any structure is lost, and from
+this point of view, this documentation shall help to achieve a common
+programming interface.
+
+Others - mainly those who used the already existing drivers not only as
+a coding example, but also as a `user interface' reference during their
+own development - have taken care that <linux/cdrom.h> reflects a
+software interface to `user programs' which is unique between all drivers
+as much as possible; these driver writers will continue to refine the
+existing <linux/cdrom.h> where it seems necessary, and they tend to look
+if any newly requested functionality isn't already there before they are
+ready to define new structures. The sbpcd driver gives an example that
+it is possible to let a robot arm play juke box - either with audio or
+with data CDs -, and that it is possible to let the juke box work on
+even if a disk has fallen upon the floor and the drive door has closed
+without having a disk inside; without any new software layer or any
+structures which are not already present in <linux/cdrom.h>.
+This `other' group of \linux\ \cdrom\ driver writers explicitely does
+NOT support the idea to define an additional software layer between driver
+and user program.
+
+
+The following text reflects the opinion of the first mentioned \linux\
+\cdrom\ driver writer group only; the other group (not only the `silent
+majority') sees this text as a good base for a future documentation of the
+existing common \linux\ \cdrom\ programming interface, as it is stated
+within <linux/cdrom.h>. Where <linux/cdrom.h> needs some external
+explanation, this text can give it if the reader is aware that - at least
+at the moment - this text claims to be the proposal of something else than
+<linux/cdrom.h>.
+
Apart from the somewhat unstructured interfacing with software, the
actual execution of the commands is different for most of the
\halign{$#$\ \hfil&$#$\ \hfil&\hbox to 10em{$#$\hss}&
$/*$ \rm# $*/$\hfil\cr
struct& cdrom_device_ops\ \{ \hidewidth\cr
- &int& (* open)(dev_t, int)\cr
- &void& (* release)(dev_t);\cr
- &int& (* open_files)(dev_t); \cr
- &int& (* drive_status)(dev_t);\cr
- &int& (* disc_status)(dev_t);\cr
- &int& (* media_changed)(dev_t);\cr
- &int& (* tray_move)(dev_t, int);\cr
- &int& (* lock_door)(dev_t, int);\cr
- &int& (* select_speed)(dev_t, int);\cr
- &int& (* select_disc)(dev_t, int);\cr
- &int& (* get_last_session) (dev_t, struct\ cdrom_multisession *{});\cr
- &int& (* get_mcn)(dev_t, struct\ cdrom_mcn *{});\cr
- &int& (* reset)(dev_t);\cr
- &int& (* audio_ioctl)(dev_t, unsigned\ int, void *{});\cr
- &int& (* dev_ioctl)(dev_t, unsigned\ int, unsigned\ long);\cr
+ &int& (* open)(kdev_t, int)\cr
+ &void& (* release)(kdev_t);\cr
+ &int& (* open_files)(kdev_t); \cr
+ &int& (* drive_status)(kdev_t);\cr
+ &int& (* disc_status)(kdev_t);\cr
+ &int& (* media_changed)(kdev_t);\cr
+ &int& (* tray_move)(kdev_t, int);\cr
+ &int& (* lock_door)(kdev_t, int);\cr
+ &int& (* select_speed)(kdev_t, int);\cr
+ &int& (* select_disc)(kdev_t, int);\cr
+ &int& (* get_last_session) (kdev_t, struct\ cdrom_multisession *{});\cr
+ &int& (* get_mcn)(kdev_t, struct\ cdrom_mcn *{});\cr
+ &int& (* reset)(kdev_t);\cr
+ &int& (* audio_ioctl)(kdev_t, unsigned\ int, void *{});\cr
+ &int& (* dev_ioctl)(kdev_t, unsigned\ int, unsigned\ long);\cr
\noalign{\medskip}
&\llap{const\ }int& capability;& capability flags \cr
&int& mask;& mask of capability: disables them \cr
command has completed, but of course waiting for the device should not
use processor time.
-\subsection{$Open(dev_t\ dev, int\ purpose)$}
+\subsection{$Open(kdev_t\ dev, int\ purpose)$}
$Open()$ should try to open the device for a specific $purpose$, which
can be either:
should only be concerned with proper initialization and device-use
count.
-\subsection{$Release(dev_t\ dev)$}
+\subsection{$Release(kdev_t\ dev)$}
The use-count of the device $dev$ should be decreased by 1, and a
single call $MOD_DEC_USE_COUNT$ should be coded here. Possibly other
$cdrom_release()$. Also, the invalidation of the allocated buffers in
the VFS is taken care of by the routine in \cdromc.
-\subsection{$Open_files(dev_t\ dev)$}
+\subsection{$Open_files(kdev_t\ dev)$}
This function should return the internal variable use-count of the
device $dev$. The use-count is not implemented in the routines in
\cdromc\ itself, because there may be many minor devices connected to
a single low-level driver.
-\subsection{$Drive_status(dev_t\ dev)$}
+\subsection{$Drive_status(kdev_t\ dev)$}
\label{drive status}
The function $drive_status$, if implemented, should provide
}
$$
-\subsection{$Disc_status(dev_t\ dev)$}
+\subsection{$Disc_status(kdev_t\ dev)$}
\label{disc status}
As a complement to $drive_status()$, this function can provide the
separate queues for the VFS and a new $ioctl()$ function that can
report device changes to software (e.g., an auto-mounting daemon).
-\subsection{$Tray_move(dev_t\ dev, int\ position)$}
+\subsection{$Tray_move(kdev_t\ dev, int\ position)$}
This function, if implemented, should control the tray movement. (No
other function should control this.) The parameter $position$ controls
error. Note that if the tray is already in the desired position, no
action need be taken, and the return value should be 0.
-\subsection{$Lock_door(dev_t\ dev, int\ lock)$}
+\subsection{$Lock_door(kdev_t\ dev, int\ lock)$}
This function (and no other code) controls locking of the door, if the
drive allows this. The value of $lock$ controls the desired locking
\end{itemize}
Return values are as for $tray_move()$.
-\subsection{$Select_speed(dev_t\ dev, int\ speed)$}
+\subsection{$Select_speed(kdev_t\ dev, int\ speed)$}
Although none of the drivers has implemented this function so far,
some drives are capable of head-speed selection, and hence this is a
high-speed copying of audio tracks). Badly pressed \cdrom s may
benefit from less-than-maximum head rate.
-\subsection{$Select_disc(dev_t\ dev, int\ number)$}
+\subsection{$Select_disc(kdev_t\ dev, int\ number)$}
If the drive can store multiple discs (a juke-box), it is likely that
a disc selection can be made by software. This function should perform
\cdrom\ drivers appears to support such functionality, but it is defined
here for future purposes.
-\subsection{$Get_last_session(dev_t\ dev, struct\ cdrom_multisession *
+\subsection{$Get_last_session(kdev_t\ dev, struct\ cdrom_multisession *
ms_info)$}
This function should implement the old corresponding $ioctl()$. For
field appropriately, of course) and the routines in \cdromc\ will make
the transform if necessary. The return value is 0 upon success.
-\subsection{$Get_mcn(dev_t\ dev, struct\ cdrom_mcn * mcn)$}
+\subsection{$Get_mcn(kdev_t\ dev, struct\ cdrom_mcn * mcn)$}
Some discs carry a `Media Catalog Number' (MCN), also called
`Universal Product Code' (UPC). This number should reflect the number that
pre-declared memory region of type $struct\ cdrom_mcn$. The MCN is
expected as a 13-character string, terminated by a null-character.
-\subsection{$Reset(dev_t dev)$}
+\subsection{$Reset(kdev_t dev)$}
This call should implement hard-resetting the drive (although in
circumstances that a hard-reset is necessary, a drive may very well
not listen to commands anymore). Preferably, control is returned to the
caller only after the drive has finished resetting.
-\subsection{$Audio_ioctl(dev_t\ dev, unsigned\ int\ cmd, void *
+\subsection{$Audio_ioctl(kdev_t\ dev, unsigned\ int\ cmd, void *
arg)$}
Some of the \cdrom-$ioctl$s defined in {\tt cdrom.h} can be
may decide to sanitize the return value in $cdrom_ioctl()$, in order
to guarantee a uniform interface to the audio-player software.)
-\subsection{$Dev_ioctl(dev_t\ dev, unsigned\ int\ cmd, unsigned\ long\
+\subsection{$Dev_ioctl(kdev_t\ dev, unsigned\ int\ cmd, unsigned\ long\
arg)$}
Some $ioctl$s seem to be specific to certain \cdrom\ drives. That is,
\subsection{How to update your driver}
-We hope all \cdrom\ driver maintainers will understand the advantages
-of re-routing the interface to the kernel though the new routines in
-\cdromc. The following scheme should help you to update your
-driver. It should not be too much work. We hope you want to take these
-steps, in order to make the \linux\ \cdrom\ support more uniform and
-more flexible.
\begin{enumerate}
\item Make a backup of your current driver.
\item Get hold of the files \cdromc\ and \ucdrom, they should be in
%
\title{{\bf Linux Allocated Devices}}
\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: May 9, 1996}
+\date{Last revised: May 12, 1996}
\maketitle
%
\noindent
/pub/linux/docs/linux-standards/fsstnd}.
To have a major number allocated, or a minor number in situations
-where that applies (e.g.\ busmice), please contact me. Also, if you
-have additional information regarding any of the devices listed below,
-or if I have made a mistake, I would greatly appreciate a note.
+where that applies (e.g.\ busmice), please contact me with the
+appropriate device information. Also, if you have additional
+information regarding any of the devices listed below, or if I have
+made a mistake, I would greatly appreciate a note.
Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
platform only. Allocations marked (68k/Atari) apply to Linux/68k on
\begin{devicelist}
\major{ 9}{}{char }{SCSI tape devices}
- \minor{0}{/dev/st0}{First SCSI tape}
- \minor{1}{/dev/st1}{Second SCSI tape}
+ \minor{0}{/dev/st0}{First SCSI tape, mode 0}
+ \minor{1}{/dev/st1}{Second SCSI tape, mode 0}
\minordots
- \minor{128}{/dev/nst0}{First SCSI tape, no rewind-on-close}
- \minor{129}{/dev/nst1}{Second SCSI tape, no rewind-on-close}
+ \minor{32}{/dev/st0l}{First SCSI tape, mode 1}
+ \minor{33}{/dev/st1l}{Second SCSI tape, mode 1}
\minordots
-\\
+ \minor{64}{/dev/st0m}{First SCSI tape, mode 2}
+ \minor{65}{/dev/st1m}{Second SCSI tape, mode 2}
+ \minordots
+ \minor{96}{/dev/st0a}{First SCSI tape, mode 3}
+ \minor{97}{/dev/st1a}{Second SCSI tape, mode 4}
+ \minordots
+ \minor{128}{/dev/nst0}{First SCSI tape, mode 0, no rewind}
+ \minor{129}{/dev/nst1}{Second SCSI tape, mode 0, no rewind}
+ \minordots
+ \minor{160}{/dev/nst0l}{First SCSI tape, mode 1, no rewind}
+ \minor{161}{/dev/nst1l}{Second SCSI tape, mode 1, no rewind}
+ \minordots
+ \minor{192}{/dev/nst0m}{First SCSI tape, mode 2, no rewind}
+ \minor{193}{/dev/nst1m}{Second SCSI tape, mode 2, no rewind}
+ \minordots
+ \minor{224}{/dev/nst0a}{First SCSI tape, mode 3, no rewind}
+ \minor{225}{/dev/nst1a}{Second SCSI tape, mode 3, no rewind}
+ \minordots
+\end{devicelist}
+
+\noindent
+``No rewind'' refers to the omission of the default automatic rewind
+on device close. The {\file MTREW} or {\file MTOFFL} ioctl()s can be
+used to rewind the tape regardless of the device used to access it.
+
+\begin{devicelist}
\major{ }{}{block}{Metadisk (RAID) devices}
\minor{0}{/dev/md0}{First metadisk group}
\minor{1}{/dev/md1}{Second metadisk group}
Maintained by H. Peter Anvin <hpa@zytor.com>
- Last revised: May 9, 1996
+ Last revised: May 12, 1996
This list is the successor to Rick Miller's Linux Device List, which
he stopped maintaining when he got busy with other things in 1993. It
tsx-11.mit.edu in the directory /pub/linux/docs/linux-standards/fsstnd.
To have a major number allocated, or a minor number in situations
-where that applies (e.g. busmice), please contact me. Also, if you
-have additional information regarding any of the devices listed below,
-or if I have made a mistake, I would greatly appreciate a note.
+where that applies (e.g. busmice), please contact me with the
+appropriate device information. Also, if you have additional
+information regarding any of the devices listed below, or if I have
+made a mistake, I would greatly appreciate a note.
Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga
platform only. Allocations marked (68k/Atari) apply to Linux/68k on
partitions is 15.
9 char SCSI tape devices
- 0 = /dev/st0 First SCSI tape
- 1 = /dev/st1 Second SCSI tape
+ 0 = /dev/st0 First SCSI tape, mode 0
+ 1 = /dev/st1 Second SCSI tape, mode 0
...
- 128 = /dev/nst0 First SCSI tape, no rewind-on-close
- 129 = /dev/nst1 Second SCSI tape, no rewind-on-close
+ 32 = /dev/st0l First SCSI tape, mode 1
+ 33 = /dev/st1l Second SCSI tape, mode 1
...
+ 64 = /dev/st0m First SCSI tape, mode 2
+ 65 = /dev/st1m Second SCSI tape, mode 2
+ ...
+ 96 = /dev/st0a First SCSI tape, mode 3
+ 97 = /dev/st1a Second SCSI tape, mode 3
+ ...
+ 128 = /dev/nst0 First SCSI tape, mode 0, no rewind
+ 129 = /dev/nst1 Second SCSI tape, mode 0, no rewind
+ ...
+ 160 = /dev/nst0l First SCSI tape, mode 1, no rewind
+ 161 = /dev/nst1l Second SCSI tape, mode 1, no rewind
+ ...
+ 192 = /dev/nst0m First SCSI tape, mode 2, no rewind
+ 193 = /dev/nst1m Second SCSI tape, mode 2, no rewind
+ ...
+ 224 = /dev/nst0a First SCSI tape, mode 3, no rewind
+ 225 = /dev/nst1a Second SCSI tape, mode 3, no rewind
+ ...
+
+ "No rewind" refers to the omission of the default
+ automatic rewind on device close. The MTREW or MTOFFL
+ ioctl()'s can be used to rewind the tape regardless of
+ the device used to access it.
+
block Metadisk (RAID) devices
0 = /dev/md0 First metadisk group
1 = /dev/md1 Second metadisk group
- JAVA Binary Kernel Support for Linux v1.01
- ------------------------------------------
+ Java(tm) Binary Kernel Support for Linux v1.01
+ ----------------------------------------------
Linux beats them ALL! While all other OS's are TALKING about direct
support of Java Binaries in the OS, Linux is doing it!
ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO
If you install the JDK in a location other than the suggested
- directory of /usr/local/java, then you will need to edit the
- kernel's fs/binfmt_java.c file and make the needed change to the
- _PATH_JAVA definition at the top of that file.
+ directory of /usr/local/java, then you will need to tell the
+ kernel where you put the Java interpreter.
+ There are two ways to do this.
+ One, edit fs/binfmt_java.c file and make the needed change to
+ the _PATH_JAVA definition at the top of that file.
+ Two, as root, issue the command:
+ echo "/path/to/java/interpreter" > /proc/sys/kernel/java-interpreter
+ (Currently, this does not work if you're using a module for
+ Java support.)
2) You must chmod the '*.class' files you wish to execute with
the execute bit. This is not normally (till now) done with
as a loadable module. If a module, load it with insmod or
kerneld.
-
To test your new setup, enter in the following simple Java app, and name
it "HelloWorld.java":
with all known browsers.
2) If you install the JDK in a location other than the suggested
- directory of /usr/local/java, then you will need to edit the
- kernel's fs/binfmt_java.c file and make the needed change to the
- _PATH_APPLET definition at the top of that file.
+ directory of /usr/local/java, then you will need to tell the
+ kernel where you put the Java appletviewer.
+ There are two ways to do this.
+ One, edit fs/binfmt_java.c file and make the needed change to
+ the _PATH_APPLET definition at the top of that file.
+ Two, as root, issue the command:
+ echo "/path/to/java/appletviewer" > /proc/sys/kernel/java-appletviewer
+ (Currently, this does not work if you're using a module for
+ Java support.)
3) You must chmod the '*.html' files you wish to execute with
the execute bit. This is not normally (till now) done with
4) And then execute it.
-
Brian A. Lantz
brian@lantz.com
+(/proc/sys/kernel/java-* support by Mike Shaver (shaver@ingenia.com))
+
- Video Mode Selection Support 2.7
+ Video Mode Selection Support 2.9
(c) 1995, 1996 Martin Mares, <mj@k332.feld.cvut.cz>
--------------------------------------------------------------------------------
- Screen store/restore fixed.
2.8 (14-Apr-96) - Previous release was not compilable without CONFIG_VIDEO_SVGA.
- Better recognition of text modes during mode scan.
+2.9 (12-May-96) - Ignored VESA modes 0x80 - 0xff (more VESA BIOS bugs!)
Alan Cox <alan@lxorguk.ukuu.org.uk>
- Custom Linux Driver And Program Development
+ Custom Linux Driver And Program Development
The following watchdog drivers are currently implemented:
- IMS WDT501-P
- INS WDT501-P (no fan tachometer)
- IMS WDT500-P
+ ICS WDT501-P
+ ICS WDT501-P (no fan tachometer)
+ ICS WDT500-P
Software Only
All four interfaces provide /dev/watchdog, which when open must be written
Overheat X o o
The external event interfaces on the WDT boards are not currently supported.
+Minor numbers are however allocated for it.
Example Watchdog Driver
}
-> People keep asking about the WDT watchdog timer hardware: The phone contacts
-> for Industrial Computer Source are:
->
-> US: 619 677 0898 (sales) 0895 (general)
-> UK: 01243 533900
-> France (1) 69.18.74.30
->
-> and please mention Linux when enquiring.
+Contact Information
+
+People keep asking about the WDT watchdog timer hardware: The phone contacts
+for Industrial Computer Source are:
+
+US: 619 677 0877 (sales) 0895 (fax)
+UK: 01243 533900
+France (1) 69.18.74.30
+
+Industrial Computer Source
+9950 Barnes Canyon Road
+San Diego, CA
+
+and please mention Linux when enquiring.
VERSION = 1
PATCHLEVEL = 99
-SUBLEVEL = 2
+SUBLEVEL = 3
ARCH = i386
# CONFIG_INET_PCTCP is not set
# CONFIG_INET_RARP is not set
# CONFIG_NO_PATH_MTU_DISCOVERY is not set
-# CONFIG_TCP_NAGLE_OFF is not set
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# Filesystems
#
# CONFIG_QUOTA is not set
+# CONFIG_LOCK_MANDATORY is not set
# CONFIG_MINIX_FS is not set
# CONFIG_EXT_FS is not set
CONFIG_EXT2_FS=y
!
-! Display adapter & video mode setup, version 2.8 (14-Apr-96)
+! Display adapter & video mode setup, version 2.9 (12-May-96)
!
! Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
! Based on the original setup.S code (C) Linus Torvalds
jz vesar
cmp ax,#0x0080 ! Check validity of mode ID
jc vesa2
- or ah,ah ! Valid ID's are 0x0000-0x007f
- jz vesae ! and 0x0100-0x07ff.
+ or ah,ah ! Valid ID's are 0x0000-0x007f and 0x0100-0x07ff
+ jz vesan ! [Certain BIOSes errorneously report 0x80-0xff]
cmp ax,#0x0800
jnc vesae
vesa2: push cx
bool 'System V IPC' CONFIG_SYSVIPC
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+fi
bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
choice 'Processor type' \
CONFIG_SYSVIPC=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_JAVA is not set
CONFIG_KERNEL_ELF=y
# CONFIG_M386 is not set
# CONFIG_M486 is not set
# CONFIG_INET_PCTCP is not set
# CONFIG_INET_RARP is not set
# CONFIG_NO_PATH_MTU_DISCOVERY is not set
-# CONFIG_TCP_NAGLE_OFF is not set
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# Filesystems
#
# CONFIG_QUOTA is not set
+# CONFIG_LOCK_MANDATORY is not set
CONFIG_MINIX_FS=y
# CONFIG_EXT_FS is not set
CONFIG_EXT2_FS=y
void smp_callin(void)
{
+ extern void calibrate_delay(void);
int cpuid=GET_APIC_ID(apic_read(APIC_ID));
unsigned long l;
+
/*
* Activate our APIC
*/
* Create devices for BSD partitions listed in a disklabel, under a
* dos-like partition. See extended_partition() for more information.
*/
-static void bsd_disklabel_partition(struct gendisk *hd, int dev)
+static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev)
{
struct buffer_head *bh;
struct bsd_disklabel *l;
#ifdef CONFIG_SUN_PARTITION
-static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
+static int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
{
int i, csum;
unsigned short *ush;
: (__u32)(x))
if(!(bh = bread(dev, 0, 1024))) {
- printk("Dev %d: unable to read partition table\n", dev);
+ printk("Dev %s: unable to read partition table\n",
+ kdevname(dev));
return -1;
}
label = (struct sun_disklabel *) bh->b_data;
p = label->partitions;
if (label->magic != SUN_LABEL_MAGIC && label->magic != SUN_LABEL_MAGIC_SWAPPED) {
- printk("Dev %d Sun disklabel: bad magic %04x\n", dev, label->magic);
+ printk("Dev %s Sun disklabel: bad magic %04x\n",
+ kdevname(dev), label->magic);
brelse(bh);
return 0;
}
for(csum = 0; ush >= ((unsigned short *) label);)
csum ^= *ush--;
if(csum) {
- printk("Dev %d Sun disklabel: Csum bad, label corrupted\n", dev);
+ printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
+ kdevname(dev));
brelse(bh);
return 0;
}
tmp_dev=hash->dev0;
if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset)
- printk ("Block %ld out of bounds on dev %04x size %d offset %d\n", block, tmp_dev->dev, tmp_dev->size, tmp_dev->offset);
+ printk ("Block %ld out of bounds on dev %s size %d offset %d\n",
+ block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset);
*rdev=tmp_dev->dev;
*rsector=(block-(tmp_dev->offset)) << 1;
void cdrom_release(struct inode *ip, struct file *fp);
int cdrom_ioctl(struct inode *ip, struct file *fp,
unsigned int cmd, unsigned long arg);
-int cdrom_media_changed(dev_t dev);
+int cdrom_media_changed(kdev_t dev);
struct file_operations cdrom_fops =
{
* is in their own interest: device control becomes a lot easier
* this way.
*/
-int open_for_data(struct cdrom_device_ops *, int);
+int open_for_data(struct cdrom_device_ops *, kdev_t);
int cdrom_open(struct inode *ip, struct file *fp)
{
- dev_t dev = ip->i_rdev;
+ kdev_t dev = ip->i_rdev;
struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
int purpose = !!(fp->f_flags & O_NONBLOCK);
return open_for_data(cdo, dev);
}
-int open_for_data(struct cdrom_device_ops * cdo, int dev)
+int open_for_data(struct cdrom_device_ops * cdo, kdev_t dev)
{
int ret;
if (cdo->drive_status != NULL) {
/* Admittedly, the logic below could be performed in a nicer way. */
void cdrom_release(struct inode *ip, struct file *fp)
{
- dev_t dev = ip->i_rdev;
+ kdev_t dev = ip->i_rdev;
struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
if (cdo == NULL || MINOR(dev) >= cdo->minors)
* in the lower 16 bits, queue 1 in the higher 16 bits.
*/
-int media_changed(dev_t dev, int queue)
+int media_changed(kdev_t dev, int queue)
{
unsigned int major = MAJOR(dev);
unsigned int minor = MINOR(dev);
return ret;
}
-int cdrom_media_changed(dev_t dev)
+int cdrom_media_changed(kdev_t dev)
{
struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
if (cdo == NULL || MINOR(dev) >= cdo->minors)
int cdrom_ioctl(struct inode *ip, struct file *fp,
unsigned int cmd, unsigned long arg)
{
- dev_t dev = ip->i_rdev;
+ kdev_t dev = ip->i_rdev;
struct cdrom_device_ops *cdo = cdromdevs[MAJOR(dev)];
if (cdo == NULL || MINOR(dev) >= cdo->minors)
/* The new open. The real opening strategy is defined in cdrom.c. */
-static int cm206_open(dev_t dev, int purpose)
+static int cm206_open(kdev_t dev, int purpose)
{
if (!cd->openfiles) { /* reset only first time */
cd->background=0;
return 0;
}
-static void cm206_release(dev_t dev)
+static void cm206_release(kdev_t dev)
{
if (cd->openfiles==1) {
if (cd->background) {
* upon success. Memory checking has been done by cdrom_ioctl(), the
* calling function, as well as LBA/MSF sanitization.
*/
-int cm206_audio_ioctl(dev_t dev, unsigned int cmd, void * arg)
+int cm206_audio_ioctl(kdev_t dev, unsigned int cmd, void * arg)
{
switch (cmd) {
case CDROMREADTOCHDR:
some driver statistics accessible through ioctl calls.
*/
-static int cm206_ioctl(dev_t dev, unsigned int cmd, unsigned long arg)
+static int cm206_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
#ifdef STATISTICS
}
}
-int cm206_media_changed(dev_t dev)
+int cm206_media_changed(kdev_t dev)
{
if (cd != NULL) {
int r;
the logic should be in cdrom.c */
/* returns number of times device is in use */
-int cm206_open_files(dev_t dev)
+int cm206_open_files(kdev_t dev)
{
if (cd) return cd->openfiles;
return -1;
}
/* controls tray movement */
-int cm206_tray_move(dev_t dev, int position)
+int cm206_tray_move(kdev_t dev, int position)
{
if (position) { /* 1: eject */
type_0_command(c_open_tray,1);
}
/* gives current state of the drive */
-int cm206_drive_status(dev_t dev)
+int cm206_drive_status(kdev_t dev)
{
get_drive_status();
if (cd->dsb & dsb_tray_not_closed) return CDS_TRAY_OPEN;
}
/* gives current state of disc in drive */
-int cm206_disc_status(dev_t dev)
+int cm206_disc_status(kdev_t dev)
{
uch xa;
get_drive_status();
}
/* locks or unlocks door lock==1: lock; return 0 upon success */
-int cm206_lock_door(dev_t dev, int lock)
+int cm206_lock_door(kdev_t dev, int lock)
{
uch command = (lock) ? c_lock_tray : c_unlock_tray;
type_0_command(command, 1); /* wait and get dsb */
/* Although a session start should be in LBA format, we return it in
MSF format because it is slightly easier, and the new generic ioctl
will take care of the necessary conversion. */
-int cm206_get_last_session(dev_t dev, struct cdrom_multisession * mssp)
+int cm206_get_last_session(kdev_t dev, struct cdrom_multisession * mssp)
{
if (!FIRST_TRACK) get_disc_status();
if (mssp != NULL) {
return 0;
}
-int cm206_get_upc(dev_t dev, struct cdrom_mcn * mcn)
+int cm206_get_upc(kdev_t dev, struct cdrom_mcn * mcn)
{
uch upc[10];
char * ret = mcn->medium_catalog_number;
return 0;
}
-int cm206_reset(dev_t dev)
+int cm206_reset(kdev_t dev)
{
stop_read();
reset_cm260();
/*
* The Mitsumi CDROM interface
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.9
- *
- ****************** H E L P *********************************
- * If you ever plan to update your CD ROM drive and perhaps
- * want to sell or simply give away your Mitsumi FX-001[DS]
- * -- Please, Please --
- * mail me (heiko@lotte.sax.de). When my last drive goes
- * ballistic no more driver support will be available from me !!!
- *************************************************************
- *
+ * VERSION: 2.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
* Andreas Kies (testing the mysterious hang up's)
* ... somebody forgotten?
- *
+ *
+ * 2.1 1996/04/29 Marcin Dalecki <dalecki@namu03.gwdg.de>
+ * Far too many bugfixes/changes to mention them all separately.
+ * 2.2 1996/05/06 Marcin Dalecki <dalecki@namu03.gwdg.de>
+ * Mostly fixes to some silly bugs in the previous release :-).
+ * (Hi Michael Thimm! Thank's for lending me Your's double speed drive.)
*/
-
-
-#if RCS
-static const char *mcdx_c_version
- = "mcdx.c,v 1.2 1996/03/22 01:14:59 heiko Exp";
-#endif
+#define VERSION "2.2"
#include <linux/version.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/segment.h>
-
#include <linux/major.h>
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
#include <linux/blk.h>
-/* for compatible parameter passing with "insmod" */
-#define mcdx_drive_map mcdx
+/*
+ * for compatible parameter passing with "insmod"
+ */
+#define mcdx_drive_map mcdx
#include <linux/mcdx.h>
-#ifndef HZ
-#error HZ not defined
-#endif
-
-/* CONSTANTS *******************************************************/
-
-const int REQUEST_SIZE = 200;
-const int DIRECT_SIZE = 200;
-const unsigned long ACLOSE_INHIBIT = 800; /* 1/100 s of autoclose inhibit */
-
-enum drivemodes { TOC, DATA, RAW, COOKED };
-enum datamodes { MODE0, MODE1, MODE2 };
-enum resetmodes { SOFT, HARD };
+#define REQUEST_SIZE 200
+#define DIRECT_SIZE 200
-const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
-const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
-const int DOOR = 0x04; /* door locking capability */
-const int MULTI = 0x08; /* multi session capability */
+enum drivemodes {
+ TOC, DATA, RAW, COOKED
+};
-const unsigned char READ1X = 0xc0;
-const unsigned char READ2X = 0xc1;
+#define MODE0 0x00
+#define MODE1 0x01
+#define MODE2 0x02
+#define DOOR_LOCK 0x01
+#define DOOR_UNLOCK 0x00
-/* DECLARATIONS ****************************************************/
-struct s_msf {
- unsigned char minute;
- unsigned char second;
- unsigned char frame;
-};
+/*
+ * Structs used to gather info reported by the drive.
+ */
struct s_subqcode {
- unsigned char control;
- unsigned char tno;
- unsigned char index;
- struct s_msf tt;
- struct s_msf dt;
+ u_char adr:4;
+ u_char ctrl:4;
+ u_char tno;
+ u_char index;
+ struct cdrom_msf0 tt;
+ u_char dummy; /* padding for matching the returned struct */
+ struct cdrom_msf0 dt;
};
-struct s_diskinfo {
- unsigned int n_first;
- unsigned int n_last;
- struct s_msf msf_leadout;
- struct s_msf msf_first;
-};
-
struct s_multi {
unsigned char multi;
- struct s_msf msf_last;
+ struct cdrom_msf0 msf_last;
};
-struct s_version {
- unsigned char code;
- unsigned char ver;
+struct s_play {
+ struct cdrom_msf0 start;
+ struct cdrom_msf0 stop;
};
-/* Per drive/controller stuff **************************************/
+/*
+ * Per drive/controller stuff.
+ */
struct s_drive_stuff {
- /* waitqueues */
- struct wait_queue *busyq;
- struct wait_queue *lockq;
- struct wait_queue *sleepq;
-
- /* flags */
- volatile int introk; /* status of last irq operation */
- volatile int busy; /* drive performs an operation */
- volatile int lock; /* exclusive usage */
- int eject_sw; /* 1 - eject on last close (default 0) */
- int autoclose; /* 1 - close the door on open (default 1) */
-
+ struct wait_queue *busyq;
+
+ /* flags */
+ u_char introk:1; /* status of last irq operation */
+ u_char busy:1; /* drive performs an operation */
+ u_char eject_sw:1; /* 1 - eject on last close (default 0) */
+ u_char autoclose:1; /* 1 - close the door on open (default 1) */
+ u_char xxx:1; /* set if changed, reset while open */
+ u_char xa:1; /* 1 if xa disk */
+ u_char audio:1; /* 1 if audio disk */
+ u_char eom:1; /* end of media reached during read request */
+
+ /* drives capabilities */
+ u_char door:1; /* can close/lock tray */
+ u_char multi_cap:1; /* multisession capable */
+ u_char double_speed:1; /* double speed drive */
+
/* cd infos */
- struct s_diskinfo di;
+ unsigned int n_first;
+ unsigned int n_last;
+ struct cdrom_msf0 msf_leadout;
struct s_multi multi;
- struct s_subqcode* toc; /* first entry of the toc array */
- struct s_subqcode start;
- struct s_subqcode stop;
- int xa; /* 1 if xa disk */
- int audio; /* 1 if audio disk */
- int audiostatus;
+
+ struct s_subqcode *toc; /* first entry of the toc array */
+ struct s_play resume; /* where to resume after pause */
+
+ int audiostatus;
/* `buffer' control */
- volatile int valid;
- volatile int pending;
- volatile int off_direct;
- volatile int off_requested;
-
- /* adds and odds */
- void* wreg_data; /* w data */
- void* wreg_reset; /* w hardware reset */
- void* wreg_hcon; /* w hardware conf */
- void* wreg_chn; /* w channel */
- void* rreg_data; /* r data */
- void* rreg_status; /* r status */
-
- int irq; /* irq used by this drive */
- int minor; /* minor number of this drive */
- int present; /* drive present and its capabilities */
- unsigned char readcmd; /* read cmd depends on single/double speed */
- unsigned char playcmd; /* play should always be single speed */
- unsigned int xxx; /* set if changed, reset while open */
- unsigned int yyy; /* set if changed, reset by media_changed */
- unsigned long ejected; /* time we called the eject function */
- int users; /* keeps track of open/close */
- int lastsector; /* last block accessible */
- int status; /* last operation's error / status */
- int readerrs; /* # of blocks read w/o error */
+ unsigned int valid:1;
+ int pending;
+ int off_direct;
+ int off_requested;
+
+ int irq; /* irq used by this drive */
+ unsigned int base; /* base for all registers of the drive */
+ int users; /* keeps track of open/close */
+ int lastsector; /* last accessible blocks */
};
+/*
+ * Macros for accessing interface registers
+ */
-/* Prototypes ******************************************************/
-
-/* The following prototypes are already declared elsewhere. They are
- repeated here to show what's going on. And to sense, if they're
- changed elsewhere. */
+#define DATA_REG (stuffp->base)
+#define RESET_REG (stuffp->base+1)
+#define STAT_REG (stuffp->base+1)
+#define CHAN_REG (stuffp->base+3)
-/* declared in blk.h */
+/*
+ * declared in blk.h
+ */
int mcdx_init(void);
void do_mcdx_request(void);
-int check_mcdx_media_change(kdev_t);
-/* already declared in init/main */
+/*
+ * already declared in init/main
+ */
void mcdx_setup(char *, int *);
-/* Indirect exported functions. These functions are exported by their
- addresses, such as mcdx_open and mcdx_close in the
- structure fops. */
-
-/* ??? exported by the mcdx_sigaction struct */
-static void mcdx_intr(int, void *, struct pt_regs*);
-
-/* exported by file_ops */
-static int mcdx_open(struct inode*, struct file*);
-static void mcdx_close(struct inode*, struct file*);
-static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
-
-/* misc internal support functions */
-static void log2msf(unsigned int, struct s_msf*);
-static unsigned int msf2log(const struct s_msf*);
-static unsigned int uint2bcd(unsigned int);
-static unsigned int bcd2uint(unsigned char);
-#if MCDX_DEBUG
-static void TRACE((int level, const char* fmt, ...));
-#endif
-static void warn(const char* fmt, ...);
-static char *port(int*);
-static int irq(int*);
-static void mcdx_delay(struct s_drive_stuff*, long jifs);
-static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
-static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
-
-static int mcdx_config(struct s_drive_stuff*, int);
-static int mcdx_closedoor(struct s_drive_stuff*, int);
-static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
-static int mcdx_lockdoor(struct s_drive_stuff*, int, int);
-static int mcdx_stop(struct s_drive_stuff*, int);
-static int mcdx_hold(struct s_drive_stuff*, int);
-static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
-static int mcdx_eject(struct s_drive_stuff*, int);
-static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
-static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
-static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
-static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
-static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
-static int mcdx_getstatus(struct s_drive_stuff*, int);
-static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
-static int mcdx_talk(struct s_drive_stuff*,
- const unsigned char* cmd, size_t,
- void *buffer, size_t size,
- unsigned int timeout, int);
-static int mcdx_readtoc(struct s_drive_stuff*);
-static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
-static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
-static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
-
-/* static variables ************************************************/
+/*
+ * Indirect exported functions. These functions are exported by their
+ * addresses, such as mcdx_open and mcdx_close in the
+ * structure fops.
+ */
+
+/*
+ * ??? exported by the mcdx_sigaction struct
+ */
+static void mcdx_intr(int, void *, struct pt_regs *);
+
+/*
+ * exported by file_ops
+ */
+static int mcdx_open(struct inode *, struct file *);
+static void mcdx_close(struct inode *, struct file *);
+static int mcdx_ioctl(struct inode *, struct file *,
+ unsigned int, unsigned long);
+static int mcdx_media_change(kdev_t);
+
static int mcdx_blocksizes[MCDX_NDRIVES];
static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
-static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
-static struct s_drive_stuff* mcdx_irq_map[16] =
- {0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0};
+static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
+static struct s_drive_stuff *mcdx_irq_map[16] =
+{0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0};
-static struct file_operations mcdx_fops = {
+static struct file_operations mcdx_fops =
+{
NULL, /* lseek - use kernel default */
block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
+ block_write, /* write - general block-dev write */
NULL, /* no readdir */
NULL, /* no select */
mcdx_ioctl, /* ioctl() */
mcdx_open, /* open() */
mcdx_close, /* close() */
NULL, /* fsync */
- NULL, /* fasync */
- check_mcdx_media_change, /* media_change */
- NULL /* revalidate */
+ NULL, /* fasync */
+ mcdx_media_change, /* media_change */
+ NULL /* revalidate */
};
-/* KERNEL INTERFACE FUNCTIONS **************************************/
-
-static int
-mcdx_ioctl(
- struct inode* ip, struct file* fp,
- unsigned int cmd, unsigned long arg)
-{
- struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
-
- if (!stuffp->present) return -ENXIO;
- if (!ip) return -EINVAL;
-
- switch (cmd) {
- case CDROMSTART: {
- TRACE((IOCTL, "ioctl() START\n"));
- return 0;
- }
-
- case CDROMSTOP: {
- TRACE((IOCTL, "ioctl() STOP\n"));
- stuffp->audiostatus = CDROM_AUDIO_INVALID;
- if (-1 == mcdx_stop(stuffp, 1))
- return -EIO;
- return 0;
- }
+/*
+ * Misc number converters
+ */
- case CDROMPLAYTRKIND: {
- int ans;
- struct cdrom_ti ti;
+static unsigned int bcd2uint(unsigned char c)
+{
+ return (c >> 4) * 10 + (c & 0x0f);
+}
- TRACE((IOCTL, "ioctl() PLAYTRKIND\n"));
- if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(ti))))
- return ans;
- memcpy_fromfs(&ti, (void*) arg, sizeof(ti));
- if ((ti.cdti_trk0 < stuffp->di.n_first)
- || (ti.cdti_trk0 > stuffp->di.n_last)
- || (ti.cdti_trk1 < stuffp->di.n_first))
- return -EINVAL;
- if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last;
- TRACE((PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
+static unsigned int uint2bcd(unsigned int ival)
+{
+ return ((ival / 10) << 4) | (ival % 10);
+}
- return mcdx_playtrk(stuffp, &ti);
- }
+static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
+{
+ return bcd2uint(pmsf->frame)
+ + bcd2uint(pmsf->second) * 75
+ + bcd2uint(pmsf->minute) * 4500
+ - CD_BLOCK_OFFSET;
+}
- case CDROMPLAYMSF: {
- int ans;
- struct cdrom_msf msf;
+/*
+ * Access to elements of the mcdx_drive_map members
+ */
+static inline unsigned int port(int *ip)
+{
+ return (unsigned int) ip[0];
+}
- TRACE((IOCTL, "ioctl() PLAYMSF\n"));
+static inline int irq(int *ip)
+{
+ return ip[1];
+}
- if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
- && (-1 == mcdx_hold(stuffp, 1))) return -EIO;
- if ((ans = verify_area(
- VERIFY_READ, (void*) arg, sizeof(struct cdrom_msf))))
- return ans;
+/*
+ * Low level hardware related functions.
+ */
- memcpy_fromfs(&msf, (void*) arg, sizeof msf);
+/*
+ * Return drives status in case of success, -1 otherwise.
+ *
+ * First we try to get the status information quickly.
+ * Then we sleep repeatedly for about 10 usecs, befor we finally reach the
+ * timeout. For this reason this command must be called with the drive beeing
+ * locked!
+ */
+static int get_status(struct s_drive_stuff *stuffp,
+ unsigned long timeout)
+{
+ unsigned long bang = jiffies + 2;
+ timeout += jiffies;
- msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
- msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
- msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
+ do {
+ if (!(inb(STAT_REG) & MCDX_RBIT_STEN)) {
+ return (inb(DATA_REG) & 0xff);
+ }
+ } while (jiffies < bang);
- msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
- msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
- msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
+ while (inb(STAT_REG) & MCDX_RBIT_STEN) {
+ if (jiffies > timeout)
+ return -1;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ / 2;
+ schedule();
+ }
+ return (inb(DATA_REG) & 0xff);
+}
- return mcdx_playmsf(stuffp, &msf);
- }
+/* Send a command to the drive, wait for the result.
+ * returns -1 on timeout, drive status otherwise.
+ * If buffer is not zero, the result (length size) is stored there.
+ * If buffer is zero the size should be the number of bytes to read
+ * from the drive. These bytes are discarded.
+ */
+static int talk(struct s_drive_stuff *stuffp,
+ const unsigned char command,
+ void *pars, size_t parslen,
+ void *buffer, size_t size,
+ unsigned int timeout)
+{
+ int st;
- case CDROMRESUME: {
- TRACE((IOCTL, "ioctl() RESUME\n"));
- return mcdx_playtrk(stuffp, NULL);
- }
+ while (stuffp->busy) {
+ interruptible_sleep_on(&stuffp->busyq);
+ }
+ stuffp->busy = 1;
+ stuffp->valid = 0;
+ outb(command, DATA_REG);
+ if (parslen)
+ outsb(DATA_REG, pars, parslen);
+
+ if (-1 == (st = get_status(stuffp, timeout))) {
+ goto end_talk;
+ }
+ if (st & MCDX_RBIT_CMDERR) {
+ printk(KERN_ERR MCDX ": error in command 0x%2x\n", command);
+ st = -1;
+ goto end_talk;
+ }
+ /* audio status? */
+ if (stuffp->audiostatus == CDROM_AUDIO_INVALID) {
+ stuffp->audiostatus =
+ (st & MCDX_RBIT_AUDIOBS) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
+ } else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
+ && !(st & MCDX_RBIT_AUDIOBS)) {
+ stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
+ }
+ /* media change? */
+ if (st & MCDX_RBIT_CHANGED) {
+ stuffp->xxx = 1;
+ if (stuffp->toc) {
+ kfree(stuffp->toc);
+ stuffp->toc = 0;
+ }
+ }
+ /* now actually get the data */
+ while (size--) {
+ if (-1 == (st = get_status(stuffp, timeout))) {
+ break;
+ }
+ *((char *) buffer) = st;
+ buffer++;
+ }
- case CDROMREADTOCENTRY: {
- struct cdrom_tocentry entry;
- struct s_subqcode *tp = NULL;
- int ans;
+ end_talk:
+ stuffp->busy = 0;
+ wake_up_interruptible(&stuffp->busyq);
- TRACE((IOCTL, "ioctl() READTOCENTRY\n"));
+ return st;
+}
- if (-1 == mcdx_readtoc(stuffp)) return -1;
+static int issue_command(struct s_drive_stuff *stuffp,
+ unsigned char command,
+ unsigned int timeout)
+{
+ return talk(stuffp, command, 0, 0, NULL, 0, timeout);
+}
- if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry)))) return ans;
- memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
+static inline int set_command(struct s_drive_stuff *stuffp,
+ const unsigned char command,
+ void *pars, size_t parlen,
+ unsigned int timeout)
+{
+ return talk(stuffp, command, pars, parlen, NULL, 0, timeout);
+}
- if (entry.cdte_track == CDROM_LEADOUT)
- tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
- else if (entry.cdte_track > stuffp->di.n_last
- || entry.cdte_track < stuffp->di.n_first) return -EINVAL;
- else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first];
+static inline int get_command(struct s_drive_stuff *stuffp,
+ const unsigned char command,
+ void *buffer, size_t size,
+ unsigned int timeout)
+{
+ return talk(stuffp, command, NULL, 0, buffer, size, timeout);
+}
- if (NULL == tp) WARN(("FATAL.\n"));
+static int request_subq_code(struct s_drive_stuff *stuffp,
+ struct s_subqcode *sub)
+{
+ return get_command(stuffp, MCDX_CMD_GET_SUBQ_CODE,
+ sub, sizeof(struct s_subqcode), 2 * HZ);
+}
- entry.cdte_adr = tp->control;
- entry.cdte_ctrl = tp->control >> 4;
+static int request_toc_data(struct s_drive_stuff *stuffp)
+{
+ char buf[8];
+ int ans;
- if (entry.cdte_format == CDROM_MSF) {
- entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
- entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
- entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
- } else if (entry.cdte_format == CDROM_LBA)
- entry.cdte_addr.lba = msf2log(&tp->dt);
- else return -EINVAL;
+ ans = get_command(stuffp, MCDX_CMD_GET_TOC, buf, sizeof(buf), 2 * HZ);
+ if (ans == -1) {
+ stuffp->n_first = 0;
+ stuffp->n_last = 0;
+ } else {
+ stuffp->n_first = bcd2uint(buf[0]);
+ stuffp->n_last = bcd2uint(buf[1]);
+ memcpy(&(stuffp->msf_leadout), buf + 2, 3);
+ }
+ return ans;
+}
- if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(entry)))) return ans;
- memcpy_tofs((void*) arg, &entry, sizeof(entry));
+static int set_drive_mode(struct s_drive_stuff *stuffp, enum drivemodes mode)
+{
+ char value;
+ if (-1 == get_command(stuffp, MCDX_CMD_GET_DRIVE_MODE,
+ &value, 1, 5 * HZ))
+ return -1;
+ switch (mode) {
+ case TOC:
+ value |= 0x04;
+ break;
+ case DATA:
+ value &= ~0x04;
+ break;
+ case RAW:
+ value |= 0x40;
+ break;
+ case COOKED:
+ value &= ~0x40;
+ break;
+ default:
+ break;
+ }
+ return set_command(stuffp, MCDX_CMD_SET_DRIVE_MODE, &value, 1, 5 * HZ);
+}
- return 0;
- }
+static int config_drive(struct s_drive_stuff *stuffp)
+{
+ unsigned char buf[2];
+ buf[0] = 0x10; /* irq enable */
+ buf[1] = 0x05; /* pre, err irq enable */
- case CDROMSUBCHNL: {
- int ans;
- struct cdrom_subchnl sub;
- struct s_subqcode q;
-
- TRACE((IOCTL, "ioctl() SUBCHNL\n"));
-
- if ((ans = verify_area(VERIFY_READ,
- (void*) arg, sizeof(sub)))) return ans;
-
- memcpy_fromfs(&sub, (void*) arg, sizeof(sub));
-
- if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
-
- TRACE((SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus));
- sub.cdsc_audiostatus = stuffp->audiostatus;
- sub.cdsc_adr = q.control;
- sub.cdsc_ctrl = q.control >> 4;
- sub.cdsc_trk = bcd2uint(q.tno);
- sub.cdsc_ind = bcd2uint(q.index);
-
- TRACE((SUBCHNL, "trk %d, ind %d\n",
- sub.cdsc_trk, sub.cdsc_ind));
-
- if (sub.cdsc_format == CDROM_LBA) {
- sub.cdsc_absaddr.lba = msf2log(&q.dt);
- sub.cdsc_reladdr.lba = msf2log(&q.tt);
- TRACE((SUBCHNL, "lba: abs %d, rel %d\n",
- sub.cdsc_absaddr.lba,
- sub.cdsc_reladdr.lba));
- } else if (sub.cdsc_format == CDROM_MSF) {
- sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
- sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
- sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
- sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
- sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
- sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
- TRACE((SUBCHNL,
- "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
- sub.cdsc_absaddr.msf.minute,
- sub.cdsc_absaddr.msf.second,
- sub.cdsc_absaddr.msf.frame,
- sub.cdsc_reladdr.msf.minute,
- sub.cdsc_reladdr.msf.second,
- sub.cdsc_reladdr.msf.frame));
- } else return -EINVAL;
-
- if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(sub))))
- return ans;
- memcpy_tofs((void*) arg, &sub, sizeof(sub));
+ if (-1 == set_command(stuffp, MCDX_CMD_CONFIG, buf,
+ sizeof(buf), 1 * HZ))
+ return -1;
- return 0;
- }
+ buf[0] = 0x02; /* dma select */
+ buf[1] = 0x00; /* no dma */
- case CDROMREADTOCHDR: {
- struct cdrom_tochdr toc;
- int ans;
+ return set_command(stuffp, MCDX_CMD_CONFIG, buf, sizeof(buf), 1 * HZ);
+}
- TRACE((IOCTL, "ioctl() READTOCHDR\n"));
- if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc)))
- return ans;
- toc.cdth_trk0 = stuffp->di.n_first;
- toc.cdth_trk1 = stuffp->di.n_last;
- memcpy_tofs((void*) arg, &toc, sizeof toc);
- TRACE((TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
- stuffp->di.n_first, stuffp->di.n_last));
- return 0;
- }
+/*
+ * Read the toc entries from the CD.
+ * Return: -1 on failure, else 0
+ */
+int read_toc(struct s_drive_stuff *stuffp)
+{
+ int trk;
+ int retries;
- case CDROMPAUSE: {
- TRACE((IOCTL, "ioctl() PAUSE\n"));
- if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
- if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
- stuffp->audiostatus = CDROM_AUDIO_PAUSED;
- if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
- return -EIO;
- return 0;
- }
+ if (stuffp->toc)
+ return 0;
+ if (-1 == issue_command(stuffp, MCDX_CMD_HOLD, 2 * HZ))
+ return -1;
+ if (-1 == set_drive_mode(stuffp, TOC))
+ return -EIO;
- case CDROMMULTISESSION: {
- int ans;
- struct cdrom_multisession ms;
- TRACE((IOCTL, "ioctl() MULTISESSION\n"));
- if (0 != (ans = verify_area(VERIFY_READ, (void*) arg,
- sizeof(struct cdrom_multisession))))
- return ans;
-
- memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
- if (ms.addr_format == CDROM_MSF) {
- ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute);
- ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second);
- ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame);
- } else if (ms.addr_format == CDROM_LBA)
- ms.addr.lba = msf2log(&stuffp->multi.msf_last);
- else
- return -EINVAL;
- ms.xa_flag = !!stuffp->multi.multi;
-
- if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
- sizeof(struct cdrom_multisession))))
- return ans;
-
- memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
- if (ms.addr_format == CDROM_MSF)
- TRACE((MS,
- "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
- ms.xa_flag,
- ms.addr.msf.minute,
- ms.addr.msf.second,
- ms.addr.msf.frame,
- stuffp->multi.msf_last.minute,
- stuffp->multi.msf_last.second,
- stuffp->multi.msf_last.frame));
- else
- {
- TRACE((MS,
- "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
- ms.xa_flag,
- ms.addr.lba,
- stuffp->multi.msf_last.minute,
- stuffp->multi.msf_last.second,
- stuffp->multi.msf_last.frame));
- }
- return 0;
+ /* all seems to be ok so far ... malloc */
+ stuffp->toc = kmalloc(sizeof(struct s_subqcode) *
+ (stuffp->n_last - stuffp->n_first + 2), GFP_KERNEL);
+ if (!stuffp->toc) {
+ printk(KERN_ERR MCDX ": malloc for toc failed\n");
+ set_drive_mode(stuffp, DATA);
+ return -EIO;
+ }
+ /* now read actually the index tarcks */
+ for (trk = 0;
+ trk < (stuffp->n_last - stuffp->n_first + 1);
+ trk++)
+ stuffp->toc[trk].index = 0;
+
+ for (retries = 300; retries; retries--) { /* why 300? */
+ struct s_subqcode q;
+ unsigned int idx;
+
+ if (-1 == request_subq_code(stuffp, &q)) {
+ set_drive_mode(stuffp, DATA);
+ return -EIO;
}
-
- case CDROMEJECT: {
- TRACE((IOCTL, "ioctl() EJECT\n"));
- if (stuffp->users > 1) return -EBUSY;
- if (-1 == mcdx_eject(stuffp, 1)) return -EIO;
- return 0;
+ idx = bcd2uint(q.index);
+
+ if ((idx > 0)
+ && (idx <= stuffp->n_last)
+ && (q.tno == 0)
+ && (stuffp->toc[idx - stuffp->n_first].index == 0)) {
+ stuffp->toc[idx - stuffp->n_first] = q;
+ trk--;
}
+ if (trk == 0)
+ break;
+ }
+ memset(&stuffp->toc[stuffp->n_last - stuffp->n_first + 1],
+ 0, sizeof(stuffp->toc[0]));
+ stuffp->toc[stuffp->n_last - stuffp->n_first + 1].dt
+ = stuffp->msf_leadout;
- case CDROMEJECT_SW: {
- stuffp->eject_sw = arg;
- return 0;
- }
-
- case CDROMVOLCTRL: {
- int ans;
- struct cdrom_volctrl volctrl;
+ /* unset toc mode */
+ if (-1 == set_drive_mode(stuffp, DATA))
+ return -EIO;
- TRACE((IOCTL, "ioctl() VOLCTRL\n"));
- if ((ans = verify_area(
- VERIFY_READ,
- (void*) arg,
- sizeof(volctrl))))
- return ans;
+ return 0;
+}
- memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
- return mcdx_setattentuator(stuffp, &volctrl, 1);
- }
+/*
+ * Return 0 on success, error value -1 otherwise.
+ */
+static int play_track(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
+{
+ struct s_play times;
- default:
- WARN(("ioctl(): unknown request 0x%04x\n", cmd));
- return -EINVAL;
+ if (ti) {
+ if (-1 == read_toc(stuffp)) {
+ stuffp->audiostatus = CDROM_AUDIO_ERROR;
+ return -EIO;
+ }
+ times.start = stuffp->toc[ti->cdti_trk0 - stuffp->n_first].dt;
+ times.stop = stuffp->resume.stop =
+ stuffp->toc[ti->cdti_trk1 - stuffp->n_first + 1].dt;
+ } else {
+ times = stuffp->resume;
+ }
+ if (-1 == set_command(stuffp, MCDX_CMD_PLAY,
+ ×, sizeof(times), 5 * HZ)) {
+ printk(KERN_WARNING MCDX ": play track timeout\n");
+ stuffp->audiostatus = CDROM_AUDIO_ERROR;
+ return -EIO;
}
+ stuffp->audiostatus = CDROM_AUDIO_PLAY;
+
+ return 0;
}
-void do_mcdx_request()
+static int lock_door(struct s_drive_stuff *stuffp, u_char lock)
{
- int dev;
- struct s_drive_stuff *stuffp;
-
- again:
-
- TRACE((REQUEST, "do_request()\n"));
+ if (stuffp->door)
+ return set_command(stuffp, MCDX_CMD_LOCK_DOOR,
+ &lock, sizeof(lock), 5 * HZ);
+ return 0;
+} /*
+ * KERNEL INTERFACE FUNCTIONS
+ */
+static int mcdx_ioctl(struct inode *ip, struct file *fp,
+ unsigned int command, unsigned long arg)
+{
+ int ans;
+ struct cdrom_ti ti;
+ struct cdrom_msf msf;
+ struct cdrom_tocentry entry;
+ struct s_subqcode *tp = NULL;
+ struct cdrom_subchnl sub;
+ struct s_subqcode q;
+ struct cdrom_tochdr toc;
+ struct cdrom_multisession ms;
+ struct cdrom_volctrl volctrl;
+ struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
- if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) {
- TRACE((REQUEST, "do_request() done\n"));
- return;
+ MCDX_TRACE_IOCTL(("mcdx_ioctl():\n"));
+
+ if (!stuffp)
+ return -ENXIO;
+ if (!ip)
+ return -EINVAL;
+
+ /*
+ * Update disk information, when necessary.
+ * This part will only work, when the new disk is of the same type as
+ * the one which was previousley there, esp. also for audio diks.
+ * This doesn't hurt us, since otherwise the mouting/unmounting scheme
+ * will ensure correct operation.
+ */
+ if (stuffp->xxx) { /* disk changed */
+ if ((-1 == request_toc_data(stuffp)) ||
+ (-1 == read_toc(stuffp)))
+ return -EIO;
+ stuffp->xxx = 0;
}
+ switch (command) {
+ case CDROMSTART: /* spin up the drive */
+ MCDX_TRACE_IOCTL(("CDROMSTART\n"));
+ /* Don't think we can do this. Even if we could,
+ * I think the drive times out and stops after a while
+ * anyway. For now, ignore it.
+ */
+ return 0;
- stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
- TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
+ case CDROMSTOP:
+ MCDX_TRACE_IOCTL(("CDROMSTOP\n"));
+ stuffp->audiostatus = CDROM_AUDIO_INVALID;
+ if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ))
+ return -EIO;
+ return 0;
- INIT_REQUEST;
- dev = MINOR(CURRENT->rq_dev);
+ case CDROMPLAYTRKIND:
+ MCDX_TRACE_IOCTL(("CDROMPLAYTRKIND\n"));
+
+ if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(ti))))
+ return ans;
+ memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
+ if ((ti.cdti_trk0 < stuffp->n_first)
+ || (ti.cdti_trk0 > stuffp->n_last)
+ || (ti.cdti_trk1 < stuffp->n_first))
+ return -EINVAL;
+ if (ti.cdti_trk1 > stuffp->n_last)
+ ti.cdti_trk1 = stuffp->n_last;
+ return play_track(stuffp, &ti);
+
+ case CDROMPLAYMSF:
+ MCDX_TRACE_IOCTL(("CDROMPLAYMSF "));
+
+ if ((ans = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct cdrom_msf))))
+ return ans;
+ memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+ msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
+ msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
+ msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
+ msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
+ msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
+ msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
+ stuffp->resume.stop.minute = msf.cdmsf_min1;
+ stuffp->resume.stop.second = msf.cdmsf_sec1;
+ stuffp->resume.stop.frame = msf.cdmsf_frame1;
+ if (-1 == set_command(stuffp, MCDX_CMD_PLAY,
+ &msf, sizeof(msf), 3 * HZ)) {
+ return -1;
+ }
+ stuffp->audiostatus = CDROM_AUDIO_PLAY;
+ return 0;
- if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
- WARN(("do_request(): bad device: %s\n",
- kdevname(CURRENT->rq_dev)));
- end_request(0);
- goto again;
- }
+ case CDROMPAUSE:
+ MCDX_TRACE_IOCTL(("CDROMPAUSE\n"));
- if (stuffp->audio) {
- WARN(("do_request() attempt to read from audio cd\n"));
- end_request(0);
- goto again;
- }
+ if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
+ return -EINVAL;
- switch (CURRENT->cmd) {
- case WRITE:
- WARN(("do_request(): attempt to write to cd!!\n"));
- end_request(0);
- break;
-
- case READ:
- stuffp->status = 0;
- while (CURRENT->nr_sectors) {
- int i;
-
- if (-1 == (i = mcdx_transfer(
- stuffp,
- CURRENT->buffer,
- CURRENT->sector,
- CURRENT->nr_sectors))) {
- /*INFO(("do_request() read error\n"));*/
- xwarn("do_request() read error\n");
- if (stuffp->status & MCDX_ST_EOM) {
- CURRENT->sector += CURRENT->nr_sectors;
- CURRENT->nr_sectors = 0;
- }
- invalidate_buffers(CURRENT->rq_dev);
- end_request(0);
- goto again;
- }
- CURRENT->sector += i;
- CURRENT->nr_sectors -= i;
- CURRENT->buffer += (i * 512);
-
- }
-
- end_request(1);
- break;
-
- default:
- panic(MCDX "do_request: unknown command.\n");
- break;
- }
-
- goto again;
-}
+ if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ))
+ return -EIO;
+ if (-1 == request_subq_code(stuffp, &q)) {
+ stuffp->audiostatus = CDROM_AUDIO_NO_STATUS;
+ return 0;
+ }
+ stuffp->resume.start = q.dt;
+ stuffp->audiostatus = CDROM_AUDIO_PAUSED;
+ return 0;
-static int
-mcdx_open(struct inode *ip, struct file *fp)
-/* actions done on open:
- * 1) get the drives status */
-{
- struct s_drive_stuff *stuffp;
+ case CDROMRESUME:
+ MCDX_TRACE_IOCTL(("CDROMRESUME\n"));
- TRACE((OPENCLOSE, "open()\n"));
- stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
- if (!stuffp->present) return -ENXIO;
+ if (stuffp->audiostatus != CDROM_AUDIO_PAUSED)
+ return -EINVAL;
+ return play_track(stuffp, NULL);
+ case CDROMREADTOCENTRY:
+ MCDX_TRACE_IOCTL(("CDROMREADTOCENTRY\n"));
- /* this is only done to test if the drive talks with us */
- if (-1 == mcdx_getstatus(stuffp, 1)) return -EIO;
+ if (-1 == read_toc(stuffp))
+ return -1;
+ if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry))))
+ return ans;
+ memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
+
+ if (entry.cdte_track == CDROM_LEADOUT)
+ tp = &stuffp->toc[stuffp->n_last - stuffp->n_first + 1];
+ else if (entry.cdte_track > stuffp->n_last
+ || entry.cdte_track < stuffp->n_first)
+ return -EINVAL;
+ else
+ tp = &stuffp->toc[entry.cdte_track - stuffp->n_first];
+
+ if (NULL == tp)
+ printk(KERN_ERR MCDX ": FATAL.\n");
+
+ entry.cdte_adr = tp->adr;
+ entry.cdte_ctrl = tp->ctrl;
+
+ if (entry.cdte_format == CDROM_MSF) {
+ entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
+ entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
+ entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
+ } else if (entry.cdte_format == CDROM_LBA)
+ entry.cdte_addr.lba = msf2log(&tp->dt);
+ else
+ return -EINVAL;
+
+ if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry))))
+ return ans;
+ memcpy_tofs((void *) arg, &entry, sizeof(entry));
- /* close the door, if necessary (get the door information
- from the hardware status register).
- If the last eject is too recent, an autoclose wouldn't probably
- be what we want ..., if we can't read the CD after an autoclose
- no further autocloses will be tried */
- if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
- if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
- if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
- else return -EIO;
- }
-
- /* if the media changed we will have to do a little more */
- if (stuffp->xxx) {
+ return 0;
- TRACE((OPENCLOSE, "open() media changed\n"));
- /* but wait - the time of media change will be set at the
- very last of this block - it seems, some of the following
- talk() will detect a media change ... (I think, config()
- is the reason. */
+ case CDROMSUBCHNL:
+ MCDX_TRACE_IOCTL(("CDROMSUBCHNL\n"));
- stuffp->audiostatus = CDROM_AUDIO_INVALID;
+ if ((ans = verify_area(VERIFY_READ,
+ (void *) arg, sizeof(sub))))
+ return ans;
- /* get the multisession information */
- TRACE((OPENCLOSE, "open() Request multisession info\n"));
- if (-1 == mcdx_requestmultidiskinfo(
- stuffp, &stuffp->multi, 6)) {
- INFO(("No multidiskinfo\n"));
- stuffp->autoclose = 0;
- } else {
- /* we succeeded, so on next open(2) we could try auto close
- again */
- stuffp->autoclose = 1;
-
-#if !MCDX_QUIET
- if (stuffp->multi.multi > 2)
- INFO(("open() unknown multisession value (%d)\n",
- stuffp->multi.multi));
-#endif
+ memcpy_fromfs(&sub, (void *) arg, sizeof(sub));
- /* multisession ? */
- if (!stuffp->multi.multi)
- stuffp->multi.msf_last.second = 2;
+ if (-1 == request_subq_code(stuffp, &q))
+ return -EIO;
- TRACE((OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
- stuffp->multi.multi,
- stuffp->multi.msf_last.minute,
- stuffp->multi.msf_last.second,
- stuffp->multi.msf_last.frame));
+ sub.cdsc_audiostatus = stuffp->audiostatus;
+ sub.cdsc_adr = q.adr;
+ sub.cdsc_ctrl = q.ctrl;
+ sub.cdsc_trk = bcd2uint(q.tno);
+ sub.cdsc_ind = bcd2uint(q.index);
+
+ if (sub.cdsc_format == CDROM_LBA) {
+ sub.cdsc_absaddr.lba = msf2log(&q.dt);
+ sub.cdsc_reladdr.lba = msf2log(&q.tt);
+ } else if (sub.cdsc_format == CDROM_MSF) {
+ sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
+ sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
+ sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
+ sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
+ sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
+ sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
+ } else
+ return -EINVAL;
+
+ if ((ans = verify_area(VERIFY_WRITE,
+ (void *) arg, sizeof(sub))))
+ return ans;
+ memcpy_tofs((void *) arg, &sub, sizeof(sub));
- } /* got multisession information */
+ return 0;
- /* request the disks table of contents (aka diskinfo) */
- if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
+ case CDROMREADTOCHDR:
+ MCDX_TRACE_IOCTL(("CDROMREADTOCHDR\n"));
- stuffp->lastsector = -1;
+ if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof toc)))
+ return ans;
- } else {
+ toc.cdth_trk0 = stuffp->n_first;
+ toc.cdth_trk1 = stuffp->n_last;
+ memcpy_tofs((void *) arg, &toc, sizeof toc);
+ return 0;
- stuffp->lastsector = (CD_FRAMESIZE / 512)
- * msf2log(&stuffp->di.msf_leadout) - 1;
-
- TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
- stuffp->di.n_first,
- stuffp->di.msf_first.minute,
- stuffp->di.msf_first.second,
- stuffp->di.msf_first.frame,
- msf2log(&stuffp->di.msf_first)));
- TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
- stuffp->di.n_last,
- stuffp->di.msf_leadout.minute,
- stuffp->di.msf_leadout.second,
- stuffp->di.msf_leadout.frame,
- msf2log(&stuffp->di.msf_leadout)));
- }
+ case CDROMMULTISESSION:
+ MCDX_TRACE_IOCTL(("CDROMMULTISESSION\n"));
+
+ if (0 != (ans = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct cdrom_multisession))))
+ return ans;
+
+ memcpy_fromfs(&ms,
+ (void *) arg, sizeof(struct cdrom_multisession));
+ if (ms.addr_format == CDROM_MSF) {
+ ms.addr.msf.minute =
+ bcd2uint(stuffp->multi.msf_last.minute);
+ ms.addr.msf.second =
+ bcd2uint(stuffp->multi.msf_last.second);
+ ms.addr.msf.frame =
+ bcd2uint(stuffp->multi.msf_last.frame);
+ } else if (ms.addr_format == CDROM_LBA)
+ ms.addr.lba = msf2log(&stuffp->multi.msf_last);
+ else
+ return -EINVAL;
+ ms.xa_flag = !!stuffp->multi.multi;
+
+ if (0 != (ans = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct cdrom_multisession))))
+ return ans;
+
+ memcpy_tofs((void *) arg,
+ &ms, sizeof(struct cdrom_multisession));
+ return 0;
+ case CDROMEJECT:
+ MCDX_TRACE_IOCTL(("CDROMEJECT\n"));
+ if (stuffp->users > 1)
+ return -EBUSY;
+ if (stuffp->door) {
+ if (-1 == issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ))
+ return -EIO;
+ }
+ /*
+ * Force rereading of toc next time the disk gets accessed!
+ */
if (stuffp->toc) {
- TRACE((MALLOC, "open() free old toc @ %p\n", stuffp->toc));
kfree(stuffp->toc);
-
- stuffp->toc = NULL;
+ stuffp->toc = 0;
}
+ return 0;
- TRACE((OPENCLOSE, "open() init irq generation\n"));
- if (-1 == mcdx_config(stuffp, 1)) return -EIO;
-
-#if FALLBACK
- /* Set the read speed */
- WARN(("AAA %x AAA\n", stuffp->readcmd));
- if (stuffp->readerrs) stuffp->readcmd = READ1X;
- else stuffp->readcmd =
- stuffp->present | SINGLE ? READ1X : READ2X;
- WARN(("XXX %x XXX\n", stuffp->readcmd));
-#endif
-
- /* try to get the first sector, iff any ... */
- if (stuffp->lastsector >= 0) {
- char buf[512];
- int ans;
- int tries;
-
- stuffp->xa = 0;
- stuffp->audio = 0;
+ case CDROMEJECT_SW:
+ MCDX_TRACE_IOCTL(("CDROMEJECT_SW\n"));
- for (tries = 6; tries; tries--) {
+ stuffp->eject_sw = !!arg;
+ return 0;
- stuffp->introk = 1;
+ case CDROMVOLCTRL:
+ MCDX_TRACE_IOCTL(("CDROMVOLCTRL\n"));
+
+ if ((ans = verify_area(VERIFY_READ,
+ (void *) arg,
+ sizeof(volctrl))))
+ return ans;
+
+ memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
+ /* Adjust for the wiredness of workman. */
+ volctrl.channel2 = volctrl.channel1;
+ volctrl.channel1 = volctrl.channel3 = 0xff;
+ return talk(stuffp, MCDX_CMD_SET_ATTENATOR,
+ &volctrl, sizeof(volctrl),
+ &volctrl, sizeof(volctrl), 2 * HZ);
+
+ default:
+ printk(KERN_WARNING MCDX
+ ": unknown ioctl request 0x%04x\n", command);
+ return -EINVAL;
+ }
+}
- TRACE((OPENCLOSE, "open() try as %s\n",
- stuffp->xa ? "XA" : "normal"));
+/*
+ * This does actually the transfer from the drive.
+ * Return: -1 on timeout or other error
+ * else status byte (as in stuff->st)
+ * FIXME: the excessive jumping throught wait queues degrades the
+ * performance significantly.
+ */
+static int transfer_data(struct s_drive_stuff *stuffp,
+ char *p, int sector, int nr_sectors)
+{
+ int off;
+ int done = 0;
+
+ if (stuffp->valid
+ && (sector >= stuffp->pending)
+ && (sector < stuffp->off_direct)) {
+ off = stuffp->off_requested < (off = sector + nr_sectors)
+ ? stuffp->off_requested : off;
+
+ do {
+ /* wait for the drive become idle, but first
+ * check for possible occurred errors --- the drive
+ * seems to report them asynchronously
+ */
+ current->timeout = jiffies + 5 * HZ;
+ while (stuffp->introk && stuffp->busy
+ && current->timeout) {
+ interruptible_sleep_on(&stuffp->busyq);
+ }
- /* set data mode */
- if (-1 == (ans = mcdx_setdatamode(stuffp,
- stuffp->xa ? MODE2 : MODE1, 1))) {
- /* return -EIO; */
- stuffp->xa = 0;
- break;
+ /* test for possible errors */
+ if (current->timeout == 0 || !stuffp->introk) {
+ if (current->timeout == 0) {
+ printk(KERN_ERR MCDX ": transfer timeout\n");
+ } else if (!stuffp->introk) {
+ printk(KERN_ERR MCDX
+ ": error via irq in transfer reported\n");
}
- if ((stuffp->audio = e_audio(ans))) break;
-
- while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1)))
- ;
-
- if (ans == 1) break;
- stuffp->xa = !stuffp->xa;
+ stuffp->busy = 0;
+ stuffp->valid = 0;
+ stuffp->introk = 1;
+ return -1;
}
- /* if (!tries) return -EIO; */
- }
+ /* test if it's the first sector of a block,
+ * there we have to skip some bytes as we read raw data
+ */
+ if (stuffp->xa && (0 == (stuffp->pending & 3))) {
+ insb(DATA_REG, p,
+ CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE);
+ }
+ /* now actually read the data */
+ insb(DATA_REG, p, 512);
+
+ /* test if it's the last sector of a block,
+ * if so, we have to expect an interrupt and to skip
+ * some data too
+ */
+ if ((stuffp->busy = (3 == (stuffp->pending & 3)))
+ && stuffp->xa) {
+ int i;
+ for (i = 0; i < CD_XA_TAIL; ++i)
+ inb(DATA_REG);
+ }
+ if (stuffp->pending == sector) {
+ p += 512;
+ done++;
+ sector++;
+ }
+ } while (++(stuffp->pending) < off);
+ } else {
+ unsigned char cmd[6];
+ stuffp->valid = 1;
+ stuffp->pending = sector & ~3;
- /* xa disks will be read in raw mode, others not */
- if (-1 == mcdx_setdrivemode(stuffp,
- stuffp->xa ? RAW : COOKED, 1))
- return -EIO;
+ /* do some sanity checks */
+ if (stuffp->pending > stuffp->lastsector) {
+ printk(KERN_ERR MCDX
+ ": sector %d transfer from nirvana requested.\n",
+ stuffp->pending);
+ stuffp->eom = 1;
+ stuffp->valid = 0;
+ return -1;
+ }
+ if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE)
+ > stuffp->lastsector + 1)
+ stuffp->off_direct = stuffp->lastsector + 1;
+ if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
+ > stuffp->lastsector + 1)
+ stuffp->off_requested = stuffp->lastsector + 1;
+ {
+ unsigned int l = (stuffp->pending / 4)
+ + CD_BLOCK_OFFSET;
- if (stuffp->audio) {
- INFO(("open() audio disk found\n"));
- } else if (stuffp->lastsector >= 0) {
- INFO(("open() %s%s disk found\n",
- stuffp->xa ? "XA / " : "",
- stuffp->multi.multi ? "Multi Session" : "Single Session"));
- }
+ cmd[0] = uint2bcd(l / 4500), l %= 4500;
+ /* minute */
+ cmd[1] = uint2bcd(l / 75); /* second */
+ cmd[2] = uint2bcd(l % 75); /* frame */
+ }
- stuffp->xxx = 0;
+ stuffp->busy = 1;
+ /*
+ * FIXME: What about the ominous frame length?!
+ */
+ cmd[3] = ~0;
+ cmd[4] = ~0;
+ cmd[5] = ~0;
+
+ outb(stuffp->double_speed ? MCDX_CMD_PLAY_2X : MCDX_CMD_PLAY,
+ DATA_REG);
+ outsb(DATA_REG, cmd, 6);
}
- /* lock the door if not already done */
- if (0 == stuffp->users && (-1 == mcdx_lockdoor(stuffp, 1, 1)))
- return -EIO;
+ stuffp->off_direct =
+ (stuffp->off_direct += done) < stuffp->off_requested
+ ? stuffp->off_direct
+ : stuffp->off_requested;
- stuffp->users++;
- MOD_INC_USE_COUNT;
- return 0;
+ return done;
}
-static void
-mcdx_close(struct inode *ip, struct file *fp)
+void do_mcdx_request()
{
- struct s_drive_stuff *stuffp;
+ int dev;
+ struct s_drive_stuff *stuffp;
- TRACE((OPENCLOSE, "close()\n"));
+ again:
- stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
-
- if (0 == --stuffp->users) {
- sync_dev(ip->i_rdev); /* needed for r/o device? */
+ if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) {
+ return;
+ }
+ stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
- /* invalidate_inodes(ip->i_rdev); */
- invalidate_buffers(ip->i_rdev);
+ INIT_REQUEST;
+ dev = MINOR(CURRENT->rq_dev);
+ if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp)) {
+ printk(KERN_WARNING MCDX ": bad device requested: %s\n",
+ kdevname(CURRENT->rq_dev));
+ end_request(0);
+ goto again;
+ }
+ if (stuffp->audio) {
+ printk(KERN_WARNING MCDX ": attempt to read from audio cd\n");
+ end_request(0);
+ goto again;
+ }
+ switch (CURRENT->cmd) {
+ case WRITE:
+ printk(KERN_ERR MCDX ": attempt to write to cd!!\n");
+ end_request(0);
+ break;
-#if !MCDX_QUIET
- if (-1 == mcdx_lockdoor(stuffp, 0, 3))
- INFO(("close() Cannot unlock the door\n"));
-#else
- mcdx_lockdoor(stuffp, 0, 3);
-#endif
+ case READ:
+ stuffp->eom = 0; /* clear end of media flag */
+ while (CURRENT->nr_sectors) {
+ int i;
- /* eject if wished */
- if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
+ if (-1 == (i = transfer_data(stuffp,
+ CURRENT->buffer,
+ CURRENT->sector,
+ CURRENT->nr_sectors))) {
+ if (stuffp->eom) {
+ CURRENT->sector += CURRENT->nr_sectors;
+ CURRENT->nr_sectors = 0;
+ } else {
+ /*
+ * FIXME: TRY SOME ERROR RECOVERY HERE!
+ */
+ }
+ end_request(0);
+ goto again;
+ }
+ CURRENT->sector += i;
+ CURRENT->nr_sectors -= i;
+ CURRENT->buffer += (i * 512);
+ }
+ end_request(1);
+ break;
- }
- MOD_DEC_USE_COUNT;
+ default:
+ panic(MCDX "do_request: unknown command.\n");
+ break;
+ }
- return;
+ goto again;
}
-int check_mcdx_media_change(kdev_t full_dev)
-/* Return: 1 if media changed since last call to this function
- 0 otherwise */
+/*
+ * actions done on open:
+ * 1) get the drives status
+ */
+static int mcdx_open(struct inode *ip, struct file *fp)
{
- struct s_drive_stuff *stuffp;
-
- INFO(("check_mcdx_media_change called for device %s\n",
- kdevname(full_dev)));
-
- stuffp = mcdx_stuffp[MINOR(full_dev)];
- mcdx_getstatus(stuffp, 1);
-
- if (stuffp->yyy == 0) return 0;
-
- stuffp->yyy = 0;
- return 1;
-}
+ struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
+ int st = 0;
+ unsigned long bang;
-void mcdx_setup(char *str, int *pi)
-{
- if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
- if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
-}
+ MCDX_TRACE(("mcdx_open()\n"));
-/* DIRTY PART ******************************************************/
+ if (!stuffp)
+ return -ENXIO;
-static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/* This routine is used for sleeping.
- May be we could use a simple count loop w/ jumps to itself, but
- I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
-{
- unsigned long tout = jiffies + jifs;
- if (jifs < 0) return;
-
- /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */
-
- if (current->pid == 0) { /* no sleep allowed */
- while (jiffies < tout) {
- current->timeout = jiffies;
- schedule();
- }
- } else { /* sleeping is allowed */
- current->timeout = tout;
- /* current->state = TASK_INTERRUPTIBLE; */
- /* And perhaps we should remove the while() { ... } */
- while (current->timeout) {
- interruptible_sleep_on(&stuff->sleepq);
- TRACE((SLEEP, "delay: to is %d\n", current->timeout));
- }
- }
-}
+ /* close the door, if necessary (get the door information
+ * from the hardware status register).
+ * If we can't read the CD after an autoclose
+ * no further autocloses will be tried
+ */
+ if (inb(STAT_REG) & MCDX_RBIT_DOOR) {
+ if (stuffp->autoclose && (stuffp->door))
+ issue_command(stuffp, MCDX_CMD_CLOSE_DOOR, 10 * HZ);
+ else
+ return -EIO;
+ }
+ /*
+ * Check if a disk is in.
+ */ bang = jiffies + 10 * HZ;
+ while (jiffies < bang) {
+ st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 5 * HZ);
+ if (st != -1 && (st & MCDX_RBIT_DISKSET))
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1 * HZ;
+ schedule();
+ }
+ if (st == -1 || (st & MCDX_RBIT_DISKSET) == 0) {
+ printk(KERN_INFO MCDX ": no disk in drive\n");
+ return -EIO;
+ }
+ /* if the media changed we will have to do a little more
+ * FIXME: after removing of the mcdx_requestmultisession() it is showed
+ * that the logics of this may be broken.
+ */
+ if (stuffp->xxx) {
+ /* but wait - the time of media change will be set at the
+ * very last of this block.
+ */
-static void
-mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
-{
- struct s_drive_stuff *stuffp;
- unsigned char b;
+ stuffp->audiostatus = CDROM_AUDIO_INVALID;
+ stuffp->autoclose = 1;
- stuffp = mcdx_irq_map[irq];
+ /* get the multisession information */
- if (stuffp == NULL ) {
- xwarn("mcdx: no device for intr %d\n", irq);
- return;
- }
+ if (stuffp->multi_cap) {
+ int i = 6; /* number of retries */
+ while (i && (-1 == get_command(stuffp,
+ MCDX_CMD_GET_MDISK_INFO,
+ &stuffp->multi, sizeof(struct s_multi), 2 * HZ)))
+ --i;
+ if (!i) {
+ stuffp->autoclose = 0;
+ /*
+ * No multidisk info
+ */
+ }
+ } else
+ stuffp->multi.multi = 0;
- /* get the interrupt status */
- b = inb((unsigned int) stuffp->rreg_status);
- stuffp->introk = ~b & MCDX_RBIT_DTEN;
+ if (stuffp->autoclose) {
+ /* we succeeded, so on next open(2) we could try
+ * auto close again
+ */
- /* NOTE: We only should get interrupts if data were requested.
- But the drive seems to generate ``asynchronous'' interrupts
- on several error conditions too. (Despite the err int enable
- setting during initialisation) */
-
- /* if not ok, read the next byte as the drives status */
- if (!stuffp->introk) {
- TRACE((IRQ, "intr() irq %d hw status 0x%02x\n", irq, b));
- if (~b & MCDX_RBIT_STEN) {
- xinfo( "intr() irq %d status 0x%02x\n",
- irq, inb((unsigned int) stuffp->rreg_data));
+ /* multisession ? */
+ if (!stuffp->multi.multi)
+ stuffp->multi.msf_last.second = 2;
+ } /* got multisession information */
+ /* request the disks table of contents (aka diskinfo) */
+ if (-1 == request_toc_data(stuffp)) {
+ stuffp->lastsector = -1;
} else {
- xinfo( "intr() irq %d ambiguous hw status\n", irq);
+ stuffp->lastsector = (CD_FRAMESIZE / 512)
+ * msf2log(&stuffp->msf_leadout) - 1;
}
- } else {
- TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, b));
- }
- stuffp->busy = 0;
- wake_up_interruptible(&stuffp->busyq);
-}
+ if (stuffp->toc) {
+ kfree(stuffp->toc);
+ stuffp->toc = 0;
+ }
+ if (-1 == config_drive(stuffp))
+ return -EIO;
+ /* try to get the first sector, iff any ... */
+ if (stuffp->lastsector >= 0) {
+ char buf[512];
+ int ans;
+ int tries;
-static int
-mcdx_talk (
- struct s_drive_stuff *stuffp,
- const unsigned char *cmd, size_t cmdlen,
- void *buffer, size_t size,
- unsigned int timeout, int tries)
-/* Send a command to the drive, wait for the result.
- * returns -1 on timeout, drive status otherwise
- * If buffer is not zero, the result (length size) is stored there.
- * If buffer is zero the size should be the number of bytes to read
- * from the drive. These bytes are discarded.
- */
-{
- int st;
- char c;
- int discard;
+ stuffp->xa = 0;
+ stuffp->audio = 0;
- if ((discard = (buffer == NULL))) buffer = &c;
+ for (tries = 6; tries; tries--) {
+ unsigned char c;
+ stuffp->introk = 1;
- while (stuffp->lock) {
- interruptible_sleep_on(&stuffp->lockq);
- TRACE((SLEEP, "talk: lock = %d\n",
- stuffp->lock));
- }
+ /* set data mode */
+ c = stuffp->xa ? MODE2 : MODE1;
+ ans = set_command(stuffp,
+ MCDX_CMD_SET_DATA_MODE,
+ &c, sizeof(c), 5 * HZ);
- stuffp->lock = 1;
- stuffp->valid = 0;
+ if (-1 == ans) {
+ /* return -EIO; */
+ stuffp->xa = 0;
+ break;
+ } else if (ans & MCDX_RBIT_AUDIOTR) {
+ stuffp->audio = 1;
+ break;
+ }
+
+ while (0 == (ans = transfer_data(stuffp, buf,
+ 0, 1)));
-#if MCDX_DEBUG & TALK
- {
- unsigned char i;
- TRACE((TALK, "talk() %d / %d tries, res.size %d, command 0x%02x",
- tries, timeout, size, (unsigned char) cmd[0]));
- for (i = 1; i < cmdlen; i++) printk(" 0x%02x", cmd[i]);
- printk("\n");
+ if (ans == 1)
+ break;
+ stuffp->xa = !stuffp->xa;
+ }
+ /* if (!tries) return -EIO; */
+ }
+ /* xa disks will be read in raw mode, others not */
+ if (-1 == set_drive_mode(stuffp, stuffp->xa ? RAW : COOKED))
+ return -EIO;
+ stuffp->xxx = 0;
}
-#endif
+ /* lock the door if not already done */
+ if (0 == stuffp->users && (-1 == lock_door(stuffp, DOOR_LOCK)))
+ return -EIO;
- /* give up if all tries are done (bad) or if the status
- * st != -1 (good) */
- for (st = -1; st == -1 && tries; tries--) {
-
- char *bp = (char*) buffer;
- size_t sz = size;
-
- outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
- TRACE((TALK, "talk() command sent\n"));
-
- /* get the status byte */
- if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
- INFO(("talk() %02x timed out (status), %d tr%s left\n",
- cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
- continue;
- }
- st = *bp;
- sz--;
- if (!discard) bp++;
-
- TRACE((TALK, "talk() got status 0x%02x\n", st));
-
- /* command error? */
- if (e_cmderr(st)) {
- WARN(("command error cmd = %02x %s \n",
- cmd[0], cmdlen > 1 ? "..." : ""));
- st = -1;
- continue;
- }
+ stuffp->users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
- /* audio status? */
- if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
- stuffp->audiostatus =
- e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
- else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
- && e_audiobusy(st) == 0)
- stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
-
- /* media change? */
- if (e_changed(st)) {
- INFO(("talk() media changed\n"));
- stuffp->xxx = stuffp->yyy = 1;
- }
-
- /* now actually get the data */
- while (sz--) {
- if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
- INFO(("talk() %02x timed out (data), %d tr%s left\n",
- cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
- st = -1; break;
- }
- if (!discard) bp++;
- TRACE((TALK, "talk() got 0x%02x\n", *(bp - 1)));
- }
- }
-
-#if !MCDX_QUIET
- if (!tries && st == -1) INFO(("talk() giving up\n"));
-#endif
+static void mcdx_close(struct inode *ip, struct file *fp)
+{
+ struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
- stuffp->lock = 0;
- wake_up_interruptible(&stuffp->lockq);
+ MCDX_TRACE(("mcdx_close()\n"));
- TRACE((TALK, "talk() done with 0x%02x\n", st));
- return st;
-}
-
-/* MODULE STUFF ***********************************************************/
-#ifdef MODULE
+ if (0 == --stuffp->users) {
+ sync_dev(ip->i_rdev); /* needed for r/o device? */
-int init_module(void)
-{
- int i;
- int drives = 0;
+ /* invalidate_inodes(ip->i_rdev); */
+ invalidate_buffers(ip->i_rdev);
+ lock_door(stuffp, DOOR_UNLOCK);
- mcdx_init();
- for (i = 0; i < MCDX_NDRIVES; i++) {
- if (mcdx_stuffp[i]) {
- TRACE((INIT, "init_module() drive %d stuff @ %p\n",
- i, mcdx_stuffp[i]));
- drives++;
+ /* eject if wished and possible */
+ if (stuffp->eject_sw && (stuffp->door)) {
+ issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ);
}
}
+ MOD_DEC_USE_COUNT;
- if (!drives)
- return -EIO;
-
- register_symtab(0);
- return 0;
+ return;
}
-void cleanup_module(void)
+/*
+ * Return: 1 if media changed since last call to this function
+ * 0 otherwise
+ */
+static int mcdx_media_change(kdev_t full_dev)
{
- int i;
+ struct s_drive_stuff *stuffp;
- INFO(("cleanup_module called\n"));
-
- for (i = 0; i < MCDX_NDRIVES; i++) {
- struct s_drive_stuff *stuffp;
- stuffp = mcdx_stuffp[i];
- if (!stuffp) continue;
- release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
- free_irq(stuffp->irq, NULL);
- if (stuffp->toc) {
- TRACE((MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc));
- kfree(stuffp->toc);
- }
- TRACE((MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp));
- mcdx_stuffp[i] = NULL;
- kfree(stuffp);
- }
+ MCDX_TRACE(("mcdx_media_change()\n"));
- if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
- WARN(("cleanup() unregister_blkdev() failed\n"));
- }
-#if !MCDX_QUIET
- else INFO(("cleanup() succeeded\n"));
-#endif
-}
-
-#endif MODULE
-
-/* Support functions ************************************************/
+ /*
+ * FIXME: propably this is unneded or should be simplified!
+ */
+ issue_command(stuffp = mcdx_stuffp[MINOR(full_dev)],
+ MCDX_CMD_GET_STATUS, 5 * HZ);
-#if MCDX_DEBUG
-void trace(int level, const char* fmt, ...)
-{
- char s[255];
- va_list args;
- if (level < 1) return;
- va_start(args, fmt);
- if (sizeof(s) < vsprintf(s, fmt, args))
- printk(MCDX ":: dprintf exceeds limit!!\n");
- else printk(MCDX ":: %s", s);
- va_end(args);
+ return stuffp->xxx;
}
-#endif
-void warn(const char* fmt, ...)
+/* Interrupt handler routine.
+ * This function is called, when during transfer the end of a physical 2048
+ * byte block is reached.
+ */
+static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
{
- char s[255];
- va_list args;
- va_start(args, fmt);
- if (sizeof(s) < vsprintf(s, fmt, args))
- printk(MCDX ":: dprintf exceeds limit!!\n");
- else printk(MCDX ": %s", s);
- va_end(args);
+ struct s_drive_stuff *stuffp;
+ u_char b;
+
+ if (!(stuffp = mcdx_irq_map[irq])) {
+ return; /* hugh? */
+ }
+
+ /* NOTE: We only should get interrupts if data were requested.
+ * But the drive seems to generate ``asynchronous'' interrupts
+ * on several error conditions too. (Despite the err int enable
+ * setting during initialisation)
+ */
+
+ /* get the interrupt status */
+ b = inb(STAT_REG);
+ if (!(b & MCDX_RBIT_DTEN)) {
+ stuffp->introk = 1;
+ } else {
+ stuffp->introk = 0;
+ if (!(b & MCDX_RBIT_STEN)) {
+ printk(KERN_DEBUG MCDX ": irq %d status 0x%02x\n",
+ irq, inb(DATA_REG));
+ } else {
+ MCDX_TRACE(("irq %d ambiguous hw status\n", irq));
+ }
+ }
+ stuffp->busy = 0;
+ wake_up_interruptible(&stuffp->busyq);
}
+/*
+ * FIXME!
+ * This seems to hang badly, when the driver is loaded with inappriopriate
+ * port/irq settings!
+ */
int mcdx_init(void)
{
int drive;
#ifdef MODULE
- WARN(("Version 1.9 for %s\n", kernel_version));
+ printk(KERN_INFO "Mitsumi driver version " VERSION " for %s\n",
+ kernel_version);
#else
- WARN(("Version 1.9\n"));
+ printk(KERN_INFO "Mitsumi driver version " VERSION "\n");
#endif
-
- WARN(("mcdx.c,v 1.2 1996/03/22 01:14:59 heiko Exp\n"));
-
- /* zero the pointer array */
- for (drive = 0; drive < MCDX_NDRIVES; drive++)
- mcdx_stuffp[drive] = NULL;
-
- /* do the initialisation */
- for (drive = 0; drive < MCDX_NDRIVES; drive++) {
- struct s_version version;
- struct s_drive_stuff* stuffp;
- int size;
+ printk("%d\n", MCDX_NDRIVES);
+ for (drive = 0; drive < MCDX_NDRIVES; drive++) {
+ struct {
+ u_char code;
+ u_char version;
+ } firmware;
+ int i;
+ struct s_drive_stuff *stuffp;
+ int size;
mcdx_blocksizes[drive] = 0;
+ mcdx_stuffp[drive] = 0;
- size = sizeof(*stuffp);
-
- TRACE((INIT, "init() try drive %d\n", drive));
+ size = sizeof(*stuffp);
- TRACE((INIT, "kmalloc space for stuffpt's\n"));
- TRACE((MALLOC, "init() malloc %d bytes\n", size));
if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
- WARN(("init() malloc failed\n"));
- break;
+ printk(KERN_ERR MCDX
+ ": malloc of drives data failed!\n");
+ break;
}
+ /* set default values */ memset(stuffp, 0, sizeof(*stuffp));
+ stuffp->autoclose = 1; /* close the door on open(2) */
- TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
-
- /* set default values */
- memset(stuffp, 0, sizeof(*stuffp));
- stuffp->autoclose = 1; /* close the door on open(2) */
-
- stuffp->present = 0; /* this should be 0 already */
- stuffp->toc = NULL; /* this should be NULL already */
-
- /* setup our irq and i/o addresses */
stuffp->irq = irq(mcdx_drive_map[drive]);
- stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
- stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
- stuffp->wreg_hcon = stuffp->wreg_reset + 1;
- stuffp->wreg_chn = stuffp->wreg_hcon + 1;
+ stuffp->base = port(mcdx_drive_map[drive]);
/* check if i/o addresses are available */
- if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
- WARN(("0x%3p,%d: "
- "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n",
- stuffp->wreg_data, stuffp->irq,
- stuffp->wreg_data,
- stuffp->wreg_data + MCDX_IO_SIZE - 1));
- TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
- kfree(stuffp);
- TRACE((INIT, "init() continue at next drive\n"));
- continue; /* next drive */
+ if (check_region(stuffp->base, MCDX_IO_SIZE)) {
+ printk(KERN_WARNING
+ "Init failed. I/O ports (0x%3x..0x%3x) "
+ "already in use.\n",
+ stuffp->base, stuffp->base + MCDX_IO_SIZE - 1);
+ kfree(stuffp);
+ continue; /* next drive */
}
-
- TRACE((INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data));
-
- TRACE((INIT, "init() hardware reset\n"));
- mcdx_reset(stuffp, HARD, 1);
-
- TRACE((INIT, "init() get version\n"));
- if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
+ /*
+ * Hardware reset.
+ */
+ outb(0, CHAN_REG); /* no dma, no irq -> hardware */
+ outb(0, RESET_REG); /* hw reset */
+
+ i = 10; /* number of retries */
+ while (-1 == get_command(stuffp, MCDX_CMD_GET_FIRMWARE,
+ &firmware, sizeof(firmware), 2 * HZ))
+ --i;
+ if (!i) {
/* failed, next drive */
- WARN(("%s=0x%3p,%d: Init failed. Can't get version.\n",
- MCDX,
- stuffp->wreg_data, stuffp->irq));
- TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
- kfree(stuffp);
- TRACE((INIT, "init() continue at next drive\n"));
+ printk(KERN_WARNING
+ "%s=0x%3x,%d: Init failed. Can't get version.\n",
+ MCDX, stuffp->base, stuffp->irq);
+ kfree(stuffp);
continue;
}
-
- switch (version.code) {
- case 'D':
- stuffp->readcmd = READ2X;
- stuffp->present = DOUBLE | DOOR | MULTI;
- break;
- case 'F':
- stuffp->readcmd = READ1X;
- stuffp->present = SINGLE | DOOR | MULTI;
- break;
- case 'M':
- stuffp->readcmd = READ1X;
- stuffp->present = SINGLE;
- break;
- default:
- stuffp->present = 0; break;
- }
-
- stuffp->playcmd = READ1X;
-
-
- if (!stuffp->present) {
- WARN(("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
- MCDX, stuffp->wreg_data, stuffp->irq));
+ switch (firmware.code) {
+ case 'D':
+ stuffp->double_speed = stuffp->door =
+ stuffp->multi_cap = 1;
+ break;
+ case 'F':
+ stuffp->door = stuffp->multi_cap = 1;
+ break;
+ case 'M':
+ break;
+ default:
kfree(stuffp);
- continue; /* next drive */
}
- TRACE((INIT, "init() register blkdev\n"));
- if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops) != 0) {
- WARN(("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
- MCDX,
- stuffp->wreg_data, stuffp->irq, MAJOR_NR));
+ if (!stuffp)
+ continue; /* next drive */
+
+ if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops)) {
kfree(stuffp);
- continue; /* next drive */
+ continue; /* next drive */
}
-
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = READ_AHEAD;
blksize_size[MAJOR_NR] = mcdx_blocksizes;
- TRACE((INIT, "init() subscribe irq and i/o\n"));
mcdx_irq_map[stuffp->irq] = stuffp;
- if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, DEVICE_NAME, NULL)) {
- WARN(("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
- MCDX,
- stuffp->wreg_data, stuffp->irq, stuffp->irq));
+ if (request_irq(stuffp->irq, mcdx_intr,
+ SA_INTERRUPT, DEVICE_NAME, NULL)) {
stuffp->irq = 0;
kfree(stuffp);
- continue;
- }
- request_region((unsigned int) stuffp->wreg_data,
- MCDX_IO_SIZE,
- DEVICE_NAME);
-
- TRACE((INIT, "init() get garbage\n"));
- {
- int i;
- mcdx_delay(stuffp, HZ/2);
- for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status);
+ continue; /* next drive */
}
+ request_region(stuffp->base, MCDX_IO_SIZE, DEVICE_NAME);
+ /* get junk after some delay.
+ */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ / 2;
+ schedule();
+ for (i = 100; i; i--)
+ (void) inb(STAT_REG);
#if WE_KNOW_WHY
- outb(0x50, (unsigned int) stuffp->wreg_chn); /* irq 11 -> channel register */
+ outb(0x50, CHAN_REG); /* irq 11 -> channel register */
#endif
- TRACE((INIT, "init() set non dma but irq mode\n"));
- mcdx_config(stuffp, 1);
+ config_drive(stuffp);
- stuffp->minor = drive;
-
- WARN((DEVICE_NAME " installed at 0x%3p, irq %d."
- " (Firmware version %c %x)\n",
- stuffp->wreg_data, stuffp->irq, version.code,
- version.ver));
+ printk(KERN_INFO MCDX "%d: at 0x%3x, irq %d, firmware: %c %x\n",
+ drive, stuffp->base, stuffp->irq,
+ firmware.code, firmware.version);
mcdx_stuffp[drive] = stuffp;
- TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
}
return 0;
}
-static int
-mcdx_transfer(struct s_drive_stuff *stuffp,
- char *p, int sector, int nr_sectors)
-/* This seems to do the actually transfer. But it does more. It
- keeps track of errors occurred and will (if possible) fall back
- to single speed on error.
- Return: -1 on timeout or other error
- else status byte (as in stuff->st) */
-{
- int ans;
-
- ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
- return ans;
-#if FALLBACK
- if (-1 == ans) stuffp->readerrs++;
- else return ans;
-
- if (stuffp->readerrs && stuffp->readcmd == READ1X) {
- WARN(("XXX Already reading 1x -- no chance\n"));
- return -1;
- }
-
- WARN(("XXX Fallback to 1x\n"));
-
- stuffp->readcmd = READ1X;
- return mcdx_transfer(stuffp, p, sector, nr_sectors);
-#endif
-
-}
-
-
-static int mcdx_xfer(struct s_drive_stuff *stuffp,
- char *p, int sector, int nr_sectors)
-/* This does actually the transfer from the drive.
- Return: -1 on timeout or other error
- else status byte (as in stuff->st) */
-{
- int off;
- int done = 0;
-
- TRACE((TRANSFER, "transfer() %d sectors at sector %d\n",
- nr_sectors, sector));
-
- if (stuffp->audio) {
- WARN(("attempt to read from audio cd\n"));
- return -1;
- }
-
- while (stuffp->lock) {
- interruptible_sleep_on(&stuffp->lockq);
- TRACE((SLEEP, "xfer: lock = %d\n",
- stuffp->lock));
- }
-
- if (stuffp->valid
- && (sector >= stuffp->pending)
- && (sector < stuffp->off_direct)) {
-
-
- off = stuffp->off_requested < (off = sector + nr_sectors)
- ? stuffp->off_requested : off;
-
- stuffp->lock = current->pid;
-
- do {
- /* wait for the drive become idle, but first
- check for possible occurred errors --- the drive
- seems to report them asynchronously */
-
- current->timeout = jiffies + 5 * HZ;
- while (stuffp->introk && stuffp->busy && current->timeout) {
- interruptible_sleep_on(&stuffp->busyq);
- TRACE((SLEEP, "request: busy = %d, timeout = %d\n",
- stuffp->busy, current->timeout));
- }
-
- /* test for possible errors */
- if (current->timeout == 0 || !stuffp->introk) {
- if (current->timeout == 0) {
- WARN(("mcdx_transfer() timeout\n"));
- } else if (!stuffp->introk) {
- WARN(("mcdx_transfer() error via irq reported\n"));
- } else {
- WARN(("mcdx_transfer() unknown failure in data request\n"));
- }
-
- stuffp->lock = 0;
- stuffp->busy = 0;
- stuffp->valid = 0;
-
- wake_up_interruptible(&stuffp->lockq);
- TRACE((TRANSFER, "transfer() done (-1)\n"));
- return -1;
- }
-
- /* test if it's the first sector of a block,
- * there we have to skip some bytes as we read raw data */
- if (stuffp->xa && (0 == (stuffp->pending & 3))) {
- const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
- TRACE((TRANSFER, "transfer() sector %d, skip %d header bytes\n",
- stuffp->pending, HEAD));
- insb((unsigned int) stuffp->rreg_data, p, HEAD);
- }
-
- /* now actually read the data */
-
- TRACE((TRANSFER, "transfer() read sector %d\n", stuffp->pending));
- insb((unsigned int) stuffp->rreg_data, p, 512);
-
- /* test if it's the last sector of a block,
- * if so, we have to expect an interrupt and to skip some
- * data too */
- if ((stuffp->busy = (3 == (stuffp->pending & 3))) && stuffp->xa) {
- char dummy[CD_XA_TAIL];
- TRACE((TRANSFER, "transfer() sector %d, skip %d trailer bytes\n",
- stuffp->pending, CD_XA_TAIL));
- insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
- }
-
- if (stuffp->pending == sector) {
- p += 512;
- done++;
- sector++;
- }
- } while (++(stuffp->pending) < off);
-
- stuffp->lock = 0;
- wake_up_interruptible(&stuffp->lockq);
-
- } else {
-
- static unsigned char cmd[] = {
- 0,
- 0, 0, 0,
- 0, 0, 0
- };
-
- cmd[0] = stuffp->readcmd;
-
- stuffp->valid = 1;
- stuffp->pending = sector & ~3;
-
- /* do some sanity checks */
- TRACE((TRANSFER, "transfer() request sector %d\n", stuffp->pending));
- if (stuffp->pending > stuffp->lastsector) {
- WARN(("transfer() sector %d from nirvana requested.\n",
- stuffp->pending));
- stuffp->status = MCDX_ST_EOM;
- stuffp->valid = 0;
- TRACE((TRANSFER, "transfer() done (-1)\n"));
- return -1;
- }
-
- if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE)
- > stuffp->lastsector + 1)
- stuffp->off_direct = stuffp->lastsector + 1;
- if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
- > stuffp->lastsector + 1)
- stuffp->off_requested = stuffp->lastsector + 1;
-
- TRACE((TRANSFER, "transfer() pending %d\n", stuffp->pending));
- TRACE((TRANSFER, "transfer() off_dir %d\n", stuffp->off_direct));
- TRACE((TRANSFER, "transfer() off_req %d\n", stuffp->off_requested));
-
- {
- struct s_msf pending;
- log2msf(stuffp->pending / 4, &pending);
- cmd[1] = pending.minute;
- cmd[2] = pending.second;
- cmd[3] = pending.frame;
- }
-
- stuffp->busy = 1;
- cmd[6] = (unsigned char) (stuffp->off_requested - stuffp->pending) / 4;
-
- outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
-
- }
-
- stuffp->off_direct = (stuffp->off_direct += done) < stuffp->off_requested
- ? stuffp->off_direct : stuffp->off_requested;
-
- TRACE((TRANSFER, "transfer() done (%d)\n", done));
- return done;
-}
-
-
-/* Access to elements of the mcdx_drive_map members */
-
-static char* port(int *ip) { return (char*) ip[0]; }
-static int irq(int *ip) { return ip[1]; }
-
-/* Misc number converters */
-
-static unsigned int bcd2uint(unsigned char c)
-{ return (c >> 4) * 10 + (c & 0x0f); }
-
-static unsigned int uint2bcd(unsigned int ival)
-{ return ((ival / 10) << 4) | (ival % 10); }
-
-static void log2msf(unsigned int l, struct s_msf* pmsf)
-{
- l += CD_BLOCK_OFFSET;
- pmsf->minute = uint2bcd(l / 4500), l %= 4500;
- pmsf->second = uint2bcd(l / 75);
- pmsf->frame = uint2bcd(l % 75);
-}
+#ifdef MODULE
-static unsigned int msf2log(const struct s_msf* pmsf)
-{
- return bcd2uint(pmsf->frame)
- + bcd2uint(pmsf->second) * 75
- + bcd2uint(pmsf->minute) * 4500
- - CD_BLOCK_OFFSET;
-}
-
-int mcdx_readtoc(struct s_drive_stuff* stuffp)
-/* Read the toc entries from the CD,
- * Return: -1 on failure, else 0 */
+int init_module(void)
{
+ int i;
- if (stuffp->toc) {
- TRACE((READTOC, "ioctl() toc already read\n"));
- return 0;
- }
-
- TRACE((READTOC, "ioctl() readtoc for %d tracks\n",
- stuffp->di.n_last - stuffp->di.n_first + 1));
-
- if (-1 == mcdx_hold(stuffp, 1)) return -1;
-
- TRACE((READTOC, "ioctl() tocmode\n"));
- if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
-
- /* all seems to be ok so far ... malloc */
- {
- int size;
- size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
-
- TRACE((MALLOC, "ioctl() malloc %d bytes\n", size));
- stuffp->toc = kmalloc(size, GFP_KERNEL);
- if (!stuffp->toc) {
- WARN(("Cannot malloc %s bytes for toc\n", size));
- mcdx_setdrivemode(stuffp, DATA, 1);
- return -EIO;
- }
- }
-
- /* now read actually the index */
- {
- int trk;
- int retries;
-
- for (trk = 0;
- trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
- trk++)
- stuffp->toc[trk].index = 0;
-
- for (retries = 300; retries; retries--) { /* why 300? */
- struct s_subqcode q;
- unsigned int idx;
-
- if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
- mcdx_setdrivemode(stuffp, DATA, 1);
- return -EIO;
- }
-
- idx = bcd2uint(q.index);
-
- if ((idx > 0)
- && (idx <= stuffp->di.n_last)
- && (q.tno == 0)
- && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
- stuffp->toc[idx - stuffp->di.n_first] = q;
- TRACE((READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk));
- trk--;
- }
- if (trk == 0) break;
+ mcdx_init();
+ for (i = 0; i < MCDX_NDRIVES; i++) {
+ if (mcdx_stuffp[i]) {
+ register_symtab(0);
+ return 0;
}
- memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1],
- 0, sizeof(stuffp->toc[0]));
- stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
- = stuffp->di.msf_leadout;
}
-
- /* unset toc mode */
- TRACE((READTOC, "ioctl() undo toc mode\n"));
- if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
- return -EIO;
-
-#if MCDX_DEBUG && READTOC
- { int trk;
- for (trk = 0;
- trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
- trk++)
- TRACE((READTOC, "ioctl() %d readtoc %02x %02x %02x"
- " %02x:%02x.%02x %02x:%02x.%02x\n",
- trk + stuffp->di.n_first,
- stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
- stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
- stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame));
- }
-#endif
-
- return 0;
+ return -EIO;
}
-static int
-mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
-{
- unsigned char cmd[7] = {
- 0, 0, 0, 0, 0, 0, 0
- };
-
- cmd[0] = stuffp->playcmd;
-
- cmd[1] = msf->cdmsf_min0;
- cmd[2] = msf->cdmsf_sec0;
- cmd[3] = msf->cdmsf_frame0;
- cmd[4] = msf->cdmsf_min1;
- cmd[5] = msf->cdmsf_sec1;
- cmd[6] = msf->cdmsf_frame1;
-
- TRACE((PLAYMSF, "ioctl(): play %x "
- "%02x:%02x:%02x -- %02x:%02x:%02x\n",
- cmd[0], cmd[1], cmd[2], cmd[3],
- cmd[4], cmd[5], cmd[6]));
-
- outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
-
- if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
- WARN(("playmsf() timeout\n"));
- return -1;
- }
-
- stuffp->audiostatus = CDROM_AUDIO_PLAY;
- return 0;
-}
-
-static int
-mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti)
-{
- struct s_subqcode* p;
- struct cdrom_msf msf;
-
- if (-1 == mcdx_readtoc(stuffp)) return -1;
-
- if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
- else p = &stuffp->start;
-
- msf.cdmsf_min0 = p->dt.minute;
- msf.cdmsf_sec0 = p->dt.second;
- msf.cdmsf_frame0 = p->dt.frame;
-
- if (ti) {
- p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
- stuffp->stop = *p;
- } else p = &stuffp->stop;
-
- msf.cdmsf_min1 = p->dt.minute;
- msf.cdmsf_sec1 = p->dt.second;
- msf.cdmsf_frame1 = p->dt.frame;
-
- return mcdx_playmsf(stuffp, &msf);
-}
-
-
-/* Drive functions ************************************************/
-
-static int
-mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
-{
- if (stuffp->present & DOOR)
- return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries);
- else
- return 0;
-}
-
-static int
-mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
-
-static int
-mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
-
-static int
-mcdx_eject(struct s_drive_stuff *stuffp, int tries)
-{
- if (stuffp->present & DOOR) {
- stuffp->ejected = jiffies;
- return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries);
- } else return 0;
-}
-
-static int
-mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
- struct s_subqcode *sub,
- int tries)
-{
- char buf[11];
- int ans;
-
- if (-1 == (ans = mcdx_talk(
- stuffp, "\x20", 1, buf, sizeof(buf),
- 2 * HZ, tries)))
- return -1;
- sub->control = buf[1];
- sub->tno = buf[2];
- sub->index = buf[3];
- sub->tt.minute = buf[4];
- sub->tt.second = buf[5];
- sub->tt.frame = buf[6];
- sub->dt.minute = buf[8];
- sub->dt.second = buf[9];
- sub->dt.frame = buf[10];
-
- return ans;
-}
-
-static int
-mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
-{
- char buf[5];
- int ans;
-
- if (stuffp->present & MULTI) {
- ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries);
- multi->multi = buf[1];
- multi->msf_last.minute = buf[2];
- multi->msf_last.second = buf[3];
- multi->msf_last.frame = buf[4];
- return ans;
- } else {
- multi->multi = 0;
- return 0;
- }
-}
-
-static int
-mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
-{
- char buf[9];
- int ans;
- ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
- if (ans == -1) {
- info->n_first = 0;
- info->n_last = 0;
- } else {
- info->n_first = bcd2uint(buf[1]);
- info->n_last = bcd2uint(buf[2]);
- info->msf_leadout.minute = buf[3];
- info->msf_leadout.second = buf[4];
- info->msf_leadout.frame = buf[5];
- info->msf_first.minute = buf[6];
- info->msf_first.second = buf[7];
- info->msf_first.frame = buf[8];
- }
- return ans;
-}
-
-static int
-mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
+void cleanup_module(void)
{
- char cmd[2];
- int ans;
-
- TRACE((HW, "setdrivemode() %d\n", mode));
-
- if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
- return -1;
+ int i;
- switch (mode) {
- case TOC: cmd[1] |= 0x04; break;
- case DATA: cmd[1] &= ~0x04; break;
- case RAW: cmd[1] |= 0x40; break;
- case COOKED: cmd[1] &= ~0x40; break;
- default: break;
- }
- cmd[0] = 0x50;
- return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
-}
+ unregister_blkdev(MAJOR_NR, DEVICE_NAME);
-static int
-mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
-{
- unsigned char cmd[2] = { 0xa0 };
- TRACE((HW, "setdatamode() %d\n", mode));
- switch (mode) {
- case MODE0: cmd[1] = 0x00; break;
- case MODE1: cmd[1] = 0x01; break;
- case MODE2: cmd[1] = 0x02; break;
- default: return -EINVAL;
+ for (i = 0; i < MCDX_NDRIVES; i++) {
+ struct s_drive_stuff *stuffp;
+ stuffp = mcdx_stuffp[i];
+ if (!stuffp)
+ continue;
+ release_region(stuffp->base, MCDX_IO_SIZE);
+ free_irq(stuffp->irq, NULL);
+ if (stuffp->toc) {
+ kfree(stuffp->toc);
+ }
+ mcdx_stuffp[i] = NULL;
+ kfree(stuffp);
}
- return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
}
-static int
-mcdx_config(struct s_drive_stuff *stuffp, int tries)
-{
- char cmd[4];
-
- TRACE((HW, "config()\n"));
-
- cmd[0] = 0x90;
-
- cmd[1] = 0x10; /* irq enable */
- cmd[2] = 0x05; /* pre, err irq enable */
-
- if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
- return -1;
-
- cmd[1] = 0x02; /* dma select */
- cmd[2] = 0x00; /* no dma */
-
- return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
-}
-
-static int
-mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
-{
- char buf[3];
- int ans;
+#else /* MODULE */
- if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
- 1, buf, sizeof(buf), 2 * HZ, tries)))
- return ans;
-
- ver->code = buf[1];
- ver->ver = buf[2];
-
- return ans;
-}
-
-static int
-mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
-{
- if (mode == HARD) {
- outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
- outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
- return 0;
- } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
-}
-
-static int
-mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
-{
- char cmd[2] = { 0xfe };
- if (stuffp->present & DOOR) {
- cmd[1] = lock ? 0x01 : 0x00;
- return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries);
- } else return 0;
-}
-
-static int
-mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
-
-static int
-mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
-{
- unsigned long timeout = to + jiffies;
- char c;
-
- if (!buf) buf = &c;
-
- while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
- if (jiffies > timeout) return -1;
- mcdx_delay(stuffp, delay);
- }
-
- *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
-
- return 0;
-}
-
-static int
-mcdx_setattentuator(
- struct s_drive_stuff* stuffp,
- struct cdrom_volctrl* vol,
- int tries)
+/*
+ * This function is used by the kernel in init/main.c to provide semantics
+ * for the corresponding kernel options. It's unused otherwise.
+ */
+void mcdx_setup(char *str, int *pi)
{
- char cmd[5];
- cmd[0] = 0xae;
- cmd[1] = vol->channel0;
- cmd[2] = 0;
- cmd[3] = vol->channel1;
- cmd[4] = 0;
-
- return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
+ if (pi[0] > 0)
+ mcdx_drive_map[0][0] = pi[1];
+ if (pi[0] > 1)
+ mcdx_drive_map[0][1] = pi[2];
}
-
-/* ex:set ts=4 sw=4: */
+#endif /* MODULE */
* Also for the TEAC CD-55A drive.
* Also for the ECS-AT "Vertos 100" drive.
* Not for Sanyo drives (but for the H94A, sjcd is there...).
- * Not for any other Funai drives than the CD200 types
- * (sometimes labelled E2550UA or MK4015 or E2880UA).
+ * Not for any other Funai drives than the CD200 types (sometimes
+ * labelled E2550UA or MK4015 or 2800F).
*/
-#define VERSION "v4.2 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "v4.3 Eberhard Moenkeberg <emoenke@gwdg.de>"
/* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
*
* is user-configurable (even at runtime), but to get aware of this, one
* needs a special mental quality: the ability to read.
*
+ * 4.3 CD200F does not like to receive a command while the drive is
+ * reading the ToC; still trying to solve it.
+ * Removed some redundant verify_area calls (yes, Heiko Eissfeldt
+ * is visiting all the Linux CDROM drivers ;-).
+ *
*
* TODO
*
*/
static void msg(int level, const char *fmt, ...)
{
+#if DISTRIBUTION
+#define MSG_LEVEL KERN_NOTICE
+#else
+#define MSG_LEVEL KERN_INFO
+#endif DISTRIBUTION
+
char buf[256];
va_list args;
msgnum++;
if (msgnum>99) msgnum=0;
- sprintf(buf, KERN_NOTICE "%s-%d [%02d]: ", major_name, d, msgnum);
+ sprintf(buf, MSG_LEVEL "%s-%d [%02d]: ", major_name, d, msgnum);
va_start(args, fmt);
vsprintf(&buf[18], fmt, args);
va_end(args);
drvcmd[2]=0;
drvcmd[3]=150;
}
- flags_cmd_out=f_putcmd|f_ResponseStatus;
+ flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
}
else if (famT_drive)
{
case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n");
- st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_tocentry));
+ st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
if (st) return (st);
memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry));
i=tocentry.cdte_track;
else if (tocentry.cdte_format==CDROM_LBA) /* blk required */
tocentry.cdte_addr.lba=msf2blk(D_S[d].TocBuffer[i].address);
else return (-EINVAL);
- st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry));
- if (st) return (st);
memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry));
return (0);
}
st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
if (st) return (st);
- st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
- if (st) return (st);
memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
switch (D_S[d].audio_state)
{
case CDROMMULTISESSION: /* tell start-of-last-session */
msg(DBG_IOC,"ioctl: CDROMMULTISESSION entered.\n");
- st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_multisession));
+ st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
if (st) return (st);
memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
if (ms_info.addr_format==CDROM_MSF) /* MSF-bin requested */
else return (-EINVAL);
if (D_S[d].f_multisession) ms_info.xa_flag=1; /* valid redirection address */
else ms_info.xa_flag=0; /* invalid redirection address */
- st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_multisession));
- if (st) return (st);
memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
msg(DBG_MUL,"ioctl: CDROMMULTISESSION done (%d, %08X).\n",
ms_info.xa_flag, ms_info.addr.lba);
if [ "$CONFIG_WATCHDOG" != "n" ]; then
bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
tristate ' WDT Watchdog timer' CONFIG_WDT
- if [ "$CONFIG_WDT" = "y" ]; then
+ if [ "$CONFIG_WDT" != "n" ]; then
bool ' WDT501 features' CONFIG_WDT_501
if [ "$CONFIG_WDT_501" = "y" ]; then
bool ' Fan Tachometer' CONFIG_WDT_501_FAN
fi
else
- bool ' Software Watchdog' CONFIG_SOFT_WATCHDOG
+ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
fi
fi
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
M = y
endif
-ifdef CONFIG_SOFT_WATCHDOG
-L_OBJS += softdog.o
+ifeq ($(CONFIG_SOFT_WATCHDOG),y)
M = y
-# This is not modularized, so if configured then "misc.c" will be resident
+L_OBJS += softdog.o
+else
+ ifeq ($(CONFIG_SOFT_WATCHDOG),m)
+ M_OBJS += softdog.o
+ MM = m
+ endif
endif
ifdef CONFIG_SUN_MOUSE
for (i=0; i<0x100000; i++)
if ((inb_p(0x64) & 0x02) == 0)
return;
- printk("Keyboard timed out\n");
+ printk(KERN_WARNING "Keyboard timed out\n");
}
static inline void send_cmd(unsigned char c)
if (!(status & 0x21)) { /* neither ODS nor OBF */
scancode = inb(0x60); /* read data anyway */
#if 0
- printk("keyboard: status 0x%x mask 0x%x data 0x%x\n",
+ printk(KERN_DEBUG "keyboard: status 0x%x mask 0x%x data 0x%x\n",
status, kbd_read_mask, scancode);
#endif
}
/* strange ... */
reply_expected = 1;
#if 0
- printk("keyboard reply expected - got %02x\n", scancode);
+ printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
+ scancode);
#endif
}
if (scancode == 0) {
#ifdef KBD_REPORT_ERR
- printk("keyboard buffer overflow\n");
+ printk(KERN_INFO "keyboard buffer overflow\n");
#endif
prev_scancode = 0;
goto end_kbd_intr;
#ifndef KBD_IS_FOCUS_9000
#ifdef KBD_REPORT_ERR
if (!raw_mode)
- printk("keyboard error\n");
+ printk(KERN_DEBUG "keyboard error\n");
#endif
#endif
prev_scancode = 0;
} else {
#ifdef KBD_REPORT_UNKN
if (!raw_mode)
- printk("keyboard: unknown e1 escape sequence\n");
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
#endif
prev_scancode = 0;
goto end_kbd_intr;
else {
#ifdef KBD_REPORT_UNKN
if (!raw_mode)
- printk("keyboard: unknown scancode e0 %02x\n", scancode);
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
#endif
goto end_kbd_intr;
}
if (!keycode) {
if (!raw_mode) {
#ifdef KBD_REPORT_UNKN
- printk("keyboard: unrecognized scancode (%02x) - ignored\n"
- , scancode);
+ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
+ " - ignored\n", scancode);
#endif
}
goto end_kbd_intr;
static void do_lowercase(unsigned char value, char up_flag)
{
- printk("keyboard.c: do_lowercase was called - impossible\n");
+ printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n");
}
static void do_self(unsigned char value, char up_flag)
if (func_table[value])
puts_queue(func_table[value]);
} else
- printk("do_fn called with value=%d\n", value);
+ printk(KERN_ERR "do_fn called with value=%d\n", value);
}
static void do_pad(unsigned char value, char up_flag)
*/
kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
if (kbd_wait_for_input() != 0x55) {
- printk("initialize_kbd: keyboard failed self test.\n");
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard failed self test.\n");
restore_flags(flags);
return(-1);
}
*/
kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
if (kbd_wait_for_input() != 0x00) {
- printk("initialize_kbd: keyboard failed self test 2.\n");
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard failed self test 2.\n");
restore_flags(flags);
return(-1);
}
*/
kbd_write(KBD_DATA_REG, KBD_RESET);
if (kbd_wait_for_input() != KBD_ACK) {
- printk("initialize_kbd: reset kbd failed, no ACK.\n");
+ printk(KERN_WARNING "initialize_kbd: "
+ "reset kbd failed, no ACK.\n");
restore_flags(flags);
return(-1);
}
if (kbd_wait_for_input() != KBD_POR) {
- printk("initialize_kbd: reset kbd failed, not POR.\n");
+ printk(KERN_WARNING "initialize_kbd: "
+ "reset kbd failed, not POR.\n");
restore_flags(flags);
return(-1);
}
*/
kbd_write(KBD_DATA_REG, KBD_DISABLE);
if (kbd_wait_for_input() != KBD_ACK) {
- printk("initialize_kbd: disable kbd failed, no ACK.\n");
+ printk(KERN_WARNING "initialize_kbd: "
+ "disable kbd failed, no ACK.\n");
restore_flags(flags);
return(-1);
}
*/
kbd_write(KBD_DATA_REG, KBD_ENABLE);
if (kbd_wait_for_input() != KBD_ACK) {
- printk("initialize_kbd: keyboard enable failed.\n");
+ printk(KERN_WARNING "initialize_kbd: "
+ "keyboard enable failed.\n");
restore_flags(flags);
return(-1);
}
/*
- * SoftDog 0.02: A Software Watchdog Device
+ * SoftDog 0.04: A Software Watchdog Device
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
*
* Software only watchdog driver. Unlike its big brother the WDT501P
* driver this won't always recover a failed machine.
+ *
+ * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
+ * Modularised.
+ * Added soft_margin; use upon insmod to change the timer delay.
+ * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
+ * minors.
*/
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#define WATCHDOG_MINOR 130
-#define TIMER_MARGIN (60*HZ) /* Allow 1 minute */
+#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */
+
+static int soft_margin = TIMER_MARGIN; /* in seconds */
/*
* Our timer
static void watchdog_fire(unsigned long data)
{
extern void hard_reset_now(void);
+#ifdef ONLY_TESTING
+ printk(KERN_CRIT "SOFTDOG: Would Reboot.\n");
+#else
+ printk(KERN_CRIT "SOFTDOG: Initiating system reboot.\n");
hard_reset_now();
printk("WATCHDOG: Reboot didn't ?????\n");
+#endif
}
/*
{
if(timer_alive)
return -EBUSY;
+ MOD_INC_USE_COUNT;
/*
* Activate timer
*/
- watchdog_ticktock.expires=jiffies+TIMER_MARGIN;
+ watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
add_timer(&watchdog_ticktock);
timer_alive++;
return 0;
{
/*
* Shut off the timer.
+ * Lock it in if it's a module and we defined ...NOWAYOUT
*/
#ifndef CONFIG_WATCHDOG_NOWAYOUT
del_timer(&watchdog_ticktock);
-#endif
+ MOD_DEC_USE_COUNT;
timer_alive=0;
+#endif
}
static int softdog_write(struct inode *inode, struct file *file, const char *data, int len)
* Refresh the timer.
*/
del_timer(&watchdog_ticktock);
- watchdog_ticktock.expires=jiffies+TIMER_MARGIN;
+ watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
add_timer(&watchdog_ticktock);
return 1;
}
-/*
- * The mouse stuff ought to be renamed misc_register etc before 1.4...
- */
-
-void watchdog_init(void)
+static struct file_operations softdog_fops=
+{
+ NULL, /* Seek */
+ NULL, /* Read */
+ softdog_write, /* Write */
+ NULL, /* Readdir */
+ NULL, /* Select */
+ NULL, /* Ioctl */
+ NULL, /* MMap */
+ softdog_open,
+ softdog_release,
+ NULL,
+ NULL /* Fasync */
+};
+
+static struct miscdevice softdog_miscdev=
{
- static struct file_operations softdog_fops=
- {
- NULL, /* Seek */
- NULL, /* Read */
- softdog_write, /* Write */
- NULL, /* Readdir */
- NULL, /* Select */
- NULL, /* Ioctl */
- NULL, /* MMap */
- softdog_open,
- softdog_release,
- NULL,
- NULL /* Fasync */
- };
- static struct miscdevice softdog_mouse={
- WATCHDOG_MINOR,
- "softdog",
- &softdog_fops
- };
+ WATCHDOG_MINOR,
+ "softdog",
+ &softdog_fops
+};
- misc_register(&softdog_mouse);
+void watchdog_init(void)
+{
+ misc_register(&softdog_miscdev);
init_timer(&watchdog_ticktock);
watchdog_ticktock.function=watchdog_fire;
- printk("Software Watchdog Timer: 0.03\n");
+ printk("Software Watchdog Timer: 0.04, timer margin: %d sec\n", soft_margin);
}
+
+#ifdef MODULE
+int init_module(void)
+{
+ watchdog_init();
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ misc_deregister(&softdog_miscdev);
+}
+#endif
* If the time is zero, turn off sound ourselves.
*/
ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+ if ((arg & 0xffff) == 0 ) arg |= 1; /* jp: huh? */
count = ticks ? (1193180 / (arg & 0xffff)) : 0;
kd_mksound(count, ticks);
return 0;
if (!perm)
return -EPERM;
- i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode));
+ i = verify_area(VERIFY_READ, (void *)vtmode, sizeof(struct vt_mode));
if (i)
return i;
mode = get_user(&vtmode->mode);
}
}
-static inline int isdn_tty_paranoia_check(modem_info * info, dev_t device, const char *routine)
+static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
{
#ifdef MODEM_PARANOIA_CHECK
if (!info) {
if [ "$CONFIG_SLIP" != "n" ]; then
bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+ bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
fi
bool 'Radio network interfaces' CONFIG_NET_RADIO
if [ "$CONFIG_NET_RADIO" != "n" ]; then
#include <linux/config.h>
#include <linux/module.h>
-/* Undef this, if you don't need 6bit encapsulation code in the driver */
-#define CONFIG_SLIP_MODE_SLIP6
-
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>
return SCSI_ABORT_SUCCESS;
}
-int ultrastor_reset(Scsi_Cmnd * SCpnt)
+int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
{
int flags;
register int i;
printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
/* A command has been lost. Reset and report an error
for all commands. */
- ultrastor_reset(NULL);
+ ultrastor_reset(NULL, 0);
return;
}
#endif
const char *ultrastor_info(struct Scsi_Host * shpnt);
int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int ultrastor_abort(Scsi_Cmnd *);
-int ultrastor_reset(Scsi_Cmnd *);
+int ultrastor_reset(Scsi_Cmnd *, unsigned int);
int ultrastor_biosparam(Disk *, kdev_t, int *);
comment 'Filesystems'
bool 'Quota support' CONFIG_QUOTA
+bool 'Mandatory lock support' CONFIG_LOCK_MANDATORY
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'Extended fs support' CONFIG_EXT_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
#define _PATH_JAVA "/usr/bin/java"
#define _PATH_APPLET "/usr/bin/appletviewer"
-#define _PATH_SH "/bin/sh"
+#define _PATH_SH "/bin/bash"
+
+char binfmt_java_interpreter[65] = _PATH_JAVA;
+char binfmt_java_appletviewer[65] = _PATH_APPLET;
static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
{
bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
bprm->argc++;
- strcpy (bprm->buf, _PATH_JAVA);
+ strcpy (bprm->buf, binfmt_java_interpreter);
cp = bprm->buf;
bprm->p = copy_strings(1, &cp, bprm->page, bprm->p, 2);
bprm->argc++;
bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
bprm->argc++;
- strcpy (bprm->buf, _PATH_APPLET);
+ strcpy (bprm->buf, binfmt_java_appletviewer);
cp = bprm->buf;
bprm->p = copy_strings(1, &cp, bprm->page, bprm->p, 2);
bprm->argc++;
- strcpy (bprm->buf, _PATH_BSHELL);
+ strcpy (bprm->buf, _PATH_SH);
interp = bprm->buf;
if ((i_name = strrchr (bprm->buf, '/')) != NULL)
i_name++;
/* serial module kerneld load support */
struct tty_driver *get_tty_driver(kdev_t device);
#define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
-#define need_serial(ma,mi) (get_tty_driver(to_kdev_t(MKDEV(ma,mi))) == NULL)
+#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
#endif
struct device_struct {
void dquot_init(void)
{
- printk("VFS: Diskquotas version %s initialized\r\n", __DQUOT_VERSION__);
+ printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\r\n",
+ __DQUOT_VERSION__);
memset(hash_table, 0, sizeof(hash_table));
memset((caddr_t)&dqstats, 0, sizeof(dqstats));
first_dquot = NODQUOT;
#ifdef CONFIG_QUOTA
-void add_dquot_ref(dev_t dev, short type)
+void add_dquot_ref(kdev_t dev, short type)
{
struct file *filp;
int cnt;
}
}
-void reset_dquot_ptrs(dev_t dev, short type)
+void reset_dquot_ptrs(kdev_t dev, short type)
{
struct file *filp;
int cnt;
* Fixed deadlock condition for pathological code that mixes calls to
* flock() and fcntl().
* Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
+ *
+ * BUG: MUST DISALLOW MANDATORY LOCK ON NFS/SMB/NCP FILE SYSTEM
+ * TO MATCH SYS5.4 SEMANTICS.
+ *
*/
+#include <linux/config.h>
+
#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/kernel.h>
int locks_mandatory_locked(struct inode *inode)
{
+#ifdef CONFIG_LOCK_MANDATORY
struct file_lock *fl;
/* Search the lock list for this inode for any POSIX locks.
if ((fl->fl_flags & F_POSIX) && (fl->fl_owner != current))
return (-EAGAIN);
}
+#endif
return (0);
}
/* Candidates for mandatory locking have the setgid bit set
* but no group execute bit - an otherwise meaningless combination.
*/
+#ifdef CONFIG_LOCK_MANDATORY
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
return (locks_mandatory_area(read_write, inode, filp, offset,
count));
+#endif
return (0);
}
-
+
int locks_mandatory_area(int read_write, struct inode *inode,
struct file *filp, unsigned int offset,
unsigned int count)
{
+#ifdef CONFIG_LOCK_MANDATORY
struct file_lock *fl;
repeat:
goto repeat;
}
}
+#endif
return (0);
}
p += sprintf(p, "FLOCK ADVISORY ");
}
p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
- p += sprintf(p, "%d %04x:%ld %ld %ld ",
- fl->fl_owner->pid, fl->fl_file->f_inode->i_dev,
+ p += sprintf(p, "%d %s:%ld %ld %ld ",
+ fl->fl_owner->pid, kdevname(fl->fl_file->f_inode->i_dev),
fl->fl_file->f_inode->i_ino, fl->fl_start,
fl->fl_end);
p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n%d:%s",
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
/* XXX - should be ui_db[1] on little endian ufs filesystems */
- inode->i_rdev = ufsip->ui_db[0];
+ inode->i_rdev = to_kdev_t(ufsip->ui_db[0]);
}
/* XXX - implement fast and slow symlinks */
dc_mask_transmit_ready)
/* now some constants related to the cm206 */
-/* another drive status byte, echoed by the cm206 on most commmands */
+/* another drive status byte, echoed by the cm206 on most commands */
#define dsb_error_condition 0x1
#define dsb_play_in_progress 0x4
/*
* Definitions for the Mitsumi CDROM interface
* Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.9
+ * VERSION: 2.2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
*/
+#ifndef __MCDX_H
+#define __MCDX_H
/*
- * The following lines are for user configuration
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * PLEASE CONFIGURE THIS ACCORIDNG TO YOURS HARDWARE/JUMPER SETTINGS.
*
- * {0|1} -- 1 if you want the driver detect your drive, may crash and
- * needs a long time to seek. The higher the address the longer the
- * seek.
+ * o MCDX_NDRIVES : number of used entries of the following table
+ * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller
*
- * WARNING: AUTOPROBE doesn't work.
+ * NOTE: I didn't get a drive at irq 9(2) working. Not even alone.
*/
-#define MCDX_AUTOPROBE 0
-
-/*
- * Drive specific settings according to the jumpers on the controller
- * board(s).
- * o MCDX_NDRIVES : number of used entries of the following table
- * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller
- *
- * NOTE: I didn't get a drive at irq 9(2) working. Not even alone.
- */
-#if MCDX_AUTOPROBE == 0
- #define MCDX_NDRIVES 1
- #define MCDX_DRIVEMAP { \
- {0x300, 11}, \
+ /* #define I_WAS_IN_MCDX_H */
+#define MCDX_NDRIVES 1
+#define MCDX_DRIVEMAP { {0x300, 11}, \
{0x304, 05}, \
{0x000, 00}, \
{0x000, 00}, \
{0x000, 00}, \
- }
-#else
- #error Autoprobing is not implemented yet.
-#endif
-
-#ifndef MCDX_QUIET
-#define MCDX_QUIET 1
-#endif
-
-#ifndef MCDX_DEBUG
-#define MCDX_DEBUG 0
-#endif
-
-/* *** make the following line uncommented, if you're sure,
- * *** all configuration is done */
-/* #define I_WAS_HERE */
+}
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NO USER INTERVENTION NEEDED BELOW
+ * If You are shure that all configuration is done, please uncomment the
+ * line below.
+ */
-/* The name of the device */
-#define MCDX "mcdx"
+#undef MCDX_DEBUG /* This is *REALLY* only for developement! */
-#if MCDX_QUIET == 1
-#define INFO(x)
-#define xinfo(fmt, args...)
+#ifdef MCDX_DEBUG
+#define MCDX_TRACE(x) printk x
+#define MCDX_TRACE_IOCTL(x) printk x
#else
-#define INFO(x) warn x
-#define xinfo(fmt, args...) _warn(fmt, ## args)
+#define MCDX_TRACE(x)
+#define MCDX_TRACE_IOCTL(x)
#endif
-#define WARN(x) warn x
-#define xwarn(fmt, args...) _warn(fmt, ## args)
-#define _warn warn
-
-#if MCDX_DEBUG == 1
-#define TRACE(x) trace x
-#define INIT 0
-#define MALLOC 0
-#define IOCTL 0
-#define PLAYTRK 0
-#define SUBCHNL 0
-#define TOCHDR 0
-#define MS 0
-#define PLAYMSF 0
-#define READTOC 0
-#define OPENCLOSE 0
-#define HW 0
-#define TALK 0
-#define IRQ 0
-#define TRANSFER 0
-#define REQUEST 0
-#define SLEEP 0
-#else
-#define TRACE(x)
-#endif
+/* The name of the device */
+#define MCDX "mcdx"
-/* The following addresses are taken from the Mitsumi Reference
- * and describe the possible i/o range for the controller.
+/*
+ * Per controller 4 bytes i/o are needed.
*/
-#define MCDX_IO_BEGIN ((char*) 0x300) /* first base of i/o addr */
-#define MCDX_IO_END ((char*) 0x3fc) /* last base of i/o addr */
-
-/* Per controller 4 bytes i/o are needed. */
#define MCDX_IO_SIZE 4
-/*
- * Bits
+/*
+ * Masks for the status byte, returned from every command, set if
+ * the description is true
*/
-
-/* The status byte, returned from every command, set if
- * the description is true */
#define MCDX_RBIT_OPEN 0x80 /* door is open */
#define MCDX_RBIT_DISKSET 0x40 /* disk set (recognised) */
#define MCDX_RBIT_CHANGED 0x20 /* disk was changed */
#define MCDX_RBIT_CHECK 0x10 /* disk rotates, servo is on */
-#define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */
+#define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */
#define MCDX_RBIT_RDERR 0x04 /* read error, refer SENSE KEY */
#define MCDX_RBIT_AUDIOBS 0x02 /* currently playing audio */
#define MCDX_RBIT_CMDERR 0x01 /* command, param or format error */
-/* The I/O Register holding the h/w status of the drive,
- * can be read at i/o base + 1 */
+/*
+ * The I/O Register holding the h/w status of the drive,
+ * can be read at i/o base + 1
+ */
#define MCDX_RBIT_DOOR 0x10 /* door is open */
#define MCDX_RBIT_STEN 0x04 /* if 0, i/o base contains drive status */
#define MCDX_RBIT_DTEN 0x02 /* if 0, i/o base contains data */
/*
- * The commands.
+ * The commands.
*/
-
-#define OPCODE 1 /* offset of opcode */
-#define MCDX_CMD_REQUEST_TOC 1, 0x10
-#define MCDX_CMD_REQUEST_STATUS 1, 0x40
-#define MCDX_CMD_RESET 1, 0x60
-#define MCDX_CMD_REQUEST_DRIVE_MODE 1, 0xc2
-#define MCDX_CMD_SET_INTERLEAVE 2, 0xc8, 0
-#define MCDX_CMD_DATAMODE_SET 2, 0xa0, 0
- #define MCDX_DATAMODE1 0x01
- #define MCDX_DATAMODE2 0x02
-#define MCDX_CMD_LOCK_DOOR 2, 0xfe, 0
+#define MCDX_CMD_GET_TOC 0x10
+#define MCDX_CMD_GET_MDISK_INFO 0x11
+#define MCDX_CMD_GET_SUBQ_CODE 0x20
+#define MCDX_CMD_GET_STATUS 0x40
+#define MCDX_CMD_SET_DRIVE_MODE 0x50
+#define MCDX_CMD_RESET 0x60
+#define MCDX_CMD_HOLD 0x70
+#define MCDX_CMD_CONFIG 0x90
+#define MCDX_CMD_SET_ATTENATOR 0xae
+#define MCDX_CMD_PLAY 0xc0
+#define MCDX_CMD_PLAY_2X 0xc1
+#define MCDX_CMD_GET_DRIVE_MODE 0xc2
+#define MCDX_CMD_SET_INTERLEAVE 0xc8
+#define MCDX_CMD_GET_FIRMWARE 0xdc
+#define MCDX_CMD_SET_DATA_MODE 0xa0
+#define MCDX_CMD_STOP 0xf0
+#define MCDX_CMD_EJECT 0xf6
+#define MCDX_CMD_CLOSE_DOOR 0xf8
+#define MCDX_CMD_LOCK_DOOR 0xfe
#define READ_AHEAD 4 /* 8 Sectors (4K) */
-/* Useful macros */
-#define e_door(x) ((x) & MCDX_RBIT_OPEN)
-#define e_check(x) (~(x) & MCDX_RBIT_CHECK)
-#define e_notset(x) (~(x) & MCDX_RBIT_DISKSET)
-#define e_changed(x) ((x) & MCDX_RBIT_CHANGED)
-#define e_audio(x) ((x) & MCDX_RBIT_AUDIOTR)
-#define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS)
-#define e_cmderr(x) ((x) & MCDX_RBIT_CMDERR)
-#define e_readerr(x) ((x) & MCDX_RBIT_RDERR)
-
-/** no drive specific */
#define MCDX_CDBLK 2048 /* 2048 cooked data each blk */
-#define MCDX_DATA_TIMEOUT (HZ/10) /* 0.1 second */
-
-/*
- * Access to the msf array
- */
-#define MSF_MIN 0 /* minute */
-#define MSF_SEC 1 /* second */
-#define MSF_FRM 2 /* frame */
-
-/*
- * Errors
- */
-#define MCDX_E 1 /* unspec error */
-#define MCDX_ST_EOM 0x0100 /* end of media */
-#define MCDX_ST_DRV 0x00ff /* mask to query the drive status */
+#define MCDX_DATA_TIMEOUT (HZ/10) /* 0.1 second */
-#ifndef I_WAS_HERE
+#ifndef I_WAS_IN_MCDX_H
#warning You have not edited mcdx.h
#warning Perhaps irq and i/o settings are wrong.
#endif
-/* ex:set ts=4 sw=4: */
+#endif /* __MCDX_H */
\ No newline at end of file
unsigned char *data; /* Data head pointer */
unsigned char *tail; /* Tail pointer */
unsigned char *end; /* End pointer */
- void (*destructor)(struct sk_buff *this); /* Destruct function */
+ void (*destructor)(struct sk_buff *); /* Destruct function */
};
#ifdef CONFIG_SKB_LARGE
#define KERN_REALROOTDEV 16 /* real root device to mount after initrd */
#define KERN_NFSRNAME 17 /* NFS root name */
#define KERN_NFSRADDRS 18 /* NFS root addresses */
+#define KERN_JAVA_INTERPRETER 19 /* path to Java(tm) interpreter */
+#define KERN_JAVA_APPLETVIEWER 20 /* path to Java(tm) appletviewer */
/* CTL_VM names: */
#define VM_SWAPCTL 1 /* struct: Set vm swapping control */
#ifndef LINUX_UCDROM_H
#define LINUX_UCDROM_H
+#ifdef __KERNEL__
struct cdrom_device_ops {
/* routines */
- int (*open) (dev_t, int);
- void (*release) (dev_t);
- int (*open_files) (dev_t); /* number of open files */
- int (*drive_status) (dev_t);
- int (*disc_status) (dev_t);
- int (*media_changed) (dev_t);
- int (*tray_move) (dev_t, int);
- int (*lock_door) (dev_t, int);
- int (*select_speed) (dev_t, int);
- int (*select_disc) (dev_t, int);
- int (*get_last_session) (dev_t, struct cdrom_multisession *);
- int (*get_mcn) (dev_t, struct cdrom_mcn *);
- int (*reset) (dev_t dev); /* hard reset device */
- int (*audio_ioctl) (dev_t, unsigned int, void *); /* play stuff */
- int (*dev_ioctl) (dev_t, unsigned int, unsigned long); /* dev-specific */
+ int (*open) (kdev_t, int);
+ void (*release) (kdev_t);
+ int (*open_files) (kdev_t); /* number of open files */
+ int (*drive_status) (kdev_t);
+ int (*disc_status) (kdev_t);
+ int (*media_changed) (kdev_t);
+ int (*tray_move) (kdev_t, int);
+ int (*lock_door) (kdev_t, int);
+ int (*select_speed) (kdev_t, int);
+ int (*select_disc) (kdev_t, int);
+ int (*get_last_session) (kdev_t, struct cdrom_multisession *);
+ int (*get_mcn) (kdev_t, struct cdrom_mcn *);
+ int (*reset) (kdev_t dev); /* hard reset device */
+ int (*audio_ioctl) (kdev_t, unsigned int, void *); /* play stuff */
+ int (*dev_ioctl) (kdev_t, unsigned int, unsigned long); /* dev-specific */
/* specifications */
const int capability; /* capability flags */
int mask; /* mask of capability: disables them */
int options; /* options flags */
long mc_flags; /* media change buffer flags (2*16) */
};
+#endif
/* capability flags */
#define CDC_CLOSE_TRAY 0x1 /* caddy systems _can't_ close */
#define CDROM_DRIVE_STATUS 0x5326 /* tray position, etc. */
#define CDROM_DISC_STATUS 0x5327 /* disc type etc. */
-/* Rename and old ioctl */
+/* Rename an old ioctl */
#define CDROM_GET_MCN CDROM_GET_UPC /* medium catalog number */
+#ifdef __KERNEL__
/* the general file operations structure: */
extern struct file_operations cdrom_fops;
extern int register_cdrom(int major, char *name,
struct cdrom_device_ops *cdo);
extern int unregister_cdrom(int major, char *name);
+#endif
#endif /* LINUX_UCDROM_H */
/*
+#ifndef __LINUX_NET_AFUNIX_H
+#define __LINUX_NET_AFUNIX_H
extern void unix_proto_init(struct net_proto *pro);
extern struct proto_ops unix_proto_ops;
extern void unix_inflight(struct file *fp);
extern void unix_notinflight(struct file *fp);
typedef struct sock unix_socket;
+extern void unix_gc(void);
-unix_socket *unix_socket_list;
+extern unix_socket *unix_socket_list;
#define UNIX_MAX_FD 8
+
+#endif
extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr);
+extern void hard_reset_now(void);
+
struct symbol_table symbol_table = {
#include <linux/symtab_begin.h>
#ifdef MODVERSIONS
X(simple_strtoul),
X(system_utsname),
X(sys_call_table),
+ X(hard_reset_now),
/* Signal interfaces */
X(send_sig),
ac.ac_uid = current->uid;
ac.ac_gid = current->gid;
ac.ac_tty = (current)->tty == NULL ? -1 :
- MKDEV(4, current->tty->device);
+ kdev_t_to_nr(current->tty->device);
ac.ac_flag = 0;
if (current->flags & PF_FORKNOEXEC)
ac.ac_flag |= AFORK;
* Added /proc support, Dec 1995
* Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
* Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
+ * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
*/
#include <linux/config.h>
static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
void *, size_t, void **);
+extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
+
/* The default sysctl tables: */
static ctl_table root_table[] = {
0644, NULL, &proc_dostring, &sysctl_string },
{KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
0644, NULL, &proc_dostring, &sysctl_string },
+#endif
+#ifdef CONFIG_BINFMT_JAVA
+ {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
+ 64, 0644, NULL, &proc_dostring, &sysctl_string },
+ {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
+ 64, 0644, NULL, &proc_dostring, &sysctl_string },
#endif
{0}
};
Code Section Bug Report Contact
-------------------+-------------------------------------------
-802 [other ] alan@cymru.net
+802 [other ] alan@lxorguk.ukuu.org.uk
[token ring ] needs a maintainer/debugger
-appletalk alan@cymru.net and netatalk@umich.edu
+appletalk alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
ax25 jsn@cs.nott.ac.uk
-core alan@cymru.net
-ethernet alan@cymru.net
-ipv4 alan@cymru.net
-ipx alan@cymru.net,greg@caldera.com
+core alan@lxorguk.ukuu.org.uk
+ethernet alan@lxorguk.ukuu.org.uk
+ipv4 alan@lxorguk.ukuu.org.uk
+ipx alan@lxorguk.ukuu.org.uk,greg@caldera.com
netrom jsn@cs.nott.ac.uk
-unix alan@cymru.net
+unix alan@lxorguk.ukuu.org.uk
- If in doubt contact me <alan@cymru.net> first.
+ If in doubt contact me <alan@lxorguk.ukuu.org.uk> first.
---------------------------------------------------------------------------
For commercial UK custom Linux networking projects, drivers and development
(but not free support!) I can be contacted via
- I^2IT Ltd, The Innovation Centre, University Of Wales
+ CymruNET Ltd, The Innovation Centre, University Of Wales
Swansea SA2 8PP.
Fax: +44 1792 295811
Tel: +44 1792 295213
void aarp_proto_init(void)
{
if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
- printk("Unable to register AARP with SNAP.\n");
+ printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
init_timer(&aarp_timer);
aarp_timer.function=aarp_expire_timeout;
aarp_timer.data=0;
limit=ntohs(nr->nr_lastnet);
if(limit-ntohs(nr->nr_firstnet) > 256)
{
- printk("Too many routes/iface.\n");
+ printk(KERN_WARING "Too many routes/iface.\n");
return -EINVAL;
}
for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
{
(void) sock_register(atalk_proto_ops.family, &atalk_proto_ops);
if ((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL)
- printk("Unable to register DDP with SNAP.\n");
+ printk(KERN_CRIT "Unable to register DDP with SNAP.\n");
ltalk_packet_type.type=htons(ETH_P_LOCALTALK);
dev_add_pack(<alk_packet_type);
atalk_if_get_info
});
- printk(KERN_INFO "Appletalk 0.17 for Linux NET3.034\n");
+ printk(KERN_INFO "Appletalk 0.17 for Linux NET3.035\n");
}
#ifdef MODULE
case AX25_PACLEN:
if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
return -EINVAL;
+#if 0
if (ax25_ctl.arg > 256) /* we probably want this */
- printk("ax25_ctl_ioctl: Warning --- huge paclen %d\n", (int)ax25_ctl.arg);
+ printk(KERN_WARNING "ax25_ctl_ioctl: Warning --- huge paclen %d\n", (int)ax25_ctl.arg);
+#endif
ax25->paclen = ax25_ctl.arg;
break;
ax25_cs_get_info
});
- printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.32 BETA for Linux NET3.034 (Linux 1.3.77)\n");
+ printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.32 BETA for Linux NET3.035 (Linux 2.0)\n");
#ifdef CONFIG_BPQETHER
proc_net_register(&(struct proc_dir_entry) {
ax25_bpq_get_info
});
- printk("G8BPQ Encapsulation of AX.25 frames enabled\n");
+ printk(KERN_INFO "G8BPQ Encapsulation of AX.25 frames enabled\n");
#endif
}
int size;
if(skb_headroom(skb) < AX25_BPQ_HEADER_LEN) {
- printk("ax25_queue_xmit: not enough space to add BPQ Ether header\n");
+ printk(KERN_CRIT "ax25_queue_xmit: not enough space to add BPQ Ether header\n");
dev_kfree_skb(skb, FREE_WRITE);
return;
}
*buff++ = AX25_P_ARP;
break;
default:
- printk("wrong protocol type 0x%x2.2\n", type);
+ printk(KERN_ERR "wrong protocol type 0x%x2.2\n", type);
*buff++ = 0;
break;
}
*/
if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) {
restore_flags(flags);
- printk("ax25_output: alloc_skb returned NULL\n");
+ printk(KERN_DEBUG "ax25_output: alloc_skb returned NULL\n");
if (skb_device_locked(skb))
skb_device_unlock(skb);
return;
}
if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) {
- printk("ax25_transmit_buffer: not enough room for digi-peaters\n");
+ printk(KERN_CRIT "ax25_transmit_buffer: not enough room for digi-peaters\n");
skb->free = 1;
kfree_skb(skb, FREE_WRITE);
return;
len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
if (skb_headroom(skb) < len) {
- printk("ax25_dg_build_path: not enough headroom for digis in skb\n");
+ printk(KERN_CRIT "ax25_dg_build_path: not enough headroom for digis in skb\n");
return;
}
struct ax25_dev *ax25_dev;
if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
- printk("ax25_dev_get_flag called with invalid device\n");
+ printk(KERN_WARNING "ax25_dev_get_flag called with invalid device\n");
return 1;
}
{ /* (4.8.1) */
int port_no;
+ printk(KERN_INFO "Ethernet Bridge 002 for NET3.035 (Linux 2.0)\n");
bridge_info.designated_root = bridge_info.bridge_id; /* (4.8.1.1) */
bridge_info.root_path_cost = Zero;
bridge_info.root_port = No_port;
unsigned long flags;
if (port_info[port_no].state == Disabled) {
- printk("send_config_bpdu: port %i not valid\n",port_no);
+ printk(KERN_DEBUG "send_config_bpdu: port %i not valid\n",port_no);
return(-1);
}
if (br_stats.flags & BR_DEBUG)
size = sizeof(Config_bpdu) + dev->hard_header_len;
skb = alloc_skb(size, GFP_ATOMIC);
if (skb == NULL) {
- printk("send_config_bpdu: no skb available\n");
+ printk(KERN_DEBUG "send_config_bpdu: no skb available\n");
return(-1);
}
skb->dev = dev;
unsigned long flags;
if (port_info[port_no].state == Disabled) {
- printk("send_tcn_bpdu: port %i not valid\n",port_no);
+ printk(KERN_DEBUG "send_tcn_bpdu: port %i not valid\n",port_no);
return(-1);
}
if (br_stats.flags & BR_DEBUG)
size = sizeof(Tcn_bpdu) + dev->hard_header_len;
skb = alloc_skb(size, GFP_ATOMIC);
if (skb == NULL) {
- printk("send_tcn_bpdu: no skb available\n");
+ printk(KERN_DEBUG "send_tcn_bpdu: no skb available\n");
return(-1);
}
skb->dev = dev;
}
}
break;
+#if 0
default:
printk("br_device_event: unknown event [%x]\n",
(unsigned int)event);
+#endif
}
return NOTIFY_DONE;
}
printk("br_receive_frame: ");
/* sanity */
if (!skb) {
- printk("no skb!\n");
+ printk(KERN_CRIT "br_receive_frame: no skb!\n");
return(1);
}
skb_device_lock(skb);
return(br_forward(skb, port));
default:
- printk("br_receive_frame: port [%i] unknown state [%i]\n",
+ printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n",
port, port_info[port].state);
return(0); /* pass frame up stack? */
}
/* sanity */
if (!skb)
{
- printk("br_tx_frame: no skb!\n");
+ printk(KERN_CRIT "br_tx_frame: no skb!\n");
return(0);
}
/* check for loopback */
GFP_ATOMIC);
if (!f) {
- printk("br_learn: unable to malloc fdb\n");
+ printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
return(-1);
}
f->port = port; /* source port */
int br_forward(struct sk_buff *skb, int port) /* 3.7 */
{
struct fdb *f;
- unsigned long flags;
/*
* flood all ports with frames destined for a group
{
int i;
struct sk_buff *nskb;
- unsigned long flags;
for (i = One; i <= No_of_ports; i++)
{
received_tcn_bpdu(port, bpdu);
break;
default:
- printk("br_bpdu: received unknown bpdu, type = %i\n",
+ printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n",
bpdu->type);
/* break; */
}
{
int err;
struct br_cf bcf;
- int i;
switch(cmd)
{
case BRCMD_BRIDGE_ENABLE:
if (br_stats.flags & BR_UP)
return(-EALREADY);
- printk("br: enabling bridging function\n");
+ printk(KERN_DEBUG "br: enabling bridging function\n");
br_stats.flags |= BR_UP; /* enable bridge */
start_hello_timer();
break;
case BRCMD_BRIDGE_DISABLE:
if (!(br_stats.flags & BR_UP))
return(-EALREADY);
- printk("br: disabling bridging function\n");
+ printk(KERN_DEBUG "br: disabling bridging function\n");
br_stats.flags &= ~BR_UP; /* disable bridge */
stop_hello_timer();
#if 0
return(-EINVAL);
if (port_info[bcf.arg1].state != Disabled)
return(-EALREADY);
- printk("br: enabling port %i\n",bcf.arg1);
+ printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
enable_port(bcf.arg1);
break;
case BRCMD_PORT_DISABLE:
return(-EINVAL);
if (port_info[bcf.arg1].state == Disabled)
return(-EALREADY);
- printk("br: disabling port %i\n",bcf.arg1);
+ printk(KERN_DEBUG "br: disabling port %i\n",bcf.arg1);
disable_port(bcf.arg1);
break;
case BRCMD_SET_BRIDGE_PRIORITY:
static int fdb_inited = 0;
int addr_cmp(unsigned char *a1, unsigned char *a2);
-static void printk_avl (struct fdb * tree);
/*
* fdb_head is the AVL tree corresponding to fdb
struct fdb * node = *nodeplace;
if (node == avl_br_empty) {
/* what? node_to_delete not found in tree? */
- printk("avl_remove: node to delete not found in tree\n");
+ printk(KERN_ERR "br: avl_remove: node to delete not found in tree\n");
return(-1);
}
*stack_ptr++ = nodeplace; stack_count++;
return;
}
}
- printk("dev_remove_pack: %p not found.\n", pt);
+ printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
}
/*****************************************************************************************
#ifdef CONFIG_NET_DEBUG
if (pri >= DEV_NUMBUFFS)
{
- printk("bad priority in dev_queue_xmit.\n");
+ printk(KERN_WARNING "bad priority in dev_queue_xmit.\n");
pri = 1;
}
#endif
if (n_at < 0)
{
restore_flags(flags);
- printk("net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
+ printk(KERN_WARNING "net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
nat->type);
return -1;
}
static int
net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
{
- printk("net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
+ printk(KERN_WARNING "net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
dev_kfree_skb(skb, FREE_WRITE);
return 0;
}
nat = nat_getbytype(family);
if (!nat) {
#endif
- printk("net_alias_dev_create(%s:%d): unregistered family==%d\n",
+ printk(KERN_WARNING "net_alias_dev_create(%s:%d): unregistered family==%d\n",
main_dev->name, slot, family);
/* *err = -EAFNOSUPPORT; */
*err = -EINVAL;
{
if (!(alias = prevdev->next->my_alias))
{
- printk("ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
+ printk(KERN_ERR "ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
continue; /* or should give up? */
}
if (alias->slot == slot) break;
if (*aliasp != alias)
if ((aliasp = net_alias_slow_findp(alias_info, alias)))
- printk("net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
+ printk(KERN_WARNING "net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
else
{
- printk("ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
+ printk(KERN_ERR "ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
return NULL; /* ENODEV */
}
continue;
}
else
- printk("net_alias_free(%s): '%s' is not my alias\n",
+ printk(KERN_ERR "net_alias_free(%s): '%s' is not my alias\n",
main_dev->name, alias->name);
}
else
- printk("net_alias_free(%s): found a non-alias after device!\n",
+ printk(KERN_ERR "net_alias_free(%s): found a non-alias after device!\n",
main_dev->name);
dev = dev->next;
}
if (!sa)
{
- printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
+ printk(KERN_ERR "ERROR: net_alias_rehash(): NULL sockaddr passed\n");
return -1;
}
if ( (main_dev = alias->main_dev) == NULL )
{
- printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
+ printk(KERN_ERR "ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
return -1;
}
if (!(alias_info=main_dev->alias_info))
{
- printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
+ printk(KERN_ERR "ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
return -1;
}
o_nat = alias->nat;
if (!o_nat)
{
- printk("ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
+ printk(KERN_ERR "ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
return -1;
}
n_nat = nat_getbytype(sa->sa_family);
if (!n_nat)
{
- printk("ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
+ printk(KERN_ERR "ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
return -1;
}
}
if(!*aliasp)
if ((aliasp = net_alias_slow_findp(alias_info, alias)))
- printk("net_alias_rehash(%s): bad hashing recovered\n", alias->name);
+ printk(KERN_WARNING "net_alias_rehash(%s): bad hashing recovered\n", alias->name);
else
{
- printk("ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
+ printk(KERN_ERR "ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
return -1;
}
unsigned long flags;
if (!nat)
{
- printk("register_net_alias_type(): NULL arg\n");
+ printk(KERN_ERR "register_net_alias_type(): NULL arg\n");
return -EINVAL;
}
nat->type = type;
if (!nat)
{
- printk("unregister_net_alias_type(): NULL arg\n");
+ printk(KERN_ERR "unregister_net_alias_type(): NULL arg\n");
return -EINVAL;
}
*/
if (nat->n_attach)
{
- printk("unregister_net_alias_type(): has %d attachments. failed\n",
+ printk(KERN_ERR "unregister_net_alias_type(): has %d attachments. failed\n",
nat->n_attach);
return -EINVAL;
}
}
}
restore_flags(flags);
- printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
+ printk(KERN_ERR "unregister_net_alias_type(type=%d): not found!\n", nat->type);
return -EINVAL;
}
void show_net_buffers(void)
{
- printk("Networking buffers in use : %u\n",net_skbcount);
- printk("Network buffers locked by drivers : %u\n",net_locked);
- printk("Total network buffer allocations : %u\n",net_allocs);
- printk("Total failed network buffer allocs : %u\n",net_fails);
- printk("Total free while locked events : %u\n",net_free_locked);
+ printk(KERN_INFO "Networking buffers in use : %u\n",net_skbcount);
+ printk(KERN_INFO "Network buffers locked by drivers : %u\n",net_locked);
+ printk(KERN_INFO "Total network buffer allocations : %u\n",net_allocs);
+ printk(KERN_INFO "Total failed network buffer allocs : %u\n",net_fails);
+ printk(KERN_INFO "Total free while locked events : %u\n",net_free_locked);
#ifdef CONFIG_INET
- printk("IP fragment buffer size : %u\n",ip_frag_mem);
+ printk(KERN_INFO "IP fragment buffer size : %u\n",ip_frag_mem);
#endif
}
{
if (skb == NULL)
{
- printk("kfree_skb: skb = NULL (from %p)\n",
+ printk(KERN_CRIT "kfree_skb: skb = NULL (from %p)\n",
__builtin_return_address(0));
return;
}
return;
}
if (skb->free == 2)
- printk("Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n",
+ printk(KERN_WARNING "Warning: kfree_skb passed an skb that nobody set the free flag on! (from %p)\n",
__builtin_return_address(0));
if (skb->list)
- printk("Warning: kfree_skb passed an skb still on a list (from %p).\n",
+ printk(KERN_WARNING "Warning: kfree_skb passed an skb still on a list (from %p).\n",
__builtin_return_address(0));
if(skb->destructor)
{
static int count = 0;
if (++count < 5) {
- printk("alloc_skb called nonatomically from interrupt %p\n",
+ printk(KERN_ERR "alloc_skb called nonatomically from interrupt %p\n",
__builtin_return_address(0));
priority = GFP_ATOMIC;
}
if (htype != ETH_P_IP)
{
- printk("eth_header_cache_bind: %04x cache is not implemented\n", htype);
+ printk(KERN_DEBUG "eth_header_cache_bind: %04x cache is not implemented\n", htype);
return;
}
if (arp_bind_cache(hhp, dev, htype, daddr))
{
if (hh->hh_type != ETH_P_IP)
{
- printk("eth_header_cache_update: %04x cache is not implemented\n", hh->hh_type);
+ printk(KERN_DEBUG "eth_header_cache_update: %04x cache is not implemented\n", hh->hh_type);
return;
}
memcpy(hh->hh_data, haddr, ETH_ALEN);
bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
tristate 'IP: Reverse ARP' CONFIG_INET_RARP
bool 'IP: Disable Path MTU Discovery (normally enabled)' CONFIG_NO_PATH_MTU_DISCOVERY
-bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF
+#bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF
bool 'IP: Drop source routed frames' CONFIG_IP_NOSR
bool 'IP: Allow large windows (not recommended if <16Mb of memory)' CONFIG_SKB_LARGE
if(!(entry->flags&ATF_COM))
{
- printk("arp_send_q: incomplete entry for %s\n",
+ printk(KERN_ERR "arp_send_q: incomplete entry for %s\n",
in_ntoa(entry->ip));
/* Can't flush the skb, because RFC1122 says to hang on to */
/* at least one from any unresolved entry. --MS */
+ dev->hard_header_len, GFP_ATOMIC);
if (skb == NULL)
{
- printk("ARP: no memory to send an arp packet\n");
+ printk(KERN_DEBUG "ARP: no memory to send an arp packet\n");
return;
}
skb_reserve(skb, dev->hard_header_len);
break;
default:
- printk("ARP: dev->type mangled!\n");
+ printk(KERN_ERR "ARP: dev->type mangled!\n");
kfree_skb(skb, FREE_READ);
return 0;
}
im->tm_running=0;
}
else {
- printk("igmp_stop_timer() called with timer not running by %p\n",__builtin_return_address(0));
+ printk(KERN_ERR "igmp_stop_timer() called with timer not running by %p\n",__builtin_return_address(0));
}
}
if(saddr==0)
{
- printk("Broken multicast host using 0.0.0.0 heard on %s\n",
+ printk(KERN_INFO "Broken multicast host using 0.0.0.0 heard on %s\n",
dev->name);
kfree_skb(skb, FREE_READ);
return 0;
void cleanup_module(void)
{
if (ip_alias_done() != 0)
- printk("ip_alias: can't remove module");
+ printk(KERN_INFO "ip_alias: can't remove module");
}
#endif /* MODULE */
optptr[2] = srrptr+4;
}
else
- printk("ip_forward(): Argh! Destination lost!\n");
+ printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");
}
if (opt->ts_needaddr)
{
skb2->arp = skb->arp;
if(skb->free==0)
- printk("IP fragmenter: BUG free!=1 in fragmenter\n");
+ printk(KERN_ERR "IP fragmenter: BUG free!=1 in fragmenter\n");
skb2->free = 1;
skb_put(skb2,len + hlen);
skb2->h.raw=(char *) skb2->data;
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/firewall.h>
-#include <linux/config.h> /* For CONFIG_FIREWALL */
#include <net/datalink.h>
#include <net/sock.h>
__u32 daddr, unsigned short len, __u32 saddr,
int redo, struct inet_protocol *protocol)
{
-#ifdef CONFIG_FIREWALL
- int err;
-#endif
/* Don't unlink in the middle of a turnaround */
MOD_INC_USE_COUNT;
#ifdef TUNNEL_DEBUG
void cleanup_module( void)
{
if ( inet_del_protocol(&ipip_protocol) < 0 )
- printk("ipip close: can't remove protocol\n");
+ printk(KERN_INFO "ipip close: can't remove protocol\n");
}
#endif
void ip_mr_init(void)
{
- printk("Linux IP multicast router 0.05-maybe-works 8)\n");
+ printk(KERN_INFO "Linux IP multicast router 0.05.\n");
register_netdevice_notifier(&ip_mr_notifier);
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
ip = si->sin_addr.s_addr;
if (ip == 0)
{
- printk("RARP: SETRARP: requested PA is 0.0.0.0 !\n");
+ printk(KERN_DEBUG "RARP: SETRARP: requested PA is 0.0.0.0 !\n");
return -EINVAL;
}
copy = min(sk->mss - tcp_size, seglen);
if (copy <= 0)
{
- printk("TCP: **bug**: \"copy\" <= 0\n");
+ printk(KERN_CRIT "TCP: **bug**: \"copy\" <= 0\n");
return -EFAULT;
}
tcp_size += copy;
copy = seglen;
if (copy <= 0)
{
- printk("TCP: **bug**: copy=%d, sk->mss=%d\n", copy, sk->mss);
+ printk(KERN_CRIT "TCP: **bug**: copy=%d, sk->mss=%d\n", copy, sk->mss);
return -EFAULT;
}
if (!sk->prot)
{
- printk("IMPOSSIBLE 3\n");
+ printk(KERN_CRIT "IMPOSSIBLE 3\n");
return(0);
}
if (size < sizeof(struct tcphdr) || size > skb->len)
{
- printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
+ printk(KERN_ERR "tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
skb, skb->data, th, skb->len);
kfree_skb(skb, FREE_WRITE);
return;
/* If it's got a syn or fin it's notionally included in the size..*/
if(!th->syn && !th->fin)
{
- printk("tcp_send_skb: attempt to queue a bogon.\n");
+ printk(KERN_ERR "tcp_send_skb: attempt to queue a bogon.\n");
kfree_skb(skb,FREE_WRITE);
return;
}
th->check = 0;
if (skb->next != NULL)
{
- printk("tcp_send_partial: next != NULL\n");
+ printk(KERN_ERR "tcp_send_partial: next != NULL\n");
skb_unlink(skb);
}
skb_queue_tail(&sk->write_queue, skb);
if (buff == NULL)
{
/* This is a disaster if it occurs */
- printk("tcp_send_fin: Impossible malloc failure");
+ printk(KERN_CRIT "tcp_send_fin: Impossible malloc failure");
return;
}
buff->free = 0;
if (buff->next != NULL)
{
- printk("tcp_send_fin: next != NULL\n");
+ printk(KERN_ERR "tcp_send_fin: next != NULL\n");
skb_unlink(buff);
}
skb_queue_tail(&sk->write_queue, buff);
if((long)when < 0)
{
when=3;
- printk("Error: Negative timer in xmit_timer\n");
+ printk(KERN_ERR "Error: Negative timer in xmit_timer\n");
}
sk->retransmit_timer.expires=jiffies+when;
add_timer(&sk->retransmit_timer);
break;
default:
- printk ("rexmit_timer: timer expired - reason unknown\n");
+ printk (KERN_ERR "rexmit_timer: timer expired - reason unknown\n");
break;
}
}
}
else
{
- printk("IPX: Network number collision %lx\n\t%s %s and %s %s\n",
+ printk(KERN_WARNING "IPX: Network number collision %lx\n\t%s %s and %s %s\n",
htonl(ipx->ipx_source.net),
ipx_device_name(i),
ipx_frame_name(i->if_dlink_type),
dev_add_pack(&ipx_8023_packet_type);
if ((p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with 802.2\n");
+ printk(KERN_CRIT "IPX: Unable to register with 802.2\n");
if ((p8022tr_datalink = register_8022tr_client(ipx_8022_type, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with 802.2TR\n");
+ printk(KERN_CRIT "IPX: Unable to register with 802.2TR\n");
if ((pSNAP_datalink = register_snap_client(ipx_snap_id, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with SNAP\n");
+ printk(KERN_CRIT "IPX: Unable to register with SNAP\n");
register_netdevice_notifier(&ipx_dev_notifier);
proc_net_register(&ipx_if_procinfo);
proc_net_register(&ipx_rt_procinfo);
- printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.034\n");
+ printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.035\n");
printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
}
int ct;
if(register_chrdev(NETLINK_MAJOR,"netlink", &netlink_fops)) {
- printk("netlink: unable to get major %d\n", NETLINK_MAJOR);
+ printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
return -EIO;
}
for(ct=0;ct<MAX_LINKS;ct++)
int init_module(void)
{
- printk("Network Kernel/User communications module 0.03\n");
+ printk(KERN_INFO "Network Kernel/User communications module 0.03\n");
return init_netlink();
}
if (nr_ctl.arg < 16 || nr_ctl.arg > 65535)
return -EINVAL;
if (nr_ctl.arg > 236) /* we probably want this */
- printk("nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
+ printk(KERN_WARNING "nr_ctl_ioctl: Warning --- huge paclen %d\n", (int)nr_ctl.arg);
sk->nr->paclen = nr_ctl.arg;
break;
{
sock_register(nr_proto_ops.family, &nr_proto_ops);
register_netdevice_notifier(&nr_dev_notifier);
- printk("G4KLX NET/ROM for Linux. Version 0.4 ALPHA for AX25.032 Linux 1.3.77\n");
+ printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.5 for AX25.032 Linux 2.0\n");
nr_default.quality = NR_DEFAULT_QUAL;
nr_default.obs_count = NR_DEFAULT_OBS;
return 0;
if (!dev->start) {
- printk("netrom: xmit call when iface is down\n");
+ printk(KERN_ERR "netrom: xmit call when iface is down\n");
return 1;
}
if (sk->nr->state != NR_STATE_1 && sk->nr->state != NR_STATE_2 &&
sk->nr->state != NR_STATE_3) {
- printk("nr_process_rx_frame: frame received - state: %d\n", sk->nr->state);
+ printk(KERN_ERR "nr_process_rx_frame: frame received - state: %d\n", sk->nr->state);
return queued;
}
case NR_INFOACK:
break;
default:
- printk("nr_write_internal: invalid frame type %d\n", frametype);
+ printk(KERN_ERR "nr_write_internal: invalid frame type %d\n", frametype);
return;
}
if (!(sock = sock_alloc()))
{
- printk("NET: sys_socket: no more sockets\n");
+ printk(KERN_WARNING "socket: no more sockets\n");
return(-ENOSR); /* Was: EAGAIN, but we are out of
system resources! */
}
if (!(newsock = sock_alloc()))
{
- printk("NET: sock_accept: no more sockets\n");
+ printk(KERN_WARNING "accept: no more sockets\n");
return(-ENOSR); /* Was: EAGAIN, but we are out of system
resources! */
}
{
int i;
- printk("Swansea University Computer Society NET3.034 for Linux 1.3.77\n");
+ printk(KERN_INFO "Swansea University Computer Society NET3.035 for Linux 2.0\n");
/*
* Initialize all address (protocol) families.
}
else
{
- /* passed fds are erased where?? */
+ /* passed fds are erased in the kfree_skb hook */
kfree_skb(skb,FREE_WRITE);
}
}
skpair->protinfo.af_unix.locks--; /* It may now die */
sk->protinfo.af_unix.other=NULL; /* No pair */
unix_destroy_socket(sk); /* Try to flush out this socket. Throw out buffers at least */
-
+ unix_gc(); /* Garbage collect fds */
+
/*
* FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In
* Linux we behave like files and pipes do and wait for the last dereference.
)
{
kfree(cm);
- printk("recvmsg: Bad msg_accrights\n");
+/* printk("recvmsg: Bad msg_accrights\n");*/
return -EINVAL;
}
}
void unix_proto_init(struct net_proto *pro)
{
- printk("NET3: Unix domain sockets 0.12 for Linux NET3.033.\n");
+ printk(KERN_INFO "NET3: Unix domain sockets 0.12 for Linux NET3.035.\n");
sock_register(unix_proto_ops.family, &unix_proto_ops);
#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
/*
- * NET3: Garbage Collector For AF_UNIX sockets (STUBS)
+ * NET3: Garbage Collector For AF_UNIX sockets
*
* Garbage Collector:
* Copyright (C) Barak A. Pearlmutter.
* Released under the GPL version 2 or later.
*
- * NOTE:
- * We don't actually call this yet. I'm finishing some tests before I
- * enable it. The bold can add it in themselves.
- *
* Chopped about by Alan Cox 22/3/96 to make it fit the AF_UNIX socket problem.
* If it doesn't work blame me, it worked when Barak sent it.
*
extern inline unix_socket *unix_get_socket(struct file *filp)
{
- struct socket *s;
+ unix_socket * u_sock = NULL;
+ struct inode *inode = filp->f_inode;
+
/*
* Socket ?
*/
- if(filp->f_inode->i_mode!=S_IFSOCK)
- return NULL;
- s=&(filp->f_inode->u.socket_i);
- /*
- * AF_UNIX ?
- */
- if(s->ops!=&unix_proto_ops)
- return NULL;
- /*
- * Got one.
- */
- return s->data;
+ if (inode && inode->i_sock) {
+ struct socket * s = &inode->u.socket_i;
+
+ /*
+ * AF_UNIX ?
+ */
+ if (s->ops == &unix_proto_ops)
+ u_sock = s->data;
+ }
+ return u_sock;
}
/*
* We exist only in the passing tree of sockets
* that is no longer connected to active descriptors
* Time to die..
+ *
+ * Subtle item: We will correctly sweep out the
+ * socket that has just been closed by the user.
+ * We must not close this as we are in the middle
+ * of its close at this moment. Skip that file
+ * using f_count==0 to spot it.
*/
- if(s->socket && s->socket->file)
+
+ if(s->socket && s->socket->file && s->socket->file->f_count)
close_fp(s->socket->file);
}
else