Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0351166f
Commit
0351166f
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import pre2.0.1
parent
0294f4bd
Changes
28
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
1975 additions
and
488 deletions
+1975
-488
.name
.name
+1
-0
CREDITS
CREDITS
+4
-1
Documentation/Changes
Documentation/Changes
+50
-93
Documentation/Configure.help
Documentation/Configure.help
+1
-0
Documentation/cdrom/cdrom-standard.tex
Documentation/cdrom/cdrom-standard.tex
+837
-0
Documentation/cdrom/cm206
Documentation/cdrom/cm206
+36
-28
Documentation/ioctl-number.txt
Documentation/ioctl-number.txt
+3
-3
Documentation/java.txt
Documentation/java.txt
+1
-1
Documentation/magic-number.txt
Documentation/magic-number.txt
+1
-1
Documentation/oops-tracing.txt
Documentation/oops-tracing.txt
+1
-1
Makefile
Makefile
+2
-2
drivers/cdrom/Makefile
drivers/cdrom/Makefile
+10
-0
drivers/cdrom/cdrom.c
drivers/cdrom/cdrom.c
+511
-0
drivers/cdrom/cm206.c
drivers/cdrom/cm206.c
+351
-294
drivers/char/random.c
drivers/char/random.c
+2
-2
drivers/char/rtc.c
drivers/char/rtc.c
+1
-1
drivers/net/hydra.c
drivers/net/hydra.c
+5
-5
drivers/net/lance.c
drivers/net/lance.c
+5
-10
fs/affs/inode.c
fs/affs/inode.c
+1
-1
include/linux/cm206.h
include/linux/cm206.h
+48
-1
include/linux/kerneld.h
include/linux/kerneld.h
+1
-1
include/linux/stats206.h
include/linux/stats206.h
+0
-34
include/linux/ucdrom.h
include/linux/ucdrom.h
+92
-0
include/net/tcp.h
include/net/tcp.h
+4
-2
ipc/msg.c
ipc/msg.c
+1
-1
net/Changes
net/Changes
+1
-1
net/ipv4/arp.c
net/ipv4/arp.c
+4
-4
net/ipv4/tcp_input.c
net/ipv4/tcp_input.c
+1
-1
No files found.
.name
0 → 100644
View file @
0351166f
pre-2.0
CREDITS
View file @
0351166f
...
...
@@ -2,7 +2,8 @@
contributed to the linux project. It is sorted by name, and
formatted in a format that allows for easy grepping and
beautification by scripts. The fields are: name (N), email (E),
web-address (W), description (D) and snail-mail address (S).
web-address (W), PGP key ID and fingerprint (P), description (D)
and snail-mail address (S).
Thanks,
Linus
...
...
@@ -570,6 +571,8 @@ S: United Kingdom
N: Michael K. Johnson
E: johnsonm@redhat.com
W: http://www.redhat.com/~johnsonm
P: 1024/4536A8DD 2A EC 88 08 40 64 CE D8 DD F8 12 2B 61 43 83 15
D: The Linux Documentation Project
D: Kernel Hackers' Guide
D: Procps
...
...
Documentation/Changes
View file @
0351166f
This document contains a list of the latest releases of the most
important packages for Linux as well as instructions for newcomers to
the 1.3.x series of kernels.
the 1.3.x series of kernels. By glancing through it, you should be
able to find out what you need to upgrade to successfully run the
latest kernels.
Last updated: Apr 29, 1996.
Author: Chris Ricker (gt1355b@prism.gatech.edu), based on the original by
Alessandro Sigala (ssigala@globalnet.it).
It was originally based on material from the linux-kernel mailing
list, Jared Mauch's web page "Software Victims of the 1.3 Kernel
Development" (http://www2.nether.net/~jared/victim.html), and Axel
Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources,
and was originally written and maintained by Alessandro Sigala
(ssigala@globalnet.it).
Last updated: May 10, 1996.
Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
Current Releases
****************
- Kernel modules Stable: 1.3.57, Exp: 1.3.69
f
- Kernel modules Stable: 1.3.57, Exp: 1.3.69
g
- PPP daemon Stable: 2.2.0f
- Dynamic linker (ld.so) 1.7.14
- GNU CC 2.7.2
...
...
@@ -22,66 +30,28 @@ Current Releases
- SysVinit 2.60
- Util-linux 2.5
What you really need to upgrade
*******************************
Dynamic linker
==============
You might upgrade the dynamic linker to the latest release, but only
to solve some bugs.
SysVinit
========
The FIFO behavior is changed in the latest 1.3.x kernel releases.
Upgrade to 2.60 if the older version seems broken.
PPP daemon and utilities
========================
To use the PPP protocol with the 1.3.x linux kernel, you need to
upgrade the PPP package to version 2.2.0f.
Procps utilities
================
In the latest 1.3.x kernel releases the /proc filesystem structure
was changed, so you need to upgrade the Procps package to version
0.99a. In the very latest kernels, /proc has changed again. There's
not yet an officially updated version of procps, so make due with
0.99a; you might want to look for one of the patches floating around to
update 0.99a for use with 1.3.94 and later kernels.
Installation notes
******************
Kernel Modules
==============
The current kernel modules release is 1.3.57, but you need the
experimental release 1.3.69 to use newer binutils 2.6.0.x, because
modules compiled with new binutils can't be loaded by modules 1.3.57.
Upgrade notes
*************
The Linux C Library
===================
The latest stable Linux C Library release is 5.2.18. If you upgrade
to this from 5.0.9 or earlier, be sure to read the
`release.libc-5.2.18'
file, since GNU make and a few other fairly important utils can be
broken by the upgrade.
to this from 5.0.9 or earlier, be sure to read the
`release.libc-5.2.18' file, since GNU make and a few other fairly
important utils can be
broken by the upgrade.
The current (beta) Linux C Library release is 5.3.12. In this
release there are some important changes that may cause troubles to
buggy programs (programs that call free() on a pointer not returned by
malloc() work with previous libc, but not with this release)
then read
the
`release.libc-5.3.9' file carefully! In the latest libc releases a
malloc() work with previous libc, but not with this release)
so read the
`release.libc-5.3.9' file carefully! In the latest libc releases a
dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU
was defined, has been fixed. Unfortunately, some GNU packages depend
on
this bug. GNU make 3.xx is one of them. To fix that you need to patch
and recompile those programs (a patch for make is included in the fil
e
`release.libc-.5.3.9', and the address to obtain a precompiled binary
is at the end of this file).
was defined, has been fixed. Unfortunately, some GNU packages depend
on this bug. GNU make 3.xx is one of them. To fix that you need to
patch and recompile those programs (a patch for make is included in th
e
file `release.libc-.5.3.9', and the address to obtain a precompiled
binary
is at the end of this file).
Also, the libc-5.3.x line has a known security hole relating to
rlogin. Libc-5.3.12 fixes this, so if you're going to run an
...
...
@@ -102,7 +72,9 @@ the old libc). If you're feeling lazy, just comment out
"fcntl_setlk() called by process %d with broken flock()
emulation\n", current->pid);'
in linux/fs/locks.c and recompile.
in linux/fs/locks.c and recompile. If you're still running a.out,
there's an unofficial libc-4.7.6 release out to which you can upgrade
to fix this problem.
The Termcap Library
===================
...
...
@@ -111,38 +83,23 @@ The Termcap Library
read the `README' file contained into the package to get some important
information about the `tgetent' function changes!
Upgrading to 1.3.x kernel from 1.2.13
*************************************
This section was based on material from the linux-kernel mailing
list, Jared Mauch's web page "Software Victims of the 1.3 Kernel
Development" (http://www2.nether.net/~jared/victim.html), and Axel
Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources.
This section is intended primarily to help those that are new to the
1.3.x series of Linux kernels. In the ongoing effort to make a faster,
better kernel and eventually achieve total world domination, several
features of the Linux kernel have been improved. As a result, when you
first upgrade to 1.3.x from 1.2.13, you will also have to upgrade
several utilities that are closely associated with the kernel and make
use of these features.
Proc filesystem
===============
Procps utilities
================
Various changes in the /proc filesystem have been made, affecting
ps, top, etc. Running `top' or `ps -auwwx' will now give you a floating
point exception. To fix the problem, upgrade to procps-0.99a.tar.gz,
available at
ftp://tsx-11.mit.edu/pub/linux/BETA/procps/procps-0.99a.tar.gz.
In the latest 1.3.x kernel releases the /proc file system structure
was changed, so you need to upgrade the procps package to version
0.99a. In the very latest kernels, /proc has changed again. There's
not yet an officially updated version of procps, so make due with
0.99a; you might want to look for one of the patches floating around to
update 0.99a for use with 1.3.94 and later kernels.
Modules
=======
Kernel
Modules
=======
=======
1.3.x is almost completely modularized, and kerneld is now
incorporated into the kernel. To take advantage of this, you'll need
the latest version of the module support apps. The latest non-beta is
modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69
f
.tar.gz.
modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69
g
.tar.gz.
These should be available at the same place you picked up your kernel
(ftp://ftp.cc.gatech.edu/pub/linux/kernel/) and the home page is
http://www.pi.se/blox/modules/index.html. Note: If you try to load a
...
...
@@ -151,12 +108,12 @@ module and get a message like
`gcc2_compiled, undefined Failed to load module! The symbols from
kernel 1.3.foo don't match 1.3.foo'
where `foo' is a number between 1 and
89
, then it's time to upgrade
module utilities from 1.3.57 to 1.3.69
f
; you'll only get this error if
you're running the latest binutils, so most people don't need to
upgrade
.
where `foo' is a number between 1 and
100
, then it's time to upgrade
module utilities from 1.3.57 to 1.3.69
g
; you'll only get this error if
you're running the latest binutils, so most people don't need to
upgrade
past 1.3.57
.
Another little tip:
you can't have both a.out *and* ELF support
Another little tip: you can't have both a.out *and* ELF support
compiled as modules. Otherwise, you get a nice Catch-22 when you try
to run insmod to install a.out/ELF support so you can run insmod ;-).
If you have an all-ELF system, but need a.out for the occasional
...
...
@@ -218,9 +175,9 @@ ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7h.tar.gz.
Console
=======
The Linux console type has changed. If your setup is old enough
that
you have problems, you'll need to update your termcap. To fix, add
linux to one of the types in /etc/termcap or snoop around
The Linux console type has changed. If your setup is old enough
that you have problems, you'll need to update your termcap. To fix,
add
linux to one of the types in /etc/termcap or snoop around
http://www.ccil.org/~esr/ncurses.html (reputedly the latest universal
termcap maintainer). You may also need to update terminfo by running
the following as root:
...
...
@@ -344,8 +301,8 @@ ever works ;-), get
ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz.
Please send info about any other packages that 1.3.x "broke" or about
any new features of 1.3.x that require extra
packages for use to Chris
Ricker (gt1355b@prism.gatech.edu).
any new features of 1.3.x that require extra
or new packages for use to
Chris
Ricker (gt1355b@prism.gatech.edu).
How to know the version of the installed programs
*************************************************
...
...
@@ -358,7 +315,7 @@ PPP: pppd -h (wrong but it show the version)
Libc: ls -l /lib/libc.so.5
LibC++: ls -l /usr/lib/libg++.so
Binutils: ld -v
dl
d: ldd -v and ldd -V
ld
d: ldd -v and ldd -V
termcap: ls -l /lib/libtermcap.so.*
modules: insmod -V
procps: ps --version
...
...
Documentation/Configure.help
View file @
0351166f
...
...
@@ -623,6 +623,7 @@ CONFIG_BINFMT_JAVA
don't know what to answer at this point then answer Y. You may answer
M for module support and later load the module when you install the
JDK or find a interesting Java program that you can't live without.
Processor type
CONFIG_M386
This is the processor type of your CPU. It is used for optimizing
...
...
Documentation/cdrom/cdrom-standard.tex
0 → 100644
View file @
0351166f
\documentclass
{
article
}
\def\version
{$
Id: cdrom
-
standard.tex,v
0
.
4
1996
/
04
/
17
20
:
46
:
34
david Exp
$}
\evensidemargin
=0pt
\oddsidemargin
=0pt
\topmargin
=-
\headheight
\advance\topmargin
by -
\headsep
\textwidth
=15.99cm
\textheight
=24.62cm
% normal A4, 1'' margin
\def\linux
{{
\sc
Linux
}}
\def\cdrom
{{
\sc
CDrom
}}
\def\cdromc
{{
\tt
cdrom.c
}}
\def\ucdrom
{{
\tt
ucdrom.h
}}
\everymath
{
\it
}
\everydisplay
{
\it
}
\catcode
`
\_
=
\active
\def
_{
\_\penalty
100
}
\catcode
`
\<
=
\active
\def
<#1>
{{
\langle\hbox
{
\rm
#1
}
\rangle
}}
\begin{document}
\title
{
A
\linux\ \cdrom\
standard
}
\author
{
David van Leeuwen
\\
{
\normalsize\tt
david@tm.tno.nl
}}
\maketitle
\section
{
Introduction
}
\linux\
is probably the Unix-like operating system that supports the widest
variety of hardware devices. The reasons for this are presumably
\begin{itemize}
\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.
\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.
Apart from the somewhat unstructured interfacing with software, the
actual execution of the commands is different for most of the
different drivers: e.g., some drivers close the tray if an
$
open
()
$
call
occurs while the tray is unloaded, others not. Some drivers lock the
door upon opening the device, to prevent an incoherent file system,
but others don't, to allow software ejection. Undoubtedly, the
capabilities of the different drives vary, but even when two drives have
the same capability the driver behavior may be different.
Personally, I think that the most important drive interfaces will be
the IDE/ATAPI drives and of course the SCSI drives, but as prices of
hardware drop continuously, it is not unlikely that people will have
more than one
\cdrom\
drive, possibly of mixed types. (In December
1994, one of the cheapest
\cdrom\
drives was a Philips cm206, a
double-speed proprietary drive. In the months that I was busy writing
a
\linux\
driver for it, proprietary drives became old-fashioned and
IDE/ATAPI drives became standard. At the time of writing (April 1996)
the cheapest double speed drive is IDE and at one fifth of the price
of its predecessor. Eight speed drives are available now.)
This document defines (in pre-release versions: proposes) the various
$
ioctl
$
s, and the way the drivers should implement this.
\section
{
Standardizing through another software level
}
\label
{
cdrom.c
}
At the time this document is written, all drivers directly implement
the
$
ioctl
()
$
calls through their own routines, with the danger of
forgetting calls to
$
verify
_
area
()
$
and the risk of divergence in
implementation.
For this reason, we
\footnote
{
The writing style is such that `we' is
used when (at least part of) the
\cdrom
-device driver authors support
the idea, an `I' is used for personal opinions
}
propose to define
another software-level, that separates the
$
ioctl
()
$
and
$
open
()
$
implementation from the actual hardware implementation. We believe
that
\cdrom\
drives are specific enough (i.e., different from other
block-devices such as floppy or hard disc drives), to define a set of
{
\em
\cdrom\
device operations
}
,
$
<cdrom
-
device>
_
dops
$
. These are of a
different nature than the classical block-device file operations
$
<block
-
device>
_
fops
$
.
The extra interfacing level routines are implemented in a file
\cdromc
, and a low-level
\cdrom\
driver hands over the interfacing to
the kernel by registering the following general
$
struct
\
file
_
operations
$
:
$$
\halign
{
$#$
\ \hfil
&
$#$
\ \hfil
&
$
/*
$
\rm
# $
*/
$
\hfil\cr
struct
&
file
_
operations
\
cdrom
_
fops
=
\{\hidewidth\cr
&
NULL,
&
lseek
\cr
&
block
_
read,
&
read
-
general
\
block
-
dev
\
read
\cr
&
block
_
write,
&
write
-
general block
-
dev write
\cr
&
NULL,
&
readdir
\cr
&
NULL,
&
select
\cr
&
cdrom
_
ioctl,
&
ioctl
\cr
&
NULL,
&
mmap
\cr
&
cdrom
_
open,
&
open
\cr
&
cdrom
_
release,
&
release
\cr
&
NULL,
&
fsync
\cr
&
NULL,
&
fasync
\cr
&
cdrom
_
media
_
changed,
&
media
_
change
\cr
&
NULL
&
revalidate
\cr
\}
;
\cr
}
$$
Every active
\cdrom\
device shares this
$
struct
$
. The routines declared
above are all implemented in
\cdromc
, and this is the place where the
{
\em
behavior
\/
}
of all
\cdrom
-devices is defined, and hence
standardized. The implementation of the interfacing to the various
types of hardware still is done by the various
\cdrom
-device drivers,
but these routines only implement certain
{
\em
capabilities
\/
}
that
are typical to
\cdrom\
(removable-media) devices.
Registration of the
\cdrom\
device driver should now be to the general
routines in
\cdromc
, not to the VFS any more. This is done though the
call
$$
register
_
cdrom
(
int
\
major, char
*
name,
struct
\
cdrom
_
device
_
ops
\
device
_
options
)
$$
The device operations structure lists the implemented routines for
interfacing to the hardware, and some specifications of capabilities
of the device, such as the maximum head-transfer rate. [It is
impossible to come up with a complete list of all capabilities of
(future)
\cdrom\
drives, as the developments in technology follow-up
at an incredible rate. Maybe write-operation (WORM devices) will
become very popular in the future.] The list now is:
$$
\halign
{
$#$
\ \hfil
&
$#$
\ \hfil
&
\hbox
to
10
em
{
$#$
\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
\noalign
{
\medskip
}
&
\llap
{
const
\
}
int
&
capability;
&
capability flags
\cr
&
int
&
mask;
&
mask of capability: disables them
\cr
&
\llap
{
$const
\
$
}
float
&
speed;
&
maximum speed for reading data
\cr
&
\llap
{
$const
\
$
}
int
&
minors;
&
number of supported minor devices
\cr
&
\llap
{
$const
\
$
}
int
&
capacity;
&
number of discs in jukebox
\cr
\noalign
{
\medskip
}
&
int
&
options;
&
options flags
\cr
&
long
&
mc
_
flags;
&
media
-
change buffer flags
(
$
2
\times
16
$
)
\cr
\}\cr
}
$$
The
\cdrom
-driver should simply implement (some of) these
functions, and register the functions to the global
\cdrom\
driver,
which performs interfacing with the Virtual File System and system
$
ioctl
$
s. The flags
$
capability
$
specify the hardware-capabilities on
registration of the device, the flags
$
mask
$
can be used to mask some
of those capabilities (for one reason or another). The value
$
minors
$
should be a positive value indicating the number of minor devices that
are supported by the driver, normally~1. (They are supposed to be
numbered from 0 upwards). The value
$
capacity
$
should be the number of
discs the drive can hold simultaneously, if it is designed as a
juke-box, or otherwise~1.
Two registers contain variables local to the
\cdrom\
device. The flags
$
options
$
are used to specify how the general
\cdrom\
routines
should behave. These various flags registers should provide enough
flexibility to adapt to the different user's wishes (and
{
\em
not
\/
}
the `arbitrary' wishes of the author of the low-level device driver,
as is the case in the old scheme). The register
$
mc
_
flags
$
is used to
buffer the information from
$
media
_
changed
()
$
to two separate queues.
Note that most functions have fewer parameters than their
$
blkdev
_
fops
$
counterparts. This is because very little of the
information in the structures
$
inode
$
and
$
file
$
are used, the main
parameter is the device
$
dev
$
, from which the minor-number can be
extracted. (Most low-level
\cdrom\
drivers don't even look at that value
as only one device is supported.)
The intermediate software layer that
\cdromc\
forms will performs some
additional bookkeeping. The minor number of the device is checked
against the maximum registered in
$
<device>
_
dops
$
. The function
$
cdrom
_
ioctl
()
$
will verify the appropriate user-memory regions for
read and write, and in case a location on the CD is transferred, it
will `sanitize' the format by making requests to the low-level drivers
in a standard format, and translating all formats between the
user-software and low level drivers. This relieves much of the drivers
memory checking and format checking and translation. Also, the
necessary structures will be declared on the program stack.
The implementation of the functions should be as defined in the
following sections. Three functions
{
\em
must
\/
}
be implemented,
namely
$
open
()
$
,
$
release
()
$
and
$
open
_
files
()
$
. Other functions may
be omitted, their corresponding capability flags will be cleared upon
registration. Generally, a function returns zero on success and
negative on error. A function call should return only after the
command has completed, but of course waiting for the device should not
use processor time.
\subsection
{$
Open
(
dev
_
t
\
dev, int
\
purpose
)
$}
$
Open
()
$
should try to open the device for a specific
$
purpose
$
, which
can be either:
\begin{itemize}
\item
[0]
Open for data read, as is used by
{
\tt
mount()
}
(2), or the
user commands
{
\tt
dd
}
or
{
\tt
cat
}
.
\item
[1]
Open for
$
ioctl
$
commanding, as is used for audio-CD playing
programs mostly.
\end{itemize}
In this routine, a static counter should be updated, reflecting the
number of times the specific device is successfully opened (and in
case the driver supports modules, the call
$
MOD
_
INC
_
USE
_
COUNT
$
should be performed exactly once, if successful). The return value is
negative on error, and zero on success. The open-for-ioctl call can
only fail if there is no hardware.
Notice that any strategic code (closing tray upon
$
open
()
$
, etc.)
\
is
done by the calling routine in
\cdromc
, so the low-level routine
should only be concerned with proper initialization and device-use
count.
\subsection
{$
Release
(
dev
_
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
device-specific actions should be taken such as spinning down the
device. However, strategic actions such as ejection of the tray, or
unlocking the door, should be left over to the general routine
$
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
)
$}
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
)
$}
\label
{
drive status
}
The function
$
drive
_
status
$
, if implemented, should provide
information of the status of the drive (not the status of the disc,
which may or may not be in the drive). In
\ucdrom\
the possibilities
are listed:
$$
\halign
{
$#$
\ \hfil
&
$
/*
$
\rm
# $
*/
$
\hfil\cr
CDS
_
NO
_
INFO
&
no information available
\cr
CDS
_
NO
_
DISC
&
no disc is inserted, tray is closed
\cr
CDS
_
TRAY
_
OPEN
&
tray is opened
\cr
CDS
_
DRIVE
_
NOT
_
READY
&
something is wrong, tray is moving?
\cr
CDS
_
DISC
_
OK
&
a disc is loaded and everything is fine
\cr
}
$$
\subsection
{$
Disc
_
status
(
dev
_
t
\
dev
)
$}
\label
{
disc status
}
As a complement to
$
drive
_
status
()
$
, this functions can provide the
general
\cdrom
-routines with information about the current disc that is
inserted in the drive represented by
$
dev
$
. The history of development
of the CD's use as a carrier medium for various digital information
has lead to many different disc types, hence this function can return:
$$
\halign
{
$#$
\ \hfil
&
$
/*
$
\rm
# $
*/
$
\hfil\cr
CDS
_
NO
_
INFO
&
no information available
\cr
CDS
_
NO
_
DISC
&
no disc is inserted, or tray is opened
\cr
CDS
_
AUDIO
&
Audio disc
(
2352
audio bytes
/
frame
)
\cr
CDS
_
DATA
_
1
&
data disc, mode
1
(
2048
user bytes
/
frame
)
\cr
CDS
_
DATA
_
2
&
data disc, mode
2
(
2336
user bytes
/
frame
)
\cr
CDS
_
XA
_
2
_
1
&
mixed data
(
XA
)
, mode
2
, form
1
(
2048
user bytes
)
\cr
CDS
_
XA
_
2
_
2
&
mixed data
(
XA
)
, mode
2
, form
1
(
2324
user bytes
)
\cr
}
$$
As far as I know,
\cdrom
's are always of type
$
CDS
_
DATA
_
1
$
. For
some information concerning frame layout of the various disc types, see
a recent version of
{
\tt
cdrom.h
}
.
\subsection
{$
Media
_
changed
(
dev
\_
t
\
dev
)
$}
This function is very similar to the original function in
$
struct
\
file
_
operations
$
. It returns 1 if the medium of the device
$
dev
$
has
changed since the last call, and 0 otherwise. Note that by `re-routing'
this function through
$
cdrom
_
media
_
changed
()
$
, we can implement
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
)
$}
This function, if implemented, should control the tray movement. (No
other function should control this.) The parameter
$
position
$
controls
the desired direction of movement:
\begin{itemize}
\item
[0]
Close tray
\item
[1]
Open tray
\end{itemize}
This function returns 0 upon success, and a non-zero value upon
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
)
$}
This function (and no other code) controls locking of the door, if the
drive allows this. The value of
$
lock
$
controls the desired locking
state:
\begin{itemize}
\item
[0]
Unlock door, manual opening is allowed
\item
[1]
Lock door, tray cannot be ejected manually
\end{itemize}
Return values are as for
$
tray
_
move
()
$
.
\subsection
{$
Select
_
speed
(
dev
_
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
capability that should be standardized through a function in the
device-operations structure. This function should select the speed at
which data is read or audio is played back. The special value `0'
means `auto-selection', i.e., maximum data-rate or real-time audio
rate. If the drive doesn't have this `auto-selection' capability, the
decision should be made on the current disc loaded and the return
value should be positive. A negative return value indicates an
error. (Although the audio-low-pass filters probably aren't designed
for it, more than real-time playback of audio might be used for
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
)
$}
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
disc selection. It should return the number of the selected disc on
success, a negative value on error. Currently, none of the
\linux\
\cdrom\
drivers appear to support such functionality, but it defined
here for future purpose.
\subsection
{$
Get
_
last
_
session
(
dev
_
t
\
dev, struct
\
cdrom
_
multisession
*
ms
_
info
)
$}
This function should implement the old corresponding
$
ioctl
()
$
. For
device
$
dev
$
, the start of the last session of the current disc should
be returned in the pointer argument
$
ms
_
info
$
. Note that routines in
\cdromc\
have sanitized this argument: its
requested format will
{
\em
always
\/
}
be of the type
$
CDROM
_
LBA
$
(linear block addressing mode), whatever the calling software
requested. But sanitization goes even further: the low-level
implementation may return the requested information in
$
CDROM
_
MSF
$
format if it wishes so (setting the
$
ms
_
info
\rightarrow
addr
_
format
$
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
)
$}
Some discs carry a `Media Catalog Number' (MCN), also called
`Universal Product Code' (UPC). This number should reflect the number that
is generally found in the bar-code on the product. Unfortunately, the
few discs that carry such a number on the disc don't even use the same
format. The return argument to this function is a pointer to a
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
)
$}
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
*
arg
)
$}
Some of the
\cdrom
-
$
ioctl
$
s defined in
{
\tt
cdrom.h
}
can be
implemented by the routines described above, and hence the function
$
cdrom
_
ioctl
$
will use those. However, most
$
ioctl
$
s deal with
audio-control. We have decided to leave these accessed through a
single function, repeating the arguments
$
cmd
$
and
$
arg
$
. Note that
the latter is of type
$
void
*
{}$
, rather than
$
unsigned
\
long
\
int
$
. The routine
$
cdrom
_
ioctl
()
$
does do some useful things,
though. It sanitizes the address format type to
$
CDROM
_
MSF
$
(Minutes,
Seconds, Frames) for all audio calls. It also verifies the memory
location of
$
arg
$
, and reserves stack-memory for the argument. This
makes implementation of the
$
audio
_
ioctl
()
$
much simpler than in the
old driver scheme. For an example you may look up the function
$
cm
206
_
audio
_
ioctl
()
$
in
{
\tt
cm206.c
}
that should be updated with
this documentation.
An unimplemented ioctl should return
$
-
EINVAL
$
, but a harmless request
(e.g.,
$
CDROMSTART
$
) may be ignored by returning 0 (success). Other
errors should be according to the standards, whatever they are. (We
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
\
arg
)
$}
Some
$
ioctl
$
s seem to be specific to certain
\cdrom\
drives. That is,
they are introduced to service some capabilities of certain drives. In
fact, there are 6 different
$
ioctl
$
s for reading data, either in some
particular kind of format, or audio data. Not many drives support
reading audio tracks as data, I believe this is because of protection
of copyrights of artists. Moreover, I think that if audio-tracks are
supported, it should be done through the VFS and not via
$
ioctl
$
s. A
problem here could be the fact that audio-frames are 2352 bytes long,
so either the audio-file-system should ask for 75264 bytes at once
(the least common multiple of 512 and 2352), or the drivers should
bend their backs to cope with this incoherence (to which I would
oppose, this code then should be standardized in
\cdromc
).
Because there are so many
$
ioctl
$
s that seem to be introduced to
satisfy certain drivers,
\footnote
{
Is there software around that actually uses
these? I 'd be interested!
}
any `non-standard'
$
ioctl
$
s are routed through
the call
$
dev
_
ioctl
()
$
. In principle, `private'
$
ioctl
$
s should be
numbered after the device's major number, and not the general
\cdrom\
$
ioctl
$
number,
{
\tt
0x53
}
. Currently the non-supported
$
ioctl
$
s are:
{
\it
CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, CDROMREADRAW,
CDROMREADCOOKED, CDROMSEEK, CDROMPLAY
\-
BLK and CDROMREADALL
}
.
\subsection
{
\cdrom\
capabilities
}
Instead of just implementing some
$
ioctl
$
calls, the interface in
\cdromc\
supplies the possibility to indicate the
{
\em
capabilities
\/
}
of a
\cdrom\
drive. This can be done by ORing any number of
capability-constants that are defined in
\ucdrom\
at the registration
phase. Currently, the capabilities are any of:
$$
\halign
{
$#$
\ \hfil
&
$
/*
$
\rm
# $
*/
$
\hfil\cr
CDC
_
CLOSE
_
TRAY
&
can close tray by software control
\cr
CDC
_
OPEN
_
TRAY
&
can open tray
\cr
CDC
_
LOCK
&
can lock and unlock the door
\cr
CDC
_
SELECT
_
SPEED
&
can select speed, in units of $
\sim
$
150
\,
kB
/
s
\cr
CDC
_
SELECT
_
DISC
&
drive is juke
-
box
\cr
CDC
_
MULTI
_
SESSION
&
can read sessions $>
\rm
1
$
\cr
CDC
_
MCN
&
can read Medium Catalog Number
\cr
CDC
_
MEDIA
_
CHANGED
&
can report if disc has changed
\cr
CDC
_
PLAY
_
AUDIO
&
can perform audio
-
functions
(
play, pause, etc
)
\cr
}
$$
The capability flag is declared
$
const
$
, to prevent drivers to
accidentally tamper with the contents. However, upon registration,
some (claimed) capability flags may be cleared if the supporting
function has not been implemented (see
$
register
_
cdrom
()
$
in
\cdromc
).
If you want to disable any of the capabilities, there is a special
flag register
$
<device>
_
dops.mask
$
that may (temporarily) disable
certain capabilities. In the file
\cdromc\
you will encounter many
constructions of the type
$$
\it
if
\
(
cdo
\rightarrow
capability
\mathrel\&
\mathord
{
\sim
}
cdo
\rightarrow
mask
\mathrel
{
\&
}
CDC
_
<capability>
)
\ldots
$$
The
$
mask
$
could be set in the low-level driver code do disable
certain capabilities for special brands of the device that can't
perform the actions. However, there is not (yet) and
$
ioctl
$
to set
the mask
\dots
The reason is that I think it is better to control the
{
\em
behavior
\/
}
rather than the
{
\em
capabilities
}
.
\subsection
{
Options
}
A final flag register controls the
{
\em
behavior
\/
}
of the
\cdrom\
drives, in order to satisfy the different users's wishes, hopefully
independently of the ideas of the respectable author that happened to
have made the drive's support available to the
\linux\
community. The
current behavior options are:
$$
\halign
{
$#$
\ \hfil
&
$
/*
$
\rm
# $
*/
$
\hfil\cr
CDO
_
AUTO
_
CLOSE
&
try to close tray upon device $open
()
$
\cr
CDO
_
AUTO
_
EJECT
&
try to open tray on last device $close
()
$
\cr
CDO
_
USE
_
FFLAGS
&
use $file
_
pointer
\rightarrow
f
_
flags$ to indicate
purpose for $open
()
$
\cr
CDO
_
LOCK
&
try to lock door if device is opened
\cr
CDO
_
CHECK
_
TYPE
&
ensure disc type is data if opened for data
\cr
}
$$
The initial value of this register is
$
CDO
_
AUTO
_
CLOSE
\mathrel
|
CDO
_
USE
_
FFLAGS
\mathrel
| CDO
_
LOCK
$
, reflecting my own view on user
interface and software standards. Before you protest, there are two
new
$
ioctl
$
s implemented in
\cdromc
, that allow you to control the
behavior by software. These are:
$$
\halign
{
$#$
\ \hfil
&
$
/*
$
\rm
# $
*/
$
\hfil\cr
CDROM
_
SET
_
OPTIONS
&
set options specified in $
(
int
)
\
arg$
\cr
CDROM
_
CLEAR
_
OPTIONS
&
clear options specified in $
(
int
)
\
arg$
\cr
}
$$
One option needs some more explanation:
$
CDO
_
USE
_
FFLAGS
$
. In the next
section we explain what the need for this option is.
\section
{
The need to know the purpose of opening
}
Traditionally, Unix devices can be used in two different `modes',
either by reading/writing to the device file, or by issuing
controlling commands to the device, by the device's
$
ioctl
()
$
call. The problem with
\cdrom\
drives, is that they can be used for
two entirely different purposes. One is to mount removable
file systems,
\cdrom
s, the other is to play audio CD's. Audio commands
are implemented entirely through
$
ioctl
$
s, presumably because the
first implementation (SUN?) has been such. In principle there is
nothing wrong with this, but a good control of the `CD player' demands
that the device can
{
\em
always
\/
}
be opened in order to give the
$
ioctl
$
commands, regardless of the state the drive is in.
On the other hand, when used as a removable-media disc drive (what the
original purpose of
\cdrom
s is) we would like to make sure that the
disc drive is ready for operation upon opening the device. In the old
scheme, some
\cdrom\
drivers don't do any integrity checking, resulting
in a number of i/o errors reported by the VFS to the kernel when an
attempt for mounting a
\cdrom\
on an empty drive occurs. This is not a
particularly elegant way to find out that there is no
\cdrom\
inserted;
it more-or-less looks like the old IBM-PC trying to read an empty floppy
drive for a couple of seconds, after which the system complains it
can't read from it. Nowadays we can
{
\em
sense
\/
}
the existence of a
removable medium in a drive, and we believe we should exploit that
fact. An integrity check on opening of the device, that verifies the
availability of a
\cdrom\
and its correct type (data), would be
desirable.
These two ways of using a
\cdrom\
drive, principally for data and
secondarily for playing audio discs, have different demands for the
behavior of the
$
open
()
$
call. Audio use simply wants to open the
device in order to get a file handle which is needed for issuing
$
ioctl
$
commands, while data use wants to open for correct and
reliable data transfer. The only way user programs can indicate what
their
{
\em
purpose
\/
}
of opening the device is, is trough the
$
flags
$
parameter (see
{
\tt
open(2)
}
). For
\cdrom\
devices, these flags aren't
implemented (some drivers implement checking for write-related flags,
but this is not strictly necessary if the device file has correct
permission flags). Most option flags simply don't make sense to
\cdrom\
devices:
$
O
_
CREAT
$
,
$
O
_
NOCTTY
$
,
$
O
_
TRUNC
$
,
$
O
_
APPEND
$
, and
$
O
_
SYNC
$
have no meaning to a
\cdrom
.
We therefore propose to use the flag
$
O
_
NONBLOCK
$
as an indication
that the device is opened just for issuing
$
ioctl
$
commands. Strictly, the meaning of
$
O
_
NONBLOCK
$
is that opening and
subsequent calls to the device don't cause the calling process to
wait. We could interpret this as ``don't wait until someone has been
inserted some valid data-
\cdrom
.'' Thus, our proposal of the
implementation for the
$
open
()
$
call for
\cdrom
s is:
\begin{itemize}
\item
If no other flags are set than
$
O
_
RDONLY
$
, the device is opened
for data transfer, and the return value will be 0 only upon successful
initialization of the transfer. The call may even induce some actions
on the
\cdrom
, such as closing the tray.
\item
If the option flag
$
O
_
NONBLOCK
$
is set, opening will always be
successful, unless the whole device doesn't exist. The drive will take
no actions whatsoever.
\end{itemize}
\subsection
{
And what about standards?
}
You might hesitate to accept this proposal as is comes from the
\linux\
community, and not from some standardizing institute. What
about SUN, SGI, HP and all those other Unix and hardware vendors?
Well, these companies are in the lucky position that they generally
control both the hardware and software of their supported products,
and are large enough to set their own standard. They do not have to
deal with a dozen or more different, competing hardware
configurations.
\footnote
{
Personally, I think that SUN's approach to
mounting
\cdrom
s is very good in origin: under Solaris a
volume-daemon automatically mounts a newly inserted
\cdrom\
under
{
\tt
/cdrom/
$
<volume
-
name>
$
/
}
. In my opinion they should have pushed this
further and have
{
\em
every
\/
}
\cdrom\
on the local area network be
mounted at the similar location, i.e., no matter in which particular
machine you insert a
\cdrom
, it will always appear at the same
position in the directory tree, on every system. When I wanted to
implement such a user-program for
\linux
, I came across the
differences in behavior of the various drivers, and the need for an
$
ioctl
$
informing about media changes.
}
We believe that using
$
O
_
NONBLOCK
$
as indication for opening a device
for
$
ioctl
$
commanding only, can be easily introduced in the
\linux\
community. All the CD-player authors will have to be informed, we can
even send in our own patches to the programs. The use of
$
O
_
NONBLOCK
$
has most likely no influence on the behavior of the CD-players on
other operating systems than
\linux
. Finally, a user can always revert
to old behavior by a call to
$
ioctl
(
file
_
descriptor, CDROM
_
CLEAR
_
OPTIONS,
CDO
_
USE
_
FFLAGS
)
$
.
\subsection
{
The preferred strategy of
$
open
()
$}
The routines in
\cdromc\
are designed in such way, that a run-time
configuration of the behavior of
\cdrom\
devices (of
{
\em
any
\/
}
type)
can be carried out, by the
$
CDROM
_
SET
/
CLEAR
_
OPTIONS
$
$
ioctls
$
. Thus, various
modes of operation can be set:
\begin{description}
\item
[$CDO_AUTO_CLOSE \mathrel| CDO_USE_FFLAGS \mathrel| CDO_LOCK$]
This is the default setting. (With
$
CDO
_
CHECK
_
TYPE
$
it will be better,
in the future.) If the device is not yet opened by any other process,
and it is opened for data (
$
O
_
NONBLOCK
$
is not set) and the tray is
found open, an attempt to close the tray is made. Then, it is verified
that a disc is in the drive and, if
$
CDO
_
CHECK
_
TYPE
$
is set, that its
type is `data mode 1.' Only if all tests are passed, the return value
is zero. The door is locked to prevent file system corruption. If
opened for audio (
$
O
_
NONBLOCK
$
is set), no actions are taken and a
value of 0 will be returned.
\item
[0]
$
Open
()
$
will always be successful, the option flags are
ignored. Neither actions are undertaken, nor any integrity checks are
made.
\item
[$CDO_AUTO_CLOSE \mathrel| CDO_AUTO_EJECT \mathrel| CDO_LOCK$]
This mimics the behavior of the current sbpcd-driver. The option flags
are ignored, the tray is closed on the first open, if
necessary. Similarly, the tray is opened on the last release, i.e., if
a
\cdrom\
is unmounted, it is automatically ejected, such that the
user can replace it.
\end{description}
We hope that these option can convince everybody (both driver
maintainers and user program developers) to adapt to the new cdrom
driver scheme and option flag interpretation.
\section
{
Description of routines in
\cdromc
}
Only a few routines in
\cdromc\
are exported to the drivers. In this
section we will treat these, as well as the functioning of the routines
that `take over' the interface to the kernel. The header file
belonging to
\cdromc\
is called
\ucdrom
, but may be included in
{
\tt
cdrom.h
}
in the future.
\subsection
{$
struct
\
file
_
operations
\
cdrom
_
fops
$}
The contents of this structure has been described in
section~
\ref
{
cdrom.c
}
, and this structure should be used in
registering the block device to the kernel:
$$
register
_
blkdev
(
major, <name>,
\&
cdrom
_
fops
)
;
$$
\subsection
{$
Int
\
register
_
cdrom
(
int
\
major, char
*
name, struct
\
cdrom
_
device
_
ops
\
*
cdo
)
$}
Similar to registering
$
cdrom
_
fops
$
to the kernel, the device
operations structure, as described in section~
\ref
{
cdrom.c
}
, should be
registered to the general
\cdrom\
interface:
$$
register
_
cdrom
(
major, <name>,
\&
<device>
_
dops
)
;
$$
This function returns zero upon success, and non-zero upon failure.
\subsection
{$
Int
\
unregister
_
cdrom
(
int
\
major, char
*
name
)
$}
Unregistering device
$
name
$
with major number
$
major
$
disconnects the
registered device-operation routines from the
\cdrom\
interface.
This function returns zero upon success, and non-zero upon failure.
\subsection
{$
Int
\
cdrom
_
open
(
struct
\
inode
*
ip, struct
\
file
*
fp
)
$}
This function is not called directly by the low-level drivers, it is
listed in the standard
$
cdrom
_
fops
$
. If the VFS opens a file, this
function becomes active. A strategy logic is implemented in this
routine, taking care of all capabilities and options that are set in
the
$
cdrom
_
device
_
ops
$
connected to the device. Then, the program flow is
transferred to the device
_
dependent
$
open
()
$
call.
\subsection
{$
Void
\
cdrom
_
release
(
struct
\
inode
*
ip, struct
\
file
*
fp
)
$}
This function implements the reverse-logic of
$
cdrom
_
open
()
$
, and then
calls the device-dependent
$
release
()
$
routine. When the use-count
has reached 0, the allocated buffers in the are flushed by calls to
$
sync
_
dev
(
dev
)
$
and
$
invalidate
_
buffers
(
dev
)
$
.
\subsection
{$
Int
\
cdrom
_
ioctl
(
struct
\
inode
*
ip, struct
\
file
*
fp,
unsigned
\
int
\
cmd, unsigned
\
long
\
arg
)
$}
\label
{
cdrom-ioctl
}
This function handles all
$
ioctl
$
requests for
\cdrom\
devices in a
uniform way. The different calls fall into three categories:
$
ioctl
$
s
that can be directly implemented by device operations, ones that are
routed through the call
$
audio
_
ioctl
()
$
, and the remaining ones, that
are presumable device-dependent. Generally, a negative return value
indicates an error.
\subsubsection
{
Directly implemented
$
ioctl
$
s
}
\label
{
ioctl-direct
}
The following `old'
\cdrom
-
$
ioctl
$
s are implemented by directly
calling device-operations in
$
cdrom
_
device
_
ops
$
, if implemented and
not masked:
\begin{description}
\item
[CDROMMULTISESSION]
Requests the last session on a
\cdrom
.
\item
[CDROMEJECT]
Open tray.
\item
[CDROMCLOSETRAY]
Close tray.
\item
[CDROMEJECT_SW]
If
$
arg
\not
=
0
$
, set behavior to auto-close (close
tray on first open) and auto-eject (eject on last release), otherwise
set behavior to non-moving on
$
open
()
$
and
$
release
()
$
calls.
\item
[CDROM_GET_MCN or CDROM_GET_UPC]
Get the Medium Catalog Number from a CD.
\end{description}
\subsubsection
{$
Ioctl
$
s rooted through
$
audio
_
ioctl
()
$}
\label
{
ioctl-audio
}
The following set of
$
ioctl
$
s are all implemented through a call to
the
$
cdrom
_
fops
$
function
$
audio
_
ioctl
()
$
. Memory checks and
allocation are performed in
$
cdrom
_
ioctl
()
$
, and also sanitization of
address format (
$
CDROM
_
LBA
$
/
$
CDROM
_
MSF
$
) is done.
\begin{description}
\item
[CDROMSUBCHNL]
Get sub-channel data in argument
$
arg
$
of type
$
struct
\
cdrom
_
subchnl
*
{}$
.
\item
[CDROMREADTOCHDR]
Read Table of Contents header, in
$
arg
$
of type
$
struct
\
cdrom
_
tochdr
*
{}$
.
\item
[CDROMREADTOCENTRY]
Read a Table of Contents entry in
$
arg
$
and
specified by
$
arg
$
of type
$
struct
\
cdrom
_
tocentry
*
{}$
.
\item
[CDROMPLAYMSF]
Play audio fragment specified in Minute, Second,
Frame format, delimited by
$
arg
$
of type
$
struct
\
cdrom
_
msf
*
{}$
.
\item
[CDROMPLAYTRKIND]
Play audio fragment in track-index format
delimited by
$
arg
$
of type
$
struct cdrom
_
ti
*
{}$
.
\item
[CDROMVOLCTRL]
Set volume specified by
$
arg
$
of type
$
struct
\
cdrom
_
volctrl
*
{}$
.
\item
[CDROMVOLREAD]
Read volume into by
$
arg
$
of type
$
struct
\
cdrom
_
volctrl
*
{}$
.
\item
[CDROMSTART]
Spin up disc.
\item
[CDROMSTOP]
Stop playback of audio fragment.
\item
[CDROMPAUSE]
Pause playback of audio fragment.
\item
[CDROMRESUME]
Resume playing.
\end{description}
\subsubsection
{
New
$
ioctl
$
s in
\cdromc
}
The following
$
ioctl
$
s have been introduced to allow user programs to
control the behavior of individual
\cdrom\
devices. New
$
ioctl
$
commands an be identified by their underscores in the name.
\begin{description}
\item
[CDROM_SET_OPTIONS]
Set options specified by
$
arg
$
. Returns the
option flag register after modification. Use
$
arg
=
\rm
0
$
for reading
the current flags.
\item
[CDROM_CLEAR_OPTIONS]
Clear options specified by
$
arg
$
. Returns
the option flag register after modification.
\item
[CDROM_SELECT_SPEED]
Select head-rate speed of disc specified as
by
$
arg
$
. The value 0 means `auto-select', i.e., play audio discs at
real time and data disc at maximum speed. The value
$
arg
$
is
checked against the maximum head rate of the drive found in
the
$
cdrom
_
dops
$
.
\item
[CDROM_SELECT_DISC]
Select disc numbered
$
arg
$
from a juke-box.
First disc is numbered 0. The number
$
arg
$
is checked against the
maximum number of discs in the juke-box found in the
$
cdrom
_
dops
$
.
\item
[CDROM_MEDIA_CHANGED]
Returns 1 if a disc has been changed since
the last call. Note that calls to cdrom
_$
media
_
changed
$
by the VFS
are treated by an independent queue, so both mechanisms will detect
a media change once. Currently,
\cdromc\
implements maximum 16 minors
per major device.
\item
[CDROM_DRIVE_STATUS]
Returns the status of the drive by a call to
$
drive
_
status
()
$
. Return values are as defined in section~
\ref
{
drive
status
}
. Note that this call doesn't return information on the
current playing activity of the drive, this can be polled through an
$
ioctl
$
call to
$
CDROMSUBCHNL
$
.
\item
[CDROM_DISC_STATUS]
Returns the type of the disc currently in the
drive by a call to
$
disc
_
status
()
$
. Return values are as defined in
section~
\ref
{
disc status
}
.
\end{description}
\subsubsection
{
Device dependent
$
ioct
$
s
}
Finally, all other
$
ioctl
$
s are passed to the function
$
dev
_
ioctl
()
$
,
if implemented. No memory allocation or verification is carried out.
\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
the directory tree that came with this documentation.
\item
Include
{
\tt
\char
`
\<
linux/ucdrom.h>
}
just after
{
\tt
cdrom.h
}
.
\item
change the 3rd argument of
$
register
_
blkdev
$
from
$
\&
<your
-
drive>
_
fops
$
to
$
\&
cdrom
_
fops
$
.
\item
Just after that line, add a line to register to the
\cdrom\
routines:
$$
register
_
cdrom
(
major, <name>, <your
-
drive>
_
dops
)
;
$$
Similarly, add a call to
$
unregister
_
cdrom
()
$
.
\item
Copy an example of the device-operations
$
struct
$
to your source,
e.g., from
{
\tt
cm206.c
}
$
cm
206
_
dops
$
, and change all entries to names
corresponding to your driver, or names you just happen to like. If
your driver doesn't support a certain function, make the entry
$
NULL
$
. At the entry
$
capability
$
you should list all capabilities
your drive could support, in principle. If your drive has a capability
that is not listed, please send me a message.
\item
Implement all functions in your
$
<device>
_
dops
$
structure,
according to prototypes listed in
\ucdrom
, and specifications given in
section~
\ref
{
cdrom.c
}
. Most likely you have already implemented
the code in a large part, and you may just have to adapt the prototype
and return values.
\item
Rename your
$
<device>
_
ioctl
()
$
function to
$
audio
_
ioctl
$
and
change the prototype a little. Remove entries listed in the first part
in section~
\ref
{
cdrom-ioctl
}
, if your code was OK, this are just calls
to the routines you adapted in the previous step.
\item
You may remove all remaining memory checking code in the
$
audio
_
ioctl
()
$
function that deal with audio commands (these are
listed in the second part of section~
\ref
{
cdrom-ioctl
}
). There is no
need for memory allocation either, so most
$
case
$
s in the
$
switch
$
statement look similar to:
$$
case
\
CDROMREADTOCENTRY
\colon
get
_
toc
_
entry
\bigl
((
struct
\
cdrom
_
tocentry
*
{}
)
\
arg
\bigr
)
;
$$
\item
All remaining
$
ioctl
$
cases must be moved to a separate
function,
$
<device>
_
ioctl
$
, the device-dependent
$
ioctl
$
s. Note that
memory checking and allocation must be kept in this code!
\item
Change the prototypes of
$
<device>
_
open
()
$
and
$
<device>
_
release
()
$
, and remove any strategic code (i.e., tray
movement, door locking, etc.).
\item
Try to recompile the drivers. We advice you to use modules, both
for
{
\tt
cdrom.o
}
and your driver, as debugging is much easier this
way.
\end{enumerate}
\section
{
Thanks
}
Thanks to all the people involved. Thanks to Thomas Quinot, Jon Tombs,
Ken Pizzini, Eberhard M
\"
onkeberg and Andrew Kroll, the
\linux\
\cdrom\
device driver developers that were kind enough to give
sugestions and criticisms during the writing. Finally of course, I
want to thank Linus Torvalds for making this possible in the first
place.
\end{document}
Documentation/cdrom/cm206
View file @
0351166f
...
...
@@ -3,14 +3,20 @@ cm206 in combination with the cm260 host adapter card.
(c) 1995 David A. van Leeuwen
Features as of version 0.33
Changes since version 0.99
--------------------------
- Interfacing to the kernel is routed though an extra interface layer,
cdrom.c. This allows runtime-configurable `bahavior' of the cdrom-drive,
independent of the driver.
Features since version 0.33
---------------------------
- Full audio support, that is, both workman, workbone and cdp work
now reasonably. Reading TOC still takes some time. xmcd has been
reported to run successfully.
- Made auto-probe code a little better, i hope
Features
as of
version 0.28
Features
since
version 0.28
---------------------------
- Full speed transfer rate (300 kB/s).
- Minimum kernel memory usage for buffering (less than 3 kB).
...
...
@@ -21,12 +27,6 @@ Features as of version 0.28
- Auto-probing of adapter card's base port and irq line,
also configurable at boot time or module load time.
Features still lacking
----------------------
- cm205ms+cm250 support. (I do have cm205ms docs now. I still have to
study Kai Petzke's cm205 drives to understand the workings of the
cm250 adapter card. Don't bet on me, write a driver yourself!)
Decide how you are going to use the driver. There are two
options:
...
...
@@ -66,9 +66,16 @@ Using the driver as a module
----------------------------
If you will only seldomly use the cd-rom driver, you can choose for
option (b), install as a loadable module. You may have to re-compile
the module when you upgrade the kernel to a new version. Read the file
`README.modules' in /usr/src/linux. To install the module, you use the
command, as root
the module when you upgrade the kernel to a new version.
Since version 0.96, much of the functionality has been transferred to
a generic cdrom interface in the file cdrom.c. The module cm206.o
depends on cdrom.o. If the latter is not compiled in in the kernel,
you must explicitly load it before cm206.o:
insmod /usr/src/linux/modules/cdrom.o
To install the module, you use the command, as root
insmod /usr/src/linux/modules/cm206.o
...
...
@@ -80,16 +87,8 @@ line to be used, e.g.
The order of base port and irq line don't matter; you may specify only
one, the other will have the value of the compiled-in default. You
may also have to install the file-system module `iso9660.o', if you
didn't compile that into the kernel. (If you use `tcsh' as shell, you
might consider defining
didn't compile that into the kernel.
alias listinstalledmodules 'cat /proc/modules | awk \{print\$1\}'
complete rmmod 'p/1/`listinstalledmodules`/'
alias listcompiledmodules '(cd /usr/src/linux/modules; \ls -o *.o)'
alias insmod 'insmod /usr/src/linux/modules/\!:1 \!:2*'
complete insmod 'p/1/`listcompiledmodules`/'
which makes typing insmod and rmmod somewhat easier.)
Using the driver as part of the kernel
--------------------------------------
...
...
@@ -103,6 +102,16 @@ If you may specify either IRQ (3--11) or base port (0x300--0x370),
auto probing is turned off for both settings, thus setting the
other value to the compiled-in default.
Note that you can put these parameters also in the lilo configuration file:
# linux config
image = /vmlinuz
root = /dev/hda1
label = Linux
append = "cm206=0x340,11"
read-only
If module parameters and LILO config options don't work
-------------------------------------------------------
If autoprobing does not work, you can hard-wire the default values
...
...
@@ -111,7 +120,6 @@ of the base port address (CM206_BASE) and interrupt request line
the defines of CM206_IRQ and CM206_BASE.
Mounting the cdrom
------------------
1) Make sure that there is the right device installed in /dev.
...
...
@@ -138,15 +146,14 @@ Mounting the cdrom
If things don't work
--------------------
- Try to do a `
tail /var/adm/messages' to find out if the driver
said anything about
what is going wrong during the initialization.
- Try to do a `
dmesg' to find out if the driver said anything about
what is going wrong during the initialization.
- Try to do a `dd if=/dev/cm206cd | od -tc | less' to read from the
CD.
- Look in the /proc directory to see if `cm206' shows up under
one of `interrupts', `ioports', `devices' or `modules' (if
applicable).
- Look in the /proc directory to see if `cm206' shows up under one of
`interrupts', `ioports', `devices' or `modules' (if applicable).
DISCLAIMER
...
...
@@ -173,5 +180,6 @@ The copyright of the cm206 driver for Linux is
(c) 1995 David A. van Leeuwen
The driver is released, like most Linux software, under the conditions
of the GNU general public license.
The driver is released under the conditions of the GNU general public
license, that can be found in the file COPYING in the root of this
source tree.
Documentation/ioctl-number.txt
View file @
0351166f
Ioctl Numbers
6
May 1996
10
May 1996
Michael Chastain
<mec@duracef.shout.net>
...
...
@@ -25,7 +25,7 @@ Or you can e-mail me at <mec@duracef.shout.net> and I'll register one
for you.
The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
to distinguish ioctls from each other. The third argument is
a
size
to distinguish ioctls from each other. The third argument is
the
size
of the structure going into the kernel or coming out of the kernel.
Some devices use their major number as the identifier; this is not
...
...
@@ -55,7 +55,6 @@ This table is current to Linux 1.3.98.
Ioctl Include File Comments
========================================================
0x00 linux/fs.h only FIBMAP, FIGETBSZ
0x00 linux/random.h codes in 0x010800NN
0x00 linux/mc146818rtc.h conflict!
0x02 linux/fd.h
0x03 linux/hdreg.h
...
...
@@ -75,6 +74,7 @@ Ioctl Include File Comments
'M' linux/soundcard.h
'P' linux/soundcard.h
'Q' linux/soundcard.h
'R' linux/random.h
'S' linux/cdrom.h conflict!
'S' scsi/scsi.h conflict!
'S' scsi/scsi_ioctl.h conflict!
...
...
Documentation/java.txt
View file @
0351166f
...
...
@@ -51,7 +51,7 @@ Set the executable permissions of the binary file, with:
And then execute it:
./Hello
w
World.class
./HelloWorld.class
Yes, it's JUST THAT EASY! ;-)
...
...
Documentation/magic-number.txt
View file @
0351166f
...
...
@@ -21,7 +21,7 @@ struct tty_ldisc {
Please follow this discipline when you are adding future enhancements
to the kernel! It has saved me countless hours of debugging,
especially in the screw cases where an array has been overrun and
especially in the screw
y
cases where an array has been overrun and
structures following the array have been overwritten. Using this
discipline, these cases get detected quickly and safely.
...
...
Documentation/oops-tracing.txt
View file @
0351166f
...
...
@@ -6,7 +6,7 @@ The main trick is having 5 years of experience with those pesky oops
messages ;-)
Actually, there are things you can do that make this easier. I have two
separate approache
d
:
separate approache
s
:
gdb /usr/src/linux/vmlinux
gdb> disassemble <offending_function>
...
...
Makefile
View file @
0351166f
VERSION
=
1
PATCHLEVEL
=
3
SUBLEVEL
=
1
00
PATCHLEVEL
=
99
SUBLEVEL
=
1
ARCH
=
i386
...
...
drivers/cdrom/Makefile
View file @
0351166f
...
...
@@ -20,6 +20,16 @@ L_OBJS :=
M_OBJS
:=
MOD_LIST_NAME
:=
CDROM_MODULES
# The following if's should be generalized (ORed) for all drivers that
# use the generic interface of cdrom.c
ifeq
($(CONFIG_CM206),y)
L_OBJS
+=
cdrom.o
else
ifeq
($(CONFIG_CM206),m)
M_OBJS
+=
cdrom.o
endif
endif
ifeq
($(CONFIG_AZTCD),y)
L_OBJS
+=
aztcd.o
else
...
...
drivers/cdrom/cdrom.c
0 → 100644
View file @
0351166f
/* cdrom.c. Common ioctl and open routines for various Linux cdrom drivers. -*- linux-c -*-
Copyright (c) 1996 David van Leeuwen.
The routines in the file should provide an interface between
software accessing cdroms and the various drivers that implement
specific hardware devices.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/fcntl.h>
#include <linux/cdrom.h>
#include <linux/ucdrom.h>
#define FM_WRITE 0x2
/* file mode write bit */
#define VERSION "$Id: cdrom.c,v 0.4 1996/04/17 20:47:50 david Exp david $"
/* Not-exported routines. */
int
cdrom_open
(
struct
inode
*
ip
,
struct
file
*
fp
);
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
);
struct
file_operations
cdrom_fops
=
{
NULL
,
/* lseek */
block_read
,
/* read - general block-dev read */
block_write
,
/* write - general block-dev write */
NULL
,
/* readdir */
NULL
,
/* select */
cdrom_ioctl
,
/* ioctl */
NULL
,
/* mmap */
cdrom_open
,
/* open */
cdrom_release
,
/* release */
NULL
,
/* fsync */
NULL
,
/* fasync */
cdrom_media_changed
,
/* media_change */
NULL
/* revalidate */
};
static
struct
cdrom_device_ops
*
cdromdevs
[
MAX_BLKDEV
]
=
{
NULL
,
};
/* This macro makes sure we don't have to check on cdrom_device_ops
* existence in the run-time routines below. Change_capability is a
* hack to have the capability flags defined const, while we can still
* change it here without gcc complaining at every line.
*/
#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
/* We don't use $name$ yet, but it could be used for the /proc
* filesystem in the future, or for other purposes.
*/
int
register_cdrom
(
int
major
,
char
*
name
,
struct
cdrom_device_ops
*
cdo
)
{
int
*
change_capability
=
&
cdo
->
capability
;
/* hack, gcc complains OK */
if
(
major
<
0
||
major
>=
MAX_BLKDEV
)
return
-
1
;
if
(
cdo
->
open_files
==
NULL
||
cdo
->
open
==
NULL
||
cdo
->
release
==
NULL
)
return
-
2
;
ENSURE
(
tray_move
,
CDC_CLOSE_TRAY
|
CDC_OPEN_TRAY
);
ENSURE
(
lock_door
,
CDC_LOCK
);
ENSURE
(
select_speed
,
CDC_SELECT_SPEED
);
ENSURE
(
select_disc
,
CDC_SELECT_DISC
);
ENSURE
(
get_last_session
,
CDC_MULTI_SESSION
);
ENSURE
(
audio_ioctl
,
CDC_PLAY_AUDIO
);
ENSURE
(
media_changed
,
CDC_MEDIA_CHANGED
);
cdromdevs
[
major
]
=
cdo
;
cdo
->
options
=
CDO_AUTO_CLOSE
|
CDO_USE_FFLAGS
|
CDO_LOCK
;
cdo
->
mc_flags
=
0
;
return
0
;
}
#undef ENSURE
int
unregister_cdrom
(
int
major
,
char
*
name
)
{
if
(
major
<
0
||
major
>=
MAX_BLKDEV
)
return
-
1
;
if
(
cdromdevs
[
major
]
==
NULL
)
return
-
2
;
cdromdevs
[
major
]
=
NULL
;
return
0
;
}
/* We need our own cdrom error types! This is a temporary solution. */
#define ENOMEDIUM EAGAIN
/* no medium in removable device */
/* We use the open-option O_NONBLOCK as in indicator of that the
* purpose of opening is only for subsequent ioctl() calls; no device
* integrity checks are performed.
*
* We hope that all cd-player programs will adopt this convention. It
* is in their own advantage: device conotrol becomes a lot easier
* this way.
*/
int
open_for_data
(
struct
cdrom_device_ops
*
,
int
);
int
cdrom_open
(
struct
inode
*
ip
,
struct
file
*
fp
)
{
dev_t
dev
=
ip
->
i_rdev
;
struct
cdrom_device_ops
*
cdo
=
cdromdevs
[
MAJOR
(
dev
)];
int
purpose
=
!!
(
fp
->
f_flags
&
O_NONBLOCK
);
if
(
cdo
==
NULL
||
MINOR
(
dev
)
>=
cdo
->
minors
)
return
-
ENODEV
;
if
(
fp
->
f_mode
&
FM_WRITE
)
return
-
EROFS
;
purpose
=
purpose
||
!
(
cdo
->
options
&
CDO_USE_FFLAGS
);
if
(
cdo
->
open_files
(
dev
)
||
purpose
)
return
cdo
->
open
(
dev
,
purpose
);
else
return
open_for_data
(
cdo
,
dev
);
}
int
open_for_data
(
struct
cdrom_device_ops
*
cdo
,
int
dev
)
{
int
ret
;
if
(
cdo
->
drive_status
!=
NULL
)
{
int
ds
=
cdo
->
drive_status
(
dev
);
if
(
ds
==
CDS_TRAY_OPEN
)
{
/* can/may i close it? */
if
(
cdo
->
capability
&
~
cdo
->
mask
&
CDC_CLOSE_TRAY
&&
cdo
->
options
&
CDO_AUTO_CLOSE
)
{
if
(
cdo
->
tray_move
(
dev
,
0
))
return
-
EIO
;
}
else
return
-
ENOMEDIUM
;
/* can't close: too bad */
ds
=
cdo
->
drive_status
(
dev
);
if
(
ds
==
CDS_NO_DISC
)
return
-
ENOMEDIUM
;
}
}
if
(
cdo
->
disc_status
!=
NULL
)
{
int
ds
=
cdo
->
disc_status
(
dev
);
if
(
ds
==
CDS_NO_DISC
)
return
-
ENOMEDIUM
;
if
(
cdo
->
options
&
CDO_CHECK_TYPE
&&
ds
!=
CDS_DATA_1
)
return
-
ENODATA
;
}
/* all is well, we can open the device */
ret
=
cdo
->
open
(
dev
,
0
);
/* open for data */
if
(
cdo
->
capability
&
~
cdo
->
mask
&
CDC_LOCK
&&
cdo
->
options
&
CDO_LOCK
)
cdo
->
lock_door
(
dev
,
1
);
return
ret
;
}
/* 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
;
struct
cdrom_device_ops
*
cdo
=
cdromdevs
[
MAJOR
(
dev
)];
if
(
cdo
==
NULL
||
MINOR
(
dev
)
>=
cdo
->
minors
)
return
;
if
(
cdo
->
open_files
(
dev
)
==
1
&&
/* last process that closes dev */
cdo
->
options
&
CDO_LOCK
&&
cdo
->
capability
&
~
cdo
->
mask
&
CDC_LOCK
)
cdo
->
lock_door
(
dev
,
0
);
cdo
->
release
(
dev
);
if
(
cdo
->
open_files
(
dev
)
==
0
)
{
/* last process that closes dev */
sync_dev
(
dev
);
invalidate_buffers
(
dev
);
if
(
cdo
->
options
&
CDO_AUTO_EJECT
&&
cdo
->
capability
&
~
cdo
->
mask
&
CDC_OPEN_TRAY
)
cdo
->
tray_move
(
dev
,
1
);
}
}
/* We want to make media_changed accessible to the user through an
* ioctl. The main problem now is that we must double-buffer the
* low-level implementation, to assure that the VFS and the user both
* see a medium change once.
*
* For now, i've implemented only 16 minor devs (half a long), i have to
* think of a better solution... $Queue$ is either 0 or 1. Queue 0 is
* in the lower 16 bits, queue 1 in the higher 16 bits.
*/
int
media_changed
(
dev_t
dev
,
int
queue
)
{
unsigned
int
major
=
MAJOR
(
dev
);
unsigned
int
minor
=
MINOR
(
dev
);
struct
cdrom_device_ops
*
cdo
=
cdromdevs
[
major
];
int
ret
;
unsigned
long
mask
=
1
<<
(
16
*
queue
+
minor
);
queue
&=
1
;
if
(
cdo
==
NULL
||
minor
>=
16
)
return
-
1
;
ret
=
!!
(
cdo
->
mc_flags
&
mask
);
/* changed since last call? */
if
(
cdo
->
media_changed
(
dev
))
{
cdo
->
mc_flags
|=
0x10001
<<
minor
;
/* set bit on both queues */
ret
|=
1
;
}
cdo
->
mc_flags
&=
~
mask
;
/* clear bit */
return
ret
;
}
int
cdrom_media_changed
(
dev_t
dev
)
{
struct
cdrom_device_ops
*
cdo
=
cdromdevs
[
MAJOR
(
dev
)];
if
(
cdo
==
NULL
||
MINOR
(
dev
)
>=
cdo
->
minors
)
return
-
ENODEV
;
if
(
cdo
->
media_changed
==
NULL
)
return
-
EINVAL
;
return
media_changed
(
dev
,
0
);
}
/* Requests to the low-level drivers will /always/ be done in the
following format convention:
CDROM_LBA: all data-related requests.
CDROM_MSF: all audio-related requests.
However, a low-level implementation is allowed to refuse this
request, and return information in its own favorite format.
It doesn't make sense /at all/ to ask for a play_audio in LBA
format, or ask for multi-session info in MSF format. However, for
backward compatibility these format requests will be satisfied, but
the requests to the low-level drivers will be sanitized in the more
meaningful format indicated above.
*/
#undef current
/* set in sched.h */
void
sanitize_format
(
union
cdrom_addr
*
addr
,
u_char
*
current
,
u_char
requested
)
{
if
(
*
current
==
requested
)
return
;
/* nothing to be done! */
if
(
requested
==
CDROM_LBA
)
{
addr
->
lba
=
(
int
)
addr
->
msf
.
frame
+
75
*
(
addr
->
msf
.
second
-
2
+
60
*
addr
->
msf
.
minute
);
}
else
{
/* CDROM_MSF */
int
lba
=
addr
->
lba
;
addr
->
msf
.
frame
=
lba
%
75
;
lba
/=
75
;
lba
+=
2
;
addr
->
msf
.
second
=
lba
%
60
;
addr
->
msf
.
minute
=
lba
/
60
;
}
*
current
=
requested
;
}
/* All checking and format change makes this code really hard to read!
* So let's make some check and memory move macros. These macros are
* a little inenficient when used both in the same piece of code, as
* verify_area is used twice, but who cares, as ioctl() calls
* shouldn't be in inner loops.
*/
#define GETARG(type, x) { \
int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
if (ret) return ret; \
memcpy_fromfs(&x, (type *) arg, sizeof x); }
#define PUTARG(type, x) { \
int ret=verify_area(VERIFY_WRITE, (void *) arg, sizeof x); \
if (ret) return ret; \
memcpy_tofs((type *) arg, &x, sizeof x); }
/* Some of the cdrom ioctls are not implemented here, because these
* appear to be either too device-specific, or it is not clear to me
* what use they are. These are (number of drivers that support them
* in parenthesis): CDROMREADMODE1 (2+ide), CDROMREADMODE2 (2+ide),
* CDROMREADAUDIO (2+ide), CDROMREADRAW (2), CDROMREADCOOKED (2),
* CDROMSEEK (2), CDROMPLAYBLK (scsi), CDROMREADALL (1). Read-audio,
* OK (although i guess the record companies aren't too hapy with
* this, most drives therefor refuse to transport audio data). But
* why are there 5 different READs defined? For now, these functions
* are left over to the device-specific ioctl routine,
* cdo->dev_ioctl. Note that as a result of this, no
* memory-verification is performed for these ioctls.
*/
int
cdrom_ioctl
(
struct
inode
*
ip
,
struct
file
*
fp
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
dev_t
dev
=
ip
->
i_rdev
;
struct
cdrom_device_ops
*
cdo
=
cdromdevs
[
MAJOR
(
dev
)];
if
(
cdo
==
NULL
||
MINOR
(
dev
)
>=
cdo
->
minors
)
return
-
ENODEV
;
/* the first few commands do not deal with audio capabilities, but
only with routines in cdrom device operations. */
switch
(
cmd
)
{
/* maybe we should order cases after statistics of use? */
case
CDROMMULTISESSION
:
{
struct
cdrom_multisession
ms_info
;
u_char
requested_format
;
if
(
!
(
cdo
->
capability
&
CDC_MULTI_SESSION
))
return
-
EINVAL
;
GETARG
(
struct
cdrom_multisession
,
ms_info
);
requested_format
=
ms_info
.
addr_format
;
ms_info
.
addr_format
=
CDROM_LBA
;
cdo
->
get_last_session
(
dev
,
&
ms_info
);
sanitize_format
(
&
ms_info
.
addr
,
&
ms_info
.
addr_format
,
requested_format
);
PUTARG
(
struct
cdrom_multisession
,
ms_info
);
return
0
;
}
case
CDROMEJECT
:
if
(
cdo
->
open_files
(
dev
)
==
1
&&
cdo
->
capability
&
~
cdo
->
mask
&
CDC_OPEN_TRAY
)
return
cdo
->
tray_move
(
dev
,
1
);
else
return
-
EINVAL
;
case
CDROMCLOSETRAY
:
if
(
cdo
->
open_files
(
dev
)
==
1
&&
cdo
->
capability
&
~
cdo
->
mask
&
CDC_CLOSE_TRAY
)
return
cdo
->
tray_move
(
dev
,
0
);
else
return
-
EINVAL
;
case
CDROMEJECT_SW
:
cdo
->
options
&=
~
(
CDO_AUTO_CLOSE
|
CDO_AUTO_EJECT
);
if
(
arg
)
cdo
->
options
|=
CDO_AUTO_CLOSE
|
CDO_AUTO_EJECT
;
return
0
;
case
CDROM_MEDIA_CHANGED
:
if
(
cdo
->
capability
&
~
cdo
->
mask
&
CDC_MEDIA_CHANGED
)
return
media_changed
(
dev
,
1
);
else
return
-
EINVAL
;
case
CDROM_SET_OPTIONS
:
cdo
->
options
|=
(
int
)
arg
;
return
cdo
->
options
;
case
CDROM_CLEAR_OPTIONS
:
cdo
->
options
&=
~
(
int
)
arg
;
return
cdo
->
options
;
case
CDROM_SELECT_SPEED
:
if
(
0
<=
arg
&&
arg
<
(
int
)
(
cdo
->
speed
+
0
.
5
)
&&
cdo
->
capability
&
~
cdo
->
mask
&
CDC_SELECT_SPEED
)
return
cdo
->
select_speed
(
dev
,
arg
);
else
return
-
EINVAL
;
case
CDROM_SELECT_DISC
:
if
(
0
<=
arg
&&
arg
<=
cdo
->
capacity
&&
cdo
->
capability
&
~
cdo
->
mask
&
CDC_SELECT_DISC
)
return
cdo
->
select_disc
(
dev
,
arg
);
else
return
-
EINVAL
;
/* The following function is implemented, although very few audio
* discs give Universal Product Code information, which should just be
* the Medium Catalog Number on the box. Note, that the way the code
* is written on the CD is /not/ uniform across all discs!
*/
case
CDROM_GET_MCN
:
{
struct
cdrom_mcn
mcn
;
if
(
!
(
cdo
->
capability
&
CDC_MCN
))
return
-
EINVAL
;
if
(
!
cdo
->
get_mcn
(
dev
,
&
mcn
))
{
PUTARG
(
struct
cdrom_mcn
,
mcn
);
return
0
;
}
return
-
EINVAL
;
}
case
CDROM_DRIVE_STATUS
:
if
(
cdo
->
drive_status
==
NULL
)
return
-
EINVAL
;
else
return
cdo
->
drive_status
(
dev
);
case
CDROM_DISC_STATUS
:
if
(
cdo
->
disc_status
==
NULL
)
return
-
EINVAL
;
else
return
cdo
->
disc_status
(
dev
);
/* The following is not implemented, because there are too many
* different data type. We could support /1/ raw mode, that is large
* enough to hold everything.
*/
#if 0
case CDROMREADMODE1: {
struct cdrom_msf msf;
char buf[CD_FRAMESIZE];
GETARG(struct cdrom_msf, msf);
if (!cdo->read_audio(dev, cmd, &msf, &buf)) {
PUTARG(char *, buf);
return 0;
}
return -EINVAL;
}
#endif
}
/* switch */
/* Now all the audio-ioctls follow, they are all routed through the
same call audio_ioctl(). */
if
(
cdo
->
capability
&
CDC_PLAY_AUDIO
)
switch
(
cmd
)
{
case
CDROMSUBCHNL
:
{
struct
cdrom_subchnl
q
;
u_char
requested
,
back
;
GETARG
(
struct
cdrom_subchnl
,
q
);
requested
=
q
.
cdsc_format
;
q
.
cdsc_format
=
CDROM_MSF
;
if
(
!
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
q
))
{
back
=
q
.
cdsc_format
;
/* local copy */
sanitize_format
(
&
q
.
cdsc_absaddr
,
&
back
,
requested
);
sanitize_format
(
&
q
.
cdsc_reladdr
,
&
q
.
cdsc_format
,
requested
);
PUTARG
(
struct
cdrom_subchnl
,
q
);
return
0
;
}
else
return
-
EINVAL
;
}
case
CDROMREADTOCHDR
:
{
struct
cdrom_tochdr
header
;
GETARG
(
struct
cdrom_tochdr
,
header
);
if
(
!
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
header
))
{
PUTARG
(
struct
cdrom_tochdr
,
header
);
return
0
;
}
else
return
-
EINVAL
;
}
case
CDROMREADTOCENTRY
:
{
struct
cdrom_tocentry
entry
;
u_char
requested_format
;
GETARG
(
struct
cdrom_tocentry
,
entry
);
requested_format
=
entry
.
cdte_format
;
/* make interface to low-level uniform */
entry
.
cdte_format
=
CDROM_MSF
;
if
(
!
(
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
entry
)))
{
sanitize_format
(
&
entry
.
cdte_addr
,
&
entry
.
cdte_format
,
requested_format
);
PUTARG
(
struct
cdrom_tocentry
,
entry
);
return
0
;
}
else
return
-
EINVAL
;
}
case
CDROMPLAYMSF
:
{
struct
cdrom_msf
msf
;
GETARG
(
struct
cdrom_mdf
,
msf
);
return
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
msf
);
}
case
CDROMPLAYTRKIND
:
{
struct
cdrom_ti
track_index
;
GETARG
(
struct
cdrom_ti
,
track_index
);
return
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
track_index
);
}
case
CDROMVOLCTRL
:
{
struct
cdrom_volctrl
volume
;
GETARG
(
struct
cdrom_volctl
,
volume
);
return
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
volume
);
}
case
CDROMVOLREAD
:
{
struct
cdrom_volctrl
volume
;
if
(
!
cdo
->
audio_ioctl
(
dev
,
cmd
,
&
volume
))
{
PUTARG
(
struct
cdrom_volctl
,
volume
);
return
0
;
}
return
-
EINVAL
;
}
case
CDROMSTART
:
case
CDROMSTOP
:
case
CDROMPAUSE
:
case
CDROMRESUME
:
return
cdo
->
audio_ioctl
(
dev
,
cmd
,
NULL
);
}
/* switch */
if
(
cdo
->
dev_ioctl
!=
NULL
)
/* device specific ioctls? */
return
cdo
->
dev_ioctl
(
dev
,
cmd
,
arg
);
return
-
EINVAL
;
}
#ifdef MODULE
int
init_module
(
void
)
{
printk
(
KERN_INFO
"Module inserted "
VERSION
"
\n
"
);
return
0
;
}
void
cleanup_module
(
void
)
{
printk
(
KERN_INFO
"Module cdrom removed
\n
"
);
}
#endif
/*
* Local variables:
* comment-column: 40
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux-obj/include -Wall -Wstrict-prototypes -O2 -m486 -c cdrom.c -o cdrom.o"
* End:
*/
drivers/cdrom/cm206.c
View file @
0351166f
/* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card.
Copyright (c) 1995 David van Leeuwen.
Copyright (c) 1995
, 1996
David van Leeuwen.
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
...
...
@@ -54,11 +54,30 @@
10 jun 1995: 0.33 Workman still behaves funny, but you should be
able to eject and substitute another disc.
An adaption of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg
An adapt
at
ion of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg
18 jul 199
6
: 0.34 Patch by Heiko Eissfeldt included, mainly considering
18 jul 199
5
: 0.34 Patch by Heiko Eissfeldt included, mainly considering
verify_area's in the ioctls. Some bugs introduced by
EM considering the base port and irq fixed.
18 dec 1995: 0.35 Add some code for error checking... no luck...
We jump to reach our goal: version 1.0 in the next stable linux kernel.
19 mar 1996: 0.95 Different implementation of CDROM_GET_UPC, on
request of Thomas Quinot.
25 mar 1996: 0.96 Interpretation of opening with O_WRONLY or O_RDWR:
open only for ioctl operation, e.g., for operation of
tray etc.
4 apr 1996: 0.97 First implementation of layer between VFS and cdrom
driver, a generic interface. Much of the functionality
of cm206_open() and cm206_ioctl() is transferred to a
new file cdrom.c and its header ucdrom.h.
Upgrade to Linux kernel 1.3.78.
11 apr 1996 0.98 Upgrade to Linux kernel 1.3.85
More uniformization stuff.
*
* Parts of the code are based upon lmscd.c written by Kai Petzke,
* sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin
...
...
@@ -73,13 +92,13 @@
* with `cm206' in it, as this stuff is too series-dependent.
*
* Currently, my limited knowledge is based on:
* - The Linux Kernel Hacker's guide, v. 0.5
, by Michael J. Johnson
* - The Linux Kernel Hacker's guide, v. 0.5, by Michael J. Johnson
* - Linux Kernel Programmierung, by Michael Beck and others
* - Philips/LMS cm206 and cm226 product specification
* - Philips/LMS cm260 product specification
*
* David van Leeuwen, david@tm.tno.nl. */
#define VERSION "
0.34
"
#define VERSION "
$Id: cm206.c,v 0.99 1996/04/14 20:26:26 david Exp $
"
#include <linux/module.h>
...
...
@@ -94,10 +113,18 @@
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/ucdrom.h>
#include <asm/io.h>
#define MAJOR_NR CM206_CDROM_MAJOR
#include <linux/blk.h>
#undef DEBUG
#define STATISTICS
/* record times and frequencies of events */
#undef AUTO_PROBE_MODULE
#define USE_INSW
#include <linux/cm206.h>
/* This variable defines whether or not to probe for adapter base port
...
...
@@ -109,11 +136,6 @@ static int auto_probe=1; /* Yes, why not? */
static
int
cm206_base
=
CM206_BASE
;
static
int
cm206_irq
=
CM206_IRQ
;
#undef DEBUG
#undef DEBUG_SECTORS
#define STATISTICS
#undef AUTO_PROBE_MODULE
#define POLLOOP 10000
#define READ_AHEAD 1
/* defines private buffer, waste! */
#define BACK_AHEAD 1
/* defines adapter-read ahead */
...
...
@@ -121,13 +143,16 @@ static int cm206_irq = CM206_IRQ;
#define UART_TIMEOUT (5*HZ/100)
#define DSB_TIMEOUT (7*HZ)
/* time for the slowest command to finish */
#define LINUX_BLOCK_SIZE 512
/* WHERE is this defined? */
#define RAW_SECTOR_SIZE 2352
/* ok, is also defined in cdrom.h */
#define ISO_SECTOR_SIZE 2048
#define BLOCKS_ISO (ISO_SECTOR_SIZE/LINUX_BLOCK_SIZE)
/* 4 */
#define CD_SYNC_HEAD 16
/* CD_SYNC + CD_HEAD */
#ifdef STATISTICS
/* keep track of errors in counters */
#
include <linux/stats206.h>
#define stats(i) ++cd->stats[st_ ## i]
; \
cd->last_stat[st_ ## i] = cd->stat_counter++;
#
define stats(i) { ++cd->stats[st_ ## i]; \
cd->last_stat[st_ ## i] = cd->stat_counter++
; \
}
#else
#define stats(i) (void) 0
#endif
...
...
@@ -141,7 +166,7 @@ static int cm206_irq = CM206_IRQ;
typedef
unsigned
char
uch
;
/* 8-bits */
typedef
unsigned
short
ush
;
/* 16-bits */
struct
toc_struct
{
struct
toc_struct
{
/* private copy of Table of Contents */
uch
track
,
fsm
[
3
],
q0
;
};
...
...
@@ -174,6 +199,7 @@ struct cm206_struct {
struct
toc_struct
toc
[
101
];
/* The whole table of contents + lead-out */
uch
q
[
10
];
/* Last read q-channel info */
uch
audio_status
[
5
];
/* last read position on pause */
uch
media_changed
;
/* record if media changed */
};
#define DISC_STATUS cd->disc_status[0]
...
...
@@ -182,7 +208,7 @@ struct cm206_struct {
#define PAUSED cd->audio_status[0]
/* misuse this memory byte! */
#define PLAY_TO cd->toc[0]
/* toc[0] records end-time in play */
static
struct
cm206_struct
*
cd
;
static
struct
cm206_struct
*
cd
;
/* the main memory structure */
/* First, we define some polling functions. These are actually
only being used in the initialization. */
...
...
@@ -221,62 +247,64 @@ uch send_receive_polled(int command)
as there seems so reason for this to happen.
*/
static
void
cm206_interrupt
(
int
sig
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
/* you rang? */
static
void
cm206_interrupt
(
int
sig
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
/* you rang? */
{
volatile
ush
fool
;
cd
->
intr_ds
=
inw
(
r_data_status
);
/* resets data_ready, data_error,
crc_error, sync_error, toc_ready
interrupts */
cd
->
intr_ls
=
inw
(
r_line_status
);
/* resets overrun bit */
/* receive buffer full? */
if
(
cd
->
intr_ls
&
ls_receive_buffer_full
)
{
cd
->
intr_ur
=
inb
(
r_uart_receive
);
/* get order right! */
cd
->
intr_ls
=
inw
(
r_line_status
);
/* resets rbf interrupt */
if
(
!
cd
->
background
&&
cd
->
uart
)
wake_up_interruptible
(
&
cd
->
uart
);
}
/* data ready in fifo? */
else
if
(
cd
->
intr_ds
&
ds_data_ready
)
{
if
(
cd
->
background
)
++
cd
->
adapter_last
;
if
((
cd
->
wait_back
||
!
cd
->
background
)
&&
cd
->
data
)
wake_up_interruptible
(
&
cd
->
data
);
stats
(
data_ready
);
}
/* ready to issue a write command? */
else
if
(
cd
->
command
&&
cd
->
intr_ls
&
ls_transmitter_buffer_empty
)
{
outw
(
dc_normal
|
(
inw
(
r_data_status
)
&
0x7f
),
r_data_control
);
outw
(
cd
->
command
,
r_uart_transmit
);
cd
->
command
=
0
;
if
(
!
cd
->
background
)
wake_up_interruptible
(
&
cd
->
uart
);
}
/* now treat errors (at least, identify them for debugging) */
else
if
(
cd
->
intr_ds
&
ds_fifo_overflow
)
{
debug
((
"Fifo overflow at sectors 0x%x
\n
"
,
cd
->
sector_first
));
fool
=
inw
(
r_fifo_output_buffer
);
/* de-assert the interrupt */
cd
->
fifo_overflowed
=
1
;
/* signal one word less should be read */
stats
(
fifo_overflow
);
}
else
if
(
cd
->
intr_ds
&
ds_data_error
)
{
debug
((
"Data error at sector 0x%x
\n
"
,
cd
->
sector_first
));
stats
(
data_error
);
}
else
if
(
cd
->
intr_ds
&
ds_crc_error
)
{
debug
((
"CRC error at sector 0x%x
\n
"
,
cd
->
sector_first
));
stats
(
crc_error
);
}
else
if
(
cd
->
intr_ds
&
ds_sync_error
)
{
debug
((
"Sync at sector 0x%x
\n
"
,
cd
->
sector_first
));
stats
(
sync_error
);
}
else
if
(
cd
->
intr_ds
&
ds_toc_ready
)
{
/* do something appropriate */
}
/* couldn't see why this interrupt, maybe due to init */
else
{
outw
(
dc_normal
|
READ_AHEAD
,
r_data_control
);
stats
(
lost_intr
);
}
cd
->
intr_ds
=
inw
(
r_data_status
);
/* resets data_ready, data_error,
crc_error, sync_error, toc_ready
interrupts */
cd
->
intr_ls
=
inw
(
r_line_status
);
/* resets overrun bit */
if
(
cd
->
intr_ls
&
ls_attention
)
stats
(
attention
);
/* receive buffer full? */
if
(
cd
->
intr_ls
&
ls_receive_buffer_full
)
{
cd
->
intr_ur
=
inb
(
r_uart_receive
);
/* get order right! */
cd
->
intr_ls
=
inw
(
r_line_status
);
/* resets rbf interrupt */
if
(
!
cd
->
background
&&
cd
->
uart
)
wake_up_interruptible
(
&
cd
->
uart
);
}
/* data ready in fifo? */
else
if
(
cd
->
intr_ds
&
ds_data_ready
)
{
if
(
cd
->
background
)
++
cd
->
adapter_last
;
if
((
cd
->
wait_back
||
!
cd
->
background
)
&&
cd
->
data
)
wake_up_interruptible
(
&
cd
->
data
);
stats
(
data_ready
);
}
/* ready to issue a write command? */
else
if
(
cd
->
command
&&
cd
->
intr_ls
&
ls_transmitter_buffer_empty
)
{
outw
(
dc_normal
|
(
inw
(
r_data_status
)
&
0x7f
),
r_data_control
);
outw
(
cd
->
command
,
r_uart_transmit
);
cd
->
command
=
0
;
if
(
!
cd
->
background
)
wake_up_interruptible
(
&
cd
->
uart
);
}
/* now treat errors (at least, identify them for debugging) */
else
if
(
cd
->
intr_ds
&
ds_fifo_overflow
)
{
debug
((
"Fifo overflow at sectors 0x%x
\n
"
,
cd
->
sector_first
));
fool
=
inw
(
r_fifo_output_buffer
);
/* de-assert the interrupt */
cd
->
fifo_overflowed
=
1
;
/* signal one word less should be read */
stats
(
fifo_overflow
);
}
else
if
(
cd
->
intr_ds
&
ds_data_error
)
{
debug
((
"Data error at sector 0x%x
\n
"
,
cd
->
sector_first
));
stats
(
data_error
);
}
else
if
(
cd
->
intr_ds
&
ds_crc_error
)
{
debug
((
"CRC error at sector 0x%x
\n
"
,
cd
->
sector_first
));
stats
(
crc_error
);
}
else
if
(
cd
->
intr_ds
&
ds_sync_error
)
{
debug
((
"Sync at sector 0x%x
\n
"
,
cd
->
sector_first
));
stats
(
sync_error
);
}
else
if
(
cd
->
intr_ds
&
ds_toc_ready
)
{
/* do something appropiate */
}
/* couldn't see why this interrupt, maybe due to init */
else
{
outw
(
dc_normal
|
READ_AHEAD
,
r_data_control
);
stats
(
lost_intr
);
}
if
(
cd
->
background
&&
(
cd
->
adapter_last
-
cd
->
adapter_first
==
cd
->
max_sectors
||
cd
->
fifo_overflowed
))
||
cd
->
fifo_overflowed
))
mark_bh
(
CM206_BH
);
/* issue a stop read command */
stats
(
interrupt
);
}
...
...
@@ -446,6 +474,20 @@ int read_background(int start, int reading)
return
0
;
}
#ifdef USE_INSW
#define transport_data insw
#else
/* this routine implements insw(,,). There was a time i had the
impression that there would be any difference in error-behaviour. */
void
transport_data
(
int
port
,
ush
*
dest
,
int
count
)
{
int
i
;
ush
*
d
;
for
(
i
=
0
,
d
=
dest
;
i
<
count
;
i
++
,
d
++
)
*
d
=
inw
(
port
);
}
#endif
int
read_sector
(
int
start
)
{
if
(
cd
->
background
)
{
...
...
@@ -462,7 +504,8 @@ int read_sector(int start)
stop_read
();
return
-
3
;
}
insw
(
r_fifo_output_buffer
,
cd
->
sector
,
READ_AHEAD
*
RAW_SECTOR_SIZE
/
2
);
transport_data
(
r_fifo_output_buffer
,
cd
->
sector
,
READ_AHEAD
*
RAW_SECTOR_SIZE
/
2
);
if
(
read_background
(
start
+
READ_AHEAD
,
1
))
stats
(
read_background
);
cd
->
sector_first
=
start
;
cd
->
sector_last
=
start
+
READ_AHEAD
;
stats
(
read_restarted
);
...
...
@@ -514,12 +557,18 @@ void cm206_bh(void)
}
}
/* This command clears the dsb_possible_media_change flag, so we must
* retain it.
*/
void
get_drive_status
(
void
)
{
uch
status
[
2
];
type_1_command
(
c_drive_status
,
2
,
status
);
/* this might be done faster */
cd
->
dsb
=
status
[
0
];
cd
->
cc
=
status
[
1
];
cd
->
media_changed
|=
!!
(
cd
->
dsb
&
(
dsb_possible_media_change
|
dsb_drive_not_ready
|
dsb_tray_not_closed
));
}
void
get_disc_status
(
void
)
...
...
@@ -529,55 +578,30 @@ void get_disc_status(void)
}
}
static
int
cm206_open
(
struct
inode
*
ip
,
struct
file
*
fp
)
/* The new open. The real opeining strategy is defined in cdrom.c. */
static
int
cm206_open
(
dev_t
dev
,
int
purpose
)
{
if
(
!
cd
->
openfiles
)
{
if
(
!
cd
->
openfiles
)
{
/* reset only first time */
cd
->
background
=
0
;
reset_cm260
();
cd
->
adapter_last
=
-
1
;
/* invalidate adapter memory */
cd
->
sector_last
=
-
1
;
get_drive_status
();
if
(
cd
->
dsb
&
dsb_tray_not_closed
)
{
int
i
=
0
;
type_0_command
(
c_close_tray
,
1
);
while
(
i
++<
10
&&
cd
->
dsb
&
dsb_drive_not_ready
)
{
cm206_delay
(
100
);
get_drive_status
();
}
}
if
(
cd
->
dsb
&
(
dsb_not_useful
))
return
-
EIO
;
if
(
!
(
cd
->
dsb
&
dsb_disc_present
))
return
-
ENODATA
;
if
(
cd
->
dsb
&
dsb_possible_media_change
)
{
memset
(
cd
->
toc
,
0
,
sizeof
(
cd
->
toc
));
memset
(
cd
->
audio_status
,
0
,
sizeof
(
cd
->
audio_status
));
}
get_disc_status
();
type_0_command
(
c_lock_tray
,
1
);
if
(
!
(
cd
->
dsb
&
dsb_tray_locked
))
{
debug
((
"Couldn't lock tray
\n
"
));
}
#if 0
if (!(DISC_STATUS & cds_all_audio))
read_background(16,0); /* do something useful */
#endif
}
++
cd
->
openfiles
;
MOD_INC_USE_COUNT
;
stats
(
open
);
return
0
;
}
static
void
cm206_release
(
struct
inode
*
ip
,
struct
file
*
fp
)
static
void
cm206_release
(
dev_t
dev
)
{
if
(
cd
->
openfiles
==
1
)
{
if
(
cd
->
background
)
{
cd
->
background
=
0
;
stop_read
();
}
type_0_command
(
c_unlock_tray
,
1
);
cd
->
sector_last
=
-
1
;
/* Make our internal buffer invalid */
FIRST_TRACK
=
0
;
/* No valid disc status */
sync_dev
(
ip
->
i_rdev
);
/* These two lines are stolen */
invalidate_buffers
(
ip
->
i_rdev
);
FIRST_TRACK
=
0
;
/* No valid disc status */
}
--
cd
->
openfiles
;
MOD_DEC_USE_COUNT
;
}
...
...
@@ -587,7 +611,7 @@ static void cm206_release(struct inode *ip, struct file *fp)
void
empty_buffer
(
int
sectors
)
{
while
(
sectors
>=
0
)
{
insw
(
r_fifo_output_buffer
,
cd
->
sector
+
cd
->
fifo_overflowed
,
transport_data
(
r_fifo_output_buffer
,
cd
->
sector
+
cd
->
fifo_overflowed
,
RAW_SECTOR_SIZE
/
2
-
cd
->
fifo_overflowed
);
--
sectors
;
++
cd
->
adapter_first
;
/* update the current adapter sector */
...
...
@@ -598,7 +622,7 @@ void empty_buffer(int sectors)
cd
->
sector_last
=
cd
->
adapter_first
;
/* update the buffer sector */
}
/* try_adapter. This function determines
o
f the requested sector is is
/* try_adapter. This function determines
i
f the requested sector is is
in adapter memory, or will appear there soon. Returns 0 upon
success */
int
try_adapter
(
int
sector
)
...
...
@@ -648,18 +672,18 @@ static void do_cm206_request(void)
}
error
=
0
;
for
(
i
=
0
;
i
<
CURRENT
->
nr_sectors
;
i
++
)
{
cd_sec_no
=
(
CURRENT
->
sector
+
i
)
/
4
;
/* 4 times 512 bytes */
quarter
=
(
CURRENT
->
sector
+
i
)
%
4
;
dest
=
CURRENT
->
buffer
+
i
*
512
;
cd_sec_no
=
(
CURRENT
->
sector
+
i
)
/
BLOCKS_ISO
;
/* 4 times 512 bytes */
quarter
=
(
CURRENT
->
sector
+
i
)
%
BLOCKS_ISO
;
dest
=
CURRENT
->
buffer
+
i
*
LINUX_BLOCK_SIZE
;
/* is already in buffer memory? */
if
(
cd
->
sector_first
<=
cd_sec_no
&&
cd_sec_no
<
cd
->
sector_last
)
{
source
=
((
uch
*
)
cd
->
sector
)
+
16
+
quarter
*
512
+
(
cd_sec_no
-
cd
->
sector_first
)
*
RAW_SECTOR_SIZE
;
memcpy
(
dest
,
source
,
512
);
source
=
((
uch
*
)
cd
->
sector
)
+
16
+
quarter
*
LINUX_BLOCK_SIZE
+
(
cd_sec_no
-
cd
->
sector_first
)
*
RAW_SECTOR_SIZE
;
memcpy
(
dest
,
source
,
LINUX_BLOCK_SIZE
);
}
else
if
(
!
try_adapter
(
cd_sec_no
)
||
!
read_sector
(
cd_sec_no
))
{
source
=
((
uch
*
)
cd
->
sector
)
+
16
+
quarter
*
512
;
memcpy
(
dest
,
source
,
512
);
source
=
((
uch
*
)
cd
->
sector
)
+
16
+
quarter
*
LINUX_BLOCK_SIZE
;
memcpy
(
dest
,
source
,
LINUX_BLOCK_SIZE
);
}
else
{
error
=
1
;
...
...
@@ -669,27 +693,6 @@ static void do_cm206_request(void)
}
}
int
get_multi_session_info
(
struct
cdrom_multisession
*
mssp
)
{
if
(
!
FIRST_TRACK
)
get_disc_status
();
if
(
mssp
)
{
if
(
DISC_STATUS
&
cds_multi_session
)
{
/* multi-session */
if
(
mssp
->
addr_format
==
CDROM_LBA
)
mssp
->
addr
.
lba
=
fsm2lba
(
&
cd
->
disc_status
[
3
]);
else
{
mssp
->
addr
.
msf
.
frame
=
cd
->
disc_status
[
3
];
mssp
->
addr
.
msf
.
second
=
cd
->
disc_status
[
4
];
mssp
->
addr
.
msf
.
minute
=
cd
->
disc_status
[
5
];
}
mssp
->
xa_flag
=
1
;
}
else
{
mssp
->
xa_flag
=
0
;
}
return
1
;
}
return
0
;
}
/* Audio support. I've tried very hard, but the cm206 drive doesn't
seem to have a get_toc (table-of-contents) function, while i'm
pretty sure it must read the toc upon disc insertion. Therefore
...
...
@@ -753,11 +756,6 @@ int get_toc_lba(uch track)
cd
->
toc
[
ct
].
track
=
q
[
1
];
/* lead out still 0xaa */
fsm
(
l
,
cd
->
toc
[
ct
].
fsm
);
cd
->
toc
[
ct
].
q0
=
q
[
0
];
/* contains adr and ctrl info */
/*
if (ct==LAST_TRACK+1)
printk("Leadout %x %x %x %x %d %d %d \n", q[1], q[3], q[4], q[5],
q[7], q[8], q[9]);
*/
if
(
ct
==
track
)
return
l
;
}
old_lba
=
lba
;
...
...
@@ -782,6 +780,7 @@ void update_toc_entry(uch track)
if
(
!
cd
->
toc
[
track
].
track
)
get_toc_lba
(
track
);
}
/* return 0 upon success */
int
read_toc_header
(
struct
cdrom_tochdr
*
hp
)
{
if
(
!
FIRST_TRACK
)
get_disc_status
();
...
...
@@ -792,9 +791,9 @@ int read_toc_header(struct cdrom_tochdr * hp)
cd
->
toc
[
1
].
track
=
1
;
/* fill in first track position */
for
(
i
=
0
;
i
<
3
;
i
++
)
cd
->
toc
[
1
].
fsm
[
i
]
=
cd
->
disc_status
[
3
+
i
];
update_toc_entry
(
LAST_TRACK
+
1
);
/* find most entries */
return
1
;
return
0
;
}
return
0
;
return
-
1
;
}
void
play_from_to_msf
(
struct
cdrom_msf
*
msfp
)
...
...
@@ -859,120 +858,54 @@ int get_current_q(struct cdrom_subchnl * qp)
else
if
(
PAUSED
)
qp
->
cdsc_audiostatus
=
CDROM_AUDIO_PAUSED
;
else
qp
->
cdsc_audiostatus
=
CDROM_AUDIO_NO_STATUS
;
return
1
;
return
0
;
}
void
invalidate_toc
(
void
)
{
memset
(
cd
->
toc
,
0
,
sizeof
(
cd
->
toc
));
memset
(
cd
->
disc_status
,
0
,
sizeof
(
cd
->
disc_status
));
}
/* cdrom.c guarantees that cdte_format == CDROM_MSF */
void
get_toc_entry
(
struct
cdrom_tocentry
*
ep
)
{
uch
track
=
normalize_track
(
ep
->
cdte_track
);
update_toc_entry
(
track
);
if
(
ep
->
cdte_format
==
CDROM_MSF
)
{
ep
->
cdte_addr
.
msf
.
frame
=
cd
->
toc
[
track
].
fsm
[
0
];
ep
->
cdte_addr
.
msf
.
second
=
cd
->
toc
[
track
].
fsm
[
1
];
ep
->
cdte_addr
.
msf
.
minute
=
cd
->
toc
[
track
].
fsm
[
2
];
}
else
ep
->
cdte_addr
.
lba
=
fsm2lba
(
cd
->
toc
[
track
].
fsm
);
ep
->
cdte_addr
.
msf
.
frame
=
cd
->
toc
[
track
].
fsm
[
0
];
ep
->
cdte_addr
.
msf
.
second
=
cd
->
toc
[
track
].
fsm
[
1
];
ep
->
cdte_addr
.
msf
.
minute
=
cd
->
toc
[
track
].
fsm
[
2
];
ep
->
cdte_adr
=
cd
->
toc
[
track
].
q0
&
0xf
;
ep
->
cdte_ctrl
=
cd
->
toc
[
track
].
q0
>>
4
;
ep
->
cdte_datamode
=
0
;
}
/* Ioctl. I have made the statistics accessible through an ioctl
call. The constant is defined in cm206.h, it shouldn't clash with
the standard Linux ioctls. Multisession info is gathered at
run-time, this may turn out to be slow. */
static
int
cm206_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
/* Audio ioctl. Ioctl commands connected to audio are in such an
* idiosyncratic i/o format, that we leave these untouched. Return 0
* upon success. Memory checking has been done by cdrom_ioctl(), the
* calling function, as well as LBA/MSF sanatization.
*/
int
cm206_audio_ioctl
(
dev_t
dev
,
unsigned
int
cmd
,
void
*
arg
)
{
switch
(
cmd
)
{
#ifdef STATISTICS
case
CM206CTL_GET_STAT
:
if
(
arg
>=
NR_STATS
)
return
-
EINVAL
;
else
return
cd
->
stats
[
arg
];
case
CM206CTL_GET_LAST_STAT
:
if
(
arg
>=
NR_STATS
)
return
-
EINVAL
;
else
return
cd
->
last_stat
[
arg
];
#endif
case
CDROMMULTISESSION
:
{
struct
cdrom_multisession
ms_info
;
int
st
;
stats
(
ioctl_multisession
);
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_multisession
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
ms_info
,
(
struct
cdrom_multisession
*
)
arg
,
sizeof
(
struct
cdrom_multisession
));
get_multi_session_info
(
&
ms_info
);
memcpy_tofs
((
struct
cdrom_multisession
*
)
arg
,
&
ms_info
,
sizeof
(
struct
cdrom_multisession
));
return
0
;
}
case
CDROMRESET
:
/* If needed, it's probably too late anyway */
stop_read
();
reset_cm260
();
outw
(
dc_normal
|
dc_break
|
READ_AHEAD
,
r_data_control
);
udelay
(
1000
);
/* 750 musec minimum */
outw
(
dc_normal
|
READ_AHEAD
,
r_data_control
);
cd
->
sector_last
=
-
1
;
/* flag no data buffered */
cd
->
adapter_last
=
-
1
;
return
0
;
}
get_drive_status
();
if
(
cd
->
dsb
&
(
dsb_drive_not_ready
|
dsb_tray_not_closed
)
)
return
-
EAGAIN
;
switch
(
cmd
)
{
case
CDROMREADTOCHDR
:
{
struct
cdrom_tochdr
header
;
int
st
;
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
header
));
if
(
st
)
return
(
st
);
if
(
read_toc_header
(
&
header
))
{
memcpy_tofs
((
struct
cdrom_tochdr
*
)
arg
,
&
header
,
sizeof
(
header
));
return
0
;
}
else
return
-
ENODATA
;
}
case
CDROMREADTOCENTRY
:
{
struct
cdrom_tocentry
entry
;
int
st
;
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
entry
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
entry
,
(
struct
cdrom_tocentry
*
)
arg
,
sizeof
entry
);
get_toc_entry
(
&
entry
);
memcpy_tofs
((
struct
cdrom_tocentry
*
)
arg
,
&
entry
,
sizeof
entry
);
case
CDROMREADTOCHDR
:
return
read_toc_header
((
struct
cdrom_tochdr
*
)
arg
);
case
CDROMREADTOCENTRY
:
get_toc_entry
((
struct
cdrom_tocentry
*
)
arg
);
return
0
;
}
case
CDROMPLAYMSF
:
{
struct
cdrom_msf
msf
;
int
st
;
st
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
msf
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
msf
,
(
struct
cdrom_mdf
*
)
arg
,
sizeof
msf
);
play_from_to_msf
(
&
msf
);
case
CDROMPLAYMSF
:
play_from_to_msf
((
struct
cdrom_msf
*
)
arg
);
return
0
;
}
case
CDROMPLAYTRKIND
:
{
struct
cdrom_ti
track_index
;
int
st
;
st
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
track_index
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
track_index
,
(
struct
cdrom_ti
*
)
arg
,
sizeof
(
track_index
));
play_from_to_track
(
track_index
.
cdti_trk0
,
track_index
.
cdti_trk1
);
case
CDROMPLAYTRKIND
:
/* admittedly, not particulary beautiful */
play_from_to_track
(((
struct
cdrom_ti
*
)
arg
)
->
cdti_trk0
,
((
struct
cdrom_ti
*
)
arg
)
->
cdti_trk1
);
return
0
;
}
case
CDROMSTOP
:
PAUSED
=
0
;
if
(
cd
->
dsb
&
dsb_play_in_progress
)
return
type_0_command
(
c_stop
,
1
);
return
0
;
else
return
0
;
case
CDROMPAUSE
:
get_drive_status
();
if
(
cd
->
dsb
&
dsb_play_in_progress
)
{
type_0_command
(
c_stop
,
1
);
type_1_command
(
c_audio_status
,
5
,
cd
->
audio_status
);
...
...
@@ -983,62 +916,181 @@ static int cm206_ioctl(struct inode * inode, struct file * file,
if
(
PAUSED
)
play_from_to_track
(
0
,
0
);
PAUSED
=
0
;
return
0
;
case
CDROMEJECT
:
PAUSED
=
0
;
if
(
cd
->
openfiles
==
1
)
{
/* Must do an open before an eject! */
type_0_command
(
c_open_tray
,
1
);
memset
(
cd
->
toc
,
0
,
sizeof
(
cd
->
toc
));
memset
(
cd
->
disc_status
,
0
,
sizeof
(
cd
->
disc_status
));
return
0
;
}
else
return
-
EBUSY
;
case
CDROMSTART
:
case
CDROMVOLCTRL
:
return
0
;
case
CDROMSUBCHNL
:
{
struct
cdrom_subchnl
q
;
int
st
;
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
q
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
q
,
(
struct
cdrom_subchnl
*
)
arg
,
sizeof
q
);
if
(
get_current_q
(
&
q
))
{
memcpy_tofs
((
struct
cdrom_subchnl
*
)
arg
,
&
q
,
sizeof
q
);
return
0
;
}
else
return
-
cmd
;
case
CDROMSUBCHNL
:
return
get_current_q
((
struct
cdrom_subchnl
*
)
arg
);
default:
return
-
EINVAL
;
}
case
CDROM_GET_UPC
:
{
uch
upc
[
10
];
int
st
;
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
8
);
if
(
st
)
return
(
st
);
if
(
type_1_command
(
c_read_upc
,
10
,
upc
))
return
-
EIO
;
memcpy_tofs
((
uch
*
)
arg
,
&
upc
[
1
],
8
);
return
0
;
}
}
/* Ioctl. These ioctls are specific to the cm206 driver. I have made
some driver statistics accessible through ioctl calls.
*/
static
int
cm206_ioctl
(
dev_t
dev
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
switch
(
cmd
)
{
#ifdef STATISTICS
case
CM206CTL_GET_STAT
:
if
(
arg
>=
NR_STATS
)
return
-
EINVAL
;
else
return
cd
->
stats
[
arg
];
case
CM206CTL_GET_LAST_STAT
:
if
(
arg
>=
NR_STATS
)
return
-
EINVAL
;
else
return
cd
->
last_stat
[
arg
];
#endif
default:
debug
((
"Unknown ioctl call 0x%x
\n
"
,
cmd
));
return
-
EINVAL
;
}
}
/* from lmscd.c */
static
struct
file_operations
cm206_fops
=
{
NULL
,
/* lseek */
block_read
,
/* read - general block-dev read */
block_write
,
/* write - general block-dev write */
NULL
,
/* readdir */
NULL
,
/* select */
cm206_ioctl
,
/* ioctl */
NULL
,
/* mmap */
cm206_open
,
/* open */
cm206_release
,
/* release */
NULL
,
/* fsync */
NULL
,
/* fasync */
NULL
,
/* media_change */
NULL
/* revalidate */
int
cm206_media_changed
(
dev_t
dev
)
{
if
(
cd
!=
NULL
)
{
int
r
;
get_drive_status
();
/* ensure cd->media_changed OK */
r
=
cd
->
media_changed
;
cd
->
media_changed
=
0
;
/* clear bit */
return
r
;
}
else
return
-
EIO
;
}
/* The new generic cdrom support. Routines should be consice, most of
the logic should be in cdrom.c */
/* returns number of times device is in use */
int
cm206_open_files
(
dev_t
dev
)
{
if
(
cd
)
return
cd
->
openfiles
;
return
-
1
;
}
/* controls tray movement */
int
cm206_tray_move
(
dev_t
dev
,
int
position
)
{
if
(
position
)
{
/* 1: eject */
type_0_command
(
c_open_tray
,
1
);
invalidate_toc
();
}
else
type_0_command
(
c_close_tray
,
1
);
/* 0: close */
return
0
;
}
/* gives current state of the drive */
int
cm206_drive_status
(
dev_t
dev
)
{
get_drive_status
();
if
(
cd
->
dsb
&
dsb_tray_not_closed
)
return
CDS_TRAY_OPEN
;
if
(
!
(
cd
->
dsb
&
dsb_disc_present
))
return
CDS_NO_DISC
;
if
(
cd
->
dsb
&
dsb_drive_not_ready
)
return
CDS_DRIVE_NOT_READY
;
return
CDS_DISC_OK
;
}
/* gives current state of disc in drive */
int
cm206_disc_status
(
dev_t
dev
)
{
uch
xa
;
get_drive_status
();
if
((
cd
->
dsb
&
dsb_not_useful
)
|
!
(
cd
->
dsb
&
dsb_disc_present
))
return
CDS_NO_DISC
;
get_disc_status
();
if
(
DISC_STATUS
&
cds_all_audio
)
return
CDS_AUDIO
;
xa
=
DISC_STATUS
>>
4
;
switch
(
xa
)
{
case
0
:
return
CDS_DATA_1
;
/* can we detect CDS_DATA_2? */
case
1
:
return
CDS_XA_2_1
;
/* untested */
case
2
:
return
CDS_XA_2_2
;
}
return
0
;
}
/* locks or unlocks door lock==1: lock; return 0 upon success */
int
cm206_lock_door
(
dev_t
dev
,
int
lock
)
{
uch
command
=
(
lock
)
?
c_lock_tray
:
c_unlock_tray
;
type_0_command
(
command
,
1
);
/* wait and get dsb */
/* the logic calculates the success, 0 means successful */
return
lock
^
((
cd
->
dsb
&
dsb_tray_locked
)
!=
0
);
}
/* 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
)
{
if
(
!
FIRST_TRACK
)
get_disc_status
();
if
(
mssp
!=
NULL
)
{
if
(
DISC_STATUS
&
cds_multi_session
)
{
/* multi-session */
mssp
->
addr
.
msf
.
frame
=
cd
->
disc_status
[
3
];
mssp
->
addr
.
msf
.
second
=
cd
->
disc_status
[
4
];
mssp
->
addr
.
msf
.
minute
=
cd
->
disc_status
[
5
];
mssp
->
addr_format
=
CDROM_MSF
;
mssp
->
xa_flag
=
1
;
}
else
{
mssp
->
xa_flag
=
0
;
}
return
1
;
}
return
0
;
}
int
cm206_get_upc
(
dev_t
dev
,
struct
cdrom_mcn
*
mcn
)
{
uch
upc
[
10
];
char
*
ret
=
mcn
->
medium_catalog_number
;
int
i
;
if
(
type_1_command
(
c_read_upc
,
10
,
upc
))
return
-
EIO
;
for
(
i
=
0
;
i
<
13
;
i
++
)
{
int
w
=
i
/
2
+
1
,
r
=
i
%
2
;
if
(
r
)
ret
[
i
]
=
0x30
|
(
upc
[
w
]
&
0x0f
);
else
ret
[
i
]
=
0x30
|
((
upc
[
w
]
>>
4
)
&
0x0f
);
}
ret
[
13
]
=
'\0'
;
return
0
;
}
int
cm206_reset
(
dev_t
dev
)
{
stop_read
();
reset_cm260
();
outw
(
dc_normal
|
dc_break
|
READ_AHEAD
,
r_data_control
);
udelay
(
1000
);
/* 750 musec minimum */
outw
(
dc_normal
|
READ_AHEAD
,
r_data_control
);
cd
->
sector_last
=
-
1
;
/* flag no data buffered */
cd
->
adapter_last
=
-
1
;
invalidate_toc
();
return
0
;
}
static
struct
cdrom_device_ops
cm206_dops
=
{
cm206_open
,
/* open */
cm206_release
,
/* release */
cm206_open_files
,
/* number of open_files */
cm206_drive_status
,
/* drive status */
cm206_disc_status
,
/* disc status */
cm206_media_changed
,
/* media changed */
cm206_tray_move
,
/* tray move */
cm206_lock_door
,
/* lock door */
NULL
,
/* select speed */
NULL
,
/* select disc */
cm206_get_last_session
,
/* get last session */
cm206_get_upc
,
/* get universal product code */
cm206_reset
,
/* hard reset */
cm206_audio_ioctl
,
/* audio ioctl */
cm206_ioctl
,
/* device-specific ioctl */
CDC_CLOSE_TRAY
|
CDC_OPEN_TRAY
|
CDC_LOCK
|
CDC_MULTI_SESSION
|
CDC_MEDIA_CHANGED
|
CDC_MCN
|
CDC_PLAY_AUDIO
,
/* capability */
0
,
/* mask flags */
2
.
0
,
/* maximum speed */
1
,
/* number of minor devices */
1
,
/* number of discs */
0
,
/* options, ignored */
0
/* mc_flags, ignored */
};
/* This routine gets called during init if thing go wrong, can be used
...
...
@@ -1047,8 +1099,12 @@ void cleanup(int level)
{
switch
(
level
)
{
case
4
:
if
(
unregister_cdrom
(
MAJOR_NR
,
"cm206"
))
{
printk
(
"Can't unregister cdrom cm206
\n
"
);
return
;
}
if
(
unregister_blkdev
(
MAJOR_NR
,
"cm206"
))
{
printk
(
"Can't unregister cm206
\n
"
);
printk
(
"Can't unregister
major
cm206
\n
"
);
return
;
}
case
3
:
...
...
@@ -1074,25 +1130,16 @@ void cleanup(int level)
int
probe_base_port
(
int
base
)
{
int
b
=
0x300
,
e
=
0x370
;
/* this is the range of start addresses */
volatile
int
fool
;
#if 0
const pattern1=0x65, pattern2=0x1a;
#endif
volatile
int
fool
,
i
;
if
(
base
)
b
=
e
=
base
;
for
(
base
=
b
;
base
<=
e
;
base
+=
0x10
)
{
if
(
check_region
(
base
,
0x10
))
continue
;
fool
=
inw
(
base
+
2
);
/* empty possibly uart_receive_buffer */
for
(
i
=
0
;
i
<
3
;
i
++
)
fool
=
inw
(
base
+
2
);
/* empty possibly uart_receive_buffer */
if
((
inw
(
base
+
6
)
&
0xffef
)
!=
0x0001
||
/* line_status */
(
inw
(
base
)
&
0xad00
)
!=
0
)
/* data status */
continue
;
#if 0 /* writes... dangerous... */
outw(dc_normal | pattern1, base+8);
if ((inw(base) & 0x7f) != pattern1) continue;
outw(dc_normal | pattern2, base+8);
if ((inw(base) & 0x7f) != pattern2) continue;
outw(dc_normal | READ_AHEAD, base+8);
#endif
return
(
base
);
}
return
0
;
...
...
@@ -1106,7 +1153,7 @@ int probe_irq(int nr) {
sti
();
irqs
=
probe_irq_on
();
reset_cm260
();
/* causes interrupt */
udelay
(
10
);
/* wait for it */
udelay
(
10
0
);
/* wait for it */
irq
=
probe_irq_off
(
irqs
);
outw
(
dc_normal
|
READ_AHEAD
,
r_data_control
);
/* services interrupt */
if
(
nr
&&
irq
!=
nr
&&
irq
>
0
)
return
0
;
/* wrong interrupt happened */
...
...
@@ -1119,7 +1166,7 @@ int cm206_init(void)
uch
e
=
0
;
long
int
size
=
sizeof
(
struct
cm206_struct
);
printk
(
KERN_INFO
"cm206: v"
VERSION
);
printk
(
KERN_INFO
VERSION
);
cm206_base
=
probe_base_port
(
auto_probe
?
0
:
cm206_base
);
if
(
!
cm206_base
)
{
printk
(
" can't find adapter!
\n
"
);
...
...
@@ -1162,11 +1209,16 @@ int cm206_init(void)
return
-
EIO
;
}
printk
(
".
\n
"
);
if
(
register_blkdev
(
MAJOR_NR
,
"cm206"
,
&
c
m206
_fops
)
!=
0
)
{
if
(
register_blkdev
(
MAJOR_NR
,
"cm206"
,
&
c
drom
_fops
)
!=
0
)
{
printk
(
"Cannot register for major %d!
\n
"
,
MAJOR_NR
);
cleanup
(
3
);
return
-
EIO
;
}
if
(
register_cdrom
(
MAJOR_NR
,
"cm206"
,
&
cm206_dops
)
!=
0
)
{
printk
(
"Cannot register for cdrom %d!
\n
"
,
MAJOR_NR
);
cleanup
(
3
);
return
-
EIO
;
}
blk_dev
[
MAJOR_NR
].
request_fn
=
DEVICE_REQUEST
;
read_ahead
[
MAJOR_NR
]
=
16
;
/* reads ahead what? */
init_bh
(
CM206_BH
,
cm206_bh
);
...
...
@@ -1235,3 +1287,8 @@ void cm206_setup(char *s, int *p)
}
}
#endif
/* MODULE */
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/include/linux -Wall -Wstrict-prototypes -O2 -m486 -c cm206.c -o cm206.o"
* End:
*/
drivers/char/random.c
View file @
0351166f
...
...
@@ -879,8 +879,8 @@ static inline int extract_entropy(struct random_bucket *r, char * buf,
HASH_TRANSFORM
(
tmp
,
r
->
pool
);
/*
* In case the hash function has some recogniz
e
able
* output pattern, we fold it half.
* In case the hash function has some recognizable
* output pattern, we fold it
in
half.
*/
cp
=
(
char
*
)
tmp
;
dp
=
cp
+
(
HASH_BUFFER_SIZE
*
sizeof
(
__u32
))
-
1
;
...
...
drivers/char/rtc.c
View file @
0351166f
...
...
@@ -762,7 +762,7 @@ void get_rtc_alm_time(struct rtc_time *alm_tm)
* ensure you actually start getting interrupts. Probably for
* compatibility with older/broken chipset RTC implementations.
* We also clear out any old irq data after an ioctl() that
* meddles the interrupt enable/disable bits.
* meddles
with
the interrupt enable/disable bits.
*/
void
mask_rtc_irq_bit
(
unsigned
char
bit
)
{
...
...
drivers/net/hydra.c
View file @
0351166f
...
...
@@ -7,8 +7,8 @@
/* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) */
/* This file is subject to the terms and conditions of the GNU General */
/* Public License. See the file
README.legal in the main directory of the
*/
/* Linux
/68k distribution for more details.
*/
/* Public License. See the file
COPYING in the main directory of the
*/
/* Linux
distribution for more details.
*/
/* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a */
/* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM */
...
...
@@ -100,9 +100,9 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
#endif
/* this is now coherent
to
the C version below, */
/* compile the source with -D__USE_ASM__ if you */
/* want it - it'll only be some 10% faster thou */
/* this is now coherent
with
the C version below, */
/* compile the source with -D__USE_ASM__ if you
*/
/* want it - it'll only be some 10% faster thou
gh
*/
#if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
...
...
drivers/net/lance.c
View file @
0351166f
...
...
@@ -165,6 +165,9 @@ tx_full and tbusy flags.
* - added support for Linux/Alpha, but removed most of it, because
* it worked only for the PCI chip.
* - added hook for the 32bit lance driver
*
* Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
* - hopefully fix above so Linux/Alpha can use ISA cards too.
*/
/* Set the number of Tx and Rx buffers, using Log_2(# buffers).
...
...
@@ -298,9 +301,7 @@ static void set_multicast_list(struct device *dev);
int
lance_init
(
void
)
{
#ifndef __alpha__
int
*
port
;
#endif
if
(
high_memory
<=
16
*
1024
*
1024
)
lance_need_isa_bounce_buffers
=
0
;
...
...
@@ -344,8 +345,6 @@ int lance_init(void)
}
#endif
/* defined(CONFIG_PCI) */
/* On the Alpha don't look for PCnet chips on the ISA bus */
#ifndef __alpha__
for
(
port
=
lance_portlist
;
*
port
;
port
++
)
{
int
ioaddr
=
*
port
;
...
...
@@ -359,8 +358,6 @@ int lance_init(void)
lance_probe1
(
ioaddr
);
}
}
#endif
return
0
;
}
...
...
@@ -376,15 +373,14 @@ void lance_probe1(int ioaddr)
int
hp_builtin
=
0
;
/* HP on-board ethernet. */
static
int
did_version
=
0
;
/* Already printed version info. */
#ifndef __alpha__
/* First we look for special cases.
Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
There are two HP versions, check the BIOS for the configuration port.
This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com.
*/
if
(
*
((
unsigned
short
*
)
0x000f0102
)
==
0x5048
)
{
if
(
readw
(
0x000f0102
)
==
0x5048
)
{
static
const
short
ioaddr_table
[]
=
{
0x300
,
0x320
,
0x340
,
0x360
};
int
hp_port
=
(
*
((
unsigned
char
*
)
0x000f00f1
)
&
1
)
?
0x499
:
0x99
;
int
hp_port
=
(
readl
(
0x000f00f1
)
&
1
)
?
0x499
:
0x99
;
/* We can have boards other than the built-in! Verify this is on-board. */
if
((
inb
(
hp_port
)
&
0xc0
)
==
0x80
&&
ioaddr_table
[
inb
(
hp_port
)
&
3
]
==
ioaddr
)
...
...
@@ -393,7 +389,6 @@ void lance_probe1(int ioaddr)
/* We also recognize the HP Vectra on-board here, but check below. */
hpJ2405A
=
(
inb
(
ioaddr
)
==
0x08
&&
inb
(
ioaddr
+
1
)
==
0x00
&&
inb
(
ioaddr
+
2
)
==
0x09
);
#endif
/* Reset the LANCE. */
reset_val
=
inw
(
ioaddr
+
LANCE_RESET
);
/* Reset the LANCE */
...
...
fs/affs/inode.c
View file @
0351166f
...
...
@@ -308,7 +308,7 @@ affs_read_super(struct super_block *s,void *data, int silent)
s
->
u
.
affs_sb
.
s_partition_size
=
size
;
s
->
u
.
affs_sb
.
s_reserved
=
reserved
;
/* Try to find root block. It
'
s location may depend on the block size. */
/* Try to find root block. Its location may depend on the block size. */
s
->
u
.
affs_sb
.
s_hashsize
=
0
;
if
(
blocksize
>
0
)
{
...
...
include/linux/cm206.h
View file @
0351166f
...
...
@@ -2,6 +2,9 @@
Copyright (c) 1995 David van Leeuwen
*/
#ifndef LINUX_CM206_H
#define LINUX_CM206_H
/* First, the cm260 stuff */
/* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined
below, the values are not used unless autoprobing is turned off and
...
...
@@ -48,11 +51,12 @@
#define dc_mask_transmit_ready 0x100
#define dc_flag_enable 0x80
/* Define the default data control register flags here */
#define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \
dc_mask_transmit_ready)
/* now some constants related to the cm206 */
/* another drive status byte, echoed by the cm206 on most commands */
/* another drive status byte, echoed by the cm206 on most comm
m
ands */
#define dsb_error_condition 0x1
#define dsb_play_in_progress 0x4
...
...
@@ -126,3 +130,46 @@
#define CM206CTL_GET_STAT 0x2000
#define CM206CTL_GET_LAST_STAT 0x2001
/* for kernel 1.2.n */
#if !defined(CDROM_GET_UPC)
#define CDROM_GET_UPC 0x5311
#define CDROMRESET 0x5312
#endif
#ifdef STATISTICS
/* This is an ugly way to guarantee that the names of the statistics
* are the same in the code and in the diagnostics program. */
#ifdef __KERNEL__
#define x(a) st_ ## a
#define y enum
#else
#define x(a) #a
#define y char * stats_name[] =
#endif
y
{
x
(
interrupt
),
x
(
data_ready
),
x
(
fifo_overflow
),
x
(
data_error
),
x
(
crc_error
),
x
(
sync_error
),
x
(
lost_intr
),
x
(
echo
),
x
(
write_timeout
),
x
(
receive_timeout
),
x
(
read_timeout
),
x
(
dsb_timeout
),
x
(
stop_0xff
),
x
(
back_read_timeout
),
x
(
sector_transferred
),
x
(
read_restarted
),
x
(
read_background
),
x
(
bh
),
x
(
open
),
x
(
ioctl_multisession
),
x
(
attention
)
#ifdef __KERNEL__
,
x
(
last_entry
)
#endif
};
#ifdef __KERNEL__
#define NR_STATS st_last_entry
#else
#define NR_STATS (sizeof(stats_name)/sizeof(char*))
#endif
#undef y
#undef x
#endif STATISTICS
#endif LINUX_CM206_H
include/linux/kerneld.h
View file @
0351166f
...
...
@@ -12,7 +12,7 @@
/*
* Uncomment the following line for the new kerneld protocol
* This includes the pid of the kernel level request
o
r into the kerneld header
* This includes the pid of the kernel level request
e
r into the kerneld header
*/
/*
#define NEW_KERNELD_PROTOCOL
...
...
include/linux/stats206.h
deleted
100644 → 0
View file @
0294f4bd
/* stats206.h. Define constants to gather statistics on the cm206 behavior.
Copyright (c) 1995 David van Leeuwen.
This is published under the Gnu Public Licence, read the header in
the file cm206.c.
*/
/* This is an ugly way to guarantee that the names of the statistics
* are the same in the code and in the diagnostics program. */
#ifdef __KERNEL__
#define x(a) st_ ## a
#define y enum
#else
#define x(a) #a
#define y char * stats_name[] =
#endif
y
{
x
(
interrupt
),
x
(
data_ready
),
x
(
fifo_overflow
),
x
(
data_error
),
x
(
crc_error
),
x
(
sync_error
),
x
(
lost_intr
),
x
(
echo
),
x
(
write_timeout
),
x
(
receive_timeout
),
x
(
read_timeout
),
x
(
dsb_timeout
),
x
(
stop_0xff
),
x
(
back_read_timeout
),
x
(
sector_transferred
),
x
(
read_restarted
),
x
(
read_background
),
x
(
bh
),
x
(
open
),
x
(
ioctl_multisession
)
#ifdef __KERNEL__
,
x
(
last_entry
)
#endif
};
#ifdef __KERNEL__
#define NR_STATS st_last_entry
#else
#define NR_STATS sizeof(stats_name)/sizeof(char*)
#endif
include/linux/ucdrom.h
0 → 100644
View file @
0351166f
/* ucdrom.h. Uniform cdrom data structures for cdrom.c. -*- linux-c -*-
Copyright (c) 1996 David van Leeuwen.
*/
#ifndef LINUX_UCDROM_H
#define LINUX_UCDROM_H
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 */
/* specifications */
const
int
capability
;
/* capability flags */
int
mask
;
/* mask of capability: disables them */
const
float
speed
;
/* maximum speed for reading data */
const
int
minors
;
/* number of minor devs supported */
const
int
capacity
;
/* number of discs in jukebox */
/* device-related storage */
int
options
;
/* options flags */
long
mc_flags
;
/* media change buffer flags (2*16) */
};
/* capability flags */
#define CDC_CLOSE_TRAY 0x1
/* caddy systems _can't_ close */
#define CDC_OPEN_TRAY 0x2
/* but _can_ eject. */
#define CDC_LOCK 0x4
/* disable manual eject */
#define CDC_SELECT_SPEED 0x8
/* programmable speed */
#define CDC_SELECT_DISC 0x10
/* select disc from juke-box */
#define CDC_MULTI_SESSION 0x20
/* read sessions>1 */
#define CDC_MCN 0x40
/* Medium Catalog Number */
#define CDC_MEDIA_CHANGED 0x80
/* media changed */
#define CDC_PLAY_AUDIO 0x100
/* audio functions */
/* drive status possibilities */
#define CDS_NO_INFO 0
/* if not implemented */
#define CDS_NO_DISC 1
#define CDS_TRAY_OPEN 2
#define CDS_DRIVE_NOT_READY 3
#define CDS_DISC_OK 4
/* disc status possibilities, other than CDS_NO_DISC */
#define CDS_AUDIO 100
#define CDS_DATA_1 101
#define CDS_DATA_2 102
#define CDS_XA_2_1 103
#define CDS_XA_2_2 104
/* User-configurable behavior options */
#define CDO_AUTO_CLOSE 0x1
/* close tray on first open() */
#define CDO_AUTO_EJECT 0x2
/* open tray on last release() */
#define CDO_USE_FFLAGS 0x4
/* use O_NONBLOCK information on open */
#define CDO_LOCK 0x8
/* lock tray on open files */
#define CDO_CHECK_TYPE 0x10
/* check type on open for data */
/* Some more ioctls to control these options */
#define CDROM_SET_OPTIONS 0x5320
#define CDROM_CLEAR_OPTIONS 0x5321
#define CDROM_SELECT_SPEED 0x5322
/* head-speed */
#define CDROM_SELECT_DISC 0x5323
/* for juke-boxes */
#define CDROM_MEDIA_CHANGED 0x5325
#define CDROM_DRIVE_STATUS 0x5326
/* tray position, etc. */
#define CDROM_DISC_STATUS 0x5327
/* disc type etc. */
/* Rename and old ioctl */
#define CDROM_GET_MCN CDROM_GET_UPC
/* medium catalog number */
/* 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
/* LINUX_UCDROM_H */
/*
* Local variables:
* comment-column: 40
* End:
*/
include/net/tcp.h
View file @
0351166f
...
...
@@ -211,13 +211,15 @@ static __inline__ int tcp_raise_window(struct sock * sk)
static
__inline__
unsigned
short
tcp_select_window
(
struct
sock
*
sk
)
{
int
window
=
tcp_new_window
(
sk
);
int
oldwin
=
tcp_old_window
(
sk
);
/* Don't allow a shrinking window */
if
(
window
>
tcp_old_window
(
sk
)
)
{
if
(
window
>
oldwin
)
{
sk
->
window
=
window
;
sk
->
lastwin_seq
=
sk
->
acked_seq
;
oldwin
=
window
;
}
return
sk
->
window
;
return
oldwin
;
}
/*
...
...
ipc/msg.c
View file @
0351166f
...
...
@@ -49,7 +49,7 @@ void msg_init (void)
/*
* If the send queue is full, try to free any old messages.
* These are most probably unwanted, since noone has picked them up...
* These are most probably unwanted, since no
one has picked them up...
*/
#define MSG_FLUSH_TIME 10
/* seconds */
static
void
flush_msg
(
struct
msqid_ds
*
msq
)
...
...
net/Changes
View file @
0351166f
...
...
@@ -437,7 +437,7 @@ problem. [See the LiS project]
10. Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board
driver but that's for an internal project and its general release is still
a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
Mike McLagan][Friz Elfert is doing the isdn4linux kit].
Mike McLagan][Fri
t
z Elfert is doing the isdn4linux kit].
11. IP over SCSI.
...
...
net/ipv4/arp.c
View file @
0351166f
...
...
@@ -788,9 +788,9 @@ static int arp_force_expire(void)
}
/*
* Check if there are
too old entries and remove them. If the ATF_PERM
*
flag is set, they are always left in the arp cache (permanent entry).
*
If an entry was not be confirmed
for ARP_CONFIRM_INTERVAL,
* Check if there are
entries that are too old and remove them. If the
*
ATF_PERM flag is set, they are always left in the arp cache (permanent
*
entries). If an entry was not confirmed
for ARP_CONFIRM_INTERVAL,
* send point-to-point ARP request.
* If it will not be confirmed for ARP_CONFIRM_TIMEOUT,
* give it to shred by arp_expire_entry.
...
...
@@ -1390,7 +1390,7 @@ int arp_find(unsigned char *haddr, u32 paddr, struct device *dev,
}
/*
* A request was already sen
d
, but no reply yet. Thus
* A request was already sen
t
, but no reply yet. Thus
* queue the packet with the previous attempt
*/
...
...
net/ipv4/tcp_input.c
View file @
0351166f
...
...
@@ -195,7 +195,7 @@ static void bad_tcp_sequence(struct sock *sk, struct tcphdr *th, u32 end_seq,
extern
__inline__
int
tcp_sequence
(
struct
sock
*
sk
,
u32
seq
,
u32
end_seq
)
{
u32
end_window
=
sk
->
acked
_seq
+
sk
->
window
;
u32
end_window
=
sk
->
lastwin
_seq
+
sk
->
window
;
return
/* if start is at end of window, end must be too (zero window) */
(
seq
==
end_window
&&
seq
==
end_seq
)
||
/* if start is before end of window, check for interest */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment