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
3448e1a6
Commit
3448e1a6
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 0.99.14x
parent
3ba1ba97
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
3786 additions
and
272 deletions
+3786
-272
Makefile
Makefile
+1
-1
config.in
config.in
+1
-0
drivers/block/Makefile
drivers/block/Makefile
+8
-0
drivers/block/blk.h
drivers/block/blk.h
+8
-0
drivers/block/ll_rw_blk.c
drivers/block/ll_rw_blk.c
+7
-0
drivers/block/sbpcd.c
drivers/block/sbpcd.c
+2985
-0
drivers/char/console.c
drivers/char/console.c
+1
-1
drivers/char/tty_ioctl.c
drivers/char/tty_ioctl.c
+0
-15
drivers/net/CONFIG
drivers/net/CONFIG
+28
-16
drivers/net/README.8390
drivers/net/README.8390
+0
-96
drivers/net/ne.c
drivers/net/ne.c
+3
-7
fs/isofs/inode.c
fs/isofs/inode.c
+10
-0
fs/open.c
fs/open.c
+1
-0
include/linux/major.h
include/linux/major.h
+2
-1
include/linux/sbpcd.h
include/linux/sbpcd.h
+473
-0
include/linux/timer.h
include/linux/timer.h
+4
-0
include/linux/tty.h
include/linux/tty.h
+1
-1
init/main.c
init/main.c
+6
-0
kernel/ksyms.S
kernel/ksyms.S
+3
-1
net/inet/ip.c
net/inet/ip.c
+34
-37
net/inet/sock.c
net/inet/sock.c
+5
-3
net/inet/sock.h
net/inet/sock.h
+7
-1
net/inet/tcp.c
net/inet/tcp.c
+195
-88
net/inet/timer.c
net/inet/timer.c
+3
-4
No files found.
Makefile
View file @
3448e1a6
VERSION
=
0.99
PATCHLEVEL
=
14
ALPHA
=
w
ALPHA
=
x
all
:
Version zImage
...
...
config.in
View file @
3448e1a6
...
...
@@ -87,6 +87,7 @@ fi
*
bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n
bool 'Mitsumi CDROM driver support' CONFIG_MCD n
bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
*
* Filesystems
*
...
...
drivers/block/Makefile
View file @
3448e1a6
...
...
@@ -34,6 +34,14 @@ OBJS := $(OBJS) mcd.o
SRCS
:=
$(SRCS)
mcd.c
endif
ifdef
CONFIG_SBPCD
OBJS
:=
$(OBJS)
sbpcd.o
SRCS
:=
$(SRCS)
sbpcd.c
ifdef
PATCHLEVEL
CFLAGS
:=
$(CFLAGS)
-DPATCHLEVEL
=
$(PATCHLEVEL)
endif
endif
#CONFIG_SBPCD
ifdef
CONFIG_BLK_DEV_HD
OBJS
:=
$(OBJS)
hd.o
SRCS
:=
$(SRCS)
hd.c
...
...
drivers/block/blk.h
View file @
3448e1a6
...
...
@@ -189,6 +189,14 @@ static void floppy_off(unsigned int nr);
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
#define DEVICE_NAME "Matsushita CD-ROM"
#define DEVICE_REQUEST do_sbpcd_request
#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#else
#error "unknown blk device"
...
...
drivers/block/ll_rw_blk.c
View file @
3448e1a6
...
...
@@ -18,6 +18,10 @@
#include "blk.h"
#ifdef CONFIG_SBPCD
extern
u_long
sbpcd_init
(
u_long
,
u_long
);
#endif CONFIG_SBPCD
/*
* The request-struct contains all necessary data
* to load a nr of sectors into memory
...
...
@@ -485,6 +489,9 @@ long blk_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_MCD
mem_start
=
mcd_init
(
mem_start
,
mem_end
);
#endif
#ifdef CONFIG_SBPCD
mem_start
=
sbpcd_init
(
mem_start
,
mem_end
);
#endif CONFIG_SBPCD
if
(
ramdisk_size
)
mem_start
+=
rd_init
(
mem_start
,
ramdisk_size
*
1024
);
return
mem_start
;
...
...
drivers/block/sbpcd.c
0 → 100644
View file @
3448e1a6
/*
* sbpcd.c CD-ROM device driver for the whole family of IDE-style
* Kotobuki/Matsushita/Panasonic CR-5xx drives for
* SoundBlaster ("Pro" or "16 ASP" or compatible) cards
* and for "no-sound" interfaces like Lasermate and the
* Panasonic CI-101P.
*
* NOTE: This is release 1.0.
* It works with my SbPro & drive CR-521 V2.11 from 2/92
* and with the new CR-562-B V0.75 on a "naked" Panasonic
* CI-101P interface. And vice versa.
*
*
* VERSION HISTORY
*
* 0.1 initial release, April/May 93, after mcd.c
*
* 0.2 the "repeat:"-loop in do_sbpcd_request did not check for
* end-of-request_queue (resulting in kernel panic).
* Flow control seems stable, but throughput is not better.
*
* 0.3 interrupt locking totally eliminated (maybe "inb" and "outb"
* are still locking) - 0.2 made keyboard-type-ahead losses.
* check_sbpcd_media_change added (to use by isofs/inode.c)
* - but it detects almost nothing.
*
* 0.4 use MAJOR 25 definitely.
* Almost total re-design to support double-speed drives and
* "naked" (no sound) interface cards.
* Flow control should be exact now (tell me if not).
* Don't occupy the SbPro IRQ line (not needed either); will
* live together with Hannu Savolainen's sndkit now.
* Speeded up data transfer to 150 kB/sec, with help from Kai
* Makisara, the "provider" of the "mt" tape utility.
* Give "SpinUp" command if necessary.
* First steps to support up to 4 drives (but currently only one).
* Implemented audio capabilities - workman should work, xcdplayer
* gives some problems.
* This version is still consuming too much CPU time, and
* sleeping still has to be worked on.
* During "long" implied seeks, it seems possible that a
* ReadStatus command gets ignored. That gives the message
* "ResponseStatus timed out" (happens about 6 times here during
* a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is
* handled without data error, but it should get done better.
*
* 0.5 Free CPU during waits (again with help from Kai Makisara).
* Made it work together with the LILO/kernel setup standard.
* Included auto-probing code, as suggested by YGGDRASIL.
* Formal redesign to add DDI debugging.
* There are still flaws in IOCTL (workman with double speed drive).
*
* 1.0 Added support for all drive ids (0...3, no longer only 0)
* and up to 4 drives on one controller.
* Added "#define MANY_SESSION" for "old" multi session CDs.
*
* 1.1 Do SpinUp for new drives, too.
* Revised for clean compile under "old" kernels (pl9).
*
* special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
* elaborated speed-up experiments (and the fabulous results!), for
* the "push" towards load-free wait loops, and for the extensive mail
* thread which brought additional hints and bug fixes.
*
*
* Copyright (C) 1993, 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
* or <eberhard_moenkeberg@rollo.central.de>
*
* The FTP-home of this driver is
* ftp.gwdg.de:/pub/linux/cdrom/drivers/sbpcd/.
* I will serve tsx-11.mit.edu, sunsite.unc.edu and
* ftp.funet.fi, too.
*
*
* If you change this software, you should mail a .diff
* file with some description lines to emoenke.gwdg.de.
* I want to know about it.
*
* If you are the editor of a Linux CD, you should
* add sbpcd.c into your boot floppy kernel and send
* me one of your CDs for free.
*
* 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the GNU General Public License
* (for example /usr/src/linux/COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef PATCHLEVEL
#define PATCHLEVEL 9
#endif
#include <linux/config.h>
#include <linux/errno.h>
#if SBPCD_USE_IRQ
#include <linux/signal.h>
#endif SBPCD_USE_IRQ
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
#include <linux/sbpcd.h>
#if PATCHLEVEL>13
#include <linux/ddi.h>
#include <linux/major.h>
#else
#define DDIOCSDBG 0x9000
#define MATSUSHITA_CDROM_MAJOR 25
#endif
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <stdarg.h>
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
#include "blk.h"
#define VERSION "1.1"
#define SBPCD_DEBUG
#ifndef CONFIG_SBPCD
#error "SBPCD: \"make config\" again. Enable Matsushita/Panasonic CDROM support"
#endif
#ifndef CONFIG_ISO9660_FS
#error "SBPCD: \"make config\" again. File system iso9660 is necessary."
#endif
/*
* still testing around...
*/
#define MANY_SESSION 0
#define CDMKE
#undef FUTURE
#define WORKMAN 1
/* some testing stuff to make it better */
/*==========================================================================*/
/*==========================================================================*/
/*
* auto-probing address list
* inspired by Adam J. Richter from Yggdrasil
*
* still not good enough - can cause a hang.
* example: a NE 2000 ehernet card at 300 will cause a hang probing 310.
* if that happens, reboot and use the LILO (kernel) command line.
* the conflicting possible ethernet card addresses get probed last - to
* minimize the hang possibilities.
*
* The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error,
* the 0x2xx-addresses must get checked before 0x6xx.
*
* what are other cards' default and range ???
* what about ESCOM PowerSound???
* what about HighScreen???
*/
static
int
autoprobe
[]
=
{
CDROM_PORT
,
SBPRO
,
/* probe with user's setup first */
0x230
,
1
,
/* Soundblaster Pro and 16 (default) */
0x300
,
0
,
/* CI-101P (default), Galaxy (default), Reveal (one default) */
0x250
,
1
,
/* OmniCD default, Soundblaster Pro and 16 */
0x260
,
1
,
/* OmniCD */
0x320
,
0
,
/* Lasermate, CI-101P, Galaxy, Reveal (other default) */
0x340
,
0
,
/* Lasermate, CI-101P */
0x360
,
0
,
/* Lasermate, CI-101P */
0x270
,
1
,
/* Soundblaster 16 */
0x630
,
0
,
/* "sound card #9" (default) */
0x650
,
0
,
/* "sound card #9" */
0x670
,
0
,
/* "sound card #9" */
0x690
,
0
,
/* "sound card #9" */
0x330
,
0
,
/* Lasermate, CI-101P */
0x350
,
0
,
/* Lasermate, CI-101P */
0x370
,
0
,
/* Lasermate, CI-101P */
0x290
,
1
,
/* Soundblaster 16 */
0x310
,
0
,
/* Lasermate, CI-101P */
};
#define NUM_AUTOPROBE (sizeof(autoprobe) / sizeof(int))
/*==========================================================================*/
/*
* the forward references:
*/
static
void
sbp_read_cmd
(
void
);
static
int
sbp_data
(
void
);
/*==========================================================================*/
/*
* pattern for printk selection:
*
* (1<<DBG_INF) necessary information
* (1<<DBG_IRQ) interrupt trace
* (1<<DBG_REA) "read" status trace
* (1<<DBG_CHK) "media check" trace
* (1<<DBG_TIM) datarate timer test
* (1<<DBG_INI) initialization trace
* (1<<DBG_TOC) tell TocEntry values
* (1<<DBG_IOC) ioctl trace
* (1<<DBG_STA) "ResponseStatus" trace
* (1<<DBG_ERR) "xx_ReadError" trace
* (1<<DBG_CMD) "cmd_out" trace
* (1<<DBG_WRN) give explanation before auto-probing
* (1<<DBG_MUL) multi session code test
* (1<<DBG_ID) "drive_id != 0" test code
* (1<<DBG_IOX) some special information
* (1<<DBG_DID) drive ID test
* (1<<DBG_RES) drive reset info
* (1<<DBG_SPI) SpinUp test info
* (1<<DBG_000) unnecessary information
*/
#if 1
static
int
sbpcd_debug
=
(
1
<<
DBG_INF
)
|
(
1
<<
DBG_WRN
);
#else
static
int
sbpcd_debug
=
(
1
<<
DBG_INF
)
|
(
1
<<
DBG_TOC
)
|
(
1
<<
DBG_IOX
);
#endif
static
int
sbpcd_ioaddr
=
CDROM_PORT
;
/* default I/O base address */
static
int
sbpro_type
=
SBPRO
;
static
int
CDo_command
,
CDo_reset
;
static
int
CDo_sel_d_i
,
CDo_enable
;
static
int
CDi_info
,
CDi_status
,
CDi_data
;
static
int
MIXER_addr
,
MIXER_data
;
static
struct
cdrom_msf
msf
;
static
struct
cdrom_ti
ti
;
static
struct
cdrom_tochdr
tochdr
;
static
struct
cdrom_tocentry
tocentry
;
static
struct
cdrom_subchnl
SC
;
static
struct
cdrom_volctrl
volctrl
;
char
*
str_sb
=
"SoundBlaster"
;
char
*
str_lm
=
"LaserMate"
;
char
*
type
;
/*==========================================================================*/
#if FUTURE
static
struct
wait_queue
*
sbp_waitq
=
NULL
;
#endif FUTURE
/*==========================================================================*/
#define SBP_BUFFER_FRAMES 4
/* driver's own read_ahead */
/*==========================================================================*/
static
u_char
drive_family
[]
=
"CR-5"
;
static
u_char
drive_vendor
[]
=
"MATSHITA"
;
static
u_int
response_count
=
0
;
static
u_int
flags_cmd_out
;
static
u_char
cmd_type
=
0
;
static
u_char
drvcmd
[
7
];
static
u_char
infobuf
[
20
];
static
u_char
timed_out
=
0
;
static
u_int
datarate
=
1000000
;
static
u_int
maxtim16
=
16000000
;
static
u_int
maxtim04
=
4000000
;
static
u_int
maxtim02
=
2000000
;
static
u_int
maxtim_8
=
30000
;
#if MANY_SESSION
static
u_int
maxtim_data
=
9000
;
#else
static
u_int
maxtim_data
=
3000
;
#endif MANY_SESSION
/*==========================================================================*/
static
int
ndrives
=
0
;
static
u_char
drv_pattern
[
4
]
=
{
0x80
,
0x80
,
0x80
,
0x80
};
/* auto speed */
/* /X:... drv_pattern[0] |= (sax_n1|sax_n2); */
/* /A:... for (i=0;i<4;i++) drv_pattern[i] |= sax_a; */
/* /N:... ndrives=i-'0'; */
/*==========================================================================*/
/*
* drive space begins here (needed separate for each unit)
*/
static
int
d
=
0
;
/* DS index: drive number */
static
struct
{
char
drv_minor
;
/* minor number or -1 */
char
drive_model
[
4
];
char
firmware_version
[
4
];
u_char
*
sbp_buf
;
/* Pointer to internal data buffer,
space allocated during sbpcd_init() */
int
sbp_first_frame
;
/* First frame in buffer */
int
sbp_last_frame
;
/* Last frame in buffer */
int
sbp_read_frames
;
/* Number of frames being read to buffer */
int
sbp_current
;
/* Frame being currently read */
u_char
drv_type
;
u_char
drv_options
;
u_char
status_byte
;
u_char
diskstate_flags
;
u_char
sense_byte
;
u_char
CD_changed
;
u_char
error_byte
;
u_char
f_multisession
;
u_int
lba_multi
;
u_char
audio_state
;
u_int
pos_audio_start
;
u_int
pos_audio_end
;
char
vol_chan0
;
u_char
vol_ctrl0
;
char
vol_chan1
;
u_char
vol_ctrl1
;
#if 000
char vol_chan2;
u_char vol_ctrl2;
char vol_chan3;
u_char vol_ctrl3;
#endif 000
u_char
SubQ_audio
;
u_char
SubQ_ctl_adr
;
u_char
SubQ_trk
;
u_char
SubQ_pnt_idx
;
u_int
SubQ_run_tot
;
u_int
SubQ_run_trk
;
u_char
SubQ_whatisthis
;
u_char
UPC_ctl_adr
;
u_char
UPC_buf
[
7
];
int
CDsize_blk
;
int
frame_size
;
int
CDsize_frm
;
u_char
xa_byte
;
/* 0x20: XA capabilities */
u_char
n_first_track
;
/* binary */
u_char
n_last_track
;
/* binary (not bcd), 0x01...0x63 */
u_int
size_msf
;
/* time of whole CD, position of LeadOut track */
u_int
size_blk
;
u_char
TocEnt_nixbyte
;
/* em */
u_char
TocEnt_ctl_adr
;
u_char
TocEnt_number
;
u_char
TocEnt_format
;
/* em */
u_int
TocEnt_address
;
u_char
ored_ctl_adr
;
/* to detect if CDROM contains data tracks */
struct
{
u_char
nixbyte
;
/* em */
u_char
ctl_adr
;
/* 0x4x: data, 0x0x: audio */
u_char
number
;
u_char
format
;
/* em */
/* 0x00: lba, 0x01: msf */
u_int
address
;
}
TocBuffer
[
MAX_TRACKS
+
1
];
/* last entry faked */
int
in_SpinUp
;
}
DS
[
4
];
/*
* drive space ends here (needed separate for each unit)
*/
/*==========================================================================*/
/*==========================================================================*/
/*
* DDI interface definitions
*/
#ifdef SBPCD_DEBUG
# define DPRINTF(x) sbpcd_dprintf x
void
sbpcd_dprintf
(
int
level
,
char
*
fmt
,
...)
{
char
buff
[
256
];
va_list
args
;
extern
int
vsprintf
(
char
*
buf
,
const
char
*
fmt
,
va_list
args
);
if
(
!
(
sbpcd_debug
&
(
1
<<
level
)))
return
;
va_start
(
args
,
fmt
);
vsprintf
(
buff
,
fmt
,
args
);
va_end
(
args
);
printk
(
buff
);
}
#else
# define DPRINTF(x)
/* nothing */
#endif SBPCD_DEBUG
/*
* maintain trace bit pattern
*/
static
int
sbpcd_dbg_ioctl
(
unsigned
long
arg
,
int
level
)
{
int
val
;
val
=
get_fs_long
((
int
*
)
arg
);
switch
(
val
)
{
case
0
:
/* OFF */
sbpcd_debug
=
0
;
break
;
default:
if
(
val
>=
128
)
sbpcd_debug
&=
~
(
1
<<
(
val
-
128
));
else
sbpcd_debug
|=
(
1
<<
val
);
}
return
(
0
);
}
/*==========================================================================*/
/*==========================================================================*/
/*
* Wait a little while (used for polling the drive). If in initialization,
* setting a timeout doesn't work, so just loop for a while.
*/
static
inline
void
sbp_sleep
(
u_int
jifs
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
+
jifs
;
schedule
();
}
/*==========================================================================*/
/*==========================================================================*/
/*
* convert logical_block_address to m-s-f_number (3 bytes only)
*/
static
void
lba2msf
(
int
lba
,
u_char
*
msf
)
{
lba
+=
CD_BLOCK_OFFSET
;
msf
[
0
]
=
lba
/
(
CD_SECS
*
CD_FRAMES
);
lba
%=
CD_SECS
*
CD_FRAMES
;
msf
[
1
]
=
lba
/
CD_FRAMES
;
msf
[
2
]
=
lba
%
CD_FRAMES
;
}
/*==========================================================================*/
/*==========================================================================*/
/*
* convert msf-bin to msf-bcd
*/
static
void
bin2bcdx
(
u_char
*
p
)
/* must work only up to 75 or 99 */
{
*
p
=
((
*
p
/
10
)
<<
4
)
|
(
*
p
%
10
);
}
/*==========================================================================*/
static
u_int
blk2msf
(
u_int
blk
)
{
MSF
msf
;
u_int
mm
;
msf
.
c
[
3
]
=
0
;
msf
.
c
[
2
]
=
(
blk
+
CD_BLOCK_OFFSET
)
/
(
CD_SECS
*
CD_FRAMES
);
mm
=
(
blk
+
CD_BLOCK_OFFSET
)
%
(
CD_SECS
*
CD_FRAMES
);
msf
.
c
[
1
]
=
mm
/
CD_FRAMES
;
msf
.
c
[
0
]
=
mm
%
CD_FRAMES
;
return
(
msf
.
n
);
}
/*==========================================================================*/
static
u_int
make16
(
u_char
rh
,
u_char
rl
)
{
return
((
rh
<<
8
)
|
rl
);
}
/*==========================================================================*/
static
u_int
make32
(
u_int
rh
,
u_int
rl
)
{
return
((
rh
<<
16
)
|
rl
);
}
/*==========================================================================*/
static
u_char
swap_nibbles
(
u_char
i
)
{
return
((
i
<<
4
)
|
(
i
>>
4
));
}
/*==========================================================================*/
static
u_char
byt2bcd
(
u_char
i
)
{
return
(((
i
/
10
)
<<
4
)
+
i
%
10
);
}
/*==========================================================================*/
static
u_char
bcd2bin
(
u_char
bcd
)
{
return
((
bcd
>>
4
)
*
10
+
(
bcd
&
0x0F
));
}
/*==========================================================================*/
static
int
msf2blk
(
int
msfx
)
{
MSF
msf
;
int
i
;
msf
.
n
=
msfx
;
i
=
(
msf
.
c
[
2
]
*
CD_SECS
+
msf
.
c
[
1
])
*
CD_FRAMES
+
msf
.
c
[
0
]
-
CD_BLOCK_OFFSET
;
if
(
i
<
0
)
return
(
0
);
return
(
i
);
}
/*==========================================================================*/
/* evaluate xx_ReadError code (still mysterious) */
static
int
sta2err
(
int
sta
)
{
if
(
sta
<=
2
)
return
(
sta
);
if
(
sta
==
0x05
)
return
(
-
4
);
if
(
sta
==
0x06
)
return
(
-
6
);
if
(
sta
==
0x0d
)
return
(
-
6
);
if
(
sta
==
0x0e
)
return
(
-
3
);
if
(
sta
==
0x14
)
return
(
-
3
);
if
(
sta
==
0x0c
)
return
(
-
11
);
if
(
sta
==
0x0f
)
return
(
-
11
);
if
(
sta
==
0x10
)
return
(
-
11
);
if
(
sta
>=
0x16
)
return
(
-
12
);
DS
[
d
].
CD_changed
=
0xFF
;
if
(
sta
==
0x11
)
return
(
-
15
);
return
(
-
2
);
}
/*==========================================================================*/
static
void
clr_cmdbuf
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
7
;
i
++
)
drvcmd
[
i
]
=
0
;
cmd_type
=
0
;
}
/*==========================================================================*/
static
void
mark_timeout
(
void
)
{
timed_out
=
1
;
DPRINTF
((
DBG_TIM
,
"SBPCD: timer stopped.
\n
"
));
}
/*==========================================================================*/
static
void
flush_status
(
void
)
{
#ifdef CDMKE
int
i
;
if
(
current
==
task
[
0
])
for
(
i
=
maxtim02
;
i
!=
0
;
i
--
)
inb
(
CDi_status
);
else
{
sbp_sleep
(
150
);
for
(
i
=
maxtim_data
;
i
!=
0
;
i
--
)
inb
(
CDi_status
);
}
#else
timed_out
=
0
;
SET_TIMER
(
mark_timeout
,
150
);
do
{
}
while
(
!
timed_out
);
CLEAR_TIMER
;
inb
(
CDi_status
);
#endif CDMKE
}
/*==========================================================================*/
static
int
CDi_stat_loop
(
void
)
{
int
i
,
j
;
u_long
timeout
;
if
(
current
==
task
[
0
])
for
(
i
=
maxtim16
;
i
!=
0
;
i
--
)
{
j
=
inb
(
CDi_status
);
if
(
!
(
j
&
s_not_data_ready
))
return
(
j
);
if
(
!
(
j
&
s_not_result_ready
))
return
(
j
);
if
(
!
new_drive
)
if
(
j
&
s_attention
)
return
(
j
);
}
else
for
(
timeout
=
jiffies
+
1000
,
i
=
maxtim_data
;
timeout
>
jiffies
;
)
{
for
(
;
i
!=
0
;
i
--
)
{
j
=
inb
(
CDi_status
);
if
(
!
(
j
&
s_not_data_ready
))
return
(
j
);
if
(
!
(
j
&
s_not_result_ready
))
return
(
j
);
if
(
!
new_drive
)
if
(
j
&
s_attention
)
return
(
j
);
}
sbp_sleep
(
1
);
i
=
1
;
}
return
(
-
1
);
}
/*==========================================================================*/
static
int
ResponseInfo
(
void
)
{
int
i
,
j
,
st
=
0
;
u_long
timeout
;
if
(
current
==
task
[
0
])
for
(
i
=
0
;
i
<
response_count
;
i
++
)
{
for
(
j
=
maxtim_8
;
j
!=
0
;
j
--
)
{
st
=
inb
(
CDi_status
);
if
(
!
(
st
&
s_not_result_ready
))
break
;
}
if
(
j
==
0
)
return
(
-
1
);
infobuf
[
i
]
=
inb
(
CDi_info
);
}
else
{
for
(
i
=
0
,
timeout
=
jiffies
+
100
;
i
<
response_count
;
i
++
)
{
for
(
j
=
maxtim_data
;
;
)
{
for
(
;
j
!=
0
;
j
--
)
{
st
=
inb
(
CDi_status
);
if
(
!
(
st
&
s_not_result_ready
))
break
;
}
if
(
j
!=
0
||
timeout
<=
jiffies
)
break
;
sbp_sleep
(
0
);
j
=
1
;
}
if
(
timeout
<=
jiffies
)
return
(
-
1
);
infobuf
[
i
]
=
inb
(
CDi_info
);
}
}
return
(
0
);
}
/*==========================================================================*/
static
int
EvaluateStatus
(
int
st
)
{
if
(
!
new_drive
)
{
DS
[
d
].
status_byte
=
0
;
if
(
st
&
p_caddin_old
)
DS
[
d
].
status_byte
|=
p_door_closed
|
p_caddy_in
;
if
(
st
&
p_spinning
)
DS
[
d
].
status_byte
|=
p_spinning
;
if
(
st
&
p_check
)
DS
[
d
].
status_byte
|=
p_check
;
if
(
st
&
p_busy_old
)
DS
[
d
].
status_byte
|=
p_busy_new
;
if
(
st
&
p_disk_ok
)
DS
[
d
].
status_byte
|=
p_disk_ok
;
}
else
{
DS
[
d
].
status_byte
=
st
;
st
=
p_success_old
;
/* for new drives: fake "successful" bit of old drives */
}
return
(
st
);
}
/*==========================================================================*/
static
int
ResponseStatus
(
void
)
{
int
i
,
j
;
u_long
timeout
;
DPRINTF
((
DBG_STA
,
"SBPCD: doing ResponseStatus...
\n
"
));
if
(
current
==
task
[
0
])
{
if
(
flags_cmd_out
&
f_respo3
)
j
=
maxtim_8
;
else
if
(
flags_cmd_out
&
f_respo2
)
j
=
maxtim16
;
else
j
=
maxtim04
;
for
(;
j
!=
0
;
j
--
)
{
i
=
inb
(
CDi_status
);
if
(
!
(
i
&
s_not_result_ready
))
break
;
}
}
else
{
if
(
flags_cmd_out
&
f_respo3
)
timeout
=
jiffies
;
else
if
(
flags_cmd_out
&
f_respo2
)
timeout
=
jiffies
+
1600
;
else
timeout
=
jiffies
+
400
;
j
=
maxtim_8
;
do
{
for
(
;
j
!=
0
;
j
--
)
{
i
=
inb
(
CDi_status
);
if
(
!
(
i
&
s_not_result_ready
))
break
;
}
if
(
j
!=
0
||
timeout
<=
jiffies
)
break
;
sbp_sleep
(
0
);
j
=
1
;
}
while
(
1
);
}
if
(
j
==
0
)
{
if
((
flags_cmd_out
&
f_respo3
)
==
0
)
DPRINTF
((
DBG_STA
,
"SBPCD: ResponseStatus: timeout.
\n
"
));
EvaluateStatus
(
0
);
return
(
-
1
);
}
i
=
inb
(
CDi_info
);
i
=
EvaluateStatus
(
i
);
return
(
i
);
}
/*==========================================================================*/
static
void
xx_ReadStatus
(
void
)
{
int
i
;
DPRINTF
((
DBG_STA
,
"SBPCD: giving xx_ReadStatus command
\n
"
));
if
(
!
new_drive
)
OUT
(
CDo_command
,
0x81
);
else
{
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
OUT
(
CDo_command
,
0x05
);
for
(
i
=
0
;
i
<
6
;
i
++
)
OUT
(
CDo_command
,
0
);
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
}
}
/*==========================================================================*/
int
xx_ReadError
(
void
)
{
int
cmd_out
(
void
);
int
i
;
clr_cmdbuf
();
DPRINTF
((
DBG_ERR
,
"SBPCD: giving xx_ReadError command.
\n
"
));
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x82
;
response_count
=
8
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
;
}
else
{
drvcmd
[
0
]
=
0x82
;
response_count
=
6
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
;
}
i
=
cmd_out
();
DS
[
d
].
error_byte
=
0
;
DPRINTF
((
DBG_ERR
,
"SBPCD: xx_ReadError: cmd_out(82) returns %d (%02X)
\n
"
,
i
,
i
));
if
(
i
<
0
)
return
(
i
);
if
(
new_drive
)
i
=
2
;
else
i
=
1
;
DS
[
d
].
error_byte
=
infobuf
[
i
];
DPRINTF
((
DBG_ERR
,
"SBPCD: xx_ReadError: infobuf[%d] is %d (%02X)
\n
"
,
i
,
DS
[
d
].
error_byte
,
DS
[
d
].
error_byte
));
i
=
sta2err
(
infobuf
[
i
]);
return
(
i
);
}
/*==========================================================================*/
int
cmd_out
(
void
)
{
int
i
=
0
;
if
(
flags_cmd_out
&
f_putcmd
)
{
DPRINTF
((
DBG_CMD
,
"SBPCD: cmd_out: put"
));
for
(
i
=
0
;
i
<
7
;
i
++
)
DPRINTF
((
DBG_CMD
,
" %02X"
,
drvcmd
[
i
]));
DPRINTF
((
DBG_CMD
,
"
\n
"
));
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
for
(
i
=
0
;
i
<
7
;
i
++
)
OUT
(
CDo_command
,
drvcmd
[
i
]);
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
}
if
(
response_count
!=
0
)
{
if
(
cmd_type
!=
0
)
{
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x01
);
DPRINTF
((
DBG_INF
,
"SBPCD: misleaded to try ResponseData.
\n
"
));
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x00
);
}
else
i
=
ResponseInfo
();
if
(
i
<
0
)
return
(
-
9
);
}
if
(
DS
[
d
].
in_SpinUp
!=
0
)
DPRINTF
((
DBG_SPI
,
"SBPCD: to CDi_stat_loop.
\n
"
));
if
(
flags_cmd_out
&
f_lopsta
)
{
i
=
CDi_stat_loop
();
if
((
i
<
0
)
||!
(
i
&
s_attention
))
return
(
-
9
);
}
if
(
!
(
flags_cmd_out
&
f_getsta
))
goto
LOC_229
;
LOC_228:
if
(
DS
[
d
].
in_SpinUp
!=
0
)
DPRINTF
((
DBG_SPI
,
"SBPCD: to xx_ReadStatus.
\n
"
));
xx_ReadStatus
();
LOC_229:
if
(
flags_cmd_out
&
f_ResponseStatus
)
{
if
(
DS
[
d
].
in_SpinUp
!=
0
)
DPRINTF
((
DBG_SPI
,
"SBPCD: to ResponseStatus.
\n
"
));
i
=
ResponseStatus
();
/* builds status_byte, returns orig. status or p_busy_new */
if
(
i
<
0
)
return
(
-
9
);
if
(
flags_cmd_out
&
(
f_bit1
|
f_wait_if_busy
))
{
if
(
!
st_check
)
{
if
(
flags_cmd_out
&
f_bit1
)
if
(
i
&
p_success_old
)
goto
LOC_232
;
if
(
!
(
flags_cmd_out
&
f_wait_if_busy
))
goto
LOC_228
;
if
(
!
st_busy
)
goto
LOC_228
;
}
}
}
LOC_232:
if
(
!
(
flags_cmd_out
&
f_obey_p_check
))
return
(
0
);
if
(
!
st_check
)
return
(
0
);
if
(
DS
[
d
].
in_SpinUp
!=
0
)
DPRINTF
((
DBG_SPI
,
"SBPCD: to xx_ReadError.
\n
"
));
i
=
xx_ReadError
();
if
(
DS
[
d
].
in_SpinUp
!=
0
)
DPRINTF
((
DBG_SPI
,
"SBPCD: to cmd_out OK.
\n
"
));
return
(
i
);
}
/*==========================================================================*/
static
int
xx_Seek
(
u_int
pos
,
char
f_blk_msf
)
{
int
i
;
clr_cmdbuf
();
if
(
f_blk_msf
>
1
)
return
(
-
3
);
if
(
!
new_drive
)
{
if
(
f_blk_msf
==
1
)
pos
=
msf2blk
(
pos
);
drvcmd
[
2
]
=
(
pos
>>
16
)
&
0x00FF
;
drvcmd
[
3
]
=
(
pos
>>
8
)
&
0x00FF
;
drvcmd
[
4
]
=
pos
&
0x00FF
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_lopsta
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
|
f_bit1
;
}
else
{
if
(
f_blk_msf
==
0
)
pos
=
blk2msf
(
pos
);
drvcmd
[
1
]
=
(
pos
>>
16
)
&
0x00FF
;
drvcmd
[
2
]
=
(
pos
>>
8
)
&
0x00FF
;
drvcmd
[
3
]
=
pos
&
0x00FF
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_ResponseStatus
|
f_obey_p_check
;
}
drvcmd
[
0
]
=
0x01
;
response_count
=
0
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
static
int
xx_SpinUp
(
void
)
{
int
i
;
DPRINTF
((
DBG_SPI
,
"SBPCD: SpinUp.
\n
"
));
DS
[
d
].
in_SpinUp
=
1
;
clr_cmdbuf
();
if
(
!
new_drive
)
{
drvcmd
[
0
]
=
0x05
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_lopsta
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
|
f_bit1
;
}
else
{
drvcmd
[
0
]
=
0x02
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_ResponseStatus
|
f_obey_p_check
;
}
response_count
=
0
;
i
=
cmd_out
();
DS
[
d
].
in_SpinUp
=
0
;
return
(
i
);
}
/*==========================================================================*/
static
int
yy_SpinDown
(
void
)
{
int
i
;
if
(
!
new_drive
)
return
(
-
3
);
clr_cmdbuf
();
drvcmd
[
0
]
=
0x06
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
0
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
static
int
yy_SetSpeed
(
u_char
speed
,
u_char
x1
,
u_char
x2
)
{
int
i
;
if
(
!
new_drive
)
return
(
-
3
);
clr_cmdbuf
();
drvcmd
[
0
]
=
0x09
;
drvcmd
[
1
]
=
0x03
;
drvcmd
[
2
]
=
speed
;
drvcmd
[
3
]
=
x1
;
drvcmd
[
4
]
=
x2
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
0
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
static
int
xx_SetVolume
(
void
)
{
int
i
;
u_char
channel0
,
channel1
,
volume0
,
volume1
;
u_char
control0
,
value0
,
control1
,
value1
;
DS
[
d
].
diskstate_flags
&=
~
volume_bit
;
clr_cmdbuf
();
channel0
=
DS
[
d
].
vol_chan0
;
volume0
=
DS
[
d
].
vol_ctrl0
;
channel1
=
control1
=
DS
[
d
].
vol_chan1
;
volume1
=
value1
=
DS
[
d
].
vol_ctrl1
;
control0
=
value0
=
0
;
if
(((
DS
[
d
].
drv_options
&
sax_a
)
!=
0
)
&&
(
DS
[
d
].
drv_type
>=
drv_211
))
{
if
((
volume0
!=
0
)
&&
(
volume1
==
0
))
{
volume1
=
volume0
;
channel1
=
channel0
;
}
else
if
((
volume0
==
0
)
&&
(
volume1
!=
0
))
{
volume0
=
volume1
;
channel0
=
channel1
;
}
}
if
(
channel0
>
1
)
{
channel0
=
0
;
volume0
=
0
;
}
if
(
channel1
>
1
)
{
channel1
=
1
;
volume1
=
0
;
}
if
(
new_drive
)
{
control0
=
channel0
+
1
;
control1
=
channel1
+
1
;
value0
=
(
volume0
>
volume1
)
?
volume0
:
volume1
;
value1
=
value0
;
if
(
volume0
==
0
)
control0
=
0
;
if
(
volume1
==
0
)
control1
=
0
;
drvcmd
[
0
]
=
0x09
;
drvcmd
[
1
]
=
0x05
;
drvcmd
[
3
]
=
control0
;
drvcmd
[
4
]
=
value0
;
drvcmd
[
5
]
=
control1
;
drvcmd
[
6
]
=
value1
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
}
else
{
if
(
DS
[
d
].
drv_type
>=
drv_300
)
{
control0
=
volume0
&
0xFC
;
value0
=
volume1
&
0xFC
;
if
((
volume0
!=
0
)
&&
(
volume0
<
4
))
control0
|=
0x04
;
if
((
volume1
!=
0
)
&&
(
volume1
<
4
))
value0
|=
0x04
;
if
(
channel0
!=
0
)
control0
|=
0x01
;
if
(
channel1
==
1
)
value0
|=
0x01
;
}
else
{
value0
=
(
volume0
>
volume1
)
?
volume0
:
volume1
;
if
(
DS
[
d
].
drv_type
<
drv_211
)
{
if
(
channel0
!=
0
)
{
i
=
channel1
;
channel1
=
channel0
;
channel0
=
i
;
i
=
volume1
;
volume1
=
volume0
;
volume0
=
i
;
}
if
(
channel0
==
channel1
)
{
if
(
channel0
==
0
)
{
channel1
=
1
;
volume1
=
0
;
volume0
=
value0
;
}
else
{
channel0
=
0
;
volume0
=
0
;
volume1
=
value0
;
}
}
}
if
((
volume0
!=
0
)
&&
(
volume1
!=
0
))
{
if
(
volume0
==
0xFF
)
volume1
=
0xFF
;
else
if
(
volume1
==
0xFF
)
volume0
=
0xFF
;
}
else
if
(
DS
[
d
].
drv_type
<
drv_201
)
volume0
=
volume1
=
value0
;
if
(
DS
[
d
].
drv_type
>=
drv_201
)
{
if
(
volume0
==
0
)
control0
|=
0x80
;
if
(
volume1
==
0
)
control0
|=
0x40
;
}
if
(
DS
[
d
].
drv_type
>=
drv_211
)
{
if
(
channel0
!=
0
)
control0
|=
0x20
;
if
(
channel1
!=
1
)
control0
|=
0x10
;
}
}
drvcmd
[
0
]
=
0x84
;
drvcmd
[
1
]
=
0x83
;
drvcmd
[
4
]
=
control0
;
drvcmd
[
5
]
=
value0
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
}
response_count
=
0
;
i
=
cmd_out
();
if
(
i
>
0
)
return
(
i
);
DS
[
d
].
diskstate_flags
|=
volume_bit
;
return
(
0
);
}
/*==========================================================================*/
static
int
GetStatus
(
void
)
{
int
i
;
flags_cmd_out
=
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
0
;
cmd_type
=
0
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
static
int
xy_DriveReset
(
void
)
{
int
i
;
DPRINTF
((
DBG_RES
,
"SBPCD: xy_DriveReset called.
\n
"
));
if
(
!
new_drive
)
OUT
(
CDo_reset
,
0x00
);
else
{
clr_cmdbuf
();
drvcmd
[
0
]
=
0x0A
;
flags_cmd_out
=
f_putcmd
;
response_count
=
0
;
i
=
cmd_out
();
}
flush_status
();
i
=
GetStatus
();
if
(
i
>=
0
)
return
-
1
;
if
(
DS
[
d
].
error_byte
!=
aud_12
)
return
-
1
;
return
(
0
);
}
/*==========================================================================*/
static
int
SetSpeed
(
void
)
{
int
i
,
speed
;
if
(
!
(
DS
[
d
].
drv_options
&
(
speed_auto
|
speed_300
|
speed_150
)))
return
(
0
);
speed
=
0x80
;
if
(
!
(
DS
[
d
].
drv_options
&
speed_auto
))
{
speed
|=
0x40
;
if
(
!
(
DS
[
d
].
drv_options
&
speed_300
))
speed
=
0
;
}
i
=
yy_SetSpeed
(
speed
,
0
,
0
);
return
(
i
);
}
/*==========================================================================*/
static
int
DriveReset
(
void
)
{
int
i
;
i
=
xy_DriveReset
();
if
(
i
<
0
)
return
(
-
2
);
do
{
i
=
GetStatus
();
if
((
i
<
0
)
&&
(
i
!=-
15
))
return
(
-
2
);
/* i!=-15 is from sta2err */
if
(
!
st_caddy_in
)
break
;
}
while
(
!
st_diskok
);
DS
[
d
].
CD_changed
=
1
;
i
=
SetSpeed
();
if
(
i
<
0
)
return
(
-
2
);
return
(
0
);
}
/*==========================================================================*/
static
int
xx_Pause_Resume
(
int
pau_res
)
{
int
i
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x0D
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_ResponseStatus
|
f_obey_p_check
;
}
else
{
drvcmd
[
0
]
=
0x8D
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
}
if
(
pau_res
!=
1
)
drvcmd
[
1
]
=
0x80
;
response_count
=
0
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
#if 000
static int yy_LockDoor(char lock)
{
int i;
if (!new_drive) return (-3);
clr_cmdbuf();
drvcmd[0]=0x0C;
if (lock==1) drvcmd[1]=0x01;
flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
response_count=0;
i=cmd_out();
return (i);
}
#endif 000
/*==========================================================================*/
static
int
xx_ReadSubQ
(
void
)
{
int
i
,
j
;
DS
[
d
].
diskstate_flags
&=
~
subq_bit
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x87
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
11
;
}
else
{
drvcmd
[
0
]
=
0x89
;
drvcmd
[
1
]
=
0x02
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
13
;
}
for
(
j
=
0
;
j
<
255
;
j
++
)
{
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
if
(
infobuf
[
0
]
!=
0
)
break
;
if
(
!
st_spinning
)
{
DS
[
d
].
SubQ_ctl_adr
=
DS
[
d
].
SubQ_trk
=
DS
[
d
].
SubQ_pnt_idx
=
DS
[
d
].
SubQ_whatisthis
=
0
;
DS
[
d
].
SubQ_run_tot
=
DS
[
d
].
SubQ_run_trk
=
0
;
return
(
0
);
}
}
DS
[
d
].
SubQ_audio
=
infobuf
[
0
];
DS
[
d
].
SubQ_ctl_adr
=
swap_nibbles
(
infobuf
[
1
]);
DS
[
d
].
SubQ_trk
=
byt2bcd
(
infobuf
[
2
]);
DS
[
d
].
SubQ_pnt_idx
=
byt2bcd
(
infobuf
[
3
]);
i
=
4
;
if
(
!
new_drive
)
i
=
5
;
DS
[
d
].
SubQ_run_tot
=
make32
(
make16
(
0
,
infobuf
[
i
]),
make16
(
infobuf
[
i
+
1
],
infobuf
[
i
+
2
]));
/* msf-bin */
i
=
7
;
if
(
!
new_drive
)
i
=
9
;
DS
[
d
].
SubQ_run_trk
=
make32
(
make16
(
0
,
infobuf
[
i
]),
make16
(
infobuf
[
i
+
1
],
infobuf
[
i
+
2
]));
/* msf-bin */
DS
[
d
].
SubQ_whatisthis
=
infobuf
[
i
+
3
];
DS
[
d
].
diskstate_flags
|=
subq_bit
;
return
(
0
);
}
/*==========================================================================*/
static
int
xx_ModeSense
(
void
)
{
int
i
;
DS
[
d
].
diskstate_flags
&=
~
frame_size_bit
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x84
;
drvcmd
[
1
]
=
0x00
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
5
;
}
else
{
drvcmd
[
0
]
=
0x85
;
drvcmd
[
1
]
=
0x00
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
response_count
=
2
;
}
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
i
=
0
;
if
(
new_drive
)
DS
[
d
].
sense_byte
=
infobuf
[
i
++
];
DS
[
d
].
frame_size
=
make16
(
infobuf
[
i
],
infobuf
[
i
+
1
]);
DS
[
d
].
diskstate_flags
|=
frame_size_bit
;
return
(
0
);
}
/*==========================================================================*/
#if 0000
static int xx_TellVolume(void)
{
int i;
u_char switches;
u_char chan0,vol0,chan1,vol1;
DS[d].diskstate_flags &= ~volume_bit;
clr_cmdbuf();
if (new_drive)
{
drvcmd[0]=0x84;
drvcmd[1]=0x05;
response_count=5;
flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check;
}
else
{
drvcmd[0]=0x85;
drvcmd[1]=0x03;
response_count=2;
flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check;
}
i=cmd_out();
if (i<0) return (i);
if (new_drive)
{
chan0=infobuf[1]&0x0F;
vol0=infobuf[2];
chan1=infobuf[3]&0x0F;
vol1=infobuf[4];
if (chan0==0)
{
chan0=1;
vol0=0;
}
if (chan1==0)
{
chan1=2;
vol1=0;
}
chan0 >>= 1;
chan1 >>= 1;
}
else
{
chan0=0;
chan1=1;
vol0=vol1=infobuf[1];
if (DS[d].drv_type>=drv_201)
{
if (DS[d].drv_type<drv_300)
{
switches=infobuf[0];
if ((switches&0x80)!=0) vol0=0;
if ((switches&0x40)!=0) vol1=0;
if (DS[d].drv_type>=drv_211)
{
if ((switches&0x20)!=0) chan0=1;
if ((switches&0x10)!=0) chan1=0;
}
}
else
{
vol0=infobuf[0];
if ((vol0&0x01)!=0) chan0=1;
if ((vol1&0x01)==0) chan1=0;
vol0 &= 0xFC;
vol1 &= 0xFC;
if (vol0!=0) vol0 += 3;
if (vol1!=0) vol1 += 3;
}
}
}
DS[d].vol_chan0=chan0;
DS[d].vol_ctrl0=vol0;
DS[d].vol_chan1=chan1;
DS[d].vol_ctrl1=vol1;
DS[d].vol_chan2=2;
DS[d].vol_ctrl2=0xFF;
DS[d].vol_chan3=3;
DS[d].vol_ctrl3=0xFF;
DS[d].diskstate_flags |= volume_bit;
return (0);
}
#endif
/*==========================================================================*/
static
int
xx_ReadCapacity
(
void
)
{
int
i
;
DS
[
d
].
diskstate_flags
&=
~
cd_size_bit
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x85
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
}
else
{
drvcmd
[
0
]
=
0x88
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
}
response_count
=
5
;
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
DS
[
d
].
CDsize_blk
=
make32
(
make16
(
0
,
infobuf
[
0
]),
make16
(
infobuf
[
1
],
infobuf
[
2
]));
if
(
new_drive
)
DS
[
d
].
CDsize_blk
=
msf2blk
(
DS
[
d
].
CDsize_blk
);
DS
[
d
].
CDsize_frm
=
(
DS
[
d
].
CDsize_blk
*
make16
(
infobuf
[
3
],
infobuf
[
4
]))
/
CD_FRAMESIZE
;
DS
[
d
].
CDsize_blk
+=
151
;
DS
[
d
].
diskstate_flags
|=
cd_size_bit
;
return
(
0
);
}
/*==========================================================================*/
static
int
xx_ReadTocDescr
(
void
)
{
int
i
;
DS
[
d
].
diskstate_flags
&=
~
toc_bit
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x8B
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
}
else
{
drvcmd
[
0
]
=
0x8B
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
}
response_count
=
6
;
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
DS
[
d
].
xa_byte
=
infobuf
[
0
];
DS
[
d
].
n_first_track
=
infobuf
[
1
];
DS
[
d
].
n_last_track
=
infobuf
[
2
];
DS
[
d
].
size_msf
=
make32
(
make16
(
0
,
infobuf
[
3
]),
make16
(
infobuf
[
4
],
infobuf
[
5
]));
DS
[
d
].
size_blk
=
msf2blk
(
DS
[
d
].
size_msf
);
DS
[
d
].
diskstate_flags
|=
toc_bit
;
DPRINTF
((
DBG_TOC
,
"SBPCD: TocDesc: %02X %02X %02X %08X
\n
"
,
DS
[
d
].
xa_byte
,
DS
[
d
].
n_first_track
,
DS
[
d
].
n_last_track
,
DS
[
d
].
size_msf
));
return
(
0
);
}
/*==========================================================================*/
static
int
xx_ReadTocEntry
(
int
num
)
{
int
i
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x8C
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
}
else
{
drvcmd
[
0
]
=
0x8C
;
drvcmd
[
1
]
=
0x02
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
}
drvcmd
[
2
]
=
num
;
response_count
=
8
;
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
DS
[
d
].
TocEnt_nixbyte
=
infobuf
[
0
];
DS
[
d
].
TocEnt_ctl_adr
=
swap_nibbles
(
infobuf
[
1
]);
DS
[
d
].
TocEnt_number
=
infobuf
[
2
];
DS
[
d
].
TocEnt_format
=
infobuf
[
3
];
if
(
new_drive
)
i
=
4
;
else
i
=
5
;
DS
[
d
].
TocEnt_address
=
make32
(
make16
(
0
,
infobuf
[
i
]),
make16
(
infobuf
[
i
+
1
],
infobuf
[
i
+
2
]));
DPRINTF
((
DBG_TOC
,
"SBPCD: TocEntry: %02X %02X %02X %02X %08X
\n
"
,
DS
[
d
].
TocEnt_nixbyte
,
DS
[
d
].
TocEnt_ctl_adr
,
DS
[
d
].
TocEnt_number
,
DS
[
d
].
TocEnt_format
,
DS
[
d
].
TocEnt_address
));
return
(
0
);
}
/*==========================================================================*/
static
int
xx_ReadPacket
(
void
)
{
int
i
;
clr_cmdbuf
();
drvcmd
[
0
]
=
0x8E
;
drvcmd
[
1
]
=
response_count
;
flags_cmd_out
=
f_putcmd
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
static
int
convert_UPC
(
u_char
*
p
)
{
int
i
;
p
++
;
if
(
!
new_drive
)
p
[
13
]
=
0
;
for
(
i
=
0
;
i
<
7
;
i
++
)
{
if
(
new_drive
)
DS
[
d
].
UPC_buf
[
i
]
=
swap_nibbles
(
*
p
++
);
else
{
DS
[
d
].
UPC_buf
[
i
]
=
((
*
p
++
)
<<
4
)
&
0xFF
;
DS
[
d
].
UPC_buf
[
i
]
|=
*
p
++
;
}
}
DS
[
d
].
UPC_buf
[
6
]
&=
0xF0
;
return
(
0
);
}
/*==========================================================================*/
static
int
xx_ReadUPC
(
void
)
{
int
i
;
DS
[
d
].
diskstate_flags
&=
~
upc_bit
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x88
;
response_count
=
8
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
}
else
{
drvcmd
[
0
]
=
0x08
;
response_count
=
0
;
flags_cmd_out
=
f_putcmd
|
f_lopsta
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
|
f_bit1
;
}
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
if
(
!
new_drive
)
{
response_count
=
16
;
i
=
xx_ReadPacket
();
if
(
i
<
0
)
return
(
i
);
}
DS
[
d
].
UPC_ctl_adr
=
0
;
if
(
new_drive
)
i
=
0
;
else
i
=
2
;
if
((
infobuf
[
i
]
&
0x80
)
!=
0
)
{
convert_UPC
(
&
infobuf
[
i
]);
DS
[
d
].
UPC_ctl_adr
&=
0xF0
;
DS
[
d
].
UPC_ctl_adr
|=
0x02
;
}
DS
[
d
].
diskstate_flags
|=
upc_bit
;
return
(
0
);
}
/*==========================================================================*/
static
int
yy_CheckMultiSession
(
void
)
{
int
i
;
DS
[
d
].
diskstate_flags
&=
~
multisession_bit
;
DS
[
d
].
f_multisession
=
0
;
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x8D
;
response_count
=
6
;
flags_cmd_out
=
f_putcmd
|
f_ResponseStatus
|
f_obey_p_check
;
i
=
cmd_out
();
if
(
i
<
0
)
return
(
i
);
if
((
infobuf
[
0
]
&
0x80
)
!=
0
)
{
DPRINTF
((
DBG_MUL
,
"SBPCD: MultiSession CD detected: %02X %02X %02X %02X %02X %02X
\n
"
,
infobuf
[
0
],
infobuf
[
1
],
infobuf
[
2
],
infobuf
[
3
],
infobuf
[
4
],
infobuf
[
5
]));
DS
[
d
].
f_multisession
=
1
;
DS
[
d
].
lba_multi
=
msf2blk
(
make32
(
make16
(
0
,
infobuf
[
1
]),
make16
(
infobuf
[
2
],
infobuf
[
3
])));
}
}
DS
[
d
].
diskstate_flags
|=
multisession_bit
;
return
(
0
);
}
/*==========================================================================*/
static
void
check_datarate
(
void
)
{
#ifdef CDMKE
int
i
=
0
;
timed_out
=
0
;
datarate
=
0
;
/* set a timer to make (timed_out!=0) after 1.1 seconds */
DPRINTF
((
DBG_TIM
,
"SBPCD: timer started (110).
\n
"
));
sti
();
/* to avoid possible "printf" bug */
SET_TIMER
(
mark_timeout
,
110
);
do
{
i
=
inb
(
CDi_status
);
datarate
++
;
#if 00000
if (datarate>0x0FFFFFFF) break;
#endif 00000
}
while
(
!
timed_out
);
/* originally looping for 1.1 seconds */
CLEAR_TIMER
;
DPRINTF
((
DBG_TIM
,
"SBPCD: datarate: %d
\n
"
,
datarate
));
if
(
datarate
<
65536
)
datarate
=
65536
;
maxtim16
=
datarate
*
16
;
maxtim04
=
datarate
*
4
;
maxtim02
=
datarate
*
2
;
maxtim_8
=
datarate
/
32
;
#if MANY_SESSION
maxtim_data
=
datarate
/
100
;
#else
maxtim_data
=
datarate
/
300
;
#endif MANY_SESSION
DPRINTF
((
DBG_TIM
,
"SBPCD: maxtim_8 %d, maxtim_data %d.
\n
"
,
maxtim_8
,
maxtim_data
));
#endif CDMKE
}
/*==========================================================================*/
static
int
check_version
(
void
)
{
int
i
,
j
;
/* clear any pending error state */
clr_cmdbuf
();
drvcmd
[
0
]
=
0x82
;
response_count
=
9
;
flags_cmd_out
=
f_putcmd
;
cmd_out
();
/* read drive version */
clr_cmdbuf
();
for
(
i
=
0
;
i
<
12
;
i
++
)
infobuf
[
i
]
=
0
;
drvcmd
[
0
]
=
0x83
;
response_count
=
12
;
flags_cmd_out
=
f_putcmd
;
i
=
cmd_out
();
if
(
i
<
0
)
DPRINTF
((
DBG_INI
,
"SBPCD: cmd_83 returns %d
\n
"
,
i
));
DPRINTF
((
DBG_INI
,
"SBPCD: infobuf =
\"
"
));
for
(
i
=
0
;
i
<
12
;
i
++
)
DPRINTF
((
DBG_INI
,
"%c"
,
infobuf
[
i
]));
DPRINTF
((
DBG_INI
,
"
\"\n
"
));
for
(
i
=
0
;
i
<
4
;
i
++
)
if
(
infobuf
[
i
]
!=
drive_family
[
i
])
break
;
if
(
i
==
4
)
{
DS
[
d
].
drive_model
[
0
]
=
infobuf
[
i
++
];
DS
[
d
].
drive_model
[
1
]
=
infobuf
[
i
++
];
DS
[
d
].
drive_model
[
2
]
=
'-'
;
DS
[
d
].
drive_model
[
3
]
=
'x'
;
DS
[
d
].
drv_type
=
drv_new
;
}
else
{
for
(
i
=
0
;
i
<
8
;
i
++
)
if
(
infobuf
[
i
]
!=
drive_vendor
[
i
])
break
;
if
(
i
!=
8
)
return
(
-
1
);
DS
[
d
].
drive_model
[
0
]
=
'2'
;
DS
[
d
].
drive_model
[
1
]
=
'x'
;
DS
[
d
].
drive_model
[
2
]
=
'-'
;
DS
[
d
].
drive_model
[
3
]
=
'x'
;
DS
[
d
].
drv_type
=
drv_old
;
}
for
(
j
=
0
;
j
<
4
;
j
++
)
DS
[
d
].
firmware_version
[
j
]
=
infobuf
[
i
+
j
];
j
=
(
DS
[
d
].
firmware_version
[
0
]
&
0x0F
)
*
100
+
(
DS
[
d
].
firmware_version
[
2
]
&
0x0F
)
*
10
+
(
DS
[
d
].
firmware_version
[
3
]
&
0x0F
);
if
(
new_drive
)
{
if
(
j
<
100
)
DS
[
d
].
drv_type
=
drv_099
;
else
DS
[
d
].
drv_type
=
drv_100
;
}
else
if
(
j
<
200
)
DS
[
d
].
drv_type
=
drv_199
;
else
if
(
j
<
201
)
DS
[
d
].
drv_type
=
drv_200
;
else
if
(
j
<
210
)
DS
[
d
].
drv_type
=
drv_201
;
else
if
(
j
<
211
)
DS
[
d
].
drv_type
=
drv_210
;
else
if
(
j
<
300
)
DS
[
d
].
drv_type
=
drv_211
;
else
DS
[
d
].
drv_type
=
drv_300
;
return
(
0
);
}
/*==========================================================================*/
static
int
switch_drive
(
int
num
)
{
int
i
;
d
=
num
;
i
=
num
;
if
(
sbpro_type
)
i
=
(
i
&
0x01
)
<<
1
|
(
i
&
0x02
)
>>
1
;
OUT
(
CDo_enable
,
i
);
DPRINTF
((
DBG_DID
,
"SBPCD: switch_drive: drive %d activated.
\n
"
,
DS
[
d
].
drv_minor
));
return
(
0
);
}
/*==========================================================================*/
/*
* probe for the presence of drives on the selected controller
*/
static
int
check_drives
(
void
)
{
int
i
,
j
;
char
*
printk_header
=
""
;
DPRINTF
((
DBG_INI
,
"SBPCD: check_drives entered.
\n
"
));
ndrives
=
0
;
for
(
j
=
0
;
j
<
NR_SBPCD
;
j
++
)
{
DS
[
j
].
drv_minor
=
j
;
switch_drive
(
j
);
DPRINTF
((
DBG_ID
,
"SBPCD: check_drives: drive %d activated.
\n
"
,
j
));
i
=
check_version
();
DPRINTF
((
DBG_ID
,
"SBPCD: check_version returns %d.
\n
"
,
i
));
if
(
i
>=
0
)
{
ndrives
++
;
DS
[
d
].
drv_options
=
drv_pattern
[
j
];
if
(
!
new_drive
)
DS
[
d
].
drv_options
&=~
(
speed_auto
|
speed_300
|
speed_150
);
printk
(
"%sDrive %d: %s%.4s (%.4s)
\n
"
,
printk_header
,
DS
[
d
].
drv_minor
,
drive_family
,
DS
[
d
].
drive_model
,
DS
[
d
].
firmware_version
);
printk_header
=
" - "
;
}
else
DS
[
d
].
drv_minor
=-
1
;
}
if
(
ndrives
==
0
)
return
(
-
1
);
return
(
0
);
}
/*==========================================================================*/
#if 000
static void timewait(void)
{
int i;
for (i=0; i<65500; i++);
}
#endif 000
/*==========================================================================*/
#if FUTURE
/*
* obtain if requested service disturbs current audio state
*/
static
int
obey_audio_state
(
u_char
audio_state
,
u_char
func
,
u_char
subfunc
)
{
switch
(
audio_state
)
/* audio status from controller */
{
case
aud_11
:
/* "audio play in progress" */
case
audx11
:
switch
(
func
)
/* DOS command code */
{
case
cmd_07
:
/* input flush */
case
cmd_0d
:
/* open device */
case
cmd_0e
:
/* close device */
case
cmd_0c
:
/* ioctl output */
return
(
1
);
case
cmd_03
:
/* ioctl input */
switch
(
subfunc
)
/* DOS ioctl input subfunction */
{
case
cxi_00
:
case
cxi_06
:
case
cxi_09
:
return
(
1
);
default:
return
(
ERROR15
);
}
return
(
1
);
default:
return
(
ERROR15
);
}
return
(
1
);
case
aud_12
:
/* "audio play paused" */
case
audx12
:
return
(
1
);
default:
return
(
2
);
}
}
#endif FUTURE
/*==========================================================================*/
/* allowed is only
* ioctl_o, flush_input, open_device, close_device,
* tell_address, tell_volume, tell_capabiliti,
* tell_framesize, tell_CD_changed, tell_audio_posi
*/
static
int
check_allowed1
(
u_char
func1
,
u_char
func2
)
{
#if 000
if (func1==ioctl_o) return (0);
if (func1==read_long) return (-1);
if (func1==read_long_prefetch) return (-1);
if (func1==seek) return (-1);
if (func1==audio_play) return (-1);
if (func1==audio_pause) return (-1);
if (func1==audio_resume) return (-1);
if (func1!=ioctl_i) return (0);
if (func2==tell_SubQ_run_tot) return (-1);
if (func2==tell_cdsize) return (-1);
if (func2==tell_TocDescrip) return (-1);
if (func2==tell_TocEntry) return (-1);
if (func2==tell_subQ_info) return (-1);
if (new_drive) if (func2==tell_SubChanInfo) return (-1);
if (func2==tell_UPC) return (-1);
#else
return
(
0
);
#endif 000
}
/*==========================================================================*/
static
int
check_allowed2
(
u_char
func1
,
u_char
func2
)
{
#if 000
if (func1==read_long) return (-1);
if (func1==read_long_prefetch) return (-1);
if (func1==seek) return (-1);
if (func1==audio_play) return (-1);
if (func1!=ioctl_o) return (0);
if (new_drive)
{
if (func2==EjectDisk) return (-1);
if (func2==CloseTray) return (-1);
}
#else
return
(
0
);
#endif 000
}
/*==========================================================================*/
static
int
check_allowed3
(
u_char
func1
,
u_char
func2
)
{
#if 000
if (func1==ioctl_i)
{
if (func2==tell_address) return (0);
if (func2==tell_capabiliti) return (0);
if (func2==tell_CD_changed) return (0);
if (!new_drive) if (func2==tell_SubChanInfo) return (0);
return (-1);
}
if (func1==ioctl_o)
{
if (func2==DriveReset) return (0);
if (!new_drive)
{
if (func2==EjectDisk) return (0);
if (func2==LockDoor) return (0);
if (func2==CloseTray) return (0);
}
return (-1);
}
if (func1==flush_input) return (-1);
if (func1==read_long) return (-1);
if (func1==read_long_prefetch) return (-1);
if (func1==seek) return (-1);
if (func1==audio_play) return (-1);
if (func1==audio_pause) return (-1);
if (func1==audio_resume) return (-1);
#else
return
(
0
);
#endif 000
}
/*==========================================================================*/
static
int
seek_pos_audio_end
(
void
)
{
int
i
;
i
=
msf2blk
(
DS
[
d
].
pos_audio_end
)
-
1
;
if
(
i
<
0
)
return
(
-
1
);
i
=
xx_Seek
(
i
,
0
);
return
(
i
);
}
/*==========================================================================*/
static
int
ReadToC
(
void
)
{
int
i
,
j
;
DS
[
d
].
diskstate_flags
&=
~
toc_bit
;
DS
[
d
].
ored_ctl_adr
=
0
;
for
(
j
=
DS
[
d
].
n_first_track
;
j
<=
DS
[
d
].
n_last_track
;
j
++
)
{
i
=
xx_ReadTocEntry
(
j
);
if
(
i
<
0
)
return
(
i
);
DS
[
d
].
TocBuffer
[
j
].
nixbyte
=
DS
[
d
].
TocEnt_nixbyte
;
DS
[
d
].
TocBuffer
[
j
].
ctl_adr
=
DS
[
d
].
TocEnt_ctl_adr
;
DS
[
d
].
TocBuffer
[
j
].
number
=
DS
[
d
].
TocEnt_number
;
DS
[
d
].
TocBuffer
[
j
].
format
=
DS
[
d
].
TocEnt_format
;
DS
[
d
].
TocBuffer
[
j
].
address
=
DS
[
d
].
TocEnt_address
;
DS
[
d
].
ored_ctl_adr
|=
DS
[
d
].
TocEnt_ctl_adr
;
}
/* fake entry for LeadOut Track */
DS
[
d
].
TocBuffer
[
j
].
nixbyte
=
0
;
DS
[
d
].
TocBuffer
[
j
].
ctl_adr
=
0
;
DS
[
d
].
TocBuffer
[
j
].
number
=
0
;
DS
[
d
].
TocBuffer
[
j
].
format
=
0
;
DS
[
d
].
TocBuffer
[
j
].
address
=
DS
[
d
].
size_msf
;
DS
[
d
].
diskstate_flags
|=
toc_bit
;
return
(
0
);
}
/*==========================================================================*/
static
int
DiskInfo
(
void
)
{
int
i
;
i
=
SetSpeed
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: first SetSpeed returns %d
\n
"
,
i
));
i
=
SetSpeed
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: second SetSpeed returns %d
\n
"
,
i
));
return
(
i
);
}
}
i
=
xx_ModeSense
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: first xx_ModeSense returns %d
\n
"
,
i
));
i
=
xx_ModeSense
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: second xx_ModeSense returns %d
\n
"
,
i
));
return
(
i
);
}
return
(
i
);
}
i
=
xx_ReadCapacity
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: first ReadCapacity returns %d
\n
"
,
i
));
i
=
xx_ReadCapacity
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: second ReadCapacity returns %d
\n
"
,
i
));
return
(
i
);
}
return
(
i
);
}
i
=
xx_ReadTocDescr
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: ReadTocDescr returns %d
\n
"
,
i
));
return
(
i
);
}
i
=
ReadToC
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: ReadToC returns %d
\n
"
,
i
));
return
(
i
);
}
i
=
yy_CheckMultiSession
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: yy_CheckMultiSession returns %d
\n
"
,
i
));
return
(
i
);
}
i
=
xx_ReadTocEntry
(
DS
[
d
].
n_first_track
);
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: xx_ReadTocEntry(1) returns %d
\n
"
,
i
));
return
(
i
);
}
i
=
xx_ReadUPC
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: DiskInfo: xx_ReadUPC returns %d
\n
"
,
i
));
return
(
i
);
}
return
(
0
);
}
/*==========================================================================*/
/*
* called always if driver gets entered
* returns 0 or ERROR2 or ERROR15
*/
static
int
prepare
(
u_char
func
,
u_char
subfunc
)
{
int
i
;
if
(
!
new_drive
)
{
i
=
inb
(
CDi_status
);
if
(
i
&
s_attention
)
GetStatus
();
}
else
GetStatus
();
if
(
DS
[
d
].
CD_changed
==
0xFF
)
{
#if MANY_SESSION
#else
DS
[
d
].
diskstate_flags
=
0
;
#endif MANY_SESSION
DS
[
d
].
audio_state
=
0
;
if
(
!
st_diskok
)
{
i
=
check_allowed1
(
func
,
subfunc
);
if
(
i
<
0
)
return
(
-
2
);
}
else
{
i
=
check_allowed3
(
func
,
subfunc
);
if
(
i
<
0
)
{
DS
[
d
].
CD_changed
=
1
;
return
(
-
15
);
}
}
}
else
{
if
(
!
st_diskok
)
{
#if MANY_SESSION
#else
DS
[
d
].
diskstate_flags
=
0
;
#endif MANY_SESSION
DS
[
d
].
audio_state
=
0
;
i
=
check_allowed1
(
func
,
subfunc
);
if
(
i
<
0
)
return
(
-
2
);
}
else
{
if
(
st_busy
)
{
if
(
DS
[
d
].
audio_state
!=
audio_pausing
)
{
i
=
check_allowed2
(
func
,
subfunc
);
if
(
i
<
0
)
return
(
-
2
);
}
}
else
{
if
(
DS
[
d
].
audio_state
==
audio_playing
)
seek_pos_audio_end
();
DS
[
d
].
audio_state
=
0
;
}
if
(
!
frame_size_valid
)
{
i
=
DiskInfo
();
if
(
i
<
0
)
{
#if MANY_SESSION
#else
DS
[
d
].
diskstate_flags
=
0
;
#endif MANY_SESSION
DS
[
d
].
audio_state
=
0
;
i
=
check_allowed1
(
func
,
subfunc
);
if
(
i
<
0
)
return
(
-
2
);
}
}
}
}
return
(
0
);
}
/*==========================================================================*/
static
int
xx_PlayAudioMSF
(
int
pos_audio_start
,
int
pos_audio_end
)
{
int
i
;
if
(
DS
[
d
].
audio_state
==
audio_playing
)
return
(
-
EINVAL
);
clr_cmdbuf
();
if
(
new_drive
)
{
drvcmd
[
0
]
=
0x0E
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_ResponseStatus
|
f_obey_p_check
|
f_wait_if_busy
;
}
else
{
drvcmd
[
0
]
=
0x0B
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_lopsta
|
f_getsta
|
f_ResponseStatus
|
f_obey_p_check
|
f_wait_if_busy
;
}
drvcmd
[
1
]
=
(
pos_audio_start
>>
16
)
&
0x00FF
;
drvcmd
[
2
]
=
(
pos_audio_start
>>
8
)
&
0x00FF
;
drvcmd
[
3
]
=
pos_audio_start
&
0x00FF
;
drvcmd
[
4
]
=
(
pos_audio_end
>>
16
)
&
0x00FF
;
drvcmd
[
5
]
=
(
pos_audio_end
>>
8
)
&
0x00FF
;
drvcmd
[
6
]
=
pos_audio_end
&
0x00FF
;
response_count
=
0
;
i
=
cmd_out
();
return
(
i
);
}
/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/
/*
* ioctl support, adopted from scsi/sr_ioctl.c and mcd.c
*/
static
int
sbpcd_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
u_int
cmd
,
u_long
arg
)
{
int
i
,
st
;
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)
\n
"
,
MINOR
(
inode
->
i_rdev
),
cmd
,
arg
));
if
(
!
inode
)
return
(
-
EINVAL
);
st
=
GetStatus
();
if
(
st
<
0
)
return
(
-
EIO
);
if
(
!
toc_valid
)
{
i
=
DiskInfo
();
if
(
i
<
0
)
return
(
-
EIO
);
/* error reading TOC */
}
i
=
MINOR
(
inode
->
i_rdev
);
if
(
(
i
<
0
)
||
(
i
>=
NR_SBPCD
)
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: ioctl: bad device: %d
\n
"
,
i
));
return
(
-
ENODEV
);
/* no such drive */
}
switch_drive
(
i
);
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: device %d, request %04X
\n
"
,
i
,
cmd
));
switch
(
cmd
)
/* Sun-compatible */
{
case
DDIOCSDBG
:
/* DDI Debug */
if
(
!
suser
())
return
(
-
EPERM
);
i
=
verify_area
(
VERIFY_READ
,
(
int
*
)
arg
,
sizeof
(
int
));
if
(
i
>=
0
)
i
=
sbpcd_dbg_ioctl
(
arg
,
1
);
return
(
i
);
case
CDROMPAUSE
:
/* Pause the drive */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMPAUSE entered.
\n
"
));
/* pause the drive unit when it is currently in PLAY mode, */
/* or reset the starting and ending locations when in PAUSED mode. */
/* If applicable, at the next stopping point it reaches */
/* the drive will discontinue playing. */
switch
(
DS
[
d
].
audio_state
)
{
case
audio_playing
:
i
=
xx_Pause_Resume
(
1
);
if
(
i
<
0
)
return
(
-
EIO
);
DS
[
d
].
audio_state
=
audio_pausing
;
i
=
xx_ReadSubQ
();
if
(
i
<
0
)
return
(
-
EIO
);
DS
[
d
].
pos_audio_start
=
DS
[
d
].
SubQ_run_tot
;
return
(
0
);
case
audio_pausing
:
i
=
xx_Seek
(
DS
[
d
].
pos_audio_start
,
1
);
if
(
i
<
0
)
return
(
-
EIO
);
return
(
0
);
default:
return
(
-
EINVAL
);
}
case
CDROMRESUME
:
/* resume paused audio play */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMRESUME entered.
\n
"
));
/* resume playing audio tracks when a previous PLAY AUDIO call has */
/* been paused with a PAUSE command. */
/* It will resume playing from the location saved in SubQ_run_tot. */
if
(
DS
[
d
].
audio_state
!=
audio_pausing
)
return
-
EINVAL
;
i
=
xx_Pause_Resume
(
3
);
if
(
i
<
0
)
return
(
-
EIO
);
DS
[
d
].
audio_state
=
audio_playing
;
return
(
0
);
case
CDROMPLAYMSF
:
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMPLAYMSF entered.
\n
"
));
#if WORKMAN
if
(
DS
[
d
].
audio_state
==
audio_playing
)
{
i
=
xx_Pause_Resume
(
1
);
if
(
i
<
0
)
return
(
-
EIO
);
i
=
xx_ReadSubQ
();
if
(
i
<
0
)
return
(
-
EIO
);
DS
[
d
].
pos_audio_start
=
DS
[
d
].
SubQ_run_tot
;
i
=
xx_Seek
(
DS
[
d
].
pos_audio_start
,
1
);
}
#else
if
(
DS
[
d
].
audio_state
==
audio_playing
)
return
(
-
EINVAL
);
#endif
st
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_msf
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
msf
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_msf
));
/* values come as msf-bin */
DS
[
d
].
pos_audio_start
=
(
msf
.
cdmsf_min0
<<
16
)
|
(
msf
.
cdmsf_sec0
<<
8
)
|
msf
.
cdmsf_frame0
;
DS
[
d
].
pos_audio_end
=
(
msf
.
cdmsf_min1
<<
16
)
|
(
msf
.
cdmsf_sec1
<<
8
)
|
msf
.
cdmsf_frame1
;
DPRINTF
((
DBG_IOX
,
"SBPCD: ioctl: CDROMPLAYMSF %08X %08X
\n
"
,
DS
[
d
].
pos_audio_start
,
DS
[
d
].
pos_audio_end
));
i
=
xx_PlayAudioMSF
(
DS
[
d
].
pos_audio_start
,
DS
[
d
].
pos_audio_end
);
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: xx_PlayAudioMSF returns %d
\n
"
,
i
));
#if 0
if (i<0) return (-EIO);
#endif 0
DS
[
d
].
audio_state
=
audio_playing
;
return
(
0
);
case
CDROMPLAYTRKIND
:
/* Play a track. This currently ignores index. */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMPLAYTRKIND entered.
\n
"
));
if
(
DS
[
d
].
audio_state
==
audio_playing
)
{
DPRINTF
((
DBG_IOX
,
"SBPCD: CDROMPLAYTRKIND: already audio_playing.
\n
"
));
return
(
0
);
return
(
-
EINVAL
);
}
st
=
verify_area
(
VERIFY_READ
,(
void
*
)
arg
,
sizeof
(
struct
cdrom_ti
));
if
(
st
<
0
)
{
DPRINTF
((
DBG_IOX
,
"SBPCD: CDROMPLAYTRKIND: verify_area error.
\n
"
));
return
(
st
);
}
memcpy_fromfs
(
&
ti
,(
void
*
)
arg
,
sizeof
(
struct
cdrom_ti
));
DPRINTF
((
DBG_IOX
,
"SBPCD: ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d
\n
"
,
ti
.
cdti_trk0
,
ti
.
cdti_ind0
,
ti
.
cdti_trk1
,
ti
.
cdti_ind1
));
if
(
ti
.
cdti_trk0
<
DS
[
d
].
n_first_track
)
return
(
-
EINVAL
);
if
(
ti
.
cdti_trk0
>
DS
[
d
].
n_last_track
)
return
(
-
EINVAL
);
if
(
ti
.
cdti_trk1
<
ti
.
cdti_trk0
)
ti
.
cdti_trk1
=
ti
.
cdti_trk0
;
if
(
ti
.
cdti_trk1
>
DS
[
d
].
n_last_track
)
ti
.
cdti_trk1
=
DS
[
d
].
n_last_track
;
DS
[
d
].
pos_audio_start
=
DS
[
d
].
TocBuffer
[
ti
.
cdti_trk0
].
address
;
DS
[
d
].
pos_audio_end
=
DS
[
d
].
TocBuffer
[
ti
.
cdti_trk1
+
1
].
address
;
i
=
xx_PlayAudioMSF
(
DS
[
d
].
pos_audio_start
,
DS
[
d
].
pos_audio_end
);
#if 0
if (i<0) return (-EIO);
#endif 0
DS
[
d
].
audio_state
=
audio_playing
;
return
(
0
);
case
CDROMREADTOCHDR
:
/* Read the table of contents header */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMREADTOCHDR entered.
\n
"
));
tochdr
.
cdth_trk0
=
DS
[
d
].
n_first_track
;
tochdr
.
cdth_trk1
=
DS
[
d
].
n_last_track
;
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_tochdr
));
if
(
st
)
return
(
st
);
memcpy_tofs
((
void
*
)
arg
,
&
tochdr
,
sizeof
(
struct
cdrom_tochdr
));
return
(
0
);
case
CDROMREADTOCENTRY
:
/* Read an entry in the table of contents */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMREADTOCENTRY entered.
\n
"
));
st
=
verify_area
(
VERIFY_READ
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_tocentry
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
tocentry
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_tocentry
));
i
=
tocentry
.
cdte_track
;
if
(
i
==
CDROM_LEADOUT
)
i
=
DS
[
d
].
n_last_track
+
1
;
else
if
(
i
<
DS
[
d
].
n_first_track
||
i
>
DS
[
d
].
n_last_track
)
return
(
-
EINVAL
);
tocentry
.
cdte_adr
=
DS
[
d
].
TocBuffer
[
i
].
ctl_adr
&
0x0F
;
tocentry
.
cdte_ctrl
=
(
DS
[
d
].
TocBuffer
[
i
].
ctl_adr
>>
4
)
&
0x0F
;
tocentry
.
cdte_datamode
=
DS
[
d
].
TocBuffer
[
i
].
format
;
if
(
tocentry
.
cdte_format
==
CDROM_MSF
)
/* MSF-bin required */
{
tocentry
.
cdte_addr
.
msf
.
minute
=
(
DS
[
d
].
TocBuffer
[
i
].
address
>>
16
)
&
0x00FF
;
tocentry
.
cdte_addr
.
msf
.
second
=
(
DS
[
d
].
TocBuffer
[
i
].
address
>>
8
)
&
0x00FF
;
tocentry
.
cdte_addr
.
msf
.
frame
=
DS
[
d
].
TocBuffer
[
i
].
address
&
0x00FF
;
}
else
if
(
tocentry
.
cdte_format
==
CDROM_LBA
)
/* blk required */
tocentry
.
cdte_addr
.
lba
=
msf2blk
(
DS
[
d
].
TocBuffer
[
i
].
address
);
else
return
(
-
EINVAL
);
st
=
verify_area
(
VERIFY_WRITE
,(
void
*
)
arg
,
sizeof
(
struct
cdrom_tocentry
));
if
(
st
)
return
(
st
);
memcpy_tofs
((
void
*
)
arg
,
&
tocentry
,
sizeof
(
struct
cdrom_tocentry
));
return
(
0
);
case
CDROMSTOP
:
/* Spin down the drive */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMSTOP entered.
\n
"
));
i
=
DriveReset
();
#if WORKMAN
DS
[
d
].
CD_changed
=
0xFF
;
DS
[
d
].
diskstate_flags
=
0
;
#endif WORKMAN
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: DriveReset returns %d
\n
"
,
i
));
DS
[
d
].
audio_state
=
0
;
i
=
DiskInfo
();
return
(
0
);
case
CDROMSTART
:
/* Spin up the drive */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMSTART entered.
\n
"
));
i
=
xx_SpinUp
();
DS
[
d
].
audio_state
=
0
;
return
(
0
);
case
CDROMEJECT
:
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMEJECT entered.
\n
"
));
if
(
!
new_drive
)
return
(
0
);
#if WORKMAN
DS
[
d
].
CD_changed
=
0xFF
;
DS
[
d
].
diskstate_flags
=
0
;
#endif WORKMAN
i
=
yy_SpinDown
();
if
(
i
<
0
)
return
(
-
EIO
);
DS
[
d
].
audio_state
=
0
;
return
(
0
);
case
CDROMVOLCTRL
:
/* Volume control */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMVOLCTRL entered.
\n
"
));
st
=
verify_area
(
VERIFY_READ
,(
void
*
)
arg
,
sizeof
(
volctrl
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
volctrl
,(
char
*
)
arg
,
sizeof
(
volctrl
));
DS
[
d
].
vol_chan0
=
0
;
DS
[
d
].
vol_ctrl0
=
volctrl
.
channel0
;
DS
[
d
].
vol_chan1
=
1
;
DS
[
d
].
vol_ctrl1
=
volctrl
.
channel1
;
i
=
xx_SetVolume
();
return
(
0
);
case
CDROMSUBCHNL
:
/* Get subchannel info */
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMSUBCHNL entered.
\n
"
));
if
((
st_spinning
)
||
(
!
subq_valid
))
{
i
=
xx_ReadSubQ
();
if
(
i
<
0
)
return
(
-
EIO
);
}
st
=
verify_area
(
VERIFY_WRITE
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_subchnl
));
if
(
st
)
return
(
st
);
memcpy_fromfs
(
&
SC
,
(
void
*
)
arg
,
sizeof
(
struct
cdrom_subchnl
));
if
(
DS
[
d
].
SubQ_audio
==
0x80
)
DS
[
d
].
SubQ_audio
=
CDROM_AUDIO_NO_STATUS
;
SC
.
cdsc_audiostatus
=
DS
[
d
].
SubQ_audio
;
SC
.
cdsc_adr
=
DS
[
d
].
SubQ_ctl_adr
;
SC
.
cdsc_ctrl
=
DS
[
d
].
SubQ_ctl_adr
>>
4
;
SC
.
cdsc_trk
=
bcd2bin
(
DS
[
d
].
SubQ_trk
);
SC
.
cdsc_ind
=
bcd2bin
(
DS
[
d
].
SubQ_pnt_idx
);
if
(
SC
.
cdsc_format
==
CDROM_LBA
)
{
SC
.
cdsc_absaddr
.
lba
=
msf2blk
(
DS
[
d
].
SubQ_run_tot
);
SC
.
cdsc_reladdr
.
lba
=
msf2blk
(
DS
[
d
].
SubQ_run_trk
);
}
else
/* not only if (SC.cdsc_format==CDROM_MSF) */
{
SC
.
cdsc_absaddr
.
msf
.
minute
=
(
DS
[
d
].
SubQ_run_tot
>>
16
)
&
0x00FF
;
SC
.
cdsc_absaddr
.
msf
.
second
=
(
DS
[
d
].
SubQ_run_tot
>>
8
)
&
0x00FF
;
SC
.
cdsc_absaddr
.
msf
.
frame
=
DS
[
d
].
SubQ_run_tot
&
0x00FF
;
SC
.
cdsc_reladdr
.
msf
.
minute
=
(
DS
[
d
].
SubQ_run_trk
>>
16
)
&
0x00FF
;
SC
.
cdsc_reladdr
.
msf
.
second
=
(
DS
[
d
].
SubQ_run_trk
>>
8
)
&
0x00FF
;
SC
.
cdsc_reladdr
.
msf
.
frame
=
DS
[
d
].
SubQ_run_trk
&
0x00FF
;
}
memcpy_tofs
((
void
*
)
arg
,
&
SC
,
sizeof
(
struct
cdrom_subchnl
));
DPRINTF
((
DBG_IOC
,
"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X
\n
"
,
SC
.
cdsc_format
,
SC
.
cdsc_audiostatus
,
SC
.
cdsc_adr
,
SC
.
cdsc_ctrl
,
SC
.
cdsc_trk
,
SC
.
cdsc_ind
,
SC
.
cdsc_absaddr
,
SC
.
cdsc_reladdr
));
return
(
0
);
case
CDROMREADMODE2
:
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMREADMODE2 requested.
\n
"
));
return
(
-
EINVAL
);
case
CDROMREADMODE1
:
DPRINTF
((
DBG_IOC
,
"SBPCD: ioctl: CDROMREADMODE1 requested.
\n
"
));
return
(
-
EINVAL
);
default:
DPRINTF
((
DBG_IOX
,
"SBPCD: ioctl: unknown function request %04X
\n
"
,
cmd
));
return
(
-
EINVAL
);
}
/* end switch(cmd) */
}
/*==========================================================================*/
/*
* Take care of the different block sizes between cdrom and Linux.
* When Linux gets variable block sizes this will probably go away.
*/
static
void
sbp_transfer
(
void
)
{
long
offs
;
while
(
(
CURRENT
->
nr_sectors
>
0
)
&&
(
CURRENT
->
sector
/
4
>=
DS
[
d
].
sbp_first_frame
)
&&
(
CURRENT
->
sector
/
4
<=
DS
[
d
].
sbp_last_frame
)
)
{
offs
=
(
CURRENT
->
sector
-
DS
[
d
].
sbp_first_frame
*
4
)
*
512
;
memcpy
(
CURRENT
->
buffer
,
DS
[
d
].
sbp_buf
+
offs
,
512
);
CURRENT
->
nr_sectors
--
;
CURRENT
->
sector
++
;
CURRENT
->
buffer
+=
512
;
}
}
/*==========================================================================*/
/*
* We seem to get never an interrupt.
*/
#if SBPCD_USE_IRQ
static
void
sbpcd_interrupt
(
int
unused
)
{
int
st
;
st
=
inb
(
CDi_status
)
&
0xFF
;
DPRINTF
((
DBG_IRQ
,
"SBPCD: INTERRUPT received - CDi_status=%02X
\n
"
,
st
));
}
#endif SBPCD_USE_IRQ
/*==========================================================================*/
/*
* Called from the timer to check the results of the get-status cmd.
*/
static
int
sbp_status
(
void
)
{
int
st
;
st
=
ResponseStatus
();
if
(
st
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: sbp_status: timeout.
\n
"
));
return
(
0
);
}
if
(
!
st_spinning
)
DPRINTF
((
DBG_SPI
,
"SBPCD: motor got off - ignoring.
\n
"
));
if
(
st_check
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: st_check detected - retrying.
\n
"
));
return
(
0
);
}
if
(
!
st_door_closed
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: door is open - retrying.
\n
"
));
return
(
0
);
}
if
(
!
st_caddy_in
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: disk removed - retrying.
\n
"
));
return
(
0
);
}
if
(
!
st_diskok
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: !st_diskok detected - retrying.
\n
"
));
return
(
0
);
}
if
(
st_busy
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: st_busy detected - retrying.
\n
"
));
return
(
0
);
}
return
(
1
);
}
/*==========================================================================*/
/*
* I/O request routine, called from Linux kernel.
*/
static
void
do_sbpcd_request
(
void
)
{
u_int
block
;
int
dev
;
u_int
nsect
;
int
i
,
status_tries
,
data_tries
;
request_loop:
sti
();
if
((
CURRENT
==
NULL
)
||
(
CURRENT
->
dev
<
0
))
return
;
if
(
CURRENT
->
sector
==
-
1
)
return
;
dev
=
MINOR
(
CURRENT
->
dev
);
if
(
(
dev
<
0
)
||
(
dev
>=
NR_SBPCD
)
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: do_request: bad device: %d
\n
"
,
dev
));
return
;
}
switch_drive
(
dev
);
INIT_REQUEST
;
block
=
CURRENT
->
sector
;
nsect
=
CURRENT
->
nr_sectors
;
if
(
CURRENT
->
cmd
!=
READ
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: bad cmd %d
\n
"
,
CURRENT
->
cmd
));
end_request
(
0
);
goto
request_loop
;
}
DPRINTF
((
DBG_MUL
,
"SBPCD: read LBA %d
\n
"
,
block
/
4
));
sbp_transfer
();
/* if we satisfied the request from the buffer, we're done. */
if
(
CURRENT
->
nr_sectors
==
0
)
{
end_request
(
1
);
goto
request_loop
;
}
i
=
prepare
(
0
,
0
);
/* at moment not really a hassle check, but ... */
if
(
i
!=
0
)
DPRINTF
((
DBG_INF
,
"SBPCD:
\"
prepare
\"
tells error %d -- ignored
\n
"
,
i
));
if
(
!
st_spinning
)
xx_SpinUp
();
for
(
data_tries
=
3
;
data_tries
>
0
;
data_tries
--
)
{
for
(
status_tries
=
3
;
status_tries
>
0
;
status_tries
--
)
{
flags_cmd_out
|=
f_respo3
;
xx_ReadStatus
();
if
(
sbp_status
()
!=
0
)
break
;
sbp_sleep
(
1
);
/* wait a bit, try again */
}
if
(
status_tries
==
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: sbp_status: failed after 3 tries
\n
"
));
break
;
}
sbp_read_cmd
();
sbp_sleep
(
0
);
if
(
sbp_data
()
!=
0
)
{
end_request
(
1
);
goto
request_loop
;
}
}
end_request
(
0
);
sbp_sleep
(
10
);
/* wait a bit, try again */
goto
request_loop
;
}
/*==========================================================================*/
/*
* build and send the READ command.
* Maybe it would be better to "set mode1" before ...
*/
static
void
sbp_read_cmd
(
void
)
{
int
i
;
int
block
;
DS
[
d
].
sbp_first_frame
=
DS
[
d
].
sbp_last_frame
=-
1
;
/* purge buffer */
block
=
CURRENT
->
sector
/
4
;
if
(
new_drive
)
{
#if MANY_SESSION
DPRINTF
((
DBG_MUL
,
"SBPCD: read MSF %08X
\n
"
,
blk2msf
(
block
)));
if
(
(
DS
[
d
].
f_multisession
)
&&
(
multisession_valid
)
)
{
DPRINTF
((
DBG_MUL
,
"SBPCD: MultiSession: use %08X for %08X (msf)
\n
"
,
blk2msf
(
DS
[
d
].
lba_multi
+
block
),
blk2msf
(
block
)));
block
=
DS
[
d
].
lba_multi
+
block
;
}
#else
if
(
(
block
==
166
)
&&
(
DS
[
d
].
f_multisession
)
&&
(
multisession_valid
)
)
{
DPRINTF
((
DBG_MUL
,
"SBPCD: MultiSession: use %08X for %08X (msf)
\n
"
,
blk2msf
(
DS
[
d
].
lba_multi
+
16
),
blk2msf
(
block
)));
block
=
DS
[
d
].
lba_multi
+
16
;
}
#endif MANY_SESSION
}
if
(
block
+
SBP_BUFFER_FRAMES
<=
DS
[
d
].
CDsize_frm
)
DS
[
d
].
sbp_read_frames
=
SBP_BUFFER_FRAMES
;
else
{
DS
[
d
].
sbp_read_frames
=
DS
[
d
].
CDsize_frm
-
block
;
/* avoid reading past end of data */
if
(
DS
[
d
].
sbp_read_frames
<
1
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: requested frame %d, CD size %d ???
\n
"
,
block
,
DS
[
d
].
CDsize_frm
));
DS
[
d
].
sbp_read_frames
=
1
;
}
}
DS
[
d
].
sbp_current
=
0
;
flags_cmd_out
=
f_putcmd
|
f_respo2
|
f_ResponseStatus
|
f_obey_p_check
;
if
(
!
new_drive
)
{
if
(
DS
[
d
].
drv_type
>=
drv_201
)
{
lba2msf
(
block
,
&
drvcmd
[
1
]);
/* msf-bcd format required */
bin2bcdx
(
&
drvcmd
[
1
]);
bin2bcdx
(
&
drvcmd
[
2
]);
bin2bcdx
(
&
drvcmd
[
3
]);
}
else
{
drvcmd
[
1
]
=
(
block
>>
16
)
&
0x000000ff
;
drvcmd
[
2
]
=
(
block
>>
8
)
&
0x000000ff
;
drvcmd
[
3
]
=
block
&
0x000000ff
;
}
drvcmd
[
4
]
=
0
;
drvcmd
[
5
]
=
DS
[
d
].
sbp_read_frames
;
drvcmd
[
6
]
=
(
DS
[
d
].
drv_type
<
drv_201
)
?
0
:
2
;
/* flag "lba or msf-bcd format" */
drvcmd
[
0
]
=
0x02
;
/* "read frames" command for old drives */
flags_cmd_out
|=
f_lopsta
|
f_getsta
|
f_bit1
;
}
else
/* if new_drive */
{
lba2msf
(
block
,
&
drvcmd
[
1
]);
/* msf-bin format required */
drvcmd
[
4
]
=
0
;
drvcmd
[
5
]
=
0
;
drvcmd
[
6
]
=
DS
[
d
].
sbp_read_frames
;
drvcmd
[
0
]
=
0x10
;
/* "read frames" command for new drives */
}
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
for
(
i
=
0
;
i
<
7
;
i
++
)
OUT
(
CDo_command
,
drvcmd
[
i
]);
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
return
;
}
/*==========================================================================*/
/*
* Check the completion of the read-data command. On success, read
* the SBP_BUFFER_FRAMES * 2048 bytes of data from the disk into buffer.
*/
static
int
sbp_data
(
void
)
{
int
i
=
0
,
j
=
0
,
frame
;
u_int
try
=
0
;
u_long
timeout
;
u_char
*
p
;
u_int
data_tries
=
0
;
u_int
data_waits
=
0
;
u_int
data_retrying
=
0
;
int
error_flag
;
error_flag
=
0
;
for
(
frame
=
DS
[
d
].
sbp_current
;
frame
<
DS
[
d
].
sbp_read_frames
&&!
error_flag
;
frame
++
)
{
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
try
=
maxtim_data
;
for
(
timeout
=
jiffies
+
100
;
;
)
{
for
(
;
try
!=
0
;
try
--
)
{
j
=
inb
(
CDi_status
);
if
(
!
(
j
&
s_not_data_ready
))
break
;
if
(
!
(
j
&
s_not_result_ready
))
break
;
if
(
!
new_drive
)
if
(
j
&
s_attention
)
break
;
}
if
(
try
!=
0
||
timeout
<=
jiffies
)
break
;
if
(
data_retrying
==
0
)
data_waits
++
;
data_retrying
=
1
;
sbp_sleep
(
1
);
try
=
1
;
}
if
(
try
==
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: sbp_data: CDi_status timeout.
\n
"
));
error_flag
++
;
break
;
}
if
(
j
&
s_not_data_ready
)
{
if
((
DS
[
d
].
ored_ctl_adr
&
0x40
)
==
0
)
DPRINTF
((
DBG_INF
,
"SBPCD: CD contains no data tracks.
\n
"
));
else
DPRINTF
((
DBG_INF
,
"SBPCD: sbp_data: DATA_READY timeout.
\n
"
));
error_flag
++
;
break
;
}
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
CLEAR_TIMER
;
error_flag
=
0
;
p
=
DS
[
d
].
sbp_buf
+
frame
*
CD_FRAMESIZE
;
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x01
);
READ_DATA
(
CDi_data
,
p
,
CD_FRAMESIZE
);
if
(
sbpro_type
)
OUT
(
CDo_sel_d_i
,
0x00
);
DS
[
d
].
sbp_current
++
;
data_tries
++
;
data_retrying
=
0
;
if
(
data_tries
>=
1000
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: info: %d waits in %d frames.
\n
"
,
data_waits
,
data_tries
));
data_waits
=
data_tries
=
0
;
}
}
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
if
(
error_flag
)
/* must have been spurious D_RDY or (ATTN&&!D_RDY) */
{
DPRINTF
((
DBG_INF
,
"SBPCD: read aborted by drive
\n
"
));
i
=
DriveReset
();
/* ugly fix to prevent a hang */
return
(
0
);
}
if
(
!
new_drive
)
{
#if SBPCD_DIS_IRQ
cli
();
#endif SBPCD_DIS_IRQ
i
=
maxtim_data
;
for
(
timeout
=
jiffies
+
100
;
timeout
>
jiffies
;
timeout
--
)
{
for
(
;
i
!=
0
;
i
--
)
{
j
=
inb
(
CDi_status
);
if
(
!
(
j
&
s_not_data_ready
))
break
;
if
(
!
(
j
&
s_not_result_ready
))
break
;
if
(
j
&
s_attention
)
break
;
}
if
(
i
!=
0
||
timeout
<=
jiffies
)
break
;
sbp_sleep
(
0
);
i
=
1
;
}
if
(
i
==
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: STATUS TIMEOUT AFTER READ"
));
}
if
(
!
(
j
&
s_attention
))
{
DPRINTF
((
DBG_INF
,
"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying
\n
"
));
i
=
DriveReset
();
/* ugly fix to prevent a hang */
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
return
(
0
);
}
#if SBPCD_DIS_IRQ
sti
();
#endif SBPCD_DIS_IRQ
}
do
{
if
(
!
new_drive
)
xx_ReadStatus
();
i
=
ResponseStatus
();
/* builds status_byte, returns orig. status (old) or faked p_success_old (new) */
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: xx_ReadStatus error after read: %02X
\n
"
,
DS
[
d
].
status_byte
));
return
(
0
);
}
}
while
((
!
new_drive
)
&&
(
!
st_check
)
&&
(
!
(
i
&
p_success_old
)));
if
(
st_check
)
{
i
=
xx_ReadError
();
DPRINTF
((
DBG_INF
,
"SBPCD: xx_ReadError was necessary after read: %02X
\n
"
,
i
));
return
(
0
);
}
DS
[
d
].
sbp_first_frame
=
CURRENT
->
sector
/
4
;
DS
[
d
].
sbp_last_frame
=
DS
[
d
].
sbp_first_frame
+
DS
[
d
].
sbp_read_frames
-
1
;
sbp_transfer
();
return
(
1
);
}
/*==========================================================================*/
/*==========================================================================*/
/*
* Open the device special file. Check that a disk is in. Read TOC.
*/
int
sbpcd_open
(
struct
inode
*
ip
,
struct
file
*
fp
)
{
int
i
;
if
(
ndrives
==
0
)
return
(
-
ENXIO
);
/* no hardware */
i
=
MINOR
(
ip
->
i_rdev
);
if
(
(
i
<
0
)
||
(
i
>=
NR_SBPCD
)
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: open: bad device: %d
\n
"
,
i
));
return
(
-
ENODEV
);
/* no such drive */
}
switch_drive
(
i
);
if
(
!
st_spinning
)
xx_SpinUp
();
flags_cmd_out
|=
f_respo2
;
xx_ReadStatus
();
/* command: give 1-byte status */
i
=
ResponseStatus
();
if
(
i
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: sbpcd_open: xx_ReadStatus timed out
\n
"
));
return
(
-
EIO
);
/* drive doesn't respond */
}
DPRINTF
((
DBG_STA
,
"SBPCD: sbpcd_open: status %02X
\n
"
,
DS
[
d
].
status_byte
));
if
(
!
st_door_closed
||!
st_caddy_in
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: sbpcd_open: no disk in drive
\n
"
));
return
(
-
EIO
);
}
/*
* we could try to keep an "open" counter here and lock the door if 0->1.
* not done yet.
*/
if
(
!
st_spinning
)
xx_SpinUp
();
i
=
DiskInfo
();
if
((
DS
[
d
].
ored_ctl_adr
&
0x40
)
==
0
)
DPRINTF
((
DBG_INF
,
"SBPCD: CD contains no data tracks.
\n
"
));
return
(
0
);
}
/*==========================================================================*/
/*
* On close, we flush all sbp blocks from the buffer cache.
*/
static
void
sbpcd_release
(
struct
inode
*
ip
,
struct
file
*
file
)
{
int
i
;
/*
* we could try to count down an "open" counter here
* and unlock the door if zero.
* not done yet.
*/
i
=
MINOR
(
ip
->
i_rdev
);
if
(
(
i
<
0
)
||
(
i
>=
NR_SBPCD
)
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: release: bad device: %d
\n
"
,
i
));
return
;
}
switch_drive
(
i
);
DS
[
d
].
sbp_first_frame
=
DS
[
d
].
sbp_last_frame
=-
1
;
sync_dev
(
ip
->
i_rdev
);
/* nonsense if read only device? */
invalidate_buffers
(
ip
->
i_rdev
);
DS
[
d
].
diskstate_flags
&=
~
cd_size_bit
;
}
/*==========================================================================*/
/*
*
*/
static
struct
file_operations
sbpcd_fops
=
{
NULL
,
/* lseek - default */
block_read
,
/* read - general block-dev read */
block_write
,
/* write - general block-dev write */
NULL
,
/* readdir - bad */
NULL
,
/* select */
sbpcd_ioctl
,
/* ioctl */
NULL
,
/* mmap */
sbpcd_open
,
/* open */
sbpcd_release
/* release */
};
/*==========================================================================*/
/*
* SBP interrupt descriptor
*/
#if SBPCD_USE_IRQ
static
struct
sigaction
sbpcd_sigaction
=
{
sbpcd_interrupt
,
0
,
SA_INTERRUPT
,
NULL
};
#endif SBPCD_USE_IRQ
/*==========================================================================*/
/*
* accept "kernel command line" parameters
* (suggested by Peter MacDonald with SLS 1.03)
*
* use: tell LILO:
* sbpcd=0x230,SoundBlaster
* or
* sbpcd=0x300,LaserMate
*
* (upper/lower case sensitive here!!!).
*
* the address value has to be the TRUE CDROM PORT ADDRESS -
* not the soundcard base address.
*
*/
void
sbpcd_setup
(
char
*
s
,
int
*
p
)
{
DPRINTF
((
DBG_INI
,
"SBPCD: sbpcd_setup called with %04X,%s
\n
"
,
p
[
1
],
s
));
if
(
!
strcmp
(
s
,
str_sb
))
sbpro_type
=
1
;
else
sbpro_type
=
0
;
if
(
p
[
0
]
>
0
)
sbpcd_ioaddr
=
p
[
1
];
CDo_command
=
sbpcd_ioaddr
;
CDi_info
=
sbpcd_ioaddr
;
CDi_status
=
sbpcd_ioaddr
+
1
;
CDo_reset
=
sbpcd_ioaddr
+
2
;
CDo_enable
=
sbpcd_ioaddr
+
3
;
if
(
sbpro_type
==
1
)
{
MIXER_addr
=
sbpcd_ioaddr
-
0x10
+
0x04
;
MIXER_data
=
sbpcd_ioaddr
-
0x10
+
0x05
;
CDo_sel_d_i
=
sbpcd_ioaddr
+
1
;
CDi_data
=
sbpcd_ioaddr
;
}
else
CDi_data
=
sbpcd_ioaddr
+
2
;
}
/*==========================================================================*/
/*
* Test for presence of drive and initialize it. Called at boot time.
*/
u_long
sbpcd_init
(
u_long
mem_start
,
u_long
mem_end
)
{
int
i
=
0
,
j
=
0
;
int
addr
[
2
]
=
{
1
,
CDROM_PORT
};
int
port_index
;
DPRINTF
((
DBG_INF
,
"SBPCD version %s
\n
"
,
VERSION
));
DPRINTF
((
DBG_INF
,
"SBPCD: Looking for a SoundBlaster/Matsushita CD-ROM drive
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD:
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: = = = = = = = = = = W A R N I N G = = = = = = = = = =
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: Auto-Probing can cause a hang (f.e. touching an ethernet card).
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: If that happens, you have to reboot and use the
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: LILO (kernel) command line feature like:
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD:
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: LILO boot: linux sbpcd=0x230,SoundBlaster
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: or like:
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: LILO boot: linux sbpcd=0x300,LaserMate
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD:
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: with your REAL address.
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =
\n
"
));
DPRINTF
((
DBG_WRN
,
"SBPCD:
\n
"
));
sti
();
/* to avoid possible "printk" bug */
autoprobe
[
0
]
=
sbpcd_ioaddr
;
/* possibly changed by kernel command line */
autoprobe
[
1
]
=
sbpro_type
;
/* possibly changed by kernel command line */
for
(
port_index
=
0
;
port_index
<
NUM_AUTOPROBE
;
port_index
+=
2
)
{
addr
[
1
]
=
autoprobe
[
port_index
];
if
(
check_region
(
addr
[
1
],
4
))
continue
;
DPRINTF
((
DBG_INI
,
"SBPCD: check_region done.
\n
"
));
if
(
autoprobe
[
port_index
+
1
]
==
0
)
type
=
str_lm
;
else
type
=
str_sb
;
sbpcd_setup
(
type
,
addr
);
DPRINTF
((
DBG_INF
,
"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.
\n
"
,
type
,
CDo_command
));
DPRINTF
((
DBG_INF
,
"SBPCD: - "
));
sti
();
/* to avoid possible "printk" bug */
i
=
check_drives
();
DPRINTF
((
DBG_INI
,
"SBPCD: check_drives done.
\n
"
));
sti
();
/* to avoid possible "printk" bug */
if
(
i
>=
0
)
break
;
/* drive found */
printk
(
"
\n
"
);
sti
();
/* to avoid possible "printk" bug */
}
/* end of cycling through the set of possible I/O port addresses */
if
(
ndrives
==
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: No drive found.
\n
"
));
sti
();
return
(
mem_start
);
}
DPRINTF
((
DBG_INF
,
"SBPCD: %d %s CD-ROM drive(s) at 0x%04X.
\n
"
,
ndrives
,
type
,
CDo_command
));
sti
();
/* to avoid possible "printk" bug */
check_datarate
();
DPRINTF
((
DBG_INI
,
"SBPCD: check_datarate done.
\n
"
));
sti
();
/* to avoid possible "printk" bug */
for
(
j
=
0
;
j
<
NR_SBPCD
;
j
++
)
{
if
(
DS
[
j
].
drv_minor
==-
1
)
continue
;
switch_drive
(
j
);
xy_DriveReset
();
if
(
!
st_spinning
)
xx_SpinUp
();
DS
[
d
].
sbp_first_frame
=
-
1
;
/* First frame in buffer */
DS
[
d
].
sbp_last_frame
=
-
1
;
/* Last frame in buffer */
DS
[
d
].
sbp_read_frames
=
0
;
/* Number of frames being read to buffer */
DS
[
d
].
sbp_current
=
0
;
/* Frame being currently read */
DS
[
d
].
CD_changed
=
1
;
DS
[
d
].
frame_size
=
CD_FRAMESIZE
;
xx_ReadStatus
();
i
=
ResponseStatus
();
/* returns orig. status or p_busy_new */
if
(
i
<
0
)
DPRINTF
((
DBG_INF
,
"SBPCD: init: ResponseStatus returns %02X
\n
"
,
i
));
else
{
if
(
st_check
)
{
i
=
xx_ReadError
();
DPRINTF
((
DBG_INI
,
"SBPCD: init: xx_ReadError returns %d
\n
"
,
i
));
sti
();
/* to avoid possible "printk" bug */
}
}
DPRINTF
((
DBG_INI
,
"SBPCD: init: first GetStatus: %d
\n
"
,
i
));
sti
();
/* to avoid possible "printk" bug */
if
(
DS
[
d
].
error_byte
==
aud_12
)
{
do
{
i
=
GetStatus
();
DPRINTF
((
DBG_INI
,
"SBPCD: init: second GetStatus: %02X
\n
"
,
i
));
sti
();
/* to avoid possible "printk" bug */
if
(
i
<
0
)
break
;
if
(
!
st_caddy_in
)
break
;
}
while
(
!
st_diskok
);
}
i
=
SetSpeed
();
if
(
i
>=
0
)
DS
[
d
].
CD_changed
=
1
;
}
if
(
sbpro_type
)
{
OUT
(
MIXER_addr
,
MIXER_CD_Volume
);
OUT
(
MIXER_data
,
0xCC
);
/* one nibble per channel */
}
if
(
register_blkdev
(
MATSUSHITA_CDROM_MAJOR
,
"sbpcd"
,
&
sbpcd_fops
)
!=
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: Can't get MAJOR %d for Matsushita CDROM
\n
"
,
MATSUSHITA_CDROM_MAJOR
));
sti
();
/* to avoid possible "printk" bug */
return
(
mem_start
);
}
blk_dev
[
MATSUSHITA_CDROM_MAJOR
].
request_fn
=
DEVICE_REQUEST
;
read_ahead
[
MATSUSHITA_CDROM_MAJOR
]
=
4
;
/* just one frame */
snarf_region
(
CDo_command
,
4
);
#if SBPCD_USE_IRQ
if
(
irqaction
(
SBPCD_INTR_NR
,
&
sbpcd_sigaction
))
{
DPRINTF
((
DBG_INF
,
"SBPCD: Can't get IRQ%d for sbpcd driver
\n
"
,
SBPCD_INTR_NR
));
sti
();
/* to avoid possible "printk" bug */
}
#endif SBPCD_USE_IRQ
/*
* allocate memory for the frame buffers
*/
for
(
j
=
0
;
j
<
NR_SBPCD
;
j
++
)
{
if
(
DS
[
j
].
drv_minor
==-
1
)
continue
;
DS
[
j
].
sbp_buf
=
(
u_char
*
)
mem_start
;
mem_start
+=
SBP_BUFFER_FRAMES
*
CD_FRAMESIZE
;
}
DPRINTF
((
DBG_INF
,
"SBPCD: init done.
\n
"
));
sti
();
/* to avoid possible "printk" bug */
return
(
mem_start
);
}
/*==========================================================================*/
/*
* adopted from sr.c
*
* Check if the media has changed in the CD-ROM drive.
* used externally (isofs/inode.c) - but still does not work.
*
*/
int
check_sbpcd_media_change
(
int
full_dev
,
int
unused_minor
)
{
int
st
;
if
(
MAJOR
(
full_dev
)
!=
MATSUSHITA_CDROM_MAJOR
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: media_check: invalid device.
\n
"
));
return
(
-
1
);
}
xx_ReadStatus
();
/* command: give 1-byte status */
st
=
ResponseStatus
();
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check: %02X
\n
"
,
DS
[
d
].
status_byte
));
if
(
st
<
0
)
{
DPRINTF
((
DBG_INF
,
"SBPCD: media_check: ResponseStatus error.
\n
"
));
return
(
1
);
/* status not obtainable */
}
if
(
DS
[
d
].
CD_changed
==
0xFF
)
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check:
\"
changed
\"
assumed.
\n
"
));
if
(
!
st_spinning
)
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check: motor off.
\n
"
));
if
(
!
st_door_closed
)
{
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check: door open.
\n
"
));
DS
[
d
].
CD_changed
=
0xFF
;
}
if
(
!
st_caddy_in
)
{
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check: no disk in drive.
\n
"
));
DS
[
d
].
CD_changed
=
0xFF
;
}
if
(
!
st_diskok
)
DPRINTF
((
DBG_CHK
,
"SBPCD: media_check: !st_diskok.
\n
"
));
#if 0000
if (DS[d].CD_changed==0xFF)
{
DS[d].CD_changed=1;
return (1); /* driver had a change detected before */
}
#endif 0000 /* seems to give additional errors at the moment */
if
(
!
st_diskok
)
return
(
1
);
/* disk not o.k. */
if
(
!
st_caddy_in
)
return
(
1
);
/* disk removed */
if
(
!
st_door_closed
)
return
(
1
);
/* door open */
return
(
0
);
}
/*==========================================================================*/
drivers/char/console.c
View file @
3448e1a6
...
...
@@ -213,7 +213,7 @@ static int screen_size = 0;
#define VT102ID "\033[?6c"
static
unsigned
char
*
translations
[]
=
{
/* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
/* 8-bit Latin-1 mapped to the PC chara
c
ter set: '\0' means non-printable */
(
unsigned
char
*
)
"
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
"
"
\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0
"
...
...
drivers/char/tty_ioctl.c
View file @
3448e1a6
...
...
@@ -213,24 +213,9 @@ static int set_termios_2(struct tty_struct * tty, struct termios * termios)
wake_up_interruptible
(
&
tty
->
link
->
secondary
.
proc_list
);
}
#if 0
/* puting mpty's into echo mode is very bad, and I think under
some situations can cause the kernel to do nothing but
copy characters back and forth. -RAB */
/* This can no longer happen because a set_termios is redirected
to the pty slave. -- jrs */
if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
#endif
unset_locked_termios
(
tty
->
termios
,
&
old_termios
,
termios_locked
[
tty
->
line
]);
#if 0
retval = tty_set_ldisc(tty, tty->termios->c_line);
if (retval)
return retval;
#endif
if
(
tty
->
set_termios
)
(
*
tty
->
set_termios
)(
tty
,
&
old_termios
);
...
...
drivers/net/CONFIG
View file @
3448e1a6
#
# Set any special options here. Most drivers will autoprobe/autoIRQ
# if you set the address or IRQ to zero, so we do that by default.
# Cards and options supported:
# This file is used for selecting non-standard netcard options, and
# need not be modified for typical use.
#
# Drivers are *not* selected in this file, but rather with files
# automatically generated during the top-level kernel configuration.
#
# Special options supported, indexed by their 'config' name:
#
# EI_DEBUG Set the debugging level for 8390-based boards
# CONFIG_WD80x3 The Western Digital (SMC) WD80x3 driver
# WD_SHMEM=xxx Forces the address of the shared memory
# WD_no_mapout Don't map out the shared memory (faster, but
...
...
@@ -16,28 +19,37 @@
# rw_bugfix Patch an obscure bug with a version of the 8390.
# CONFIG_HPLAN The HP-LAN driver (for 8390-based boards only).
# rw_bugfix Fix the same obscure bug.
# CONFIG_EL1 The 3c501 driver (just joking, never released)
# CONFIG_EL2 The 3c503 EtherLink II driver
# EL2_AUI Default to the AUI port instead of the BNC port
# no_probe_nonshared_memory Don't probe for programmed-I/O boards.
# EL2MEMTEST Test shared memory at boot-time.
# CONFIG_EL3
# EL3_DEBUG Set the debugging message level.
# CONFIG_AT1500
# LANCE_DEBUG Set the debugging message level.
# DEFAULT_DMA Change the default DMA to other than 5.
# CONFIG_PLIP The Crynwr-protocol PL/IP driver
# INITIALTIMEOUTFACTOR Timing parameters.
# MAXTIMEOUTFACTOR
# D_LINK The D-Link DE-600 Portable Ethernet Adaptor.
# D_LINK_IO The D-Link I/O address (0x378 ==
default
)
# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 ==
default
)
# D_LINK_IO The D-Link I/O address (0x378 ==
typical
)
# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 ==
typical
)
# D_LINK_DEBUG Enable or disable D-Link debugging
#
OPTS = #-DEI8390=0 -DEI8390_IRQ=0
WD_OPTS = #-DWD_SHMEM=0
EL2_OPTS = #-UEL2_AUI
# The following options exist, but cannot be set in this file.
# lance.c
# LANCE_DMA Change the default DMA to other than DMA5.
# 8390.c
# NO_PINGPONG Disable ping-pong transmit buffers.
# Most drivers also have a *_DEBUG setting that may be adjusted.
# The 8390 drivers share the EI_DEBUG settting.
# General options for Space.c
OPTS = # -DETH0_ADDR=0x300 -DETH0_IRQ=11
WD_OPTS = #-DWD_SHMEM=0xDD000
EL2_OPTS = #-DEL2_AUI
NE_OPTS =
HP_OPTS =
PLIP_OPTS =
# The following are the only parameters that must be set in this file.
DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
AT_OPTS = # -DLANCE_DMA=5
drivers/net/README.8390
deleted
100644 → 0
View file @
3ba1ba97
These drivers support all common 8390-based ethernet boards. Currently
"common" is defined as:
3Com Products:
* 3Com 3c503 Board loaned by Chance Reschke, USRA.edu (thanks!)
3Com 3c503/16 and excellent documentation provided by 3Com.
Clones-n-things
NE1000 Novell and Eagle are useless for documentation,
* NE2000 but copied the designs directly from NatSemi;->.
WD/SMC products
WD8003
* WD8013 Board loaned by Russ Nelson, Crynwr Software. Thanks!
* I've seen it work myself!
There is support for the following boards, but since I've only been
able to borrow a thinnet of an HP ethercard I've relied upon reports
from others:
HP LAN adaptors
** HP27245
** HP27247
** HP27250
Thanks are due to the dozens of alpha testers. Special thanks are due
to Chance Reschke <@usra.edu> and Russ Nelson <@crynwr.com> for
loaning me ethercards.
The following addresses are autoprobed, in this order:
wd.c: 0x300, 0x280, 0x380, 0x240
3c503: 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2a0, 0x2e0
ne.c: 0x300, 0x280, 0x320, 0x340, 0x360
hp.c: 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240
80x3 clones that are reported to work:
LANNET LEC-45
"NE2000" clones that are reported to work:
Alta Combo(NE2000 clone)
Aritsoft LANtastic AE-2 (NE2000 clone w/ extra memory)
Asante Etherpak 2001/2003
D-Link Ethernet II
LTC E-NET/16 P/N: 8300-200-002 (lipka@lip.hanse.de)
Network Solutions HE-203
SVEC 4 Dimension Ethernet
4-Dimension FD0490 EtherBoard16
Cabletron products:
E1010 No ID PROM and sketchy info from Ctron means you'll
E1010-x have to compile-in information about your board.
E2010
E2010-x
N.B. The E2100 will not work with Linux until Cabletron
releases the programming information!
Important defines
For Space.c
#define EI8390 0 /* The base address of your ethercard. */
#define EI8390_IRQ 0 /* and the interrupt you want to use. */
/* '0' means autoconfigure */
For 8390.c
#define EI_DEBUG 2 /* Use '0' for no messages. */
#define EL2 /* For the 3c503 driver. */
#define NE2000 /* For the NE1000/NE2000/Ctron driver. */
#define WD80x3 /* For the WD8003/WD8013 driver. */
#define HPLAN /* For the HP27xxx driver. */
For the individual drivers
EI8390 Define (probably in autoconf.h or config.site.h) this to the base
address of your ethernet card.
EI8390_IRQ Define (probably in autoconf.h or config.site.h) this to the
IRQ line of your ethernet card. Most drivers convert a IRQ2 to an
IRQ9 for you, so don't be surprised.
EI_DEBUG Set to the desired numeric debugging level. Use 3 or
greater when actively debugging a problem, '1' for a
casual interest in what's going on, and '0' for normal
use.
NO_PINGPONG
Define this if you don't want ping-pong transmit buffers.
EL2_AUI
Define for this if you are using the 3c503 and use the AUI/DIX
connector rather than the built-in thin-net transceiver.
WD_SHMEM
Define this to override the shared memory address used by the
WD driver. This should only be necessary for jumpered ethercards.
If you have a Cabletron ethercard you might want to look at ne.c:neprobe()
for info on how to enable more packet buffer space.
ETHERLINK1_IRQ
ETHERLINK1 Define these to the base address and IRQ of a 3c501 (NOT 3c503)
card. Refer to net/tcp/Space.c.
drivers/net/ne.c
View file @
3448e1a6
...
...
@@ -17,7 +17,7 @@
/* Routines for the NatSemi-based designs (NE[12]000). */
static
char
*
version
=
"ne.c:v0.99-1
5 1/19
/93 Donald Becker (becker@super.org)
\n
"
;
"ne.c:v0.99-1
4a 12/3
/93 Donald Becker (becker@super.org)
\n
"
;
#include <linux/config.h>
#include <linux/kernel.h>
...
...
@@ -123,10 +123,6 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose)
printk
(
"NE*000 ethercard probe at %#3x:"
,
ioaddr
);
/* First hard-reset the ethercard. */
i
=
inb_p
(
ioaddr
+
NE_RESET
);
outb_p
(
i
,
ioaddr
+
NE_RESET
);
/* Read the 16 bytes of station address prom, returning 1 for
an eight-bit interface and 2 for a 16-bit interface.
We must first initialize registers, similar to NS8390_init(eifdev, 0).
...
...
@@ -162,8 +158,8 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose)
/* We must set the 8390 for word mode, AND RESET IT. */
int
tmp
;
outb_p
(
0x49
,
ioaddr
+
EN0_DCFG
);
tmp
=
inb_p
(
ioaddr
+
NE_RESET
);
outb
(
tmp
,
ioaddr
+
NE_RESET
);
tmp
=
inb_p
(
NE_BASE
+
NE_RESET
);
outb
(
tmp
,
NE_BASE
+
NE_RESET
);
/* Un-double the SA_prom values. */
for
(
i
=
0
;
i
<
16
;
i
++
)
SA_prom
[
i
]
=
SA_prom
[
i
+
i
];
...
...
fs/isofs/inode.c
View file @
3448e1a6
...
...
@@ -30,6 +30,9 @@ extern int check_cdu31a_media_change(int, int);
#if defined(CONFIG_MCD)
extern
int
check_mcd_media_change
(
int
,
int
);
#endif
#if defined (CONFIG_SBPCD)
extern
int
check_sbpcd_media_change
(
int
,
int
);
#endif CONFIG_SBPCD
#ifdef LEAK_CHECK
static
int
check_malloc
=
0
;
...
...
@@ -288,6 +291,13 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
goto
out
;
}
#endif
#if defined(CONFIG_SBPCD)
if
(
MAJOR
(
s
->
s_dev
)
==
MATSUSHITA_CDROM_MAJOR
)
{
if
(
check_sbpcd_media_change
(
s
->
s_dev
,
0
))
goto
out
;
};
#endif CONFIG_SBPCD
return
s
;
out:
/* Kick out for various error conditions */
brelse
(
bh
);
...
...
fs/open.c
View file @
3448e1a6
...
...
@@ -225,6 +225,7 @@ asmlinkage int sys_fchdir(unsigned int fd)
return
-
EACCES
;
iput
(
current
->
pwd
);
current
->
pwd
=
inode
;
inode
->
i_count
++
;
return
(
0
);
}
...
...
include/linux/major.h
View file @
3448e1a6
...
...
@@ -42,7 +42,7 @@
* 22 - (at2disk)
* 23 - mitsumi cdrom
* 24 - sony535 cdrom
* 25 -
* 25 -
matsushita cdrom minors 0..3
* 26 -
* 27 - qic117 tape
*/
...
...
@@ -71,6 +71,7 @@
/* unused: 22 */
#define MITSUMI_CDROM_MAJOR 23
#define CDU535_CDROM_MAJOR 24
#define MATSUSHITA_CDROM_MAJOR 25
#define QIC117_TAPE_MAJOR 27
/*
...
...
include/linux/sbpcd.h
0 → 100644
View file @
3448e1a6
/*
* sbpcd.h Specify interface address and interface type here.
*/
/*
* these definitions can get overridden by the kernel command line
* ("lilo boot option"). Examples:
* sbpcd=0x230,SoundBlaster
* or
* sbpcd=0x300,LaserMate
* these strings are case sensitive !!!
*/
/*
* change this to select the type of your interface board:
*
* set SBPRO to 1 for "true" SoundBlaster card
* set SBPRO to 0 for "poor" (no sound) interface cards
* and for "compatible" soundcards.
*
* most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!!
* if SBPRO gets set wrong, the drive will get found - but any
* data access will give errors (audio access will work).
* The OmniCD interface card from CreativeLabs needs SBPRO 1.
*
* mail to emoenke@gwdg.de if your "compatible" card needs SBPRO 1
* (currently I do not know any "compatible" with SBPRO 1)
* then I can include better information with the next release.
*/
#define SBPRO 1
/*
* put your CDROM port base address here:
* SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ...
* LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
* there are some soundcards on the market with 0x0630, 0x0650, ...
*
* obey! changed against v0.4 !!!
* for SBPRO cards, specify the CDROM address - no longer the audio address!
* example: if your SBPRO audio address is 0x220, specify 0x230.
*
* a fill-in is not always necessary - the driver does auto-probing now,
* with the here specified address first...
*/
#define CDROM_PORT 0x0230
/*==========================================================================*/
/*==========================================================================*/
/*
* nothing to change below here if you are not experimenting
*/
/*==========================================================================*/
/*==========================================================================*/
/*
* Debug output levels
*/
#define DBG_INF 1
/* necessary information */
#define DBG_IRQ 2
/* interrupt trace */
#define DBG_REA 3
/* "read" status trace */
#define DBG_CHK 4
/* "media check" trace */
#define DBG_TIM 5
/* datarate timer test */
#define DBG_INI 6
/* initialization trace */
#define DBG_TOC 7
/* tell TocEntry values */
#define DBG_IOC 8
/* ioctl trace */
#define DBG_STA 9
/* "ResponseStatus" trace */
#define DBG_ERR 10
/* "xx_ReadError" trace */
#define DBG_CMD 11
/* "cmd_out" trace */
#define DBG_WRN 12
/* give explanation before auto-probing */
#define DBG_MUL 13
/* multi session code test */
#define DBG_ID 14
/* "drive_id !=0" test code */
#define DBG_IOX 15
/* some special information */
#define DBG_DID 16
/* drive ID test */
#define DBG_RES 17
/* drive reset info */
#define DBG_SPI 18
/* SpinUp test */
#define DBG_000 19
/* unnecessary information */
/*==========================================================================*/
/*==========================================================================*/
/*
* bits of flags_cmd_out:
*/
#define f_respo3 0x100
#define f_putcmd 0x80
#define f_respo2 0x40
#define f_lopsta 0x20
#define f_getsta 0x10
#define f_ResponseStatus 0x08
#define f_obey_p_check 0x04
#define f_bit1 0x02
#define f_wait_if_busy 0x01
/*
* diskstate_flags:
*/
#define upc_bit 0x40
#define volume_bit 0x20
#define toc_bit 0x10
#define multisession_bit 0x08
#define cd_size_bit 0x04
#define subq_bit 0x02
#define frame_size_bit 0x01
/*
* disk states (bits of diskstate_flags):
*/
#define upc_valid (DS[d].diskstate_flags&upc_bit)
#define volume_valid (DS[d].diskstate_flags&volume_bit)
#define toc_valid (DS[d].diskstate_flags&toc_bit)
#define multisession_valid (DS[d].diskstate_flags&multisession_bit)
#define cd_size_valid (DS[d].diskstate_flags&cd_size_bit)
#define subq_valid (DS[d].diskstate_flags&subq_bit)
#define frame_size_valid (DS[d].diskstate_flags&frame_size_bit)
/*
* bits of the status_byte (result of xx_ReadStatus):
*/
#define p_door_closed 0x80
#define p_caddy_in 0x40
#define p_spinning 0x20
#define p_check 0x10
#define p_busy_new 0x08
#define p_door_locked 0x04
#define p_bit_1 0x02
#define p_disk_ok 0x01
/*
* "old" drives status result bits:
*/
#define p_caddin_old 0x40
#define p_success_old 0x08
#define p_busy_old 0x04
/*
* used drive states:
*/
#define st_door_closed (DS[d].status_byte&p_door_closed)
#define st_caddy_in (DS[d].status_byte&p_caddy_in)
#define st_spinning (DS[d].status_byte&p_spinning)
#define st_check (DS[d].status_byte&p_check)
#define st_busy (DS[d].status_byte&p_busy_new)
#define st_door_locked (DS[d].status_byte&p_door_locked)
#define st_diskok (DS[d].status_byte&p_disk_ok)
/*
* bits of the CDi_status register:
*/
#define s_not_result_ready 0x04
/* 0: "result ready" */
#define s_not_data_ready 0x02
/* 0: "data ready" */
#define s_attention 0x01
/* 1: "attention required" */
/*
* usable as:
*/
#define DRV_ATTN ((inb(CDi_status)&s_attention)!=0)
#define DATA_READY ((inb(CDi_status)&s_not_data_ready)==0)
#define RESULT_READY ((inb(CDi_status)&s_not_result_ready)==0)
/*
* drive types (firmware versions):
*/
#define drv_199 0
/* <200 */
#define drv_200 1
/* <201 */
#define drv_201 2
/* <210 */
#define drv_210 3
/* <211 */
#define drv_211 4
/* <300 */
#define drv_300 5
/* else */
#define drv_099 0x10
/* new, <100 */
#define drv_100 0x11
/* new, >=100 */
#define drv_new 0x10
/* all new drives have that bit set */
#define drv_old 0x00
/* */
/*
* drv_099 and drv_100 are the "new" drives
*/
#define new_drive (DS[d].drv_type&0x10)
/*
* audio states:
*/
#define audio_playing 2
#define audio_pausing 1
/*
* drv_pattern, drv_options:
*/
#define speed_auto 0x80
#define speed_300 0x40
#define speed_150 0x20
#define sax_a 0x04
#define sax_xn2 0x02
#define sax_xn1 0x01
/*
* values of cmd_type (0 else):
*/
#define cmd_type_READ_M1 0x01
/* "data mode 1": 2048 bytes per frame */
#define cmd_type_READ_M2 0x02
/* "data mode 2": 12+2048+280 bytes per frame */
#define cmd_type_READ_SC 0x04
/* "subchannel info": 96 bytes per frame */
/*
* sense byte: used only if new_drive
* only during cmd 09 00 xx ah al 00 00
*
* values: 00
* 82
* xx from infobuf[0] after 85 00 00 00 00 00 00
*/
#define CD_MINS 75
/* minutes per CD */
#define CD_SECS 60
/* seconds per minutes */
#define CD_FRAMES 75
/* frames per second */
#define CD_FRAMESIZE 2048
/* bytes per frame, data mode */
#define CD_FRAMESIZE_XA 2340
/* bytes per frame, "xa" mode */
#define CD_FRAMESIZE_RAW 2352
/* bytes per frame, "raw" mode */
#define CD_BLOCK_OFFSET 150
/* offset of first logical frame */
/* audio status (bin) */
#define aud_00 0x00
/* Audio status byte not supported or not valid */
#define audx11 0x0b
/* Audio play operation in progress */
#define audx12 0x0c
/* Audio play operation paused */
#define audx13 0x0d
/* Audio play operation successfully completed */
#define audx14 0x0e
/* Audio play operation stopped due to error */
#define audx15 0x0f
/* No current audio status to return */
/* audio status (bcd) */
#define aud_11 0x11
/* Audio play operation in progress */
#define aud_12 0x12
/* Audio play operation paused */
#define aud_13 0x13
/* Audio play operation successfully completed */
#define aud_14 0x14
/* Audio play operation stopped due to error */
#define aud_15 0x15
/* No current audio status to return */
/*============================================================================
==============================================================================
COMMAND SET of "old" drives like CR-521, CR-522
(the CR-562 family is different):
No. Command Code
--------------------------------------------
Drive Commands:
1 Seek 01
2 Read Data 02
3 Read XA-Data 03
4 Read Header 04
5 Spin Up 05
6 Spin Down 06
7 Diagnostic 07
8 Read UPC 08
9 Read ISRC 09
10 Play Audio 0A
11 Play Audio MSF 0B
12 Play Audio Track/Index 0C
Status Commands:
13 Read Status 81
14 Read Error 82
15 Read Drive Version 83
16 Mode Select 84
17 Mode Sense 85
18 Set XA Parameter 86
19 Read XA Parameter 87
20 Read Capacity 88
21 Read SUB_Q 89
22 Read Disc Code 8A
23 Read Disc Information 8B
24 Read TOC 8C
25 Pause/Resume 8D
26 Read Packet 8E
27 Read Path Check 00
all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first
mnemo 7-byte command #bytes response (r0...rn)
________ ____________________ ____
Read Status:
status: 81. (1) one-byte command, gives the main
status byte
Read Error:
check1: 82 00 00 00 00 00 00. (6) r1: audio status
Read Packet:
check2: 8e xx 00 00 00 00 00. (xx) gets xx bytes response, relating
to commands 01 04 05 07 08 09
Play Audio:
play: 0a ll-bb-aa nn-nn-nn. (0) play audio, ll-bb-aa: starting block (lba),
nn-nn-nn: #blocks
Play Audio MSF:
0b mm-ss-ff mm-ss-ff (0) play audio from/to
Play Audio Track/Index:
0c ...
Pause/Resume:
pause: 8d pr 00 00 00 00 00. (0) pause (pr=00)
resume (pr=80) audio playing
Mode Select:
84 00 nn-nn ??-?? 00 (0) nn-nn: 2048 or 2340
possibly defines transfer size
set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1)
le(vel): min=0, max=FF, else half
(firmware 2.11)
Mode Sense:
get_vol: 85 03 00 00 00 00 00. (2) tell current audio volume setting
Read Disc Information:
tocdesc: 8b 00 00 00 00 00 00. (6) read the toc descriptor ("msf-bin"-format)
Read TOC:
tocent: 8c fl nn 00 00 00 00. (8) read toc entry #nn
(fl=0:"lba"-, =2:"msf-bin"-format)
Read Capacity:
capacit: 88 00 00 00 00 00 00. (5) "read CD-ROM capacity"
Read Path Check:
ping: 00 00 00 00 00 00 00. (2) r0=AA, r1=55
("ping" if the drive is connected)
Read Drive Version:
ident: 83 00 00 00 00 00 00. (12) gives "MATSHITAn.nn"
(n.nn = 2.01, 2.11., 3.00, ...)
Seek:
seek: 01 00 ll-bb-aa 00 00. (0)
seek: 01 02 mm-ss-ff 00 00. (0)
Read Data:
read: 02 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2048 bytes,
starting at block xx-xx-xx
fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx
Read XA-Data:
read: 03 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2340 bytes,
starting at block xx-xx-xx
fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx
Read SUB_Q:
89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf,
fl=0: "lba", fl=2: "msf"
Read Disc Code:
8a 00 00 00 00 00 00. (14) possibly extended "check condition"-info
Read Header:
04 00 ll-bb-aa 00 00. (0) 4 bytes response with "check2"
04 02 mm-ss-ff 00 00. (0) 4 bytes response with "check2"
Spin Up:
05 00 ll-bb-aa 00 00. (0) possibly implies a "seek"
Spin Down:
06 ...
Diagnostic:
07 00 ll-bb-aa 00 00. (2) 2 bytes response with "check2"
07 02 mm-ss-ff 00 00. (2) 2 bytes response with "check2"
Read UPC:
08 00 ll-bb-aa 00 00. (16)
08 02 mm-ss-ff 00 00. (16)
Read ISRC:
09 00 ll-bb-aa 00 00. (15) 15 bytes response with "check2"
09 02 mm-ss-ff 00 00. (15) 15 bytes response with "check2"
Set XA Parameter:
86 ...
Read XA Parameter:
87 ...
==============================================================================
============================================================================*/
/*==========================================================================*/
/*==========================================================================*/
/*
* highest allowed drive number (MINOR+1)
* currently only one controller, maybe later up to 4
*/
#define NR_SBPCD 4
/*
* we try to never disable interrupts - seems to work
*/
#define SBPCD_DIS_IRQ 0
/*
* we don't use the IRQ line - leave it free for the sound driver
*/
#define SBPCD_USE_IRQ 0
/*
* you can set the interrupt number of your interface board here:
* It is not used at this time. No need to set it correctly.
*/
#define SBPCD_INTR_NR 7
/*
* "write byte to port"
*/
#define OUT(x,y) outb(y,x)
#define MIXER_CD_Volume 0x28
/*==========================================================================*/
/*
* use "REP INSB" for strobing the data in:
*/
#if PATCHLEVEL<15
#define READ_DATA(port, buf, nr) \
__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","dx","di")
#else
#define READ_DATA(port, buf, nr) insb(port, buf, nr)
#endif
/*==========================================================================*/
/*
* to fork and execute a function after some elapsed time:
* one "jifs" unit is 10 msec.
*/
#define SET_TIMER(func, jifs) \
((timer_table[SBPCD_TIMER].expires = jiffies + jifs), \
(timer_table[SBPCD_TIMER].fn = func), \
(timer_active |= 1<<SBPCD_TIMER))
#define CLEAR_TIMER timer_active &= ~(1<<SBPCD_TIMER)
/*==========================================================================*/
/*
* Creative Labs Programmers did this:
*/
#define MAX_TRACKS 120
/* why more than 99? */
/*==========================================================================*/
/*
* To make conversions easier (machine dependent!)
*/
typedef
union
_msf
{
u_int
n
;
u_char
c
[
4
];
}
MSF
;
typedef
union
_blk
{
u_int
n
;
u_char
c
[
4
];
}
BLK
;
/*==========================================================================*/
include/linux/timer.h
View file @
3448e1a6
...
...
@@ -30,6 +30,8 @@
* TAPE_QIC02_TIMER timer for QIC-02 tape driver (it's not hardcoded)
*
* MCD_TIMER Mitsumi CD-ROM Timer
*
* SBPCD_TIMER SoundBlaster/Matsushita/Panasonic CD-ROM timer
*/
#define BLANK_TIMER 0
...
...
@@ -48,6 +50,8 @@
#define HD_TIMER2 24
#define SBPCD_TIMER 25
struct
timer_struct
{
unsigned
long
expires
;
void
(
*
fn
)(
void
);
...
...
include/linux/tty.h
View file @
3448e1a6
...
...
@@ -294,7 +294,7 @@ struct tty_ldisc {
unsigned
int
cmd
,
unsigned
long
arg
);
int
(
*
select
)(
struct
tty_struct
*
tty
,
struct
inode
*
inode
,
struct
file
*
file
,
int
sel_type
,
s
elect_table
*
wait
);
s
truct
select_table_struct
*
wait
);
/*
* The following routines are called from below.
*/
...
...
init/main.c
View file @
3448e1a6
...
...
@@ -91,6 +91,9 @@ extern void t128_setup(char *str, int *ints);
extern
void
generic_NCR5380_setup
(
char
*
str
,
int
*
intr
);
extern
void
aha152x_setup
(
char
*
str
,
int
*
ints
);
extern
void
sound_setup
(
char
*
str
,
int
*
ints
);
#ifdef CONFIG_SBPCD
extern
void
sbpcd_setup
(
char
*
str
,
int
*
ints
);
#endif CONFIG_SBPCD
#ifdef CONFIG_SYSVIPC
extern
void
ipc_init
(
void
);
...
...
@@ -198,6 +201,9 @@ struct {
#ifdef CONFIG_SOUND
{
"sound="
,
sound_setup
},
#endif
#ifdef CONFIG_SBPCD
{
"sbpcd="
,
sbpcd_setup
},
#endif CONFIG_SBPCD
{
0
,
0
}
};
...
...
kernel/ksyms.S
View file @
3448e1a6
...
...
@@ -9,9 +9,11 @@
_register_chrdev
_unregister_chrdev
___verify_write
_wake_up_interruptible
_wp_works_ok
___verify_write
_current
_jiffies
_printk
...
...
net/inet/ip.c
View file @
3448e1a6
...
...
@@ -72,6 +72,8 @@
extern
int
last_retran
;
extern
void
sort_send
(
struct
sock
*
sk
);
#define min(a,b) ((a)<(b)?(a):(b))
void
ip_print
(
struct
iphdr
*
ip
)
{
...
...
@@ -1402,8 +1404,7 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
}
}
sti
();
reset_timer
(
sk
,
TIME_WRITE
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
reset_timer
(
sk
,
TIME_WRITE
,
sk
->
rto
);
}
else
{
skb
->
sk
=
sk
;
}
...
...
@@ -1423,14 +1424,16 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
void
ip_retransmit
(
struct
sock
*
sk
,
int
all
)
ip_
do_
retransmit
(
struct
sock
*
sk
,
int
all
)
{
struct
sk_buff
*
skb
;
struct
proto
*
prot
;
struct
device
*
dev
;
int
retransmits
;
prot
=
sk
->
prot
;
skb
=
sk
->
send_head
;
retransmits
=
sk
->
retransmits
;
while
(
skb
!=
NULL
)
{
dev
=
skb
->
dev
;
/* I know this can't happen but as it does.. */
...
...
@@ -1469,7 +1472,7 @@ ip_retransmit(struct sock *sk, int all)
/* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
oops:
sk
->
retransmits
++
;
oops:
retransmits
++
;
sk
->
prot
->
retransmits
++
;
if
(
!
all
)
break
;
...
...
@@ -1477,43 +1480,37 @@ oops: sk->retransmits++;
if
(
sk
->
retransmits
>
sk
->
cong_window
)
break
;
skb
=
(
struct
sk_buff
*
)
skb
->
link3
;
}
/*
* Increase the RTT time every time we retransmit.
* This will cause exponential back off on how hard we try to
* get through again. Once we get through, the rtt will settle
* back down reasonably quickly.
*/
sk
->
backoff
++
;
reset_timer
(
sk
,
TIME_WRITE
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
}
/* Backoff function - the subject of much research */
int
backoff
(
int
n
)
/*
* This is the normal code called for timeouts. It does the retransmission
* and then does backoff. ip_do_retransmit is separated out because
* tcp_ack needs to send stuff from the retransmit queue without
* initiating a backoff.
*/
void
ip_retransmit
(
struct
sock
*
sk
,
int
all
)
{
/* Use binary exponential up to retry #4, and quadratic after that
* This yields the sequence
* 1, 2, 4, 8, 16, 25, 36, 49, 64, 81, 100 ...
*/
ip_do_retransmit
(
sk
,
all
);
if
(
n
<
0
)
{
printk
(
"Backoff < 0!
\n
"
);
return
16
;
/* Make up a value */
}
if
(
n
<=
4
)
return
1
<<
n
;
/* Binary exponential back off */
else
{
if
(
n
<
255
)
return
n
*
n
;
/* Quadratic back off */
else
{
printk
(
"Overloaded backoff!
\n
"
);
return
255
*
255
;
}
}
/*
* Increase the timeout each time we retransmit. Note that
* we do not increase the rtt estimate. rto is initialized
* from rtt, but increases here. Jacobson (SIGCOMM 88) suggests
* that doubling rto each time is the least we can get away with.
* In KA9Q, Karns uses this for the first few times, and then
* goes to quadratic. netBSD doubles, but only goes up to *64,
* and clamps at 1 to 64 sec afterwards. Note that 120 sec is
* defined in the protocol as the maximum possible RTT. I guess
* we'll have to use something other than TCP to talk to the
* University of Mars.
*/
sk
->
retransmits
++
;
sk
->
backoff
++
;
sk
->
rto
=
min
(
sk
->
rto
<<
1
,
120
*
HZ
);
reset_timer
(
sk
,
TIME_WRITE
,
sk
->
rto
);
}
/*
...
...
net/inet/sock.c
View file @
3448e1a6
...
...
@@ -843,13 +843,15 @@ inet_create(struct socket *sock, int protocol)
sk
->
copied_seq
=
0
;
sk
->
fin_seq
=
0
;
sk
->
proc
=
0
;
sk
->
rtt
=
TCP_WRITE_TIME
;
sk
->
rtt
=
TCP_WRITE_TIME
<<
3
;
sk
->
rto
=
TCP_WRITE_TIME
;
sk
->
mdev
=
0
;
sk
->
backoff
=
0
;
sk
->
packets_out
=
0
;
sk
->
cong_window
=
1
;
/* start with only sending one packet at a time. */
sk
->
exp_growth
=
1
;
/* if set cong_window grow exponentially every time
we get an ack. */
sk
->
cong_count
=
0
;
sk
->
ssthresh
=
0
;
sk
->
max_window
=
0
;
sk
->
urginline
=
0
;
sk
->
intr
=
0
;
sk
->
linger
=
0
;
...
...
net/inet/sock.h
View file @
3448e1a6
...
...
@@ -79,7 +79,6 @@ struct sock {
destroy
,
ack_timed
,
no_check
,
exp_growth
,
zapped
,
/* In ax25 & ipx means not linked */
broadcast
,
nonagle
;
...
...
@@ -103,14 +102,21 @@ struct sock {
unsigned
short
window
;
unsigned
short
bytes_rcv
;
unsigned
short
mtu
;
unsigned
short
max_window
;
unsigned
short
num
;
volatile
unsigned
short
cong_window
;
volatile
unsigned
short
cong_count
;
volatile
unsigned
short
ssthresh
;
volatile
unsigned
short
packets_out
;
volatile
unsigned
short
urg
;
volatile
unsigned
short
shutdown
;
unsigned
short
mss
;
volatile
unsigned
long
rtt
;
volatile
unsigned
long
mdev
;
volatile
unsigned
long
rto
;
/* currently backoff isn't used, but I'm maintaining it in case
* we want to go back to a backoff formula that needs it
*/
volatile
unsigned
short
backoff
;
volatile
short
err
;
unsigned
char
protocol
;
...
...
net/inet/tcp.c
View file @
3448e1a6
...
...
@@ -103,6 +103,7 @@
#define SEQ_TICK 3
unsigned
long
seq_offset
;
#define LOCALNET_BIGPACKETS
static
__inline__
int
min
(
unsigned
int
a
,
unsigned
int
b
)
...
...
@@ -177,10 +178,18 @@ static int tcp_select_window(struct sock *sk)
{
int
new_window
=
sk
->
prot
->
rspace
(
sk
);
/* Enforce RFC793 - we've offered it we must live with it */
if
(
new_window
<
sk
->
window
)
return
(
sk
->
window
);
/*
* two things are going on here. First, we don't ever offer a
* window less than min(sk->mtu, MAX_WINDOW/2). This is the
* receiver side of SWS as specified in RFC1122.
* Second, we always give them at least the window they
* had before, in order to avoid retracting window. This
* is technically allowed, but RFC1122 advises against it and
* in practice it causes trouble.
*/
if
(
new_window
<
min
(
sk
->
mtu
,
MAX_WINDOW
/
2
)
||
new_window
<
sk
->
window
)
return
(
sk
->
window
);
return
(
new_window
);
}
...
...
@@ -210,18 +219,13 @@ tcp_retransmit(struct sock *sk, int all)
return
;
}
/*
* If we had the full V-J mechanism, this might be right. But
* for the moment we want simple slow start after error.
*
* if (sk->cong_window > 4)
* sk->cong_window = sk->cong_window / 2;
*/
sk
->
ssthresh
=
sk
->
cong_window
>>
1
;
/* remember window where we lost */
/* sk->ssthresh in theory can be zero. I guess that's OK */
sk
->
cong_count
=
0
;
sk
->
cong_window
=
1
;
sk
->
exp_growth
=
0
;
/* Do the actual
l
retransmit. */
/* Do the actual retransmit. */
ip_retransmit
(
sk
,
all
);
}
...
...
@@ -638,8 +642,7 @@ static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
if
(
before
(
sk
->
window_seq
,
sk
->
wfront
->
h
.
seq
)
&&
sk
->
send_head
==
NULL
&&
sk
->
ack_backlog
==
0
)
reset_timer
(
sk
,
TIME_PROBE0
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
reset_timer
(
sk
,
TIME_PROBE0
,
sk
->
rto
);
}
else
{
sk
->
prot
->
queue_xmit
(
sk
,
skb
->
dev
,
skb
,
0
);
}
...
...
@@ -918,25 +921,26 @@ tcp_write(struct sock *sk, unsigned char *from,
continue
;
}
#if 0
/*
* We also need to worry about the window.
* If window < 1/4 offered window, don't use it. That's
* silly window prevention. What we actually do is
* If window < 1/2 the maximum window we've seen from this
* host, don't use it. This is sender side
* silly window prevention, as specified in RFC1122.
* (Note that this is diffferent than earlier versions of
* SWS prevention, e.g. RFC813.). What we actually do is
* use the whole MTU. Since the results in the right
* edge of the packet being outside the window, it will
* be queued for later rather than sent.
*/
copy
=
diff
(
sk
->
window_seq
,
sk
->
send_seq
);
if (copy < (diff(sk->window_seq, sk->rcv_ack_seq) >> 2))
copy = sk->mtu;
if
(
sk
->
max_window
>
1
)
{
if
(
copy
<
(
sk
->
max_window
>>
1
))
copy
=
sk
->
mtu
;
}
else
/* no max_window yet, punt this test */
copy
=
sk
->
mtu
;
copy
=
min
(
copy
,
sk
->
mtu
);
copy
=
min
(
copy
,
len
);
#else
/* This also prevents silly windows by simply ignoring the offered window.. */
copy
=
min
(
sk
->
mtu
,
len
);
#endif
/* We should really check the window here also. */
if
(
sk
->
packets_out
&&
copy
<
sk
->
mtu
&&
!
(
flags
&
MSG_OOB
))
{
...
...
@@ -1780,6 +1784,16 @@ tcp_options(struct sock *sk, struct tcphdr *th)
}
static
inline
unsigned
long
default_mask
(
unsigned
long
dst
)
{
dst
=
ntohl
(
dst
);
if
(
IN_CLASSA
(
dst
))
return
htonl
(
IN_CLASSA_NET
);
if
(
IN_CLASSB
(
dst
))
return
htonl
(
IN_CLASSB_NET
);
return
htonl
(
IN_CLASSC_NET
);
}
/*
* This routine handles a connection request.
* It should make sure we haven't already responded.
...
...
@@ -1846,8 +1860,13 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk
->
send_head
=
NULL
;
newsk
->
send_tail
=
NULL
;
newsk
->
back_log
=
NULL
;
newsk
->
rtt
=
TCP_CONNECT_TIME
;
newsk
->
rtt
=
TCP_CONNECT_TIME
<<
3
;
newsk
->
rto
=
TCP_CONNECT_TIME
;
newsk
->
mdev
=
0
;
newsk
->
max_window
=
0
;
newsk
->
cong_window
=
1
;
newsk
->
cong_count
=
0
;
newsk
->
ssthresh
=
0
;
newsk
->
backoff
=
0
;
newsk
->
blog
=
0
;
newsk
->
intr
=
0
;
...
...
@@ -1903,8 +1922,14 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* note use of sk->mss, since user has no direct access to newsk */
if
(
sk
->
mss
)
newsk
->
mtu
=
sk
->
mss
;
else
newsk
->
mtu
=
576
-
HEADER_SIZE
;
else
{
#ifdef LOCALNET_BIGPACKETS
if
((
saddr
&
default_mask
(
saddr
))
==
(
daddr
&
default_mask
(
daddr
)))
newsk
->
mtu
=
MAX_WINDOW
;
else
#endif
newsk
->
mtu
=
576
-
HEADER_SIZE
;
}
/* but not bigger than device MTU */
newsk
->
mtu
=
min
(
newsk
->
mtu
,
dev
->
mtu
-
HEADER_SIZE
);
...
...
@@ -2036,7 +2061,11 @@ tcp_close(struct sock *sk, int timeout)
case
TCP_FIN_WAIT2
:
case
TCP_LAST_ACK
:
/* start a timer. */
reset_timer
(
sk
,
TIME_CLOSE
,
4
*
sk
->
rtt
);
/* original code was 4 * sk->rtt. In converting to the
* new rtt representation, we can't quite use that.
* it seems to make most sense to use the backed off value
*/
reset_timer
(
sk
,
TIME_CLOSE
,
4
*
sk
->
rto
);
if
(
timeout
)
tcp_time_wait
(
sk
);
release_sock
(
sk
);
return
;
/* break causes a double release - messy */
...
...
@@ -2109,8 +2138,7 @@ tcp_close(struct sock *sk, int timeout)
if
(
sk
->
wfront
==
NULL
)
{
prot
->
queue_xmit
(
sk
,
dev
,
buff
,
0
);
}
else
{
reset_timer
(
sk
,
TIME_WRITE
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
reset_timer
(
sk
,
TIME_WRITE
,
sk
->
rto
);
buff
->
next
=
NULL
;
if
(
sk
->
wback
==
NULL
)
{
sk
->
wfront
=
buff
;
...
...
@@ -2218,6 +2246,12 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
{
unsigned
long
ack
;
int
flag
=
0
;
/*
* 1 - there was data in packet as well as ack or new data is sent or
* in shutdown state
* 2 - data from retransmit queue was acked and removed
* 4 - window shrunk or data from retransmit queue was acked and removed
*/
if
(
sk
->
zapped
)
return
(
1
);
/* Dead, cant ack any more so why bother */
...
...
@@ -2227,6 +2261,9 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
"sk->rcv_ack_seq=%d, sk->window_seq = %d
\n
"
,
ack
,
ntohs
(
th
->
window
),
sk
->
rcv_ack_seq
,
sk
->
window_seq
));
if
(
ntohs
(
th
->
window
)
>
sk
->
max_window
)
sk
->
max_window
=
ntohs
(
th
->
window
);
if
(
sk
->
retransmits
&&
sk
->
timeout
==
TIME_KEEPOPEN
)
sk
->
retransmits
=
0
;
...
...
@@ -2309,9 +2346,29 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
/* We don't want too many packets out there. */
if
(
sk
->
timeout
==
TIME_WRITE
&&
sk
->
cong_window
<
2048
&&
ack
!=
sk
->
rcv_ack_seq
)
{
if
(
sk
->
exp_growth
)
sk
->
cong_window
*=
2
;
else
sk
->
cong_window
++
;
sk
->
cong_window
<
2048
&&
after
(
ack
,
sk
->
rcv_ack_seq
))
{
/*
* This is Jacobson's slow start and congestion avoidance.
* SIGCOMM '88, p. 328. Because we keep cong_window in integral
* mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a
* counter and increment it once every cwnd times. It's possible
* that this should be done only if sk->retransmits == 0. I'm
* interpreting "new data is acked" as including data that has
* been retransmitted but is just now being acked.
*/
if
(
sk
->
cong_window
<
sk
->
ssthresh
)
/* in "safe" area, increase */
sk
->
cong_window
++
;
else
{
/* in dangerous area, increase slowly. In theory this is
sk->cong_window += 1 / sk->cong_window
*/
if
(
sk
->
cong_count
>=
sk
->
cong_window
)
{
sk
->
cong_window
++
;
sk
->
cong_count
=
0
;
}
else
sk
->
cong_count
++
;
}
}
DPRINTF
((
DBG_TCP
,
"tcp_ack: Updating rcv ack sequence.
\n
"
));
...
...
@@ -2327,6 +2384,12 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
!
before
(
sk
->
window_seq
,
sk
->
wfront
->
h
.
seq
))
{
sk
->
retransmits
=
0
;
sk
->
backoff
=
0
;
/* recompute rto from rtt. this eliminates any backoff */
sk
->
rto
=
((
sk
->
rtt
>>
2
)
+
sk
->
mdev
)
>>
1
;
if
(
sk
->
rto
>
120
*
HZ
)
sk
->
rto
=
120
*
HZ
;
if
(
sk
->
rto
<
1
*
HZ
)
sk
->
rto
=
1
*
HZ
;
}
}
...
...
@@ -2344,23 +2407,36 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
if
(
sk
->
retransmits
)
{
/* if we're retransmitting, don't start any new
* packets until after everything in retransmit queue
* is acked. That's as close as I can come at the
* moment to slow start the way this code is organized
/* we were retransmitting. don't count this in RTT est */
flag
|=
2
;
/*
* even though we've gotten an ack, we're still
* retransmitting as long as we're sending from
* the retransmit queue. Keeping retransmits non-zero
* prevents us from getting new data interspersed with
* retransmissions.
*/
if
(
sk
->
send_head
->
link3
)
sk
->
retransmits
=
1
;
else
sk
->
retransmits
=
0
;
}
/*
* need to restart backoff whenever we get a response,
* or things get impossible if we lose a window-full of
* data with very small MSS
/*
* Note that we only reset backoff and rto in the
* rtt recomputation code. And that doesn't happen
* if there were retransmissions in effect. So the
* first new packet after the retransmissions is
* sent with the backoff still in effect. Not until
* we get an ack from a non-retransmitted packet do
* we reset the backoff and rto. This allows us to deal
* with a situation where the network delay has increased
* suddenly. I.e. Karn's algorithm. (SIGCOMM '87, p5.)
*/
sk
->
backoff
=
0
;
/* We have one less packet out there. */
if
(
sk
->
packets_out
>
0
)
sk
->
packets_out
--
;
DPRINTF
((
DBG_TCP
,
"skb=%X skb->h.seq = %d acked ack=%d
\n
"
,
...
...
@@ -2371,42 +2447,32 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
oskb
=
sk
->
send_head
;
/*
* In theory we're supposed to ignore rtt's when there's
* retransmission in process. Unfortunately this means
* that if there's a sharp increase in RTT, we may
* never get out of retransmission. For the moment
* ignore the test.
*/
if
(
!
(
flag
&
2
))
{
long
m
;
if
(
/* sk->retransmits == 0 && */
!
(
flag
&
2
))
{
long
abserr
,
rtt
=
jiffies
-
oskb
->
when
;
/*
* Berkeley's code puts these limits on a separate timeout
* field, not on the RTT estimate itself. However the way this
* code is done, that would complicate things. If we're going
* to clamp the values, we have to do so before calculating
* the mdev, or we'll get unreasonably large mdev's. Experience
* shows that with a minium rtt of .1 sec, we get spurious
* retransmits, due to delayed acks on some hosts. Berkeley uses
* 1 sec, so why not?
/* The following amusing code comes from Jacobson's
* article in SIGCOMM '88. Note that rtt and mdev
* are scaled versions of rtt and mean deviation.
* This is designed to be as fast as possible
* m stands for "measurement".
*/
if
(
rtt
<
100
)
rtt
=
100
;
/* 1 sec */
if
(
rtt
>
12000
)
rtt
=
12000
;
/* 2 min - max rtt allowed by protocol */
if
(
sk
->
state
==
TCP_SYN_SENT
||
sk
->
state
==
TCP_SYN_RECV
)
{
/* first ack, so nothing else to average with */
sk
->
rtt
=
rtt
;
sk
->
mdev
=
rtt
;
/* overcautious initial estimate */
}
else
{
abserr
=
(
rtt
>
sk
->
rtt
)
?
rtt
-
sk
->
rtt
:
sk
->
rtt
-
rtt
;
sk
->
rtt
=
(
7
*
sk
->
rtt
+
rtt
)
>>
3
;
sk
->
mdev
=
(
3
*
sk
->
mdev
+
abserr
)
>>
2
;
}
m
=
jiffies
-
oskb
->
when
;
/* RTT */
m
-=
(
sk
->
rtt
>>
3
);
/* m is now error in rtt est */
sk
->
rtt
+=
m
;
/* rtt = 7/8 rtt + 1/8 new */
if
(
m
<
0
)
m
=
-
m
;
/* m is now abs(error) */
m
-=
(
sk
->
mdev
>>
2
);
/* similar update on mdev */
sk
->
mdev
+=
m
;
/* mdev = 3/4 mdev + 1/4 new */
/* now update timeout. Note that this removes any backoff */
sk
->
rto
=
((
sk
->
rtt
>>
2
)
+
sk
->
mdev
)
>>
1
;
if
(
sk
->
rto
>
120
*
HZ
)
sk
->
rto
=
120
*
HZ
;
if
(
sk
->
rto
<
1
*
HZ
)
sk
->
rto
=
1
*
HZ
;
sk
->
backoff
=
0
;
}
flag
|=
(
2
|
4
);
...
...
@@ -2446,8 +2512,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
sk
->
send_head
==
NULL
&&
sk
->
ack_backlog
==
0
&&
sk
->
state
!=
TCP_TIME_WAIT
)
{
reset_timer
(
sk
,
TIME_PROBE0
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
reset_timer
(
sk
,
TIME_PROBE0
,
sk
->
rto
);
}
}
else
{
if
(
sk
->
send_head
==
NULL
&&
sk
->
ack_backlog
==
0
&&
...
...
@@ -2461,8 +2526,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
delete_timer
(
sk
);
}
else
{
if
(
sk
->
state
!=
(
unsigned
char
)
sk
->
keepopen
)
{
reset_timer
(
sk
,
TIME_WRITE
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
reset_timer
(
sk
,
TIME_WRITE
,
sk
->
rto
);
}
if
(
sk
->
state
==
TCP_TIME_WAIT
)
{
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
...
...
@@ -2503,12 +2567,41 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
}
}
/*
* I make no guarantees about the first clause in the following
* test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under
* what conditions "!flag" would be true. However I think the rest
* of the conditions would prevent that from causing any
* unnecessary retransmission.
* Clearly if the first packet has expired it should be
* retransmitted. The other alternative, "flag&2 && retransmits", is
* harder to explain: You have to look carefully at how and when the
* timer is set and with what timeout. The most recent transmission always
* sets the timer. So in general if the most recent thing has timed
* out, everything before it has as well. So we want to go ahead and
* retransmit some more. If we didn't explicitly test for this
* condition with "flag&2 && retransmits", chances are "when + rto < jiffies"
* would not be true. If you look at the pattern of timing, you can
* show that rto is increased fast enough that the next packet would
* almost never be retransmitted immediately. Then you'd end up
* waiting for a timeout to send each packet on the retranmission
* queue. With my implementation of the Karn sampling algorithm,
* the timeout would double each time. The net result is that it would
* take a hideous amount of time to recover from a single dropped packet.
* It's possible that there should also be a test for TIME_WRITE, but
* I think as long as "send_head != NULL" and "retransmit" is on, we've
* got to be in real retransmission mode.
* Note that ip_do_retransmit is called with all==1. Setting cong_window
* back to 1 at the timeout will cause us to send 1, then 2, etc. packets.
* As long as no further losses occur, this seems reasonable.
*/
if
(((
!
flag
)
||
(
flag
&
4
))
&&
sk
->
send_head
!=
NULL
&&
(
sk
->
send_head
->
when
+
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
)
<
jiffies
))
{
sk
->
exp_growth
=
0
;
ip_retransmit
(
sk
,
1
);
}
(
((
flag
&
2
)
&&
sk
->
retransmits
)
||
(
sk
->
send_head
->
when
+
sk
->
rto
<
jiffies
)
))
{
ip_do_retransmit
(
sk
,
1
)
;
reset_timer
(
sk
,
TIME_WRITE
,
sk
->
rto
);
}
DPRINTF
((
DBG_TCP
,
"leaving tcp_ack
\n
"
));
return
(
1
);
...
...
@@ -2979,8 +3072,15 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* use 512 or whatever user asked for */
if
(
sk
->
mss
)
sk
->
mtu
=
sk
->
mss
;
else
sk
->
mtu
=
576
-
HEADER_SIZE
;
else
{
#ifdef LOCALNET_BIGPACKETS
if
((
sk
->
saddr
&
default_mask
(
sk
->
saddr
))
==
(
sk
->
daddr
&
default_mask
(
sk
->
daddr
)))
sk
->
mtu
=
MAX_WINDOW
;
else
#endif
sk
->
mtu
=
576
-
HEADER_SIZE
;
}
/* but not bigger than device MTU */
sk
->
mtu
=
min
(
sk
->
mtu
,
dev
->
mtu
-
HEADER_SIZE
);
...
...
@@ -3639,8 +3739,15 @@ tcp_send_probe0(struct sock *sk)
*/
sk
->
prot
->
queue_xmit
(
sk
,
dev
,
skb2
,
1
);
sk
->
backoff
++
;
reset_timer
(
sk
,
TIME_PROBE0
,
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
));
/*
* in the case of retransmissions, there's good reason to limit
* rto to 120 sec, as that's the maximum legal RTT on the Internet.
* For probes it could reasonably be longer. However making it
* much longer could cause unacceptable delays in some situation,
* so we might as well use the same value
*/
sk
->
rto
=
min
(
sk
->
rto
<<
1
,
120
*
HZ
);
reset_timer
(
sk
,
TIME_PROBE0
,
sk
->
rto
);
sk
->
retransmits
++
;
sk
->
prot
->
retransmits
++
;
}
...
...
net/inet/timer.c
View file @
3448e1a6
...
...
@@ -157,10 +157,9 @@ net_timer (unsigned long data)
* So we need to check for that.
*/
if
(
sk
->
send_head
)
{
if
(
jiffies
<
(
sk
->
send_head
->
when
+
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
)))
{
reset_timer
(
sk
,
TIME_WRITE
,
(
sk
->
send_head
->
when
+
backoff
(
sk
->
backoff
)
*
(
2
*
sk
->
mdev
+
sk
->
rtt
))
-
jiffies
);
if
(
jiffies
<
(
sk
->
send_head
->
when
+
sk
->
rto
))
{
reset_timer
(
sk
,
TIME_WRITE
,
(
sk
->
send_head
->
when
+
sk
->
rto
-
jiffies
));
release_sock
(
sk
);
break
;
}
...
...
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