Commit 5f50b72d authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.52

parent c3347054
......@@ -7,6 +7,10 @@
Linus
----------
N: Werner Almesberger
E: almesber@bernina.ethz.ch
D: dosfs, LILO, some fd features, various other hacks here and there
N: Krishna Balasubramanian
E: balasub@cis.ohio-state.edu
D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
......@@ -38,8 +42,9 @@ E: becker@cesdis.gsfc.nasa.gov
D: General low-level networking hacker
D: Most of the ethercard drivers
D: Original author of the NFS server
S: 17100 Science Drive
S: Bowie, Maryland 20715
S: USRA Center of Excellence in Space Data and Information Sciences
S: Code 930.5, Goddard Space Flight Center
S: Greenbelt, Maryland 20771
S: USA
N: Stephen R. van den Berg (AKA BuGless)
......@@ -48,11 +53,11 @@ D: General kernel, gcc, and libc hacker
D: Specialisation: tweaking, ensuring portability, tweaking, cleaning,
D: tweaking and occasionally debugging :-)
S: Bouwensstraat 22
S: 6369 BG Simpelveld
S: 6369 BG Simpelveld
S: The Netherlands
N: Hennus Bergman
E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home]
E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home]
D: Author and maintainer of the QIC-02 tape driver
S: The Netherlands
......@@ -72,7 +77,7 @@ N: John Boyd
E: boyd@cis.ohio-state.edu
D: Co-author of wd7000 SCSI driver
S: 101 Curl Drive #591
S: Columbus, Ohio 43210
S: Columbus, Ohio 43210
S: USA
N: Andries Brouwer
......@@ -82,12 +87,21 @@ S: Bessemerstraat 21
S: Amsterdam
S: The Netherlands
N: Michael Callahan
E: callahan@maths.ox.ac.uk
D: PPP for Linux
S: The Mathematical Institute
S: 25-29 St Giles
S: Oxford
S: United Kingdom
N: Remy Card
E: Remy.Card@masi.ibp.fr
D: Extended file system designer and developer
D: Second extended file system designer and developer
S: Institut Blaise Pascal
S: 4 Place Jussieu, 75252 Paris Cedex 05
S: 4 Place Jussieu
S: 75252 Paris Cedex 05
S: France
N: Ed Carp
......@@ -95,14 +109,14 @@ E: ecarp@netcom.com
D: uucp, elm, pine, pico port
D: cron, at(1) developer
S: 48287 Sawleaf
S: Fremont, California 94539
S: Fremont, California 94539
S: USA
N: Raymond Chen
E: raymondc@microsoft.com
D: Author of Configure script
S: 14509 NE 39th St, #1096
S: Bellevue WA 98007
S: 14509 NE 39th Street #1096
S: Bellevue, Washington 98007
S: USA
N: Alan Cox
......@@ -113,7 +127,6 @@ E: GW4PTS@GB7SWN (packet radio)
D: NET2Debugged author
D: Network layer debugging
D: AX.25 & IPX alpha releases
S: <No>
N: Laurence Culhane
E: loz@holmes.demon.co.uk
......@@ -121,12 +134,21 @@ D: Wrote the initial alpha SLIP code
S: 81 Hood Street
S: Northampton
S: NN1 3QT
S: England
S: United Kingdom
N: Wayne Davison
E: davison@borland.com
D: Second extended file system co-designer
N: Todd J. Derr
E: tjd@cs.pitt.edu
D: maintainer of dual-monitor patches for 1.0+
D: MouseMan driver for selection
S: Department of Computer Science
S: University of Pittsburgh
S: Pittsburgh, Pennsylvania 15260
S: USA
N: Thomas Dunbar
E: tdunbar@vtaix.cc.vt.edu
D: TeX & METAFONT hacking/maintenance
......@@ -144,19 +166,20 @@ S: 47807 Krefeld
S: Germany
N: Drew Eckhardt
E: drew@cs.Colorado.EDU
E: drew@Colorado.EDU
D: SCSI code
D: Assorted snippets elsewhere
D: Boot sector "..." printing
S: 538 West Laurell Court
S: Louisville, Colorado 80027
S: 2255 Spruce
S: Boulder, Colorado 80302
S: USA
N: Bjorn Ekwall
E: bj0rn@blox.se
D: Driver for the D-Link parallel port Ethernet adapter
D: Extended support for loadable modules
D: D-Link pocket adapter drivers
S: Myrstuguv. 83
S: S-143 32 VARBY
S: S-143 32 VARBY
S: Sweden
N: Doug Evans
......@@ -189,9 +212,15 @@ D: The Linux Support Team Erlangen
N: Lawrence Foard
E: entropy@world.std.com
D: Floppy track reading, fs code
S: Suite #108
S: 217 Park Ave.
S: Worcester Ma 01609
S: 217 Park Avenue, Suite 108
S: Worcester, Massachusetts 01609
S: USA
N: Karl Fogel
E: kfogel@cs.oberlin.edu
D: Contributor, Linux User's Guide
S: 1123 North Oak Park Avenue
S: Oak Park, Illinois 60302
S: USA
N: Nigel Gamble
......@@ -201,12 +230,19 @@ S: 301 Norwood Terrace, Apartment N226
S: Boca Raton, Florida 33431-6588
S: USA
N: Jacques Gelinas
E: jacques@solucorp.qc.ca
D: Author of the Umsdos file system
S: 1326 De Val-Brillant
S: Laval, Quebec
S: Canada H7Y 1V9
N: David Gentzel
E: gentzel@nova.enet.dec.com
D: BusLogic driver and original UltraStor driver
S: Whitfield Software Services
S: 631 Idlewood Avenue
S: Carnegie, Pennsylvania 15106-1126
S: Carnegie, Pennsylvania 15106-1126
S: USA
N: Philip Gladstone
......@@ -220,13 +256,21 @@ S: Augartenstrasse 40
S: D - 76137 Karlsruhe
S: Germany
N: Greg Hankins
E: gregh@cc.gatech.edu
D: fixed keyboard driver to separate LED and locking status
S: 25360 Georgia Tech Station
S: Atlanta, Georgia 30332
S: USA
N: Andrew Haylett
E: ajh@gec-mrc.co.uk
D: Selection mechanism
S: GEC-Marconi Research Centre
S: West Hanningfield Road
S: Great Baddow, Essex CM2 8HN
S: UK
S: Great Baddow
S: CM2 8HN
S: United Kingdom
N: Michael Hipp
E: mhipp@student.uni-tuebingen.de
......@@ -236,11 +280,12 @@ S: D - 72072 Tuebingen
S: Germany
N: Dirk Hohndel
E: hohndel@informatik.uni-wuerzburg.de
D: XFree86
S: Universit"at W"urzburg, LS Informatik I
S: Am Hubland, 97218 W"urzburg
S: Germany
E: hohndel@aib.com
D: The XFree86[tm] Project
S: AIB Software Corporation
S: 46030 Manekin Plaza, Suite 160
S: Dulles, Virginia 20166
S: USA
N: Nick Holloway
E: alfie@dcs.warwick.ac.uk
......@@ -250,7 +295,7 @@ S: Department of Computer Science
S: University of Warwick
S: Coventry
S: CV4 7AL
S: UK
S: United Kingdom
N: Ron Holt
E: ron@novell.com
......@@ -270,6 +315,31 @@ S: Panoramastrasse 18
S: D-69126 Heidelberg
S: Germany
N: Ian Jackson
E: iwj10@cus.cam.ac.uk
E: ijackson@nyx.cs.du.edu
D: FAQ maintainer and poster of the daily postings
D: FSSTND group member
D: Debian core team member and maintainer of several Debian packages
S: 2 Lexington Close
S: Cambridge
S: CB3 0DS
S: United Kingdom
N: Mike Jagdis
E: jaggy@purplet.demon.co.uk
E: Mike.Jagdis@purplet.demon.co.uk
D: iBCS personalities, socket and X interfaces, x.out loader, syscalls...
D: Purple Distribution maintainer
D: UK FidoNet support
D: ISODE && PP
D: Kernel and device driver hacking
S: 280 Silverdale Road
S: Earley
S: Reading
S: RG6 2NU
S: United Kingdom
N: Michael K. Johnson
E: johnsonm@sunsite.unc.edu
D: The Linux Documentation Project
......@@ -288,7 +358,7 @@ D: NET-2
D: Drivers
D: Kernel cleanups
S: Hoefbladhof 27
S: 2215 DV Voorhout
S: 2215 DV Voorhout
S: The Netherlands
N: Olaf Kirch
......@@ -313,13 +383,28 @@ N: Bas Laarhoven
E: bas@vimec.nl
D: Loadable modules and ftape driver
S: Mr. v. Boemellaan 39
S: NL-5237 KA 's-Hertogenbosch
S: NL-5237 KA 's-Hertogenbosch
S: The Netherlands
N: Kevin Lentin
E: kevinl@cs.monash.edu.au
D: NCR53C400/T130B SCSI extension to NCR5380 driver.
S: 18 Board Street
S: Doncaster VIC 3108
S: Australia
N: Mark Lord
E: mlord@bnr.ca
E: mlord@achilles.net
D: IDE drive support in hd.c
S: 33 Ridgefield Cr
S: Nepean, Ontario
S: Canada K2H 6S3
N: Warner Losh
E: imp@boulder.parcplace.com
D: Provided OI/OB for Linux, general hacker
S: 4909 Pearl East Circle Suite 200
S: 4909 Pearl East Circle, Suite 200
S: Boulder, Colorado 80303
S: USA
......@@ -352,8 +437,8 @@ E: pat@it.com.au
D: 8 bit XT hard disk driver
D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking
S: 25 McMillan Street
S: Victoria Park, 6100
S: Western Australia
S: Victoria Park 6100
S: Australia
N: John A. Martin
E: jmartin@csc.com
......@@ -366,6 +451,15 @@ S: 1100 West Street
S: Laurel, Maryland 20707-3587
S: USA
N: Kevin E. Martin
E: martin@cs.unc.edu
D: Developed original accelerated X servers included in XFree86
D: XF86_Mach64 (forthcoming -- please don't ask when)
D: XF86_Mach32
D: XF86_Mach8
D: XF86_8514
D: cfdisk (curses based disk partitioning program)
N: Bradley McLean
E: brad@bradpc.gaylord.com
D: Device driver hacker
......@@ -411,7 +505,9 @@ D: Linux Projects Map, Linux Commercial-HOWTO
D: general Linux publicity in Germany, vacation port
D: UUCP and CNEWS binary packages for LST
S: Editorial Board iX Mag
S: Helstorfer Str. 7, D-30625 Hannover
S: Helstorfer Str. 7
S: D-30625 Hannover
S: Germany
N: Corey Minyard
E: minyard@wf-rch.cirr.com
......@@ -431,7 +527,7 @@ N: Ian A. Murdock
E: imurdock@gnu.ai.mit.edu
D: Creator of Debian distribution
S: 30 White Tail Lane
S: Lafayette, Indiana 47906
S: Lafayette, Indiana 47905
S: USA
N: Johan Myreen
......@@ -442,6 +538,7 @@ S: FIN-00330 Helsingfors
S: Finland
N: David C. Niemi
E: niemidc@clark.net
E: niemidc@slma.com
D: FSSTND, The XFree86 Project
D: DMA memory support, floppy driver
......@@ -449,6 +546,16 @@ S: 2364 Old Trail Drive
S: Reston, Virginia 22091
S: USA
N: Michael O'Reilly
E: michael@iinet.com.au
E: oreillym@tartarus.uwa.edu.au
D: Wrote the original dynamic sized disk cache stuff. I think the only
D: part that remains is the GFP_KERNEL et al #defines. :)
S: 192 Nichsolson Road
S: Subiaco, 6008
S: Perth, Western Australia
S: Australia
N: Kai Petzke
E: wpp@marie.physik.tu-berlin.de
D: Driver for Laser Magnetic Storage CD-ROM
......@@ -463,11 +570,10 @@ E: snprobst@immd4.informatik.uni-erlangen.de
D: The Linux Support Team Erlangen
N: Daniel Quinlan
E: quinlan@bucknell.edu
E: quinlan@yggdrasil.com
D: FSSTND Coordinator
S: Box C3529
S: Bucknell University
S: Lewisburg, Pennsylvania 17837
S: 816 Saratoga Avenue, Apartment M208
S: San Jose, California 95129
S: USA
N: Florian La Roche
......@@ -481,7 +587,7 @@ S: Germany
N: Stephen Rothwell
E: sfr@pdact.pd.necisa.oz.au
D: Boot/setup/build work for setup > 2K
S: 59 Bugden Ave
S: 59 Bugden Avenue
S: Gowrie ACT 2904
S: Australia
......@@ -510,6 +616,15 @@ S: 620 Park View Drive #206
S: Santa Clara, California 95054
S: USA
N: Rick Sladkey
E: jrs@world.std.com
D: utility hacker: Emacs, NFS server, mount, kmem-ps, UPS debugger, strace, GDB
D: library hacker: RPC, profil(3), realpath(3), regexp.h
D: kernel hacker: unnamed block devs, NFS client, fast select, precision timer
S: 24 Avon Place
S: Arlington, Massachusetts 02174
S: USA
N: Chris Smith
E: csmith@convex.com
D: HPFS filesystem
......@@ -521,7 +636,7 @@ E: drew@lethe.north.net
D: iBCS2 developer
S: 22 Irvington Cres.
S: Willowdale, Ontario
S: Canada, M2N 2Z1
S: Canada M2N 2Z1
N: Tommy Thorn
E: Tommy.Thorn@daimi.aau.dk
......@@ -579,8 +694,9 @@ S: Dept. of Computer Science
S: University of Edinburgh
S: JCMB, The King's Buildings
S: Mayfield Road
S: Edinburgh EH9 3JZ
S: Scotland, UK
S: Edinburgh
S: EH9 3JZ
S: United Kingdom
N: Thomas Uhl
E: uhl@sun1.rz.fh-heilbronn.de
......@@ -591,12 +707,22 @@ S: Obere Heerbergstrasse 17
S: 97078 Wuerzburg
S: Germany
N: Jeffrey A. Uphoff
E: juphoff@nrao.edu
E: jeff.uphoff@linux.org
D: 'dip' contributor.
D: AIPS port, astronomical community support.
S: National Radio Astronomy Observatory
S: 520 Edgemont Road
S: Charlottesville, Virginia 22903
S: USA
N: Patrick Volkerding
E: volkerdi@ftp.cdrom.com
D: Produced the Slackware distribution, updated the SVGAlib
D: patches for ghostscript, worked on color 'ls', etc.
S: 301 15th Street S.
S: Moorhead, MN 56560
S: Moorhead, Minnesota 56560
S: USA
N: Juergen Weigert
......@@ -611,7 +737,7 @@ D: HOWTO coordinator and writer
D: Maintainer of sunsite.unc.edu Linux doc archives
D: Moderator, comp.os.linux.announce
S: 205 Gray Street NE
S: Wilson, North Carolina 27893
S: Wilson, North Carolina 27893
S: USA
......@@ -635,7 +761,7 @@ E: gunter@mbfys.kun.nl
D: Some bug fixes in the polling printer driver (lp.c)
S: University of Nijmegen
S: Geert-Grooteplein Noord 21
S: 6525 EZ Nijmegen
S: 6525 EZ Nijmegen
S: The Netherlands
N: Lars Wirzenius
......@@ -655,8 +781,8 @@ S: Finland
N: Roger E. Wolff
E: wolff@dutecai.et.tudelft.nl
D: Written kmalloc/kfree
S: Oosterstraat 23
S: 2611 TT Delft
S: Oosterstraat 23
S: 2611 TT Delft
S: The Netherlands
N: Frank Xia
......@@ -668,15 +794,14 @@ S: USA
N: Eric Youngdale
E: ericy@cais.com
E: eric@tantalus.nrl.navy.mil
D: General kernel hacker
D: SCSI, iso9660, ELF, ibcs2, clustering in buffer cache, generalized mmap.
D: SCSI iso9660 and ELF
S: 17 Canterbury Square #101
S: Alexandria, Virginia 22304
S: USA
N: Orest Zborowski
E: orestz@microsoft.com
E: orestz@eskimo.com
D: XFree86 and kernel development
S: 1507 145th Place SE #B5
S: Bellevue, Washington 98007
......
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 51
SUBLEVEL = 52
ARCH = i386
......
......@@ -541,5 +541,4 @@ _sys_call_table:
.long _sys_setfsuid
.long _sys_setfsgid
.long _sys_llseek /* 140 */
.space (NR_syscalls-139)*4
.space (NR_syscalls-140)*4
......@@ -75,14 +75,13 @@ extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
#elif (MAJOR_NR == FLOPPY_MAJOR)
static void floppy_on(unsigned int nr);
static void floppy_off(unsigned int nr);
#define DEVICE_NAME "floppy"
#define DEVICE_INTR do_floppy
#define DEVICE_REQUEST do_fd_request
#define DEVICE_NR(device) ( ((device) & 3) | (((device) & 0x80 ) >> 5 ))
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
#elif (MAJOR_NR == HD_MAJOR)
......
......@@ -23,10 +23,12 @@
* drives attached to both, please mail me: Alain.Knaff@imag.fr */
/* #define HAVE_2_CONTROLLERS */
/* Undefine the following if you have problems accessing ED disks, but don't
* have problems accessing them with the stock driver. If that is the case,
* please mail me: Alain.Knaff@imag.fr */
/* #define FDC_FIFO_BUG */
/* Define the following if you don't like that your drives seek audibly
* after a disk change
*/
#define SILENT_DC_CLEAR
/* End of configuration */
......@@ -98,6 +100,11 @@
* disk types.
*/
/*
* 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
* format bug fixes, but unfortunately some new bugs too...
*/
/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
* errors to allow safe writing by specialized programs.
*/
......@@ -108,6 +115,7 @@
#define DEBUGT 2
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
......@@ -131,7 +139,7 @@
#define MAJOR_NR FLOPPY_MAJOR
#include "blk.h"
static unsigned int changed_floppies = 0, fake_change = 0;
static unsigned int changed_floppies = 0xff, fake_change = 0;
static int initialising=1;
......@@ -159,6 +167,17 @@ static int initialising=1;
#define UDRWE (&write_errors[drive])
#define UFDCS (&fdc_state[FDC(drive)])
#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
#define DPRINT1(x,x1) \
printk(DEVICE_NAME "%d: " x,current_drive,(x1));
#define DPRINT2(x,x1,x2) \
printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
#define DPRINT3(x,x1,x2,x3) \
printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
/* read/write */
#define COMMAND raw_cmd.cmd[0]
#define DR_SELECT raw_cmd.cmd[1]
......@@ -295,12 +314,12 @@ static struct floppy_struct floppy_type[32] = {
{ 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
{ 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x6C,"d880" }, /* 20 880KB 5.25" */
{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x6C,"h880" }, /* 20 880KB 5.25" */
{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x6C,"D1040" }, /* 21 1.04MB 3.5" */
{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x6C,"D1120" }, /* 22 1.12MB 3.5" */
{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x6C,"h1600" }, /* 23 1.6MB 5.25" */
{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x6C,"H1760" }, /* 24 1.76MB 3.5" */
{ 3840,24,2,80,0,0x1C,0x18,0xCF,0x6C,"H1920" }, /* 25 1.92MB 3.5" */
{ 3840,24,2,80,0,0x1C,0x20,0xCF,0x6C,"H1920" }, /* 25 1.92MB 3.5" */
{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x6C,"E3200" }, /* 26 3.20MB 3.5" */
{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x6C,"E3520" }, /* 27 3.52MB 3.5" */
{ 7680,48,2,80,0,0x25,0x63,0xCF,0x6C,"E3840" }, /* 28 3.84MB 3.5" */
......@@ -345,6 +364,8 @@ static int probing = 0;
static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0;
static struct wait_queue *fdc_wait = NULL, *command_done = NULL;
#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)
#define CALL(x) if( (x) == -EINTR) return -EINTR;
/* Errors during formatting are counted here. */
static int format_errors;
......@@ -366,6 +387,7 @@ static struct format_descr format_req;
* Note that you must not change the sizes below without updating head.S.
*/
extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
#define max_buffer_sectors MAX_BUFFER_SECTORS
int *errors;
typedef void (*done_f)(int);
......@@ -377,13 +399,14 @@ void (*error)(void); /* this is called to tally an error */
done_f done; /* this is called to say if the operation has succeeded/failed */
} *cont;
static void floppy_ready(void);
static void floppy_start(void);
static void redo_fd_request(void);
static void recalibrate_floppy(void);
static void seek_floppy(void);
static void floppy_shutdown(void);
int floppy_grab_irq_and_dma(void);
void floppy_release_irq_and_dma(void);
static int floppy_grab_irq_and_dma(void);
static void floppy_release_irq_and_dma(void);
/*
* The "reset" variable should be tested whenever an interrupt is scheduled,
......@@ -411,10 +434,6 @@ static int buffer_drive = -1;
static int buffer_min = -1;
static int buffer_max = -1;
#ifdef FDC_FIFO_BUG
static int force=0;
#endif
/* fdc related variables, should end up in a struct */
static struct floppy_fdc_state fdc_state[N_FDC];
int fdc; /* current fdc */
......@@ -455,31 +474,84 @@ static inline void debugt(char *message)
* This part of the file contains the code talking directly to the hardware,
* and also the main service loop (seek-configure-spinup-command)
*/
/*
* disk change.
* This routine is responsible for maintaining the changed_floppies flag,
* and the last_checked date.
*
* last_checked is the date of the last check which showed 'no disk change'
* changed_floppies is set under two conditions:
* 1. The floppy has been changed after some i/o to that floppy already
* took place.
* 2. No floppy disk is in the drive.
*
* For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
* For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
* each seek. If a disk is present, the disk change line should also be
* cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
* change line is set, this means either that no disk is in the drive, or
* that it has been removed since the last seek.
*
* This means that we really have a third possibility too:
* The floppy has been changed after the last seek.
*/
static int disk_change(int drive)
{
if(inb_p(FD_DIR) & 0x80){
UDRS->flags |= FD_VERIFY; /* verify write protection */
if(UDRS->maxblock || /* disk change check */
!(UDRS->flags & FD_DISK_NEWCHANGE)){/* disk presence check */
/* mark it changed or absent */
set_bit(drive,&changed_floppies);
/* invalidate its geometry */
if (UDRS->keep_data >= 0) {
if ((DP->flags & FTD_MSG) &&
current_type[drive] != NULL)
DPRINT("Disk type is undefined after "
"disk change\n");
current_type[drive] = NULL;
floppy_sizes[drive] = MAX_DISK_SIZE;
}
}
UDRS->flags |= FD_DISK_NEWCHANGE;
return 1;
} else {
UDRS->last_checked=jiffies;
UDRS->flags &= ~FD_DISK_NEWCHANGE;
return 0;
}
}
static int set_dor(int fdc, char mask, char data)
{
register unsigned char drive, unit, newdor,olddor;
cli();
olddor = FDCS->dor;
newdor = (olddor & mask) | data;
if ( newdor != olddor ){
unit = olddor & 0x3;
drive = REVDRIVE(fdc,unit);
if ( olddor & ( 0x10 << unit )){
if ( inb_p( FD_DIR ) & 0x80 )
UDRS->flags |= FD_VERIFY;
else
UDRS->last_checked=jiffies;
}
if ( olddor & ( 0x10 << unit ))
disk_change(drive);
FDCS->dor = newdor;
outb_p( newdor, FD_DOR);
}
sti();
return olddor;
}
static void twaddle(void)
{
cli();
outb_p(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
outb_p(FDCS->dor, FD_DOR);
sti();
}
/* reset all driver information about the current fdc. This is needed after
......@@ -516,34 +588,47 @@ static void set_fdc(int drive)
FDCS->reset = 1;
}
static int usage_count = 0;
/* locks the driver */
static void lock_fdc(int drive)
static int lock_fdc(int drive, int interruptible)
{
if(!usage_count){
printk("trying to lock fdc while usage count=0\n");
return -1;
}
floppy_grab_irq_and_dma();
cli();
while (fdc_busy) sleep_on(&fdc_wait);
while (fdc_busy && NO_SIGNAL)
interruptible_sleep_on(&fdc_wait);
if(fdc_busy){
sti();
return -EINTR;
}
fdc_busy = 1;
sti();
command_status = FD_COMMAND_NONE;
set_fdc(drive);
return 0;
}
#define LOCK_FDC(drive,interruptible) \
if(lock_fdc(drive,interruptible)) return -EINTR;
/* unlocks the driver */
static inline int unlock_fdc(void)
static inline void unlock_fdc(void)
{
if (current_drive < N_DRIVE)
floppy_off(current_drive);
if (!fdc_busy)
printk(DEVICE_NAME ": FDC access conflict!\n");
DPRINT("FDC access conflict!\n");
if ( DEVICE_INTR )
printk(DEVICE_NAME
":device interrupt still active at FDC release: %p!\n",
DEVICE_INTR);
DPRINT1("device interrupt still active at FDC release: %p!\n",
DEVICE_INTR);
command_status = FD_COMMAND_NONE;
timer_active &= ~(1 << FLOPPY_TIMER);
fdc_busy = 0;
floppy_release_irq_and_dma();
wake_up(&fdc_wait);
return 0;
}
/* switches the motor off after a given timeout */
......@@ -621,10 +706,10 @@ static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
* transfer */
static void fd_watchdog(void)
{
if ( inb_p( FD_DIR ) & 0x80 ){
changed_floppies |= ( 1 << current_drive);
if ( disk_change(current_drive) ){
DPRINT("disk removed during i/o\n");
floppy_shutdown();
} else {
} else {
del_timer(&fd_timer);
fd_timer.function = (timeout_fn) fd_watchdog;
fd_timer.expires = 10;
......@@ -666,7 +751,7 @@ static void setup_DMA(void)
raw_cmd.length > 512 * CURRENT->nr_sectors) &&
(current_addr < floppy_track_buffer ||
current_addr + raw_cmd.length >
floppy_track_buffer + 1024 * MAX_BUFFER_SECTORS)){
floppy_track_buffer + 1024 * max_buffer_sectors)){
printk("bad address. start=%p lg=%lx tb=%p\n",
current_addr, raw_cmd.length, floppy_track_buffer);
if ( CURRENT ){
......@@ -714,16 +799,11 @@ static int output_byte(char byte)
if (FDCS->reset)
return -1;
for(counter = 0 ; counter < 10000 ; counter++) {
for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
if (!(status & STATUS_READY))
continue;
if (status == STATUS_READY
#ifdef FDC_FIFO_BUG
|| ((status == STATUS_READY|STATUS_DIR|STATUS_BUSY) &&force)
#endif
)
{
if (status == STATUS_READY){
outb_p(byte,FD_DATA);
return 0;
} else
......@@ -731,18 +811,12 @@ static int output_byte(char byte)
}
FDCS->reset = 1;
if ( !initialising )
printk(DEVICE_NAME ": Unable to send byte to FDC %d (%x)\n",
fdc, status);
DPRINT2("Unable to send byte %x to FDC. Status=%x\n",
byte, status);
return -1;
}
#define LAST_OUT(x) if(output_byte(x)){ reset_fdc();return;}
#ifdef FDC_FIFO_BUG
#define output_byte_force(x) force=1;output_byte(x);force=0;
#else
#define output_byte_force(x) output_byte(x);
#endif
/* gets the response from the fdc */
static int result(void)
{
......@@ -750,7 +824,7 @@ static int result(void)
if (FDCS->reset)
return -1;
for (counter = 0 ; counter < 10000 ; counter++) {
for (counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
status = inb_p(FD_STATUS)&
(STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
if (!(status & STATUS_READY))
......@@ -761,8 +835,7 @@ static int result(void)
break;
if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
if (i >= MAX_REPLIES) {
printk(DEVICE_NAME
": floppy_stat reply overrun\n");
DPRINT("floppy_stat reply overrun\n");
break;
}
reply_buffer[i++] = inb_p(FD_DATA);
......@@ -770,14 +843,13 @@ static int result(void)
}
FDCS->reset = 1;
if ( !initialising )
printk(DEVICE_NAME ": Getstatus times out (%x) on fdc %d [%d]\n",
status, fdc,i);
DPRINT3("Getstatus times out (%x) on fdc %d [%d]\n",
status, fdc, i);
return -1;
}
/* Set perpendicular mode as required, based on data rate, if supported.
* 82077 Untested! 1Mbps data rate only possible with 82077-1.
* TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
* 82077 Now tested. 1Mbps data rate only possible with 82077-1.
*/
static inline void perpendicular_mode(void)
{
......@@ -788,14 +860,13 @@ static inline void perpendicular_mode(void)
if (floppy->rate & 0x40){
switch(raw_cmd.rate){
case 0:
perp_mode=/*2*/3;
perp_mode=2;
break;
case 3:
perp_mode=3;
break;
default:
printk(DEVICE_NAME
": Invalid data rate for perpendicular mode!\n");
DPRINT("Invalid data rate for perpendicular mode!\n");
cont->done(0);
FDCS->reset = 1; /* convenient way to return to
* redo without to much hassle (deep
......@@ -809,11 +880,10 @@ static inline void perpendicular_mode(void)
return;
if (FDCS->version >= FDC_82077_ORIG && FDCS->has_fifo) {
output_byte(FD_PERPENDICULAR);
output_byte_force(perp_mode);
output_byte(perp_mode);
FDCS->perp_mode = perp_mode;
} else if (perp_mode) {
printk(DEVICE_NAME
": perpendicular mode not supported by this FDC.\n");
DPRINT("perpendicular mode not supported by this FDC.\n");
}
} /* perpendicular_mode */
......@@ -853,15 +923,15 @@ static void fdc_specify(void)
/* Turn on FIFO for 82077-class FDC (improves performance) */
/* TODO: lock this in via LOCK during initialization */
output_byte(FD_CONFIGURE);
output_byte_force(0);
output_byte(0);
output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */
output_byte_force(0); /* precompensation from track 0 upwards */
output_byte(0); /* precompensation from track 0 upwards */
if ( FDCS->reset ){
FDCS->has_fifo=0;
return;
}
FDCS->need_configure = 0;
/*printk(DEVICE_NAME ": FIFO enabled\n");*/
/*DPRINT("FIFO enabled\n");*/
}
switch (raw_cmd.rate & 0x03) {
......@@ -902,8 +972,7 @@ static void fdc_specify(void)
hut = hut_max_code;
spec1 = (srt << 4) | hut;
#define fd_disable_dma 0
spec2 = (hlt << 1) | fd_disable_dma;
spec2 = (hlt << 1);
/* If these parameters did not change, just return with success */
if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
......@@ -955,7 +1024,7 @@ static int interpret_errors(void)
char bad;
if (inr!=7) {
printk(DEVICE_NAME ": -- FDC reply error");
DPRINT("-- FDC reply error");
FDCS->reset = 1;
return 1;
}
......@@ -965,7 +1034,7 @@ static int interpret_errors(void)
case 1: /* error occured during command execution */
bad = 1;
if (ST1 & ST1_WP) {
printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive);
DPRINT("Drive is write protected\n");
DRS->flags &= ~FD_DISK_WRITABLE;
cont->done(0);
bad = 2;
......@@ -973,11 +1042,10 @@ static int interpret_errors(void)
DRS->flags |= FD_NEED_TWADDLE;
} else if (ST1 & ST1_OR) {
if (DP->flags & FTD_MSG )
printk(DEVICE_NAME ": Over/Underrun - retrying\n");
/* could continue from where we stopped, but ... */
DPRINT("Over/Underrun - retrying\n");
bad = 0;
}else if(*errors >= DP->max_errors.reporting){
printk(DEVICE_NAME " %d: ", ST0 & ST0_DS);
DPRINT("");
if (ST0 & ST0_ECE) {
printk("Recalibrate failed!");
} else if (ST2 & ST2_CRC) {
......@@ -1008,11 +1076,11 @@ static int interpret_errors(void)
DRS->track = NEED_2_RECAL;
return bad;
case 2: /* invalid command given */
printk(DEVICE_NAME ": Invalid FDC command given!\n");
DPRINT("Invalid FDC command given!\n");
cont->done(0);
return 2;
case 3:
printk(DEVICE_NAME ": Abnormal termination caused by polling\n");
DPRINT("Abnormal termination caused by polling\n");
cont->error();
return 2;
default: /* (0) Normal command termination */
......@@ -1034,7 +1102,7 @@ static void setup_rw_floppy(void)
if ( flags & ( FD_RAW_READ | FD_RAW_WRITE))
flags |= FD_RAW_INTR;
if (flags & FD_RAW_SPIN){
if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){
ready_date = DRS->spinup_date + DP->spinup;
/* If spinup will take a long time, rerun scandrives
* again just before spinup completion. Beware that
......@@ -1042,7 +1110,7 @@ static void setup_rw_floppy(void)
*/
if ( ready_date > jiffies + DP->select_delay){
ready_date -= DP->select_delay;
function = (timeout_fn) floppy_on;
function = (timeout_fn) floppy_start;
} else
function = (timeout_fn) setup_rw_floppy;
......@@ -1052,11 +1120,8 @@ static void setup_rw_floppy(void)
}
dflags = DRS->flags;
if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE)){
if ( flags & FD_RAW_USER_SUPPLIED )
buffer_track = -1;
if ( (flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
setup_DMA();
}
if ( flags & FD_RAW_INTR )
SET_INTR(main_command_interrupt);
......@@ -1080,6 +1145,10 @@ static void setup_rw_floppy(void)
fd_watchdog();
}
#ifdef SILENT_DC_CLEAR
static int blind_seek;
#endif
/*
* This is the routine called after every seek (or recalibrate) interrupt
* from the floppy controller.
......@@ -1088,32 +1157,58 @@ static void seek_interrupt(void)
{
#ifdef DEBUGT
debugt("seek interrupt:");
#endif
#ifdef SILENT_DC_CLEAR
set_dor(fdc, ~0, (0x10 << UNIT(current_drive)));
#endif
if (inr != 2 || (ST0 & 0xF8) != 0x20 ) {
printk(DEVICE_NAME ": seek failed\n");
DPRINT("seek failed\n");
DRS->track = NEED_2_RECAL;
cont->error();
cont->redo();
return;
}
if ( DRS->track >= 0 && DRS->track != ST1 )
DRS->flags &= ~FD_DISK_NEWCHANGE;
if (DRS->track >= 0 && DRS->track != ST1
#ifdef SILENT_DC_CLEAR
&& !blind_seek
#endif
)
DRS->flags &= ~FD_DISK_NEWCHANGE; /* effective seek */
DRS->track = ST1;
seek_floppy();
}
static void check_wp(void)
{
if (DRS->flags & FD_VERIFY) {
/* check write protection */
output_byte( FD_GETSTATUS );
output_byte( UNIT(current_drive) );
if ( result() != 1 ){
FDCS->reset = 1;
return;
}
DRS->flags &= ~(FD_VERIFY | FD_DISK_WRITABLE | FD_NEED_TWADDLE);
if (!( ST3 & 0x40))
DRS->flags |= FD_DISK_WRITABLE;
}
}
static void seek_floppy(void)
{
int track;
#ifdef SILENT_DC_CLEAR
blind_seek=0;
#endif
disk_change(current_drive);
if ((raw_cmd.flags & FD_RAW_NEED_DISK) &&
!(DRS->flags & FD_DISK_NEWCHANGE ) &&
(inb_p(FD_DIR) & 0x80)){
test_bit(current_drive,&changed_floppies)){
/* the media changed flag should be cleared after the seek.
* If it isn't, this means that there is really no disk in
* the drive.
*/
changed_floppies |= ( 1 << current_drive);
cont->done(0);
cont->redo();
return;
......@@ -1122,26 +1217,38 @@ static void seek_floppy(void)
recalibrate_floppy();
return;
} else if ((DRS->flags & FD_DISK_NEWCHANGE) &&
(raw_cmd.flags & FD_RAW_NEED_DISK) &&
(DRS->track <= NO_TRACK || DRS->track == raw_cmd.track)) {
/* we seek to clear the media-changed condition. Does anybody
* know a more elegant way, which works on all drives? */
if ( raw_cmd.track )
track = raw_cmd.track - 1;
else
else {
#ifdef SILENT_DC_CLEAR
set_dor(fdc, ~ (0x10 << UNIT(current_drive)), 0);
blind_seek = 1;
#endif
track = 1;
} else if (raw_cmd.track != DRS->track)
track = raw_cmd.track;
else {
setup_rw_floppy();
return;
}
} else {
check_wp();
if (raw_cmd.track != DRS->track)
track = raw_cmd.track;
else {
setup_rw_floppy();
return;
}
}
#ifndef SILENT_DC_CLEAR
if ( !track && DRS->track >= 0 && DRS->track < 80 ){
DRS->flags &= ~FD_DISK_NEWCHANGE;
/* if we go to track 0 anyways, we can just as well use
* recalibrate */
recalibrate_floppy();
} else {
} else
#endif
{
SET_INTR(seek_interrupt);
output_byte(FD_SEEK);
output_byte(UNIT(current_drive));
......@@ -1213,8 +1320,7 @@ static void unexpected_floppy_interrupt(void)
int i;
if ( initialising )
return;
printk(DEVICE_NAME ": unexpected interrupt\n");
inr = result();
DPRINT("unexpected interrupt\n");
if ( inr >= 0 )
for(i=0; i<inr; i++)
printk("%d %x\n", i, reply_buffer[i] );
......@@ -1230,20 +1336,8 @@ static void unexpected_floppy_interrupt(void)
FDCS->reset = 1;
}
static void floppy_bh(void (*handler)(void))
{
inr = result();
if ( inr == 0 ){
do {
output_byte(FD_SENSEI);
inr = result();
} while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2);
}
handler();
}
struct tq_struct floppy_tq =
{ 0, 0, (void *) (void *) floppy_bh, 0 };
{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 };
/* interrupt handler */
static void floppy_interrupt(int unused)
......@@ -1255,12 +1349,19 @@ static void floppy_interrupt(int unused)
printk("floppy interrupt on bizarre fdc\n");
return;
}
if (!handler)
inr = result();
if (!handler){
unexpected_floppy_interrupt();
else {
floppy_tq.data = (void *) handler;
queue_task_irq(&floppy_tq, &tq_timer);
return;
}
if ( inr == 0 ){
do {
output_byte(FD_SENSEI);
inr = result();
} while ( (ST0 & 0x83) != UNIT(current_drive) && inr == 2);
}
floppy_tq.routine = (void *)(void *) handler;
queue_task_irq(&floppy_tq, &tq_timer);
}
static void recalibrate_floppy(void)
......@@ -1310,86 +1411,88 @@ static void empty(void)
{
}
void show_floppy(void)
{
int i;
printk("\n");
printk("floppy driver state\n");
printk("-------------------\n");
for(i=0; i<N_FDC; i++){
printk("dor %d = %x\n", i, fdc_state[i].dor );
outb_p(fdc_state[i].address+2, fdc_state[i].dor);
udelay(1000); /* maybe we'll catch an interrupt... */
}
printk("status=%x\n", inb_p(FD_STATUS));
printk("fdc_busy=%d\n", fdc_busy);
if( DEVICE_INTR)
printk("DEVICE_INTR=%p\n", DEVICE_INTR);
if(floppy_tq.sync)
printk("floppy_tq.routine=%p\n", floppy_tq.routine);
if(fd_timer.prev)
printk("fd_timer.function=%p\n", fd_timer.function);
if( timer_active & (1 << FLOPPY_TIMER)){
printk("timer_table=%p\n",timer_table[FLOPPY_TIMER].fn);
printk("expires=%ld\n",timer_table[FLOPPY_TIMER].expires);
printk("now=%ld\n",jiffies);
}
printk("cont=%p\n", cont);
printk("CURRENT=%p\n", CURRENT);
printk("command_status=%d\n", command_status);
printk("\n");
}
static void floppy_shutdown(void)
{
del_timer( &fd_timer);
CLEAR_INTR;
floppy_tq.data = (void *) empty;
if ( !initialising )
printk(DEVICE_NAME ": timeout\n");
floppy_tq.routine = (void *)(void *) empty;
del_timer( &fd_timer);
disable_dma(FLOPPY_DMA);
/* avoid dma going to a random drive after shutdown */
if(!initialising)
DPRINT("floppy timeout\n");
FDCS->reset = 1;
cont->done(0);
cont->redo(); /* this will recall reset when needed */
}
/* start motor, check media-changed condition and write protection */
static int start_motor(void)
static void start_motor(void)
{
int cnt;
int dir;
int mask, data;
mask = 0xfc;
data = UNIT(current_drive);
if ( (FDCS->dor & 0x03) != UNIT(current_drive) )
/* notes select time if floppy is not yet selected */
DRS->select_date = jiffies;
if ( ! ( FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
set_debugt();
/* no read since this drive is running */
DRS->first_read_date = 0;
/* note motor start time if motor is not yet running */
DRS->spinup_date = jiffies;
}
if (!(raw_cmd.flags & FD_RAW_NO_MOTOR)){
if(!(FDCS->dor & ( 0x10 << UNIT(current_drive) ) )){
set_debugt();
/* no read since this drive is running */
DRS->first_read_date = 0;
/* note motor start time if motor is not yet running */
DRS->spinup_date = jiffies;
data |= (0x10 << UNIT(current_drive));
}
} else
if (FDCS->dor & ( 0x10 << UNIT(current_drive) ) )
mask &= ~(0x10 << UNIT(current_drive));
/* starts motor and selects floppy */
del_timer(motor_off_timer + current_drive);
set_dor( fdc, 0xfc,
( 0x10 << UNIT(current_drive) ) | UNIT(current_drive) );
dir = inb_p( FD_DIR) & 0x80;
if ( ! (dir & 0x80) )
DRS->last_checked =jiffies;
if ( dir || ( DRS->flags & FD_VERIFY )) {
DRS->flags &= FD_DRIVE_PRESENT | FD_DISK_NEWCHANGE;
DRS->flags |= FD_DISK_WRITABLE;
set_dor( fdc, mask, data);
if( raw_cmd.flags & FD_RAW_NO_MOTOR)
return;
/* check write protection */
output_byte( FD_GETSTATUS );
output_byte( UNIT(current_drive) );
if ( (cnt=result()) != 1 ){
changed_floppies |= 1 << current_drive;
FDCS->reset = 1;
DRS->flags |= FD_VERIFY;
return -1;
}
if ( ( ST3 & 0x60 ) == 0x60 )
DRS->flags &= ~FD_DISK_WRITABLE;
if ( ! ( DRS->flags & FD_DISK_NEWCHANGE) ){
/* the following code is only executed the first time
* a particular disk change has been detected */
changed_floppies |= 1 << current_drive;
if (DRS->keep_data >= 0) {
if ((DP->flags & FTD_MSG) &&
current_type[current_drive] != NULL)
printk(DEVICE_NAME
": Disk type is undefined after "
"disk change in fd%d\n",
current_drive);
current_type[current_drive] = NULL;
floppy_sizes[current_drive] = MAX_DISK_SIZE;
}
if ( ST3 & 0x10 )
DRS->track = 0;
}
}
if ( dir ) /* check if media changed is still on */
DRS->flags |= FD_DISK_NEWCHANGE;
else {
DRS->flags &= ~FD_DISK_NEWCHANGE;
DRS->last_checked =jiffies;
}
if(disk_change(current_drive))
twaddle(); /* this clears the dcl on certain drive/controller
* combinations */
return DRS->flags;
return;
}
static void floppy_ready(void)
......@@ -1411,7 +1514,7 @@ static void floppy_ready(void)
setup_rw_floppy();
}
static void floppy_on(unsigned int drive)
static void floppy_start(void)
{
timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
timer_active |= 1 << FLOPPY_TIMER;
......@@ -1422,7 +1525,7 @@ static void floppy_on(unsigned int drive)
/*
* ========================================================================
* here ends the bottom half. Exported routines are:
* floppy_on, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
* floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
* start_motor, reset_fdc, reset_fdc_info, interpret_errors.
* Initialisation also uses output_byte, result, set_dor, floppy_interrupt
* and set_dor.
......@@ -1448,15 +1551,30 @@ static struct cont_t wakeup_cont={
(done_f)empty
};
static int wait_til_done(void)
static int wait_til_done( void (*handler)(void ), int interruptible )
{
int ret;
while(command_status < 2)
floppy_tq.routine = (void *)(void *) handler;
queue_task(&floppy_tq, &tq_timer);
cli();
while(command_status < 2 && NO_SIGNAL)
if (current->pid)
sleep_on( & command_done );
else
interruptible_sleep_on(&command_done);
else {
sti();
run_task_queue(&tq_timer);
cli();
}
if(command_status < 2){
sti();
floppy_shutdown();
redo_fd_request();
return -EINTR;
}
sti();
if ( FDCS->reset )
command_status = FD_COMMAND_ERROR;
if ( command_status == FD_COMMAND_OKAY )
......@@ -1627,7 +1745,7 @@ static void redo_format(void)
raw_cmd.track = format_req.track << floppy->stretch;
buffer_track = -1;
setup_format_params();
floppy_on(current_drive);
floppy_start();
#ifdef DEBUGT
debugt("queue format request");
#endif
......@@ -1643,21 +1761,20 @@ static int do_format(int device, struct format_descr *tmp_format_req)
{
int okay;
lock_fdc(DRIVE(device));
LOCK_FDC(DRIVE(device),1);
set_floppy(device);
if (!floppy ||
tmp_format_req->track >= floppy->track ||
tmp_format_req->head >= floppy->head){
unlock_fdc();
redo_fd_request();
return -EINVAL;
}
format_req = *tmp_format_req;
format_errors = 0;
cont = &format_cont;
errors = &format_errors;
redo_format();
okay=wait_til_done();
unlock_fdc();
CALL(okay=wait_til_done(redo_format,1));
redo_fd_request();
return okay;
}
......@@ -1676,8 +1793,7 @@ static void request_done(int uptodate)
timer_active &= ~(1 << FLOPPY_TIMER);
if (!CURRENT){
printk(DEVICE_NAME
": request list destroyed in floppy request done\n");
DPRINT("request list destroyed in floppy request done\n");
return;
}
if (uptodate){
......@@ -1707,7 +1823,7 @@ static void request_done(int uptodate)
}
if ( current_count_sectors && ! CURRENT )
printk(DEVICE_NAME "request list destroyed in floppy request done\n");
DPRINT("request list destroyed in floppy request done\n");
} else {
if(CURRENT->cmd == WRITE) {
......@@ -1727,11 +1843,7 @@ static void request_done(int uptodate)
/* Interrupt handler evaluating the result of the r/w operation */
static void rw_interrupt(void)
{
#if 0
int i;
#endif
int nr_sectors, ssize;
char bad;
if ( ! DRS->first_read_date )
DRS->first_read_date = jiffies;
......@@ -1746,8 +1858,8 @@ static void rw_interrupt(void)
if ( nr_sectors > current_count_sectors + ssize -
(current_count_sectors + sector_t) % ssize +
sector_t % ssize){
printk(DEVICE_NAME ": long rw: %x instead of %lx\n",
nr_sectors, current_count_sectors);
DPRINT2("long rw: %x instead of %lx\n",
nr_sectors, current_count_sectors);
printk("rs=%d s=%d\n", R_SECTOR, SECTOR);
printk("rh=%d h=%d\n", R_HEAD, HEAD);
printk("rt=%d t=%d\n", R_TRACK, TRACK);
......@@ -1757,23 +1869,8 @@ static void rw_interrupt(void)
#endif
if ( nr_sectors < 0 )
nr_sectors = 0;
if ( nr_sectors < current_count_sectors ){
#if 0
printk(DEVICE_NAME ": short read got %d instead of %ld\n",
nr_sectors, current_count_sectors);
#endif
#if 0
printk("command: ");
for(i=0; i<raw_cmd.cmd_count; i++)
printk("%x ", raw_cmd.cmd[i]);
printk("rate=%x\n", raw_cmd.rate);
printk("reply: ");
for(i=0; i< inr; i++)
printk("%x ", reply_buffer[i]);
printk("\n");
#endif
if ( nr_sectors < current_count_sectors )
current_count_sectors = nr_sectors;
}
switch (interpret_errors()){
case 2:
......@@ -1788,13 +1885,6 @@ static void rw_interrupt(void)
break;
case 0:
if ( !current_count_sectors){
int i;
printk(DEVICE_NAME ": dma problem?\n");
for(i=0; i< inr ; i++)
printk("%2x,", reply_buffer[i]);
printk("\n");
bad=1;
cont->error();
cont->redo();
return;
}
......@@ -1806,9 +1896,8 @@ static void rw_interrupt(void)
if (probing) {
if (DP->flags & FTD_MSG)
printk(DEVICE_NAME
": Auto-detected floppy type %s in fd%d\n",
floppy->name,current_drive);
DPRINT2("Auto-detected floppy type %s in fd%d\n",
floppy->name,current_drive);
current_type[current_drive] = floppy;
floppy_sizes[DRIVE(current_drive) + (FDC(current_drive) << 7)] =
floppy->size >> 1;
......@@ -1840,7 +1929,7 @@ static int buffer_chain_size(void)
#ifdef SANITY
if ( !bh ){
printk(DEVICE_NAME ": null request in buffer_chain_size\n");
DPRINT("null request in buffer_chain_size\n");
return size >> 9;
}
#endif
......@@ -1893,7 +1982,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
#ifdef SANITY
if ((remaining >> 9) > CURRENT->nr_sectors &&
CT(COMMAND) == FD_WRITE ){
printk(DEVICE_NAME ": in copy buffer\n");
DPRINT("in copy buffer\n");
printk("current_count_sectors=%ld\n", current_count_sectors);
printk("remaining=%d\n", remaining >> 9);
printk("CURRENT->nr_sectors=%ld\n",CURRENT->nr_sectors);
......@@ -1918,16 +2007,14 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
size = remaining;
#ifdef SANITY
if (!bh){
printk(DEVICE_NAME
": bh=null in copy buffer before copy\n");
DPRINT("bh=null in copy buffer before copy\n");
break;
}
if (dma_buffer + size >
floppy_track_buffer + ( 2 * MAX_BUFFER_SECTORS << 9 ) ||
floppy_track_buffer + (max_buffer_sectors << 10) ||
dma_buffer < floppy_track_buffer ){
printk(DEVICE_NAME
": buffer overrun in copy buffer %d\n",
(floppy_track_buffer - dma_buffer) >>9);
DPRINT1("buffer overrun in copy buffer %d\n",
(floppy_track_buffer - dma_buffer) >>9);
printk("sector_t=%d buffer_min=%d\n",
sector_t, buffer_min);
printk("current_count_sectors=%ld\n",
......@@ -1939,7 +2026,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
break;
}
if ( ((int)buffer) % 512 )
printk(DEVICE_NAME ": %p buffer not aligned\n", buffer);
DPRINT1("%p buffer not aligned\n", buffer);
#endif
if ( CT(COMMAND) == FD_READ )
memcpy( buffer, dma_buffer, size);
......@@ -1953,8 +2040,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
bh = bh->b_reqnext;
#ifdef SANITY
if ( !bh){
printk(DEVICE_NAME
": bh=null in copy buffer after copy\n");
DPRINT("bh=null in copy buffer after copy\n");
break;
}
#endif
......@@ -1965,8 +2051,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
if ( remaining ){
if ( remaining > 0 )
max_sector -= remaining >> 9;
printk(DEVICE_NAME
": weirdness: remaining %d\n", remaining>>9);
DPRINT1("weirdness: remaining %d\n", remaining>>9);
}
#endif
}
......@@ -1998,8 +2083,7 @@ static int make_raw_rw_request(void)
raw_cmd.flags |= FD_RAW_WRITE;
COMMAND = FM_MODE(floppy,FD_WRITE);
} else {
printk(DEVICE_NAME
": make_raw_rw_request: unknown command\n");
DPRINT("make_raw_rw_request: unknown command\n");
return 0;
}
......@@ -2081,7 +2165,7 @@ static int make_raw_rw_request(void)
} else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
int direct, indirect;
indirect= transfer_size(ssize,max_sector,MAX_BUFFER_SECTORS*2) -
indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
sector_t;
max_size = buffer_chain_size();
......@@ -2121,8 +2205,8 @@ static int make_raw_rw_request(void)
sector_t < buffer_min ||
((CT(COMMAND) == FD_READ ||
(aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&&
max_sector > 2 * MAX_BUFFER_SECTORS + buffer_min &&
max_size + sector_t > 2 * MAX_BUFFER_SECTORS + buffer_min)
max_sector > 2 * max_buffer_sectors + buffer_min &&
max_size + sector_t > 2 * max_buffer_sectors + buffer_min)
/* not enough space */ ){
buffer_track = -1;
buffer_drive = current_drive;
......@@ -2137,15 +2221,14 @@ static int make_raw_rw_request(void)
* (buffer will be overwritten) */
#ifdef SANITY
if (sector_t != aligned_sector_t && buffer_track == -1 )
printk(DEVICE_NAME
": internal error offset !=0 on write\n");
DPRINT("internal error offset !=0 on write\n");
#endif
buffer_track = raw_cmd.track;
buffer_drive = current_drive;
copy_buffer(ssize, max_sector, 2*MAX_BUFFER_SECTORS+buffer_min);
copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min);
} else
transfer_size(ssize, max_sector,
2*MAX_BUFFER_SECTORS+buffer_min-aligned_sector_t);
2*max_buffer_sectors+buffer_min-aligned_sector_t);
/* round up current_count_sectors to get dma xfer size */
raw_cmd.length = sector_t+current_count_sectors-aligned_sector_t;
......@@ -2159,8 +2242,8 @@ static int make_raw_rw_request(void)
aligned_sector_t < buffer_min )) ||
raw_cmd.length % ( 128 << SIZECODE ) ||
raw_cmd.length <= 0 || current_count_sectors <= 0){
printk(DEVICE_NAME ": fractionary current count b=%lx s=%lx\n",
raw_cmd.length, current_count_sectors);
DPRINT2("fractionary current count b=%lx s=%lx\n",
raw_cmd.length, current_count_sectors);
if ( current_addr != CURRENT->buffer )
printk("addr=%d, length=%ld\n",
(current_addr - floppy_track_buffer ) >> 9,
......@@ -2182,9 +2265,8 @@ static int make_raw_rw_request(void)
current_count_sectors < 0 ||
raw_cmd.length < 0 ||
current_addr + raw_cmd.length >
floppy_track_buffer + ( 2 * MAX_BUFFER_SECTORS << 9 )){
printk(DEVICE_NAME
": buffer overrun in schedule dma\n");
floppy_track_buffer + (max_buffer_sectors << 10)){
DPRINT("buffer overrun in schedule dma\n");
printk("sector_t=%d buffer_min=%d current_count=%ld\n",
sector_t, buffer_min,
raw_cmd.length >> 9 );
......@@ -2198,10 +2280,10 @@ static int make_raw_rw_request(void)
}
} else if (raw_cmd.length > CURRENT->nr_sectors << 9 ||
current_count_sectors > CURRENT->nr_sectors){
printk(DEVICE_NAME ": buffer overrun in direct transfer\n");
DPRINT("buffer overrun in direct transfer\n");
return 0;
} else if ( raw_cmd.length < current_count_sectors << 9 ){
printk(DEVICE_NAME ": more sectors than bytes\n");
DPRINT("more sectors than bytes\n");
printk("bytes=%ld\n", raw_cmd.length >> 9 );
printk("sectors=%ld\n", current_count_sectors);
}
......@@ -2209,15 +2291,24 @@ static int make_raw_rw_request(void)
return 2;
}
static struct cont_t rw_cont={
rw_interrupt,
redo_fd_request,
bad_flp_intr,
request_done };
static void redo_fd_request(void)
{
#define REPEAT {request_done(0); continue; }
int device;
int tmp;
if (current_drive < N_DRIVE)
floppy_off(current_drive);
if (CURRENT && CURRENT->dev < 0) return;
/* hooray, the goto is gone! */
cont = &rw_cont;
while(1){
if (!CURRENT) {
CLEAR_INTR;
......@@ -2229,13 +2320,16 @@ static void redo_fd_request(void)
if (CURRENT->bh && !CURRENT->bh->b_lock)
panic(DEVICE_NAME ": block not locked");
device = MINOR(CURRENT->dev);
device = CURRENT->dev;
set_fdc( DRIVE(device));
CHECK_RESET;
timer_table[FLOPPY_TIMER].expires = jiffies + DP->timeout;
timer_active |= 1 << FLOPPY_TIMER;
raw_cmd.flags=0;
start_motor();
if (( changed_floppies | fake_change) & ( 1 << DRIVE(device))){
printk(DEVICE_NAME
": disk absent or changed during operation\n");
if(test_bit( DRIVE(device), &fake_change) ||
test_bit( DRIVE(device), &changed_floppies)){
DPRINT("disk absent or changed during operation\n");
REPEAT;
}
set_floppy(device);
......@@ -2243,8 +2337,7 @@ static void redo_fd_request(void)
if (!probing){
DRS->probed_format = 0;
if ( next_valid_format() ){
printk(DEVICE_NAME
": no autodetectable formats\n");
DPRINT("no autodetectable formats\n");
floppy = NULL;
REPEAT;
}
......@@ -2262,8 +2355,8 @@ static void redo_fd_request(void)
if ( DRS->flags & FD_NEED_TWADDLE )
twaddle();
floppy_on(current_drive);
floppy_tq.routine = (void *)(void *) floppy_start;
queue_task(&floppy_tq, &tq_timer);
#ifdef DEBUGT
debugt("queue fd request");
#endif
......@@ -2272,18 +2365,15 @@ static void redo_fd_request(void)
#undef REPEAT
}
static struct cont_t rw_cont={
rw_interrupt,
redo_fd_request,
bad_flp_intr,
request_done };
void do_fd_request(void)
{
if ( fdc_busy)
printk("do fd request\n");
lock_fdc(-1);
cont = &rw_cont;
if (fdc_busy)
/* fdc busy, this new request will be treated when the
current one is done */
return;
/* fdc_busy cannot be set by an interrupt or a bh */
floppy_grab_irq_and_dma();
fdc_busy=1;
redo_fd_request();
}
......@@ -2303,12 +2393,12 @@ static struct cont_t reset_cont={
generic_failure,
generic_done };
static int user_reset_fdc(int drive, int arg)
static int user_reset_fdc(int drive, int arg, int interruptible)
{
int result;
result=0;
lock_fdc(drive);
LOCK_FDC(drive,interruptible);
switch(arg){
case FD_RESET_ALWAYS:
FDCS->reset=1;
......@@ -2322,12 +2412,11 @@ static int user_reset_fdc(int drive, int arg)
cont = &reset_cont;
timer_table[FLOPPY_TIMER].expires = jiffies + 5;
timer_active |= 1 << FLOPPY_TIMER;
reset_fdc();
result=wait_til_done();
CALL(result=wait_til_done(reset_fdc,interruptible));
}
if ( UDRS->track == PROVEN_ABSENT )
UDRS->track = NEED_2_RECAL;
unlock_fdc();
redo_fd_request();
return result;
}
......@@ -2345,16 +2434,10 @@ static int fd_copyout(void *param, volatile void *address, int size)
memcpy_tofs(param,(void *) address, size);
return 0;
}
#define COPYOUT(x) (fd_copyout( (void *)param, &(x), sizeof(x)))
#define COPYIN(x) (memcpy_fromfs( &(x), (void *) param, sizeof(x)),0)
static void poll_drive(int drive)
{
lock_fdc(drive);
start_motor();
unlock_fdc();
}
static char *drive_name(int type, int drive )
{
struct floppy_struct *floppy;
......@@ -2390,10 +2473,14 @@ static int raw_cmd_ioctl(int drive, void *param)
if ( FDC(i) != fdc)
continue;
if ( i == drive ){
if ( drive_state[i].fd_ref > 1 )
return -EBUSY;
} else if ( drive_state[i].fd_ref )
return -EBUSY;
if ( drive_state[i].fd_ref > 1 ){
FDCS->rawcmd = 2;
break;
}
} else if ( drive_state[i].fd_ref ){
FDCS->rawcmd = 2;
break;
}
}
if(FDCS->reset)
......@@ -2402,23 +2489,27 @@ static int raw_cmd_ioctl(int drive, void *param)
COPYIN(raw_cmd);
raw_cmd.rate &= 0x03;
count = raw_cmd.length;
if ((raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)) &&
count > MAX_BUFFER_SECTORS * 512 * 2 )
return -ENOMEM;
if (raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)){
if(count > max_buffer_sectors * 1024 )
return -ENOMEM;
buffer_track = -1;
}
if ( raw_cmd.flags & FD_RAW_WRITE ){
i = verify_area(VERIFY_READ, raw_cmd.data, count );
if (i)
return i;
buffer_track = -1;
memcpy_fromfs(floppy_track_buffer, raw_cmd.data, count);
}
current_addr = floppy_track_buffer;
raw_cmd.flags |= FD_RAW_USER_SUPPLIED;
cont = &raw_cmd_cont;
floppy_on(current_drive);
ret=wait_til_done();
CALL(ret=wait_til_done(floppy_start,1));
if( inb_p(FD_DIR) & 0x80 )
raw_cmd.flags |= FD_RAW_DISK_CHANGE;
else
raw_cmd.flags &= ~FD_RAW_DISK_CHANGE;
if(raw_cmd.flags & FD_RAW_NO_MOTOR_AFTER)
motor_off_callback(drive);
if ( !ret && !FDCS->reset ){
raw_cmd.reply_count = inr;
......@@ -2437,16 +2528,16 @@ static int raw_cmd_ioctl(int drive, void *param)
if (i)
return i;
}
return COPYOUT(raw_cmd);
}
static int invalidate_drive(int rdev)
{
/* invalidate the buffer track to force a reread */
fake_change |= 1 << DRIVE(rdev);
set_bit( DRIVE(rdev), &fake_change);
redo_fd_request();
check_disk_change(rdev);
unlock_fdc();
return 0;
}
......@@ -2462,12 +2553,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
struct floppy_struct *this_floppy;
char *name;
device = MINOR(inode->i_rdev);
device = inode->i_rdev;
switch (cmd) {
RO_IOCTLS(device,param);
}
type = TYPE(MINOR(device));
drive = DRIVE(MINOR(device));
type = TYPE(device);
drive = DRIVE(device);
switch (cmd) {
case FDGETDRVTYP:
i=verify_area(VERIFY_WRITE,(void *) param,16);
......@@ -2491,7 +2582,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return -ENODEV;
return COPYOUT(this_floppy[0]);
case FDPOLLDRVSTAT:
poll_drive(drive);
check_disk_change(device);
/* fall through */
case FDGETDRVSTAT:
return COPYOUT(*UDRS);
......@@ -2516,10 +2607,10 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case FDRAWCMD:
if (type)
return -EINVAL;
lock_fdc(drive);
LOCK_FDC(drive,1);
set_floppy(device);
i = raw_cmd_ioctl(drive, (void *) param);
unlock_fdc();
CALL(i = raw_cmd_ioctl(drive, (void *) param));
redo_fd_request();
return i;
case FDFMTTRK:
if (UDRS->fd_ref != 1)
......@@ -2533,14 +2624,14 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case FDFMTBEG:
return 0;
case FDCLRPRM:
lock_fdc(drive);
LOCK_FDC(drive,1);
current_type[drive] = NULL;
floppy_sizes[drive] = 2;
UDRS->keep_data = 0;
return invalidate_drive(device);
case FDFMTEND:
case FDFLUSH:
lock_fdc(drive);
LOCK_FDC(drive,1);
return invalidate_drive(device);
case FDSETPRM:
case FDDEFPRM:
......@@ -2555,12 +2646,11 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
if ( type){
if ( !suser() )
return -EPERM;
lock_fdc(-1);
LOCK_FDC(-1,1);
for ( cnt = 0; cnt < N_DRIVE; cnt++){
if (TYPE(drive_state[cnt].fd_device) == type &&
drive_state[cnt].fd_ref){
fake_change |= 1 << cnt;
}
drive_state[cnt].fd_ref)
set_bit(drive, &fake_change);
}
floppy_type[type] = newparams;
floppy_type[type].name="user format";
......@@ -2572,7 +2662,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
floppy_sizes[cnt+0x80]=
#endif
floppy_type[type].size>>1;
unlock_fdc();
redo_fd_request();
for ( cnt = 0; cnt < N_DRIVE; cnt++){
if (TYPE(drive_state[cnt].fd_device) == type &&
drive_state[cnt].fd_ref)
......@@ -2582,11 +2672,13 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
lock_fdc(drive);
if ( cmd != FDDEFPRM )
LOCK_FDC(drive,1);
if ( cmd != FDDEFPRM ){
/* notice a disk change immediately, else
* we loose our settings immediately*/
raw_cmd.flags = 0;
start_motor();
}
user_params[drive] = newparams;
if (buffer_drive == drive &&
buffer_max > user_params[drive].sect)
......@@ -2605,11 +2697,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
if (DRS->maxblock >
user_params[drive].sect ||
DRS->maxtrack )
return invalidate_drive(device);
invalidate_drive(device);
else
return unlock_fdc();
redo_fd_request();
return 0;
case FDRESET:
return user_reset_fdc( drive, (int)param);
return user_reset_fdc( drive, (int)param, 1);
case FDMSGON:
UDP->flags |= FTD_MSG;
return 0;
......@@ -2621,9 +2714,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
(unsigned short) (param & 0x0f);
return 0;
case FDTWADDLE:
lock_fdc(drive);
LOCK_FDC(drive,1);
twaddle();
unlock_fdc();
redo_fd_request();
}
if ( ! suser() )
return -EPERM;
......@@ -2674,21 +2767,9 @@ static void config_types(void)
printk("\n");
}
static void maybe_check_change(int device)
{
register int drive;
drive = DRIVE(device);
if (UDRS->last_checked + UDP->checkfreq < jiffies ||
UDRS->flags & FD_VERIFY ||
(( changed_floppies | fake_change ) & ( 1 << drive)))
check_disk_change(device);
}
int floppy_is_wp( int minor)
{
maybe_check_change(minor + (MAJOR_NR << 8));
check_disk_change(minor + (MAJOR_NR << 8));
return ! ( drive_state[ DRIVE(minor) ].flags & FD_DISK_WRITABLE );
}
......@@ -2697,10 +2778,10 @@ int floppy_is_wp( int minor)
static int floppy_##op(struct inode * inode, struct file * filp, \
char * buf, int count) \
{ \
maybe_check_change(inode->i_rdev); \
check_disk_change(inode->i_rdev); \
if ( drive_state[DRIVE(inode->i_rdev)].track == PROVEN_ABSENT ) \
return -ENXIO; \
if ( changed_floppies & ( 1 << DRIVE(inode->i_rdev) )) \
if ( test_bit(DRIVE(inode->i_rdev),&changed_floppies)) \
return -ENXIO; \
return block_##op(inode, filp, buf, count); \
}
......@@ -2708,21 +2789,21 @@ static int floppy_##op(struct inode * inode, struct file * filp, \
WRAPPER(read)
WRAPPER(write)
static int exclusive = 0;
static void floppy_release(struct inode * inode, struct file * filp)
{
int drive= DRIVE(inode->i_rdev);
int drive;
drive = DRIVE(inode->i_rdev);
if(filp->f_mode & 2)
fsync_dev(inode->i_rdev);
if ( UDRS->fd_ref < 0)
fsync_dev(inode->i_rdev);
if (UDRS->fd_ref < 0)
UDRS->fd_ref=0;
else if (!UDRS->fd_ref--) {
printk(DEVICE_NAME ": floppy_release with fd_ref == 0");
DPRINT("floppy_release with fd_ref == 0");
UDRS->fd_ref = 0;
}
floppy_release_irq_and_dma();
exclusive=0;
}
/*
......@@ -2733,17 +2814,14 @@ static void floppy_release(struct inode * inode, struct file * filp)
#define RETERR(x) \
do{floppy_release(inode,filp); \
return -(x);}while(0)
static int usage_count = 0;
static int floppy_open(struct inode * inode, struct file * filp)
{
int drive;
int old_dev;
if (exclusive)
return -EBUSY;
if (!filp) {
printk(DEVICE_NAME ": Weird, open called with filp=0\n");
DPRINT("Weird, open called with filp=0\n");
return -EIO;
}
......@@ -2751,11 +2829,6 @@ static int floppy_open(struct inode * inode, struct file * filp)
if ( drive >= N_DRIVE || !( ALLOWED_DRIVE_MASK & ( 1 << drive)) )
return -ENXIO;
if (command_status == FD_COMMAND_DETECT && drive >= current_drive) {
lock_fdc(-1);
unlock_fdc();
}
if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
return -ENXIO;
......@@ -2767,17 +2840,18 @@ static int floppy_open(struct inode * inode, struct file * filp)
if (UDRS->fd_ref && old_dev != inode->i_rdev)
return -EBUSY;
if (filp->f_flags & O_EXCL) {
if (usage_count)
return -EBUSY;
else
exclusive = 1;
}
if(UDRS->fd_ref == -1 ||
(UDRS->fd_ref && (filp->f_flags & O_EXCL)))
return -EBUSY;
if (floppy_grab_irq_and_dma())
return -EBUSY;
UDRS->fd_ref++;
if(filp->f_flags & O_EXCL)
UDRS->fd_ref = -1;
else
UDRS->fd_ref++;
UDRS->fd_device = inode->i_rdev;
if (old_dev && old_dev != inode->i_rdev) {
......@@ -2799,15 +2873,16 @@ static int floppy_open(struct inode * inode, struct file * filp)
if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
RETERR(ENXIO);
if (user_reset_fdc(drive, FD_RESET_IF_NEEDED))
if (user_reset_fdc(drive, FD_RESET_IF_NEEDED,0))
RETERR(EIO);
if (filp->f_mode & 3) {
UDRS->last_checked = 0;
check_disk_change(inode->i_rdev);
if (changed_floppies & ( 1 << drive ))
if (test_bit(drive,&changed_floppies))
RETERR(ENXIO);
}
if (filp->f_mode && UDRS->track == PROVEN_ABSENT )
RETERR(ENXIO);
......@@ -2817,50 +2892,41 @@ static int floppy_open(struct inode * inode, struct file * filp)
#undef RETERR
}
/*
* Acknowledge disk change
*/
static int ack_change(int drive)
{
unsigned int mask = 1 << drive;
UDRS->maxblock = 0;
UDRS->maxtrack = 0;
if ( buffer_drive == drive )
buffer_track = -1;
fake_change &= ~mask;
changed_floppies &= ~mask;
return 1;
}
/*
* Check if the disk has been changed or if a change has been faked.
*/
static int check_floppy_change(dev_t dev)
{
int drive = DRIVE( dev );
unsigned int mask = 1 << drive;
if (MAJOR(dev) != MAJOR_NR) {
printk(DEVICE_NAME ": floppy_changed: not a floppy\n");
DPRINT("floppy_changed: not a floppy\n");
return 0;
}
if (fake_change & mask)
return ack_change(drive);
if(test_bit(drive, &changed_floppies))
return 1;
if ((UDRS->flags & FD_VERIFY ) || (changed_floppies & mask) ||
UDRS->last_checked + UDP->checkfreq <
jiffies){
user_reset_fdc(drive, FD_RESET_IF_NEEDED);
poll_drive(drive);
if (changed_floppies & mask){
UDRS->generation++;
return ack_change(drive);
}
if(UDRS->last_checked + UDP->checkfreq < jiffies){
lock_fdc(drive,0);
start_motor();
redo_fd_request();
}
if(test_bit(drive, &changed_floppies))
return 1;
if(test_bit(drive, &fake_change))
return 1;
return 0;
}
static struct cont_t poll_cont={
success_and_wakeup,
floppy_ready,
generic_failure,
generic_done };
/* revalidate the floppy disk, i.e. trigger format autodetection by reading
* the bootblock (block 0). "Autodetection" is also needed to check wether
* there is a disk in the drive at all... Thus we also do it for fixed
......@@ -2868,13 +2934,48 @@ static int check_floppy_change(dev_t dev)
static int floppy_revalidate(dev_t dev)
{
struct buffer_head * bh;
if (!(bh = getblk(dev,0,1024)))
return 1;
if ( bh && ! bh->b_uptodate)
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
brelse(bh);
int drive=DRIVE(dev);
int cf;
cf = test_bit(drive, &changed_floppies);
if(cf || test_bit(drive, &fake_change)){
lock_fdc(drive,0);
cf = test_bit(drive, &changed_floppies);
if(! (cf || test_bit(drive, &fake_change))){
redo_fd_request(); /* already done by another thread */
return 0;
}
UDRS->maxblock = 0;
UDRS->maxtrack = 0;
if ( buffer_drive == drive)
buffer_track = -1;
clear_bit(drive, &fake_change);
clear_bit(drive, &changed_floppies);
if(cf){
UDRS->generation++;
if(!current_type[drive] && !TYPE(dev)){
/* auto-sensing */
if (!(bh = getblk(dev,0,1024))){
redo_fd_request();
return 1;
}
if ( bh && ! bh->b_uptodate)
ll_rw_block(READ, 1, &bh);
redo_fd_request();
wait_on_buffer(bh);
brelse(bh);
return 0;
} else {
/* no auto-sense, just clear dcl */
raw_cmd.flags=FD_RAW_NEED_SEEK|FD_RAW_NEED_DISK;
raw_cmd.track=0;
raw_cmd.cmd_count=0;
cont = &poll_cont;
wait_til_done(floppy_ready,0);
}
}
redo_fd_request();
}
return 0;
}
......@@ -2946,6 +3047,8 @@ void floppy_init(void)
{
int i;
sti();
if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
printk("Unable to get major %d for floppy\n",MAJOR_NR);
return;
......@@ -2979,7 +3082,7 @@ void floppy_init(void)
/* initialise drive state */
for (i = 0; i < N_DRIVE ; i++) {
current_drive = i;
DRS->flags = FD_VERIFY;
DRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE;
DRS->generation = 0;
DRS->keep_data = 0;
DRS->fd_ref = 0;
......@@ -2996,7 +3099,7 @@ void floppy_init(void)
for (i = 0 ; i < N_FDC ; i++) {
fdc = i;
FDCS->rawcmd = 2;
if(user_reset_fdc(-1,FD_RESET_IF_NEEDED))
if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
continue;
/* Try to determine the floppy controller type */
FDCS->version = get_fdc_version();
......@@ -3008,7 +3111,7 @@ void floppy_init(void)
* to avoid interrupt garbage.
*/
FDCS->has_fifo = FDCS->version >= FDC_82077_ORIG;
user_reset_fdc(-1,FD_RESET_ALWAYS);
user_reset_fdc(-1,FD_RESET_ALWAYS,0);
}
fdc=0;
current_drive = 0;
......@@ -3016,20 +3119,22 @@ void floppy_init(void)
initialising=0;
}
int floppy_grab_irq_and_dma(void)
static int floppy_grab_irq_and_dma(void)
{
if (usage_count++)
cli();
if (usage_count++){
sti();
return 0;
}
sti();
if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) {
printk(DEVICE_NAME
": Unable to grab IRQ%d for the floppy driver\n",
FLOPPY_IRQ);
DPRINT1("Unable to grab IRQ%d for the floppy driver\n",
FLOPPY_IRQ);
return -1;
}
if (request_dma(FLOPPY_DMA,"floppy")) {
printk(DEVICE_NAME
": Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA);
DPRINT1("Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA);
free_irq(FLOPPY_IRQ);
return -1;
}
......@@ -3037,10 +3142,14 @@ int floppy_grab_irq_and_dma(void)
return 0;
}
void floppy_release_irq_and_dma(void)
static void floppy_release_irq_and_dma(void)
{
if (--usage_count)
cli();
if (--usage_count){
sti();
return;
}
sti();
disable_dma(FLOPPY_DMA);
free_dma(FLOPPY_DMA);
disable_irq(FLOPPY_IRQ);
......
......@@ -80,7 +80,7 @@ static int hd_error = 0;
struct hd_i_struct {
unsigned int head,sect,cyl,wpcom,lzone,ctl;
};
static struct hd_driveid *hd_ident_info[MAX_HD];
static struct hd_driveid *hd_ident_info[MAX_HD] = {0, };
#ifdef HD_TYPE
static struct hd_i_struct hd_info[] = { HD_TYPE };
......@@ -275,16 +275,21 @@ static void identify_intr(void)
{
unsigned int dev = DEVICE_NR(CURRENT->dev);
unsigned short stat = inb_p(HD_STATUS);
struct hd_driveid id;
struct hd_driveid *id = hd_ident_info[dev];
if (unmask_intr[dev])
sti();
if (stat & (BUSY_STAT|ERR_STAT))
printk (" hd%c: identity unknown\n", dev+'a');
else {
insw(HD_DATA, (char *)&id, sizeof(id)/2); /* get ID bytes */
max_mult[dev] = id.max_multsect;
if ((id.cur_valid&1) && id.cur_cyls && id.cur_heads && (id.cur_heads <= 16) && id.cur_sectors) {
if (stat & (BUSY_STAT|ERR_STAT)) {
printk (" hd%c: non-IDE device, CHS=%d%d%d\n", dev+'a',
hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
if (id != NULL) {
hd_ident_info[dev] = NULL;
kfree_s (id, 512);
}
} else {
insw(HD_DATA, id, 256); /* get ID info */
max_mult[dev] = id->max_multsect;
if ((id->field_valid&1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
/*
* Extract the physical drive geometry for our use.
* Note that we purposely do *not* update the bios_info.
......@@ -292,31 +297,24 @@ static void identify_intr(void)
* still have the same logical view as the BIOS does,
* which keeps the partition table from being screwed.
*/
hd_info[dev].cyl = id.cur_cyls;
hd_info[dev].head = id.cur_heads;
hd_info[dev].sect = id.cur_sectors;
hd_info[dev].cyl = id->cur_cyls;
hd_info[dev].head = id->cur_heads;
hd_info[dev].sect = id->cur_sectors;
}
fixstring (id.serial_no, sizeof(id.serial_no));
fixstring (id.fw_rev, sizeof(id.fw_rev));
fixstring (id.model, sizeof(id.model));
fixstring (id->serial_no, sizeof(id->serial_no));
fixstring (id->fw_rev, sizeof(id->fw_rev));
fixstring (id->model, sizeof(id->model));
printk (" hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
dev+'a', id.model, id.cyls*id.heads*id.sectors/2048,
id.buf_size/2, hd_info[dev].cyl, hd_info[dev].head,
hd_info[dev].sect, id.max_multsect);
/* save drive info for later query via HDIO_GETIDENTITY */
if (NULL != (hd_ident_info[dev] = (struct hd_driveid *)kmalloc(sizeof(id),GFP_ATOMIC)))
*hd_ident_info[dev] = id;
/* Quantum drives go weird at this point, so reset them! */
/* In fact, we should probably do a reset in any case in */
/* case we changed the geometry */
if (!strncmp(id.model, "QUANTUM", 7))
reset = 1;
/* flush remaining 384 (reserved/undefined) ID bytes: */
insw(HD_DATA,(char *)&id,sizeof(id)/2);
insw(HD_DATA,(char *)&id,sizeof(id)/2);
insw(HD_DATA,(char *)&id,sizeof(id)/2);
dev+'a', id->model, id->cyls*id->heads*id->sectors/2048,
id->buf_size/2, hd_info[dev].cyl, hd_info[dev].head,
hd_info[dev].sect, id->max_multsect);
/*
* Early model Quantum drives go weird at this point,
* but doing a recalibrate seems to "fix" them.
* (Doing a full reset confuses some newer model Quantums)
*/
if (!strncmp(id->model, "QUANTUM", 7))
special_op[dev] = recalibrate[dev] = 1;
}
#if (HD_DELAY > 0)
last_req = read_timer();
......@@ -1040,7 +1038,7 @@ static void hd_geninit(void)
}
hd[i<<6].nr_sects = bios_info[i].head *
bios_info[i].sect * bios_info[i].cyl;
hd_ident_info[i] = NULL;
hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
special_op[i] = 1;
}
if (NR_HD) {
......
......@@ -22,6 +22,7 @@
#define RAMDISK_MINOR 1
extern void wait_for_keypress(void);
char *rd_start;
int rd_length = 0;
......@@ -102,7 +103,7 @@ static void do_load(void)
int i = 1;
int nblocks;
char *cp;
/*
* Check for a super block on the diskette.
* The old-style boot/root diskettes had their RAM image
......@@ -164,9 +165,6 @@ static void do_load(void)
}
}
int floppy_grab_irq_and_dma(void);
void floppy_release_irq_and_dma(void);
/*
* If the root device is the RAM disk, try to load it.
* In order to do this, the root device is originally set to the
......@@ -174,6 +172,9 @@ void floppy_release_irq_and_dma(void);
*/
void rd_load(void)
{
struct inode inode;
struct file filp;
/* If no RAM disk specified, give up early. */
if (!rd_length)
return;
......@@ -184,12 +185,18 @@ void rd_load(void)
if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR)
return;
/* ugly, ugly */
if (floppy_grab_irq_and_dma()) {
printk("Unable to grab floppy IRQ/DMA for loading ramdisk image\n");
return;
/* for Slackware install disks */
printk(KERN_NOTICE "VFS: Insert ramdisk floppy and press ENTER\n");
wait_for_keypress();
memset(&filp, 0, sizeof(filp));
memset(&inode, 0, sizeof(inode));
inode.i_rdev = ROOT_DEV;
filp.f_mode = 1; /* read only */
filp.f_inode = &inode;
if(blkdev_open(&inode, &filp) == 0 ){
do_load();
if(filp.f_op && filp.f_op->release)
filp.f_op->release(&inode,&filp);
}
check_disk_change(ROOT_DEV);
do_load();
floppy_release_irq_and_dma();
}
......@@ -2100,7 +2100,8 @@ static void clear_selection()
*/
#define colourmap ((char *)0xa0000)
#define blackwmap ((char *)0xb0000)
/* Pauline Middelink reports that we should use 0xA0000 for the bwmap as well.. */
#define blackwmap ((char *)0xa0000)
#define cmapsz 8192
#define seq_port_reg (0x3c4)
#define seq_port_val (0x3c5)
......
......@@ -4,6 +4,7 @@
* - Thanks much to Gunter Windau for pointing out to me where the error
* checking ought to be.
* Copyright (C) 1993 by Nigel Gamble (added interrupt code)
* Copyright (C) 1994 by Alan Cox (Modularised it)
*/
#include <linux/errno.h>
......@@ -17,6 +18,24 @@
#include <asm/segment.h>
#include <asm/system.h>
/* the BIOS manuals say there can be up to 4 lpt devices
* but I have not seen a board where the 4th address is listed
* if you have different hardware change the table below
* please let me know if you have different equipment
* if you have more than 3 printers, remember to increase LP_NO
*/
struct lp_struct lp_table[] = {
{ 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
{ 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
{ 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
};
#define LP_NO 3
#ifdef MODULE
#include <linux/module.h>
#include "../../tools/version.h"
#endif
/*
* All my debugging code assumes that you debug with only one printer at
* a time. RWWH
......@@ -305,7 +324,9 @@ static int lp_open(struct inode * inode, struct file * file)
}
LP_F(minor) |= LP_BUSY;
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
return 0;
}
......@@ -321,6 +342,9 @@ static void lp_release(struct inode * inode, struct file * file)
}
LP_F(minor) &= ~LP_BUSY;
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
......@@ -418,6 +442,8 @@ static struct file_operations lp_fops = {
lp_release
};
#ifndef MODULE
long lp_init(long kmem_start)
{
int offset = 0;
......@@ -450,3 +476,42 @@ long lp_init(long kmem_start)
printk("lp_init: no lp devices found\n");
return kmem_start;
}
#else
char kernel_version[]= UTS_RELEASE;
int init_module(void)
{
int offset = 0;
unsigned int testvalue = 0;
int count = 0;
if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
printk("unable to get major %d for line printer\n", LP_MAJOR);
return -EIO;
}
/* take on all known port values */
for (offset = 0; offset < LP_NO; offset++) {
/* write to port & read back to check */
outb_p( LP_DUMMY, LP_B(offset));
for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
;
testvalue = inb_p(LP_B(offset));
if (testvalue == LP_DUMMY) {
LP_F(offset) |= LP_EXIST;
lp_reset(offset);
printk("lp_init: lp%d exists, ", offset);
if (LP_IRQ(offset))
printk("using IRQ%d\n", LP_IRQ(offset));
else
printk("using polling driver\n");
count++;
}
}
if (count == 0)
printk("lp_init: no lp devices found\n");
return 0;
}
#endif
......@@ -453,6 +453,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
goto handle_newline;
}
if (c == EOF_CHAR(tty)) {
if (tty->canon_head != tty->read_head)
set_bit(TTY_PUSH, &tty->flags);
c = __DISABLED_CHAR;
goto handle_newline;
}
......@@ -718,24 +720,6 @@ static inline void copy_from_read_buf(struct tty_struct *tty,
*nr -= n;
}
/*
* Called to gobble up an immediately following EOF when there is no
* more room in buf (this can happen if the user "pushes" some
* characters using ^D). This prevents the next read() from falsely
* returning EOF.
*/
static inline void gobble_eof(struct tty_struct *tty)
{
cli();
if ((tty->read_cnt) &&
(tty->read_buf[tty->read_tail] == __DISABLED_CHAR) &&
clear_bit(tty->read_tail, &tty->read_flags)) {
tty->read_tail = (tty->read_tail+1) & (N_TTY_BUF_SIZE-1);
tty->read_cnt--;
}
sti();
}
static int read_chan(struct tty_struct *tty, struct file *file,
unsigned char *buf, unsigned int nr)
{
......@@ -744,6 +728,9 @@ static int read_chan(struct tty_struct *tty, struct file *file,
unsigned char *b = buf;
int minimum, time;
int retval = 0;
int size;
do_it_again:
if (!tty->read_buf) {
printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
......@@ -858,7 +845,6 @@ static int read_chan(struct tty_struct *tty, struct file *file,
put_fs_byte(c, b++);
if (--nr)
continue;
gobble_eof(tty);
break;
}
if (--tty->canon_data < 0) {
......@@ -896,7 +882,14 @@ static int read_chan(struct tty_struct *tty, struct file *file,
current->state = TASK_RUNNING;
current->timeout = 0;
return (b - buf) ? b - buf : retval;
size = b - buf;
if (size && nr)
clear_bit(TTY_PUSH, &tty->flags);
if (!size && clear_bit(TTY_PUSH, &tty->flags))
goto do_it_again;
if (!size && !retval)
clear_bit(TTY_PUSH, &tty->flags);
return (size ? size : retval);
}
static int write_chan(struct tty_struct * tty, struct file * file,
......
......@@ -1242,6 +1242,9 @@ static int tty_ioctl(struct inode * inode, struct file * file,
case TIOCSTI:
if ((current->tty != tty) && !suser())
return -EPERM;
retval = verify_area(VERIFY_READ, (void *) arg, 1);
if (retval)
return retval;
ch = get_fs_byte((char *) arg);
tty->ldisc.receive_buf(tty, &ch, &mbz, 1);
return 0;
......@@ -1254,6 +1257,10 @@ static int tty_ioctl(struct inode * inode, struct file * file,
sizeof (struct winsize));
return 0;
case TIOCSWINSZ:
retval = verify_area(VERIFY_READ, (void *) arg,
sizeof (struct winsize));
if (retval)
return retval;
memcpy_fromfs(&tmp_ws, (struct winsize *) arg,
sizeof (struct winsize));
if (memcmp(&tmp_ws, &tty->winsize,
......@@ -1279,6 +1286,9 @@ static int tty_ioctl(struct inode * inode, struct file * file,
redirect = real_tty;
return 0;
case FIONBIO:
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
if (retval)
return retval;
arg = get_fs_long((unsigned long *) arg);
if (arg)
file->f_flags |= O_NONBLOCK;
......@@ -1371,6 +1381,9 @@ static int tty_ioctl(struct inode * inode, struct file * file,
arg = get_fs_long((unsigned long *) arg);
return tty_set_ldisc(tty, arg);
case TIOCLINUX:
retval = verify_area(VERIFY_READ, (void *) arg, 1);
if (retval)
return retval;
switch (get_fs_byte((char *)arg))
{
case 0:
......
......@@ -98,6 +98,9 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
return retval;
if (opt & TERMIOS_TERMIO) {
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
if (retval)
return retval;
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, (struct termio *) arg,
sizeof (struct termio));
......@@ -109,9 +112,13 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
#undef SET_LOW_BITS
} else
} else {
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
if (retval)
return retval;
memcpy_fromfs(&tmp_termios, (struct termios *) arg,
sizeof (struct termios));
}
if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
......@@ -307,6 +314,10 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
(unsigned long *) arg);
return 0;
case TIOCGLCKTRMIOS:
retval = verify_area(VERIFY_READ, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
arg = get_fs_long((unsigned long *) arg);
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct termios));
......@@ -319,7 +330,15 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
case TIOCSLCKTRMIOS:
if (!suser())
return -EPERM;
retval = verify_area(VERIFY_READ, (void *) arg,
sizeof (unsigned long));
if (retval)
return retval;
arg = get_fs_long((unsigned long *) arg);
retval = verify_area(VERIFY_READ, (void *) arg,
sizeof (struct termios));
if (retval)
return retval;
memcpy_fromfs(&real_tty->termios_locked,
(struct termios *) arg,
sizeof (struct termios));
......
......@@ -78,6 +78,7 @@ make one yourself. The wiring is:
#include <netinet/in.h>
#include <errno.h>
#include <linux/delay.h>
#include <linux/lp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
......@@ -196,7 +197,7 @@ plip_init(struct device *dev)
struct net_local *pl;
/* Check that there is something at base_addr. */
outb(0x00, PAR_CONTROL(dev));
outb(LP_PINITP, PAR_CONTROL(dev));
outb(0x00, PAR_DATA(dev));
if (inb(PAR_DATA(dev)) != 0x00)
return -ENODEV;
......@@ -212,9 +213,9 @@ plip_init(struct device *dev)
printk("%s: configured for parallel port at %#3x",
dev->name, dev->base_addr);
autoirq_setup(0);
outb(0x00, PAR_CONTROL(dev));
outb(0x10, PAR_CONTROL(dev));
outb(0x00, PAR_CONTROL(dev));
outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
dev->irq = autoirq_report(1);
if (dev->irq)
printk(", probed IRQ %d.\n", dev->irq);
......@@ -368,7 +369,7 @@ plip_open(struct device *dev)
irq2dev_map[dev->irq] = dev;
sti();
/* enable rx interrupt. */
outb(0x10, PAR_CONTROL(dev));
outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
plip_device_clear(dev);
dev->start = 1;
#ifdef MODULE
......@@ -393,7 +394,7 @@ plip_close(struct device *dev)
/* make sure that we don't register the timer */
del_timer(&lp->tl);
/* release the interrupt. */
outb(0x00, PAR_CONTROL(dev));
outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
......
/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
* High DMA channel support & info by Hannu Savolainen
* and John Boyd, Nov. 1992.
*/
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
#include <asm/io.h> /* need byte IO */
#define deb_outb(x,y) {printk("out %02x, %02x\n", x, y);outb(x,y);}
#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
#define outb outb_p
#endif
/*
* NOTES about DMA transfers:
*
* controller 1: channels 0-3, byte operations, ports 00-1F
* controller 2: channels 4-7, word operations, ports C0-DF
*
* - ALL registers are 8 bits only, regardless of transfer size
* - channel 4 is not used - cascades 1 into 2.
* - channels 0-3 are byte - addresses/counts are for physical bytes
* - channels 5-7 are word - addresses/counts are for physical words
* - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
* - transfer count loaded to registers is 1 less than actual count
* - controller 2 offsets are all even (2x offsets for controller 1)
* - page registers for 5-7 don't use data bit 0, represent 128K pages
* - page registers for 0-3 use bit 0, represent 64K pages
*
* DMA transfers are limited to the lower 16MB of _physical_ memory.
* Note that addresses loaded into registers must be _physical_ addresses,
* not logical addresses (which may differ if paging is active).
*
* Address mapping for channels 0-3:
*
* A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses)
* | ... | | ... | | ... |
* | ... | | ... | | ... |
* | ... | | ... | | ... |
* P7 ... P0 A7 ... A0 A7 ... A0
* | Page | Addr MSB | Addr LSB | (DMA registers)
*
* Address mapping for channels 5-7:
*
* A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses)
* | ... | \ \ ... \ \ \ ... \ \
* | ... | \ \ ... \ \ \ ... \ (not used)
* | ... | \ \ ... \ \ \ ... \
* P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0
* | Page | Addr MSB | Addr LSB | (DMA registers)
*
* Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
* and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
* the hardware level, so odd-byte transfers aren't possible).
*
* Transfer count (_not # bytes_) is limited to 64K, represented as actual
* count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more,
* and up to 128K bytes may be transferred on channels 5-7 in one operation.
*
*/
#define MAX_DMA_CHANNELS 8
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
/* DMA controller registers */
#define DMA1_CMD_REG 0x08 /* command register (w) */
#define DMA1_STAT_REG 0x08 /* status register (r) */
#define DMA1_REQ_REG 0x09 /* request register (w) */
#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
#define DMA1_MODE_REG 0x0B /* mode register (w) */
#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
#define DMA2_CMD_REG 0xD0 /* command register (w) */
#define DMA2_STAT_REG 0xD0 /* status register (r) */
#define DMA2_REQ_REG 0xD2 /* request register (w) */
#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
#define DMA2_MODE_REG 0xD6 /* mode register (w) */
#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
#define DMA_ADDR_0 0x00 /* DMA address registers */
#define DMA_ADDR_1 0x02
#define DMA_ADDR_2 0x04
#define DMA_ADDR_3 0x06
#define DMA_ADDR_4 0xC0
#define DMA_ADDR_5 0xC4
#define DMA_ADDR_6 0xC8
#define DMA_ADDR_7 0xCC
#define DMA_CNT_0 0x01 /* DMA count registers */
#define DMA_CNT_1 0x03
#define DMA_CNT_2 0x05
#define DMA_CNT_3 0x07
#define DMA_CNT_4 0xC2
#define DMA_CNT_5 0xC6
#define DMA_CNT_6 0xCA
#define DMA_CNT_7 0xCE
#define DMA_PAGE_0 0x87 /* DMA page registers */
#define DMA_PAGE_1 0x83
#define DMA_PAGE_2 0x81
#define DMA_PAGE_3 0x82
#define DMA_PAGE_5 0x8B
#define DMA_PAGE_6 0x89
#define DMA_PAGE_7 0x8A
#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
/* enable/disable a specific DMA channel */
static __inline__ void enable_dma(unsigned int dmanr)
{
if (dmanr<=3)
deb_outb(dmanr, DMA1_MASK_REG)
else
deb_outb(dmanr & 3, DMA2_MASK_REG);
}
static __inline__ void disable_dma(unsigned int dmanr)
{
if (dmanr<=3)
deb_outb(dmanr | 4, DMA1_MASK_REG)
else
deb_outb((dmanr & 3) | 4, DMA2_MASK_REG);
}
/* Clear the 'DMA Pointer Flip Flop'.
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
* Use this once to initialize the FF to a known state.
* After that, keep track of it. :-)
* --- In order to do that, the DMA routines below should ---
* --- only be used while interrupts are disabled! ---
*/
static __inline__ void clear_dma_ff(unsigned int dmanr)
{
if (dmanr<=3)
deb_outb(0, DMA1_CLEAR_FF_REG)
else
deb_outb(0, DMA2_CLEAR_FF_REG);
}
/* set mode (above) for a specific DMA channel */
static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
{
if (dmanr<=3)
deb_outb(mode | dmanr, DMA1_MODE_REG)
else
deb_outb(mode | (dmanr&3), DMA2_MODE_REG);
}
/* Set only the page register bits of the transfer address.
* This is used for successive transfers when we know the contents of
* the lower 16 bits of the DMA current address register, but a 64k boundary
* may have been crossed.
*/
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
{
switch(dmanr) {
case 0:
deb_outb(pagenr, DMA_PAGE_0);
break;
case 1:
deb_outb(pagenr, DMA_PAGE_1);
break;
case 2:
deb_outb(pagenr, DMA_PAGE_2);
break;
case 3:
deb_outb(pagenr, DMA_PAGE_3);
break;
case 5:
deb_outb(pagenr & 0xfe, DMA_PAGE_5);
break;
case 6:
deb_outb(pagenr & 0xfe, DMA_PAGE_6);
break;
case 7:
deb_outb(pagenr & 0xfe, DMA_PAGE_7);
break;
}
}
/* Set transfer address & page bits for specific DMA channel.
* Assumes dma flipflop is clear.
*/
static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
{
set_dma_page(dmanr, a>>16);
if (dmanr <= 3) {
deb_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
deb_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE )
} else {
deb_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
deb_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
}
}
/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
* a specific DMA channel.
* You must ensure the parameters are valid.
* NOTE: from a manual: "the number of transfers is one more
* than the initial word count"! This is taken into account.
* Assumes dma flip-flop is clear.
* NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
*/
static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
{
count--;
if (dmanr <= 3) {
deb_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
deb_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
} else {
deb_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
deb_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
}
}
/* Get DMA residue count. After a DMA transfer, this
* should return zero. Reading this while a DMA transfer is
* still in progress will return unpredictable results.
* If called before the channel has been used, it may return 1.
* Otherwise, it returns the number of _bytes_ left to transfer.
*
* Assumes DMA flip-flop is clear.
*/
static __inline__ int get_dma_residue(unsigned int dmanr)
{
unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
: ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
/* using short to get 16-bit wrap around */
unsigned short count;
count = 1 + inb(io_port);
count += inb(io_port) << 8;
return (dmanr<=3)? count : (count<<1);
}
/* These are in kernel/dma.c: */
extern int request_dma(unsigned int dmanr,char * deviceID); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
#endif /* _ASM_DMA_H */
......@@ -147,6 +147,7 @@ static int sync_buffers(dev_t dev, int wait)
2) wait for completion by waiting for all buffers to unlock. */
repeat:
retry = 0;
repeat2:
ncount = 0;
/* We search all lists as a failsafe mechanism, not because we expect
there to be dirty buffers on any of the other lists. */
......@@ -170,6 +171,7 @@ static int sync_buffers(dev_t dev, int wait)
continue;
}
wait_on_buffer (bh);
goto repeat2;
}
/* If an unlocked buffer is not uptodate, there has
been an IO error. Skip it. */
......@@ -183,6 +185,9 @@ static int sync_buffers(dev_t dev, int wait)
on the third pass. */
if (!bh->b_dirt || pass>=2)
continue;
/* don't bother about locked buffers */
if (bh->b_lock)
continue;
bh->b_count++;
bh->b_flushtime = 0;
ll_rw_block(WRITE, 1, &bh);
......@@ -1735,31 +1740,37 @@ asmlinkage int sys_bdflush(int func, int data)
int ncount;
struct buffer_head * bh, *next;
if(!suser()) return -EPERM;
if (!suser())
return -EPERM;
if(func == 1)
if (func == 1)
return sync_old_buffers();
/* Basically func 0 means start, 1 means read param 1, 2 means write param 1, etc */
if(func >= 2){
if (func >= 2) {
i = (func-2) >> 1;
if (i < 0 || i >= N_PARAM) return -EINVAL;
if (i < 0 || i >= N_PARAM)
return -EINVAL;
if((func & 1) == 0) {
error = verify_area(VERIFY_WRITE, (void *) data, sizeof(int));
if(error) return error;
if (error)
return error;
put_fs_long(bdf_prm.data[i], data);
return 0;
};
if(data < bdflush_min[i] || data > bdflush_max[i]) return -EINVAL;
if (data < bdflush_min[i] || data > bdflush_max[i])
return -EINVAL;
bdf_prm.data[i] = data;
return 0;
};
if(bdflush_running++) return -EBUSY; /* Only one copy of this running at one time */
if (bdflush_running)
return -EBUSY; /* Only one copy of this running at one time */
bdflush_running++;
/* OK, from here on is the daemon */
while(1==1){
for (;;) {
#ifdef DEBUG
printk("bdflush() activated...");
#endif
......
......@@ -728,10 +728,10 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
if (!fn)
break;
retval = fn(&bprm, regs);
if (retval == 0) {
if (retval >= 0) {
iput(bprm.inode);
current->did_exec = 1;
return 0;
return retval;
}
if (retval != -ENOEXEC)
break;
......
......@@ -72,7 +72,7 @@ static int ext_readdir(struct inode * inode, struct file * filp,
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
if (filp->f_pos % 8 != 0)
if ((filp->f_pos & 7) != 0)
return -EBADF;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
......
......@@ -232,11 +232,13 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
{
off_t pos;
int written, c;
struct buffer_head * bh;
struct buffer_head * bh, *bufferlist[NBUF];
char * p;
struct super_block * sb;
int err;
int i,buffercount,write_error;
write_error = buffercount = 0;
if (!inode) {
printk("ext2_file_write: inode = NULL\n");
return -EINVAL;
......@@ -294,12 +296,32 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
buf += c;
bh->b_uptodate = 1;
mark_buffer_dirty(bh, 0);
if (filp->f_flags & O_SYNC) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
if (filp->f_flags & O_SYNC)
bufferlist[buffercount++] = bh;
else
brelse(bh);
if (buffercount == NBUF){
ll_rw_block(WRITE, buffercount, bufferlist);
for(i=0; i<buffercount; i++){
wait_on_buffer(bufferlist[i]);
if (!bufferlist[i]->b_uptodate)
write_error=1;
brelse(bufferlist[i]);
}
buffercount=0;
}
brelse (bh);
if(write_error)
break;
}
if ( buffercount ){
ll_rw_block(WRITE, buffercount, bufferlist);
for(i=0; i<buffercount; i++){
wait_on_buffer(bufferlist[i]);
if (!bufferlist[i]->b_uptodate)
write_error=1;
brelse(bufferlist[i]);
}
}
if (pos > inode->i_size)
inode->i_size = pos;
if (filp->f_flags & O_SYNC)
......
......@@ -92,7 +92,11 @@ struct hpfs_spare_block
{
unsigned magic; /* f991 1849 */
unsigned magic1; /* fa52 29c5, more magic? */
unsigned dirty; /* 0 clean, 1 "improperly stopped" */
unsigned dirty: 1; /* 0 clean, 1 "improperly stopped" */
unsigned flag1234: 4; /* unknown flags */
unsigned fast: 1; /* partition was fast formatted */
unsigned flag6to31: 26; /* unknown flags */
secno hotfix_map; /* info about remapped bad sectors */
unsigned n_spares_used; /* number of hotfixes */
......
......@@ -109,7 +109,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
return -EBADF;
error = verify_area(VERIFY_WRITE, l, sizeof(*l));
error = verify_area(VERIFY_READ, l, sizeof(*l));
if (error)
return error;
memcpy_fromfs(&flock, l, sizeof(flock));
......
......@@ -3,6 +3,12 @@
*
* Copyright (C) 1992 Rick Sladkey
*
* Changes Copyright (C) 1994 by Florian La Roche
* - Do not copy data too often around in the kernel.
* - In nfs_file_read the return value of kmalloc wasn't checked.
* - Put in a better version of read look-ahead buffering. Original idea
* and implementation by Wai S Kok elekokw@ee.nus.sg.
*
* nfs regular file handling functions
*/
......@@ -21,7 +27,6 @@
static int nfs_file_read(struct inode *, struct file *, char *, int);
static int nfs_file_write(struct inode *, struct file *, char *, int);
static int nfs_fsync(struct inode *, struct file *);
extern int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
static struct file_operations nfs_file_operations = {
NULL, /* lseek - default */
......@@ -53,6 +58,32 @@ struct inode_operations nfs_file_inode_operations = {
NULL /* truncate */
};
/* Once data is inserted, it can only be deleted, if (in_use==0). */
struct read_cache {
int in_use; /* currently in use? */
unsigned long inode_num; /* inode number */
off_t file_pos; /* file position */
int len; /* size of data */
unsigned long time; /* time, this entry was inserted */
char * buf; /* data */
int buf_size; /* size of buffer */
};
#define READ_CACHE_SIZE 5
#define EXPIRE_CACHE (HZ * 3) /* keep no longer than 3 seconds */
unsigned long num_requests = 0;
unsigned long num_cache_hits = 0;
static int tail = 0; /* next cache slot to replace */
static struct read_cache cache[READ_CACHE_SIZE] = {
{ 0, 0, -1, 0, 0, NULL, 0 },
{ 0, 0, -1, 0, 0, NULL, 0 },
{ 0, 0, -1, 0, 0, NULL, 0 },
{ 0, 0, -1, 0, 0, NULL, 0 },
{ 0, 0, -1, 0, 0, NULL, 0 } };
static int nfs_fsync(struct inode *inode, struct file *file)
{
return 0;
......@@ -61,10 +92,7 @@ static int nfs_fsync(struct inode *inode, struct file *file)
static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
int count)
{
int result;
int hunk;
int i;
int n;
int result, hunk, i, n, fs;
struct nfs_fattr fattr;
char *data;
off_t pos;
......@@ -79,46 +107,88 @@ static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
return -EINVAL;
}
pos = file->f_pos;
if (file->f_pos + count > inode->i_size)
if (pos + count > inode->i_size)
count = inode->i_size - pos;
if (count <= 0)
return 0;
++num_requests;
cli();
for (i = 0; i < READ_CACHE_SIZE; i++)
if ((cache[i].inode_num == inode->i_ino)
&& (cache[i].file_pos <= pos)
&& (cache[i].file_pos + cache[i].len >= pos + count)
&& (abs(jiffies - cache[i].time) <= EXPIRE_CACHE))
break;
if (i < READ_CACHE_SIZE) {
++cache[i].in_use;
sti();
++num_cache_hits;
memcpy_tofs(buf, cache[i].buf + pos - cache[i].file_pos, count);
--cache[i].in_use;
file->f_pos += count;
return count;
}
sti();
n = NFS_SERVER(inode)->rsize;
data = (char *) kmalloc(n, GFP_KERNEL);
for (i = 0; i < count; i += n) {
hunk = count - i;
if (hunk > n)
hunk = n;
for (i = 0; i < count - n; i += n) {
result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
pos, hunk, data, &fattr);
if (result < 0) {
kfree_s(data, n);
pos, n, buf, &fattr, 1);
if (result < 0)
return result;
}
memcpy_tofs(buf, data, result);
pos += result;
buf += result;
if (result < n) {
i += result;
break;
file->f_pos = pos;
nfs_refresh_inode(inode, &fattr);
return i + result;
}
}
file->f_pos = pos;
kfree_s(data, n);
fs = 0;
if (!(data = (char *)kmalloc(n, GFP_KERNEL))) {
data = buf;
fs = 1;
}
result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
pos, n, data, &fattr, fs);
if (result < 0) {
if (!fs)
kfree_s(data, n);
return result;
}
hunk = count - i;
if (result < hunk)
hunk = result;
if (fs) {
file->f_pos = pos + hunk;
nfs_refresh_inode(inode, &fattr);
return i + hunk;
}
memcpy_tofs(buf, data, hunk);
file->f_pos = pos + hunk;
nfs_refresh_inode(inode, &fattr);
return i;
cli();
if (cache[tail].in_use == 0) {
if (cache[tail].buf)
kfree_s(cache[tail].buf, cache[tail].buf_size);
cache[tail].buf = data;
cache[tail].buf_size = n;
cache[tail].inode_num = inode->i_ino;
cache[tail].file_pos = pos;
cache[tail].len = result;
cache[tail].time = jiffies;
if (++tail >= READ_CACHE_SIZE)
tail = 0;
} else
kfree_s(data, n);
sti();
return i + hunk;
}
static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
int count)
{
int result;
int hunk;
int i;
int n;
int result, hunk, i, n, pos;
struct nfs_fattr fattr;
char *data;
int pos;
if (!inode) {
printk("nfs_file_write: inode = NULL\n");
......@@ -135,18 +205,14 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
if (file->f_flags & O_APPEND)
pos = inode->i_size;
n = NFS_SERVER(inode)->wsize;
data = (char *) kmalloc(n, GFP_KERNEL);
for (i = 0; i < count; i += n) {
hunk = count - i;
if (hunk >= n)
hunk = n;
memcpy_fromfs(data, buf, hunk);
result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode),
pos, hunk, data, &fattr);
if (result < 0) {
kfree_s(data, n);
pos, hunk, buf, &fattr);
if (result < 0)
return result;
}
pos += hunk;
buf += hunk;
if (hunk < n) {
......@@ -155,7 +221,6 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
}
}
file->f_pos = pos;
kfree_s(data, n);
nfs_refresh_inode(inode, &fattr);
return i;
}
......
......@@ -54,7 +54,7 @@ static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
if (hunk > n)
hunk = n;
result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
pos, hunk, (char *) (page + i), &fattr);
pos, hunk, (char *) (page + i), &fattr, 0);
if (result < 0)
break;
pos += result;
......
......@@ -9,10 +9,17 @@
* so at last we can have decent(ish) throughput off a
* Sun server.
*
* Coding optimized and cleaned up by Florian La Roche.
* Note: Error returns are optimized for NFS_OK, which isn't translated via
* nfs_stat_to_errno(), but happens to be already the right return code.
*
* FixMe: We ought to define a sensible small max size for
* things like getattr that are tiny packets and use the
* old get_free_page stuff with it.
*
* Also, the code currently doesn't check the size of the packet, when
* it decodes the packet.
*
* Feel free to fix it and mail me the diffs if it worries you.
*/
......@@ -36,6 +43,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/in.h>
#include <asm/segment.h>
#ifdef NFS_PROC_DEBUG
......@@ -52,6 +60,9 @@ static int proc_debug = 0;
#endif /* !NFS_PROC_DEBUG */
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
static int *nfs_rpc_header(int *p, int procedure, int ruid);
static int *nfs_rpc_verify(int *p);
static int nfs_stat_to_errno(int stat);
......@@ -61,11 +72,30 @@ static int nfs_stat_to_errno(int stat);
*/
#define NFS_SLACK_SPACE 1024 /* Total overkill */
/* !!! Be careful, this constant is now also used in sock.c...
We should easily convert to not using it anymore for most cases... */
static inline int *nfs_rpc_alloc(int size)
{
size+=NFS_SLACK_SPACE; /* Allow for the NFS crap as well as buffer */
return (int *)kmalloc(size,GFP_KERNEL);
#if 1
/* Allow for the NFS crap as well as buffer */
return (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL);
#else
/* If kmalloc fails, then we will give an EIO to user level.
(Please correct me, I am wron here... ??) This is not
desirable, but it is also not desirable to execute the
following code: Just loop until we get memory, call schedule(),
so that other processes are run inbetween (and hopefully give
some memory back). Florian
*/
int i;
while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL))) {
/* printk("NFS: call schedule\n"); */
schedule();
}
return i;
#endif
}
static inline void nfs_rpc_free(int *p)
......@@ -78,68 +108,73 @@ static inline void nfs_rpc_free(int *p)
* between machine dependent and xdr data formats.
*/
#define QUADLEN(len) (((len) + 3) >> 2)
static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle)
{
*((struct nfs_fh *) p) = *fhandle;
p += (sizeof (*fhandle) + 3) >> 2;
return p;
return p + QUADLEN(sizeof(*fhandle));
}
static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle)
{
*fhandle = *((struct nfs_fh *) p);
p += (sizeof (*fhandle) + 3) >> 2;
return p;
return p + QUADLEN(sizeof(*fhandle));
}
static inline int *xdr_encode_string(int *p, const char *string)
{
int len, quadlen;
len = strlen(string);
quadlen = (len + 3) >> 2;
int len = strlen(string);
int quadlen = QUADLEN(len);
p[quadlen] = 0;
*p++ = htonl(len);
memcpy((char *) p, string, len);
memset(((char *) p) + len, '\0', (quadlen << 2) - len);
p += quadlen;
return p;
memcpy(p, string, len);
return p + quadlen;
}
static inline int *xdr_decode_string(int *p, char *string, int maxlen)
static inline int *xdr_decode_string(int *p, char *string, unsigned int maxlen)
{
unsigned int len;
len = ntohl(*p++);
unsigned int len = ntohl(*p++);
if (len > maxlen)
return NULL;
memcpy(string, (char *) p, len);
memcpy(string, p, len);
string[len] = '\0';
p += (len + 3) >> 2;
return p;
return p + QUADLEN(len);
}
static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len,
unsigned int maxlen)
{
*len = ntohl(*p++);
if (*len > maxlen)
return NULL;
*string = (char *) p;
return p + QUADLEN(*len);
}
static inline int *xdr_encode_data(int *p, char *data, int len)
{
int quadlen;
int quadlen = QUADLEN(len);
quadlen = (len + 3) >> 2;
p[quadlen] = 0;
*p++ = htonl(len);
memcpy((char *) p, data, len);
memset(((char *) p) + len, '\0', (quadlen << 2) - len);
p += quadlen;
return p;
memcpy_fromfs(p, data, len);
return p + quadlen;
}
static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen,
int fs)
{
unsigned int len;
len = *lenp = ntohl(*p++);
unsigned len = *lenp = ntohl(*p++);
if (len > maxlen)
return NULL;
memcpy(data, (char *) p, len);
p += (len + 3) >> 2;
return p;
if (fs)
memcpy_tofs(data, p, len);
else
memcpy(data, p, len);
return p + QUADLEN(len);
}
static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr)
......@@ -214,15 +249,16 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
retry:
p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply getattr\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -230,9 +266,10 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply getattr failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
......@@ -249,15 +286,16 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
p = xdr_encode_fhandle(p, fhandle);
p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply setattr\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -265,9 +303,10 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply setattr failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
......@@ -288,16 +327,17 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fhandle(p, fhandle);
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply lookup\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -305,37 +345,35 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *n
goto retry;
}
PRINTK("NFS reply lookup failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
char *res)
int **p0, char **string, unsigned int *len, unsigned int maxlen)
{
int *p, *p0;
int status;
int ruid = 0;
int *p;
int status, ruid = 0;
PRINTK("NFS call readlink\n");
if (!(p0 = nfs_rpc_alloc(server->rsize)))
if (!(*p0 = nfs_rpc_alloc(server->rsize)))
return -EIO;
retry:
p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid);
p = nfs_rpc_header(*p0, NFSPROC_READLINK, ruid);
p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
nfs_rpc_free(p0);
if ((status = nfs_rpc_call(server, *p0, p, server->rsize)) < 0)
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
if (!(p = nfs_rpc_verify(*p0)))
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
if (!(p = xdr_decode_string(p, res, NFS_MAXPATHLEN))) {
if (!(p = xdr_decode_string2(p, string, len, maxlen))) {
printk("nfs_proc_readlink: giant pathname\n");
status = NFSERR_IO;
status = -errno_NFSERR_IO;
}
else
PRINTK("NFS reply readlink %s\n", res);
else /* status = 0, */
PRINTK("NFS reply readlink\n");
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -343,18 +381,18 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply readlink failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
int offset, int count, char *data, struct nfs_fattr *fattr)
int offset, int count, char *data, struct nfs_fattr *fattr, int fs)
{
int *p, *p0;
int status;
int ruid = 0;
int len = 0; /* = 0 is for gcc */
int len;
PRINTK("NFS call read %d @ %d\n", count, offset);
if (!(p0 = nfs_rpc_alloc(server->rsize)))
......@@ -365,20 +403,22 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
*p++ = htonl(offset);
*p++ = htonl(count);
*p++ = htonl(count); /* traditional, could be any value */
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fattr(p, fattr);
if (!(p = xdr_decode_data(p, data, &len, count))) {
if (!(p = xdr_decode_data(p, data, &len, count, fs))) {
printk("nfs_proc_read: giant data size\n");
status = NFSERR_IO;
status = -errno_NFSERR_IO;
}
else
else {
status = len;
PRINTK("NFS reply read %d\n", len);
}
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -386,9 +426,10 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply read failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
......@@ -408,15 +449,16 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
*p++ = htonl(offset);
*p++ = htonl(count); /* traditional, could be any value */
p = xdr_encode_data(p, data, count);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply write\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -424,9 +466,10 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply write failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
......@@ -445,16 +488,17 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fhandle(p, fhandle);
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply create\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -462,9 +506,10 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
goto retry;
}
PRINTK("NFS reply create failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
......@@ -480,14 +525,15 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n
p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply remove\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -495,9 +541,10 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *n
goto retry;
}
PRINTK("NFS reply remove failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_rename(struct nfs_server *server,
......@@ -517,14 +564,15 @@ int nfs_proc_rename(struct nfs_server *server,
p = xdr_encode_string(p, old_name);
p = xdr_encode_fhandle(p, new_dir);
p = xdr_encode_string(p, new_name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply rename\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -532,9 +580,10 @@ int nfs_proc_rename(struct nfs_server *server,
goto retry;
}
PRINTK("NFS reply rename failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
......@@ -552,14 +601,15 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_encode_fhandle(p, fhandle);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply link\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -567,9 +617,10 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply link failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
......@@ -588,14 +639,15 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_encode_string(p, name);
p = xdr_encode_string(p, path);
p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply symlink\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -603,9 +655,10 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
goto retry;
}
PRINTK("NFS reply symlink failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
......@@ -624,16 +677,17 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
p = xdr_encode_sattr(p, sattr);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fhandle(p, fhandle);
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply mkdir\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -641,9 +695,10 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
goto retry;
}
PRINTK("NFS reply mkdir failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
......@@ -659,14 +714,15 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na
p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
p = xdr_encode_fhandle(p, dir);
p = xdr_encode_string(p, name);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply rmdir\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -674,9 +730,10 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *na
goto retry;
}
PRINTK("NFS reply rmdir failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
......@@ -685,7 +742,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
int *p, *p0;
int status;
int ruid = 0;
int i = 0; /* = 0 is for gcc */
int i;
int size;
int eof;
......@@ -698,12 +755,12 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_encode_fhandle(p, fhandle);
*p++ = htonl(cookie);
*p++ = htonl(size);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
for (i = 0; i < count && *p++; i++) {
if (!(p = xdr_decode_entry(p, entry++)))
......@@ -711,7 +768,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
}
if (!p) {
printk("nfs_proc_readdir: giant filename\n");
status = NFSERR_IO;
status = -errno_NFSERR_IO;
}
else {
eof = (i == count && !*p++ && *p++)
......@@ -720,6 +777,7 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
entry[-1].eof = 1;
PRINTK("NFS reply readdir %d %s\n", i,
eof ? "eof" : "");
status = i;
}
}
else {
......@@ -728,9 +786,10 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply readdir failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
return status;
}
int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
......@@ -746,15 +805,16 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
retry:
p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
p = xdr_encode_fhandle(p, fhandle);
if ((status = nfs_rpc_call(server, p0, p)) < 0) {
if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
nfs_rpc_free(p0);
return status;
}
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
status = -errno_NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fsinfo(p, res);
PRINTK("NFS reply statfs\n");
/* status = 0; */
}
else {
if (!ruid && current->fsuid == 0 && current->uid != 0) {
......@@ -762,9 +822,10 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
goto retry;
}
PRINTK("NFS reply statfs failed = %d\n", status);
status = -nfs_stat_to_errno(status);
}
nfs_rpc_free(p0);
return -nfs_stat_to_errno(status);
return status;
}
/*
......@@ -828,7 +889,7 @@ static int *nfs_rpc_verify(int *p)
printk("nfs_rpc_verify: giant auth size\n");
return NULL;
}
p += (n + 3) >> 2;
p += QUADLEN(n);
if ((n = ntohl(*p++)) != RPC_SUCCESS) {
printk("nfs_rpc_verify: RPC call failed: %d\n", n);
return NULL;
......@@ -841,10 +902,6 @@ static int *nfs_rpc_verify(int *p)
* the local errno values which may not be the same.
*/
#ifndef EDQUOT
#define EDQUOT ENOSPC
#endif
static struct {
int stat;
int errno;
......@@ -852,7 +909,7 @@ static struct {
{ NFS_OK, 0 },
{ NFSERR_PERM, EPERM },
{ NFSERR_NOENT, ENOENT },
{ NFSERR_IO, EIO },
{ NFSERR_IO, errno_NFSERR_IO },
{ NFSERR_NXIO, ENXIO },
{ NFSERR_ACCES, EACCES },
{ NFSERR_EXIST, EEXIST },
......
......@@ -11,6 +11,11 @@
*
* An xid mismatch no longer causes the request to be trashed.
*
* Peter Eriksson - incorrect XID used to confuse Linux
* Florian La Roche - use the correct max size, if reading a packet and
* also verify, if the whole packet has been read...
* more checks should be done in proc.c...
*
*/
#include <linux/config.h>
......@@ -44,7 +49,7 @@ extern struct socket *socki_lookup(struct inode *inode);
* to the server socket.
*/
static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
{
struct file *file;
struct inode *inode;
......@@ -192,26 +197,23 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
#if 0
printk("nfs_rpc_call: XID mismatch\n");
#endif
goto re_select;
}
/* JEJB/JSP 2/7/94
*
* we have the correct xid, so read into the correct place and
* return it
*
* Here we need to know the size given to alloc, server->wsize for
* writes or server->rsize for reads. In practice these are the
* same.
*
* If they are not the same then a reply to a write request will be
* a small acknowledgment, so even if wsize < rsize we should never
* cause data to be written past the end of the buffer (unless some
* brain damaged implementation sends out a large write acknowledge).
*
* FIXME: I should really know how big a packet was alloc'd --
* should pass it to do_nfs_rpc. */
*/
result=sock->ops->recvfrom(sock, (void *)start,
server->rsize + NFS_SLACK_SPACE, 1, 0, NULL,
size + 1024, 1, 0, NULL,
/* Here is NFS_SLACK_SPACE..., hack */
&addrlen);
if (result < addrlen) {
printk("NFS: just caught a too small read memory size..., email to NET channel\n");
printk("NFS: result=%d,addrlen=%d\n", result, addrlen);
result = -EIO;
}
current->blocked = old_mask;
set_fs(fs);
return result;
......@@ -223,14 +225,14 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
* RPC replies.
*/
int nfs_rpc_call(struct nfs_server *server, int *start, int *end)
int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
{
int result;
while (server->lock)
sleep_on(&server->wait);
server->lock = 1;
result = do_nfs_rpc_call(server, start, end);
result = do_nfs_rpc_call(server, start, end, size);
server->lock = 0;
wake_up(&server->wait);
return result;
......
......@@ -3,6 +3,8 @@
*
* Copyright (C) 1992 Rick Sladkey
*
* Optimization changes Copyright (C) 1994 Florian La Roche
*
* nfs symlink handling code
*/
......@@ -14,6 +16,7 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/string.h>
static int nfs_readlink(struct inode *, char *, int);
static int nfs_follow_link(struct inode *, struct inode *, int, int,
......@@ -43,8 +46,9 @@ struct inode_operations nfs_symlink_inode_operations = {
static int nfs_follow_link(struct inode *dir, struct inode *inode,
int flag, int mode, struct inode **res_inode)
{
int error;
char *res;
int error, *mem;
unsigned int len;
char *res, *res2;
*res_inode = NULL;
if (!dir) {
......@@ -65,27 +69,33 @@ static int nfs_follow_link(struct inode *dir, struct inode *inode,
iput(dir);
return -ELOOP;
}
res = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL);
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res);
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
&res, &len, NFS_MAXPATHLEN);
if ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL)) == NULL) {
printk("NFS: no memory in nfs_follow_link\n");
error = -EIO;
}
if (error) {
iput(inode);
iput(dir);
kfree_s(res, NFS_MAXPATHLEN + 1);
kfree(mem);
return error;
}
memcpy(res2, res, len);
res2[len] = '\0';
kfree(mem);
iput(inode);
current->link_count++;
error = open_namei(res, flag, mode, res_inode, dir);
error = open_namei(res2, flag, mode, res_inode, dir);
current->link_count--;
kfree_s(res, NFS_MAXPATHLEN + 1);
kfree_s(res2, NFS_MAXPATHLEN + 1);
return error;
}
static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
{
int i;
char c;
int error;
int error, *mem;
unsigned int len;
char *res;
if (!S_ISLNK(inode->i_mode)) {
......@@ -94,15 +104,14 @@ static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
}
if (buflen > NFS_MAXPATHLEN)
buflen = NFS_MAXPATHLEN;
res = (char *) kmalloc(buflen + 1, GFP_KERNEL);
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res);
error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
&res, &len, buflen);
iput(inode);
if (error) {
kfree_s(res, buflen + 1);
return error;
if (! error) {
memcpy_tofs(buffer, res, len);
put_fs_byte('\0', buffer + len);
error = len;
}
for (i = 0; i < buflen && (c = res[i]); i++)
put_fs_byte(c,buffer++);
kfree_s(res, buflen + 1);
return i;
kfree(mem);
return error;
}
......@@ -20,14 +20,13 @@
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>
extern struct file_operations * get_blkfops(unsigned int);
extern struct file_operations * get_chrfops(unsigned int);
extern void wait_for_keypress(void);
extern void fcntl_init_locks(void);
extern int floppy_grab_irq_and_dma(void);
extern int root_mountflags;
......@@ -296,23 +295,15 @@ static struct super_block * read_super(dev_t dev,char *name,int flags,
* filesystems which don't use real block-devices. -- jrs
*/
static char unnamed_dev_in_use[256];
static char unnamed_dev_in_use[256/8] = { 0, };
static dev_t get_unnamed_dev(void)
{
static int first_use = 0;
int i;
if (first_use == 0) {
first_use = 1;
memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use));
unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */
}
for (i = 0; i < sizeof unnamed_dev_in_use/sizeof unnamed_dev_in_use[0]; i++) {
if (!unnamed_dev_in_use[i]) {
unnamed_dev_in_use[i] = 1;
for (i = 1; i < 256; i++) {
if (!set_bit(i,unnamed_dev_in_use))
return (UNNAMED_MAJOR << 8) | i;
}
}
return 0;
}
......@@ -321,12 +312,11 @@ static void put_unnamed_dev(dev_t dev)
{
if (!dev)
return;
if (!unnamed_dev_in_use[dev]) {
printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",
MAJOR(dev), MINOR(dev));
if (MAJOR(dev) == UNNAMED_MAJOR &&
clear_bit(MINOR(dev), unnamed_dev_in_use))
return;
}
unnamed_dev_in_use[dev] = 0;
printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",
MAJOR(dev), MINOR(dev));
}
static int do_umount(dev_t dev)
......@@ -645,18 +635,35 @@ void mount_root(void)
{
struct file_system_type * fs_type;
struct super_block * sb;
struct inode * inode;
struct inode * inode, d_inode;
struct file filp;
int retval;
memset(super_blocks, 0, sizeof(super_blocks));
fcntl_init_locks();
if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
wait_for_keypress();
/* ugly, ugly */
if (floppy_grab_irq_and_dma())
printk("Unable to grab floppy IRQ/DMA for mounting root floppy\n");
}
memset(&filp, 0, sizeof(filp));
memset(&d_inode, 0, sizeof(d_inode));
d_inode.i_rdev = ROOT_DEV;
filp.f_inode = &d_inode;
if ( root_mountflags & MS_RDONLY)
filp.f_mode = 1; /* read only */
else
filp.f_mode = 3; /* read write */
retval = blkdev_open(&d_inode, &filp);
if(retval == -EROFS){
root_mountflags |= MS_RDONLY;
filp.f_mode = 1;
retval = blkdev_open(&d_inode, &filp);
}
for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
if(retval)
break;
if (!fs_type->requires_dev)
continue;
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
......
......@@ -4,7 +4,7 @@ It implements all of
- SystemV/386 FS,
- Coherent FS.
This is version beta 2.
This is version beta 3.
To install:
* Answer the 'System V and Coherent filesystem support' question with 'y'
......
......@@ -306,6 +306,10 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++)
if ((bh = bread(dev, offsets[i], BLOCK_SIZE)) != NULL) {
/* Try to recognize SystemV superblock */
if ((found = detect_sysv4(sb,bh)) != NULL) {
sb->sv_block_base = offsets[i];
goto ok;
}
if ((found = detect_sysv2(sb,bh)) != NULL) {
sb->sv_block_base = offsets[i];
goto ok;
......
......@@ -228,10 +228,12 @@ struct floppy_raw_cmd {
/* flags */
#define FD_RAW_READ 1
#define FD_RAW_WRITE 2
#define FD_RAW_NO_MOTOR 4
#define FD_RAW_DISK_CHANGE 4
#define FD_RAW_INTR 8
#define FD_RAW_SPIN 16
#define FD_RAW_NO_MOTOR_AFTER 32
#define FD_RAW_NEED_DISK 64
#define FD_RAW_NEED_SEEK 128
#define FD_RAW_USER_SUPPLIED 256
#endif
......@@ -89,6 +89,8 @@
#define FD_READID 0xEA /* prints the header of a sector */
#define FD_UNLOCK 0x14 /* Fifo config unlock */
#define FD_LOCK 0x94 /* Fifo config lock */
#define FD_RSEEK_OUT 0x8f /* seek out (i.e. to lower tracks) */
#define FD_RSEEK_IN 0xcf /* seek in (i.e. to higher tracks) */
/* DMA commands */
#define DMA_READ 0x46
......
......@@ -79,7 +79,7 @@ struct hd_geometry {
struct hd_driveid {
unsigned short config; /* lots of obsolete bit flags */
unsigned short cyls; /* "physical" cyls */
unsigned short reserved0; /* reserved */
unsigned short reserved2; /* reserved (word 2) */
unsigned short heads; /* "physical" heads */
unsigned short track_bytes; /* unformatted bytes per track */
unsigned short sector_bytes; /* unformatted bytes per sector */
......@@ -97,13 +97,13 @@ struct hd_driveid {
unsigned char vendor3; /* vendor unique */
unsigned short dword_io; /* 0=not_implemented; 1=implemented */
unsigned char vendor4; /* vendor unique */
unsigned char capability; /* bit0:DMA, bit1:LBA */
unsigned short reserved1; /* reserved */
unsigned char capability; /* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/
unsigned short reserved50; /* reserved (word 50) */
unsigned char vendor5; /* vendor unique */
unsigned char tPIO; /* 0=slow, 1=medium, 2=fast */
unsigned char vendor6; /* vendor unique */
unsigned char tDMA; /* 0=slow, 1=medium, 2=fast */
unsigned short cur_valid; /* when (bit0==1) use logical geom */
unsigned short field_valid; /* bits 0:cur_ok 1:eide_ok */
unsigned short cur_cyls; /* logical cylinders */
unsigned short cur_heads; /* logical heads */
unsigned short cur_sectors; /* logical sectors per track */
......@@ -114,7 +114,14 @@ struct hd_driveid {
unsigned int lba_capacity; /* total number of sectors */
unsigned short dma_1word; /* single-word dma info */
unsigned short dma_mword; /* multiple-word dma info */
/* unsigned short reserved2[64];*/ /* reserved */
/* unsigned short vendor7 [32];*/ /* vendor unique */
/* unsigned short reserved3[96];*/ /* reserved */
unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */
unsigned short eide_dma_min; /* min mword dma cycle time (ns) */
unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */
unsigned short eide_pio; /* min cycle time (ns), no IORDY */
unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */
unsigned short reserved69; /* reserved (word 69) */
unsigned short reserved70; /* reserved (word 70) */
/* unsigned short reservedxx[57];*/ /* reserved (words 71-127) */
/* unsigned short vendor7 [32];*/ /* vendor unique (words 128-159) */
/* unsigned short reservedyy[96];*/ /* reserved (words 160-255) */
};
......@@ -90,19 +90,6 @@ struct lp_struct {
char *lp_buffer;
};
/* the BIOS manuals say there can be up to 4 lpt devices
* but I have not seen a board where the 4th address is listed
* if you have different hardware change the table below
* please let me know if you have different equipment
* if you have more than 3 printers, remember to increase LP_NO
*/
struct lp_struct lp_table[] = {
{ 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
{ 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
{ 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, },
};
#define LP_NO 3
/*
* bit defines for 8255 status port
* base + 1
......
#ifndef _LINUX_NCP_H_
#define _LINUX_NCP_H_
#define NCP_OPEN 0x1111
#define NCP_CLOSE 0x5555
#define NCP_REQUEST 0x2222
#define NCP_REPLY 0x3333
struct ncp_request
{
unsigned short p_type __attribute__ ((packed));
unsigned char seq __attribute__ ((packed));
unsigned char c_low __attribute__ ((packed));
unsigned char task __attribute__ ((packed));
unsigned char c_high __attribute__ ((packed));
unsigned char func __attribute__ ((packed));
};
struct ncp_request_sf
{
unsigned short p_type __attribute__ ((packed));
unsigned char seq __attribute__ ((packed));
unsigned char c_low __attribute__ ((packed));
unsigned char task __attribute__ ((packed));
unsigned char c_high __attribute__ ((packed));
unsigned char func __attribute__ ((packed));
unsigned short s_len __attribute__ ((packed));
unsigned char s_func __attribute__ ((packed));
};
struct ncp_reply
{
unsigned short p_type __attribute__ ((packed));
unsigned char seq __attribute__ ((packed));
unsigned char c_low __attribute__ ((packed));
unsigned char task __attribute__ ((packed));
unsigned char c_high __attribute__ ((packed));
unsigned char f_stat __attribute__ ((packed));
unsigned char c_stat __attribute__ ((packed));
};
#define OTYPE_USER 0x0001
#define OTYPE_GROUP 0x0002
#define OTYPE_PQUEUE 0x0003
#define OTYPE_FSERVER 0x0004
#define OTYPE_JSERVER 0x0005
#define OTYPE_PSERVER 0x0007
#define OTYPE_UNKNOWN_1 0x002E
#define OTYPE_ADV_PSERVER 0x0047
#define OTYPE_AFSERVER 0x0107
#define OTYPE_UNKNOWN_2 0x0143
#define OTYPE_UNKNOWN_3 0x01F5
#define OTYPE_UNKNOWN_4 0x023F
#define LIMIT_OBJNAME 47
struct bind_obj
{
unsigned long id __attribute__ ((packed));
unsigned short type __attribute__ ((packed));
char name[LIMIT_OBJNAME+1] __attribute__ ((packed));
};
struct get_bind_obj
{
unsigned short type __attribute__ ((packed));
unsigned char n_len __attribute__ ((packed));
char name[0] __attribute__ ((packed));
};
struct scan_bind_obj
{
unsigned long id __attribute__ ((packed));
unsigned short type __attribute__ ((packed));
unsigned char n_len __attribute__ ((packed));
char name[0] __attribute__ ((packed));
};
struct login_req
{
unsigned char password[8] __attribute__ ((packed));
unsigned short type __attribute__ ((packed));
unsigned char n_len __attribute__ ((packed));
char name[0] __attribute__ ((packed));
};
struct ncp_time
{
unsigned char year __attribute__ ((packed));
unsigned char month __attribute__ ((packed));
unsigned char day __attribute__ ((packed));
unsigned char hours __attribute__ ((packed));
unsigned char mins __attribute__ ((packed));
unsigned char secs __attribute__ ((packed));
unsigned char c_secs __attribute__ ((packed));
};
struct login_info
{
unsigned long id __attribute__ ((packed));
unsigned short un1 __attribute__ ((packed));
char name[LIMIT_OBJNAME+1] __attribute__ ((packed));
struct ncp_time time __attribute__ ((packed));
};
#endif
......@@ -57,10 +57,11 @@ extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
const char *name, struct nfs_fh *fhandle,
struct nfs_fattr *fattr);
extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
char *res);
int **p0, char **string, unsigned int *len,
unsigned int maxlen);
extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
int offset, int count, char *data,
struct nfs_fattr *fattr);
struct nfs_fattr *fattr, int fs);
extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
int offset, int count, char *data,
struct nfs_fattr *fattr);
......@@ -88,7 +89,7 @@ extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
/* linux/fs/nfs/sock.c */
extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end);
extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size);
/* linux/fs/nfs/inode.c */
......
......@@ -247,6 +247,7 @@ struct tty_struct {
#define TTY_EXCLUSIVE 3
#define TTY_DEBUG 4
#define TTY_DO_WRITE_WAKEUP 5
#define TTY_PUSH 6
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
......
......@@ -455,7 +455,15 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
printk ("bios32_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
} else {
printk ("bios32_init : multiple entries, mail drew@colorado.edu\n");
/*
* Jeremy Fitzhardinge reports at least one PCI BIOS
* with two different service directories, and as both
* worked for him, we'll just mention the fact, and
* not actually disallow it..
*/
#if 0
return memory_start;
#endif
}
}
#ifdef CONFIG_PCI
......
......@@ -112,15 +112,24 @@ asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerva
int error;
struct itimerval set_buffer, get_buffer;
if (!value)
memset((char *) &set_buffer, 0, sizeof(set_buffer));
else
if (value) {
error = verify_area(VERIFY_READ, value, sizeof(*value));
if (error)
return error;
memcpy_fromfs(&set_buffer, value, sizeof(set_buffer));
} else
memset((char *) &set_buffer, 0, sizeof(set_buffer));
if (ovalue) {
error = verify_area(VERIFY_WRITE, ovalue, sizeof(struct itimerval));
if (error)
return error;
}
error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0);
if (error || !ovalue)
return error;
error = verify_area(VERIFY_WRITE, ovalue, sizeof(struct itimerval));
if (!error)
memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer));
memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer));
return error;
}
......@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>
#include <linux/resource.h>
#include <asm/system.h>
#include <asm/io.h>
......@@ -675,6 +676,16 @@ static void do_timer(struct pt_regs * regs)
}
#endif
}
/*
* check the cpu time limit on the process.
*/
if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
(((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_cur))
send_sig(SIGXCPU, current, 1);
if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
(((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
send_sig(SIGKILL, current, 1);
if (current != task[0] && 0 > --current->counter) {
current->counter = 0;
need_resched = 1;
......
......@@ -697,12 +697,15 @@ asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
{
struct rlimit new_rlim, *old_rlim;
int err;
if (resource >= RLIM_NLIMITS)
return -EINVAL;
err = verify_area(VERIFY_READ, rlim, sizeof(*rlim));
if (err)
return err;
memcpy_fromfs(&new_rlim, rlim, sizeof(*rlim));
old_rlim = current->rlim + resource;
new_rlim.rlim_cur = get_fs_long((unsigned long *) rlim);
new_rlim.rlim_max = get_fs_long(((unsigned long *) rlim)+1);
if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
(new_rlim.rlim_max > old_rlim->rlim_max)) &&
!suser())
......@@ -723,7 +726,6 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
{
int error;
struct rusage r;
unsigned long *lp, *lpend, *dest;
error = verify_area(VERIFY_WRITE, ru, sizeof *ru);
if (error)
......@@ -755,11 +757,7 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
r.ru_majflt = p->mm->maj_flt + p->mm->cmaj_flt;
break;
}
lp = (unsigned long *) &r;
lpend = (unsigned long *) (&r+1);
dest = (unsigned long *) ru;
for (; lp < lpend; lp++, dest++)
put_fs_long(*lp, dest);
memcpy_tofs(ru, &r, sizeof(r));
return 0;
}
......
/*
* linux/kernel/sys_call.S
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* sys_call.S contains the system-call and fault low-level handling routines.
* This also contains the timer-interrupt handler, as well as all interrupts
* and faults that can result in a task-switch.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call.
*
* I changed all the .align's to 4 (16 byte alignment), as that's faster
* on a 486.
*
* Stack layout in 'ret_from_system_call':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
* updated in fork.c:copy_process, signal.c:do_signal,
* ptrace.c and ptrace.h
*
* 0(%esp) - %ebx
* 4(%esp) - %ecx
* 8(%esp) - %edx
* C(%esp) - %esi
* 10(%esp) - %edi
* 14(%esp) - %ebp
* 18(%esp) - %eax
* 1C(%esp) - %ds
* 20(%esp) - %es
* 24(%esp) - %fs
* 28(%esp) - %gs
* 2C(%esp) - orig_eax
* 30(%esp) - %eip
* 34(%esp) - %cs
* 38(%esp) - %eflags
* 3C(%esp) - %oldesp
* 40(%esp) - %oldss
*/
#include <linux/segment.h>
#include <linux/sys.h>
EBX = 0x00
ECX = 0x04
EDX = 0x08
ESI = 0x0C
EDI = 0x10
EBP = 0x14
EAX = 0x18
DS = 0x1C
ES = 0x20
FS = 0x24
GS = 0x28
ORIG_EAX = 0x2C
EIP = 0x30
CS = 0x34
EFLAGS = 0x38
OLDESP = 0x3C
OLDSS = 0x40
CF_MASK = 0x00000001
IF_MASK = 0x00000200
NT_MASK = 0x00004000
VM_MASK = 0x00020000
/*
* these are offsets into the task-struct.
*/
state = 0
counter = 4
priority = 8
signal = 12
blocked = 16
flags = 20
errno = 24
dbgreg6 = 52
dbgreg7 = 56
exec_domain = 60
ENOSYS = 38
.globl _system_call,_lcall7
.globl _device_not_available, _coprocessor_error
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_reserved
.globl _alignment_check,_page_fault
.globl ret_from_sys_call, _sys_call_table
#define SAVE_ALL \
cld; \
push %gs; \
push %fs; \
push %es; \
push %ds; \
pushl %eax; \
pushl %ebp; \
pushl %edi; \
pushl %esi; \
pushl %edx; \
pushl %ecx; \
pushl %ebx; \
movl $(KERNEL_DS),%edx; \
mov %dx,%ds; \
mov %dx,%es; \
movl $(USER_DS),%edx; \
mov %dx,%fs;
#define RESTORE_ALL \
cmpw $(KERNEL_CS),CS(%esp); \
je 1f; \
movl _current,%eax; \
movl dbgreg7(%eax),%ebx; \
movl %ebx,%db7; \
1: popl %ebx; \
popl %ecx; \
popl %edx; \
popl %esi; \
popl %edi; \
popl %ebp; \
popl %eax; \
pop %ds; \
pop %es; \
pop %fs; \
pop %gs; \
addl $4,%esp; \
iret
.align 4
_lcall7:
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
SAVE_ALL
movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
movl CS(%esp),%edx # this is eip..
movl EFLAGS(%esp),%ecx # and this is cs..
movl %eax,EFLAGS(%esp) #
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
movl %esp,%eax
movl _current,%edx
pushl %eax
movl exec_domain(%edx),%edx # Get the execution domain
movl 4(%edx),%edx # Get the lcall7 handler for the domain
call *%edx
popl %eax
jmp ret_from_sys_call
.align 4
handle_bottom_half:
pushfl
incl _intr_count
sti
call _do_bottom_half
popfl
decl _intr_count
jmp 9f
.align 4
reschedule:
pushl $ret_from_sys_call
jmp _schedule
.align 4
_system_call:
pushl %eax # save orig_eax
SAVE_ALL
movl $-ENOSYS,EAX(%esp)
cmpl $(NR_syscalls),%eax
jae ret_from_sys_call
movl _sys_call_table(,%eax,4),%eax
testl %eax,%eax
je ret_from_sys_call
movl _current,%ebx
andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
movl $0,errno(%ebx)
movl %db6,%edx
movl %edx,dbgreg6(%ebx) # save current hardware debugging status
testb $0x20,flags(%ebx) # PF_TRACESYS
jne 1f
call *%eax
movl %eax,EAX(%esp) # save the return value
movl errno(%ebx),%edx
negl %edx
je ret_from_sys_call
movl %edx,EAX(%esp)
orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
jmp ret_from_sys_call
.align 4
1: call _syscall_trace
movl ORIG_EAX(%esp),%eax
call _sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # save the return value
movl _current,%eax
movl errno(%eax),%edx
negl %edx
je 1f
movl %edx,EAX(%esp)
orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
1: call _syscall_trace
.align 4,0x90
ret_from_sys_call:
cmpl $0,_intr_count
jne 2f
9: movl _bh_mask,%eax
andl _bh_active,%eax
jne handle_bottom_half
movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
testl $(VM_MASK),%eax # different then
jne 1f
cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ?
je 2f
1: sti
orl $(IF_MASK),%eax # these just try to make sure
andl $~NT_MASK,%eax # the program doesn't do anything
movl %eax,EFLAGS(%esp) # stupid
cmpl $0,_need_resched
jne reschedule
movl _current,%eax
cmpl _task,%eax # task[0] cannot have signals
je 2f
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
movl blocked(%eax),%ecx
movl %ecx,%ebx # save blocked in %ebx for signal handling
notl %ecx
andl signal(%eax),%ecx
jne signal_return
2: RESTORE_ALL
.align 4
signal_return:
movl %esp,%ecx
pushl %ecx
testl $(VM_MASK),EFLAGS(%ecx)
jne v86_signal_return
pushl %ebx
call _do_signal
popl %ebx
popl %ebx
RESTORE_ALL
.align 4
v86_signal_return:
call _save_v86_state
movl %eax,%esp
pushl %eax
pushl %ebx
call _do_signal
popl %ebx
popl %ebx
RESTORE_ALL
.align 4
_divide_error:
pushl $0 # no error code
pushl $_do_divide_error
.align 4,0x90
error_code:
push %fs
push %es
push %ds
pushl %eax
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
movl $0,%eax
movl %eax,%db7 # disable hardware debugging...
cld
movl $-1, %eax
xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
xorl %ebx,%ebx # zero ebx
mov %gs,%bx # get the lower order bits of gs
xchgl %ebx, GS(%esp) # get the address and save gs.
pushl %eax # push the error code
lea 4(%esp),%edx
pushl %edx
movl $(KERNEL_DS),%edx
mov %dx,%ds
mov %dx,%es
movl $(USER_DS),%edx
mov %dx,%fs
pushl %eax
movl _current,%eax
movl %db6,%edx
movl %edx,dbgreg6(%eax) # save current hardware debugging status
popl %eax
call *%ebx
addl $8,%esp
jmp ret_from_sys_call
.align 4
_coprocessor_error:
pushl $0
pushl $_do_coprocessor_error
jmp error_code
.align 4
_device_not_available:
pushl $-1 # mark this as an int
SAVE_ALL
pushl $ret_from_sys_call
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je _math_state_restore
pushl $0 # temporary storage for ORIG_EIP
call _math_emulate
addl $4,%esp
ret
.align 4
_debug:
pushl $0
pushl $_do_debug
jmp error_code
.align 4
_nmi:
pushl $0
pushl $_do_nmi
jmp error_code
.align 4
_int3:
pushl $0
pushl $_do_int3
jmp error_code
.align 4
_overflow:
pushl $0
pushl $_do_overflow
jmp error_code
.align 4
_bounds:
pushl $0
pushl $_do_bounds
jmp error_code
.align 4
_invalid_op:
pushl $0
pushl $_do_invalid_op
jmp error_code
.align 4
_coprocessor_segment_overrun:
pushl $0
pushl $_do_coprocessor_segment_overrun
jmp error_code
.align 4
_reserved:
pushl $0
pushl $_do_reserved
jmp error_code
.align 4
_double_fault:
pushl $_do_double_fault
jmp error_code
.align 4
_invalid_TSS:
pushl $_do_invalid_TSS
jmp error_code
.align 4
_segment_not_present:
pushl $_do_segment_not_present
jmp error_code
.align 4
_stack_segment:
pushl $_do_stack_segment
jmp error_code
.align 4
_general_protection:
pushl $_do_general_protection
jmp error_code
.align 4
_alignment_check:
pushl $_do_alignment_check
jmp error_code
.align 4
_page_fault:
pushl $_do_page_fault
jmp error_code
.data
.align 4
_sys_call_table:
.long _sys_setup /* 0 */
.long _sys_exit
.long _sys_fork
.long _sys_read
.long _sys_write
.long _sys_open /* 5 */
.long _sys_close
.long _sys_waitpid
.long _sys_creat
.long _sys_link
.long _sys_unlink /* 10 */
.long _sys_execve
.long _sys_chdir
.long _sys_time
.long _sys_mknod
.long _sys_chmod /* 15 */
.long _sys_chown
.long _sys_break
.long _sys_stat
.long _sys_lseek
.long _sys_getpid /* 20 */
.long _sys_mount
.long _sys_umount
.long _sys_setuid
.long _sys_getuid
.long _sys_stime /* 25 */
.long _sys_ptrace
.long _sys_alarm
.long _sys_fstat
.long _sys_pause
.long _sys_utime /* 30 */
.long _sys_stty
.long _sys_gtty
.long _sys_access
.long _sys_nice
.long _sys_ftime /* 35 */
.long _sys_sync
.long _sys_kill
.long _sys_rename
.long _sys_mkdir
.long _sys_rmdir /* 40 */
.long _sys_dup
.long _sys_pipe
.long _sys_times
.long _sys_prof
.long _sys_brk /* 45 */
.long _sys_setgid
.long _sys_getgid
.long _sys_signal
.long _sys_geteuid
.long _sys_getegid /* 50 */
.long _sys_acct
.long _sys_phys
.long _sys_lock
.long _sys_ioctl
.long _sys_fcntl /* 55 */
.long _sys_mpx
.long _sys_setpgid
.long _sys_ulimit
.long _sys_olduname
.long _sys_umask /* 60 */
.long _sys_chroot
.long _sys_ustat
.long _sys_dup2
.long _sys_getppid
.long _sys_getpgrp /* 65 */
.long _sys_setsid
.long _sys_sigaction
.long _sys_sgetmask
.long _sys_ssetmask
.long _sys_setreuid /* 70 */
.long _sys_setregid
.long _sys_sigsuspend
.long _sys_sigpending
.long _sys_sethostname
.long _sys_setrlimit /* 75 */
.long _sys_getrlimit
.long _sys_getrusage
.long _sys_gettimeofday
.long _sys_settimeofday
.long _sys_getgroups /* 80 */
.long _sys_setgroups
.long _sys_select
.long _sys_symlink
.long _sys_lstat
.long _sys_readlink /* 85 */
.long _sys_uselib
.long _sys_swapon
.long _sys_reboot
.long _sys_readdir
.long _sys_mmap /* 90 */
.long _sys_munmap
.long _sys_truncate
.long _sys_ftruncate
.long _sys_fchmod
.long _sys_fchown /* 95 */
.long _sys_getpriority
.long _sys_setpriority
.long _sys_profil
.long _sys_statfs
.long _sys_fstatfs /* 100 */
.long _sys_ioperm
.long _sys_socketcall
.long _sys_syslog
.long _sys_setitimer
.long _sys_getitimer /* 105 */
.long _sys_newstat
.long _sys_newlstat
.long _sys_newfstat
.long _sys_uname
.long _sys_iopl /* 110 */
.long _sys_vhangup
.long _sys_idle
.long _sys_vm86
.long _sys_wait4
.long _sys_swapoff /* 115 */
.long _sys_sysinfo
.long _sys_ipc
.long _sys_fsync
.long _sys_sigreturn
.long _sys_clone /* 120 */
.long _sys_setdomainname
.long _sys_newuname
.long _sys_modify_ldt
.long _sys_adjtimex
.long _sys_mprotect /* 125 */
.long _sys_sigprocmask
.long _sys_create_module
.long _sys_init_module
.long _sys_delete_module
.long _sys_get_kernel_syms /* 130 */
.long _sys_quotactl
.long _sys_getpgid
.long _sys_fchdir
.long _sys_bdflush
.long _sys_sysfs /* 135 */
.long _sys_personality
.long 0 /* for afs_syscall */
.long _sys_setfsuid
.long _sys_setfsgid
.long _sys_llseek /* 140 */
.space (NR_syscalls-139)*4
.space (NR_syscalls-140)*4
......@@ -97,6 +97,7 @@ void time_init(void)
if ((year += 1900) < 1970)
year += 100;
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
}
/*
* The timezone where the local system is located. Used as a default by some
......@@ -118,12 +119,19 @@ asmlinkage int sys_time(long * tloc)
return i;
}
asmlinkage int sys_stime(long * tptr)
asmlinkage int sys_stime(unsigned long * tptr)
{
int error;
unsigned long value;
if (!suser())
return -EPERM;
error = verify_area(VERIFY_READ, tptr, sizeof(*tptr));
if (error)
return error;
value = get_fs_long(tptr);
cli();
xtime.tv_sec = get_fs_long((unsigned long *) tptr);
xtime.tv_sec = value;
xtime.tv_usec = 0;
time_status = TIME_BAD;
time_maxerror = 0x70000000;
......@@ -266,12 +274,25 @@ inline static void warp_clock(void)
asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
{
static int firsttime = 1;
struct timeval new_tv;
struct timezone new_tz;
if (!suser())
return -EPERM;
if (tv) {
int error = verify_area(VERIFY_READ, tv, sizeof(*tv));
if (error)
return error;
memcpy_fromfs(&new_tv, tv, sizeof(*tv));
}
if (tz) {
sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
int error = verify_area(VERIFY_READ, tz, sizeof(*tz));
if (error)
return error;
memcpy_fromfs(&new_tz, tz, sizeof(*tz));
}
if (tz) {
sys_tz = new_tz;
if (firsttime) {
firsttime = 0;
if (!tv)
......@@ -279,11 +300,6 @@ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
}
}
if (tv) {
int sec, usec;
sec = get_fs_long((unsigned long *)tv);
usec = get_fs_long(((unsigned long *)tv)+1);
cli();
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
......@@ -291,15 +307,14 @@ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
* Discover what correction gettimeofday
* would have done, and then undo it!
*/
usec -= do_gettimeoffset();
new_tv.tv_usec -= do_gettimeoffset();
if (usec < 0)
{
usec += 1000000;
sec--;
if (new_tv.tv_usec < 0) {
new_tv.tv_usec += 1000000;
new_tv.tv_sec--;
}
xtime.tv_sec = sec;
xtime.tv_usec = usec;
xtime = new_tv;
time_status = TIME_BAD;
time_maxerror = 0x70000000;
time_esterror = 0x70000000;
......
......@@ -169,6 +169,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
......@@ -184,6 +185,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
......
......@@ -734,8 +734,12 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
if (!(from & PAGE_PRESENT))
return 0;
/* if it is private, it must be clean to be shared */
if ((from_area->vm_page_prot & PAGE_COW) && (from & PAGE_DIRTY))
return 0;
if (from & PAGE_DIRTY) {
if (from_area->vm_page_prot & PAGE_COW)
return 0;
if (!(from_area->vm_page_prot & PAGE_RW))
return 0;
}
/* is the page reasonable at all? */
if (from >= high_memory)
return 0;
......@@ -754,6 +758,8 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
if (in_swap_cache(from)) { /* implies PAGE_DIRTY */
if (from_area->vm_page_prot & PAGE_COW)
return 0;
if (!(from_area->vm_page_prot & PAGE_RW))
return 0;
}
copy_page((from & PAGE_MASK), newpage);
*(unsigned long *) to_page = newpage | to_area->vm_page_prot;
......@@ -763,6 +769,8 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
if (in_swap_cache(from)) {
if (from_area->vm_page_prot & PAGE_COW)
return 0;
if (!(from_area->vm_page_prot & PAGE_RW))
return 0;
from |= PAGE_DIRTY;
*(unsigned long *) from_page = from;
delete_from_swap_cache(from);
......
......@@ -209,7 +209,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
/*
* Send it and free it once sent.
*/
ip_queue_xmit(NULL, dev, skb, 1);
ip_queue_xmit(NULL, ndev, skb, 1);
}
......
/*
*
* Kernel support for NCP
*
* Mark Evans 1994
*
*/
#ifndef _NCP_H
#define _NCP_H
#include <linux/ncp.h>
struct ncp_info
{
unsigned short conn; /* connection number */
unsigned char seq; /* sequence number */
ipx_socket *ncp; /* ncp socket */
ipx_socket *watchdog; /* watchdog socket */
ipx_socket *mail; /* mail socket */
};
#define NCP_TIMEOUT (3*HZ)
#define MAX_TIMEOUT 15
#endif /* _NCP_H */
......@@ -325,7 +325,7 @@ void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
* Update the loopback route
*/
if (rt->rt_dev->flags & IFF_LOOPBACK)
if ((rt->rt_dev->flags & IFF_LOOPBACK) && !rt_loopback)
rt_loopback = rt;
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment