diff -u --recursive --new-file v2.1.87/linux/CREDITS linux/CREDITS --- v2.1.87/linux/CREDITS Tue Feb 17 13:12:43 1998 +++ linux/CREDITS Thu Feb 19 14:58:40 1998 @@ -836,6 +836,12 @@ S: D-64283 Darmstadt S: Germany +N: Russell King +E: rmk@arm.uk.linux.org +D: Linux/arm integrater, maintainer & hacker +S: Burgh Heath, Tadworth, Surrey. +S: England + N: Olaf Kirch E: okir@monad.swb.de D: Author of the Linux Network Administrators' Guide diff -u --recursive --new-file v2.1.87/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.1.87/linux/Documentation/devices.tex Thu Dec 4 17:37:00 1997 +++ linux/Documentation/devices.tex Tue Feb 17 20:11:25 1998 @@ -4,7 +4,7 @@ % pages to print... :-) If you're actually putting this in print, you % may wish to change these. % -% $Id: devices.tex,v 1.4 1997/12/05 01:34:21 hpa Exp $ +% $Id: devices.tex,v 1.7 1998/02/18 04:07:45 hpa Exp $ % \oddsidemargin=0in \textwidth=6.5in @@ -50,7 +50,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: December 4, 1997} +\date{Last revised: February 17, 1998} \maketitle % \noindent @@ -199,6 +199,7 @@ \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices} \major{ }{}{block}{Reserved for parallel port ATAPI disk} \major{48}{}{char }{SDL RISCom serial card} +\major{48}{--55}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \major{49}{}{char }{SDL RISCom serial card -- alternate devices} \major{50}{}{char }{Reserved for GLINT} \major{51}{}{char }{Baycom radio modem} @@ -243,8 +244,10 @@ \major{93}{}{char }{IBM Smart Capture Card frame grabber} \major{94}{}{char }{miroVIDEO DC10/30 capture/playback device} \major{95}{}{char }{IP Filter} -\major{96}{}{char }{Reserved for parallel port ATAPI tape} -\major{97}{--119}{}{Unallocated} +\major{96}{}{char }{Parallel port ATAPI tape} +\major{97}{}{char }{Parallel port generic ATAPI interface} +\major{98}{}{char }{Control and Measurement Device (comedi)} +\major{99}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} \major{128}{--239}{}{Unallocated} \major{240}{--254}{}{Local/experimental use} @@ -299,6 +302,11 @@ the position within the series. \end{itemize} +\noindent +In the future, it is likely that the PTY master multiplex ({\file +/dev/ptmx}) device will be used to acquire a PTY on demand. If so, +the actual PTY masters will be unnamed devices. + \begin{devicelist} \major{}{}{block}{Floppy disks} \minor{0}{/dev/fd0}{Controller 1, drive 1 autodetect} @@ -325,7 +333,7 @@ \minor{ 72}{/dev/fd?h1494}{5.25\tum\ 1494K in a 1200K drive} \minor{ 92}{/dev/fd?h1600}{5.25\tum\ 1600K in a 1200K drive\1} \minor{}{}{} - \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density} + \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density\2} \minor{ 16}{/dev/fd?u720}{3.5\tum\ \num{4}{720}K Double Density\1} \minor{120}{/dev/fd?u800}{3.5\tum\ \num{4}{800}K Double Density\2} \minor{ 52}{/dev/fd?u820}{3.5\tum\ \num{4}{820}K Double Density} @@ -366,7 +374,13 @@ \minor{1}{/dev/ttyp1}{Second PTY slave} \minordots \minor{255}{/dev/ttyef}{256th PTY slave} -\\ +\end{devicelist} + +\noindent +In the future, Linux may adopt the Unix98 naming scheme {\file +/dev/pts/0}, {\file /dev/pts/1}, ... + +\begin{devicelist} \major{}{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface} \minor{0}{/dev/hda}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdb}{Slave: whole disk (or CD-ROM)} @@ -412,6 +426,7 @@ \major{ 5}{}{char }{Alternate TTY devices} \minor{0}{/dev/tty}{Current TTY device} \minor{1}{/dev/console}{System console} + \minor{2}{/dev/ptmx}{PTY master multiplex} \minor{64}{/dev/cua0}{Callout device corresponding to {\file ttyS0}} \minordots \minor{127}{/dev/cua63}{Callout device corresponding to {\file ttyS63}} @@ -1087,8 +1102,10 @@ \end{devicelist} \noindent -Partitions are handled the same way as for IDE disks (see major number -3). +This device is obsolete and will be removed in a future version of +Linux. It has been replaced with the parallel port IDE disk driver at +major number 45. Partitions are handled the same way as for IDE disks +(see major number 3). \begin{devicelist} \major{41}{}{char }{Yet Another Micro Monitor} @@ -1098,6 +1115,11 @@ \minor{0}{/dev/bpcd}{BackPack CD-ROM} \end{devicelist} +\noindent +This device is obsolete and will be removed in a future version of +Linux. It has been replaced with the parallel port ATAPI CD-ROM +driver at major number 46. + \begin{devicelist} \major{42}{}{}{Demo/sample use} \end{devicelist} @@ -1163,13 +1185,30 @@ \minordots \minor{191}{/dev/ippp63}{64th SyncPPP device} \minor{255}{/dev/isdninfo}{ISDN monitor interface} +\\ +\major{ }{}{block}{Parallel port IDE disk devices} + \minor{0}{/dev/pda}{First parallel port IDE disk} + \minor{16}{/dev/pdb}{Second parallel port IDE disk} + \minor{32}{/dev/pdc}{Third parallel port IDE disk} + \minor{48}{/dev/pdd}{Fourth parallel port IDE disk} \end{devicelist} +\noindent +Partitions are handled in the same way as for IDE disks (see major +number 3) except that the partition limit is 15 rather than 63 per +disk. + \begin{devicelist} \major{46}{}{char }{Comtrol Rocketport serial card} \minor{0}{/dev/ttyR0}{First Rocketport port} \minor{1}{/dev/ttyR1}{Second Rocketport port} \minordots +\\ +\major{ }{}{block}{Parallel port ATAPI CD-ROM devices} + \minor{0}{/dev/pcd0}{First parallel port ATAPI CD-ROM} + \minor{1}{/dev/pcd1}{Second parallel port ATAPI CD-ROM} + \minor{2}{/dev/pcd2}{Third parallel port ATAPI CD-ROM} + \minor{3}{/dev/pcd3}{Fourth parallel port ATAPI CD-ROM} \end{devicelist} \begin{devicelist} @@ -1177,13 +1216,25 @@ \minor{0}{/dev/cur0}{Callout device corresponding to {\file ttyR0}} \minor{1}{/dev/cur1}{Callout device corresponding to {\file ttyR1}} \minordots +\\ +\major{ }{}{block}{Parallel port ATAPI disk devices} + \minor{0}{/dev/pf0}{First parallel port ATAPI disk} + \minor{1}{/dev/pf1}{Second parallel port ATAPI disk} + \minor{2}{/dev/pf2}{Third parallel port ATAPI disk} + \minor{3}{/dev/pf3}{Fourth parallel port ATAPI disk} \end{devicelist} +\noindent +This driver is intended for floppy disks and similar devices and hence +does not support partitioning. + \begin{devicelist} \major{48}{}{char }{SDL RISCom serial card} \minor{0}{/dev/ttyL0}{First RISCom port} \minor{1}{/dev/ttyL1}{Second RISCom port} \minordots +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1191,10 +1242,14 @@ \minor{0}{/dev/cul0}{Callout device corresponding to {\file ttyL0}} \minor{1}{/dev/cul1}{Callout device corresponding to {\file ttyL1}} \minordots +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} \major{50}{}{char}{Reserved for GLINT} +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1202,6 +1257,8 @@ \minor{0}{/dev/bc0}{First Baycom radio modem} \minor{1}{/dev/bc1}{Second Baycom radio modem} \minordots +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1210,6 +1267,8 @@ \minor{1}{/dev/dcbri1}{Second DataComm card} \minor{2}{/dev/dcbri2}{Third DataComm card} \minor{3}{/dev/dcbri3}{Fourth DataComm card} +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1230,6 +1289,10 @@ commercial interface by P\&E. \begin{devicelist} +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} +\end{devicelist} + +\begin{devicelist} \major{54}{}{char }{Electrocardiognosis Holter serial card} \minor{0}{/dev/holter0}{First Holter port} \minor{1}{/dev/holter1}{Second Holter port} @@ -1242,8 +1305,14 @@ heart monitoring equipment. \begin{devicelist} +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} +\end{devicelist} + +\begin{devicelist} \major{55}{}{char }{DSP56001 digital signal processor} \minor{0}{/dev/dsp56k}{First DSP56001} +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1582,7 +1651,41 @@ \end{devicelist} \begin{devicelist} -\major{96}{--119}{}{Unallocated} +\major{96}{}{char }{Parallel port ATAPI tape devices} + \minor{0}{/dev/pt0}{First parallel port ATAPI tape} + \minor{1}{/dev/pt1}{Second parallel port ATAPI tape} + \minor{2}{/dev/pt2}{Third parallel port ATAPI tape} + \minor{3}{/dev/pt3}{Fourth parallel port ATAPI tape} + \minor{128}{/dev/npt0}{First parallel port ATAPI tape, no rewind} + \minor{129}{/dev/npt1}{Second parallel port ATAPI tape, no rewind} + \minor{130}{/dev/npt2}{Third parallel port ATAPI tape, no rewind} + \minor{131}{/dev/npt3}{Fourth parallel port ATAPI tape, no rewind} +\end{devicelist} + +\begin{devicelist} +\major{97}{}{char }{Parallel port generic ATAPI interface} + \minor{0}{/dev/pg0}{First parallel port ATAPI device} + \minor{1}{/dev/pg1}{Second parallel port ATAPI device} + \minor{2}{/dev/pg2}{Third parallel port ATAPI device} + \minor{3}{/dev/pg3}{Fourth parallel port ATAPI device} +\end{devicelist} + +\noindent +These devices support the same API as the generic SCSI devices. + +\begin{devicelist} +\major{98}{}{char }{Control and Mesurement Device (comedi)} + \minor{0}{/dev/comedi0}{First comedi device} + \minor{1}{/dev/comedi1}{Second comedi device} + \minordots +\end{devicelist} + +\noindent +See {\url http://stm.lbl.gov/comedi/} or {\url +http://www.llp.fu-berlin.de/}. + +\begin{devicelist} +\major{99}{--119}{}{Unallocated} \end{devicelist} \begin{devicelist} diff -u --recursive --new-file v2.1.87/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.1.87/linux/Documentation/devices.txt Sun Jan 4 10:40:15 1998 +++ linux/Documentation/devices.txt Tue Feb 17 20:11:25 1998 @@ -1,7 +1,7 @@ LINUX ALLOCATED DEVICES Maintained by H. Peter Anvin - Last revised: December 4, 1997 + Last revised: February 17, 1998 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating @@ -91,16 +91,17 @@ the 1st through 16th series of 16 pseudo-ttys each, and * the fifth letter is one of 0123456789abcdef indicating the position within the series. + + In the future, it is likely that the PTY master + multiplex (/dev/ptmx) device will be used to acquire a + PTY on demand. If so, the actual PTY masters will be + unnamed devices. block Floppy disks - 0 = /dev/fd0 Controller 1, drive 1 autodetect - 1 = /dev/fd1 Controller 1, drive 2 autodetect - 2 = /dev/fd2 Controller 1, drive 3 autodetect - 3 = /dev/fd3 Controller 1, drive 4 autodetect - 128 = /dev/fd4 Controller 2, drive 1 autodetect - 129 = /dev/fd5 Controller 2, drive 2 autodetect - 130 = /dev/fd6 Controller 2, drive 3 autodetect - 131 = /dev/fd7 Controller 2, drive 4 autodetect + 0 = /dev/fd0 First floppy disk autodetect + 1 = /dev/fd1 Second floppy disk autodetect + 2 = /dev/fd2 Third floppy disk autodetect + 3 = /dev/fd3 Fourth floppy disk autodetect To specify format, add to the autodetect device number: 0 = /dev/fd? Autodetect format @@ -116,9 +117,10 @@ 72 = /dev/fd?h1494 5.25" 1494K in a 1200K drive 92 = /dev/fd?h1600 5.25" 1600K in a 1200K drive(1) - 12 = /dev/fd?u360 3.5" 360K Double Density - 120 = /dev/fd?u800 3.5" 800K Double Density(1) - 52 = /dev/fd?u820 3.5" 820K Double Density(2) + 12 = /dev/fd?u360 3.5" 360K Double Density(2) + 16 = /dev/fd?u720 3.5" 720K Double Density(1) + 120 = /dev/fd?u800 3.5" 800K Double Density(2) + 52 = /dev/fd?u820 3.5" 820K Double Density 68 = /dev/fd?u830 3.5" 830K Double Density 84 = /dev/fd?u1040 3.5" 1040K Double Density(1) 88 = /dev/fd?u1120 3.5" 1120K Double Density(1) @@ -152,12 +154,15 @@ 0 = /dev/ttyp0 First PTY slave 1 = /dev/ttyp1 Second PTY slave ... - 256 = /dev/ttyef 256th PTY slave + 255 = /dev/ttyef 256th PTY slave + + In the future, Linux may adopt the Unix98 naming + scheme (/dev/pts/0, /dev/pts/1, ...) block First MFM, RLL and IDE hard disk/CD-ROM interface 0 = /dev/hda Master: whole disk (or CD-ROM) 64 = /dev/hdb Slave: whole disk (or CD-ROM) - + For partitions, add to the whole disk device number: 0 = /dev/hd? Whole disk 1 = /dev/hd?1 First partition @@ -169,7 +174,7 @@ partitions, and 5 and above are logical partitions. Other versions of Linux use partitioning schemes appropriate to their respective architectures. - + 4 char TTY devices 0 = /dev/tty0 Current virtual console @@ -196,6 +201,7 @@ 5 char Alternate TTY devices 0 = /dev/tty Current TTY device 1 = /dev/console System console + 2 = /dev/ptmx PTY master multiplex 64 = /dev/cua0 Callout device corresponding to ttyS0 ... 127 = /dev/cua63 Callout device corresponding to ttyS63 @@ -742,6 +748,9 @@ block Syquest EZ135 parallel port removable drive 0 = /dev/eza Parallel EZ135 drive, whole disk + This device is obsolete and will be removed in a + future version of Linux. It has been replaced with + the parallel port IDE disk driver at major number 45. Partitions are handled in the same way as IDE disks (see major number 3). @@ -750,6 +759,10 @@ block MicroSolutions BackPack parallel port CD-ROM 0 = /dev/bpcd BackPack CD-ROM + This device is obsolete and will be removed in a + future version of Linux. It has been replaced with + the parallel port ATAPI CD-ROM driver at major number 46. + 42 Demo/sample use This number is intended for use in sample code, as @@ -807,39 +820,66 @@ 191 = /dev/ippp63 64th SyncPPP device 255 = /dev/isdninfo ISDN monitor interface + block Parallel port IDE disk devices + 0 = /dev/pda First parallel port IDE disk + 16 = /dev/pdb Second parallel port IDE disk + 32 = /dev/pdc Third parallel port IDE disk + 48 = /dev/pdd Fourth parallel port IDE disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the partition + limit is 15 rather than 63 per disk. 46 char Comtrol Rocketport serial card 0 = /dev/ttyR0 First Rocketport port 1 = /dev/ttyR1 Second Rocketport port ... + block Parallel port ATAPI CD-ROM devices + 0 = /dev/pcd0 First parallel port ATAPI CD-ROM + 1 = /dev/pcd1 Second parallel port ATAPI CD-ROM + 2 = /dev/pcd2 Third parallel port ATAPI CD-ROM + 3 = /dev/pcd3 Fourth parallel port ATAPI CD-ROM 47 char Comtrol Rocketport serial card - alternate devices 0 = /dev/cur0 Callout device corresponding to ttyR0 1 = /dev/cur1 Callout device corresponding to ttyR1 ... + block Parallel port ATAPI disk devices + 0 = /dev/pf0 First parallel port ATAPI disk + 1 = /dev/pf1 Second parallel port ATAPI disk + 2 = /dev/pf2 Third parallel port ATAPI disk + 3 = /dev/pf3 Fourth parallel port ATAPI disk + + This driver is intended for floppy disks and similar + devices and hence does not support partitioning. 48 char SDL RISCom serial card 0 = /dev/ttyL0 First RISCom port 1 = /dev/ttyL1 Second RISCom port ... + block Reserved for Mylex DAC960 PCI RAID controller 49 char SDL RISCom serial card - alternate devices 0 = /dev/cul0 Callout device corresponding to ttyL0 1 = /dev/cul1 Callout device corresponding to ttyL1 ... + block Reserved for Mylex DAC960 PCI RAID controller 50 char Reserved for GLINT + block Reserved for Mylex DAC960 PCI RAID controller 51 char Baycom radio modem 0 = /dev/bc0 First Baycom radio modem 1 = /dev/bc1 Second Baycom radio modem ... + block Reserved for Mylex DAC960 PCI RAID controller 52 char Spellcaster DataComm/BRI ISDN card 0 = /dev/dcbri0 First DataComm card 1 = /dev/dcbri1 Second DataComm card 2 = /dev/dcbri2 Third DataComm card 3 = /dev/dcbri3 Fourth DataComm card + block Reserved for Mylex DAC960 PCI RAID controller 53 char BDM interface for remote debugging MC683xx microcontrollers 0 = /dev/pd_bdm0 PD BDM interface on lp0 @@ -855,6 +895,8 @@ Domain Interface and ICD is the commercial interface by P&E. + block Reserved for Mylex DAC960 PCI RAID controller + 54 char Electrocardiognosis Holter serial card 0 = /dev/holter0 First Holter port 1 = /dev/holter1 Second Holter port @@ -864,8 +906,11 @@ to transfer data from Holter 24-hour heart monitoring equipment. + block Reserved for Mylex DAC960 PCI RAID controller + 55 char DSP56001 digital signal processor 0 = /dev/dsp56k First DSP56001 + block Reserved for Mylex DAC960 PCI RAID controller 56 char Apple Desktop Bus 0 = /dev/adb ADB bus control @@ -1120,7 +1165,33 @@ 2 = /dev/ipstate State information log file 3 = /dev/ipauth Authentication control device/log file - 96-119 UNALLOCATED + 96 char Parallel port ATAPI tape devices + 0 = /dev/pt0 First parallel port ATAPI tape + 1 = /dev/pt1 Second parallel port ATAPI tape + 2 = /dev/pt2 Third parallel port ATAPI tape + 3 = /dev/pt3 Fourth parallel port ATAPI tape + 128 = /dev/npt0 First p.p. ATAPI tape, no rewind + 129 = /dev/npt1 Second p.p. ATAPI tape, no rewind + 130 = /dev/npt2 Third p.p. ATAPI tape, no rewind + 131 = /dev/npt3 Fourth p.p. ATAPI tape, no rewind + + 97 char Parallel port generic ATAPI interface + 0 = /dev/pg0 First parallel port ATAPI device + 1 = /dev/pg1 Second parallel port ATAPI device + 2 = /dev/pg2 Third parallel port ATAPI device + 3 = /dev/pg3 Fourth parallel port ATAPI device + + These devices support the same API as the generic SCSI + devices. + + 98 char Control and Measurement Device (comedi) + 0 = /dev/comedi0 First comedi device + 1 = /dev/comedi1 Second comedi device + ... + + See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/. + + 99-119 UNALLOCATED 120-127 LOCAL/EXPERIMENTAL USE diff -u --recursive --new-file v2.1.87/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.1.87/linux/Documentation/ioctl-number.txt Tue Feb 17 13:12:43 1998 +++ linux/Documentation/ioctl-number.txt Fri Feb 20 17:54:35 1998 @@ -1,5 +1,5 @@ Ioctl Numbers -28 Jan 1998 +18 Feb 1998 Michael Chastain @@ -99,6 +99,8 @@ 'n' all linux/ncp_fs.h 'p' 00-3F linux/mc146818rtc.h 'p' 40-7F linux/nvram.h +'p' 80-9F user-space parport in development: + 'r' all linux/msdos_fs.h 's' all linux/cdk.h 't' 00-7F linux/if_ppp.h diff -u --recursive --new-file v2.1.87/linux/Makefile linux/Makefile --- v2.1.87/linux/Makefile Tue Feb 17 13:12:43 1998 +++ linux/Makefile Fri Feb 20 18:27:17 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 87 +SUBLEVEL = 88 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) @@ -402,7 +402,7 @@ depend dep: dep-files $(MODVERFILE) checkconfig: - perl -w scripts/checkconfig.pl `find $(FINDHPATH) $(SUBDIRS) -name '*.[hcS]' -print | sort` + perl -w scripts/checkconfig.pl `find * -name '*.[hcS]' -print | sort` ifdef CONFIGURATION ..$(CONFIGURATION): diff -u --recursive --new-file v2.1.87/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.87/linux/arch/alpha/kernel/irq.c Wed Feb 4 11:35:59 1998 +++ linux/arch/alpha/kernel/irq.c Thu Feb 19 14:58:40 1998 @@ -423,6 +423,16 @@ #endif /* CONFIG_ALPHA_SABLE */ } +int check_irq(unsigned int irq) +{ + struct irqaction **p; + + p = irq_action + irq; + if (*p == NULL) + return 0; + return -EBUSY; +} + int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, diff -u --recursive --new-file v2.1.87/linux/arch/alpha/kernel/t2.c linux/arch/alpha/kernel/t2.c --- v2.1.87/linux/arch/alpha/kernel/t2.c Fri Jan 30 11:28:05 1998 +++ linux/arch/alpha/kernel/t2.c Fri Feb 20 18:28:21 1998 @@ -8,7 +8,6 @@ * */ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.1.87/linux/arch/arm/kernel/entry-armv.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/entry-armv.S Fri Feb 20 18:28:21 1998 @@ -9,6 +9,7 @@ * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes * it to save wrong values... Be aware! */ +#include /* for CONFIG_ARCH_EBSA110 /* #include #include diff -u --recursive --new-file v2.1.87/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.1.87/linux/arch/arm/kernel/head-armo.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/head-armo.S Fri Feb 20 18:28:21 1998 @@ -5,7 +5,6 @@ * * 26-bit kernel startup code */ -#include #include .text diff -u --recursive --new-file v2.1.87/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.1.87/linux/arch/arm/kernel/irq.c Thu Feb 12 20:56:04 1998 +++ linux/arch/arm/kernel/irq.c Fri Feb 20 18:28:21 1998 @@ -15,6 +15,7 @@ * IRQ's are in fact implemented a bit like signal handlers for the kernel. * Naturally it's not a 1:1 relation, but there are similarities. */ +#include /* for CONFIG_DEBUG_ERRORS */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.1.87/linux/arch/arm/kernel/signal.c Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/signal.c Fri Feb 20 18:28:21 1998 @@ -4,6 +4,7 @@ * Copyright (C) 1995, 1996 Russell King */ +#include /* for CONFIG_CPU_ARM6 and CONFIG_CPU_SA110 */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S --- v2.1.87/linux/arch/arm/lib/io-acorn.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/lib/io-acorn.S Fri Feb 20 18:28:21 1998 @@ -3,6 +3,7 @@ * * Copyright (C) 1995, 1996 Russell King */ +#include /* for CONFIG_CPU_ARM2 and CONFIG_CPU_ARM3 */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/arm/lib/system.S linux/arch/arm/lib/system.S --- v2.1.87/linux/arch/arm/lib/system.S Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/lib/system.S Fri Feb 20 18:28:21 1998 @@ -6,7 +6,6 @@ * 07/06/96: Now support tasks running in SVC mode. */ #include -#include #include .text diff -u --recursive --new-file v2.1.87/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- v2.1.87/linux/arch/i386/boot/bootsect.S Wed Apr 16 14:14:59 1997 +++ linux/arch/i386/boot/bootsect.S Fri Feb 20 18:28:21 1998 @@ -22,6 +22,7 @@ ! read errors will result in a unbreakable loop. Reboot by hand. It ! loads pretty fast by getting whole tracks at a time whenever possible. +#include /* for CONFIG_ROOT_RDONLY */ #include .text diff -u --recursive --new-file v2.1.87/linux/arch/i386/boot/compressed/head.S linux/arch/i386/boot/compressed/head.S --- v2.1.87/linux/arch/i386/boot/compressed/head.S Mon Dec 1 10:34:10 1997 +++ linux/arch/i386/boot/compressed/head.S Fri Feb 20 18:28:21 1998 @@ -28,7 +28,6 @@ .text #define __ASSEMBLY__ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.1.87/linux/arch/i386/boot/setup.S Mon Dec 29 10:23:54 1997 +++ linux/arch/i386/boot/setup.S Thu Feb 19 14:58:40 1998 @@ -410,8 +410,8 @@ mov [68],ebx ! BIOS entry point offset mov [72],cx ! BIOS 16 bit code segment mov [74],dx ! BIOS data segment - mov [78],si ! BIOS code segment length - mov [80],di ! BIOS data segment length + mov [78],esi ! BIOS code segment length + mov [82],di ! BIOS data segment length jmp done_apm_bios no_32_apm_bios: diff -u --recursive --new-file v2.1.87/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c --- v2.1.87/linux/arch/i386/boot/tools/build.c Thu May 29 21:53:04 1997 +++ linux/arch/i386/boot/tools/build.c Fri Feb 20 18:28:21 1998 @@ -33,7 +33,6 @@ #include #include #include -#include #include typedef unsigned char byte; diff -u --recursive --new-file v2.1.87/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S --- v2.1.87/linux/arch/i386/boot/video.S Thu May 15 16:48:01 1997 +++ linux/arch/i386/boot/video.S Fri Feb 20 18:28:21 1998 @@ -5,6 +5,8 @@ ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson ! +#include /* for CONFIG_VIDEO_* */ + ! Enable autodetection of SVGA adapters and modes. If you really need this ! feature, drop me a mail as I think of removing it some day... #undef CONFIG_VIDEO_SVGA diff -u --recursive --new-file v2.1.87/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.87/linux/arch/i386/kernel/irq.c Tue Feb 17 13:12:44 1998 +++ linux/arch/i386/kernel/irq.c Fri Feb 20 18:28:21 1998 @@ -15,7 +15,6 @@ * Naturally it's not a 1:1 relation, but there are similarities. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.1.87/linux/arch/i386/kernel/ptrace.c Tue Dec 23 20:23:53 1997 +++ linux/arch/i386/kernel/ptrace.c Fri Feb 20 18:28:21 1998 @@ -2,6 +2,7 @@ /* By Ross Biro 1/23/92 */ /* edited by Linus Torvalds */ +#include /* for CONFIG_MATH_EMULATION */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.87/linux/arch/i386/kernel/smp.c Tue Feb 17 13:12:44 1998 +++ linux/arch/i386/kernel/smp.c Thu Feb 19 14:58:40 1998 @@ -878,8 +878,14 @@ else printk("Not responding.\n"); } - } SMP_PRINTK(("CPU has booted.\n")); + } + else + { + __cpu_logical_map[cpucount] = -1; + cpu_number_map[i] = -1; + cpucount--; + } swapper_pg_dir[0]=maincfg; local_flush_tlb(); @@ -1031,9 +1037,11 @@ * Make sure we unmap all failed CPUs */ - if (cpu_number_map[i] == -1) + if (cpu_number_map[i] == -1 && (cpu_present_map & (1 << i))) { + printk("CPU #%d not responding. Removing from cpu_present_map.\n",i); cpu_present_map &= ~(1 << i); - } + } + } /* * Cleanup possible dangling ends... diff -u --recursive --new-file v2.1.87/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.1.87/linux/arch/i386/kernel/traps.c Sun Dec 21 17:27:18 1997 +++ linux/arch/i386/kernel/traps.c Fri Feb 20 18:28:21 1998 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/amiga/amiga_ksyms.c linux/arch/m68k/amiga/amiga_ksyms.c --- v2.1.87/linux/arch/m68k/amiga/amiga_ksyms.c Wed Apr 23 19:01:14 1997 +++ linux/arch/m68k/amiga/amiga_ksyms.c Fri Feb 20 18:28:21 1998 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/atari/atari_ksyms.c linux/arch/m68k/atari/atari_ksyms.c --- v2.1.87/linux/arch/m68k/atari/atari_ksyms.c Tue Feb 17 13:12:44 1998 +++ linux/arch/m68k/atari/atari_ksyms.c Fri Feb 20 18:28:21 1998 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c --- v2.1.87/linux/arch/m68k/atari/time.c Tue Feb 17 13:12:44 1998 +++ linux/arch/m68k/atari/time.c Fri Feb 20 18:28:21 1998 @@ -10,7 +10,6 @@ * for more details. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.1.87/linux/arch/m68k/kernel/m68k_ksyms.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/kernel/m68k_ksyms.c Fri Feb 20 18:28:21 1998 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c --- v2.1.87/linux/arch/m68k/kernel/time.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/kernel/time.c Fri Feb 20 18:28:21 1998 @@ -7,6 +7,7 @@ * Most of the stuff is located in the machine specific files. */ +#include /* CONFIG_HEARTBEAT */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c --- v2.1.87/linux/arch/m68k/mac/mackeyb.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/mac/mackeyb.c Fri Feb 20 18:28:21 1998 @@ -10,7 +10,6 @@ * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c) */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c --- v2.1.87/linux/arch/m68k/mac/via6522.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/mac/via6522.c Fri Feb 20 18:28:21 1998 @@ -6,7 +6,6 @@ * via them as are assorted bits and bobs - eg rtc, adb. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/m68k/mvme16x/16xints.c linux/arch/m68k/mvme16x/16xints.c --- v2.1.87/linux/arch/m68k/mvme16x/16xints.c Tue Feb 17 13:12:45 1998 +++ linux/arch/m68k/mvme16x/16xints.c Fri Feb 20 18:28:21 1998 @@ -11,7 +11,6 @@ * */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.1.87/linux/arch/ppc/kernel/idle.c Fri Jan 16 20:34:18 1998 +++ linux/arch/ppc/kernel/idle.c Fri Feb 20 18:28:21 1998 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.1.87/linux/arch/ppc/kernel/prep_pci.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/kernel/prep_pci.c Fri Feb 20 18:28:21 1998 @@ -7,7 +7,6 @@ * The motherboard routes/maps will disappear shortly. -- Cort */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.1.87/linux/arch/ppc/kernel/process.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/kernel/process.c Fri Feb 20 18:28:21 1998 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c --- v2.1.87/linux/arch/ppc/kernel/residual.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/kernel/residual.c Fri Feb 20 18:28:21 1998 @@ -7,7 +7,6 @@ * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es) */ #if 0 -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.1.87/linux/arch/ppc/kernel/time.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/kernel/time.c Fri Feb 20 18:28:21 1998 @@ -6,7 +6,6 @@ * Paul Mackerras' version and mine for PReP and Pmac. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c --- v2.1.87/linux/arch/ppc/mm/extable.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/mm/extable.c Fri Feb 20 18:28:21 1998 @@ -4,7 +4,6 @@ * from linux/arch/i386/mm/extable.c */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c --- v2.1.87/linux/arch/sparc/ap1000/apmmu.c Fri Jan 16 20:39:23 1998 +++ linux/arch/sparc/ap1000/apmmu.c Fri Feb 20 18:28:22 1998 @@ -11,7 +11,6 @@ * based on srmmu.c */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/sparc/ap1000/bnet.c linux/arch/sparc/ap1000/bnet.c --- v2.1.87/linux/arch/sparc/ap1000/bnet.c Thu Feb 12 20:56:04 1998 +++ linux/arch/sparc/ap1000/bnet.c Fri Feb 20 18:28:22 1998 @@ -8,7 +8,6 @@ /* routines to control the AP1000 bif interface. This is the interface used to talk to the front end processor */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c --- v2.1.87/linux/arch/sparc/ap1000/msc.c Fri Jan 16 20:39:41 1998 +++ linux/arch/sparc/ap1000/msc.c Fri Feb 20 18:28:22 1998 @@ -10,7 +10,6 @@ * and Memory Controller (MC+). * */ -#include #define _APLIB_ #include #include diff -u --recursive --new-file v2.1.87/linux/arch/sparc/ap1000/timer.c linux/arch/sparc/ap1000/timer.c --- v2.1.87/linux/arch/sparc/ap1000/timer.c Mon Jan 12 15:15:43 1998 +++ linux/arch/sparc/ap1000/timer.c Fri Feb 20 18:28:22 1998 @@ -7,6 +7,7 @@ */ /* routines to control the AP1000 timer chip */ +#include /* for CONFIG_PROFILE */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.1.87/linux/arch/sparc/kernel/smp.c Thu Feb 12 20:56:04 1998 +++ linux/arch/sparc/kernel/smp.c Fri Feb 20 18:28:22 1998 @@ -3,6 +3,7 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include /* for CONFIG_PROFILE */ #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/README linux/drivers/acorn/README --- v2.1.87/linux/drivers/acorn/README Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/README Mon Feb 16 15:49:47 1998 @@ -0,0 +1,3 @@ +Drivers for the ACORN "podule" ARM specific bus. + + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/Config.in linux/drivers/acorn/block/Config.in --- v2.1.87/linux/drivers/acorn/block/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/block/Config.in Mon Feb 16 13:46:44 1998 @@ -0,0 +1,21 @@ +# +# Block device driver configuration +# +mainmenu_option next_comment +comment 'Acorn-Specific floppy, IDE, and other block devices' + +tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD +bool ' Support expansion card IDE interfaces' CONFIG_BLK_DEV_IDE_CARDS +if [ "$CONFIG_BLK_DEV_IDE_CARDS" = "y" ]; then + dep_tristate ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_BLK_DEV_IDE + dep_tristate ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE +fi + +tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM +if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then + bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT +fi + +bool 'ADFS partition support' CONFIG_BLK_DEV_PART + +endmenu diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/Makefile linux/drivers/acorn/block/Makefile --- v2.1.87/linux/drivers/acorn/block/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/block/Makefile Mon Feb 16 13:49:36 1998 @@ -0,0 +1,66 @@ +# +# Makefile for the Acorn block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# + +L_TARGET := acorn-block.a +L_OBJS := +M_OBJS := +MOD_LIST_NAME := ACORN_BLOCK_MODULES + +ifeq ($(CONFIG_ARCH_ARC),y) + ifeq ($(CONFIG_BLK_DEV_FD),y) + L_OBJS += fd1772.o fd1772dma.o + else + ifeq ($(CONFIG_BLK_DEV_FD),m) + M_OBJS += fd1772_mod.o + endif + endif +endif + +ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y) + L_OBJS += ide-ics.o +else + ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),m) + M_OBJS += ide-ics.o + endif +endif + +ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y) + L_OBJS += ide-rapide.o +else + ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),m) + M_OBJS += ide-rapide.o + endif +endif + +ifeq ($(CONFIG_BLK_DEV_MFM),y) + L_OBJS += mfmhd.o mfm.o +else + ifeq ($(CONFIG_BLK_DEV_MFM),m) + M_OBJS += mfmhd_mod.o + endif +endif + +include $(TOPDIR)/Rules.make + +fd1772_mod.o: $(FLOPPY) + $(LD) -r -o $@ $(FLOPPY) + +mfmhd_mod.o: mfmhd.o mfm.o + $(LD) -r -o $@ mfmhd.o mfm.o + +%.o: %.S +ifndef $(CONFIG_BINUTILS_NEW) + $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s + $(CC) $(CFLAGS) -c -o $@ ..tmp.s + $(RM) ..tmp.s +else + $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< +endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.1.87/linux/drivers/acorn/block/fd1772.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/block/fd1772.c Sun Jan 25 10:02:29 1998 @@ -0,0 +1,1670 @@ +/* + * linux/kernel/arch/arm/drivers/block/fd1772.c + * Based on ataflop.c in the m68k Linux + * Copyright (C) 1993 Greg Harp + * Atari Support by Bjoern Brauel, Roman Hodek + * Archimedes Support by Dave Gilbert (gilbertd@cs.man.ac.uk) + * + * Big cleanup Sep 11..14 1994 Roman Hodek: + * - Driver now works interrupt driven + * - Support for two drives; should work, but I cannot test that :-( + * - Reading is done in whole tracks and buffered to speed up things + * - Disk change detection and drive deselecting after motor-off + * similar to TOS + * - Autodetection of disk format (DD/HD); untested yet, because I + * don't have an HD drive :-( + * + * Fixes Nov 13 1994 Martin Schaller: + * - Autodetection works now + * - Support for 5 1/4" disks + * - Removed drive type (unknown on atari) + * - Do seeks with 8 Mhz + * + * Changes by Andreas Schwab: + * - After errors in multiple read mode try again reading single sectors + * (Feb 1995): + * - Clean up error handling + * - Set blk_size for proper size checking + * - Initialize track register when testing presence of floppy + * - Implement some ioctl's + * + * Changes by Torsten Lang: + * - When probing the floppies we should add the FDC1772CMDADD_H flag since + * the FDC1772 will otherwise wait forever when no disk is inserted... + * + * Things left to do: + * - Formatting + * - Maybe a better strategy for disk change detection (does anyone + * know one?) + * - There are some strange problems left: The strangest one is + * that, at least on my TT (4+4MB), the first 2 Bytes of the last + * page of the TT-Ram (!) change their contents (some bits get + * set) while a floppy DMA is going on. But there are no accesses + * to these memory locations from the kernel... (I tested that by + * making the page read-only). I cannot explain what's going on... + * - Sometimes the drive-change-detection stops to work. The + * function is still called, but the WP bit always reads as 0... + * Maybe a problem with the status reg mode or a timing problem. + * Note 10/12/94: The change detection now seems to work reliably. + * There is no proof, but I've seen no hang for a long time... + * + * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk) + * 26/12/95 - Changed all names starting with FDC to FDC1772 + * Removed all references to clock speed of FDC - we're stuck with 8MHz + * Modified disk_type structure to remove HD formats + * + * 7/ 1/96 - Wrote FIQ code, removed most remaining atariisms + * + * 13/ 1/96 - Well I think its read a single sector; but there is a problem + * fd_rwsec_done which is called in FIQ mode starts another transfer + * off (in fd_rwsec) while still in FIQ mode. Because its still in + * FIQ mode it can't service the DMA and loses data. So need to + * heavily restructure. + * 14/ 1/96 - Found that the definitions of the register numbers of the + * FDC were multiplied by 2 in the header for the 16bit words + * of the atari so half the writes were going in the wrong place. + * Also realised that the FIQ entry didn't make any attempt to + * preserve registers or return correctly; now in assembler. + * + * 11/ 2/96 - Hmm - doesn't work on real machine. Auto detect doesn't + * and hacking that past seems to wait forever - check motor + * being turned on. + * + * 17/ 2/96 - still having problems - forcing track to -1 when selecting + * new drives seems to allow it to read first few sectors + * but then we get solid hangs at apparently random places + * which change depending what is happening. + * + * 9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35 + * A lot of fiddling in DMA stuff. Having problems with it + * constnatly thinking its timeing out. Ah - its timeout + * was set to (6*HZ) rather than jiffies+(6*HZ). Now giving + * duff data! + * + * 5/ 4/96 - Made it use the new IOC_ macros rather than *ioc + * Hmm - giving unexpected FIQ and then timeouts + * 18/ 8/96 - Ran through indent -kr -i8 + * Some changes to disc change detect; don't know how well it + * works. + * 24/ 8/96 - Put all the track buffering code back in from the atari + * code - I wonder if it will still work... No :-) + * Still works if I turn off track buffering. + * 25/ 8/96 - Changed the timer expires that I'd added back to be + * jiffies + ....; and it all sprang to life! Got 2.8K/sec + * off a cp -r of a 679K disc (showed 94% cpu usage!) + * (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt! + * Also perhaps that compile was with cache off. + * changed cli in fd_readtrack_check to cliIF + * changed vmallocs to kmalloc (whats the difference!!) + * Removed the busy wait loop in do_fd_request and replaced + * by a routine on tq_immediate; only 11% cpu on a dd off the + * raw disc - but the speed is the same. + * 1/ 9/96 - Idea (failed!) - set the 'disable spin-up seqeunce' + * when we read the track if we know the motor is on; didn't + * help - perhaps we have to do it in stepping as well. + * Nope. Still doesn't help. + * Hmm - what seems to be happening is that fd_readtrack_check + * is never getting called. Its job is to terminate the read + * just after we think we should have got the data; otherwise + * the fdc takes 1 second to timeout; which is what's happening + * Now I can see 'readtrack_timer' being set (which should do the + * call); but it never seems to be called - hmm! + * OK - I've moved the check to my tq_immediate code - + * and it WORKS! 13.95K/second at 19% CPU. + * I wish I knew why that timer didn't work..... + * + * 16/11/96 - Fiddled and frigged for 2.0.18 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR FLOPPY_MAJOR +#define FLOPPY_DMA 0 +#include "blk.h" + +/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with + * little additional rework in this file). But I'm not yet sure if + * some other code depends on the number of floppies... (It is defined + * in a public header!) + */ +#if 0 +#undef FD_MAX_UNITS +#define FD_MAX_UNITS 2 +#endif + +/* Ditto worries for Arc - DAG */ +#define FD_MAX_UNITS 4 +#define TRACKBUFFER 0 +/*#define DEBUG*/ + +#ifdef DEBUG +#define DPRINT(a) printk a +#else +#define DPRINT(a) +#endif + +/* Disk types: DD */ +static struct archy_disk_type { + const char *name; + unsigned spt; /* sectors per track */ + unsigned blocks; /* total number of blocks */ + unsigned stretch; /* track doubling ? */ +} disk_type[] = { + + { "d360", 9, 720, 0 }, /* 360kB diskette */ + { "D360", 9, 720, 1 }, /* 360kb in 720kb drive */ + { "D720", 9, 1440, 0 }, /* 720kb diskette (DD) */ + /*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors + - DAG - can't see how type detect can distinguish this + from 720K until it reads block 4 by which time its too late! */ +}; + +#define NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type)) + +/* + * Maximum disk size (in kilobytes). This default is used whenever the + * current disk size is unknown. + */ +#define MAX_DISK_SIZE 720 + +static int floppy_sizes[256]; +static int floppy_blocksizes[256] = {0,}; + +/* current info on each unit */ +static struct archy_floppy_struct { + int connected; /* !=0 : drive is connected */ + int autoprobe; /* !=0 : do autoprobe */ + + struct archy_disk_type *disktype; /* current type of disk */ + + int track; /* current head position or -1 + * if unknown */ + unsigned int steprate; /* steprate setting */ + unsigned int wpstat; /* current state of WP signal + * (for disk change detection) */ +} unit[FD_MAX_UNITS]; + +/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which + is an assembler routine */ +extern void fdc1772_comendhandler(void); /* Actually doens't have these parameters - see fd1772.S */ +extern volatile int fdc1772_comendstatus; +extern volatile int fdc1772_fdc_int_done; + +#define FDC1772BASE ((0x210000>>2)|0x80000000) + +#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2)) + +/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather + than the #def below - well simple - the #def won't compile - and I + don't understand why (__outwc not defined) */ +/* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility + with the ST version of fd1772.h */ +/*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */ +void FDC1772_WRITE(int reg, unsigned char val) +{ + if (reg == FDC1772REG_CMD) { + DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies)); + if (fdc1772_fdc_int_done) { + DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n")); + fdc1772_fdc_int_done = 0; + }; + }; + outb(val, (reg / 2) + FDC1772BASE); +}; + +#define MAX_SECTORS 22 + +unsigned char *DMABuffer; /* buffer for writes */ +/*static unsigned long PhysDMABuffer; *//* physical address */ +/* DAG: On Arc we just go straight for the DMA buffer */ +#define PhysDMABuffer DMABuffer + +#ifdef TRACKBUFFER +unsigned char *TrackBuffer; /* buffer for reads */ +#define PhysTrackBuffer TrackBuffer /* physical address */ +static int BufferDrive, BufferSide, BufferTrack; +static int read_track; /* non-zero if we are reading whole tracks */ + +#define SECTOR_BUFFER(sec) (TrackBuffer + ((sec)-1)*512) +#define IS_BUFFERED(drive,side,track) \ + (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track)) +#endif + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int SelectedDrive = 0; +static int ReqCmd, ReqBlock; +static int ReqSide, ReqTrack, ReqSector, ReqCnt; +static int HeadSettleFlag = 0; +static unsigned char *ReqData, *ReqBuffer; +static int MotorOn = 0, MotorOffTrys; + +/* Synchronization of FDC1772 access. */ +static volatile int fdc_busy = 0; +static struct wait_queue *fdc_wait = NULL; + + +static unsigned int changed_floppies = 0xff, fake_change = 0; +#define CHECK_CHANGE_DELAY HZ/2 + +/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */ +#define FD_MOTOR_OFF_DELAY (10*HZ) +#define FD_MOTOR_OFF_MAXTRY (10*20) + +#define FLOPPY_TIMEOUT (6*HZ) +#define RECALIBRATE_ERRORS 4 /* After this many errors the drive + * will be recalibrated. */ +#define MAX_ERRORS 8 /* After this many errors the driver + * will give up. */ + + +#define START_MOTOR_OFF_TIMER(delay) \ + do { \ + motor_off_timer.expires = jiffies + (delay); \ + add_timer( &motor_off_timer ); \ + MotorOffTrys = 0; \ + } while(0) + +#define START_CHECK_CHANGE_TIMER(delay) \ + do { \ + timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \ + timer_active |= (1 << FLOPPY_TIMER); \ + } while(0) + +#define START_TIMEOUT() \ + do { \ + del_timer( &timeout_timer ); \ + timeout_timer.expires = jiffies + FLOPPY_TIMEOUT; \ + add_timer( &timeout_timer ); \ + } while(0) + +#define STOP_TIMEOUT() \ + do { \ + del_timer( &timeout_timer ); \ + } while(0) + +#define ENABLE_IRQ() enable_irq(FIQ_FD1772+64); + +#define DISABLE_IRQ() disable_irq(FIQ_FD1772+64); + +static void fd1772_checkint(void); + +struct tq_struct fd1772_tq = +{ 0,0, (void *)fd1772_checkint, 0 }; +/* + * The driver is trying to determine the correct media format + * while Probing is set. fd_rwsec_done() clears it after a + * successful access. + */ +static int Probing = 0; + +/* This flag is set when a dummy seek is necesary to make the WP + * status bit accessible. + */ +static int NeedSeek = 0; + + +/***************************** Prototypes *****************************/ + +static void fd_select_side(int side); +static void fd_select_drive(int drive); +static void fd_deselect(void); +static void fd_motor_off_timer(unsigned long dummy); +static void check_change(void); +static __inline__ void set_head_settle_flag(void); +static __inline__ int get_head_settle_flag(void); +static void floppy_irqconsequencehandler(void); +static void fd_error(void); +static void do_fd_action(int drive); +static void fd_calibrate(void); +static void fd_calibrate_done(int status); +static void fd_seek(void); +static void fd_seek_done(int status); +static void fd_rwsec(void); +#ifdef TRACKBUFFER +static void fd_readtrack_check( unsigned long dummy ); +#endif +static void fd_rwsec_done(int status); +static void fd_times_out(unsigned long dummy); +static void finish_fdc(void); +static void finish_fdc_done(int dummy); +static void floppy_off(unsigned int nr); +static __inline__ void copy_buffer(void *from, void *to); +static void setup_req_params(int drive); +static void redo_fd_request(void); +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int + cmd, unsigned long param); +static void fd_probe(int drive); +static int fd_test_drive_present(int drive); +static void config_types(void); +static int floppy_open(struct inode *inode, struct file *filp); +static void floppy_release(struct inode *inode, struct file *filp); + +/************************* End of Prototypes **************************/ + +static struct timer_list motor_off_timer = +{NULL, NULL, 0, 0, fd_motor_off_timer}; +#ifdef TRACKBUFFER +static struct timer_list readtrack_timer = + { NULL, NULL, 0, 0, fd_readtrack_check }; +#endif +static struct timer_list timeout_timer = +{NULL, NULL, 0, 0, fd_times_out}; + +/* DAG: Haven't got a clue what this is? */ +int stdma_islocked(void) +{ + return 0; +}; + +/* Select the side to use. */ + +static void fd_select_side(int side) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL); + restore_flags(flags); +} + + +/* Select a drive, update the FDC1772's track register + */ + +static void fd_select_drive(int drive) +{ + unsigned long flags; + +#ifdef DEBUG + printk("fd_select_drive:%d\n", drive); +#endif + /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */ + oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0); + + if (drive == SelectedDrive) + return; + + save_flags(flags); + cli(); + oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive)); + restore_flags(flags); + + /* restore track register to saved value */ + FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track); + udelay(25); + + SelectedDrive = drive; +} + + +/* Deselect both drives. */ + +static void fd_deselect(void) +{ + unsigned long flags; + + DPRINT(("fd_deselect\n")); + + save_flags(flags); + cli(); + oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE); + restore_flags(flags); + + SelectedDrive = -1; +} + + +/* This timer function deselects the drives when the FDC1772 switched the + * motor off. The deselection cannot happen earlier because the FDC1772 + * counts the index signals, which arrive only if one drive is selected. + */ + +static void fd_motor_off_timer(unsigned long dummy) +{ + unsigned long flags; + unsigned char status; + int delay; + + del_timer(&motor_off_timer); + + if (SelectedDrive < 0) + /* no drive selected, needn't deselect anyone */ + return; + + save_flags(flags); + cli(); + + if (fdc_busy) /* was stdma_islocked */ + goto retry; + + status = FDC1772_READ(FDC1772REG_STATUS); + + if (!(status & 0x80)) { + /* motor already turned off by FDC1772 -> deselect drives */ + /* In actual fact its this deselection which turns the motor off on the + Arc, since the motor control is actually on Latch A */ + DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n")); + fd_deselect(); + MotorOn = 0; + restore_flags(flags); + return; + } + /* not yet off, try again */ + + retry: + restore_flags(flags); + /* Test again later; if tested too often, it seems there is no disk + * in the drive and the FDC1772 will leave the motor on forever (or, + * at least until a disk is inserted). So we'll test only twice + * per second from then on... + */ + delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ? + (++MotorOffTrys, HZ / 20) : HZ / 2; + START_MOTOR_OFF_TIMER(delay); +} + + +/* This function is repeatedly called to detect disk changes (as good + * as possible) and keep track of the current state of the write protection. + */ + +static void check_change(void) +{ + static int drive = 0; + + unsigned long flags; + int stat; + + if (fdc_busy) + return; /* Don't start poking about if the fdc is busy */ + + return; /* lets just forget it for the mo DAG */ + + if (++drive > 1 || !unit[drive].connected) + drive = 0; + + save_flags(flags); + cli(); + + if (!stdma_islocked()) { + stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT); + + /* The idea here is that if the write protect line has changed then + the disc must have changed */ + if (stat != unit[drive].wpstat) { + DPRINT(("wpstat[%d] = %d\n", drive, stat)); + unit[drive].wpstat = stat; + set_bit(drive, &changed_floppies); + } + } + restore_flags(flags); + + START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY); +} + + +/* Handling of the Head Settling Flag: This flag should be set after each + * seek operation, because we dont't use seeks with verify. + */ + +static __inline__ void set_head_settle_flag(void) +{ + HeadSettleFlag = FDC1772CMDADD_E; +} + +static __inline__ int get_head_settle_flag(void) +{ + int tmp = HeadSettleFlag; + HeadSettleFlag = 0; + return (tmp); +} + + + + +/* General Interrupt Handling */ + +static void (*FloppyIRQHandler) (int status) = NULL; + +static void floppy_irqconsequencehandler(void) +{ + unsigned char status; + void (*handler) (int); + + fdc1772_fdc_int_done = 0; + + handler = FloppyIRQHandler; + FloppyIRQHandler = NULL; + + if (handler) { + nop(); + status = (unsigned char) fdc1772_comendstatus; + DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler)); + handler(status); + } else { + DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus)); + } + DPRINT(("FDC1772 irq: end of floppy_irq\n")); +} + + +/* Error handling: If some error happened, retry some times, then + * recalibrate, then try again, and fail after MAX_ERRORS. + */ + +static void fd_error(void) +{ + printk("FDC1772: fd_error\n"); + /*panic("fd1772: fd_error"); *//* DAG tmp */ + if (!CURRENT) + return; + CURRENT->errors++; + if (CURRENT->errors >= MAX_ERRORS) { + printk("fd%d: too many errors.\n", SelectedDrive); + end_request(0); + } else if (CURRENT->errors == RECALIBRATE_ERRORS) { + printk("fd%d: recalibrating\n", SelectedDrive); + if (SelectedDrive != -1) + unit[SelectedDrive].track = -1; + } + redo_fd_request(); +} + + + +#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0) + + +/* do_fd_action() is the general procedure for a fd request: All + * required parameter settings (drive select, side select, track + * position) are checked and set if needed. For each of these + * parameters and the actual reading or writing exist two functions: + * one that starts the setting (or skips it if possible) and one + * callback for the "done" interrupt. Each done func calls the next + * set function to propagate the request down to fd_rwsec_done(). + */ + +static void do_fd_action(int drive) +{ + DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track)); + +#ifdef TRACKBUFFER + repeat: + + if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { + if (ReqCmd == READ) { + copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); + if (++ReqCnt < CURRENT->current_nr_sectors) { + /* read next sector */ + setup_req_params( drive ); + goto repeat; + } + else { + /* all sectors finished */ + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + end_request( 1 ); + redo_fd_request(); + return; + } + } + else { + /* cmd == WRITE, pay attention to track buffer + * consistency! */ + copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) ); + } + } +#endif + + if (SelectedDrive != drive) { + /*unit[drive].track = -1; DAG */ + fd_select_drive(drive); + }; + + + if (unit[drive].track == -1) + fd_calibrate(); + else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch) + fd_seek(); + else + fd_rwsec(); +} + + +/* Seek to track 0 if the current track is unknown */ + +static void fd_calibrate(void) +{ + DPRINT(("fd_calibrate\n")); + if (unit[SelectedDrive].track >= 0) { + fd_calibrate_done(0); + return; + } + DPRINT(("fd_calibrate (after track compare)\n")); + SET_IRQ_HANDLER(fd_calibrate_done); + /* we can't verify, since the speed may be incorrect */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate); + + NeedSeek = 1; + MotorOn = 1; + START_TIMEOUT(); + /* wait for IRQ */ +} + + +static void fd_calibrate_done(int status) +{ + DPRINT(("fd_calibrate_done()\n")); + STOP_TIMEOUT(); + + /* set the correct speed now */ + if (status & FDC1772STAT_RECNF) { + printk("fd%d: restore failed\n", SelectedDrive); + fd_error(); + } else { + unit[SelectedDrive].track = 0; + fd_seek(); + } +} + + +/* Seek the drive to the requested track. The drive must have been + * calibrated at some point before this. + */ + +static void fd_seek(void) +{ + unsigned long flags; + DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack, + unit[SelectedDrive].track)); + if (unit[SelectedDrive].track == ReqTrack << + unit[SelectedDrive].disktype->stretch) { + fd_seek_done(0); + return; + } + FDC1772_WRITE(FDC1772REG_DATA, ReqTrack << + unit[SelectedDrive].disktype->stretch); + udelay(25); + save_flags(flags); + cliIF(); + SET_IRQ_HANDLER(fd_seek_done); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate | + /* DAG */ + (MotorOn?FDC1772CMDADD_H:0)); + + restore_flags(flags); + MotorOn = 1; + set_head_settle_flag(); + START_TIMEOUT(); + /* wait for IRQ */ +} + + +static void fd_seek_done(int status) +{ + DPRINT(("fd_seek_done()\n")); + STOP_TIMEOUT(); + + /* set the correct speed */ + if (status & FDC1772STAT_RECNF) { + printk("fd%d: seek error (to track %d)\n", + SelectedDrive, ReqTrack); + /* we don't know exactly which track we are on now! */ + unit[SelectedDrive].track = -1; + fd_error(); + } else { + unit[SelectedDrive].track = ReqTrack << + unit[SelectedDrive].disktype->stretch; + NeedSeek = 0; + fd_rwsec(); + } +} + + +/* This does the actual reading/writing after positioning the head + * over the correct track. + */ + +#ifdef TRACKBUFFER +static int MultReadInProgress = 0; +#endif + + +static void fd_rwsec(void) +{ + unsigned long paddr, flags; + unsigned int rwflag, old_motoron; + unsigned int track; + + DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r')); + if (ReqCmd == WRITE) { + /*cache_push( (unsigned long)ReqData, 512 ); */ + paddr = (unsigned long) ReqData; + rwflag = 0x100; + } else { +#ifdef TRACKBUFFER + if (read_track) + paddr = (unsigned long)PhysTrackBuffer; + else + paddr =(unsigned long)PhysDMABuffer; +#else + paddr = (unsigned long)PhysDMABuffer; +#endif + rwflag = 0; + } + + DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag, + ReqSector, FDC1772_READ(FDC1772REG_TRACK))); + fd_select_side(ReqSide); + + /*DPRINT(("fd_rwsec() before start sector \n")); */ + /* Start sector of this operation */ +#ifdef TRACKBUFFER + FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 ); +#else + FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector ); +#endif + + /* Cheat for track if stretch != 0 */ + if (unit[SelectedDrive].disktype->stretch) { + track = FDC1772_READ(FDC1772REG_TRACK); + FDC1772_WRITE(FDC1772REG_TRACK, track >> + unit[SelectedDrive].disktype->stretch); + } + udelay(25); + + DPRINT(("fd_rwsec() before setup DMA \n")); + /* Setup DMA - Heavily modified by DAG */ + save_flags(flags); + cliIF(); + disable_dma(FLOPPY_DMA); + set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ); + set_dma_addr(FLOPPY_DMA, (long) paddr); /* DAG - changed from Atari specific */ +#ifdef TRACKBUFFER + set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512); +#else + set_dma_count(FLOPPY_DMA, 512); /* Block/sector size - going to have to change */ +#endif + SET_IRQ_HANDLER(fd_rwsec_done); + /* Turn on dma int */ + enable_dma(FLOPPY_DMA); + /* Now give it something to do */ + FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) : +#ifdef TRACKBUFFER + (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) | + /* Hmm - the idea here is to stop the FDC spinning the disc + up when we know that we already still have it spinning */ + (MotorOn?FDC1772CMDADD_H:0)) +#else + FDC1772CMD_RDSEC +#endif + )); + + restore_flags(flags); + DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags)); + /*sti(); *//* DAG - Hmm */ + /* Hmm - should do something DAG */ + old_motoron = MotorOn; + MotorOn = 1; + NeedSeek = 1; + + /* wait for interrupt */ + +#ifdef TRACKBUFFER + if (read_track) { + /* If reading a whole track, wait about one disk rotation and + * then check if all sectors are read. The FDC will even + * search for the first non-existant sector and need 1 sec to + * recognise that it isn't present :-( + */ + del_timer( &readtrack_timer ); + readtrack_timer.function = fd_readtrack_check; + readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ); + /* 1 rot. + 5 rot.s if motor was off */ + DPRINT(("Setting readtrack_timer to %d @ %d\n",readtrack_timer.expires,jiffies)); + add_timer( &readtrack_timer ); + MultReadInProgress = 1; + } +#endif + + /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */ + START_TIMEOUT(); + /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */ +} + + +#ifdef TRACKBUFFER + +static void fd_readtrack_check( unsigned long dummy ) + +{ unsigned long flags, addr; + extern unsigned char *fdc1772_dataaddr; + + DPRINT(("fd_readtrack_check @ %d\n",jiffies)); + + save_flags(flags); + cliIF(); + + del_timer( &readtrack_timer ); + + if (!MultReadInProgress) { + /* This prevents a race condition that could arise if the + * interrupt is triggered while the calling of this timer + * callback function takes place. The IRQ function then has + * already cleared 'MultReadInProgress' when control flow + * gets here. + */ + restore_flags(flags); + return; + } + + /* get the current DMA address */ + addr=fdc1772_dataaddr; /* DAG - ? */ + DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer)); + + if (addr >= PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) { + /* already read enough data, force an FDC interrupt to stop + * the read operation + */ + SET_IRQ_HANDLER( NULL ); + restore_flags(flags); + DPRINT(("fd_readtrack_check(): done\n")); + FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI ); + udelay(25); + + /* No error until now -- the FDC would have interrupted + * otherwise! + */ + fd_rwsec_done( 0 ); + } + else { + /* not yet finished, wait another tenth rotation */ + restore_flags(flags); + DPRINT(("fd_readtrack_check(): not yet finished\n")); + readtrack_timer.expires = jiffies + HZ/5/10; + add_timer( &readtrack_timer ); + } +} + +#endif + +static void fd_rwsec_done(int status) +{ + unsigned int track; + + DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies)); + +#ifdef TRACKBUFFER + if (read_track && !MultReadInProgress) return; + MultReadInProgress = 0; + + STOP_TIMEOUT(); + + if (read_track) + del_timer( &readtrack_timer ); +#endif + + + /* Correct the track if stretch != 0 */ + if (unit[SelectedDrive].disktype->stretch) { + track = FDC1772_READ(FDC1772REG_TRACK); + FDC1772_WRITE(FDC1772REG_TRACK, track << + unit[SelectedDrive].disktype->stretch); + } + if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) { + printk("fd%d: is write protected\n", SelectedDrive); + goto err_end; + } + if ((status & FDC1772STAT_RECNF) +#ifdef TRACKBUFFER + /* RECNF is no error after a multiple read when the FDC + * searched for a non-existant sector! + */ + && !(read_track && + FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt) +#endif + ) { + if (Probing) { + if (unit[SelectedDrive].disktype > disk_type) { + /* try another disk type */ + unit[SelectedDrive].disktype--; + floppy_sizes[SelectedDrive] + = unit[SelectedDrive].disktype->blocks >> 1; + } else + Probing = 0; + } else { + /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ + if (unit[SelectedDrive].autoprobe) { + unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1; + floppy_sizes[SelectedDrive] + = unit[SelectedDrive].disktype->blocks >> 1; + Probing = 1; + } + } + if (Probing) { + setup_req_params(SelectedDrive); +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + do_fd_action(SelectedDrive); + return; + } + printk("fd%d: sector %d not found (side %d, track %d)\n", + SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack); + goto err_end; + } + if (status & FDC1772STAT_CRC) { + printk("fd%d: CRC error (side %d, track %d, sector %d)\n", + SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); + goto err_end; + } + if (status & FDC1772STAT_LOST) { + printk("fd%d: lost data (side %d, track %d, sector %d)\n", + SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); + goto err_end; + } + Probing = 0; + + if (ReqCmd == READ) { +#ifdef TRACKBUFFER + if (!read_track) + { + /*cache_clear (PhysDMABuffer, 512);*/ + copy_buffer (DMABuffer, ReqData); + } + else + { + /*cache_clear (PhysTrackBuffer, MAX_SECTORS * 512);*/ + BufferDrive = SelectedDrive; + BufferSide = ReqSide; + BufferTrack = ReqTrack; + copy_buffer (SECTOR_BUFFER (ReqSector), ReqData); + } +#else + /*cache_clear( PhysDMABuffer, 512 ); */ + copy_buffer(DMABuffer, ReqData); +#endif + } + if (++ReqCnt < CURRENT->current_nr_sectors) { + /* read next sector */ + setup_req_params(SelectedDrive); + do_fd_action(SelectedDrive); + } else { + /* all sectors finished */ + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + end_request(1); + redo_fd_request(); + } + return; + + err_end: +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + + fd_error(); +} + + +static void fd_times_out(unsigned long dummy) +{ + SET_IRQ_HANDLER(NULL); + /* If the timeout occured while the readtrack_check timer was + * active, we need to cancel it, else bad things will happen */ + del_timer( &readtrack_timer ); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); + udelay(25); + + printk("floppy timeout\n"); + STOP_TIMEOUT(); /* hmm - should we do this ? */ + fd_error(); +} + + +/* The (noop) seek operation here is needed to make the WP bit in the + * FDC1772 status register accessible for check_change. If the last disk + * operation would have been a RDSEC, this bit would always read as 0 + * no matter what :-( To save time, the seek goes to the track we're + * already on. + */ + +static void finish_fdc(void) +{ + /* DAG - just try without this dummy seek! */ + finish_fdc_done(0); + return; + + if (!NeedSeek) { + finish_fdc_done(0); + } else { + DPRINT(("finish_fdc: dummy seek started\n")); + FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track); + SET_IRQ_HANDLER(finish_fdc_done); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); + MotorOn = 1; + START_TIMEOUT(); + /* we must wait for the IRQ here, because the ST-DMA is + * released immediatly afterwards and the interrupt may be + * delivered to the wrong driver. + */ + } +} + + +static void finish_fdc_done(int dummy) +{ + unsigned long flags; + + DPRINT(("finish_fdc_done entered\n")); + STOP_TIMEOUT(); + NeedSeek = 0; + + if ((timer_active & (1 << FLOPPY_TIMER)) && + timer_table[FLOPPY_TIMER].expires < jiffies + 5) + /* If the check for a disk change is done too early after this + * last seek command, the WP bit still reads wrong :-(( + */ + timer_table[FLOPPY_TIMER].expires = jiffies + 5; + else { + /* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ + }; + del_timer(&motor_off_timer); + START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); + + save_flags(flags); + cli(); + /* stdma_release(); - not sure if I should do something DAG */ + fdc_busy = 0; + wake_up(&fdc_wait); + restore_flags(flags); + + DPRINT(("finish_fdc() finished\n")); +} + + +/* Prevent "aliased" accesses. */ +static fd_ref[4] = +{0, 0, 0, 0}; +static fd_device[4] = +{0, 0, 0, 0}; + +/* + * Current device number. Taken either from the block header or from the + * format request descriptor. + */ +#define CURRENT_DEVICE (CURRENT->rq_dev) + +/* Current error count. */ +#define CURRENT_ERRORS (CURRENT->errors) + + +/* dummy for blk.h */ +static void floppy_off(unsigned int nr) +{ +} + + +/* On the old arcs write protect depends on the particular model + of machine. On the A310, R140, and A440 there is a disc changed + detect, however on the A4x0/1 range there is not. There + is nothing to tell you which machine your on. + At the moment I'm just marking changed always. I've + left the Atari's 'change on write protect change' code in this + part (but nothing sets it). + RiscOS apparently checks the disc serial number etc. to detect changes + - but if it sees a disc change line go high (?) it flips to using + it. Well maybe I'll add that in the future (!?) +*/ +static int check_floppy_change(dev_t dev) +{ + unsigned int drive = (dev & 0x03); + + if (MAJOR(dev) != MAJOR_NR) { + printk("floppy_changed: not a floppy\n"); + return 0; + } + if (test_bit(drive, &fake_change)) { + /* simulated change (e.g. after formatting) */ + return 1; + } + if (test_bit(drive, &changed_floppies)) { + /* surely changed (the WP signal changed at least once) */ + return 1; + } + if (unit[drive].wpstat) { + /* WP is on -> could be changed: to be sure, buffers should be + * invalidated... + */ + return 1; + } + return 1; /* DAG - was 0 */ +} + +static int floppy_revalidate(dev_t dev) +{ + int drive = dev & 3; + + if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) + || unit[drive].disktype == 0) { +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + clear_bit(drive, &fake_change); + clear_bit(drive, &changed_floppies); + unit[drive].disktype = 0; + } + return 0; +} + +static __inline__ void copy_buffer(void *from, void *to) +{ + ulong *p1 = (ulong *) from, *p2 = (ulong *) to; + int cnt; + + for (cnt = 512 / 4; cnt; cnt--) + *p2++ = *p1++; +} + + +/* This sets up the global variables describing the current request. */ + +static void setup_req_params(int drive) +{ + int block = ReqBlock + ReqCnt; + + ReqTrack = block / unit[drive].disktype->spt; + ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1; + ReqSide = ReqTrack & 1; + ReqTrack >>= 1; + ReqData = ReqBuffer + 512 * ReqCnt; + +#ifdef TRACKBUFFER + read_track = (ReqCmd == READ && CURRENT_ERRORS == 0); +#endif + + DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide, + ReqTrack, ReqSector, (unsigned long) ReqData)); +} + + +static void redo_fd_request(void) +{ + int device, drive, type; + struct archy_floppy_struct *floppy; + + DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n", + (unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0, + CURRENT ? CURRENT->sector : 0)); + + if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) + goto the_end; + + repeat: + + if (!CURRENT) + goto the_end; + + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + + if (CURRENT->bh) { + if (!buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); + } + device = MINOR(CURRENT_DEVICE); + drive = device & 3; + type = device >> 2; + floppy = &unit[drive]; + + if (!floppy->connected) { + /* drive not connected */ + printk("Unknown Device: fd%d\n", drive); + end_request(0); + goto repeat; + } + if (type == 0) { + if (!floppy->disktype) { + Probing = 1; + floppy->disktype = disk_type + NUM_DISK_TYPES - 1; + floppy_sizes[drive] = floppy->disktype->blocks >> 1; + floppy->autoprobe = 1; + } + } else { + /* user supplied disk type */ + --type; + if (type >= NUM_DISK_TYPES) { + printk("fd%d: invalid disk format", drive); + end_request(0); + goto repeat; + } + floppy->disktype = &disk_type[type]; + floppy_sizes[drive] = disk_type[type].blocks >> 1; + floppy->autoprobe = 0; + } + + if (CURRENT->sector + 1 > floppy->disktype->blocks) { + end_request(0); + goto repeat; + } + /* stop deselect timer */ + del_timer(&motor_off_timer); + + ReqCnt = 0; + ReqCmd = CURRENT->cmd; + ReqBlock = CURRENT->sector; + ReqBuffer = CURRENT->buffer; + setup_req_params(drive); + do_fd_action(drive); + + return; + + the_end: + finish_fdc(); +} + +static void fd1772_checkint(void) +{ + extern int fdc1772_bytestogo; + + /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/ + if (fdc1772_fdc_int_done) + floppy_irqconsequencehandler(); + if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0); + if (fdc_busy) { + queue_task(&fd1772_tq,&tq_immediate); + mark_bh(IMMEDIATE_BH); + }; +}; + +void do_fd_request(void) +{ + unsigned long flags; + + DPRINT(("do_fd_request for pid %d\n", current->pid)); + if (fdc_busy) return; + save_flags(flags); + cli(); + while (fdc_busy) + sleep_on(&fdc_wait); + fdc_busy = 1; + ENABLE_IRQ(); + restore_flags(flags); + + fdc1772_fdc_int_done = 0; + + redo_fd_request(); + + queue_task(&fd1772_tq,&tq_immediate); + mark_bh(IMMEDIATE_BH); +} + + +static int invalidate_drive(int rdev) +{ + /* invalidate the buffer track to force a reread */ +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + + set_bit(rdev & 3, &fake_change); + check_disk_change(rdev); + return 0; +} + +static int fd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) + + int drive, device; + + device = inode->i_rdev; + switch (cmd) { + RO_IOCTLS(inode->i_rdev, param); + } + drive = MINOR(device); + if (!IOCTL_ALLOWED) + return -EPERM; + switch (cmd) { + case FDFMTBEG: + return 0; + /* case FDC1772LRPRM: ??? DAG what does this do?? + unit[drive].disktype = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE; + return invalidate_drive (device); */ + case FDFMTEND: + case FDFLUSH: + return invalidate_drive(drive); + } + if (!suser()) + return -EPERM; + if (drive < 0 || drive > 3) + return -EINVAL; + switch (cmd) { + default: + return -EINVAL; + } + return 0; +} + + +/* Initialize the 'unit' variable for drive 'drive' */ + +static void fd_probe(int drive) +{ + unit[drive].connected = 0; + unit[drive].disktype = NULL; + + if (!fd_test_drive_present(drive)) + return; + + unit[drive].connected = 1; + unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */ + unit[drive].steprate = FDC1772STEP_6; + MotorOn = 1; /* from probe restore operation! */ +} + + +/* This function tests the physical presence of a floppy drive (not + * whether a disk is inserted). This is done by issuing a restore + * command, waiting max. 2 seconds (that should be enough to move the + * head across the whole disk) and looking at the state of the "TR00" + * signal. This should now be raised if there is a drive connected + * (and there is no hardware failure :-) Otherwise, the drive is + * declared absent. + */ + +static int fd_test_drive_present(int drive) +{ + unsigned long timeout; + unsigned char status; + int ok; + + printk("fd_test_drive_present %d\n", drive); + if (drive > 1) + return (0); + return (1); /* Simple hack for the moment - the autodetect doesn't seem to work on arc */ + fd_select_drive(drive); + + /* disable interrupt temporarily */ + DISABLE_IRQ(); + FDC1772_WRITE(FDC1772REG_TRACK, 0x00); /* was ff00 why? */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6); + + /*printk("fd_test_drive_present: Going into timeout loop\n"); */ + for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; jiffies < timeout;) { + /* What does this piece of atariism do? - query for an interrupt? */ + /* if (!(mfp.par_dt_reg & 0x20)) + break; */ + /* Well this is my nearest guess - quit when we get an FDC interrupt */ + if (IOC_FIQSTAT & 2) + break; + } + + /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */ + status = FDC1772_READ(FDC1772REG_STATUS); + ok = (status & FDC1772STAT_TR00) != 0; + + /*printk("fd_test_drive_present: ok=%d\n",ok); */ + /* force interrupt to abort restore operation (FDC1772 would try + * about 50 seconds!) */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); + udelay(500); + status = FDC1772_READ(FDC1772REG_STATUS); + udelay(20); + /*printk("fd_test_drive_present: just before OK code %d\n",ok); */ + + if (ok) { + /* dummy seek command to make WP bit accessible */ + FDC1772_WRITE(FDC1772REG_DATA, 0); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); + printk("fd_test_drive_present: just before wait for int\n"); + /* DAG: Guess means wait for interrupt */ + while (!(IOC_FIQSTAT & 2)); + printk("fd_test_drive_present: just after wait for int\n"); + status = FDC1772_READ(FDC1772REG_STATUS); + } + printk("fd_test_drive_present: just before ENABLE_IRQ\n"); + ENABLE_IRQ(); + printk("fd_test_drive_present: about to return\n"); + return (ok); +} + + +/* Look how many and which kind of drives are connected. If there are + * floppies, additionally start the disk-change and motor-off timers. + */ + +static void config_types(void) +{ + int drive, cnt = 0; + + printk("Probing floppy drive(s):\n"); + for (drive = 0; drive < FD_MAX_UNITS; drive++) { + fd_probe(drive); + if (unit[drive].connected) { + printk("fd%d\n", drive); + ++cnt; + } + } + + if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) { + /* If FDC1772 is still busy from probing, give it another FORCI + * command to abort the operation. If this isn't done, the FDC1772 + * will interrupt later and its IRQ line stays low, because + * the status register isn't read. And this will block any + * interrupts on this IRQ line :-( + */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); + udelay(500); + FDC1772_READ(FDC1772REG_STATUS); + udelay(20); + } + if (cnt > 0) { + START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); + if (cnt == 1) + fd_select_drive(0); + /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ + } +} + +/* + * floppy_open check for aliasing (/dev/fd0 can be the same as + * /dev/PS0 etc), and disallows simultaneous access to the same + * drive with different device numbers. + */ + +static int floppy_open(struct inode *inode, struct file *filp) +{ + int drive; + int old_dev; + + if (!filp) { + DPRINT(("Weird, open called with filp=0\n")); + return -EIO; + } + drive = MINOR(inode->i_rdev) & 3; + if ((MINOR(inode->i_rdev) >> 2) > NUM_DISK_TYPES) + return -ENXIO; + + old_dev = fd_device[drive]; + + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + + if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) + return -EBUSY; + + if (filp->f_flags & O_EXCL) + fd_ref[drive] = -1; + else + fd_ref[drive]++; + + fd_device[drive] = inode->i_rdev; + + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); + + /* Allow ioctls if we have write-permissions even if read-only open */ + if (filp->f_mode & 2 || permission(inode, 2) == 0) + filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; + + if (filp->f_flags & O_NDELAY) + return 0; + + if (filp->f_mode & 3) { + check_disk_change(inode->i_rdev); + if (filp->f_mode & 2) { + if (unit[drive].wpstat) { + floppy_release(inode, filp); + return -EROFS; + } + } + } + return 0; +} + + +static void floppy_release(struct inode *inode, struct file *filp) +{ + int drive; + + drive = inode->i_rdev & 3; + + if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) + /* if the file is mounted OR (writable now AND writable at open + time) Linus: Does this cover all cases? */ + block_fsync(inode, filp); + + if (fd_ref[drive] < 0) + fd_ref[drive] = 0; + else if (!fd_ref[drive]--) { + printk("floppy_release with fd_ref == 0"); + fd_ref[drive] = 0; + } +} + +static struct file_operations floppy_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + fd_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + check_floppy_change, /* media_change */ + floppy_revalidate, /* revalidate */ +}; + + +int floppy_init(void) +{ + int i; + + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk("Unable to get major %d for floppy\n", MAJOR_NR); + return 1; + } + + if (request_dma(FLOPPY_DMA, "fd1772")) { + printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA); + return 1; + }; + + if (request_dma(FIQ_FD1772, "fd1772 end")) { + printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772); + free_dma(FLOPPY_DMA); + return 1; + }; + enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */ + + /* initialize variables */ + SelectedDrive = -1; +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + + /* initialize check_change timer */ + timer_table[FLOPPY_TIMER].fn = check_change; + timer_active &= ~(1 << FLOPPY_TIMER); + + +#ifdef TRACKBUFFER + DMABuffer = (char *)kmalloc((MAX_SECTORS+1)*512,GFP_KERNEL); /* Atari uses 512 - I want to eventually cope with 1K sectors */ + TrackBuffer = DMABuffer + 512; +#else + /* Allocate memory for the DMAbuffer - on the Atari this takes it + out of some special memory... */ + DMABuffer = (char *) kmalloc(2048); /* Copes with pretty large sectors */ +#endif +#ifdef TRACKBUFFER + BufferDrive = BufferSide = BufferTrack = -1; +#endif + + for (i = 0; i < FD_MAX_UNITS; i++) { + unit[i].track = -1; + } + + for (i = 0; i < 256; i++) + if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_TYPES) + floppy_sizes[i] = disk_type[(i >> 2) - 1].blocks >> 1; + else + floppy_sizes[i] = MAX_DISK_SIZE; + + blk_size[MAJOR_NR] = floppy_sizes; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + + config_types(); + + return 0; +} + +/* Just a dummy at the moment */ +void floppy_setup(char *str, int *ints) +{ +} + +void floppy_eject(void) { +} diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/ide-ics.c linux/drivers/acorn/block/ide-ics.c --- v2.1.87/linux/drivers/acorn/block/ide-ics.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/block/ide-ics.c Mon Feb 16 14:26:56 1998 @@ -0,0 +1,271 @@ +/* + * linux/arch/arm/drivers/block/ide-ics.c + * + * Copyright (c) 1996,1997 Russell King. + * + * Changelog: + * 08-06-1996 RMK Created + * 12-09-1997 RMK Added interrupt enable/disable + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../../block/ide.h" + +/* + * Maximum number of interfaces per card + */ +#define MAX_IFS 2 + +#define ICS_IDENT_OFFSET 0x8a0 + +#define ICS_ARCIN_V5_INTROFFSET 0x001 +#define ICS_ARCIN_V5_IDEOFFSET 0xa00 +#define ICS_ARCIN_V5_IDEALTOFFSET 0xae0 +#define ICS_ARCIN_V5_IDESTEPPING 4 + +#define ICS_ARCIN_V6_IDEOFFSET_1 0x800 +#define ICS_ARCIN_V6_INTROFFSET_1 0x880 +#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x8e0 +#define ICS_ARCIN_V6_IDEOFFSET_2 0xc00 +#define ICS_ARCIN_V6_INTROFFSET_2 0xc80 +#define ICS_ARCIN_V6_IDEALTOFFSET_2 0xce0 +#define ICS_ARCIN_V6_IDESTEPPING 4 + +static const card_ids icside_cids[] = { + { MANU_ICS, PROD_ICS_IDE }, + { 0xffff, 0xffff } +}; + +typedef enum { + ics_if_unknown, + ics_if_arcin_v5, + ics_if_arcin_v6 +} iftype_t; + +static struct expansion_card *ec[MAX_ECARDS]; +static int result[MAX_ECARDS][MAX_IFS]; + + +/* ---------------- Version 5 PCB Support Functions --------------------- */ +/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + unsigned int memc_port = (unsigned int)ec->irq_data; + outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET); +} + +/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + unsigned int memc_port = (unsigned int)ec->irq_data; + inb (memc_port + ICS_ARCIN_V5_INTROFFSET); +} + +static const expansioncard_ops_t icside_ops_arcin_v5 = { + icside_irqenable_arcin_v5, + icside_irqdisable_arcin_v5, + NULL, + NULL +}; + + +/* ---------------- Version 6 PCB Support Functions --------------------- */ +/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); + outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); + inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +static const expansioncard_ops_t icside_ops_arcin_v6 = { + icside_irqenable_arcin_v6, + icside_irqdisable_arcin_v6, + NULL, + NULL +}; + + + +/* Prototype: icside_identifyif (struct expansion_card *ec) + * Purpose : identify IDE interface type + * Notes : checks the description string + */ +static iftype_t icside_identifyif (struct expansion_card *ec) +{ + unsigned int addr; + iftype_t iftype; + int id = 0; + + iftype = ics_if_unknown; + + addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET; + + id = inb (addr) & 1; + id |= (inb (addr + 1) & 1) << 1; + id |= (inb (addr + 2) & 1) << 2; + id |= (inb (addr + 3) & 1) << 3; + + switch (id) { + case 0: /* A3IN */ + printk ("icside: A3IN unsupported\n"); + break; + + case 1: /* A3USER */ + printk ("icside: A3USER unsupported\n"); + break; + + case 3: /* ARCIN V6 */ + printk ("icside: detected ARCIN V6 in slot %d\n", ec->slot_no); + iftype = ics_if_arcin_v6; + break; + + case 15:/* ARCIN V5 (no id) */ + printk ("icside: detected ARCIN V5 in slot %d\n", ec->slot_no); + iftype = ics_if_arcin_v5; + break; + + default:/* we don't know - complain very loudly */ + printk ("icside: ***********************************\n"); + printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id); + printk ("icside: ***********************************\n"); + printk ("icside: please report this to: linux@arm.uk.linux.org\n"); + printk ("icside: defaulting to ARCIN V5\n"); + iftype = ics_if_arcin_v5; + break; + } + + return iftype; +} + +/* Prototype: icside_register (struct expansion_card *ec) + * Purpose : register an ICS IDE card with the IDE driver + * Notes : we make sure that interrupts are disabled from the card + */ +static inline void icside_register (struct expansion_card *ec, int index) +{ + unsigned long port; + + result[index][0] = -1; + result[index][1] = -1; + + switch (icside_identifyif (ec)) { + case ics_if_unknown: + default: + printk ("** Warning: ICS IDE Interface unrecognised! **\n"); + break; + + case ics_if_arcin_v5: + port = ecard_address (ec, ECARD_MEMC, 0); + ec->irq_data = (void *)port; + ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; + + /* + * Be on the safe side - disable interrupts + */ + inb (port + ICS_ARCIN_V5_INTROFFSET); + result[index][0] = + ide_register_port (port + ICS_ARCIN_V5_IDEOFFSET, + port + ICS_ARCIN_V5_IDEALTOFFSET, + ICS_ARCIN_V5_IDESTEPPING, + ec->irq); + break; + + case ics_if_arcin_v6: + port = ecard_address (ec, ECARD_IOC, ECARD_FAST); + ec->irq_data = (void *)port; + ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; + + /* + * Be on the safe side - disable interrupts + */ + inb (port + ICS_ARCIN_V6_INTROFFSET_1); + inb (port + ICS_ARCIN_V6_INTROFFSET_2); + result[index][0] = + ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_1, + port + ICS_ARCIN_V6_IDEALTOFFSET_1, + ICS_ARCIN_V6_IDESTEPPING, + ec->irq); + result[index][1] = + ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_2, + port + ICS_ARCIN_V6_IDEALTOFFSET_2, + ICS_ARCIN_V6_IDESTEPPING, + ec->irq); + break; + } +} + +int icside_init (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + ec[i] = NULL; + + ecard_startfind (); + + for (i = 0; ; i++) { + if ((ec[i] = ecard_find (0, icside_cids)) == NULL) + break; + + ecard_claim (ec[i]); + icside_register (ec[i], i); + } + + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i] && result[i][0] < 0 && result[i][1] < 0) { + ecard_release (ec[i]); + ec[i] = NULL; + } + return 0; +} + +#ifdef MODULE +int init_module (void) +{ + return icside_init(); +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i]) { + if (result[i][0] >= 0) + ide_unregister (result[i][0]); + + if (result[i][1] >= 0) + ide_unregister (result[i][1]); + + ecard_release (ec[i]); + ec[i] = NULL; + } +} +#endif + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/ide-rapide.c linux/drivers/acorn/block/ide-rapide.c --- v2.1.87/linux/drivers/acorn/block/ide-rapide.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/block/ide-rapide.c Mon Feb 16 14:27:05 1998 @@ -0,0 +1,78 @@ +/* + * linux/arch/arm/drivers/block/ide-ics.c + * + * Copyright (c) 1996 Russell King. + * + * Changelog: + * 08-06-1996 RMK Created + */ + +#include +#include +#include +#include +#include + +#include "../../block/ide.h" + +static const card_ids rapide_cids[] = { + { 0xffff, 0xffff } +}; + +static struct expansion_card *ec[MAX_ECARDS]; +static int result[MAX_ECARDS]; + +static inline int rapide_register (struct expansion_card *ec) +{ + unsigned long port = ecard_address (ec, ECARD_MEMC, 0); + + return ide_register_port (port, port + 0x206, 4, ec->irq); +} + +int rapide_init (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + ec[i] = NULL; + + ecard_startfind (); + + for (i = 0; ; i++) { + if ((ec[i] = ecard_find (0, rapide_cids)) == NULL) + break; + + ecard_claim (ec[i]); + result[i] = rapide_register (ec[i]); + } + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i] && result[i] < 0) { + ecard_release (ec[i]); + ec[i] = NULL; + } + return 0; +} + +#ifdef MODULE + +int init_module (void) +{ + return rapide_init(); +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i]) { + unsigned long port; + port = ecard_address (ec[i], ECARD_MEMC, 0); + + ide_unregister_port (port, ec[i]->irq, 16); + ecard_release (ec[i]); + ec[i] = NULL; + } +} +#endif + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- v2.1.87/linux/drivers/acorn/block/mfmhd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/block/mfmhd.c Mon Jan 26 14:03:39 1998 @@ -0,0 +1,1549 @@ +/* + * linux/arch/arm/drivers/block/mfmhd.c + * + * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk) + * + * MFM hard drive code [experimental] + */ + +/* + * Change list: + * + * 3/2/96:DAG: Started a change list :-) + * Set the hardsect_size pointers up since we are running 256 byte + * sectors + * Added DMA code, put it into the rw_intr + * Moved RCAL out of generic interrupt code - don't want to do it + * while DMA'ing - its now in individual handlers. + * Took interrupt handlers off task queue lists and called + * directly - not sure of implications. + * + * 18/2/96:DAG: Well its reading OK I think, well enough for image file code + * to find the image file; but now I've discovered that I actually + * have to put some code in for image files. + * + * Added stuff for image files; seems to work, but I've not + * got a multisegment image file (I don't think!). + * Put in a hack (yep a real hack) for multiple cylinder reads. + * Not convinced its working. + * + * 5/4/96:DAG: Added asm/hardware.h and use IOC_ macros + * Rewrote dma code in mfm.S (again!) - now takes a word at a time + * from main RAM for speed; still doesn't feel speedy! + * + * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding + * things up, I've finally figured out why its so damn slow. + * Linux is only reading a block at a time, and so you never + * get more than 1K per disc revoloution ~=60K/second. + * + * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to + * join adjacent blocks together. Everything falls flat on its + * face. + * Four hours of debugging later; I hadn't realised that + * ll_rw_blk would be so generous as to join blocks whose + * results aren't going into consecutive buffers. + * + * OK; severe rehacking of mfm_rw_interrupt; now end_request's + * as soon as its DMA'd each request. Odd thing is that + * we are sometimes getting interrupts where we are not transferring + * any data; why? Is that what happens when you miss? I doubt + * it; are we too fast? No - its just at command ends. Got 240K/s + * better than before, but RiscOS hits 480K/s + * + * 25/6/96:RMK: Fixed init code to allow the MFM podule to work. Increased the + * number of errors for my Miniscribe drive (8425). + * + * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off + * - so in request_done just before it clears Busy it sends a + * check drive 0 - and the LEDs go off!!!! + * + * Added test for mainboard controller. - Removes need for separate + * define. + * + * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make + * IM drivers work. + * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO + * error.) + * + * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents + * gone :-( Hand modified afterwards. + * Took out last remains of the older image map system. + * + * 22/9/96:DAG: Changed mfm.S so it will carry on DMA'ing til; BSY is dropped + * Changed mfm_rw_intr so that it doesn't follow the error + * code until BSY is dropped. Nope - still broke. Problem + * may revolve around when it reads the results for the error + * number? + * + *16/11/96:DAG: Modified for 2.0.18; request_irq changed + * + *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system. + * Improved probe for onboard MFM chip - it was hanging on my A5k. + * Added autodetect CHS code such that we don't rely on the presence + * of an ADFS boot block. Added ioport resource manager calls so + * that we don't clash with already-running hardware (eg. RiscPC Ether + * card slots if someone tries this)! + * + * 17/1/97:RMK: Upgraded to 2.1 kernels. + */ + +/* + * Possible enhancements: + * Multi-thread the code so that it is possible that while one drive + * is seeking, the other one can be reading data/seeking as well. + * This would be a performance boost with dual drive systems. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MFM_DISK_MAJOR 13 +#undef XT_DISK_MAJOR +#define XT_DISK_MAJOR -1 +#define MAJOR_NR MFM_DISK_MAJOR +#include "blk.h" + +/* + * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc + */ +#ifndef HDIO_GETGEO +#define HDIO_GETGEO 0x301 +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; +#endif + + +/* + * Configuration section + * + * This is the maximum number of drives that we accept + */ +#define MFM_MAXDRIVES 2 +/* + * Linux I/O address of onboard MFM controller or 0 to disable this + */ +#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000) +/* + * Uncomment this to enable debugging in the MFM driver... + */ +#ifndef DEBUG +/*#define DEBUG */ +#endif +/* + * List of card types that we recognise + */ +static const card_ids mfm_cids[] = { + { MANU_ACORN, PROD_ACORN_MFM }, + { 0xffff, 0xffff } +}; +/* + * End of configuration + */ + + +/* + * This structure contains all information to do with a particular physical + * device. + */ +struct mfm_info { + unsigned char sectors; + unsigned char heads; + unsigned short cylinders; + unsigned short lowcurrent; + unsigned short precomp; +#define NO_TRACK -1 +#define NEED_1_RECAL -2 +#define NEED_2_RECAL -3 + int cylinder; + unsigned int access_count; + unsigned int busy; + struct { + char recal; + char report; + char abort; + } errors; +} mfm_info[MFM_MAXDRIVES]; + +#define MFM_DRV_INFO mfm_info[raw_cmd.dev] + +static struct hd_struct mfm[MFM_MAXDRIVES << 6]; +static int mfm_sizes[MFM_MAXDRIVES << 6]; +static int mfm_blocksizes[MFM_MAXDRIVES << 6]; +static int mfm_sectsizes[MFM_MAXDRIVES << 6]; +static struct wait_queue *mfm_wait_open = NULL; + +/* Stuff from the assembly routines */ +extern unsigned int hdc63463_baseaddress; /* Controller base address */ +extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */ +extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */ +extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */ +extern int hdc63463_dataleft; /* Number of bytes left to transfer */ + + + + +static int lastspecifieddrive; +static unsigned Busy; + +static unsigned int PartFragRead; /* The number of sectors which have been read + during a partial read split over two + cylinders. If 0 it means a partial + read did not occur. */ + +static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */ +static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */ + +static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */ +static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */ +static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know + where to take over */ +static char *Copy_buffer; + + +static void mfm_seek(void); +static void mfm_rerequest(void); +static void mfm_request(void); +static int mfm_reread_partitions(kdev_t dev); +static void mfm_specify (void); +static void issue_request(int dev, unsigned int block, unsigned int nsect, + struct request *req); + +#define mfm_init xd_init +#define mfm_setup xd_setup + +static unsigned int mfm_addr; /* Controller address */ +static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */ +static unsigned int mfm_irqenable; /* Podule IRQ enable location */ +static unsigned char mfm_irq; /* Interrupt number */ +static int mfm_drives = 0; /* drives available */ +static int mfm_status = 0; /* interrupt status */ +static int *errors; + +static struct rawcmd { + unsigned int dev; + unsigned int cylinder; + unsigned int head; + unsigned int sector; + unsigned int cmdtype; + unsigned int cmdcode; + unsigned char cmddata[16]; + unsigned int cmdlen; +} raw_cmd; + +static unsigned char result[16]; + +static struct cont { + void (*interrupt) (void); /* interrupt handler */ + void (*error) (void); /* error handler */ + void (*redo) (void); /* redo handler */ + void (*done) (int st); /* done handler */ +} *cont = NULL; + +static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0}; + +int number_mfm_drives = 1; + +/* ------------------------------------------------------------------------------------------ */ +/* + * From the HD63463 data sheet from Hitachi Ltd. + */ + +#define MFM_COMMAND (mfm_addr + 0) +#define MFM_DATAOUT (mfm_addr + 1) +#define MFM_STATUS (mfm_addr + 8) +#define MFM_DATAIN (mfm_addr + 9) + +#define CMD_ABT 0xF0 /* Abort */ +#define CMD_SPC 0xE8 /* Specify */ +#define CMD_TST 0xE0 /* Test */ +#define CMD_RCLB 0xC8 /* Recalibrate */ +#define CMD_SEK 0xC0 /* Seek */ +#define CMD_WFS 0xAB /* Write Format Skew */ +#define CMD_WFM 0xA3 /* Write Format */ +#define CMD_MTB 0x90 /* Memory to buffer */ +#define CMD_CMPD 0x88 /* Compare data */ +#define CMD_WD 0x87 /* Write data */ +#define CMD_RED 0x70 /* Read erroneous data */ +#define CMD_RIS 0x68 /* Read ID skew */ +#define CMD_FID 0x61 /* Find ID */ +#define CMD_RID 0x60 /* Read ID */ +#define CMD_BTM 0x50 /* Buffer to memory */ +#define CMD_CKD 0x48 /* Check data */ +#define CMD_RD 0x40 /* Read data */ +#define CMD_OPBW 0x38 /* Open buffer write */ +#define CMD_OPBR 0x30 /* Open buffer read */ +#define CMD_CKV 0x28 /* Check drive */ +#define CMD_CKE 0x20 /* Check ECC */ +#define CMD_POD 0x18 /* Polling disable */ +#define CMD_POL 0x10 /* Polling enable */ +#define CMD_RCAL 0x08 /* Recall */ + +#define STAT_BSY 0x8000 /* Busy */ +#define STAT_CPR 0x4000 /* Command Parameter Rejection */ +#define STAT_CED 0x2000 /* Command end */ +#define STAT_SED 0x1000 /* Seek end */ +#define STAT_DER 0x0800 /* Drive error */ +#define STAT_ABN 0x0400 /* Abnormal end */ +#define STAT_POL 0x0200 /* Polling */ + +/* ------------------------------------------------------------------------------------------ */ +#ifdef DEBUG +static void console_printf(const char *fmt,...) +{ + static char buffer[2048]; /* Arbitary! */ + extern void console_print(const char *); + unsigned long flags; + va_list ap; + + save_flags_cli(flags); + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + console_print(buffer); + va_end(fmt); + + restore_flags(flags); +}; /* console_printf */ + +#define DBG(x...) console_printf(x) +#else +#define DBG(x...) +#endif + +static void print_status(void) +{ + char *error; + static char *errors[] = { + "no error", + "command aborted", + "invalid command", + "parameter error", + "not initialised", + "rejected TEST", + "no useld", + "write fault", + "not ready", + "no scp", + "in seek", + "invalid NCA", + "invalid step rate", + "seek error", + "over run", + "invalid PHA", + "data field EEC error", + "data field CRC error", + "error corrected", + "data field fatal error", + "no data am", + "not hit", + "ID field CRC error", + "time over", + "no ID am", + "not writable" + }; + if (result[1] < 0x65) + error = errors[result[1] >> 2]; + else + error = "unknown"; + printk("("); + if (mfm_status & STAT_BSY) printk("BSY "); + if (mfm_status & STAT_CPR) printk("CPR "); + if (mfm_status & STAT_CED) printk("CED "); + if (mfm_status & STAT_SED) printk("SED "); + if (mfm_status & STAT_DER) printk("DER "); + if (mfm_status & STAT_ABN) printk("ABN "); + if (mfm_status & STAT_POL) printk("POL "); + printk(") SSB = %X (%s)\n", result[1], error); + +} + +/* ------------------------------------------------------------------------------------- */ + +static void issue_command(int command, unsigned char *cmdb, int len) +{ + int status; +#ifdef DEBUG + int i; + console_printf("issue_command: %02X: ", command); + for (i = 0; i < len; i++) + console_printf("%02X ", cmdb[i]); + console_printf("\n"); +#endif + + do { + status = inw(MFM_STATUS); + } while (status & (STAT_BSY | STAT_POL)); + DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8); + + if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) { + outw(CMD_RCAL, MFM_COMMAND); + while (inw(MFM_STATUS) & STAT_BSY); + } + status = inw(MFM_STATUS); + DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8); + + while (len > 0) { + outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT); + len -= 2; + cmdb += 2; + } + status = inw(MFM_STATUS); + DBG("issue_command: status before command issue: %02X:\n ", status >> 8); + + outw(command, MFM_COMMAND); + status = inw(MFM_STATUS); + DBG("issue_command: status immediatly after command issue: %02X:\n ", status >> 8); +} + +static void wait_for_completion(void) +{ + while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY); +} + +static void wait_for_command_end(void) +{ + int i; + + while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED)); + + for (i = 0; i < 16;) { + int in; + in = inw(MFM_DATAIN); + result[i++] = in >> 8; + result[i++] = in; + } + outw (CMD_RCAL, MFM_COMMAND); +} + +/* ------------------------------------------------------------------------------------- */ + +static void mfm_rw_intr(void) +{ + int old_status; /* Holds status on entry, we read to see if the command just finished */ +#ifdef DEBUG + console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft); + print_status(); +#endif + + /* Now don't handle the error until BSY drops */ + if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) { + /* Something has gone wrong - lets try that again */ + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + if (cont) { + DBG("mfm_rw_intr: DER/ABN err\n"); + cont->error(); + cont->redo(); + }; + return; + }; + + /* OK so what ever happend its not an error, now I reckon we are left between + a choice of command end or some data which is ready to be collected */ + /* I think we have to transfer data while the interrupt line is on and its + not any other type of interrupt */ + if (CURRENT->cmd == WRITE) { + extern void hdc63463_writedma(void); + if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { + printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n"); + if (cont) { + cont->error(); + cont->redo(); + }; + return; + }; + hdc63463_writedma(); + } else { + extern void hdc63463_readdma(void); + if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { + printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n"); + if (cont) { + cont->error(); + cont->redo(); + }; + return; + }; + DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr); + hdc63463_readdma(); + }; /* Read */ + + if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) { + /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */ + /* Ah - well looking at the status its just when we get command end; so no problem */ + /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n", + hdc63463_dataptr,Copy_buffer+256); + print_status(); */ + } else { + Sectors256LeftInCurrent--; + Copy_buffer += 256; + Copy_Sector++; + + /* We have come to the end of this request */ + if (!Sectors256LeftInCurrent) { + DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n", + CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors); + + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + SectorsLeftInRequest -= CURRENT->current_nr_sectors; + + end_request(1); + if (SectorsLeftInRequest) { + hdc63463_dataptr = (unsigned int) CURRENT->buffer; + Copy_buffer = CURRENT->buffer; + Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; + errors = &(CURRENT->errors); + /* These should match the present calculations of the next logical sector + on the device + Copy_Sector=CURRENT->sector*2; */ + + if (Copy_Sector != CURRENT->sector * 2) +#ifdef DEBUG + /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n", + Copy_Sector, CURRENT->sector * 2); +#else + printk("mfm: Copy_Sector mismatch! Eek!\n"); +#endif + }; /* CURRENT */ + }; /* Sectors256LeftInCurrent */ + }; + + old_status = mfm_status; + mfm_status = inw(MFM_STATUS); + if (mfm_status & (STAT_DER | STAT_ABN)) { + /* Something has gone wrong - lets try that again */ + if (cont) { + DBG("mfm_rw_intr: DER/ABN error\n"); + cont->error(); + cont->redo(); + }; + return; + }; + + /* If this code wasn't entered due to command_end but there is + now a command end we must read the command results out. If it was + entered like this then mfm_interrupt_handler would have done the + job. */ + if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) && + ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) { + int len = 0; + while (len < 16) { + int in; + in = inw(MFM_DATAIN); + result[len++] = in >> 8; + result[len++] = in; + }; + }; /* Result read */ + + /*console_printf ("mfm_rw_intr nearexit [%02X]\n", inb(mfm_IRQPollLoc)); */ + + /* If end of command move on */ + if (mfm_status & (STAT_CED)) { + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + /* End of command - trigger the next command */ + if (cont) { + cont->done(1); + } + DBG("mfm_rw_intr: returned from cont->done\n"); + } else { + /* Its going to generate another interrupt */ + SET_INTR(mfm_rw_intr); + }; +} + +static void mfm_setup_rw(void) +{ + DBG("setting up for rw...\n"); + + SET_INTR(mfm_rw_intr); + issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen); +} + +static void mfm_recal_intr(void) +{ +#ifdef DEBUG + console_printf("recal intr - status = "); + print_status(); +#endif + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + if (mfm_status & (STAT_DER | STAT_ABN)) { + printk("recal failed\n"); + MFM_DRV_INFO.cylinder = NEED_2_RECAL; + if (cont) { + cont->error(); + cont->redo(); + } + return; + } + /* Thats seek end - we are finished */ + if (mfm_status & STAT_SED) { + issue_command(CMD_POD, NULL, 0); + MFM_DRV_INFO.cylinder = 0; + mfm_seek(); + return; + } + /* Command end without seek end (see data sheet p.20) for parallel seek + - we have to send a POL command to wait for the seek */ + if (mfm_status & STAT_CED) { + SET_INTR(mfm_recal_intr); + issue_command(CMD_POL, NULL, 0); + return; + } + printk("recal: unknown status\n"); +} + +static void mfm_seek_intr(void) +{ +#ifdef DEBUG + console_printf("seek intr - status = "); + print_status(); +#endif + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + if (mfm_status & (STAT_DER | STAT_ABN)) { + printk("seek failed\n"); + MFM_DRV_INFO.cylinder = NEED_2_RECAL; + if (cont) { + cont->error(); + cont->redo(); + } + return; + } + if (mfm_status & STAT_SED) { + issue_command(CMD_POD, NULL, 0); + MFM_DRV_INFO.cylinder = raw_cmd.cylinder; + mfm_seek(); + return; + } + if (mfm_status & STAT_CED) { + SET_INTR(mfm_seek_intr); + issue_command(CMD_POL, NULL, 0); + return; + } + printk("seek: unknown status\n"); +} + +/* IDEA2 seems to work better - its what RiscOS sets my + * disc to - on its SECOND call to specify! + */ +#define IDEA2 +#ifndef IDEA2 +#define SPEC_SL 0x16 +#define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */ +#else +#define SPEC_SL 0x00 /* OM2 - SL - step pulse low */ +#define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */ +#endif + +static void mfm_setupspecify (int drive, unsigned char *cmdb) +{ + cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */ + cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */ + cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */ + cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */ + cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */ + cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */ + cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */ + cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */ + cmdb[8] = SPEC_SH; + cmdb[9] = 0x0a; /* gap length 1 */ + cmdb[10] = 0x0d; /* gap length 2 */ + cmdb[11] = 0x0c; /* gap length 3 */ + cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */ + cmdb[13] = mfm_info[drive].precomp - 1; + cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */ + cmdb[15] = mfm_info[drive].lowcurrent - 1; +} + +static void mfm_specify (void) +{ + unsigned char cmdb[16]; + + DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive); + mfm_setupspecify (raw_cmd.dev, cmdb); + + issue_command (CMD_SPC, cmdb, 16); + /* Ensure that we will do another specify if we move to the other drive */ + lastspecifieddrive = raw_cmd.dev; + wait_for_completion(); +} + +static void mfm_seek(void) +{ + unsigned char cmdb[4]; + + DBG("seeking...\n"); + if (MFM_DRV_INFO.cylinder < 0) { + SET_INTR(mfm_recal_intr); + DBG("mfm_seek: about to call specify\n"); + mfm_specify (); /* DAG added this */ + + cmdb[0] = raw_cmd.dev + 1; + cmdb[1] = 0; + + issue_command(CMD_RCLB, cmdb, 2); + return; + } + if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) { + cmdb[0] = raw_cmd.dev + 1; + cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */ + cmdb[2] = raw_cmd.cylinder >> 8; + cmdb[3] = raw_cmd.cylinder; + + SET_INTR(mfm_seek_intr); + issue_command(CMD_SEK, cmdb, 4); + } else + mfm_setup_rw(); +} + +static void mfm_initialise(void) +{ + DBG("init...\n"); + mfm_seek(); +} + +static void request_done(int uptodate) +{ + DBG("mfm:request_done\n"); + if (uptodate) { + unsigned char block[2] = {0, 0}; + + /* Apparently worked - lets check bytes left to DMA */ + if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) { + printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256); + end_request(0); + Busy = 0; + }; + /* Potentially this means that we've done; but we might be doing + a partial access, (over two cylinders) or we may have a number + of fragments in an image file. First lets deal with partial accesss + */ + if (PartFragRead) { + /* Yep - a partial access */ + + /* and issue the remainder */ + issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); + return; + } + + /* ah well - perhaps there is another fragment to go */ + + /* Increment pointers/counts to start of next fragment */ + if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n"); + + /* No - its the end of the line */ + /* end_request's should have happened at the end of sector DMAs */ + /* Turns Drive LEDs off - may slow it down? */ + if (!CURRENT) + issue_command(CMD_CKV, block, 2); + + Busy = 0; + DBG("request_done: About to mfm_request\n"); + /* Next one please */ + mfm_request(); /* Moved from mfm_rw_intr */ + DBG("request_done: returned from mfm_request\n"); + } else { + printk("mfm:request_done: update=0\n"); + end_request(0); + Busy = 0; + } +} + +static void error_handler(void) +{ + printk("error detected... status = "); + print_status(); + (*errors)++; + if (*errors > MFM_DRV_INFO.errors.abort) + cont->done(0); + if (*errors > MFM_DRV_INFO.errors.recal) + MFM_DRV_INFO.cylinder = NEED_2_RECAL; +} + +static void rw_interrupt(void) +{ + printk("rw_interrupt\n"); +} + +static struct cont rw_cont = +{ + rw_interrupt, + error_handler, + mfm_rerequest, + request_done +}; + +/* + * Actually gets round to issuing the request - note everything at this + * point is in 256 byte sectors not Linux 512 byte blocks + */ +static void issue_request(int dev, unsigned int block, unsigned int nsect, + struct request *req) +{ + int track, start_head, start_sector; + int sectors_to_next_cyl; + + dev >>= 6; + + track = block / mfm_info[dev].sectors; + start_sector = block % mfm_info[dev].sectors; + start_head = track % mfm_info[dev].heads; + + /* First get the number of whole tracks which are free before the next + track */ + sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors; + /* Then add in the number of sectors left on this track */ + sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector); + + DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track); + + raw_cmd.dev = dev; + raw_cmd.sector = start_sector; + raw_cmd.head = start_head; + raw_cmd.cylinder = track / mfm_info[dev].heads; + raw_cmd.cmdtype = CURRENT->cmd; + raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD; + raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ + raw_cmd.cmddata[1] = raw_cmd.head; + raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; + raw_cmd.cmddata[3] = raw_cmd.cylinder; + raw_cmd.cmddata[4] = raw_cmd.head; + raw_cmd.cmddata[5] = raw_cmd.sector; + + /* Was == and worked - how the heck??? */ + if (lastspecifieddrive != raw_cmd.dev) + mfm_specify (); + + if (nsect <= sectors_to_next_cyl) { + raw_cmd.cmddata[6] = nsect >> 8; + raw_cmd.cmddata[7] = nsect; + PartFragRead = 0; /* All in one */ + PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */ + } else { + raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8; + raw_cmd.cmddata[7] = sectors_to_next_cyl; + PartFragRead = sectors_to_next_cyl; /* only do this many this time */ + PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */ + PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl; + } + raw_cmd.cmdlen = 8; + + /* Setup DMA pointers */ + hdc63463_dataptr = (unsigned int) Copy_buffer; + hdc63463_dataleft = nsect * 256; /* Better way? */ + + DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", + raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ", + raw_cmd.cylinder, + raw_cmd.head, + raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); + + cont = &rw_cont; + errors = &(CURRENT->errors); +#if 0 + mfm_tq.routine = (void (*)(void *)) mfm_initialise; + queue_task(&mfm_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + mfm_initialise(); +#endif +} /* issue_request */ + +/* + * Called when an error has just happened - need to trick mfm_request + * into thinking we weren't busy + * + * Turn off ints - mfm_request expects them this way + */ +static void mfm_rerequest(void) +{ + DBG("mfm_rerequest\n"); + cli(); + Busy = 0; + mfm_request(); +} + +static void mfm_request(void) +{ + DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy); + + if (!CURRENT) { + DBG("mfm_request: Exited due to NULL Current 1\n"); + return; + } + + if (CURRENT->rq_status == RQ_INACTIVE) { + /* Hmm - seems to be happening a lot on 1.3.45 */ + /*console_printf("mfm_request: Exited due to INACTIVE Current\n"); */ + return; + } + + /* If we are still processing then return; we will get called again */ + if (Busy) { + /* Again seems to be common in 1.3.45 */ + /*DBG*/printk("mfm_request: Exiting due to busy\n"); + return; + } + Busy = 1; + + while (1) { + unsigned int dev, block, nsect; + + DBG("mfm_request: loop start\n"); + sti(); + + DBG("mfm_request: before INIT_REQUEST\n"); + + if (!CURRENT) { + printk("mfm_request: Exiting due to !CURRENT (pre)\n"); + CLEAR_INTR; + Busy = 0; + return; + }; + + INIT_REQUEST; + + DBG("mfm_request: before arg extraction\n"); + + dev = MINOR(CURRENT->rq_dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; +#ifdef DEBUG + /*if ((dev>>6)==1) */ console_printf("mfm_request: raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect); +#endif + if (dev >= (mfm_drives << 6) || + block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) { + if (dev >= (mfm_drives << 6)) + printk("mfm: bad minor number: device=%s\n", kdevname(CURRENT->rq_dev)); + else + printk("mfm%c: bad access: block=%d, count=%d, nr_sects=%ld\n", (dev >> 6)+'a', + block, nsect, mfm[dev].nr_sects); + printk("mfm: continue 1\n"); + end_request(0); + Busy = 0; + continue; + } + + block += mfm[dev].start_sect; + + /* DAG: Linux doesn't cope with this - even though it has an array telling + it the hardware block size - silly */ + block <<= 1; /* Now in 256 byte sectors */ + nsect <<= 1; /* Ditto */ + + SectorsLeftInRequest = nsect >> 1; + Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; + Copy_buffer = CURRENT->buffer; + Copy_Sector = CURRENT->sector << 1; + + DBG("mfm_request: block after offset=%d\n", block); + + if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) { + printk("unknown mfm-command %d\n", CURRENT->cmd); + end_request(0); + Busy = 0; + printk("mfm: continue 4\n"); + continue; + } + issue_request(dev, block, nsect, CURRENT); + + break; + } + DBG("mfm_request: Dropping out bottom\n"); +} + +static void do_mfm_request(void) +{ + DBG("do_mfm_request: about to mfm_request\n"); + mfm_request(); +} + +static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs) +{ + void (*handler) (void) = DEVICE_INTR; + + CLEAR_INTR; + + DBG("mfm_interrupt_handler (handler=0x%p)\n", handler); + + mfm_status = inw(MFM_STATUS); + + /* If CPR (Command Parameter Reject) and not busy it means that the command + has some return message to give us */ + if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) { + int len = 0; + while (len < 16) { + int in; + in = inw(MFM_DATAIN); + result[len++] = in >> 8; + result[len++] = in; + } + } + if (handler) { + handler(); + return; + } + outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + printk ("mfm: unexpected interrupt - status = "); + print_status (); + while (1); +} + + + + + +/* + * Tell the user about the drive if we decided it exists. Also, + * set the size of the drive. + */ +static void mfm_geometry (int drive) +{ + if (mfm_info[drive].cylinders) + printk ("mfm%c: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", 'a' + drive, + mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096, + mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors, + mfm_info[drive].lowcurrent, mfm_info[drive].precomp); + mfm[drive << 6].start_sect = 0; + mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2; +} + +#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT +/* + * Attempt to detect a drive and find its geometry. The drive has already been + * specified... + * + * We first recalibrate the disk, then try to probe sectors, heads and then + * cylinders. NOTE! the cylinder probe may break drives. The xd disk driver + * does something along these lines, so I assume that most drives are up to + * this mistreatment... + */ +static int mfm_detectdrive (int drive) +{ + unsigned int mingeo[3], maxgeo[3]; + unsigned int attribute, need_recal = 1; + unsigned char cmdb[8]; + + memset (mingeo, 0, sizeof (mingeo)); + maxgeo[0] = mfm_info[drive].sectors; + maxgeo[1] = mfm_info[drive].heads; + maxgeo[2] = mfm_info[drive].cylinders; + + cmdb[0] = drive + 1; + cmdb[6] = 0; + cmdb[7] = 1; + for (attribute = 0; attribute < 3; attribute++) { + while (mingeo[attribute] != maxgeo[attribute]) { + unsigned int variable; + + variable = (maxgeo[attribute] + mingeo[attribute]) >> 1; + cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0; + + if (need_recal) { + int tries = 5; + + do { + issue_command (CMD_RCLB, cmdb, 2); + wait_for_completion (); + wait_for_command_end (); + if (result[1] == 0x20) + break; + } while (result[1] && --tries); + if (result[1]) { + outw (CMD_RCAL, MFM_COMMAND); + return 0; + } + need_recal = 0; + } + + switch (attribute) { + case 0: + cmdb[5] = variable; + issue_command (CMD_CMPD, cmdb, 8); + break; + case 1: + cmdb[1] = variable; + cmdb[4] = variable; + issue_command (CMD_CMPD, cmdb, 8); + break; + case 2: + cmdb[2] = variable >> 8; + cmdb[3] = variable; + issue_command (CMD_SEK, cmdb, 4); + break; + } + wait_for_completion (); + wait_for_command_end (); + + switch (result[1]) { + case 0x00: + case 0x50: + mingeo[attribute] = variable + 1; + break; + + case 0x20: + outw (CMD_RCAL, MFM_COMMAND); + return 0; + + case 0x24: + need_recal = 1; + default: + maxgeo[attribute] = variable; + break; + } + } + } + mfm_info[drive].cylinders = mingeo[2]; + mfm_info[drive].lowcurrent = mingeo[2]; + mfm_info[drive].precomp = mingeo[2] / 2; + mfm_info[drive].heads = mingeo[1]; + mfm_info[drive].sectors = mingeo[0]; + outw (CMD_RCAL, MFM_COMMAND); + return 1; +} +#endif + +/* + * Initialise all drive information for this controller. + */ +static int mfm_initdrives(void) +{ + int drive; + + if (number_mfm_drives > MFM_MAXDRIVES) { + number_mfm_drives = MFM_MAXDRIVES; + printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n"); + } + + for (drive = 0; drive < number_mfm_drives; drive++) { + mfm_info[drive].lowcurrent = 1; + mfm_info[drive].precomp = 1; + mfm_info[drive].cylinder = -1; + mfm_info[drive].errors.recal = 0; + mfm_info[drive].errors.report = 0; + mfm_info[drive].errors.abort = 4; + +#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT + mfm_info[drive].cylinders = 1024; + mfm_info[drive].heads = 8; + mfm_info[drive].sectors = 64; + { + unsigned char cmdb[16]; + + mfm_setupspecify (drive, cmdb); + cmdb[1] &= ~0x81; + issue_command (CMD_SPC, cmdb, 16); + wait_for_completion (); + if (!mfm_detectdrive (drive)) { + mfm_info[drive].cylinders = 0; + mfm_info[drive].heads = 0; + mfm_info[drive].sectors = 0; + } + cmdb[0] = cmdb[1] = 0; + issue_command (CMD_CKV, cmdb, 2); + } +#else + mfm_info[drive].cylinders = 1; /* its going to have to figure it out from the partition info */ + mfm_info[drive].heads = 4; + mfm_info[drive].sectors = 32; +#endif + } + return number_mfm_drives; +} + + + +/* + * The 'front' end of the mfm driver follows... + */ + +static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +{ + struct hd_geometry *geo = (struct hd_geometry *) arg; + kdev_t dev; + int device, major, minor, err; + + if (!inode || !(dev = inode->i_rdev)) + return -EINVAL; + + major = MAJOR(dev); + minor = MINOR(dev); + + device = DEVICE_NR(MINOR(inode->i_rdev)), err; + if (device >= mfm_drives) + return -EINVAL; + + switch (cmd) { + case HDIO_GETGEO: + if (!arg) + return -EINVAL; + if (put_user (mfm_info[device].heads, &geo->heads)) + return -EFAULT; + if (put_user (mfm_info[device].sectors, &geo->sectors)) + return -EFAULT; + if (put_user (mfm_info[device].cylinders, &geo->cylinders)) + return -EFAULT; + if (put_user (mfm[minor].start_sect, &geo->start)) + return -EFAULT; + return 0; + + case BLKFLSBUF: + if (!suser()) + return -EACCES; + fsync_dev(dev); + invalidate_buffers(dev); + return 0; + + case BLKRASET: + if (!suser()) + return -EACCES; + if (arg > 0xff) + return -EINVAL; + read_ahead[major] = arg; + return 0; + + case BLKRAGET: + return put_user(read_ahead[major], (long *)arg); + + case BLKGETSIZE: + return put_user (mfm[minor].nr_sects, (long *)arg); + + case BLKFRASET: + if (!suser()) + return -EACCES; + max_readahead[major][minor] = arg; + return 0; + + case BLKFRAGET: + return put_user(max_readahead[major][minor], (long *) arg); + + case BLKSECTGET: + return put_user(max_sectors[major][minor], (long *) arg); + + case BLKRRPART: + if (!suser()) + return -EACCES; + return mfm_reread_partitions(dev); + + RO_IOCTLS(dev, arg); + + default: + return -EINVAL; + } +} + +static int mfm_open(struct inode *inode, struct file *file) +{ + int dev = DEVICE_NR(MINOR(inode->i_rdev)); + + if (dev >= mfm_drives) + return -ENODEV; + + MOD_INC_USE_COUNT; + while (mfm_info[dev].busy) + sleep_on (&mfm_wait_open); + + mfm_info[dev].access_count++; + return 0; +} + +/* + * Releasing a block device means we sync() it, so that it can safely + * be forgotten about... + */ +static int mfm_release(struct inode *inode, struct file *file) +{ + fsync_dev(inode->i_rdev); + mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This is to handle various kernel command line parameters + * specific to this driver. + */ +void mfm_setup(char *str, int *ints) +{ + return; +} + +/* + * Set the CHS from the ADFS boot block if it is present. This is not ideal + * since if there are any non-ADFS partitions on the disk, this won't work! + * Hence, I want to get rid of this... + */ +void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, + unsigned long discsize, unsigned int secsize) +{ + int drive = MINOR(dev) >> 6; + + if (mfm_info[drive].cylinders == 1) { + mfm_info[drive].sectors = secsptrack; + mfm_info[drive].heads = heads; + mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize); + + if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) { + printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6)); + + /* These values are fairly arbitary, but are there so that if your + * lucky you can pick apart your disc to find out what is going on - + * I reckon these figures won't hurt MOST drives + */ + mfm_info[drive].sectors = 32; + mfm_info[drive].heads = 4; + mfm_info[drive].cylinders = 512; + } + if (raw_cmd.dev == drive) + mfm_specify (); + mfm_geometry (drive); + } +} + +static void mfm_geninit (struct gendisk *gdev); + +static struct gendisk mfm_gendisk = { + MAJOR_NR, /* Major number */ + "mfm", /* Major name */ + 6, /* Bits to shift to get real from partition */ + 1 << 6, /* Number of partitions per real */ + MFM_MAXDRIVES, /* maximum number of real */ + mfm_geninit, /* init function */ + mfm, /* hd struct */ + mfm_sizes, /* block sizes */ + 0, /* number */ + (void *) mfm_info, /* internal */ + NULL /* next */ +}; + +static void mfm_geninit (struct gendisk *gdev) +{ + int i; + + mfm_drives = mfm_initdrives(); + + printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1 ? "" : "s"); + gdev->nr_real = mfm_drives; + + for (i = 0; i < mfm_drives; i++) + mfm_geometry (i); + + if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL)) + printk("mfm: unable to get IRQ%d\n", mfm_irq); + + if (mfm_irqenable) + outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */ + + for (i = 0; i < (MFM_MAXDRIVES << 6); i++) { + mfm_blocksizes[i] = 1024; /* Can't increase this - if you do all hell breaks loose */ + mfm_sectsizes[i] = 512; + } + blksize_size[MAJOR_NR] = mfm_blocksizes; + hardsect_size[MAJOR_NR] = mfm_sectsizes; +} + +static struct file_operations mfm_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + mfm_ioctl, /* ioctl */ + NULL, /* mmap */ + mfm_open, /* open */ + mfm_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + + +static struct expansion_card *ecs; + +/* + * See if there is a controller at the address presently at mfm_addr + * + * We check to see if the controller is busy - if it is, we abort it first, + * and check that the chip is no longer busy after at least 180 clock cycles. + * We then issue a command and check that the BSY or CPR bits are set. + */ +static int mfm_probecontroller (unsigned int mfm_addr) +{ + if (check_region (mfm_addr, 10)) + return 0; + + if (inw (MFM_STATUS) & STAT_BSY) { + outw (CMD_ABT, MFM_COMMAND); + udelay (50); + if (inw (MFM_STATUS) & STAT_BSY) + return 0; + } + + if (inw (MFM_STATUS) & STAT_CED) + outw (CMD_RCAL, MFM_COMMAND); + + outw (CMD_SEK, MFM_COMMAND); + + if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) { + unsigned int count = 2000; + while (inw (MFM_STATUS) & STAT_BSY) { + udelay (500); + if (!--count) + return 0; + } + + outw (CMD_RCAL, MFM_COMMAND); + } + return 1; +} + +/* + * Look for a MFM controller - first check the motherboard, then the podules + * The podules have an extra interrupt enable that needs to be played with + * + * The HDC is accessed at MEDIUM IOC speeds. + */ +int mfm_init (void) +{ + unsigned char irqmask; + + if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) { + printk("mfm_init: unable to get major number %d\n", MAJOR_NR); + return -1; + } + + if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) { + mfm_addr = ONBOARD_MFM_ADDRESS; + mfm_IRQPollLoc = IOC_IRQSTATB; + mfm_irqenable = 0; + mfm_irq = IRQ_HARDDISK; + irqmask = 0x08; /* IL3 pin */ + } else { + ecs = ecard_find(0, mfm_cids); + if (!ecs) { + mfm_addr = 0; + return -1; + } + + mfm_addr = ecard_address(ecs, ECARD_IOC, ECARD_MEDIUM) + 0x800; + mfm_IRQPollLoc = mfm_addr + 0x400; + mfm_irqenable = mfm_IRQPollLoc; + mfm_irq = ecs->irq; + irqmask = 0x08; + + ecard_claim(ecs); + } + + printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq); + request_region (mfm_addr, 10, "mfm"); + + /* Stuff for the assembler routines to get to */ + hdc63463_baseaddress = ioaddr(mfm_addr); + hdc63463_irqpolladdress = ioaddr(mfm_IRQPollLoc); + hdc63463_irqpollmask = irqmask; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB?) read ahread */ + +#ifndef MODULE + mfm_gendisk.next = gendisk_head; + gendisk_head = &mfm_gendisk; +#endif + + Busy = 0; + lastspecifieddrive = -1; + + return 0; +} + +/* + * This routine is called to flush all partitions and partition tables + * for a changed MFM disk, and then re-read the new partition table. + * If we are revalidating due to an ioctl, we have USAGE == 1. + */ +static int mfm_reread_partitions(kdev_t dev) +{ + unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev)); + unsigned long flags; + + save_flags_cli(flags); + if (mfm_info[target].busy || mfm_info[target].access_count > 1) { + restore_flags (flags); + return -EBUSY; + } + mfm_info[target].busy = 1; + restore_flags (flags); + + maxp = mfm_gendisk.max_p; + start = target << mfm_gendisk.minor_shift; + + for (i = maxp - 1; i >= 0; i--) { + int minor = start + i; + kdev_t devi = MKDEV(MAJOR_NR, minor); + struct super_block *sb = get_super(devi); + + sync_dev (devi); + if (sb) + invalidate_inodes (sb); + invalidate_buffers (devi); + + mfm_gendisk.part[minor].start_sect = 0; + mfm_gendisk.part[minor].nr_sects = 0; + } + + mfm_gendisk.part[start].nr_sects = mfm_info[target].heads * + mfm_info[target].cylinders * mfm_info[target].sectors / 2; + + resetup_one_dev(&mfm_gendisk, target); + + mfm_info[target].busy = 0; + wake_up (&mfm_wait_open); + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + int ret; + ret = mfm_init(); + if (!ret) + mfm_geninit(&mfm_gendisk); + return ret; +} + +void cleanup_module(void) +{ + if (ecs && mfm_irqenable) + outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */ + free_irq(mfm_irq, NULL); + unregister_blkdev(MAJOR_NR, "mfm"); + if (ecs) + ecard_release(ecs); + if (mfm_addr) + release_region(mfm_addr, 10); +} +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/Config.in linux/drivers/acorn/net/Config.in --- v2.1.87/linux/drivers/acorn/net/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/Config.in Mon Feb 16 15:49:47 1998 @@ -0,0 +1,7 @@ +# +# Acorn Network device configuration +# These are for Acorn's Expansion card network interfaces +# +tristate 'Acorn Ether1 (82586) support' CONFIG_ARM_ETHER1 +tristate 'Acorn/ANT Ether3 (NQ8005) support' CONFIG_ARM_ETHER3 +tristate 'I-cubed EtherH (NS8390) support' CONFIG_ARM_ETHERH diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/Makefile linux/drivers/acorn/net/Makefile --- v2.1.87/linux/drivers/acorn/net/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/Makefile Mon Feb 16 15:49:47 1998 @@ -0,0 +1,35 @@ +# File: drivers/acorn/net/Makefile +# +# Makefile for the Acorn ethercard network device drivers +# + +L_TARGET := acorn-net.a +L_OBJS := net-probe.o +M_OBJS := +MOD_LIST_NAME := ACORN_NET_MODULES + +ifeq ($(CONFIG_ARM_ETHER1),y) + L_OBJS += ether1.o +else + ifeq ($(CONFIG_ARM_ETHER1),m) + M_OBJS += ether1.o + endif +endif + +ifeq ($(CONFIG_ARM_ETHER3),y) + L_OBJS += ether3.o +else + ifeq ($(CONFIG_ARM_ETHER3),m) + M_OBJS += ether3.o + endif +endif + +ifeq ($(CONFIG_ARM_ETHERH),y) + L_OBJS += etherh.o +else + ifeq ($(CONFIG_ARM_ETHERH),m) + M_OBJS += etherh.o + endif +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.1.87/linux/drivers/acorn/net/ether1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/ether1.c Mon Feb 16 15:49:47 1998 @@ -0,0 +1,1241 @@ +/* + * linux/arch/arm/drivers/net/ether1.c + * + * (C) Copyright 1996,1997,1998 Russell King + * + * Acorn ether1 driver (82586 chip) + * for Acorn machines + */ + +/* + * We basically keep two queues in the cards memory - one for transmit + * and one for receive. Each has a head and a tail. The head is where + * we/the chip adds packets to be transmitted/received, and the tail + * is where the transmitter has got to/where the receiver will stop. + * Both of these queues are circular, and since the chip is running + * all the time, we have to be careful when we modify the pointers etc + * so that the buffer memory contents is valid all the time. + */ + +/* + * Change log: + * 1.00 RMK Released + * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now. + * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready + * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt. + * Should prevent lockup. + * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong. + * TDR now only reports failure when chip reports non-zero + * TDR time-distance. + * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define __ETHER1_C +#include "ether1.h" + +static unsigned int net_debug = NET_DEBUG; + +#define struct ether1_priv *priv = (struct ether1_priv *)dev->priv \ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv + +#define BUFFER_SIZE 0x10000 +#define TX_AREA_START 0x00100 +#define TX_AREA_END 0x05000 +#define RX_AREA_START 0x05000 +#define RX_AREA_END 0x0fc00 + +#define tx_done(dev) 0 +/* ------------------------------------------------------------------------- */ +static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n"; + +#define BUS_16 16 +#define BUS_8 8 + +static const card_ids ether1_cids[] = { + { MANU_ACORN, PROD_ACORN_ETHER1 }, + { 0xffff, 0xffff } +}; + +/* ------------------------------------------------------------------------- */ + +#define DISABLEIRQS 1 +#define NORMALIRQS 0 + +#define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs) +#define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs) + +static inline unsigned short ether1_inw_p (struct device *dev, int addr, int svflgs) +{ + unsigned long flags; + unsigned short ret; + + if (svflgs) { + save_flags_cli (flags); + } + outb (addr >> 12, REG_PAGE); + ret = inw (ETHER1_RAM + ((addr & 4095) >> 1)); + if (svflgs) + restore_flags (flags); + return ret; +} + +static inline void ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs) +{ + unsigned long flags; + + if (svflgs) { + save_flags_cli (flags); + } + outb (addr >> 12, REG_PAGE); + outw (val, ETHER1_RAM + ((addr & 4095) >> 1)); + if (svflgs) + restore_flags (flags); +} + +/* + * Some inline assembler to allow fast transfers on to/off of the card. + * Since this driver depends on some features presented by the ARM + * specific architecture, and that you can't configure this driver + * without specifiing ARM mode, this is not a problem. + * + * This routine is essentially an optimised memcpy from the card's + * onboard RAM to kernel memory. + */ + +static inline void *ether1_inswb (unsigned int addr, void *data, unsigned int len) +{ + int used; + + addr = IO_BASE + (addr << 2); + + __asm__ __volatile__( + "subs %3, %3, #2 + bmi 2f +1: ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bpl 1b +2: adds %3, %3, #1 + ldreqb %0, [%1] + streqb %0, [%2]" + : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) + : "1" (addr), "2" (data), "3" (len)); + + return data; +} + +static inline void *ether1_outswb (unsigned int addr, void *data, unsigned int len) +{ + int used; + + addr = IO_BASE + (addr << 2); + + __asm__ __volatile__( + "subs %3, %3, #2 + bmi 2f +1: ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bpl 1b +2: adds %3, %3, #1 + ldreqb %0, [%2] + streqb %0, [%1]" + : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) + : "1" (addr), "2" (data), "3" (len)); + + return data; +} + + +static void ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length) +{ + unsigned int page, thislen, offset; + offset = start & 4095; + + for (page = start >> 12; length; page++) + { + outb (page, REG_PAGE); + if (offset + length > 4096) + { + length -= 4096 - offset; + thislen = 4096 - offset; + } + else + { + thislen = length; + length = 0; + } + + data = ether1_outswb (ETHER1_RAM + (offset >> 1), data, thislen); + offset = 0; + } +} + +static void ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length) +{ + unsigned int page, thislen, offset; + + offset = start & 4095; + + for (page = start >> 12; length; page++) + { + outb (page, REG_PAGE); + if (offset + length > 4096) + { + length -= 4096 - offset; + thislen = 4096 - offset; + } + else + { + thislen = length; + length = 0; + } + + data = ether1_inswb (ETHER1_RAM + (offset >> 1), data, thislen); + offset = 0; + } +} + +static int ether1_ramtest (struct device *dev, unsigned char byte) +{ + unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); + int i, ret = BUFFER_SIZE; + int max_errors = 15; + int bad = -1; + int bad_start = 0; + + if (!buffer) + return 1; + + memset (buffer, byte, BUFFER_SIZE); + ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE); + memset (buffer, byte ^ 0xff, BUFFER_SIZE); + ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE); + + for (i = 0; i < BUFFER_SIZE; i++) + { + if (buffer[i] != byte) + { + if (max_errors >= 0 && bad != buffer[i]) + { + if (bad != -1) + printk ("\n"); + printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X", + dev->name, buffer[i], byte, i); + ret = -ENODEV; + max_errors --; + bad = buffer[i]; + bad_start = i; + } + } + else + { + if (bad != -1) + { + if (bad_start == i - 1) + printk ("\n"); + else + printk (" - 0x%04X\n", i - 1); + bad = -1; + } + } + } + + if (bad != -1) + printk (" - 0x%04X\n", BUFFER_SIZE); + kfree (buffer); + + return ret; +} + +static int ether1_reset (struct device *dev) +{ + outb (CTRL_RST|CTRL_ACK, REG_CONTROL); + return BUS_16; +} + +static int ether1_init_2 (struct device *dev) +{ + int i; + dev->mem_start = 0; + + i = ether1_ramtest (dev, 0x5a); + + if (i > 0) + i = ether1_ramtest (dev, 0x1e); + + if (i <= 0) + return -ENODEV; + + dev->mem_end = i; + return 0; +} + +/* + * These are the structures that are loaded into the ether RAM card to + * initialise the 82586 + */ + +/* at 0x0100 */ + +#define NOP_ADDR (TX_AREA_START) +#define NOP_SIZE (0x06) + +static nop_t init_nop = +{ + 0, + CMD_NOP, + NOP_ADDR +}; + +/* at 0x003a */ +#define TDR_ADDR (0x003a) +#define TDR_SIZE (0x08) +static tdr_t init_tdr = { + 0, + CMD_TDR | CMD_INTR, + NOP_ADDR, + 0 +}; + +/* at 0x002e */ +#define MC_ADDR (0x002e) +#define MC_SIZE (0x0c) +static mc_t init_mc = +{ + 0, + CMD_SETMULTICAST, + TDR_ADDR, + 0, + { { 0, } } +}; + +/* at 0x0022 */ +#define SA_ADDR (0x0022) +#define SA_SIZE (0x0c) +static sa_t init_sa = { + 0, + CMD_SETADDRESS, + MC_ADDR, + { 0, } +}; + +/* at 0x0010 */ +#define CFG_ADDR (0x0010) +#define CFG_SIZE (0x12) +static cfg_t init_cfg = { + 0, + CMD_CONFIG, + SA_ADDR, + 8, + 8, + CFG8_SRDY, + CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6), + 0, + 0x60, + 0, + CFG13_RETRY(15) | CFG13_SLOTH(2), + 0, +}; + +/* at 0x0000 */ +#define SCB_ADDR (0x0000) +#define SCB_SIZE (0x10) +static scb_t init_scb = { + 0, + SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX, + CFG_ADDR, + RX_AREA_START, + 0, + 0, + 0, + 0 +}; + +/* at 0xffee */ +#define ISCP_ADDR (0xffee) +#define ISCP_SIZE (0x08) +static iscp_t init_iscp = { + 1, + SCB_ADDR, + 0x0000, + 0x0000 +}; + +/* at 0xfff6 */ +#define SCP_ADDR (0xfff6) +#define SCP_SIZE (0x0a) +static scp_t init_scp = { + SCP_SY_16BBUS, + { 0, 0 }, + ISCP_ADDR, + 0 +}; + +#define RFD_SIZE (0x16) +static rfd_t init_rfd = { + 0, + 0, + 0, + 0, + { 0, }, + { 0, }, + 0 +}; + +#define RBD_SIZE (0x0a) +static rbd_t init_rbd = { + 0, + 0, + 0, + 0, + ETH_FRAME_LEN + 8 +}; + +#define TX_SIZE (0x08) +#define TBD_SIZE (0x08) + +static int ether1_init_for_open (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int i, status, addr, next, next2; + int failures = 0; + + outb (CTRL_RST|CTRL_ACK, REG_CONTROL); + + for (i = 0; i < 6; i++) + init_sa.sa_addr[i] = dev->dev_addr[i]; + + /* load data structures into ether1 RAM */ + ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE); + ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE); + ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE); + ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE); + ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE); + ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE); + ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE); + ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE); + + if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) + { + printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n", + dev->name); + return 1; + } + + /* + * setup circularly linked list of { rfd, rbd, buffer }, with + * all rfds circularly linked, rbds circularly linked. + * First rfd is linked to scp, first rbd is linked to first + * rfd. Last rbd has a suspend command. + */ + + addr = RX_AREA_START; + + do + { + next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; + next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; + + if (next2 >= RX_AREA_END) + { + next = RX_AREA_START; + init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND; + priv->rx_tail = addr; + } + else + init_rfd.rfd_command = 0; + if (addr == RX_AREA_START) + init_rfd.rfd_rbdoffset = addr + RFD_SIZE; + else + init_rfd.rfd_rbdoffset = 0; + init_rfd.rfd_link = next; + init_rbd.rbd_link = next + RFD_SIZE; + init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE; + + ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE); + ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE); + addr = next; + } + while (next2 < RX_AREA_END); + + priv->tx_link = NOP_ADDR; + priv->tx_head = NOP_ADDR + NOP_SIZE; + priv->tx_tail = TDR_ADDR; + priv->rx_head = RX_AREA_START; + + /* release reset & give 586 a prod */ + priv->resetting = 1; + priv->initialising = 1; + outb (CTRL_RST, REG_CONTROL); + outb (0, REG_CONTROL); + outb (CTRL_CA, REG_CONTROL); + + /* 586 should now unset iscp.busy */ + i = jiffies + HZ/2; + while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) + { + if (jiffies > i) + { + printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name); + return 1; + } + } + + /* check status of commands that we issued */ + i += HZ/10; + while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i<0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + failures += 1; + } + + i += HZ/10; + while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i<0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + failures += 1; + } + + i += HZ/10; + while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i < 0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + failures += 1; + } + + i += HZ; + while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i <0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + } + else + { + status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS); + if (status & TDR_XCVRPROB) + printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name); + else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) + { +#ifdef FANCY + printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name, + status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10, + (status & TDR_TIME) % 10); +#else + printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name, + status & TDR_SHORT ? "short" : "open", (status & TDR_TIME)); +#endif + } + } + + if (failures) + ether1_reset (dev); + return failures ? 1 : 0; +} + +static int ether1_probe1 (struct device *dev) +{ + static unsigned int version_printed = 0; + struct ether1_priv *priv; + int i; + + if (!dev->priv) + dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL); + + if (!dev->priv) + return 1; + + priv = (struct ether1_priv *)dev->priv; + memset (priv, 0, sizeof (struct ether1_priv)); + + if ((priv->bus_type = ether1_reset (dev)) == 0) + { + kfree (dev->priv); + return 1; + } + + if (net_debug && version_printed++ == 0) + printk (KERN_INFO "%s", version); + + printk (KERN_INFO "%s: ether1 found [%d, %04lx, %d]", dev->name, priv->bus_type, + dev->base_addr, dev->irq); + + request_region (dev->base_addr, 16, "ether1"); + request_region (dev->base_addr + 0x800, 4096, "ether1(ram)"); + + for (i = 0; i < 6; i++) + printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]); + + if (ether1_init_2 (dev)) + { + kfree (dev->priv); + return 1; + } + + dev->open = ether1_open; + dev->stop = ether1_close; + dev->hard_start_xmit= ether1_sendpacket; + dev->get_stats = ether1_getstats; + dev->set_multicast_list = ether1_setmulticastlist; + + /* Fill in the fields of the device structure with ethernet values */ + ether_setup (dev); + +#ifndef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) + { + kfree (dev->priv); + return -EAGAIN; + } +#endif + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void ether1_addr (struct device *dev) +{ + int i; + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb (IDPROM_ADDRESS + i); +} + +int ether1_probe (struct device *dev) +{ +#ifndef MODULE + struct expansion_card *ec; + + if (!dev) + return ENODEV; + + ecard_startfind (); + if ((ec = ecard_find (0, ether1_cids)) == NULL) + return ENODEV; + + dev->base_addr = ecard_address (ec, ECARD_IOC, ECARD_FAST); + dev->irq = ec->irq; + + ecard_claim (ec); +#endif + ether1_addr (dev); + + if (ether1_probe1 (dev) == 0) + return 0; + return ENODEV; +} + +/* ------------------------------------------------------------------------- */ + +static int ether1_txalloc (struct device *dev, int size) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int start, tail; + + size = (size + 1) & ~1; + tail = priv->tx_tail; + + if (priv->tx_head + size > TX_AREA_END) + { + if (tail > priv->tx_head) + return -1; + start = TX_AREA_START; + if (start + size > tail) + return -1; + priv->tx_head = start + size; + } + else + { + if (priv->tx_head < tail && (priv->tx_head + size) > tail) + return -1; + start = priv->tx_head; + priv->tx_head += size; + } + return start; +} + +static void ether1_restart (struct device *dev, char *reason) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + priv->stats.tx_errors ++; + + if (reason) + printk (KERN_WARNING "%s: %s - resetting device\n", dev->name, reason); + else + printk (" - resetting device\n"); + + ether1_reset (dev); + + dev->start = 0; + dev->tbusy = 0; + + if (ether1_init_for_open (dev)) + printk (KERN_ERR "%s: unable to restart interface\n", dev->name); + + dev->start = 1; +} + +static int ether1_open (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; +#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) + return -EAGAIN; +#endif + MOD_INC_USE_COUNT; + + memset (&priv->stats, 0, sizeof (struct enet_statistics)); + + if (ether1_init_for_open (dev)) + { +#ifdef CLAIM_IRQ_AT_OPEN + free_irq (dev->irq, dev); +#endif + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + return 0; +} + +static int ether1_sendpacket (struct sk_buff *skb, struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + + if (priv->restart) + ether1_restart (dev, NULL); + + if (dev->tbusy) + { + /* + * If we get here, some higher level has decided that we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 5) + return 1; + + /* Try to restart the adapter. */ + ether1_restart (dev, "transmit timeout, network cable problem?"); + dev->trans_start = jiffies; + } + + /* + * Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + + if (test_and_set_bit (0, (void *)&dev->tbusy) != 0) + printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name); + else + { + int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; + unsigned long flags; + tx_t tx; + tbd_t tbd; + nop_t nop; + + /* + * insert packet followed by a nop + */ + txaddr = ether1_txalloc (dev, TX_SIZE); + tbdaddr = ether1_txalloc (dev, TBD_SIZE); + dataddr = ether1_txalloc (dev, len); + nopaddr = ether1_txalloc (dev, NOP_SIZE); + + tx.tx_status = 0; + tx.tx_command = CMD_TX | CMD_INTR; + tx.tx_link = nopaddr; + tx.tx_tbdoffset = tbdaddr; + tbd.tbd_opts = TBD_EOL | len; + tbd.tbd_link = I82586_NULL; + tbd.tbd_bufl = dataddr; + tbd.tbd_bufh = 0; + nop.nop_status = 0; + nop.nop_command = CMD_NOP; + nop.nop_link = nopaddr; + + save_flags_cli (flags); + ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); + ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); + ether1_writebuffer (dev, skb->data, dataddr, len); + ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); + tmp = priv->tx_link; + priv->tx_link = nopaddr; + + /* now reset the previous nop pointer */ + ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); + + restore_flags (flags); + + /* handle transmit */ + dev->trans_start = jiffies; + + /* check to see if we have room for a full sized ether frame */ + tmp = priv->tx_head; + tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); + priv->tx_head = tmp; + if (tst != -1) + dev->tbusy = 0; + } + dev_kfree_skb (skb, FREE_WRITE); + + return 0; +} + +static void ether1_xmit_done (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + nop_t nop; + int caddr, tst; + + caddr = priv->tx_tail; + +again: + ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); + + switch (nop.nop_command & CMD_MASK) + { + case CMD_TDR: + /* special case */ + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) + { + ether1_outw (dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, + scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + } + priv->tx_tail = NOP_ADDR; + return; + + case CMD_NOP: + if (nop.nop_link == caddr) + { + if (priv->initialising == 0) + printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name); + else + priv->initialising = 0; + return; + } + if (caddr == nop.nop_link) + return; + caddr = nop.nop_link; + goto again; + + case CMD_TX: + if (nop.nop_status & STAT_COMPLETE) + break; + printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name); + priv->restart = 1; + return; + + default: + printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name, + nop.nop_command & CMD_MASK, caddr); + priv->restart = 1; + return; + } + + while (nop.nop_status & STAT_COMPLETE) + { + if (nop.nop_status & STAT_OK) + { + priv->stats.tx_packets ++; + priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS); + } + else + { + priv->stats.tx_errors ++; + if (nop.nop_status & STAT_COLLAFTERTX) + priv->stats.collisions ++; + if (nop.nop_status & STAT_NOCARRIER) + priv->stats.tx_carrier_errors ++; + if (nop.nop_status & STAT_TXLOSTCTS) + printk (KERN_WARNING "%s: cts lost\n", dev->name); + if (nop.nop_status & STAT_TXSLOWDMA) + priv->stats.tx_fifo_errors ++; + if (nop.nop_status & STAT_COLLEXCESSIVE) + priv->stats.collisions += 16; + } + if (nop.nop_link == caddr) + { + printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name); + break; + } + + caddr = nop.nop_link; + ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); + if ((nop.nop_command & CMD_MASK) != CMD_NOP) + { + printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name); + break; + } + + if (caddr == nop.nop_link) + break; + + caddr = nop.nop_link; + ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); + if ((nop.nop_command & CMD_MASK) != CMD_TX) + { + printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name); + break; + } + } + priv->tx_tail = caddr; + + caddr = priv->tx_head; + tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); + priv->tx_head = caddr; + if (tst != -1) + dev->tbusy = 0; + + mark_bh (NET_BH); +} + +static void ether1_recv_done (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int status; + int nexttail, rbdaddr; + rbd_t rbd; + + do + { + status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS); + if ((status & RFD_COMPLETE) == 0) + break; + + rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS); + ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE); + + if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) + { + int length = rbd.rbd_status & RBD_ACNT; + struct sk_buff *skb; + + length = (length + 1) & ~1; + skb = dev_alloc_skb (length + 2); + + if (skb) + { + skb->dev = dev; + skb_reserve (skb, 2); + + ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length); + + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); + priv->stats.rx_packets ++; + } + else + priv->stats.rx_dropped ++; + } + else + { + printk (KERN_WARNING "%s: %s\n", dev->name, + (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid"); + priv->stats.rx_dropped ++; + } + + nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS); + /* nexttail should be rx_head */ + if (nexttail != priv->rx_head) + printk (KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n", + dev->name, nexttail, priv->rx_head); + ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS); + ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS); + ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status, NORMALIRQS); + ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS); + + priv->rx_tail = nexttail; + priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS); + } + while (1); +} + +static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int status; + + dev->interrupt = 1; + + status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); + + if (status) + { + ether1_outw (dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX), + SCB_ADDR, scb_t, scb_command, NORMALIRQS); + outb (CTRL_CA | CTRL_ACK, REG_CONTROL); + if (status & SCB_STCX) + ether1_xmit_done (dev); + if (status & SCB_STCNA) + { + if (priv->resetting == 0) + printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name); + else + priv->resetting += 1; + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) + { + ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + } + if (priv->resetting == 2) + priv->resetting = 0; + } + if (status & SCB_STFR) + ether1_recv_done (dev); + + if (status & SCB_STRNR) + { + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) + { + printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name); + ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + priv->stats.rx_dropped ++; /* we suspended due to lack of buffer space */ + } + else + printk (KERN_WARNING "%s: RU went not ready: %04X\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS)); + printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,NORMALIRQS)); + } + } + else + outb (CTRL_ACK, REG_CONTROL); + + dev->interrupt = 0; +} + +static int ether1_close (struct device *dev) +{ +#ifdef CLAIM_IRQ_AT_OPEN + free_irq (dev->irq, dev); +#endif + + ether1_reset (dev); + dev->start = 0; + dev->tbusy = 0; + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics *ether1_getstats (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + return &priv->stats; +} + + +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets. + * num_addrs == 0 Normal mode, clear multicast list. + * num_addrs > 0 Multicast mode, receive normal and MC packets, and do + * best-effort filtering. + */ + +static void ether1_setmulticastlist (struct device *dev) +{ +} + +/* ------------------------------------------------------------------------- */ + +#ifdef MODULE + +static char ethernames[MAX_ECARDS][9]; +static struct device *my_ethers[MAX_ECARDS]; +static struct expansion_card *ec[MAX_ECARDS]; + +int init_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + { + my_ethers[i] = NULL; + ec[i] = NULL; + strcpy (ethernames[i], " "); + } + + i = 0; + + ecard_startfind(); + + do + { + if ((ec[i] = ecard_find(0, ether1_cids)) == NULL) + break; + + my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); + memset (my_ethers[i], 0, sizeof (struct device)); + + my_ethers[i]->irq = ec[i]->irq; + my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST); + my_ethers[i]->init = ether1_probe; + my_ethers[i]->name = ethernames[i]; + + ecard_claim (ec[i]); + + if (register_netdev (my_ethers[i]) != 0) + { + for (i = 0; i < 4; i++) + { + if (my_ethers[i]) + { + kfree (my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) + { + ecard_release (ec[i]); + ec[i] = NULL; + } + } + return -EIO; + } + i++; + } + while (i < MAX_ECARDS); + + return i != 0 ? 0 : -ENODEV; +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + { + if (my_ethers[i]) + { + unregister_netdev (my_ethers[i]); + release_region (my_ethers[i]->base_addr, 16); + release_region (my_ethers[i]->base_addr + 0x800, 4096); +#ifndef CLAIM_IRQ_AT_OPEN + free_irq (my_ethers[i]->irq, my_ethers[i]); +#endif + my_ethers[i] = NULL; + } + if (ec[i]) + { + ecard_release (ec[i]); + ec[i] = NULL; + } + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/ether1.h linux/drivers/acorn/net/ether1.h --- v2.1.87/linux/drivers/acorn/net/ether1.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/ether1.h Mon Feb 16 15:49:47 1998 @@ -0,0 +1,281 @@ +/* + * linux/arch/arm/drivers/net/ether1.h + * + * network driver for Acorn Ether1 cards. + * + * (c) 1996 Russell King + */ + +#ifndef _LINUX_ether1_H +#define _LINUX_ether1_H + +#ifdef __ETHER1_C +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* Page register */ +#define REG_PAGE (dev->base_addr + 0x00) + +/* Control register */ +#define REG_CONTROL (dev->base_addr + 0x01) +#define CTRL_RST 0x01 +#define CTRL_LOOPBACK 0x02 +#define CTRL_CA 0x04 +#define CTRL_ACK 0x08 + +#define ETHER1_RAM (dev->base_addr + 0x800) + +/* HW address */ +#define IDPROM_ADDRESS (dev->base_addr + 0x09) + +struct ether1_priv { + struct enet_statistics stats; + unsigned int tx_link; + unsigned int tx_head; + volatile unsigned int tx_tail; + volatile unsigned int rx_head; + volatile unsigned int rx_tail; + unsigned char bus_type; + unsigned char resetting; + unsigned char initialising : 1; + unsigned char restart : 1; +}; + +static int ether1_open (struct device *dev); +static int ether1_sendpacket (struct sk_buff *skb, struct device *dev); +static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static int ether1_close (struct device *dev); +static struct enet_statistics *ether1_getstats (struct device *dev); +static void ether1_setmulticastlist (struct device *dev); + +#define I82586_NULL (-1) + +typedef struct { /* tdr */ + unsigned short tdr_status; + unsigned short tdr_command; + unsigned short tdr_link; + unsigned short tdr_result; +#define TDR_TIME (0x7ff) +#define TDR_SHORT (1 << 12) +#define TDR_OPEN (1 << 13) +#define TDR_XCVRPROB (1 << 14) +#define TDR_LNKOK (1 << 15) +} tdr_t; + +typedef struct { /* transmit */ + unsigned short tx_status; + unsigned short tx_command; + unsigned short tx_link; + unsigned short tx_tbdoffset; +} tx_t; + +typedef struct { /* tbd */ + unsigned short tbd_opts; +#define TBD_CNT (0x3fff) +#define TBD_EOL (1 << 15) + unsigned short tbd_link; + unsigned short tbd_bufl; + unsigned short tbd_bufh; +} tbd_t; + +typedef struct { /* rfd */ + unsigned short rfd_status; +#define RFD_NOEOF (1 << 6) +#define RFD_FRAMESHORT (1 << 7) +#define RFD_DMAOVRN (1 << 8) +#define RFD_NORESOURCES (1 << 9) +#define RFD_ALIGNERROR (1 << 10) +#define RFD_CRCERROR (1 << 11) +#define RFD_OK (1 << 13) +#define RFD_FDCONSUMED (1 << 14) +#define RFD_COMPLETE (1 << 15) + unsigned short rfd_command; +#define RFD_CMDSUSPEND (1 << 14) +#define RFD_CMDEL (1 << 15) + unsigned short rfd_link; + unsigned short rfd_rbdoffset; + unsigned char rfd_dest[6]; + unsigned char rfd_src[6]; + unsigned short rfd_len; +} rfd_t; + +typedef struct { /* rbd */ + unsigned short rbd_status; +#define RBD_ACNT (0x3fff) +#define RBD_ACNTVALID (1 << 14) +#define RBD_EOF (1 << 15) + unsigned short rbd_link; + unsigned short rbd_bufl; + unsigned short rbd_bufh; + unsigned short rbd_len; +} rbd_t; + +typedef struct { /* nop */ + unsigned short nop_status; + unsigned short nop_command; + unsigned short nop_link; +} nop_t; + +typedef struct { /* set multicast */ + unsigned short mc_status; + unsigned short mc_command; + unsigned short mc_link; + unsigned short mc_cnt; + unsigned char mc_addrs[1][6]; +} mc_t; + +typedef struct { /* set address */ + unsigned short sa_status; + unsigned short sa_command; + unsigned short sa_link; + unsigned char sa_addr[6]; +} sa_t; + +typedef struct { /* config command */ + unsigned short cfg_status; + unsigned short cfg_command; + unsigned short cfg_link; + unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */ + unsigned char cfg_fifolim; /* FIFO threshold */ + unsigned char cfg_byte8; +#define CFG8_SRDY (1 << 6) +#define CFG8_SAVEBADF (1 << 7) + unsigned char cfg_byte9; +#define CFG9_ADDRLEN(x) (x) +#define CFG9_ADDRLENBUF (1 << 3) +#define CFG9_PREAMB2 (0 << 4) +#define CFG9_PREAMB4 (1 << 4) +#define CFG9_PREAMB8 (2 << 4) +#define CFG9_PREAMB16 (3 << 4) +#define CFG9_ILOOPBACK (1 << 6) +#define CFG9_ELOOPBACK (1 << 7) + unsigned char cfg_byte10; +#define CFG10_LINPRI(x) (x) +#define CFG10_ACR(x) (x << 4) +#define CFG10_BOFMET (1 << 7) + unsigned char cfg_ifs; + unsigned char cfg_slotl; + unsigned char cfg_byte13; +#define CFG13_SLOTH(x) (x) +#define CFG13_RETRY(x) (x << 4) + unsigned char cfg_byte14; +#define CFG14_PROMISC (1 << 0) +#define CFG14_DISBRD (1 << 1) +#define CFG14_MANCH (1 << 2) +#define CFG14_TNCRS (1 << 3) +#define CFG14_NOCRC (1 << 4) +#define CFG14_CRC16 (1 << 5) +#define CFG14_BTSTF (1 << 6) +#define CFG14_FLGPAD (1 << 7) + unsigned char cfg_byte15; +#define CFG15_CSTF(x) (x) +#define CFG15_ICSS (1 << 3) +#define CFG15_CDTF(x) (x << 4) +#define CFG15_ICDS (1 << 7) + unsigned short cfg_minfrmlen; +} cfg_t; + +typedef struct { /* scb */ + unsigned short scb_status; /* status of 82586 */ +#define SCB_STRXMASK (7 << 4) /* Receive unit status */ +#define SCB_STRXIDLE (0 << 4) /* Idle */ +#define SCB_STRXSUSP (1 << 4) /* Suspended */ +#define SCB_STRXNRES (2 << 4) /* No resources */ +#define SCB_STRXRDY (4 << 4) /* Ready */ +#define SCB_STCUMASK (7 << 8) /* Command unit status */ +#define SCB_STCUIDLE (0 << 8) /* Idle */ +#define SCB_STCUSUSP (1 << 8) /* Suspended */ +#define SCB_STCUACTV (2 << 8) /* Active */ +#define SCB_STRNR (1 << 12) /* Receive unit not ready */ +#define SCB_STCNA (1 << 13) /* Command unit not ready */ +#define SCB_STFR (1 << 14) /* Frame received */ +#define SCB_STCX (1 << 15) /* Command completed */ + unsigned short scb_command; /* Next command */ +#define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */ +#define SCB_CMDRXRESUME (2 << 4) /* Resume reception */ +#define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */ +#define SCB_CMDRXABORT (4 << 4) /* Abort reception */ +#define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */ +#define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */ +#define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */ +#define SCB_CMDCUCABORT (4 << 8) /* Abort execution */ +#define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */ +#define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */ +#define SCB_CMDACKFR (1 << 14) /* Ack Frame received */ +#define SCB_CMDACKCX (1 << 15) /* Ack Command complete */ + unsigned short scb_cbl_offset; /* Offset of first command unit */ + unsigned short scb_rfa_offset; /* Offset of first receive frame area */ + unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/ + unsigned short scb_aln_errors; /* Misaligned frames */ + unsigned short scb_rsc_errors; /* Frames lost due to no space */ + unsigned short scb_ovn_errors; /* Frames lost due to slow bus */ +} scb_t; + +typedef struct { /* iscp */ + unsigned short iscp_busy; /* set by CPU before CA */ + unsigned short iscp_offset; /* offset of SCB */ + unsigned short iscp_basel; /* base of SCB */ + unsigned short iscp_baseh; +} iscp_t; + + /* this address must be 0xfff6 */ +typedef struct { /* scp */ + unsigned short scp_sysbus; /* bus size */ +#define SCP_SY_16BBUS 0x00 +#define SCP_SY_8BBUS 0x01 + unsigned short scp_junk[2]; /* junk */ + unsigned short scp_iscpl; /* lower 16 bits of iscp */ + unsigned short scp_iscph; /* upper 16 bits of iscp */ +} scp_t; + +/* commands */ +#define CMD_NOP 0 +#define CMD_SETADDRESS 1 +#define CMD_CONFIG 2 +#define CMD_SETMULTICAST 3 +#define CMD_TX 4 +#define CMD_TDR 5 +#define CMD_DUMP 6 +#define CMD_DIAGNOSE 7 + +#define CMD_MASK 7 + +#define CMD_INTR (1 << 13) +#define CMD_SUSP (1 << 14) +#define CMD_EOL (1 << 15) + +#define STAT_COLLISIONS (15) +#define STAT_COLLEXCESSIVE (1 << 5) +#define STAT_COLLAFTERTX (1 << 6) +#define STAT_TXDEFERRED (1 << 7) +#define STAT_TXSLOWDMA (1 << 8) +#define STAT_TXLOSTCTS (1 << 9) +#define STAT_NOCARRIER (1 << 10) +#define STAT_FAIL (1 << 11) +#define STAT_ABORTED (1 << 12) +#define STAT_OK (1 << 13) +#define STAT_BUSY (1 << 14) +#define STAT_COMPLETE (1 << 15) +#endif +#endif + +/* + * Ether1 card definitions: + * + * FAST accesses: + * +0 Page register + * 16 pages + * +4 Control + * '1' = reset + * '2' = loopback + * '4' = CA + * '8' = int ack + * + * RAM at address + 0x2000 + * Pod. Prod id = 3 + * Words after ID block [base + 8 words] + * +0 pcb issue (0x0c and 0xf3 invalid) + * +1 - +6 eth hw address + */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c --- v2.1.87/linux/drivers/acorn/net/ether3.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/ether3.c Mon Feb 16 15:49:48 1998 @@ -0,0 +1,896 @@ +/* + * linux/drivers/net/ether3.c + * + * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card + * for Acorn machines + * + * By Russell King, with some suggestions from borris@ant.co.uk + * + * Changelog: + * 1.04 RMK 29/02/1996 Won't pass packets that are from our ethernet + * address up to the higher levels - they're + * silently ignored. I/F can now be put into + * multicast mode. Receiver routine optimised. + * 1.05 RMK 30/02/1996 Now claims interrupt at open when part of + * the kernel rather than when a module. + * 1.06 RMK 02/03/1996 Various code cleanups + * 1.07 RMK 13/10/1996 Optimised interrupt routine and transmit + * routines. + * 1.08 RMK 14/10/1996 Fixed problem with too many packets, + * prevented the kernel message about dropped + * packets appearing too many times a second. + * Now does not disable all IRQs, only the IRQ + * used by this card. + * 1.09 RMK 10/11/1996 Only enables TX irq when buffer space is low, + * but we still service the TX queue if we get a + * RX interrupt. + * 1.10 RMK 15/07/1997 Fixed autoprobing of NQ8004. + * 1.11 RMK 16/11/1997 Fixed autoprobing of NQ8005A. + * 1.12 RMK 31/12/1997 Removed reference to dev_tint for Linux 2.1. + * + * TODO: + * When we detect a fatal error on the interface, we should restart it. + */ + +static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.12\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ether3.h" + +#ifndef MODULE +#define CLAIM_IRQ_AT_OPEN +#endif + +static unsigned int net_debug = NET_DEBUG; + +static const card_ids ether3_cids[] = +{ + {MANU_ANT2, PROD_ANT_ETHER3}, + {MANU_ANT, PROD_ANT_ETHER3}, + {MANU_ANT, PROD_ANT_ETHERB}, /* trial - will etherb work? */ + {0xffff, 0xffff} +}; + +static void ether3_setmulticastlist(struct device *dev); +static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); +static void ether3_tx(struct device *dev, struct dev_priv *priv); + +extern int inswb(int reg, void *buffer, int len); +extern int outswb(int reg, void *buffer, int len); + +#define struct dev_priv *priv = (struct dev_priv *)dev->priv \ + struct dev_priv *priv = (struct dev_priv *)dev->priv + +#define BUS_16 2 +#define BUS_8 1 +#define BUS_UNKNOWN 0 + +/* + * I'm not sure what address we should default to if the internal one + * is corrupted... + */ + +unsigned char def_eth_addr[6] = +{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; + +/* --------------------------------------------------------------------------- */ + +typedef enum { + buffer_write, + buffer_read +} buffer_rw_t; + +static int ether3_setbuffer(struct device *dev, buffer_rw_t read, int start) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + int timeout = 1000; + + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); + outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND); + while ((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) { + if (!timeout--) { + printk(KERN_ERR "%s: setbuffer broken\n", dev->name); + priv->broken = 1; + return 1; + } + udelay(1); + } + if (read == buffer_read) { + outw(start, REG_DMAADDR); + outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND); + } else { + outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND); + outw(start, REG_DMAADDR); + } + return 0; +} + +/* + * write data to the buffer memory + */ +#define ether3_writebuffer(dev,data,length) \ + outswb (REG_BUFWIN, (data), (length)) + +#define ether3_writeword(dev,data) \ + outw ((data), REG_BUFWIN) + +#define ether3_writelong(dev,data) { \ + unsigned long reg_bufwin = REG_BUFWIN; \ + outw ((data), reg_bufwin); \ + outw ((data) >> 16, reg_bufwin); \ +} + +/* + * read data from the buffer memory + */ +#define ether3_readbuffer(dev,data,length) \ + inswb (REG_BUFWIN, (data), (length)) + +#define ether3_readword(dev) \ + inw (REG_BUFWIN) + +#define ether3_readlong(dev) \ + inw (REG_BUFWIN) | (inw (REG_BUFWIN) << 16) + +/* + * Switch LED off... + */ +static void ether3_ledoff(unsigned long data) +{ + struct device *dev = (struct device *) data; + struct dev_priv *priv = (struct dev_priv *) dev->priv; + outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); +} + +/* + * switch LED on... + */ +static inline void ether3_ledon(struct device *dev, struct dev_priv *priv) +{ + del_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */ + priv->timer.data = (unsigned long) dev; + priv->timer.function = ether3_ledoff; + add_timer(&priv->timer); + if (priv->regs.config2 & CFG2_CTRLO) + outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2); +} + +/* + * Read the ethernet address string from the on board rom. + * This is an ascii string!!! + */ +static void ether3_addr(char *addr, struct expansion_card *ec) +{ + struct in_chunk_dir cd; + char *s; + + if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { + int i; + for (i = 0; i < 6; i++) { + addr[i] = simple_strtoul(s + 1, &s, 0x10); + if (*s != (i == 5 ? ')' : ':')) + break; + } + if (i == 6) + return; + } + memcpy(addr, def_eth_addr, 6); +} + +/* --------------------------------------------------------------------------- */ + +static int ether3_ramtest(struct device *dev, unsigned char byte) +{ + unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); + int i, ret = 0; + int max_errors = 4; + int bad = -1; + + if (!buffer) + return 1; + + memset(buffer, byte, RX_END); + ether3_setbuffer(dev, buffer_write, 0); + ether3_writebuffer(dev, buffer, TX_END); + ether3_setbuffer(dev, buffer_write, RX_START); + ether3_writebuffer(dev, buffer + RX_START, RX_LEN); + memset(buffer, byte ^ 0xff, RX_END); + ether3_setbuffer(dev, buffer_read, 0); + ether3_readbuffer(dev, buffer, TX_END); + ether3_setbuffer(dev, buffer_read, RX_START); + ether3_readbuffer(dev, buffer + RX_START, RX_LEN); + + for (i = 0; i < RX_END; i++) { + if (buffer[i] != byte) { + if (max_errors > 0 && bad != buffer[i]) { + printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X", + dev->name, buffer[i], byte, i); + ret = 2; + max_errors--; + bad = i; + } + } else { + if (bad != -1) { + if (bad != i - 1) + printk(" - 0x%04X", i - 1); + printk("\n"); + bad = -1; + } + } + } + if (bad != -1) + printk(" - 0xffff\n"); + kfree(buffer); + + return ret; +} + +/* ------------------------------------------------------------------------------- */ + +static int ether3_init_2(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + int i; + + priv->regs.config1 = CFG1_RECVCOMPSTAT0 | CFG1_DMABURST8; + priv->regs.config2 = CFG2_CTRLO | CFG2_RECVCRC | CFG2_ERRENCRC; + priv->regs.command = 0; + /* + * Set up our hardware address + */ + outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], REG_BUFWIN); + + if (dev->flags & IFF_PROMISC) + priv->regs.config1 |= CFG1_RECVPROMISC; + else if (dev->flags & IFF_MULTICAST) + priv->regs.config1 |= CFG1_RECVSPECBRMULTI; + else + priv->regs.config1 |= CFG1_RECVSPECBROAD; + + /* + * There is a problem with the NQ8005 in that it occasionally losses the + * last two bytes. To get round this problem, we receive the CRC as well. + * That way, if we do loose the last two, then it doesn't matter + */ + outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); + outw((TX_END >> 8) - 1, REG_BUFWIN); + outw(priv->rx_head, REG_RECVPTR); + outw(0, REG_TRANSMITPTR); + outw(priv->rx_head >> 8, REG_RECVEND); + outw(priv->regs.config2, REG_CONFIG2); + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); + outw(priv->regs.command, REG_COMMAND); + + i = ether3_ramtest(dev, 0x5A); + if (i) + return i; + i = ether3_ramtest(dev, 0x1E); + if (i) + return i; + + ether3_setbuffer(dev, buffer_write, 0); + ether3_writelong(dev, 0); + return 0; +} + +static void ether3_init_for_open(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + int i; + + memset(&priv->stats, 0, sizeof(struct enet_statistics)); + + priv->regs.command = 0; + outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND); + while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON)); + + outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], REG_BUFWIN); + + priv->tx_used = 0; + priv->tx_head = 0; + priv->tx_tail = 0; + priv->regs.config2 |= CFG2_CTRLO; + priv->rx_head = RX_START; + + outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); + outw((TX_END >> 8) - 1, REG_BUFWIN); + outw(priv->rx_head, REG_RECVPTR); + outw(priv->rx_head >> 8, REG_RECVEND); + outw(0, REG_TRANSMITPTR); + outw(priv->regs.config2, REG_CONFIG2); + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); + + ether3_setbuffer(dev, buffer_write, 0); + ether3_writelong(dev, 0); + + priv->regs.command = CMD_ENINTRX; + outw(priv->regs.command | CMD_RXON, REG_COMMAND); +} + +/* + * This is the real probe routine. + */ +static int ether3_probe1(struct device *dev) +{ + static unsigned version_printed = 0; + struct dev_priv *priv; + unsigned int i, bus_type, error = ENODEV; + + if (net_debug && version_printed++ == 0) + printk(version); + + if (!dev->priv) { + dev->priv = kmalloc(sizeof(struct dev_priv), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; + } + priv = (struct dev_priv *) dev->priv; + memset(priv, 0, sizeof(struct dev_priv)); + + request_region(dev->base_addr, 128, "ether3"); + + /* Reset card... + */ + outb(0x80, REG_CONFIG2 + 1); + bus_type = BUS_UNKNOWN; + udelay(4); + + /* Test using Receive Pointer (16-bit register) to find out + * how the ether3 is connected to the bus... + */ + outb(0, REG_RECVPTR); + outb(1, REG_RECVPTR + 1); + + if (inb(REG_RECVPTR + 1) == 1) { + if (inb(REG_RECVPTR) == 0) + bus_type = BUS_8; + else if (inw(REG_RECVPTR) == 0x101) + bus_type = BUS_16; + } + switch (bus_type) { + case BUS_UNKNOWN: + printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name); + goto failed; + + case BUS_8: + printk(KERN_ERR "%s: ether3 found, but is an unsupported 8-bit card\n", dev->name); + goto failed; + + default: + break; + } + + printk("%s: ether3 found at %lx, IRQ%d, ether address ", dev->name, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); + + if (!ether3_init_2(dev)) { + dev->open = ether3_open; + dev->stop = ether3_close; + dev->hard_start_xmit = ether3_sendpacket; + dev->get_stats = ether3_getstats; + dev->set_multicast_list = ether3_setmulticastlist; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); +#ifndef CLAIM_IRQ_AT_OPEN + if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) + error = EAGAIN; + else +#endif + return 0; + } + failed: + kfree(dev->priv); + dev->priv = NULL; + release_region(dev->base_addr, 128); + return error; +} + +#ifndef MODULE +int ether3_probe(struct device *dev) +{ + struct expansion_card *ec; + + if (!dev) + return ENODEV; + + ecard_startfind(); + + if ((ec = ecard_find(0, ether3_cids)) == NULL) + return ENODEV; + + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->irq = ec->irq; + + ecard_claim(ec); + + ether3_addr(dev->dev_addr, ec); + return ether3_probe1(dev); +} +#endif + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int ether3_open(struct device *dev) +{ + ether3_init_for_open(dev); + + MOD_INC_USE_COUNT; + +#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } +#endif + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + return 0; +} + +/* + * The inverse routine to ether3_open(). + */ +static int ether3_close(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + + dev->tbusy = 1; + dev->start = 0; + + disable_irq(dev->irq); + + outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND); + priv->regs.command = 0; + while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON)); + outb(0x80, REG_CONFIG2 + 1); + outw(0, REG_COMMAND); + + enable_irq(dev->irq); +#ifdef CLAIM_IRQ_AT_OPEN + free_irq(dev->irq, dev); +#endif + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Get the current statistics. This may be called with the card open or + * closed. + */ +static struct enet_statistics *ether3_getstats(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + return &priv->stats; +} + +/* + * Set or clear promiscuous/multicast mode filter for this adaptor. + * + * We don't attempt any packet filtering. The card may have a SEEQ 8004 + * in which does not have the other ethernet address registers present... + */ +static void ether3_setmulticastlist(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + + priv->regs.config1 &= ~CFG1_RECVPROMISC; + + if (dev->flags & IFF_PROMISC) { + /* promiscuous mode */ + priv->regs.config1 |= CFG1_RECVPROMISC; + } else if (dev->flags & IFF_ALLMULTI) { + priv->regs.config1 |= CFG1_RECVSPECBRMULTI; + } else + priv->regs.config1 |= CFG1_RECVSPECBROAD; + + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); +} + +/* + * Transmit a packet + */ +static int ether3_sendpacket(struct sk_buff *skb, struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + retry: + if (!dev->tbusy) { + /* Block a timer-based transmit from overlapping. This could better be + * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + */ + if (!test_and_set_bit(0, (void *) &dev->tbusy)) { + unsigned long flags; + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int ptr, nextptr; + + length = (length + 1) & ~1; + + if (priv->broken) { + dev_kfree_skb(skb, FREE_WRITE); + priv->stats.tx_dropped++; + dev->tbusy = 0; + return 0; + } + ptr = priv->tx_head; + nextptr = ptr + 0x600; + if (nextptr >= TX_END) + nextptr = 0; + if (nextptr == priv->tx_tail) + return 1; /* unable to queue */ + priv->tx_head = nextptr; + + save_flags_cli(flags); + ether3_setbuffer(dev, buffer_write, nextptr); + ether3_writelong(dev, 0); + ether3_setbuffer(dev, buffer_write, ptr + 4); + ether3_writebuffer(dev, skb->data, length); + ether3_writeword(dev, htons(nextptr)); + ether3_writeword(dev, (TXHDR_TRANSMIT | TXHDR_CHAINCONTINUE) >> 16); + ether3_setbuffer(dev, buffer_write, ptr); +#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) + ether3_writeword(dev, htons(ptr + length + 4)); + ether3_writeword(dev, (TXHDR_FLAGS >> 16)); + ether3_ledon(dev, priv); + priv->tx_used++; + if (priv->tx_used < MAX_TX_BUFFERED) + dev->tbusy = 0; + if (priv->tx_used >= (MAX_TX_BUFFERED * 3 / 4)) { + priv->regs.command |= CMD_ENINTTX; + outw(priv->regs.command, REG_COMMAND); + } + restore_flags(flags); + + dev->trans_start = jiffies; + dev_kfree_skb(skb, FREE_WRITE); + if (!(inw(REG_STATUS) & STAT_TXON)) { + outw(ptr, REG_TRANSMITPTR); + outw(priv->regs.command | CMD_TXON, REG_COMMAND); + } + return 0; + } else { + printk("%s: transmitter access conflict.\n", dev->name); + return 1; + } + } else { + /* If we get here, some higher level has decided we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + del_timer(&priv->timer); + printk("%s: transmit timed out, network cable problem?\n", dev->name); + dev->tbusy = 0; + priv->regs.config2 |= CFG2_CTRLO; + outw(priv->regs.config2, REG_CONFIG2); + dev->trans_start = jiffies; + goto retry; + } +} + +static void ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct dev_priv *priv; + unsigned int status; + +#if NET_DEBUG > 1 + if (net_debug & DEBUG_INT) + printk("eth3irq: %d ", irq); +#endif + + priv = (struct dev_priv *) dev->priv; + + dev->interrupt = 1; + status = inw(REG_STATUS); + /* + * Dispite we disable the TX interrupt when the packet buffer is + * mostly empty, if we happen to get a RX interrupt, we might as + * well handle the TX packets as well. + */ + if (status & STAT_INTTX) { /* Packets transmitted */ + outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND); + ether3_tx(dev, priv); + } + status = inw(REG_STATUS); + if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) { /* Got packet(s). */ + /* + * We only acknowledge the interrupt if we have received all packets + * in the buffer or else we run out of memory. This is to allow the + * bh routines to run. + */ + outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND); + /* + * Receive again if some have become available - we may have cleared + * a pending IRQ + */ + ether3_rx(dev, priv, 4); + } + dev->interrupt = 0; + +#if NET_DEBUG > 1 + if (net_debug & DEBUG_INT) + printk("done\n"); +#endif +} + +/* + * If we have a good packet(s), get it/them out of the buffers. + */ +static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt) +{ + unsigned int next_ptr = priv->rx_head, received = 0; + ether3_ledon(dev, priv); + + do { + unsigned int this_ptr, status; + unsigned char addrs[16]; + + /* + * read the first 16 bytes from the buffer. + * This contains the status bytes etc and ethernet addresses, + * and we also check the source ethernet address to see if + * it originated from us. + */ + { + unsigned int temp_ptr; + ether3_setbuffer(dev, buffer_read, next_ptr); + temp_ptr = ether3_readword(dev); + status = ether3_readword(dev); + if (!(status & RXSTAT_DONE) || !temp_ptr) + break; + + this_ptr = next_ptr + 4; + next_ptr = ntohs(temp_ptr); + } + ether3_setbuffer(dev, buffer_read, this_ptr); + ether3_readbuffer(dev, addrs + 2, 12); + + /* + * ignore our own packets... + */ + if (!(*(unsigned long *) &dev->dev_addr[0] ^ *(unsigned long *) &addrs[2 + 6]) && + !(*(unsigned short *) &dev->dev_addr[4] ^ *(unsigned short *) &addrs[2 + 10])) { + maxcnt++; /* compensate for loopedback packet */ + outw(next_ptr >> 8, REG_RECVEND); + } else if (!(status & (RXSTAT_OVERSIZE | RXSTAT_CRCERROR | RXSTAT_DRIBBLEERROR | RXSTAT_SHORTPACKET))) { + unsigned int length = next_ptr - this_ptr; + struct sk_buff *skb; + + if (next_ptr <= this_ptr) + length += RX_END - RX_START; + + skb = dev_alloc_skb(length + 2); + if (skb) { + unsigned char *buf; + + skb->dev = dev; + skb_reserve(skb, 2); + buf = skb_put(skb, length); + ether3_readbuffer(dev, buf + 12, length - 12); + outw(next_ptr >> 8, REG_RECVEND); + *(unsigned short *) (buf + 0) = *(unsigned short *) (addrs + 2); + *(unsigned long *) (buf + 2) = *(unsigned long *) (addrs + 4); + *(unsigned long *) (buf + 6) = *(unsigned long *) (addrs + 8); + *(unsigned short *) (buf + 10) = *(unsigned short *) (addrs + 12); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + received++; + } else + goto dropping; + } else { + struct enet_statistics *stats = &priv->stats; + outw(next_ptr >> 8, REG_RECVEND); + if (status & RXSTAT_OVERSIZE) + stats->rx_length_errors++; + if (status & RXSTAT_CRCERROR) + stats->rx_crc_errors++; + if (status & RXSTAT_DRIBBLEERROR) + stats->rx_fifo_errors++; + if (status & RXSTAT_SHORTPACKET) + stats->rx_length_errors++; + stats->rx_errors++; + } + } + while (--maxcnt); + + done: + priv->stats.rx_packets += received; + priv->rx_head = next_ptr; + /* + * If rx went off line, then that means that the buffer may be full. We + * have dropped at least one packet. + */ + if (!(inw(REG_STATUS) & STAT_RXON)) { + priv->stats.rx_dropped++; + outw(next_ptr, REG_RECVPTR); + outw(priv->regs.command | CMD_RXON, REG_COMMAND); + } + return maxcnt; + + dropping:{ + static unsigned long last_warned; + + outw(next_ptr >> 8, REG_RECVEND); + /* + * Don't print this message too many times... + */ + if (jiffies - last_warned > 30 * HZ) { + last_warned = jiffies; + printk("%s: memory squeeze, dropping packet.\n", dev->name); + } + priv->stats.rx_dropped++; + goto done; + } +} + +/* + * Update stats for the transmitted packet(s) + */ +static void ether3_tx(struct device *dev, struct dev_priv *priv) +{ + unsigned int tx_tail = priv->tx_tail; + + do { + unsigned long status; + /* + * Read the packet header + */ + ether3_setbuffer(dev, buffer_read, tx_tail); + status = ether3_readlong(dev); + + /* + * Check to see if this packet has been transmitted + */ + if (!(status & TXSTAT_DONE) || !(status & TXHDR_TRANSMIT)) + break; + + /* + * Update errors + */ + if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS))) + priv->stats.tx_packets++; + else { + priv->stats.tx_errors++; + if (status & TXSTAT_16COLLISIONS) + priv->stats.collisions += 16; + if (status & TXSTAT_BABBLED) + priv->stats.tx_fifo_errors++; + } + + /* + * Get next packet address + */ + tx_tail += 0x600; + if (tx_tail >= TX_END) + tx_tail = 0; + + if (priv->tx_used) + priv->tx_used--; + } while (1); + + if (priv->tx_tail != tx_tail) { + priv->tx_tail = tx_tail; + if (priv->tx_used <= MAX_TX_BUFFERED) { + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + } + priv->regs.command &= ~CMD_ENINTTX; + outw(priv->regs.command, REG_COMMAND); +} + +#ifdef MODULE + +char ethernames[MAX_ECARDS][9]; + +static struct device *my_ethers[MAX_ECARDS]; +static struct expansion_card *ec[MAX_ECARDS]; + +int init_module(void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) { + my_ethers[i] = NULL; + ec[i] = NULL; + strcpy(ethernames[i], " "); + } + + i = 0; + + ecard_startfind(); + + do { + if ((ec[i] = ecard_find(0, ether3_cids)) == NULL) + break; + + my_ethers[i] = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL); + memset(my_ethers[i], 0, sizeof(struct device)); + + my_ethers[i]->irq = ec[i]->irq; + my_ethers[i]->base_addr = ecard_address(ec[i], ECARD_MEMC, 0); + my_ethers[i]->init = ether3_probe1; + my_ethers[i]->name = ethernames[i]; + + ether3_addr(my_ethers[i]->dev_addr, ec[i]); + + ecard_claim(ec[i]); + + if (register_netdev(my_ethers[i]) != 0) { + for (i = 0; i < 4; i++) { + if (my_ethers[i]) { + kfree(my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ecard_release(ec[i]); + ec[i] = NULL; + } + } + return -EIO; + } + i++; + } + while (i < MAX_ECARDS); + + return i != 0 ? 0 : -ENODEV; +} + +void cleanup_module(void) +{ + if (MOD_IN_USE) { + printk("ether3: device busy, remove delayed\n"); + } else { + int i; + for (i = 0; i < MAX_ECARDS; i++) { + if (my_ethers[i]) { + release_region(my_ethers[i]->base_addr, 128); + unregister_netdev(my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ecard_release(ec[i]); + ec[i] = NULL; + } + } + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/ether3.h linux/drivers/acorn/net/ether3.h --- v2.1.87/linux/drivers/acorn/net/ether3.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/ether3.h Mon Feb 16 15:49:48 1998 @@ -0,0 +1,169 @@ +/* + * linux/drivers/net/ether3.h + * + * network driver for Acorn/ANT Ether3 cards + */ + +#ifndef _LINUX_ether3_H +#define _LINUX_ether3_H + +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */ +#define DEBUG_TX 2 +#define DEBUG_RX 4 +#define DEBUG_INT 8 +#define DEBUG_IC 16 +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* Command register definitions & bits */ +#define REG_COMMAND (dev->base_addr + 0x00) +#define CMD_ENINTDMA 0x0001 +#define CMD_ENINTRX 0x0002 +#define CMD_ENINTTX 0x0004 +#define CMD_ENINTBUFWIN 0x0008 +#define CMD_ACKINTDMA 0x0010 +#define CMD_ACKINTRX 0x0020 +#define CMD_ACKINTTX 0x0040 +#define CMD_ACKINTBUFWIN 0x0080 +#define CMD_DMAON 0x0100 +#define CMD_RXON 0x0200 +#define CMD_TXON 0x0400 +#define CMD_DMAOFF 0x0800 +#define CMD_RXOFF 0x1000 +#define CMD_TXOFF 0x2000 +#define CMD_FIFOREAD 0x4000 +#define CMD_FIFOWRITE 0x8000 + +/* status register */ +#define REG_STATUS (dev->base_addr + 0x00) +#define STAT_ENINTSTAT 0x0001 +#define STAT_ENINTRX 0x0002 +#define STAT_ENINTTX 0x0004 +#define STAT_ENINTBUFWIN 0x0008 +#define STAT_INTDMA 0x0010 +#define STAT_INTRX 0x0020 +#define STAT_INTTX 0x0040 +#define STAT_INTBUFWIN 0x0080 +#define STAT_DMAON 0x0100 +#define STAT_RXON 0x0200 +#define STAT_TXON 0x0400 +#define STAT_FIFOFULL 0x2000 +#define STAT_FIFOEMPTY 0x4000 +#define STAT_FIFODIR 0x8000 + +/* configuration register 1 */ +#define REG_CONFIG1 (dev->base_addr + 0x10) +#define CFG1_BUFSELSTAT0 0x0000 +#define CFG1_BUFSELSTAT1 0x0001 +#define CFG1_BUFSELSTAT2 0x0002 +#define CFG1_BUFSELSTAT3 0x0003 +#define CFG1_BUFSELSTAT4 0x0004 +#define CFG1_BUFSELSTAT5 0x0005 +#define CFG1_ADDRPROM 0x0006 +#define CFG1_TRANSEND 0x0007 +#define CFG1_LOCBUFMEM 0x0008 +#define CFG1_INTVECTOR 0x0009 +#define CFG1_DMABURSTCONT 0x0000 +#define CFG1_DMABURST800NS 0x0010 +#define CFG1_DMABURST1600NS 0x0020 +#define CFG1_DMABURST3200NS 0x0030 +#define CFG1_DMABURST1 0x0000 +#define CFG1_DMABURST4 0x0040 +#define CFG1_DMABURST8 0x0080 +#define CFG1_DMABURST16 0x00C0 +#define CFG1_RECVCOMPSTAT0 0x0100 +#define CFG1_RECVCOMPSTAT1 0x0200 +#define CFG1_RECVCOMPSTAT2 0x0400 +#define CFG1_RECVCOMPSTAT3 0x0800 +#define CFG1_RECVCOMPSTAT4 0x1000 +#define CFG1_RECVCOMPSTAT5 0x2000 +#define CFG1_RECVSPECONLY 0x0000 +#define CFG1_RECVSPECBROAD 0x4000 +#define CFG1_RECVSPECBRMULTI 0x8000 +#define CFG1_RECVPROMISC 0xC000 + +/* configuration register 2 */ +#define REG_CONFIG2 (dev->base_addr + 0x20) +#define CFG2_BYTESWAP 0x0001 +#define CFG2_ERRENCRC 0x0008 +#define CFG2_ERRENDRIBBLE 0x0010 +#define CFG2_ERRSHORTFRAME 0x0020 +#define CFG2_SLOTSELECT 0x0040 +#define CFG2_PREAMSELECT 0x0080 +#define CFG2_ADDRLENGTH 0x0100 +#define CFG2_RECVCRC 0x0200 +#define CFG2_XMITNOCRC 0x0400 +#define CFG2_LOOPBACK 0x0800 +#define CFG2_CTRLO 0x1000 +#define CFG2_RESET 0x8000 + +#define REG_RECVEND (dev->base_addr + 0x30) + +#define REG_BUFWIN (dev->base_addr + 0x40) + +#define REG_RECVPTR (dev->base_addr + 0x50) + +#define REG_TRANSMITPTR (dev->base_addr + 0x60) + +#define REG_DMAADDR (dev->base_addr + 0x70) + +/* + * Cards transmit/receive headers + */ +#define TX_NEXT (0xffff) +#define TXHDR_ENBABBLEINT (1 << 16) +#define TXHDR_ENCOLLISIONINT (1 << 17) +#define TXHDR_EN16COLLISION (1 << 18) +#define TXHDR_ENSUCCESS (1 << 19) +#define TXHDR_DATAFOLLOWS (1 << 21) +#define TXHDR_CHAINCONTINUE (1 << 22) +#define TXHDR_TRANSMIT (1 << 23) +#define TXSTAT_BABBLED (1 << 24) +#define TXSTAT_COLLISION (1 << 25) +#define TXSTAT_16COLLISIONS (1 << 26) +#define TXSTAT_DONE (1 << 31) + +#define RX_NEXT (0xffff) +#define RXHDR_CHAINCONTINUE (1 << 6) +#define RXHDR_RECEIVE (1 << 7) +#define RXSTAT_OVERSIZE (1 << 8) +#define RXSTAT_CRCERROR (1 << 9) +#define RXSTAT_DRIBBLEERROR (1 << 10) +#define RXSTAT_SHORTPACKET (1 << 11) +#define RXSTAT_DONE (1 << 15) + + +#define TX_END 0x6000 +#define RX_START 0x6000 +#define RX_LEN 0xA000 +#define RX_END 0x10000 +/* must be a power of 2 and greater than MAX_TX_BUFFERED */ +#define MAX_TXED 16 +#define MAX_TX_BUFFERED 10 + +struct dev_priv { + struct { + unsigned int command; + unsigned int config1; + unsigned int config2; + } regs; + unsigned int tx_head; /* address to insert next packet */ + unsigned int tx_tail; /* address of transmitting packet */ + unsigned int tx_used; /* number of 'slots' used */ + unsigned int rx_head; /* address to fetch next packet from */ + struct enet_statistics stats; + struct timer_list timer; + int broken; /* 0 = ok, 1 = something went wrong */ +}; + +extern int ether3_probe (struct device *dev); +static int ether3_probe1 (struct device *dev); +static int ether3_open (struct device *dev); +static int ether3_sendpacket (struct sk_buff *skb, struct device *dev); +static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static int ether3_close (struct device *dev); +static struct enet_statistics *ether3_getstats (struct device *dev); +static void ether3_setmulticastlist (struct device *dev); + +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.1.87/linux/drivers/acorn/net/etherh.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/etherh.c Mon Feb 16 15:49:48 1998 @@ -0,0 +1,538 @@ +/* + * linux/drivers/net/etherh.c + * + * NS8390 ANT etherh specific driver + * For Acorn machines + * + * By Russell King. + * + * Changelog: + * 08-Dec-1996 RMK 1.00 Created + * RMK 1.03 Added support for EtherLan500 cards + * 23-Nov-1997 RMK 1.04 Added media autodetection + * + * Insmod Module Parameters + * ------------------------ + * io= + * irq= + * xcvr=<0|1> 0 = 10bT, 1=10b2 (Lan600/600A only) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "8390.h" + +#define NET_DEBUG 0 +#define DEBUG_INIT 2 + +static unsigned int net_debug = NET_DEBUG; +static const card_ids etherh_cids[] = { + { MANU_I3, PROD_I3_ETHERLAN500 }, + { MANU_I3, PROD_I3_ETHERLAN600 }, + { MANU_I3, PROD_I3_ETHERLAN600A }, + { 0xffff, 0xffff } +}; + +static char *version = "etherh [500/600/600A] ethernet driver (c) 1997 R.M.King v1.04\n"; + +#define ETHERH500_DATAPORT 0x200 /* MEMC */ +#define ETHERH500_NS8390 0x000 /* MEMC */ +#define ETHERH500_CTRLPORT 0x200 /* IOC */ + +#define ETHERH600_DATAPORT 16 /* MEMC */ +#define ETHERH600_NS8390 0x200 /* MEMC */ +#define ETHERH600_CTRLPORT 0x080 /* MEMC */ + +#define ETHERH_CP_IE 1 +#define ETHERH_CP_IF 2 + +#define ETHERH_TX_START_PAGE 1 +#define ETHERH_STOP_PAGE 0x7f + +/* --------------------------------------------------------------------------- */ + +/* + * Read the ethernet address string from the on board rom. + * This is an ascii string... + */ +static int +etherh_addr (char *addr, struct expansion_card *ec) +{ + struct in_chunk_dir cd; + char *s; + + if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { + int i; + for (i = 0; i < 6; i++) { + addr[i] = simple_strtoul(s + 1, &s, 0x10); + if (*s != (i == 5? ')' : ':')) + break; + } + if (i == 6) + return 0; + } + return ENODEV; +} + +/* + * Reset the 8390 (hard reset) + */ +static void +etherh_reset (struct device *dev) +{ + unsigned int addr = dev->base_addr; + int crb; + + if (dev->mem_end == PROD_I3_ETHERLAN600 || dev->mem_end == PROD_I3_ETHERLAN600A) { + crb = inb (addr + EN0_RCNTHI) & 0xf8; + outb (ei_status.interface_num ? crb | 1: crb, addr+EN0_RCNTHI); + } +} + +/* + * Write a block of data out to the 8390 + */ +static void +etherh_block_output (struct device *dev, int count, const unsigned char *buf, int start_page) +{ + unsigned int addr, dma_addr; + unsigned long dma_start; + + if (ei_status.dmaing) { + printk ("%s: DMAing conflict in etherh_block_input: " + " DMAstat %d irqlock %d intr %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock, dev->interrupt); + return; + } + + ei_status.dmaing |= 1; + + addr = dev->base_addr; + dma_addr = dev->mem_start; + + count = (count + 1) & ~1; + outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); + + outb (0x42, addr + EN0_RCNTLO); + outb (0x00, addr + EN0_RCNTHI); + outb (0x42, addr + EN0_RSARLO); + outb (0x00, addr + EN0_RSARHI); + outb (E8390_RREAD | E8390_START, addr + E8390_CMD); + + udelay (1); + + outb (ENISR_RDC, addr + EN0_ISR); + outb (count, addr + EN0_RCNTLO); + outb (count >> 8, addr + EN0_RCNTHI); + outb (0, addr + EN0_RSARLO); + outb (start_page, addr + EN0_RSARHI); + outb (E8390_RWRITE | E8390_START, addr + E8390_CMD); + + if (ei_status.word16) + outsw (dma_addr, buf, count >> 1); +#ifdef BIT8 + else + outsb (dma_addr, buf, count); +#endif + + dma_start = jiffies; + + while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + printk ("%s: timeout waiting for TX RDC\n", dev->name); + etherh_reset (dev); + NS8390_init (dev, 1); + break; + } + + outb (ENISR_RDC, addr + EN0_ISR); + ei_status.dmaing &= ~1; +} + +/* + * Read a block of data from the 8390 + */ +static void +etherh_block_input (struct device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned int addr, dma_addr; + unsigned char *buf; + + if (ei_status.dmaing) { + printk ("%s: DMAing conflict in etherh_block_input: " + " DMAstat %d irqlock %d intr %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock, dev->interrupt); + return; + } + + ei_status.dmaing |= 1; + + addr = dev->base_addr; + dma_addr = dev->mem_start; + + buf = skb->data; + outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); + outb (count, addr + EN0_RCNTLO); + outb (count >> 8, addr + EN0_RCNTHI); + outb (ring_offset, addr + EN0_RSARLO); + outb (ring_offset >> 8, addr + EN0_RSARHI); + outb (E8390_RREAD | E8390_START, addr + E8390_CMD); + + if (ei_status.word16) { + insw (dma_addr, buf, count >> 1); + if (count & 1) + buf[count - 1] = inb (dma_addr); + } +#ifdef BIT8 + else + insb (dma_addr, buf, count); +#endif + + outb (ENISR_RDC, addr + EN0_ISR); + ei_status.dmaing &= ~1; +} + +/* + * Read a header from the 8390 + */ +static void +etherh_get_header (struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned int addr, dma_addr; + + if (ei_status.dmaing) { + printk ("%s: DMAing conflict in etherh_get_header: " + " DMAstat %d irqlock %d intr %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock, dev->interrupt); + return; + } + + ei_status.dmaing |= 1; + + addr = dev->base_addr; + dma_addr = dev->mem_start; + + outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); + outb (sizeof (*hdr), addr + EN0_RCNTLO); + outb (0, addr + EN0_RCNTHI); + outb (0, addr + EN0_RSARLO); + outb (ring_page, addr + EN0_RSARHI); + outb (E8390_RREAD | E8390_START, addr + E8390_CMD); + + if (ei_status.word16) + insw (dma_addr, hdr, sizeof (*hdr) >> 1); +#ifdef BIT8 + else + insb (dma_addr, hdr, sizeof (*hdr)); +#endif + + outb (ENISR_RDC, addr + EN0_ISR); + ei_status.dmaing &= ~1; +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int +etherh_open(struct device *dev) +{ + unsigned int addr = dev->base_addr; + int crb; + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, ei_interrupt, 0, "etherh", dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (dev->mem_end == PROD_I3_ETHERLAN600 || dev->mem_end == PROD_I3_ETHERLAN600A) { + crb = inb (addr + EN0_RCNTHI) & 0xf8; + outb (ei_status.interface_num ? crb | 1: crb, addr+EN0_RCNTHI); + } + + ei_open (dev); + return 0; +} + +/* + * The inverse routine to etherh_open(). + */ +static int +etherh_close(struct device *dev) +{ + ei_close (dev); + free_irq (dev->irq, dev); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This is the real probe routine. + */ +static int +etherh_probe1(struct device *dev) +{ + static int version_printed; + unsigned int addr, i, reg0, tmp; + char *dev_type; + + addr = dev->base_addr; + + if (net_debug && version_printed++ == 0) + printk(version); + + switch (dev->mem_end) { + case PROD_I3_ETHERLAN500: + dev_type = "500 "; + break; + case PROD_I3_ETHERLAN600: + dev_type = "600 "; + break; + case PROD_I3_ETHERLAN600A: + dev_type = "600A "; + break; + default: + dev_type = ""; + } + + reg0 = inb (addr); + if (reg0 == 0xff) { + if (net_debug & DEBUG_INIT) + printk ("%s: etherh error: NS8390 command register wrong\n", dev->name); + return -ENODEV; + } + + outb (E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD); + tmp = inb (addr + 13); + outb (0xff, addr + 13); + outb (E8390_NODMA | E8390_PAGE0, addr + E8390_CMD); + inb (addr + EN0_COUNTER0); + if (inb (addr + EN0_COUNTER0) != 0) { + if (net_debug & DEBUG_INIT) + printk ("%s: etherh error: NS8390 not found\n", dev->name); + outb (reg0, addr); + outb (tmp, addr + 13); + return -ENODEV; + } + + if (ethdev_init (dev)) + return -ENOMEM; + + request_region (addr, 16, "etherh"); + + printk("%s: etherh %sfound at %lx, IRQ%d, ether address ", + dev->name, dev_type, dev->base_addr, dev->irq); + + for (i = 0; i < 6; i++) + printk (i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); + + ei_status.name = "etherh"; + ei_status.word16 = 1; + ei_status.interface_num = dev->if_port & 1; + ei_status.tx_start_page = ETHERH_TX_START_PAGE; + ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; + ei_status.stop_page = ETHERH_STOP_PAGE; + ei_status.reset_8390 = etherh_reset; + ei_status.block_input = etherh_block_input; + ei_status.block_output = etherh_block_output; + ei_status.get_8390_hdr = etherh_get_header; + dev->open = etherh_open; + dev->stop = etherh_close; + + NS8390_init (dev, 0); + return 0; +} + +static void etherh_irq_enable (ecard_t *ec, int irqnr) +{ + unsigned int ctrl_addr = (unsigned int)ec->irq_data; + outb (inb (ctrl_addr) | ETHERH_CP_IE, ctrl_addr); +} + +static void etherh_irq_disable (ecard_t *ec, int irqnr) +{ + unsigned int ctrl_addr = (unsigned int)ec->irq_data; + outb (inb (ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr); +} + +static expansioncard_ops_t etherh_ops = { + etherh_irq_enable, + etherh_irq_disable, + NULL, + NULL +}; + +static void etherh_initdev (ecard_t *ec, struct device *dev) +{ + ecard_claim (ec); + + dev->irq = ec->irq; + dev->mem_end = ec->cld.product; + + switch (ec->cld.product) { + case PROD_I3_ETHERLAN500: + dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH500_NS8390; + dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; + ec->irq_data = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST) + + ETHERH500_CTRLPORT; + break; + + case PROD_I3_ETHERLAN600: + case PROD_I3_ETHERLAN600A: + dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH600_NS8390; + dev->mem_start = dev->base_addr + ETHERH600_DATAPORT; + ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT); + break; + + default: + printk ("%s: etherh error: unknown card type\n", dev->name); + } + ec->ops = ðerh_ops; + + etherh_addr (dev->dev_addr, ec); +} + +#ifndef MODULE +int +etherh_probe(struct device *dev) +{ + if (!dev) + return ENODEV; + + ecard_startfind (); + + if (!dev->base_addr) { + struct expansion_card *ec; + + if ((ec = ecard_find (0, etherh_cids)) == NULL) + return ENODEV; + + etherh_initdev (ec, dev); + } + return etherh_probe1 (dev); +} +#endif + +#ifdef MODULE +#define MAX_ETHERH_CARDS 2 + +static int io[MAX_ETHERH_CARDS]; +static int irq[MAX_ETHERH_CARDS]; +static int xcvr[MAX_ETHERH_CARDS] = { 1, 1 }; +static char ethernames[MAX_ETHERH_CARDS][9]; +static struct device *my_ethers[MAX_ETHERH_CARDS]; +static struct expansion_card *ec[MAX_ETHERH_CARDS]; + +int +init_module(void) +{ + struct device *dev = NULL; + struct expansion_card *boguscards[MAX_ETHERH_CARDS]; + int i, found = 0; + + for (i = 0; i < MAX_ETHERH_CARDS; i++) { + my_ethers[i] = NULL; + boguscards[i] = NULL; + ec[i] = NULL; + strcpy (ethernames[i], " "); + } + + ecard_startfind(); + + for (i = 0; i < MAX_ETHERH_CARDS; i++) { + if (!dev) + dev = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); + if (dev) + memset (dev, 0, sizeof (struct device)); + + if (!io[i]) { + if ((ec[i] = ecard_find (0, etherh_cids)) == NULL) + continue; + if (!dev) + return -ENOMEM; + + etherh_initdev (ec[i], dev); + } else { + ec[i] = NULL; + if (!dev) + return -ENOMEM; + dev->base_addr = io[i]; + dev->irq = irq[i]; + } + + dev->init = etherh_probe1; + dev->name = ethernames[i]; + dev->if_port = xcvr[i]; + + my_ethers[i] = dev; + + if (register_netdev (my_ethers[i]) != 0) { + printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr); + if (ec[i]) { + boguscards[i] = ec[i]; + ec[i] = NULL; + } + continue; + } + found ++; + dev = NULL; + } + if (dev) + kfree (dev); + for (i = 0; i < MAX_ETHERH_CARDS; i++) + if (boguscards[i]) { + boguscards[i]->ops = NULL; + ecard_release (boguscards[i]); + } + if (!found) + return -ENODEV; + return 0; +} + +void +cleanup_module(void) +{ + int i; + for (i = 0; i < MAX_ETHERH_CARDS; i++) { + if (my_ethers[i]) { + unregister_netdev(my_ethers[i]); + release_region (my_ethers[i]->base_addr, 16); + kfree (my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ec[i]->ops = NULL; + ecard_release(ec[i]); + ec[i] = NULL; + } + } +} +#endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/net/net-probe.c linux/drivers/acorn/net/net-probe.c --- v2.1.87/linux/drivers/acorn/net/net-probe.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/net/net-probe.c Mon Feb 16 15:49:48 1998 @@ -0,0 +1,31 @@ +/* + * Acorn specific net device driver probe routine + * + * Copyright (C) 1998 Russell King + */ +#include +#include +#include +#include + +extern int ether1_probe (struct device *dev); +extern int ether3_probe (struct device *dev); +extern int etherh_probe (struct device *dev); + +__initfunc(int acorn_ethif_probe(struct device *dev)) +{ + if (1 +#ifdef CONFIG_ARM_ETHERH + && etherh_probe (dev) +#endif +#ifdef CONFIG_ARM_ETHER3 + && ether3_probe (dev) +#endif +#ifdef CONFIG_ARM_ETHER1 + && ether1_probe (dev) +#endif + && 1) { + return 1; + } + return 0; +} diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/Config.in linux/drivers/acorn/scsi/Config.in --- v2.1.87/linux/drivers/acorn/scsi/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/Config.in Tue Feb 3 12:57:43 1998 @@ -0,0 +1,21 @@ +# +# SCSI driver configuration for Acorn +# +dep_tristate 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 $CONFIG_SCSI +if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then + bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI + dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI + + comment 'The following drives are not fully supported' + + dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI + if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then + dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI + fi + dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI +fi + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/Makefile linux/drivers/acorn/scsi/Makefile --- v2.1.87/linux/drivers/acorn/scsi/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/Makefile Sat Feb 7 07:18:17 1998 @@ -0,0 +1,103 @@ +# +# Makefile for drivers/acorn/scsi +# + +L_TARGET := acorn-scsi.a +L_OBJS := +LX_OBJS := +M_OBJS := +MX_OBJS := +MOD_LIST_NAME := ACORN_SCSI_MODULES + +CONFIG_QUEUE_BUILTIN := +CONFIG_FAS216_BUILTIN := +CONFIG_QUEUE_MODULE := +CONFIG_FAS216_MODULE := + +ifeq ($(CONFIG_SCSI_ACORNSCSI_3),y) + L_OBJS += acornscsi.o acornscsi-io.o + CONFIG_QUEUE_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_ACORNSCSI_3),m) + M_OBJS += acornscsi_mod.o + CONFIG_QUEUE_MODULE=y + endif +endif + +ifeq ($(CONFIG_SCSI_CUMANA_1),y) + L_OBJS += cumana_1.o +else + ifeq ($(CONFIG_SCSI_CUMANA_1),m) + M_OBJS += cumana_1.o + endif +endif + +ifeq ($(CONFIG_SCSI_CUMANA_2),y) + L_OBJS += cumana_2.o + CONFIG_QUEUE_BUILTIN=y + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_CUMANA_2),m) + M_OBJS += cumana_2.o + CONFIG_QUEUE_MODULE=y + CONFIG_FAS216_MODULE=y + endif +endif + +ifeq ($(CONFIG_SCSI_ECOSCSI),y) + L_OBJS += ecoscsi.o +else + ifeq ($(CONFIG_SCSI_ECOSCSI),m) + M_OBJS += ecoscsi.o + endif +endif + +ifeq ($(CONFIG_SCSI_OAK1),y) + L_OBJS += oak.o +else + ifeq ($(CONFIG_SCSI_OAK1),m) + M_OBJS += oak.o + endif +endif + +ifeq ($(CONFIG_SCSI_POWERTECSCSI),y) + L_OBJS += powertec.o + CONFIG_QUEUE_BUILTIN=y + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_POWERTECSCSI),m) + M_OBJS += powertec.o + CONFIG_QUEUE_MODULE=y + CONFIG_FAS216_MODULE=y + endif +endif + +ifeq ($(CONFIG_QUEUE_BUILTIN),y) + LX_OBJS += queue.o msgqueue.o +else + ifeq ($(CONFIG_QUEUE_MODULE),y) + MX_OBJS += queue.o msgqueue.o + endif +endif + +ifeq ($(CONFIG_FAS216_BUILTIN),y) + LX_OBJS += fas216.o +else + ifeq ($(CONFIG_FAS216_MODULE),y) + MX_OBJS += fas216.o + endif +endif + +include $(TOPDIR)/Rules.make + +acornscsi_mod.o: acornscsi.o acornscsi-io.o + $(LD) $(LD_RFLAG) -r -o $@ acornscsi.o acornscsi-io.o + +%.o: %.S +ifndef $(CONFIG_BINUTILS_NEW) + $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.$<.s + $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.$<.s + $(RM) ..tmp.$<.s +else + $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< +endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/acornscsi-io.S linux/drivers/acorn/scsi/acornscsi-io.S --- v2.1.87/linux/drivers/acorn/scsi/acornscsi-io.S Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/acornscsi-io.S Sun Jan 11 16:45:53 1998 @@ -0,0 +1,139 @@ +@ linux/arch/arm/drivers/scsi/acornscsi-io.S: Acorn SCSI card IO +#include + +#include +#include + +#if (IO_BASE == (PCIO_BASE & 0xff000000)) +#define ADDR(off,reg) \ + tst off, $0x80000000 ;\ + mov reg, $IO_BASE ;\ + orreq reg, reg, $(PCIO_BASE & 0x00ff0000) +#else +#define ADDR(off,reg) \ + tst off, $0x80000000 ;\ + movne reg, $IO_BASE ;\ + moveq reg, $(PCIO_BASE & 0xff000000) ;\ + orreq reg, reg, $(PCIO_BASE & 0x00ff0000) +#endif + +@ Purpose: transfer a block of data from the acorn scsi card to memory +@ Proto : void acornscsi_in(unsigned int addr_start, char *buffer, int length) +@ Returns: nothing + + .align +ENTRY(__acornscsi_in) + stmfd sp!, {r4 - r7, lr} + bic r0, r0, #3 + mov lr, #0xff + orr lr, lr, #0xff00 +acornscsi_in16lp: + subs r2, r2, #16 + bmi acornscsi_in8 + ldmia r0!, {r3, r4, r5, r6} + and r3, r3, lr + orr r3, r3, r4, lsl #16 + and r4, r5, lr + orr r4, r4, r6, lsl #16 + ldmia r0!, {r5, r6, r7, ip} + and r5, r5, lr + orr r5, r5, r6, lsl #16 + and r6, r7, lr + orr r6, r6, ip, lsl #16 + stmia r1!, {r3 - r6} + bne acornscsi_in16lp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +acornscsi_in8: adds r2, r2, #8 + bmi acornscsi_in4 + ldmia r0!, {r3, r4, r5, r6} + and r3, r3, lr + orr r3, r3, r4, lsl #16 + and r4, r5, lr + orr r4, r4, r6, lsl #16 + stmia r1!, {r3 - r4} + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r2, r2, #8 + +acornscsi_in4: adds r2, r2, #4 + bmi acornscsi_in2 + ldmia r0!, {r3, r4} + and r3, r3, lr + orr r3, r3, r4, lsl #16 + str r3, [r1], #4 + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r2, r2, #4 + +acornscsi_in2: adds r2, r2, #2 + ldr r3, [r0], #4 + and r3, r3, lr + strb r3, [r1], #1 + mov r3, r3, lsr #8 + strplb r3, [r1], #1 + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ Purpose: transfer a block of data from memory to the acorn scsi card +@ Proto : void acornscsi_in(unsigned int addr_start, char *buffer, int length) +@ Returns: nothing + +ENTRY(__acornscsi_out) + stmfd sp!, {r4 - r6, lr} + bic r0, r0, #3 +acornscsi_out16lp: + subs r2, r2, #16 + bmi acornscsi_out8 + ldmia r1!, {r4, r6, ip, lr} + mov r3, r4, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, r4, lsr #16 + orr r4, r4, r4, lsl #16 + mov r5, r6, lsl #16 + orr r5, r5, r5, lsr #16 + mov r6, r6, lsr #16 + orr r6, r6, r6, lsl #16 + stmia r0!, {r3, r4, r5, r6} + mov r3, ip, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, ip, lsr #16 + orr r4, r4, r4, lsl #16 + mov ip, lr, lsl #16 + orr ip, ip, ip, lsr #16 + mov lr, lr, lsr #16 + orr lr, lr, lr, lsl #16 + stmia r0!, {r3, r4, ip, lr} + bne acornscsi_out16lp + LOADREGS(fd, sp!, {r4 - r6, pc}) + +acornscsi_out8: adds r2, r2, #8 + bmi acornscsi_out4 + ldmia r1!, {r4, r6} + mov r3, r4, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, r4, lsr #16 + orr r4, r4, r4, lsl #16 + mov r5, r6, lsl #16 + orr r5, r5, r5, lsr #16 + mov r6, r6, lsr #16 + orr r6, r6, r6, lsl #16 + stmia r0!, {r3, r4, r5, r6} + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + + sub r2, r2, #8 +acornscsi_out4: adds r2, r2, #4 + bmi acornscsi_out2 + ldr r4, [r1], #4 + mov r3, r4, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, r4, lsr #16 + orr r4, r4, r4, lsl #16 + stmia r0!, {r3, r4} + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + + sub r2, r2, #4 +acornscsi_out2: adds r2, r2, #2 + ldr r3, [r1], #2 + strb r3, [r0], #1 + mov r3, r3, lsr #8 + strplb r3, [r0], #1 + LOADREGS(fd, sp!, {r4 - r6, pc}) + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c --- v2.1.87/linux/drivers/acorn/scsi/acornscsi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/acornscsi.c Fri Feb 6 15:55:44 1998 @@ -0,0 +1,2870 @@ +/* + * linux/arch/arm/drivers/scsi/acornscsi.c + * + * Acorn SCSI 3 driver + * By R.M.King. + * + * Abandoned using the Select and Transfer command since there were + * some nasty races between our software and the target devices that + * were not easy to solve, and the device errata had a lot of entries + * for this command, some of them quite nasty... + * + * Changelog: + * 26-Sep-1997 RMK Re-jigged to use the queue module. + * Re-coded state machine to be based on driver + * state not scsi state. Should be easier to debug. + * Added acornscsi_release to clean up properly. + * Updated proc/scsi reporting. + * 05-Oct-1997 RMK Implemented writing to SCSI devices. + * 06-Oct-1997 RMK Corrected small (non-serious) bug with the connect/ + * reconnect race condition causing a warning message. + * 12-Oct-1997 RMK Added catch for re-entering interrupt routine. + * 15-Oct-1997 RMK Improved handling of commands. + */ +#define DEBUG_NO_WRITE 1 +#define DEBUG_QUEUES 2 +#define DEBUG_DMA 4 +#define DEBUG_ABORT 8 +#define DEBUG_DISCON 16 +#define DEBUG_CONNECT 32 +#define DEBUG_PHASES 64 +#define DEBUG_WRITE 128 +#define DEBUG_LINK 256 +#define DEBUG_MESSAGES 512 +#define DEBUG_RESET 1024 +#define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ + DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ + DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE) + +/* DRIVER CONFIGURATION + * + * SCSI-II Tagged queue support. + * + * I don't have any SCSI devices that support it, so it is totally untested + * (except to make sure that it doesn't interfere with any non-tagging + * devices). It is not fully implemented either - what happens when a + * tagging device reconnects??? + * + * You can tell if you have a device that supports tagged queueing my + * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported + * as '2 TAG'. + * + * Also note that CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE is normally set in the config + * scripts, but disabled here. Once debugged, remove the #undef, otherwise to debug, + * comment out the undef. + */ +#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE +/* + * SCSI-II Linked command support. + * + * The higher level code doesn't support linked commands yet, and so the option + * is undef'd here. + */ +#undef CONFIG_SCSI_ACORNSCSI_LINK +/* + * SCSI-II Synchronous transfer support. + * + * Tried and tested... + * + * SDTR_SIZE - maximum number of un-acknowledged bytes (0 = off, 12 = max) + * SDTR_PERIOD - period of REQ signal (min=125, max=1020) + * DEFAULT_PERIOD - default REQ period. + */ +#define SDTR_SIZE 12 +#define SDTR_PERIOD 125 +#define DEFAULT_PERIOD 500 + +/* + * Debugging information + * + * DEBUG - bit mask from list above + * DEBUG_TARGET - is defined to the target number if you want to debug + * a specific target. [only recon/write/dma]. + */ +#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE) +/* only allow writing to SCSI device 0 */ +#define NO_WRITE 0xFE +/*#define DEBUG_TARGET 2*/ +/* + * Select timeout time (in 10ms units) + * + * This is the timeout used between the start of selection and the WD33C93 + * chip deciding that the device isn't responding. + */ +#define TIMEOUT_TIME 10 +/* + * Define this if you want to have verbose explaination of SCSI + * status/messages. + */ +#undef CONFIG_ACORNSCSI_CONSTANTS +/* + * Define this if you want to use the on board DMAC [don't remove this option] + * If not set, then use PIO mode (not currently supported). + */ +#define USE_DMAC +/* + * List of devices that the driver will recognise + */ +#define ACORNSCSI_LIST { MANU_ACORN, PROD_ACORN_SCSI } +/* + * ==================================================================================== + */ + +#ifdef DEBUG_TARGET +#define DBG(cmd,xxx...) \ + if (cmd->target == DEBUG_TARGET) { \ + xxx; \ + } +#else +#define DBG(cmd,xxx...) xxx +#endif + +#ifndef STRINGIFY +#define STRINGIFY(x) #x +#endif +#define STR(x) STRINGIFY(x) +#define NO_WRITE_STR STR(NO_WRITE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "../../scsi/constants.h" +#include "acornscsi.h" + +#define VER_MAJOR 2 +#define VER_MINOR 0 +#define VER_PATCH 5 + +#ifndef ABORT_TAG +#define ABORT_TAG 0xd +#else +#error "Yippee! ABORT TAG is now defined! Remove this error!" +#endif + +#ifndef NO_IRQ +#define NO_IRQ 255 +#endif + +#ifdef CONFIG_SCSI_ACORNSCSI_LINK +#error SCSI2 LINKed commands not supported (yet)! +#endif + +#ifdef USE_DMAC +/* + * DMAC setup parameters + */ +#define INIT_DEVCON0 (DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP) +#define INIT_DEVCON1 (DEVCON1_BHLD) +#define DMAC_READ (MODECON_READ) +#define DMAC_WRITE (MODECON_WRITE) +#define INIT_SBICDMA (CTRL_DMABURST) + +/* + * Size of on-board DMA buffer + */ +#define DMAC_BUFFER_SIZE 65536 +#endif + +/* + * This is used to dump the previous states of the SBIC + */ +static struct status_entry { + unsigned long when; + unsigned char ssr; + unsigned char ph; + unsigned char irq; + unsigned char unused; +} status[9][16]; +static unsigned char status_ptr[9]; + +#define ADD_STATUS(_q,_ssr,_ph,_irq) \ +({ \ + status[(_q)][status_ptr[(_q)]].when = jiffies; \ + status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \ + status[(_q)][status_ptr[(_q)]].ph = (_ph); \ + status[(_q)][status_ptr[(_q)]].irq = (_irq); \ + status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \ +}) + +unsigned int sdtr_period = SDTR_PERIOD; +unsigned int sdtr_size = SDTR_SIZE; + +static struct proc_dir_entry proc_scsi_acornscsi = { + PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); +static int acornscsi_reconnect_finish (AS_Host *host); +static void acornscsi_dma_cleanup (AS_Host *host); +static void acornscsi_abortcmd (AS_Host *host, unsigned char tag); + +/* ==================================================================================== + * Miscellaneous + */ + +static inline void +sbic_arm_write (unsigned int io_port, int reg, int value) +{ + outb_t (reg, io_port); + outb_t (value, io_port + 4); +} + +#define sbic_arm_writenext(io,val) \ + outb_t ((val), (io) + 4) + +static inline +int sbic_arm_read (unsigned int io_port, int reg) +{ + if(reg == ASR) + return inl_t(io_port) & 255; + outb_t (reg, io_port); + return inl_t(io_port + 4) & 255; +} + +#define sbic_arm_readnext(io) \ + inb_t((io) + 4) + +#ifdef USE_DMAC +#define dmac_read(io_port,reg) \ + inb ((io_port) + (reg)) + +#define dmac_write(io_port,reg,value) \ + ({ outb ((value), (io_port) + (reg)); }) + +#define dmac_clearintr(io_port) \ + ({ outb (0, (io_port)); }) + +static inline +unsigned int dmac_address (unsigned int io_port) +{ + return dmac_read (io_port, TXADRHI) << 16 | + dmac_read (io_port, TXADRMD) << 8 | + dmac_read (io_port, TXADRLO); +} +#endif + +static +unsigned long acornscsi_sbic_xfcount (AS_Host *host) +{ + unsigned long length; + + length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16; + length |= sbic_arm_readnext (host->scsi.io_port) << 8; + length |= sbic_arm_readnext (host->scsi.io_port); + + return length; +} + +static +int acornscsi_sbic_issuecmd (AS_Host *host, int command) +{ + int asr; + + do { + asr = sbic_arm_read (host->scsi.io_port, ASR); + } while (asr & ASR_CIP); + + sbic_arm_write (host->scsi.io_port, CMND, command); + + return 0; +} + +static void +acornscsi_csdelay (unsigned int cs) +{ + unsigned long target_jiffies, flags; + + target_jiffies = jiffies + 1 + cs * HZ / 100; + + save_flags (flags); + sti (); + + while (jiffies < target_jiffies) barrier(); + + restore_flags (flags); +} + +static +void acornscsi_resetcard (AS_Host *host) +{ + unsigned int i; + + /* assert reset line */ + host->card.page_reg = 0x80; + outb (host->card.page_reg, host->card.io_page); + + /* wait 3 cs. SCSI standard says 25ms. */ + acornscsi_csdelay (3); + + host->card.page_reg = 0; + outb (host->card.page_reg, host->card.io_page); + + /* + * Should get a reset from the card + */ + while (!(inb (host->card.io_intr) & 8)); + sbic_arm_read (host->scsi.io_port, ASR); + sbic_arm_read (host->scsi.io_port, SSR); + + /* setup sbic - WD33C93A */ + sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + + /* + * Command should cause a reset interrupt + */ + while (!(inb (host->card.io_intr) & 8)); + sbic_arm_read (host->scsi.io_port, ASR); + if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01) + printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + host->host->host_no); + + sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + + host->card.page_reg = 0x40; + outb (host->card.page_reg, host->card.io_page); + +#ifdef USE_DMAC + /* setup dmac - uPC71071 */ + dmac_write (host->dma.io_port, INIT, 0); + dmac_write (host->dma.io_port, INIT, INIT_8BIT); + dmac_write (host->dma.io_port, CHANNEL, CHANNEL_0); + dmac_write (host->dma.io_port, DEVCON0, INIT_DEVCON0); + dmac_write (host->dma.io_port, DEVCON1, INIT_DEVCON1); +#else + dmac_write (host->dma.io_port, INIT, 0); +#endif + + host->SCpnt = NULL; + host->scsi.phase = PHASE_IDLE; + host->scsi.disconnectable = 0; + + for (i = 0; i < 8; i++) { + host->busyluns[i] = 0; + host->device[i].sync_state = SYNC_NEGOCIATE; + host->device[i].disconnect_ok = 1; + } + + /* wait 25 cs. SCSI standard says 250ms. */ + acornscsi_csdelay (25); +} + +/*============================================================================================= + * Utility routines (eg. debug) + */ +#ifdef CONFIG_ACORNSCSI_CONSTANTS +static char *acornscsi_interrupttype[] = { + "rst", "suc", "p/a", "3", + "term", "5", "6", "7", + "serv", "9", "a", "b", + "c", "d", "e", "f" +}; + +static signed char acornscsi_map[] = { + 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2, -1, -1, -1, -1, 3, -1, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, -1, -1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, 16, 17, 18, 19, -1, -1, 20, 4, 5, 6, 7, 8, 9, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 21, 22, -1, -1, -1, 23, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static char *acornscsi_interruptcode[] = { + /* 0 */ + "reset - normal mode", /* 00 */ + "reset - advanced mode", /* 01 */ + + /* 2 */ + "sel", /* 11 */ + "sel+xfer", /* 16 */ + "data-out", /* 18 */ + "data-in", /* 19 */ + "cmd", /* 1A */ + "stat", /* 1B */ + "??-out", /* 1C */ + "??-in", /* 1D */ + "msg-out", /* 1E */ + "msg-in", /* 1F */ + + /* 12 */ + "/ACK asserted", /* 20 */ + "save-data-ptr", /* 21 */ + "{re}sel", /* 22 */ + + /* 15 */ + "inv cmd", /* 40 */ + "unexpected disconnect", /* 41 */ + "sel timeout", /* 42 */ + "P err", /* 43 */ + "P err+ATN", /* 44 */ + "bad status byte", /* 47 */ + + /* 21 */ + "resel, no id", /* 80 */ + "resel", /* 81 */ + "discon", /* 85 */ +}; + +static +void print_scsi_status (unsigned int ssr) +{ + if (acornscsi_map[ssr] != -1) + printk ("%s:%s", + acornscsi_interrupttype[(ssr >> 4)], + acornscsi_interruptcode[acornscsi_map[ssr]]); + else + printk ("%X:%X", ssr >> 4, ssr & 0x0f); +} +#endif + +static +void print_sbic_status (int asr, int ssr, int cmdphase) +{ +#ifdef CONFIG_ACORNSCSI_CONSTANTS + printk ("sbic: %c%c%c%c%c%c ", + asr & ASR_INT ? 'I' : 'i', + asr & ASR_LCI ? 'L' : 'l', + asr & ASR_BSY ? 'B' : 'b', + asr & ASR_CIP ? 'C' : 'c', + asr & ASR_PE ? 'P' : 'p', + asr & ASR_DBR ? 'D' : 'd'); + printk ("scsi: "); + print_scsi_status (ssr); + printk (" ph %02X\n", cmdphase); +#else + printk ("sbic: %02X scsi: %X:%X ph: %02X\n", + asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase); +#endif +} + +static +void acornscsi_dumplog (AS_Host *host, int target) +{ + unsigned int prev; + do { + signed int statptr; + + printk ("%c:", target == 8 ? 'H' : ('0' + target)); + statptr = status_ptr[target] - 10; + + if (statptr < 0) + statptr += 16; + + prev = status[target][statptr].when; + + for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) { + if (status[target][statptr].when) { +#ifdef CONFIG_ACORNSCSI_CONSTANTS + printk ("%c%02X:S=", + status[target][statptr].irq ? '-' : ' ', + status[target][statptr].ph); + print_scsi_status (status[target][statptr].ssr); +#else + printk ("%c%02X:%02X", + status[target][statptr].irq ? '-' : ' ', + status[target][statptr].ph, + status[target][statptr].ssr); +#endif + printk ("+%02ld", + (status[target][statptr].when - prev) < 100 ? + (status[target][statptr].when - prev) : 99); + prev = status[target][statptr].when; + } + } + printk ("\n"); + if (target == 8) + break; + target = 8; + } while (1); +} + +static +char acornscsi_target (AS_Host *host) +{ + if (host->SCpnt) + return '0' + host->SCpnt->target; + return 'H'; +} + +#ifdef USE_DMAC +static +void acornscsi_dumpdma (AS_Host *host, char *where) +{ + unsigned int mode, addr, len; + + mode = dmac_read (host->dma.io_port, MODECON); + addr = dmac_address (host->dma.io_port); + len = dmac_read (host->dma.io_port, TXCNTHI) << 8 | + dmac_read (host->dma.io_port, TXCNTLO); + + printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", + host->host->host_no, where, + mode, addr, (len + 1) & 0xffff, + dmac_read (host->dma.io_port, MASKREG)); + + printk ("DMA @%06x, ", host->dma.start_addr); + printk ("BH @%p +%04x, ", host->scsi.SCp.ptr, + host->scsi.SCp.this_residual); + printk ("DT @+%04x ST @+%04x", host->dma.transferred, + host->scsi.SCp.have_data_in); + printk ("\n"); +} +#endif + +/* + * Prototype: cmdtype_t acornscsi_cmdtype (int command) + * Purpose : differentiate READ from WRITE from other commands + * Params : command - command to interpret + * Returns : CMD_READ - command reads data, + * CMD_WRITE - command writes data, + * CMD_MISC - everything else + */ +static inline +cmdtype_t acornscsi_cmdtype (int command) +{ + switch (command) { + case WRITE_6: case WRITE_10: case WRITE_12: + return CMD_WRITE; + case READ_6: case READ_10: case READ_12: + return CMD_READ; + default: + return CMD_MISC; + } +} + +/* + * Prototype: int acornscsi_datadirection (int command) + * Purpose : differentiate between commands that have a DATA IN phase + * and a DATA OUT phase + * Params : command - command to interpret + * Returns : DATADIR_OUT - data out phase expected + * DATADIR_IN - data in phase expected + */ +static +datadir_t acornscsi_datadirection (int command) +{ + switch (command) { + case CHANGE_DEFINITION: case COMPARE: case COPY: + case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT: + case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER: + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case WRITE_6: case WRITE_10: case WRITE_VERIFY: + case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME: + case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12: + case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW: + case MEDIUM_SCAN: case SEND_VOLUME_TAG: case 0xea: + return DATADIR_OUT; + default: + return DATADIR_IN; + } +} + +/* + * Purpose : provide values for synchronous transfers with 33C93. + * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting + * Modified by Russell King for 8MHz WD33C93A + */ +static struct sync_xfer_tbl { + unsigned int period_ns; + unsigned char reg_value; +} sync_xfer_table[] = { + { 1, 0x20 }, { 249, 0x20 }, { 374, 0x30 }, + { 499, 0x40 }, { 624, 0x50 }, { 749, 0x60 }, + { 874, 0x70 }, { 999, 0x00 }, { 0, 0 } +}; + +/* + * Prototype: int acornscsi_getperiod (unsigned char syncxfer) + * Purpose : period for the synchronous transfer setting + * Params : syncxfer SYNCXFER register value + * Returns : period in ns. + */ +static +int acornscsi_getperiod (unsigned char syncxfer) +{ + int i; + + syncxfer &= 0xf0; + if (syncxfer == 0x10) + syncxfer = 0; + + for (i = 1; sync_xfer_table[i].period_ns; i++) + if (syncxfer == sync_xfer_table[i].reg_value) + return sync_xfer_table[i].period_ns; + return 0; +} + +/* + * Prototype: int round_period (unsigned int period) + * Purpose : return index into above table for a required REQ period + * Params : period - time (ns) for REQ + * Returns : table index + * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting + */ +static inline +int round_period (unsigned int period) +{ + int i; + + for (i = 1; sync_xfer_table[i].period_ns; i++) { + if ((period <= sync_xfer_table[i].period_ns) && + (period > sync_xfer_table[i - 1].period_ns)) + return i; + } + return 7; +} + +/* + * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) + * Purpose : calculate value for 33c93s SYNC register + * Params : period - time (ns) for REQ + * offset - offset in bytes between REQ/ACK + * Returns : value for SYNC register + * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting + */ +static +unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) +{ + return sync_xfer_table[round_period(period)].reg_value | + ((offset < SDTR_SIZE) ? offset : SDTR_SIZE); +} + +/* ==================================================================================== + * Command functions + */ +/* + * Function: acornscsi_kick (AS_Host *host) + * Purpose : kick next command to interface + * Params : host - host to send command to + * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING + * Notes : interrupts are always disabled! + */ +static +intr_ret_t acornscsi_kick (AS_Host *host) +{ + int from_queue = 0; + Scsi_Cmnd *SCpnt; + + /* first check to see if a command is waiting to be executed */ + SCpnt = host->origSCpnt; + host->origSCpnt = NULL; + + /* retrieve next command */ + if (!SCpnt) { + SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns); + if (!SCpnt) + return INTR_IDLE; + + from_queue = 1; + } + + if (host->scsi.disconnectable && host->SCpnt) { + queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + host->scsi.disconnectable = 0; +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n", + host->host->host_no, acornscsi_target (host))); +#endif + host->SCpnt = NULL; + } + + /* + * If we have an interrupt pending, then we may have been reselected. + * In this case, we don't want to write to the registers + */ + if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { + sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target); + sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN); + } + + /* + * claim host busy - all of these must happen atomically wrt + * our interrupt routine. Failure means command loss. + */ + host->scsi.phase = PHASE_CONNECTING; + host->SCpnt = SCpnt; + host->scsi.SCp = SCpnt->SCp; + host->dma.xfer_setup = 0; + host->dma.xfer_required = 0; + +#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT)) + DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n", + host->host->host_no, '0' + SCpnt->target, + SCpnt->cmnd[0])); +#endif + + if (from_queue) { +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + /* + * tagged queueing - allocate a new tag to this command + */ + if (SCpnt->device->tagged_queue) { + SCpnt->device->current_tag += 1; + if (SCpnt->device->current_tag == 0) + SCpnt->device->current_tag = 1; + SCpnt->tag = SCpnt->device->current_tag; + } else +#endif + set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + host->stats.removes += 1; + + switch (acornscsi_cmdtype (SCpnt->cmnd[0])) { + case CMD_WRITE: + host->stats.writes += 1; + break; + case CMD_READ: + host->stats.reads += 1; + break; + case CMD_MISC: + host->stats.miscs += 1; + break; + } + } + + return INTR_PROCESSING; +} + +/* + * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) + * Purpose : complete processing for command + * Params : host - interface that completed + * result - driver byte of result + */ +static +void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) +{ + Scsi_Cmnd *SCpnt = *SCpntp; + + /* clean up */ + sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + + host->stats.fins += 1; + + if (SCpnt) { + *SCpntp = NULL; + + acornscsi_dma_cleanup (host); + + SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status; + + /* + * In theory, this should not happen. In practice, it seems to. + * Only trigger an error if the device attempts to report all happy + * but with untransferred buffers... If we don't do something, then + * data loss will occur. Should we check SCpnt->underflow here? + * It doesn't appear to be set to something meaningful by the higher + * levels all the time. + */ + if (host->scsi.SCp.ptr && result == DID_OK && + acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) { + switch (status_byte (SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", + host->host->host_no, SCpnt->result); + print_command (SCpnt->cmnd); + acornscsi_dumpdma (host, "done"); + acornscsi_dumplog (host, SCpnt->target); + SCpnt->result &= 0xffff; + SCpnt->result |= DID_ERROR << 16; + } + } + + if (!SCpnt->scsi_done) + panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); + + clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + SCpnt->scsi_done (SCpnt); + } else + printk ("scsi%d: null command in acornscsi_done", host->host->host_no); + + host->scsi.phase = PHASE_IDLE; +} + +/* ==================================================================================== + * DMA routines + */ +/* + * Purpose : update SCSI Data Pointer + * Notes : this will only be one SG entry or less + */ +static +void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length) +{ + SCp->ptr += length; + SCp->this_residual -= length; + + if (!SCp->this_residual) { + if (SCp->buffers_residual) { + SCp->buffer++; + SCp->buffers_residual--; + SCp->ptr = (char *)SCp->buffer->address; + SCp->this_residual = SCp->buffer->length; + } else + SCp->ptr = NULL; + } +} + +/* + * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr, + * unsigned int start_addr, unsigned int length) + * Purpose : read data from DMA RAM + * Params : host - host to transfer from + * ptr - DRAM address + * start_addr - host mem address + * length - number of bytes to transfer + * Notes : this will only be one SG entry or less + */ +static +void acornscsi_data_read (AS_Host *host, char *ptr, + unsigned int start_addr, unsigned int length) +{ + extern void __acornscsi_in (int port, char *buf, int len); + unsigned int page, offset, len = length; + + page = (start_addr >> 12); + offset = start_addr & ((1 << 12) - 1); + + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + + while (len > 0) { + unsigned int this_len; + + if (len + offset > (1 << 12)) + this_len = (1 << 12) - offset; + else + this_len = len; + + __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len); + + offset += this_len; + ptr += this_len; + len -= this_len; + + if (offset == (1 << 12)) { + offset = 0; + page ++; + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + } + } + outb (host->card.page_reg, host->card.io_page); +} + +/* + * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr, + * unsigned int start_addr, unsigned int length) + * Purpose : write data to DMA RAM + * Params : host - host to transfer from + * ptr - DRAM address + * start_addr - host mem address + * length - number of bytes to transfer + * Notes : this will only be one SG entry or less + */ +static +void acornscsi_data_write (AS_Host *host, char *ptr, + unsigned int start_addr, unsigned int length) +{ + extern void __acornscsi_out (int port, char *buf, int len); + unsigned int page, offset, len = length; + + page = (start_addr >> 12); + offset = start_addr & ((1 << 12) - 1); + + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + + while (len > 0) { + unsigned int this_len; + + if (len + offset > (1 << 12)) + this_len = (1 << 12) - offset; + else + this_len = len; + + __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len); + + offset += this_len; + ptr += this_len; + len -= this_len; + + if (offset == (1 << 12)) { + offset = 0; + page ++; + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + } + } + outb (host->card.page_reg, host->card.io_page); +} + +/* ========================================================================================= + * On-board DMA routines + */ +#ifdef USE_DMAC +/* + * Prototype: void acornscsi_dmastop (AS_Host *host) + * Purpose : stop all DMA + * Params : host - host on which to stop DMA + * Notes : This is called when leaving DATA IN/OUT phase, + * or when interface is RESET + */ +static inline +void acornscsi_dma_stop (AS_Host *host) +{ + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr (host->dma.io_intr_clear); + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "stop")); +#endif +} + +/* + * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) + * Purpose : setup DMA controller for data transfer + * Params : host - host to setup + * direction - data transfer direction + * Notes : This is called when entering DATA I/O phase, not + * while we're in a DATA I/O phase + */ +static +void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) +{ + unsigned int address, length, mode; + + host->dma.direction = direction; + + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + + if (direction == DMA_OUT) { +#if (DEBUG & DEBUG_NO_WRITE) + if (NO_WRITE & (1 << host->SCpnt->target)) { + printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", + host->host->host_no, acornscsi_target (host)); + return; + } +#endif + mode = DMAC_WRITE; + } else + mode = DMAC_READ; + + /* + * Allocate some buffer space, limited to half the buffer size + */ + length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + if (length) { + host->dma.start_addr = address = host->dma.free_addr; + host->dma.free_addr = (host->dma.free_addr + length) & + (DMAC_BUFFER_SIZE - 1); + + /* + * Transfer data to DMA memory + */ + if (direction == DMA_OUT) + acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + length); + + length -= 1; + dmac_write (host->dma.io_port, TXCNTLO, length); + dmac_write (host->dma.io_port, TXCNTHI, length >> 8); + dmac_write (host->dma.io_port, TXADRLO, address); + dmac_write (host->dma.io_port, TXADRMD, address >> 8); + dmac_write (host->dma.io_port, TXADRHI, 0); + dmac_write (host->dma.io_port, MODECON, mode); + dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "strt")); +#endif + host->dma.xfer_setup = 1; + } +} + +/* + * Function: void acornscsi_dma_cleanup (AS_Host *host) + * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct + * Params : host - host to finish + * Notes : This is called when a command is: + * terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT + * : This must not return until all transfers are completed. + */ +static +void acornscsi_dma_cleanup (AS_Host *host) +{ + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr (host->dma.io_intr_clear); + + /* + * Check for a pending transfer + */ + if (host->dma.xfer_required) { + host->dma.xfer_required = 0; + if (host->dma.direction == DMA_IN) + acornscsi_data_read (host, host->dma.xfer_ptr, + host->dma.xfer_start, host->dma.xfer_length); + } + + /* + * Has a transfer been setup? + */ + if (host->dma.xfer_setup) { + unsigned int transferred; + + host->dma.xfer_setup = 0; + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "clup")); +#endif + + /* + * Calculate number of bytes transferred from DMA. + */ + transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + host->dma.transferred += transferred; + + if (host->dma.direction == DMA_IN) + acornscsi_data_read (host, host->scsi.SCp.ptr, + host->dma.start_addr, transferred); + + /* + * Update SCSI pointers + */ + acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + } +} + +/* + * Function: void acornscsi_dmacintr (AS_Host *host) + * Purpose : handle interrupts from DMAC device + * Params : host - host to process + * Notes : If reading, we schedule the read to main memory & + * allow the transfer to continue. + * : If writing, we fill the onboard DMA memory from main + * memory. + * : Called whenever DMAC finished it's current transfer. + */ +static +void acornscsi_dma_intr (AS_Host *host) +{ + unsigned int address, length, transferred; + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "inti")); +#endif + + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr (host->dma.io_intr_clear); + + /* + * Calculate amount transferred via DMA + */ + transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + host->dma.transferred += transferred; + + /* + * Schedule DMA transfer off board + */ + if (host->dma.direction == DMA_IN) { + host->dma.xfer_start = host->dma.start_addr; + host->dma.xfer_length = transferred; + host->dma.xfer_ptr = host->scsi.SCp.ptr; + host->dma.xfer_required = 1; + } + + acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + + /* + * Allocate some buffer space, limited to half the on-board RAM size + */ + length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + if (length) { + host->dma.start_addr = address = host->dma.free_addr; + host->dma.free_addr = (host->dma.free_addr + length) & + (DMAC_BUFFER_SIZE - 1); + + /* + * Transfer data to DMA memory + */ + if (host->dma.direction == DMA_OUT) + acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + length); + + length -= 1; + dmac_write (host->dma.io_port, TXCNTLO, length); + dmac_write (host->dma.io_port, TXCNTHI, length >> 8); + dmac_write (host->dma.io_port, TXADRLO, address); + dmac_write (host->dma.io_port, TXADRMD, address >> 8); + dmac_write (host->dma.io_port, TXADRHI, 0); + dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "into")); +#endif + } else { + host->dma.xfer_setup = 0; +#if 0 + /* + * If the interface still wants more, then this is an error. + * We give it another byte, but we also attempt to raise an + * attention condition. We continue giving one byte until + * the device recognises the attention. + */ + if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) { + acornscsi_abortcmd (host, host->SCpnt->tag); + + dmac_write (host->dma.io_port, TXCNTLO, 0); + dmac_write (host->dma.io_port, TXCNTHI, 0); + dmac_write (host->dma.io_port, TXADRLO, 0); + dmac_write (host->dma.io_port, TXADRMD, 0); + dmac_write (host->dma.io_port, TXADRHI, 0); + dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + } +#endif + } +} + +/* + * Function: void acornscsi_dma_xfer (AS_Host *host) + * Purpose : transfer data between AcornSCSI and memory + * Params : host - host to process + */ +static +void acornscsi_dma_xfer (AS_Host *host) +{ + host->dma.xfer_required = 0; + + if (host->dma.direction == DMA_IN) + acornscsi_data_read (host, host->dma.xfer_ptr, + host->dma.xfer_start, host->dma.xfer_length); +} + +/* + * Function: void acornscsi_dma_adjust (AS_Host *host) + * Purpose : adjust DMA pointers & count for bytes transfered to + * SBIC but not SCSI bus. + * Params : host - host to adjust DMA count for + */ +static +void acornscsi_dma_adjust (AS_Host *host) +{ + if (host->dma.xfer_setup) { + signed long transferred; +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) + DBG(host->SCpnt, acornscsi_dumpdma (host, "adji")); +#endif + /* + * Calculate correct DMA address - DMA is ahead of SCSI bus while + * writing. + * host->scsi.SCp.have_data_in is the number of bytes + * actually transferred to/from the SCSI bus. + * host->dma.transferred is the number of bytes transferred + * over DMA since host->dma.start_addr was last set. + * + * real_dma_addr = host->dma.start_addr + host->scsi.SCp.have_data_in + * - host->dma.transferred + */ + transferred = host->scsi.SCp.have_data_in - host->dma.transferred; + if (transferred < 0) + printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", + host->host->host_no, acornscsi_target (host), transferred); + else if (transferred == 0) + host->dma.xfer_setup = 0; + else { + transferred += host->dma.start_addr; + dmac_write (host->dma.io_port, TXADRLO, transferred); + dmac_write (host->dma.io_port, TXADRMD, transferred >> 8); + dmac_write (host->dma.io_port, TXADRHI, transferred >> 16); +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) + DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo")); +#endif + } + } +} +#endif + +/* ========================================================================================= + * Data I/O + */ +/* + * Function: void acornscsi_sendcommand (AS_Host *host) + * Purpose : send a command to a target + * Params : host - host which is connected to target + */ +static +void acornscsi_sendcommand (AS_Host *host) +{ + Scsi_Cmnd *SCpnt = host->SCpnt; + unsigned int asr; + unsigned char *cmdptr, *cmdend; + + sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext (host->scsi.io_port, 0); + sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); + acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + + cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command; + cmdend = SCpnt->cmnd + SCpnt->cmd_len; + + while (cmdptr < cmdend) { + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (asr & ASR_DBR) + sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++); + else if (asr & ASR_INT) + break; + } + if (cmdptr >= cmdend) + host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd; + host->scsi.phase = PHASE_COMMAND; +} + +static +void acornscsi_sendmessage (AS_Host *host) +{ + unsigned int message_length = msgqueue_msglength (&host->scsi.msgs); + int msglen; + char *msg; + +#if (DEBUG & DEBUG_MESSAGES) + printk ("scsi%d.%c: sending message ", + host->host->host_no, acornscsi_target (host)); +#endif + + switch (message_length) { + case 0: + acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + sbic_arm_write (host->scsi.io_port, DATA, NOP); + host->scsi.last_message = NOP; +#if (DEBUG & DEBUG_MESSAGES) + printk ("NOP"); +#endif + break; + + case 1: + acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + msg = msgqueue_getnextmsg (&host->scsi.msgs, &msglen); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + sbic_arm_write (host->scsi.io_port, DATA, msg[0]); + host->scsi.last_message = msg[0]; +#if (DEBUG & DEBUG_MESSAGES) + print_msg (msg); +#endif + break; + + default: + /* + * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14) + * 'When a target sends this (MESSAGE_REJECT) message, it + * shall change to MESSAGE IN phase and send this message + * prior to requesting additional message bytes from the + * initiator. This provides an interlock so that the + * initiator can determine which message byte is rejected. + */ + sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext (host->scsi.io_port, 0); + sbic_arm_writenext (host->scsi.io_port, message_length); + acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + + while ((msg = msgqueue_getnextmsg (&host->scsi.msgs, &msglen)) != NULL) { + unsigned int asr, i; +#if (DEBUG & DEBUG_MESSAGES) + print_msg (msg); +#endif + for (i = 0; i < msglen;) { + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (asr & ASR_DBR) + sbic_arm_write (host->scsi.io_port, DATA, msg[i++]); + if (asr & ASR_INT) + break; + } + host->scsi.last_message = msg[0]; + if (msg[0] == EXTENDED_MESSAGE) + host->scsi.last_message |= msg[2] << 8; + if (asr & ASR_INT) + break; + } + break; + } +#if (DEBUG & DEBUG_MESSAGES) + printk ("\n"); +#endif +} + +/* + * Function: void acornscsi_readstatusbyte (AS_Host *host) + * Purpose : Read status byte from connected target + * Params : host - host connected to target + */ +static +void acornscsi_readstatusbyte (AS_Host *host) +{ + acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + + host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA); +} + +/* + * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host) + * Purpose : Read one message byte from connected target + * Params : host - host connected to target + */ +static +unsigned char acornscsi_readmessagebyte (AS_Host *host) +{ + unsigned char message; + + acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + + message = sbic_arm_read (host->scsi.io_port, DATA); + + /* wait for MSGIN-XFER-PAUSED */ + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); + sbic_arm_read (host->scsi.io_port, SSR); + + return message; +} + +/* + * Function: void acornscsi_message (AS_Host *host) + * Purpose : Read complete message from connected target & action message + * Params : host - host connected to target + */ +static +void acornscsi_message (AS_Host *host) +{ + unsigned char message[16]; + unsigned int msgidx = 0, msglen = 1; + + do { + message[msgidx] = acornscsi_readmessagebyte (host); + + switch (msgidx) { + case 0: + if (message[0] == EXTENDED_MESSAGE || + (message[0] >= 0x20 && message[0] <= 0x2f)) + msglen = 2; + break; + + case 1: + if (message[0] == EXTENDED_MESSAGE) + msglen += message[msgidx]; + break; + } + msgidx += 1; + if (msgidx < msglen) { + acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + + /* wait for next msg-in */ + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); + sbic_arm_read (host->scsi.io_port, SSR); + } + } while (msgidx < msglen); + +#if (DEBUG & DEBUG_MESSAGES) + printk (KERN_DEBUG "scsi%d.%c: message in: ", + host->host->host_no, acornscsi_target (host)); + print_msg (message); + printk ("\n"); +#endif + + if (host->scsi.phase == PHASE_RECONNECTED) { + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) + * 'Whenever a target reconnects to an initiator to continue + * a tagged I/O process, the SIMPLE QUEUE TAG message shall + * be sent immediately following the IDENTIFY message...' + */ + if (message[0] == SIMPLE_QUEUE_TAG) + host->scsi.reconnected.tag = message[1]; + if (acornscsi_reconnect_finish (host)) + host->scsi.phase = PHASE_MSGIN; + } + + switch (message[0]) { + case ABORT: + case ABORT_TAG: + case COMMAND_COMPLETE: + if (host->scsi.phase != PHASE_STATUSIN) + printk (KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", + host->host->host_no, acornscsi_target (host)); + host->scsi.phase = PHASE_DONE; + host->scsi.SCp.Message = message[0]; + break; + + case SAVE_POINTERS: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20) + * 'The SAVE DATA POINTER message is sent from a target to + * direct the initiator to copy the active data pointer to + * the saved data pointer for the current I/O process. + */ + acornscsi_dma_cleanup (host); + host->SCpnt->SCp = host->scsi.SCp; + host->SCpnt->SCp.sent_command = 0; + host->scsi.phase = PHASE_MSGIN; + break; + + case RESTORE_POINTERS: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19) + * 'The RESTORE POINTERS message is sent from a target to + * direct the initiator to copy the most recently saved + * command, data, and status pointers for the I/O process + * to the corresponding active pointers. The command and + * status pointers shall be restored to the beginning of + * the present command and status areas.' + */ + acornscsi_dma_cleanup (host); + host->scsi.SCp = host->SCpnt->SCp; + host->scsi.phase = PHASE_MSGIN; + break; + + case DISCONNECT: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2) + * 'On those occasions when an error or exception condition occurs + * and the target elects to repeat the information transfer, the + * target may repeat the transfer either issuing a RESTORE POINTERS + * message or by disconnecting without issuing a SAVE POINTERS + * message. When reconnection is completed, the most recent + * saved pointer values are restored.' + */ + acornscsi_dma_cleanup (host); + host->scsi.phase = PHASE_DISCONNECT; + break; + + case MESSAGE_REJECT: +#if 0 /* this isn't needed any more */ + /* + * If we were negociating sync transfer, we don't yet know if + * this REJECT is for the sync transfer or for the tagged queue/wide + * transfer. Re-initiate sync transfer negociation now, and if + * we got a REJECT in response to SDTR, then it'll be set to DONE. + */ + if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) + host->device[host->SCpnt->target].sync_state = SYNC_NEGOCIATE; +#endif + + /* + * If we have any messages waiting to go out, then assert ATN now + */ + if (msgqueue_msglength (&host->scsi.msgs)) + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + + switch (host->scsi.last_message) { +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) + * If a target does not implement tagged queuing and a queue tag + * message is received, it shall respond with a MESSAGE REJECT + * message and accept the I/O process as if it were untagged. + */ + printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", + host->host->host_no, acornscsi_target (host)); + host->SCpnt->device->tagged_queue = 0; + set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + break; +#endif + case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): + /* + * Target can't handle synchronous transfers + */ + printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", + host->host->host_no, acornscsi_target (host)); + host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA; + host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS; + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + break; + + default: + break; + } + break; + + case QUEUE_FULL: + /* TODO: target queue is full */ + break; + + case SIMPLE_QUEUE_TAG: + /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ + printk ("scsi%d.%c: reconnect queue tag %02X\n", + host->host->host_no, acornscsi_target (host), + message[1]); + break; + + case EXTENDED_MESSAGE: + switch (message[2]) { +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + case EXTENDED_SDTR: + if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) { + /* + * We requested synchronous transfers. This isn't quite right... + * We can only say if this succeeded if we proceed on to execute the + * command from this message. If we get a MESSAGE PARITY ERROR, + * and the target retries fail, then we fallback to asynchronous mode + */ + host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED; + printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", + host->host->host_no, acornscsi_target(host), + message[4], message[3] * 4); + host->device[host->SCpnt->target].sync_xfer = + calc_sync_xfer (message[3] * 4, message[4]); + } else { + unsigned char period, length; + /* + * Target requested synchronous transfers. The agreement is only + * to be in operation AFTER the target leaves message out phase. + */ + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + period = max (message[3], sdtr_period / 4); + length = min (message[4], sdtr_size); + msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, + EXTENDED_SDTR, period, length); + host->device[host->SCpnt->target].sync_xfer = + calc_sync_xfer (period * 4, length); + } + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + break; +#else + /* We do not accept synchronous transfers. Respond with a + * MESSAGE_REJECT. + */ +#endif + + case EXTENDED_WDTR: + /* The WD33C93A is only 8-bit. We respond with a MESSAGE_REJECT + * to a wide data transfer request. + */ + default: + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_flush (&host->scsi.msgs); + msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + break; + } + break; + +#ifdef CONFIG_SCSI_ACORNSCSI_LINK + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* + * We don't support linked commands yet + */ + if (0) { +#if (DEBUG & DEBUG_LINK) + printk (KERN_DEBUG "scsi%d.%c: lun %d tag %d linked command complete\n", + host->host->host_no, acornscsi_target(host), host->SCpnt->tag); +#endif + /* + * A linked command should only terminate with one of these messages + * if there are more linked commands available. + */ + if (!host->SCpnt->next_link) { + printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", + instance->host_no, acornscsi_target (host), host->SCpnt->tag); + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + } else { + Scsi_Cmnd *SCpnt = host->SCpnt; + + acornscsi_dma_cleanup (host); + + host->SCpnt = host->SCpnt->next_link; + host->SCpnt->tag = SCpnt->tag; + SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; + SCpnt->done (SCpnt); + + /* initialise host->SCpnt->SCp */ + } + break; + } +#endif + + default: /* reject message */ + printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", + host->host->host_no, acornscsi_target (host), + message[0]); + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_flush (&host->scsi.msgs); + msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + host->scsi.phase = PHASE_MSGIN; + break; + } + acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); +} + +/* + * Function: int acornscsi_buildmessages (AS_Host *host) + * Purpose : build the connection messages for a host + * Params : host - host to add messages to + */ +static +void acornscsi_buildmessages (AS_Host *host) +{ +#if 0 + /* does the device need resetting? */ + if (cmd_reset) { + msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET); + return; + } +#endif + + msgqueue_addmsg (&host->scsi.msgs, 1, + IDENTIFY(host->device[host->SCpnt->target].disconnect_ok, + host->SCpnt->lun)); + +#if 0 + /* does the device need the current command aborted */ + if (cmd_aborted) { + acornscsi_abortcmd (host->SCpnt->tag); + return; + } +#endif + +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + if (host->SCpnt->tag) { + unsigned int tag_type; + + if (host->SCpnt->cmnd[0] == REQUEST_SENSE || + host->SCpnt->cmnd[0] == TEST_UNIT_READY || + host->SCpnt->cmnd[0] == INQUIRY) + tag_type = HEAD_OF_QUEUE_TAG; + else + tag_type = SIMPLE_QUEUE_TAG; + msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); + } +#endif + +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) { + host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST; + msgqueue_addmsg (&host->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + sdtr_period / 4, sdtr_size); + } +#endif +} + +/* + * Function: int acornscsi_starttransfer (AS_Host *host) + * Purpose : transfer data to/from connected target + * Params : host - host to which target is connected + * Returns : 0 if failure + */ +static +int acornscsi_starttransfer (AS_Host *host) +{ + int residual; + + if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { + printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", + host->host->host_no, acornscsi_target (host)); + return 0; + } + + residual = host->SCpnt->request_bufflen - host->scsi.SCp.have_data_in; + + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_writenext (host->scsi.io_port, residual >> 16); + sbic_arm_writenext (host->scsi.io_port, residual >> 8); + sbic_arm_writenext (host->scsi.io_port, residual); + acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + return 1; +} + +/* ========================================================================================= + * Connection & Disconnection + */ +/* + * Function : acornscsi_reconnect (AS_Host *host) + * Purpose : reconnect a previously disconnected command + * Params : host - host specific data + * Remarks : SCSI spec says: + * 'The set of active pointers is restored from the set + * of saved pointers upon reconnection of the I/O process' + */ +static +int acornscsi_reconnect (AS_Host *host) +{ + unsigned int target, lun, ok = 0; + + target = sbic_arm_read (host->scsi.io_port, SOURCEID); + + if (!(target & 8)) + printk (KERN_ERR "scsi%d: invalid source id after reselection " + "- device fault?\n", + host->host->host_no); + + target &= 7; + + if (host->SCpnt && !host->scsi.disconnectable) { + printk (KERN_ERR "scsi%d.%d: reconnected while command in " + "progress to target %d?\n", + host->host->host_no, target, host->SCpnt->target); + host->SCpnt = NULL; + } + + lun = sbic_arm_read (host->scsi.io_port, DATA) & 7; + + host->scsi.reconnected.target = target; + host->scsi.reconnected.lun = lun; + host->scsi.reconnected.tag = 0; + + if (host->scsi.disconnectable && host->SCpnt && + host->SCpnt->target == target && host->SCpnt->lun == lun) + ok = 1; + + if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun)) + ok = 1; + + ADD_STATUS(target, 0x81, host->scsi.phase, 0); + + if (ok) { + host->scsi.phase = PHASE_RECONNECTED; + } else { + /* this doesn't seem to work */ + printk (KERN_ERR "scsi%d.%c: reselected with no command " + "to reconnect with\n", + host->host->host_no, '0' + target); + acornscsi_dumplog (host, target); + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + host->scsi.phase = PHASE_ABORTED; + } + acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + return !ok; +} + +/* + * Function: int acornscsi_reconect_finish (AS_Host *host) + * Purpose : finish reconnecting a command + * Params : host - host to complete + * Returns : 0 if failed + */ +static +int acornscsi_reconnect_finish (AS_Host *host) +{ + if (host->scsi.disconnectable && host->SCpnt) { + host->scsi.disconnectable = 0; + if (host->SCpnt->target == host->scsi.reconnected.target && + host->SCpnt->lun == host->scsi.reconnected.lun && + host->SCpnt->tag == host->scsi.reconnected.tag) { +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: reconnected", + host->host->host_no, acornscsi_target (host))); +#endif + } else { + queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: had to move command " + "to disconnected queue\n", + host->host->host_no, acornscsi_target (host))); +#endif + host->SCpnt = NULL; + } + } + if (!host->SCpnt) { + host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected, + host->scsi.reconnected.target, + host->scsi.reconnected.lun, + host->scsi.reconnected.tag); +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: had to get command", + host->host->host_no, acornscsi_target (host))); +#endif + } + + if (!host->SCpnt) { + acornscsi_abortcmd (host, host->scsi.reconnected.tag); + host->scsi.phase = PHASE_ABORTED; + } else { + /* + * Restore data pointer from SAVED pointers. + */ + host->scsi.SCp = host->SCpnt->SCp; +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + printk (", data pointers: [%p, %X]", + host->scsi.SCp.ptr, host->scsi.SCp.this_residual); +#endif + } +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + printk ("\n"); +#endif + + host->dma.transferred = host->scsi.SCp.have_data_in; + + return host->SCpnt != NULL; +} + +/* + * Function: void acornscsi_disconnect_unexpected (AS_Host *host) + * Purpose : handle an unexpected disconnect + * Params : host - host on which disconnect occurred + */ +static +void acornscsi_disconnect_unexpected (AS_Host *host) +{ + printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n", + host->host->host_no, acornscsi_target (host)); +#if (DEBUG & DEBUG_ABORT) + acornscsi_dumplog (host, 8); +#endif + + acornscsi_done (host, &host->SCpnt, DID_ABORT); +} + +/* + * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag) + * Purpose : abort a currently executing command + * Params : host - host with connected command to abort + * tag - tag to abort + */ +static +void acornscsi_abortcmd (AS_Host *host, unsigned char tag) +{ + sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN); + + msgqueue_flush (&host->scsi.msgs); +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + if (tag) + msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag); + else +#endif + msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); +} + +/* ========================================================================================== + * Interrupt routines. + */ +/* + * Function: int acornscsi_sbicintr (AS_Host *host) + * Purpose : handle interrupts from SCSI device + * Params : host - host to process + * Returns : INTR_PROCESS if expecting another SBIC interrupt + * INTR_IDLE if no interrupt + * INTR_NEXT_COMMAND if we have finished processing the command + */ +static +intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq) +{ + unsigned int asr, ssr; + + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (!(asr & ASR_INT)) + return INTR_IDLE; + + ssr = sbic_arm_read (host->scsi.io_port, SSR); + +#if (DEBUG & DEBUG_PHASES) + print_sbic_status(asr, ssr, host->scsi.phase); +#endif + + ADD_STATUS(8, ssr, host->scsi.phase, in_irq); + + if (host->SCpnt && !host->scsi.disconnectable) + ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); + + switch (ssr) { + case 0x00: /* reset state - not advanced */ + printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", + host->host->host_no); + /* setup sbic - WD33C93A */ + sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + return INTR_IDLE; + + case 0x01: /* reset state - advanced */ + sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + msgqueue_flush (&host->scsi.msgs); + return INTR_IDLE; + + case 0x41: /* unexpected disconnect aborted command */ + acornscsi_disconnect_unexpected (host); + return INTR_NEXT_COMMAND; + } + + switch (host->scsi.phase) { + case PHASE_CONNECTING: /* STATE: command removed from issue queue */ + switch (ssr) { + case 0x11: /* -> PHASE_CONNECTED */ + /* BUS FREE -> SELECTION */ + host->scsi.phase = PHASE_CONNECTED; + msgqueue_flush (&host->scsi.msgs); + host->dma.transferred = host->scsi.SCp.have_data_in; + /* 33C93 gives next interrupt indicating bus phase */ + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (!(asr & ASR_INT)) + break; + ssr = sbic_arm_read (host->scsi.io_port, SSR); + ADD_STATUS(8, ssr, host->scsi.phase, 1); + ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1); + goto connected; + + case 0x42: /* select timed out */ + /* -> PHASE_IDLE */ + acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT); + return INTR_NEXT_COMMAND; + + case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ + /* BUS FREE -> RESELECTION */ + host->origSCpnt = host->SCpnt; + host->SCpnt = NULL; + msgqueue_flush (&host->scsi.msgs); + acornscsi_reconnect (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd (host, host->SCpnt->tag); + } + return INTR_PROCESSING; + + connected: + case PHASE_CONNECTED: /* STATE: device selected ok */ + switch (ssr) { +#ifdef NONSTANDARD + case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + /* SELECTION -> COMMAND */ + acornscsi_sendcommand (host); + break; + + case 0x8b: /* -> PHASE_STATUS */ + /* SELECTION -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; +#endif + + case 0x8e: /* -> PHASE_MSGOUT */ + /* SELECTION ->MESSAGE OUT */ + host->scsi.phase = PHASE_MSGOUT; + acornscsi_buildmessages (host); + acornscsi_sendmessage (host); + break; + + /* these should not happen */ + case 0x85: /* target disconnected */ + acornscsi_done (host, &host->SCpnt, DID_ERROR); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd (host, host->SCpnt->tag); + } + return INTR_PROCESSING; + + case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ + /* + * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase + */ + switch (ssr) { + case 0x8a: + case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + /* MESSAGE OUT -> COMMAND */ + acornscsi_sendcommand (host); + break; + + case 0x1b: /* -> PHASE_STATUS */ + /* MESSAGE OUT -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x8e: /* -> PHASE_MSGOUT */ + /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x4f: + case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + /* MESSAGE OUT -> MESSAGE IN */ + acornscsi_message (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_COMMAND: /* STATE: connected & command sent */ + switch (ssr) { + case 0x18: /* -> PHASE_DATAOUT */ + /* COMMAND -> DATA OUT */ + if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) + acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup (host, DMA_OUT); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAOUT; + return INTR_IDLE; + + case 0x19: /* -> PHASE_DATAIN */ + /* COMMAND -> DATA IN */ + if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) + acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup (host, DMA_IN); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAIN; + return INTR_IDLE; + + case 0x1b: /* -> PHASE_STATUS */ + /* COMMAND -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + /* COMMAND -> MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + /* COMMAND -> MESSAGE IN */ + acornscsi_message (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DISCONNECT: /* STATE: connected, received DISCONNECT msg */ + if (ssr == 0x85) { /* -> PHASE_IDLE */ + host->scsi.disconnectable = 1; + host->scsi.reconnected.tag = 0; + host->scsi.phase = PHASE_IDLE; + host->stats.disconnects += 1; + } else { + printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_NEXT_COMMAND; + + case PHASE_IDLE: /* STATE: disconnected */ + if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ + acornscsi_reconnect (host); + else { + printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_RECONNECTED: /* STATE: device reconnected to initiator */ + /* + * Command reconnected - if MESGIN, get message - it may be + * the tag. If not, get command out of disconnected queue + */ + /* + * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, + * reconnect I_T_L command + */ + if (ssr != 0x8f && !acornscsi_reconnect_finish (host)) + return INTR_IDLE; + ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); + switch (ssr) { + case 0x88: /* data out phase */ + /* -> PHASE_DATAOUT */ + /* MESSAGE IN -> DATA OUT */ + acornscsi_dma_setup (host, DMA_OUT); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAOUT; + return INTR_IDLE; + + case 0x89: /* data in phase */ + /* -> PHASE_DATAIN */ + /* MESSAGE IN -> DATA IN */ + acornscsi_dma_setup (host, DMA_IN); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAIN; + return INTR_IDLE; + + case 0x8a: /* command out */ + /* MESSAGE IN -> COMMAND */ + acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + break; + + case 0x8b: /* status in */ + /* -> PHASE_STATUSIN */ + /* MESSAGE IN -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x8e: /* message out */ + /* -> PHASE_MSGOUT */ + /* MESSAGE IN -> MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x8f: /* message in */ + acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DATAIN: /* STATE: transferred data in */ + /* + * This is simple - if we disconnect then the DMA address & count is + * correct. + */ + switch (ssr) { + case 0x19: /* -> PHASE_DATAIN */ + acornscsi_abortcmd (host, host->SCpnt->tag); + return INTR_IDLE; + + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x1b: /* -> PHASE_STATUSIN */ + /* DATA IN -> STATUS */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x4e: /* -> PHASE_MSGOUT */ + /* DATA IN -> MESSAGE OUT */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_sendmessage (host); + break; + + case 0x1f: /* message in */ + case 0x4f: /* message in */ + /* DATA IN -> MESSAGE IN */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DATAOUT: /* STATE: transferred data out */ + /* + * This is more complicated - if we disconnect, the DMA could be 12 + * bytes ahead of us. We need to correct this. + */ + switch (ssr) { + case 0x18: /* -> PHASE_DATAOUT */ + acornscsi_abortcmd (host, host->SCpnt->tag); + return INTR_IDLE; + + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x1b: /* -> PHASE_STATUSIN */ + /* DATA OUT -> STATUS */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_dma_adjust (host); + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x4e: /* -> PHASE_MSGOUT */ + /* DATA OUT -> MESSAGE OUT */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_dma_adjust (host); + acornscsi_sendmessage (host); + break; + + case 0x1f: /* message in */ + case 0x4f: /* message in */ + /* DATA OUT -> MESSAGE IN */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_dma_adjust (host); + acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_STATUSIN: /* STATE: status in complete */ + if (ssr == 0x1f) /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + /* STATUS -> MESSAGE IN */ + acornscsi_message (host); + else if (ssr == 0x1e) /* -> PHASE_MSGOUT */ + /* STATUS -> MESSAGE OUT */ + acornscsi_sendmessage (host); + else { + printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_MSGIN: /* STATE: message in */ + switch (ssr) { + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x4e: /* -> PHASE_MSGOUT */ + /* MESSAGE IN -> MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + case 0x2f: + case 0x4f: + case 0x8f: + acornscsi_message (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DONE: /* STATE: received status & message */ + switch (ssr) { + case 0x85: /* -> PHASE_IDLE */ + acornscsi_done (host, &host->SCpnt, DID_OK); + return INTR_NEXT_COMMAND; + + case 0x8e: + acornscsi_sendmessage (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_ABORTED: + switch (ssr) { + case 0x85: + acornscsi_done (host, &host->SCpnt, DID_ABORT); + return INTR_NEXT_COMMAND; + + case 0x1e: + case 0x2e: + case 0x4e: + case 0x8e: + acornscsi_sendmessage (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + default: + printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; +} + +/* + * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) + * Purpose : handle interrupts from Acorn SCSI card + * Params : irq - interrupt number + * dev_id - device specific data (AS_Host structure) + * regs - processor registers when interrupt occurred + */ +static +void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + AS_Host *host = (AS_Host *)dev_id; + intr_ret_t ret; + int iostatus; + int in_irq = 0; + + if (host->scsi.interrupt) + printk ("scsi%d: interrupt re-entered\n", host->host->host_no); + host->scsi.interrupt = 1; + + do { + ret = INTR_IDLE; + + iostatus = inb (host->card.io_intr); + + if (iostatus & 2) { + acornscsi_dma_intr (host); + iostatus = inb (host->card.io_intr); + } + + if (iostatus & 8) + ret = acornscsi_sbicintr (host, in_irq); + + /* + * If we have a transfer pending, start it. + * Only start it if the interface has already started transferring + * it's data + */ + if (host->dma.xfer_required) + acornscsi_dma_xfer (host); + + if (ret == INTR_NEXT_COMMAND) + ret = acornscsi_kick (host); + + in_irq = 1; + } while (ret != INTR_IDLE); + + host->scsi.interrupt = 0; +} + +/*============================================================================================= + * Interfaces between interrupt handler and rest of scsi code + */ + +/* + * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + * Purpose : queues a SCSI command + * Params : cmd - SCSI command + * done - function called on completion, with pointer to command descriptor + * Returns : 0, or < 0 on error. + */ +int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + AS_Host *host = (AS_Host *)SCpnt->host->hostdata; + + if (!done) { + /* there should be some way of rejecting errors like this without panicing... */ + panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]", + SCpnt->host->host_no, SCpnt); + return -EINVAL; + } + +#if (DEBUG & DEBUG_NO_WRITE) + if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { + printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", + SCpnt->host->host_no, '0' + SCpnt->target); + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return 0; + } +#endif + + SCpnt->scsi_done = done; + SCpnt->host_scribble = NULL; + SCpnt->result = 0; + SCpnt->tag = 0; + SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]); + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.Status = 0; + SCpnt->SCp.Message = 0; + + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + } else { + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + } + + host->stats.queues += 1; + + { + unsigned long flags; + + if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) { + SCpnt->result = DID_ERROR << 16; + done (SCpnt); + return 0; + } + save_flags_cli (flags); + if (host->scsi.phase == PHASE_IDLE) + acornscsi_kick (host); + restore_flags (flags); + } + return 0; +} + +/* + * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) + * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 + * Params : SCpntp1 - pointer to command to return + * SCpntp2 - pointer to command to check + * result - result to pass back to mid-level done function + * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. + */ +static inline +void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) +{ + Scsi_Cmnd *SCpnt = *SCpntp1; + + if (SCpnt) { + *SCpntp1 = NULL; + + SCpnt->result = result; + SCpnt->scsi_done (SCpnt); + } + + if (SCpnt == *SCpntp2) + *SCpntp2 = NULL; +} + +/* + * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt) + * Purpose : abort a command on this host + * Params : SCpnt - command to abort + * Returns : one of SCSI_ABORT_ macros + */ +int acornscsi_abort (Scsi_Cmnd *SCpnt) +{ + AS_Host *host = (AS_Host *) SCpnt->host->hostdata; + int result = SCSI_ABORT_NOT_RUNNING; + + host->stats.aborts += 1; + +#if (DEBUG & DEBUG_ABORT) + { + int asr, ssr; + asr = sbic_arm_read (host->scsi.io_port, ASR); + ssr = sbic_arm_read (host->scsi.io_port, SSR); + + printk (KERN_WARNING "acornscsi_abort: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog (host, SCpnt->target); + } +#endif + + if (queue_removecmd (&host->queues.issue, SCpnt)) { + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); +#if (DEBUG & DEBUG_ABORT) + printk ("scsi%d: command on issue queue\n", host->host->host_no); +#endif + result = SCSI_ABORT_SUCCESS; + } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) { + printk ("scsi%d: command on disconnected queue\n", host->host->host_no); + result = SCSI_ABORT_SNOOZE; + } else if (host->SCpnt == SCpnt) { + acornscsi_abortcmd (host, host->SCpnt->tag); + printk ("scsi%d: command executing\n", host->host->host_no); + result = SCSI_ABORT_SNOOZE; + } else if (host->origSCpnt == SCpnt) { + host->origSCpnt = NULL; + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); +#if (DEBUG & DEBUG_ABORT) + printk ("scsi%d: command waiting for execution\n", host->host->host_no); +#endif + result = SCSI_ABORT_SUCCESS; + } + + if (result == SCSI_ABORT_NOT_RUNNING) { + printk ("scsi%d: abort(): command not running\n", host->host->host_no); + acornscsi_dumplog (host, SCpnt->target); +#if (DEBUG & DEBUG_ABORT) + result = SCSI_ABORT_SNOOZE; +#endif + } + return result; +} + +/* + * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Purpose : reset a command on this host/reset this host + * Params : SCpnt - command causing reset + * result - what type of reset to perform + * Returns : one of SCSI_RESET_ macros + */ +int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + AS_Host *host = (AS_Host *)SCpnt->host->hostdata; + Scsi_Cmnd *SCptr; + + host->stats.resets += 1; + +#if (DEBUG & DEBUG_RESET) + { + int asr, ssr; + + asr = sbic_arm_read (host->scsi.io_port, ASR); + ssr = sbic_arm_read (host->scsi.io_port, SSR); + + printk (KERN_WARNING "acornscsi_reset: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog (host, SCpnt->target); + } +#endif + + acornscsi_dma_stop (host); + + SCptr = host->SCpnt; + + /* + * do hard reset. This resets all devices on this host, and so we + * must set the reset status on all commands. + */ + acornscsi_resetcard (host); + + /* + * report reset on commands current connected/disconnected + */ + acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET); + + while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL) + acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET); + + if (SCpnt) { + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done (SCpnt); + } +while (1); + return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS; +} + +/*============================================================================================== + * initialisation & miscellaneous support + */ +static struct expansion_card *ecs[MAX_ECARDS]; + +/* + * Prototype: void acornscsi_init (AS_Host *host) + * Purpose : initialise the AS_Host structure for one interface & setup hardware + * Params : host - host to setup + */ +static +void acornscsi_init (AS_Host *host) +{ + memset (&host->stats, 0, sizeof (host->stats)); + queue_initialise (&host->queues.issue); + queue_initialise (&host->queues.disconnected); + msgqueue_initialise (&host->scsi.msgs); + + acornscsi_resetcard (host); +} + +int acornscsi_detect(Scsi_Host_Template * tpnt) +{ + static const card_ids acornscsi_cids[] = { ACORNSCSI_LIST, { 0xffff, 0xffff } }; + int i, count = 0; + struct Scsi_Host *instance; + AS_Host *host; + + tpnt->proc_dir = &proc_scsi_acornscsi; + + for (i = 0; i < MAX_ECARDS; i++) + ecs[i] = NULL; + + ecard_startfind (); + + while(1) { + ecs[count] = ecard_find(0, acornscsi_cids); + if (!ecs[count]) + break; + + if (ecs[count]->irq == 0xff) { + printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); + continue; + } + + ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */ + + instance = scsi_register (tpnt, sizeof(AS_Host)); + host = (AS_Host *)instance->hostdata; + + instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->irq = ecs[count]->irq; + + host->host = instance; + host->scsi.io_port = ioaddr (instance->io_port + 0x800); + host->scsi.irq = instance->irq; + host->card.io_intr = POD_SPACE(instance->io_port) + 0x800; + host->card.io_page = POD_SPACE(instance->io_port) + 0xc00; + host->card.io_ram = ioaddr (instance->io_port); + host->dma.io_port = instance->io_port + 0xc00; + host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800; + + request_region (instance->io_port + 0x800, 2, "acornscsi(sbic)"); + request_region (host->card.io_intr, 1, "acornscsi(intr)"); + request_region (host->card.io_page, 1, "acornscsi(page)"); +#ifdef USE_DMAC + request_region (host->dma.io_port, 256, "acornscsi(dmac)"); +#endif + request_region (instance->io_port, 2048, "acornscsi(ram)"); + + if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) { + printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, host->scsi.irq); + host->scsi.irq = NO_IRQ; + } + + acornscsi_init (host); + + ++count; + } + return count; +} + +/* + * Function: int acornscsi_release (struct Scsi_Host *host) + * Purpose : release all resources used by this adapter + * Params : host - driver structure to release + * Returns : nothing of any consequence + */ +int acornscsi_release (struct Scsi_Host *instance) +{ + AS_Host *host = (AS_Host *)instance->hostdata; + int i; + + /* + * Put card into RESET state + */ + outb (0x80, host->card.io_page); + + if (host->scsi.irq != NO_IRQ) + free_irq (host->scsi.irq, host); + + release_region (instance->io_port + 0x800, 2); + release_region (host->card.io_intr, 1); + release_region (host->card.io_page, 1); + release_region (host->dma.io_port, 256); + release_region (instance->io_port, 2048); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) + ecard_release (ecs[i]); + + msgqueue_free (&host->scsi.msgs); + queue_free (&host->queues.disconnected); + queue_free (&host->queues.issue); + + return 0; +} + +/* + * Function: char *acornscsi_info (struct Scsi_Host *host) + * Purpose : return a string describing this interface + * Params : host - host to give information on + * Returns : a constant string + */ +const +char *acornscsi_info(struct Scsi_Host *host) +{ + static char string[100], *p; + + p = string; + + p += sprintf (string, "%s at port %X irq %d v%d.%d.%d" +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + " SYNC" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + " TAG" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_LINK + " LINK" +#endif +#if (DEBUG & DEBUG_NO_WRITE) + " NOWRITE ("NO_WRITE_STR")" +#endif + , host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH); + return string; +} + +int acornscsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin = 0, devidx; + struct Scsi_Host *instance = scsi_hostlist; + Scsi_Device *scd; + AS_Host *host; + char *p = buffer; + + for (instance = scsi_hostlist; + instance && instance->host_no != host_no; + instance = instance->next); + + if (inout == 1 || !instance) + return -EINVAL; + + host = (AS_Host *)instance->hostdata; + + p += sprintf (p, "AcornSCSI driver v%d.%d.%d" +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + " SYNC" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + " TAG" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_LINK + " LINK" +#endif +#if (DEBUG & DEBUG_NO_WRITE) + " NOWRITE ("NO_WRITE_STR")" +#endif + "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH); + + p += sprintf (p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", + host->scsi.io_port, host->scsi.irq); +#ifdef USE_DMAC + p += sprintf (p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", + host->dma.io_port, host->scsi.irq); +#endif + + p += sprintf (p, "Statistics:\n", + "Queued commands: %-10d Issued commands: %-10d\n" + "Done commands : %-10d Reads : %-10d\n" + "Writes : %-10d Others : %-10d\n" + "Disconnects : %-10d Aborts : %-10d\n" + "Resets : %-10d\n\nLast phases:", + host->stats.queues, host->stats.removes, + host->stats.fins, host->stats.reads, + host->stats.writes, host->stats.miscs, + host->stats.disconnects, host->stats.aborts, + host->stats.resets); + + for (devidx = 0; devidx < 9; devidx ++) { + unsigned int statptr, prev; + + p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); + statptr = status_ptr[devidx] - 10; + + if ((signed int)statptr < 0) + statptr += 16; + + prev = status[devidx][statptr].when; + + for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) { + if (status[devidx][statptr].when) { + p += sprintf (p, "%c%02X:%02X+%2ld", + status[devidx][statptr].irq ? '-' : ' ', + status[devidx][statptr].ph, + status[devidx][statptr].ssr, + (status[devidx][statptr].when - prev) < 100 ? + (status[devidx][statptr].when - prev) : 99); + prev = status[devidx][statptr].when; + } + } + } + + p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); + + for (scd = instance->host_queue; scd; scd = scd->next) { + int len; + + proc_print_scsidevice (scd, p, &len, 0); + p += len; + + p += sprintf (p, "Extensions: "); + + if (scd->tagged_supported) + p += sprintf (p, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", scd->current_tag); + p += sprintf (p, "\nTransfers: "); + if (host->device[scd->id].sync_xfer & 15) + p += sprintf (p, "sync, offset %d, %d ns\n", + host->device[scd->id].sync_xfer & 15, + acornscsi_getperiod (host->device[scd->id].sync_xfer)); + else + p += sprintf (p, "async\n"); + + pos = p - buffer; + if (pos + begin < offset) { + begin += pos; + p = buffer; + } + pos = p - buffer; + if (pos + begin > offset + length) + break; + } + + pos = p - buffer; + + *start = buffer + (offset - begin); + pos -= offset - begin; + + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = ACORNSCSI_3; + +#include "../../scsi/scsi_module.c" +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/acornscsi.h linux/drivers/acorn/scsi/acornscsi.h --- v2.1.87/linux/drivers/acorn/scsi/acornscsi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/acornscsi.h Sun Dec 28 09:06:25 1997 @@ -0,0 +1,378 @@ +#ifndef ACORNSCSI_H +#define ACORNSCSI_H + +#ifndef ASM +extern int acornscsi_detect (Scsi_Host_Template *); +extern int acornscsi_release (struct Scsi_Host *); +extern const char *acornscsi_info (struct Scsi_Host *); +extern int acornscsi_queuecmd (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int acornscsi_abort (Scsi_Cmnd *); +extern int acornscsi_reset (Scsi_Cmnd *, unsigned int); +extern int acornscsi_proc_info (char *, char **, off_t, int, int, int); +extern int acornscsi_biosparam (Disk *, kdev_t, int []); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#ifndef PROC_SCSI_AKA30 +#include "linux/proc_fs.h" +#define PROC_SCSI_AKA30 PROC_SCSI_EATA +#endif + +#include + +#define ACORNSCSI_3 { \ +proc_info: acornscsi_proc_info, \ +name: "AcornSCSI", \ +detect: acornscsi_detect, \ +release: acornscsi_release, /* Release */ \ +info: acornscsi_info, \ +queuecommand: acornscsi_queuecmd, \ +abort: acornscsi_abort, \ +reset: acornscsi_reset, \ +bios_param: scsicam_bios_param, \ +can_queue: CAN_QUEUE, /* can_queue */ \ +this_id: 7, /* this id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd_per_lun */ \ +unchecked_isa_dma: 0, /* unchecked isa dma */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +/* SBIC registers */ +#define OWNID 0 +#define OWNID_FS1 (1<<7) +#define OWNID_FS2 (1<<6) +#define OWNID_EHP (1<<4) +#define OWNID_EAF (1<<3) + +#define CTRL 1 +#define CTRL_DMAMODE (1<<7) +#define CTRL_DMADBAMODE (1<<6) +#define CTRL_DMABURST (1<<5) +#define CTRL_DMAPOLLED 0 +#define CTRL_HHP (1<<4) +#define CTRL_EDI (1<<3) +#define CTRL_IDI (1<<2) +#define CTRL_HA (1<<1) +#define CTRL_HSP (1<<0) + +#define TIMEOUT 2 +#define TOTSECTS 3 +#define TOTHEADS 4 +#define TOTCYLH 5 +#define TOTCYLL 6 +#define LOGADDRH 7 +#define LOGADDRM2 8 +#define LOGADDRM1 9 +#define LOGADDRL 10 +#define SECTORNUM 11 +#define HEADNUM 12 +#define CYLH 13 +#define CYLL 14 +#define TARGETLUN 15 +#define TARGETLUN_TLV (1<<7) +#define TARGETLUN_DOK (1<<6) + +#define CMNDPHASE 16 +#define SYNCHTRANSFER 17 +#define SYNCHTRANSFER_OF0 0x00 +#define SYNCHTRANSFER_OF1 0x01 +#define SYNCHTRANSFER_OF2 0x02 +#define SYNCHTRANSFER_OF3 0x03 +#define SYNCHTRANSFER_OF4 0x04 +#define SYNCHTRANSFER_OF5 0x05 +#define SYNCHTRANSFER_OF6 0x06 +#define SYNCHTRANSFER_OF7 0x07 +#define SYNCHTRANSFER_OF8 0x08 +#define SYNCHTRANSFER_OF9 0x09 +#define SYNCHTRANSFER_OF10 0x0A +#define SYNCHTRANSFER_OF11 0x0B +#define SYNCHTRANSFER_OF12 0x0C +#define SYNCHTRANSFER_8DBA 0x00 +#define SYNCHTRANSFER_2DBA 0x20 +#define SYNCHTRANSFER_3DBA 0x30 +#define SYNCHTRANSFER_4DBA 0x40 +#define SYNCHTRANSFER_5DBA 0x50 +#define SYNCHTRANSFER_6DBA 0x60 +#define SYNCHTRANSFER_7DBA 0x70 + +#define TRANSCNTH 18 +#define TRANSCNTM 19 +#define TRANSCNTL 20 +#define DESTID 21 +#define DESTID_SCC (1<<7) +#define DESTID_DPD (1<<6) + +#define SOURCEID 22 +#define SOURCEID_ER (1<<7) +#define SOURCEID_ES (1<<6) +#define SOURCEID_DSP (1<<5) +#define SOURCEID_SIV (1<<4) + +#define SSR 23 +#define CMND 24 +#define CMND_RESET 0x00 +#define CMND_ABORT 0x01 +#define CMND_ASSERTATN 0x02 +#define CMND_NEGATEACK 0x03 +#define CMND_DISCONNECT 0x04 +#define CMND_RESELECT 0x05 +#define CMND_SELWITHATN 0x06 +#define CMND_SELECT 0x07 +#define CMND_SELECTATNTRANSFER 0x08 +#define CMND_SELECTTRANSFER 0x09 +#define CMND_RESELECTRXDATA 0x0A +#define CMND_RESELECTTXDATA 0x0B +#define CMND_WAITFORSELRECV 0x0C +#define CMND_SENDSTATCMD 0x0D +#define CMND_SENDDISCONNECT 0x0E +#define CMND_SETIDI 0x0F +#define CMND_RECEIVECMD 0x10 +#define CMND_RECEIVEDTA 0x11 +#define CMND_RECEIVEMSG 0x12 +#define CMND_RECEIVEUSP 0x13 +#define CMND_SENDCMD 0x14 +#define CMND_SENDDATA 0x15 +#define CMND_SENDMSG 0x16 +#define CMND_SENDUSP 0x17 +#define CMND_TRANSLATEADDR 0x18 +#define CMND_XFERINFO 0x20 +#define CMND_SBT (1<<7) + +#define DATA 25 +#define ASR 26 +#define ASR_INT (1<<7) +#define ASR_LCI (1<<6) +#define ASR_BSY (1<<5) +#define ASR_CIP (1<<4) +#define ASR_PE (1<<1) +#define ASR_DBR (1<<0) + +/* DMAC registers */ +#define INIT 0x00 +#define INIT_8BIT (1) + +#define CHANNEL 0x80 +#define CHANNEL_0 0x00 +#define CHANNEL_1 0x01 +#define CHANNEL_2 0x02 +#define CHANNEL_3 0x03 + +#define TXCNTLO 0x01 +#define TXCNTHI 0x81 +#define TXADRLO 0x02 +#define TXADRMD 0x82 +#define TXADRHI 0x03 + +#define DEVCON0 0x04 +#define DEVCON0_AKL (1<<7) +#define DEVCON0_RQL (1<<6) +#define DEVCON0_EXW (1<<5) +#define DEVCON0_ROT (1<<4) +#define DEVCON0_CMP (1<<3) +#define DEVCON0_DDMA (1<<2) +#define DEVCON0_AHLD (1<<1) +#define DEVCON0_MTM (1<<0) + +#define DEVCON1 0x84 +#define DEVCON1_WEV (1<<1) +#define DEVCON1_BHLD (1<<0) + +#define MODECON 0x05 +#define MODECON_WOED 0x01 +#define MODECON_VERIFY 0x00 +#define MODECON_READ 0x04 +#define MODECON_WRITE 0x08 +#define MODECON_AUTOINIT 0x10 +#define MODECON_ADDRDIR 0x20 +#define MODECON_DEMAND 0x00 +#define MODECON_SINGLE 0x40 +#define MODECON_BLOCK 0x80 +#define MODECON_CASCADE 0xC0 + +#define STATUS 0x85 +#define STATUS_TC0 (1<<0) +#define STATUS_RQ0 (1<<4) + +#define TEMPLO 0x06 +#define TEMPHI 0x86 +#define REQREG 0x07 +#define MASKREG 0x87 +#define MASKREG_M0 0x01 +#define MASKREG_M1 0x02 +#define MASKREG_M2 0x04 +#define MASKREG_M3 0x08 + +/* miscellaneous internal variables */ + +#define POD_SPACE(x) ((x) + 0xd0000) +#define MASK_ON (MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0) +#define MASK_OFF (MASKREG_M3|MASKREG_M2|MASKREG_M1) + +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) < (y) ? (y) : (x)) + +/* + * SCSI driver phases + */ +typedef enum { + PHASE_IDLE, /* we're not planning on doing anything */ + PHASE_CONNECTING, /* connecting to a target */ + PHASE_CONNECTED, /* connected to a target */ + PHASE_MSGOUT, /* message out to device */ + PHASE_RECONNECTED, /* reconnected */ + PHASE_COMMANDPAUSED, /* command partly sent */ + PHASE_COMMAND, /* command all sent */ + PHASE_DATAOUT, /* data out to device */ + PHASE_DATAIN, /* data in from device */ + PHASE_STATUSIN, /* status in from device */ + PHASE_MSGIN, /* message in from device */ + PHASE_DONE, /* finished */ + PHASE_ABORTED, /* aborted */ + PHASE_DISCONNECT, /* disconnecting */ +} phase_t; + +/* + * After interrupt, what to do now + */ +typedef enum { + INTR_IDLE, /* not expecting another IRQ */ + INTR_NEXT_COMMAND, /* start next command */ + INTR_PROCESSING, /* interrupt routine still processing */ +} intr_ret_t; + +/* + * DMA direction + */ +typedef enum { + DMA_OUT, /* DMA from memory to chip */ + DMA_IN /* DMA from chip to memory */ +} dmadir_t; + +/* + * Synchronous transfer state + */ +typedef enum { /* Synchronous transfer state */ + SYNC_ASYNCHRONOUS, /* don't negociate synchronous transfers*/ + SYNC_NEGOCIATE, /* start negociation */ + SYNC_SENT_REQUEST, /* sent SDTR message */ + SYNC_COMPLETED, /* received SDTR reply */ +} syncxfer_t; + +/* + * Command type + */ +typedef enum { /* command type */ + CMD_READ, /* READ_6, READ_10, READ_12 */ + CMD_WRITE, /* WRITE_6, WRITE_10, WRITE_12 */ + CMD_MISC, /* Others */ +} cmdtype_t; + +/* + * Data phase direction + */ +typedef enum { /* Data direction */ + DATADIR_IN, /* Data in phase expected */ + DATADIR_OUT /* Data out phase expected */ +} datadir_t; + +#include "queue.h" +#include "msgqueue.h" + +/* + * AcornSCSI host specific data + */ +typedef struct acornscsi_hostdata { + /* miscellaneous */ + struct Scsi_Host *host; /* host */ + Scsi_Cmnd *SCpnt; /* currently processing command */ + Scsi_Cmnd *origSCpnt; /* original connecting command */ + + /* driver information */ + struct { + unsigned int io_port; /* base address of WD33C93 */ + unsigned char irq; /* interrupt */ + phase_t phase; /* current phase */ + + struct { + unsigned char target; /* reconnected target */ + unsigned char lun; /* reconnected lun */ + unsigned char tag; /* reconnected tag */ + } reconnected; + + Scsi_Pointer SCp; /* current commands data pointer */ + + MsgQueue_t msgs; + + unsigned short last_message; /* last message to be sent */ + unsigned char disconnectable:1; /* this command can be disconnected */ + unsigned char interrupt:1; /* interrupt active */ + } scsi; + + /* statistics information */ + struct { + unsigned int queues; + unsigned int removes; + unsigned int fins; + unsigned int reads; + unsigned int writes; + unsigned int miscs; + unsigned int disconnects; + unsigned int aborts; + unsigned int resets; + } stats; + + /* queue handling */ + struct { + Queue_t issue; /* issue queue */ + Queue_t disconnected; /* disconnected command queue */ + } queues; + + /* per-device info */ + struct { + unsigned char sync_xfer; /* synchronous transfer (SBIC value) */ + syncxfer_t sync_state; /* sync xfer negociation state */ + unsigned char disconnect_ok:1; /* device can disconnect */ + } device[8]; + unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + + /* DMA info */ + struct { + unsigned int io_port; /* base address of DMA controller */ + unsigned int io_intr_clear; /* address of DMA interrupt clear */ + unsigned int free_addr; /* next free address */ + unsigned int start_addr; /* start address of current transfer */ + dmadir_t direction; /* dma direction */ + unsigned int transferred; /* number of bytes transferred */ + unsigned int xfer_start; /* scheduled DMA transfer start */ + unsigned int xfer_length; /* scheduled DMA transfer length */ + char *xfer_ptr; /* pointer to area */ + unsigned char xfer_required:1; /* set if we need to transfer something */ + unsigned char xfer_setup:1; /* set if DMA is setup */ + } dma; + + /* card info */ + struct { + unsigned int io_intr; /* base address of interrupt id reg */ + unsigned int io_page; /* base address of page reg */ + unsigned int io_ram; /* base address of RAM access */ + unsigned char page_reg; /* current setting of page reg */ + } card; +} AS_Host; + +#endif /* ndef HOSTS_C */ + +#endif /* ndef ASM */ +#endif /* ACORNSCSI_H */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c --- v2.1.87/linux/drivers/acorn/scsi/cumana_1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/cumana_1.c Fri Feb 6 16:22:47 1998 @@ -0,0 +1,361 @@ +#define AUTOSENSE +#define PSEUDO_DMA + +/* + * Generic Generic NCR5380 driver + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + */ + +/* + * $Log: cumana_NCR5380.c,v $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "cumana_1.h" +#include "../../scsi/NCR5380.h" +#include "../../scsi/constants.h" + +static const card_ids cumanascsi_cids[] = { + { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, + { 0xffff, 0xffff } +}; + +static struct proc_dir_entry proc_scsi_cumana1 = { + PROC_SCSI_T128, 12, "CumanaSCSI-1", S_IFDIR | S_IRUGO, S_IXUGO, 2 +}; + +/* + * Function : cumanascsi_setup(char *str, int *ints) + * + * Purpose : LILO command line initialization of the overrides array, + * + * Inputs : str - unused, ints - array of integer parameters with ints[0] + * equal to the number of ints. + * + */ + +void cumanascsi_setup(char *str, int *ints) { +} + +#define CUMANA_ADDRESS(card) (ecard_address((card), ECARD_IOC, ECARD_SLOW) + 0x800) +#define CUMANA_IRQ(card) ((card)->irq) +/* + * Function : int cumanascsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes cumana NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ +static struct expansion_card *ecs[4]; + +int cumanascsi_detect(Scsi_Host_Template * tpnt) +{ + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_cumana1; + + memset (ecs, 0, sizeof (ecs)); + + while(1) { + if((ecs[count] = ecard_find(0, cumanascsi_cids)) == NULL) + break; + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + instance->io_port = CUMANA_ADDRESS(ecs[count]); + instance->irq = CUMANA_IRQ(ecs[count]); + + NCR5380_init(instance, 0); + ecard_claim(ecs[count]); + + instance->n_io_port = 255; + request_region (instance->io_port, instance->n_io_port, "CumanaSCSI-1"); + + ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; + outb(0x00, instance->io_port - 577); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk("scsi%d: interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk("scsi%d: please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + CAN_QUEUE, CMD_PER_LUN, CUMANASCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + + ++count; + } + return count; +} + +int cumanascsi_release (struct Scsi_Host *shpnt) +{ + int i; + + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + if (shpnt->io_port) + release_region (shpnt->io_port, shpnt->n_io_port); + + for (i = 0; i < 4; i++) + if (shpnt->io_port == CUMANA_ADDRESS(ecs[i])) + ecard_release (ecs[i]); + return 0; +} + +const char * cumanascsi_info (struct Scsi_Host *spnt) { + return ""; +} + +#ifdef NOT_EFFICIENT +#define CTRL(p,v) outb(*ctrl = (v), (p) - 577) +#define STAT(p) inb((p)+1) +#define IN(p) inb((p)) +#define OUT(v,p) outb((v), (p)) +#else +#define CTRL(p,v) (p[-2308] = (*ctrl = (v))) +#define STAT(p) (p[4]) +#define IN(p) (*(p)) +#define IN2(p) ((unsigned short)(*(volatile unsigned long *)(p))) +#define OUT(v,p) (*(p) = (v)) +#define OUT2(v,p) (*((volatile unsigned long *)(p)) = (v)) +#endif +#define L(v) (((v)<<16)|((v) & 0x0000ffff)) +#define H(v) (((v)>>16)|((v) & 0xffff0000)) + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + int oldctrl = *ctrl; + unsigned long *laddr; +#ifdef NOT_EFFICIENT + int iobase = instance->io_port; + int dma_io = iobase & ~(0x3C0000>>2); +#else + volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port); + volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000); +#endif + + if(!len) return 0; + + CTRL(iobase, 0x02); + laddr = (unsigned long *)addr; + while(len >= 32) + { + int status; + unsigned long v; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(!(status & 0x40)) + continue; + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + len -= 32; + if(len == 0) + break; + } + + addr = (unsigned char *)laddr; + CTRL(iobase, 0x12); + while(len > 0) + { + int status; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + OUT(*addr++, dma_io); + if(--len == 0) + break; + } + + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + OUT(*addr++, dma_io); + if(--len == 0) + break; + } + } +end: + CTRL(iobase, oldctrl|0x40); + return len; +} + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + int oldctrl = *ctrl; + unsigned long *laddr; +#ifdef NOT_EFFICIENT + int iobase = instance->io_port; + int dma_io = iobase & ~(0x3C0000>>2); +#else + volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port); + volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000); +#endif + + if(!len) return 0; + + CTRL(iobase, 0x00); + laddr = (unsigned long *)addr; + while(len >= 32) + { + int status; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(!(status & 0x40)) + continue; + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + len -= 32; + if(len == 0) + break; + } + + addr = (unsigned char *)laddr; + CTRL(iobase, 0x10); + while(len > 0) + { + int status; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + *addr++ = IN(dma_io); + if(--len == 0) + break; + } + + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + *addr++ = IN(dma_io); + if(--len == 0) + break; + } + } +end: + CTRL(iobase, oldctrl|0x40); + return len; +} + +#undef STAT +#undef CTRL +#undef IN +#undef OUT + +#define CTRL(p,v) outb(*ctrl = (v), (p) - 577) + +static char cumanascsi_read(struct Scsi_Host *instance, int reg) +{ + int iobase = instance->io_port; + int i; + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + + CTRL(iobase, 0); + i = inb(iobase + 64 + reg); + CTRL(iobase, 0x40); + + return i; +} + +static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value) +{ + int iobase = instance->io_port; + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + + CTRL(iobase, 0); + outb(value, iobase + 64 + reg); + CTRL(iobase, 0x40); +} + +#undef CTRL + +#include "../../scsi/NCR5380.c" + +#ifdef MODULE + +Scsi_Host_Template driver_template = CUMANA_NCR5380; + +#include "../../scsi/scsi_module.c" +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/cumana_1.h linux/drivers/acorn/scsi/cumana_1.h --- v2.1.87/linux/drivers/acorn/scsi/cumana_1.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/cumana_1.h Sun Dec 28 09:15:22 1997 @@ -0,0 +1,102 @@ +/* + * Cumana Generic NCR5380 driver defines + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 440-4894 + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * $Log: cumana_NCR5380.h,v $ + */ + +#ifndef CUMANA_NCR5380_H +#define CUMANA_NCR5380_H + +#define CUMANASCSI_PUBLIC_RELEASE 1 + + +#ifndef ASM +int cumanascsi_abort (Scsi_Cmnd *); +int cumanascsi_detect (Scsi_Host_Template *); +int cumanascsi_release (struct Scsi_Host *); +const char *cumanascsi_info (struct Scsi_Host *); +int cumanascsi_reset(Scsi_Cmnd *, unsigned int); +int cumanascsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int cumanascsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#include + +#define CUMANA_NCR5380 { \ +name: "Cumana 16-bit SCSI", \ +detect: cumanascsi_detect, \ +release: cumanascsi_release, /* Release */ \ +info: cumanascsi_info, \ +queuecommand: cumanascsi_queue_command, \ +abort: cumanascsi_abort, \ +reset: cumanascsi_reset, \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: 7, /* id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +unchecked_isa_dma: 0, /* unchecked_isa_dma */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +#define NCR5380_implementation_fields \ + int port, ctrl + +#define NCR5380_local_declare() \ + struct Scsi_Host *_instance + +#define NCR5380_setup(instance) \ + _instance = instance + +#define NCR5380_read(reg) cumanascsi_read(_instance, reg) +#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value) + +#define NCR5380_intr cumanascsi_intr +#define NCR5380_queue_command cumanascsi_queue_command +#define NCR5380_abort cumanascsi_abort +#define NCR5380_reset cumanascsi_reset +#define NCR5380_proc_info cumanascsi_proc_info + +#define BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#endif /* ndef HOSTS_C */ +#endif /* ndef ASM */ +#endif /* CUMANA_NCR5380_H */ + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c --- v2.1.87/linux/drivers/acorn/scsi/cumana_2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/cumana_2.c Sun Feb 15 08:58:11 1998 @@ -0,0 +1,378 @@ +/* + * linux/arch/arm/drivers/scsi/cumana_2.c + * + * Copyright (C) 1997,1998 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 30-08-1997 RMK 0.0.0 Created, READONLY version + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../../scsi/sd.h" +#include "../../scsi/hosts.h" +#include "cumana_2.h" +#include "fas216.h" + +/* Hmm - this should go somewhere else */ +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) + +/* Configuration */ +#define XTALFREQ 40 +#define INT_POLARITY CTRL_INT_HIGH + +/* + * List of devices that the driver will recognise + */ +#define CUMANASCSI2_LIST { MANU_CUMANA, PROD_CUMANA_SCSI_2 } + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 1 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_cumanascsi_2 = { + PROC_SCSI_QLOGICFAS, 6, "cumanascs2", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* + * Function: void cumanascsi_2_intr (int irq, void *dev_id, struct pt_regs *regs) + * Purpose : handle interrupts from Cumana SCSI 2 card + * Params : irq - interrupt number + * dev_id - user-defined (Scsi_Host structure) + * regs - processor registers at interrupt + */ +static void cumanascsi_2_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *instance = (struct Scsi_Host *)dev_id; + + fas216_intr (instance); +} + +/* + * Function: int cumanascsi_2_dma_setup (instance, SCpnt, direction) + * Purpose : initialises DMA/PIO + * Params : instance - host + * SCpnt - command + * direction - DMA on to/off of card + * Returns : 0 if we should not set CMD_WITHDMA for transfer info command + */ +static fasdmatype_t cumanascsi_2_dma_setup (struct Scsi_Host *instance, Scsi_Pointer *SCp, fasdmadir_t direction) +{ + /* + * We don't do DMA + */ + return fasdma_pseudo; +} + +/* + * Function: int cumanascsi_2_dma_pseudo (instance, SCpnt, direction, transfer) + * Purpose : handles pseudo DMA + * Params : instance - host + * SCpnt - command + * direction - DMA on to/off of card + * transfer - minimum number of bytes we expect to transfer + * Returns : bytes transfered + */ +static int +cumanascsi_2_dma_pseudo (struct Scsi_Host *instance, Scsi_Pointer *SCp, + fasdmadir_t direction, int transfer) +{ + CumanaScsi2_Info *info = (CumanaScsi2_Info *)instance->hostdata; + unsigned int length; + unsigned char *addr; + + length = SCp->this_residual; + addr = SCp->ptr; + + if (direction == DMA_OUT) +#if 0 + while (length > 1) { + unsigned long word; + + + if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + goto end; + + if (!(inb (info->cstatus) & CSTATUS_DRQ)) + continue; + + word = *addr | (*addr + 1) << 8; + outw (info->dmaarea); + addr += 2; + length -= 2; + } +#else + printk ("PSEUDO_OUT???\n"); +#endif + else { + if (transfer && (transfer & 255)) { + while (length >= 256) { + if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + goto end; + + if (!(inb (info->cstatus) & CSTATUS_DRQ)) + continue; + + insw (info->dmaarea, addr, 256 >> 1); + addr += 256; + length -= 256; + } + } + + while (length > 0) { + unsigned long word; + + if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + goto end; + + if (!(inb (info->cstatus) & CSTATUS_DRQ)) + continue; + + word = inw (info->dmaarea); + *addr++ = word; + if (--length > 0) { + *addr++ = word >> 8; + length --; + } + } + } + +end: + return SCp->this_residual - length; +} + +/* + * Function: int cumanascsi_2_dma_stop (instance, SCpnt) + * Purpose : stops DMA/PIO + * Params : instance - host + * SCpnt - command + */ +static void cumanascsi_2_dma_stop (struct Scsi_Host *instance, Scsi_Pointer *SCp) +{ + /* + * no DMA to stop + */ +} + +/* + * Function: int cumanascsi_2_detect (Scsi_Host_Template * tpnt) + * Purpose : initialises Cumana SCSI 2 driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int cumanascsi_2_detect (Scsi_Host_Template *tpnt) +{ + static const card_ids cumanascsi_2_cids[] = { CUMANASCSI2_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_cumanascsi_2; + memset (ecs, 0, sizeof (ecs)); + + ecard_startfind (); + + while (1) { + CumanaScsi2_Info *info; + + ecs[count] = ecard_find (0, cumanascsi_2_cids); + if (!ecs[count]) + break; + + ecard_claim (ecs[count]); + + instance = scsi_register (tpnt, sizeof (CumanaScsi2_Info)); + if (!instance) { + ecard_release (ecs[count]); + break; + } + + instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->irq = ecs[count]->irq; + + ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(instance->io_port); + ecs[count]->irqmask = CSTATUS_IRQ; + + request_region (instance->io_port , 1, "cumanascsi2-stat"); + request_region (instance->io_port + 128, 64, "cumanascsi2-dma"); + request_region (instance->io_port + 192, 16, "cumanascsi2-fas"); + if (request_irq (instance->irq, cumanascsi_2_intr, SA_INTERRUPT, "cumanascsi2", instance)) { + printk ("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + } + + info = (CumanaScsi2_Info *)instance->hostdata; + info->info.scsi.io_port = instance->io_port + 192; + info->info.scsi.irq = instance->irq; + info->info.ifcfg.clockrate = XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.dma.setup = cumanascsi_2_dma_setup; + info->info.dma.pseudo = cumanascsi_2_dma_pseudo; + info->info.dma.stop = cumanascsi_2_dma_stop; + info->dmaarea = instance->io_port + 128; + info->cstatus = instance->io_port; + + fas216_init (instance); + ++count; + } + return count; +} + +/* + * Function: int cumanascsi_2_release (struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int cumanascsi_2_release (struct Scsi_Host *instance) +{ + int i; + + fas216_release (instance); + + if (instance->irq != 255) + free_irq (instance->irq, instance); + release_region (instance->io_port, 1); + release_region (instance->io_port + 128, 32); + release_region (instance->io_port + 192, 16); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) + ecard_release (ecs[i]); + return 0; +} + +/* + * Function: const char *cumanascsi_2_info (struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *cumanascsi_2_info (struct Scsi_Host *host) +{ + CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf (string, "%s at port %X irq %d v%d.%d.%d scsi %s", + host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* + * Function: int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin; + struct Scsi_Host *host = scsi_hostlist; + CumanaScsi2_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (CumanaScsi2_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf (buffer, + "Cumana SCSI II driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf (buffer + pos, + "Address: %08X IRQ : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, info->info.scsi.type); + + pos += sprintf (buffer+pos, + "Queued commands: %-10ld Issued commands: %-10ld\n" + "Done commands : %-10ld Reads : %-10ld\n" + "Writes : %-10ld Others : %-10ld\n" + "Disconnects : %-10ld Aborts : %-10ld\n" + "Resets : %-10ld\n", + info->info.stats.queues, info->info.stats.removes, + info->info.stats.fins, info->info.stats.reads, + info->info.stats.writes, info->info.stats.miscs, + info->info.stats.disconnects, info->info.stats.aborts, + info->info.stats.resets); + + pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + + for (scd = host->host_queue; scd; scd = scd->next) { + int len; + + proc_print_scsidevice (scd, buffer, &len, pos); + pos += len; + pos += sprintf (buffer+pos, "Extensions: "); + if (scd->tagged_supported) + pos += sprintf (buffer+pos, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + pos += sprintf (buffer+pos, "\n"); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = CUMANASCSI_2; + +#include "../../scsi/scsi_module.c" +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/cumana_2.h linux/drivers/acorn/scsi/cumana_2.h --- v2.1.87/linux/drivers/acorn/scsi/cumana_2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/cumana_2.h Sun Feb 8 14:08:52 1998 @@ -0,0 +1,73 @@ +/* + * Cumana SCSI II driver + * + * Copyright (C) 1997 Russell King + */ +#ifndef CUMANA_2_H +#define CUMANA_2_H + +extern int cumanascsi_2_detect (Scsi_Host_Template *); +extern int cumanascsi_2_release (struct Scsi_Host *); +extern const char *cumanascsi_2_info (struct Scsi_Host *); +extern int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#ifndef HOSTS_C +#include "fas216.h" +#endif + +#define CUMANASCSI_2 { \ +proc_info: cumanascsi_2_proc_info, \ +name: "Cumana SCSI II", \ +detect: cumanascsi_2_detect, /* detect */ \ +release: cumanascsi_2_release, /* release */ \ +info: cumanascsi_2_info, /* info */ \ +command: fas216_command, /* command */ \ +queuecommand: fas216_queue_command, /* queuecommand */ \ +abort: fas216_abort, /* abort */ \ +reset: fas216_reset, /* reset */ \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: SCSI_ID, /* scsi host id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CAN_QUEUE, /* cmd per lun */ \ +unchecked_isa_dma: 0, /* unchecked isa dma */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ + unsigned int cstatus; /* card status register */ + unsigned int dmaarea; /* Pseudo DMA area */ +} CumanaScsi2_Info; + +#define CSTATUS_IRQ (1 << 0) +#define CSTATUS_DRQ (1 << 1) + +#endif /* HOSTS_C */ + +#endif /* CUMANASCSI_2_H */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c --- v2.1.87/linux/drivers/acorn/scsi/ecoscsi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/ecoscsi.c Fri Feb 6 16:24:45 1998 @@ -0,0 +1,240 @@ +#define AUTOSENSE +/* #define PSEUDO_DMA */ + +/* + * EcoSCSI Generic NCR5380 driver + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + */ + +/* + * $Log: ecoscsi_NCR5380.c,v $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "ecoscsi.h" +#include "../../scsi/NCR5380.h" +#include "../../scsi/constants.h" + +static struct proc_dir_entry proc_scsi_ecoscsi = { + PROC_SCSI_GENERIC_NCR5380, 7, "ecoscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static char ecoscsi_read(struct Scsi_Host *instance, int reg) +{ + int iobase = instance->io_port; + outb(reg | 8, iobase); + return inb(iobase + 1); +} + +static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value) +{ + int iobase = instance->io_port; + outb(reg | 8, iobase); + outb(value, iobase + 1); +} + +/* + * Function : ecoscsi_setup(char *str, int *ints) + * + * Purpose : LILO command line initialization of the overrides array, + * + * Inputs : str - unused, ints - array of integer parameters with ints[0] + * equal to the number of ints. + * + */ + +void ecoscsi_setup(char *str, int *ints) { +} + +/* + * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes ecoscsi NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ + +int ecoscsi_detect(Scsi_Host_Template * tpnt) +{ + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_ecoscsi; + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + instance->io_port = 0x80ce8000; + instance->n_io_port = 144; + instance->irq = IRQ_NONE; + + if (check_region (instance->io_port, instance->n_io_port)) { + scsi_unregister (instance); + return 0; + } + + ecoscsi_write (instance, MODE_REG, 0x20); /* Is it really SCSI? */ + if (ecoscsi_read (instance, MODE_REG) != 0x20) { /* Write to a reg. */ + scsi_unregister(instance); + return 0; /* and try to read */ + } + ecoscsi_write( instance, MODE_REG, 0x00 ); /* it back. */ + if (ecoscsi_read (instance, MODE_REG) != 0x00) { + scsi_unregister(instance); + return 0; + } + + NCR5380_init(instance, 0); + request_region (instance->io_port, instance->n_io_port, "ecoscsi"); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq != IRQ_NONE) { + printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); + printk("scsi%d: that the board had an interrupt!\n", instance->host_no); + } + + printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + CAN_QUEUE, CMD_PER_LUN, ECOSCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + return 1; +} + +int ecoscsi_release (struct Scsi_Host *shpnt) +{ + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + if (shpnt->io_port) + release_region (shpnt->io_port, shpnt->n_io_port); + return 0; +} + +const char * ecoscsi_info (struct Scsi_Host *spnt) { + return ""; +} + +#if 0 +#define STAT(p) inw(p + 144) + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; +printk("writing %p len %d\n",addr, len); + if(!len) return -1; + + while(1) + { + int status; + while(((status = STAT(iobase)) & 0x100)==0); + } +} + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; + int iobase2= instance->io_port + 0x100; + unsigned char *start = addr; + int s; +printk("reading %p len %d\n",addr, len); + outb(inb(iobase + 128), iobase + 135); + while(len > 0) + { + int status,b,i, timeout; + timeout = 0x07FFFFFF; + while(((status = STAT(iobase)) & 0x100)==0) + { + timeout--; + if(status & 0x200 || !timeout) + { + printk("status = %p\n",status); + outb(0, iobase + 135); + return 1; + } + } + if(len >= 128) + { + for(i=0; i<64; i++) + { + b = inw(iobase + 136); + *addr++ = b; + *addr++ = b>>8; + } + len -= 128; + } + else + { + b = inw(iobase + 136); + *addr ++ = b; + len -= 1; + if(len) + *addr ++ = b>>8; + len -= 1; + } + } + outb(0, iobase + 135); + printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]); + return 1; +} +#endif +#undef STAT + +#include "../../scsi/NCR5380.c" + +#ifdef MODULE + +Scsi_Host_Template driver_template = ECOSCSI_NCR5380; + +#include "../../scsi/scsi_module.c" +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/ecoscsi.h linux/drivers/acorn/scsi/ecoscsi.h --- v2.1.87/linux/drivers/acorn/scsi/ecoscsi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/ecoscsi.h Sun Dec 28 09:18:59 1997 @@ -0,0 +1,93 @@ +/* + * Cumana Generic NCR5380 driver defines + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * $Log: ecoscsi_NCR5380.h,v $ + */ + +#ifndef ECOSCSI_NCR5380_H +#define ECOSCSI_NCR5380_H + +#define ECOSCSI_PUBLIC_RELEASE 1 + + +#ifndef ASM +int ecoscsi_abort (Scsi_Cmnd *); +int ecoscsi_detect (Scsi_Host_Template *); +int ecoscsi_release (struct Scsi_Host *); +const char *ecoscsi_info (struct Scsi_Host *); +int ecoscsi_reset(Scsi_Cmnd *, unsigned int); +int ecoscsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int ecoscsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#define ECOSCSI_NCR5380 { \ +name: "Serial Port EcoSCSI NCR5380", \ +detect: ecoscsi_detect, \ +release: ecoscsi_release, \ +info: ecoscsi_info, \ +queuecommand: ecoscsi_queue_command, \ +abort: ecoscsi_abort, \ +reset: ecoscsi_reset, \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: 7, /* id */ \ +sg_tablesize: SG_ALL, \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C +#define NCR5380_implementation_fields \ + int port, ctrl + +#define NCR5380_local_declare() \ + struct Scsi_Host *_instance + +#define NCR5380_setup(instance) \ + _instance = instance + +#define NCR5380_read(reg) ecoscsi_read(_instance, reg) +#define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value) + +#define NCR5380_intr ecoscsi_intr +#define NCR5380_queue_command ecoscsi_queue_command +#define NCR5380_abort ecoscsi_abort +#define NCR5380_reset ecoscsi_reset +#define NCR5380_proc_info ecoscsi_proc_info + +#define BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#endif /* ndef HOSTS_C */ +#endif /* ndef ASM */ +#endif /* ECOSCSI_NCR5380_H */ + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c --- v2.1.87/linux/drivers/acorn/scsi/fas216.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/fas216.c Wed Feb 18 14:14:47 1998 @@ -0,0 +1,1575 @@ +/* + * linux/arch/arm/drivers/scsi/fas216.c + * + * Copyright (C) 1997 Russell King + * + * Based in information in qlogicfas.c by Tom Zerucha, Michael Griffith, and + * other sources. + * + * This is a generic driver. To use it, have a look at cumana_2.c. You + * should define your own structure that overlays FAS216_Info, eg: + * struct my_host_data { + * FAS216_Info info; + * ... my host specific data ... + * }; + * + * Changelog: + * 30-08-1997 RMK Created + * 14-09-1997 RMK Started disconnect support + * 08-02-1998 RMK Corrected real DMA support + * 15-02-1998 RMK Started sync xfer support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define FAS216_C + +#include "scsi.h" +#include "hosts.h" +#include "fas216.h" + +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 2 + +#undef NO_DISCONNECTS +#undef DEBUG_CONNECT +#undef DEBUG_BUSSERVICE +#undef DEBUG_FUNCTIONDONE +#undef DEBUG_MESSAGES + +static char *fas216_bus_phase (int stat) +{ + static char *phases[] = { + "DATA OUT", "DATA IN", + "COMMAND", "STATUS", + "MISC OUT", "MISC IN", + "MESG OUT", "MESG IN" + }; + + return phases[stat & STAT_BUSMASK]; +} + +static char fas216_target (FAS216_Info *info) +{ + if (info->SCpnt) + return '0' + info->SCpnt->target; + else + return 'H'; +} + +static void fas216_done (FAS216_Info *info, unsigned int result); + +/* Function: int fas216_clockrate (unsigned int clock) + * Purpose : calculate correct value to be written into clock conversion + * factor register. + * Params : clock - clock speed in MHz + * Returns : CLKF_ value + */ +static int fas216_clockrate (int clock) +{ + if (clock <= 10 || clock > 40) { + printk(KERN_CRIT + "fas216: invalid clock rate: check your driver!\n"); + clock = -1; + } else + clock = ((clock - 1) / 5 + 1) & 7; + + return clock; +} + +/* Function: int fas216_syncperiod(FAS216_Info *info, int ns) + * Purpose : Calculate value to be loaded into the STP register + * for a given period in ns + * Params : info - state structure for interface connected to device + * : ns - period in ns (between subsequent bytes) + * Returns : Value suitable for REG_STP + */ +static int fas216_syncperiod(FAS216_Info *info, int ns) +{ + int value = (info->ifcfg.clockrate * ns) / 1000; + + if (value < 4) + value = 4; + else if value > 35) + value = 35; + + return value & 31; +} + +/* Function: void fas216_updateptrs (FAS216_Info *info, int bytes_transferred) + * Purpose : update data pointers after transfer suspended/paused + * Params : info - interface's local pointer to update + * bytes_transferred - number of bytes transferred + */ +static void +fas216_updateptrs (FAS216_Info *info, int bytes_transferred) +{ + unsigned char *ptr = info->scsi.SCp.ptr; + unsigned int residual = info->scsi.SCp.this_residual; + + info->SCpnt->request_bufflen -= bytes_transferred; + + while (residual <= bytes_transferred && bytes_transferred) { + /* We have used up this buffer */ + bytes_transferred -= residual; + if (info->scsi.SCp.buffers_residual) { + info->scsi.SCp.buffer++; + info->scsi.SCp.buffers_residual--; + ptr = (unsigned char *)info->scsi.SCp.buffer->address; + residual = info->scsi.SCp.buffer->length; + } else { + ptr = NULL; + residual = 0; + } + } + + residual -= bytes_transferred; + ptr += bytes_transferred; + + info->scsi.SCp.ptr = ptr; + info->scsi.SCp.this_residual = residual; +} + +/* Function: void fas216_pio (FAS216_Info *info, fasdmadir_t direction) + * Purpose : transfer data off of/on to card using programmed IO + * Params : info - interface to transfer data to/from + * direction - direction to transfer data (DMA_OUT/DMA_IN) + * Notes : this is incredibly slow + */ +static void +fas216_pio (FAS216_Info *info, fasdmadir_t direction) +{ + unsigned int length = info->scsi.SCp.this_residual; + char *ptr = info->scsi.SCp.ptr; + + if (direction == DMA_OUT) { + while (length > 0) { + if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { + outb(*ptr++, REG_FF(info)); + length -= 1; + } else if (inb(REG_STAT(info)) & STAT_INT) + break; + } + } else { + while (length > 0) { + if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { + *ptr++ = inb(REG_FF(info)); + length -= 1; + } else if (inb(REG_STAT(info)) & STAT_INT) + break; + } + } + + if (length == 0) { + if (info->scsi.SCp.buffers_residual) { + info->scsi.SCp.buffer++; + info->scsi.SCp.buffers_residual--; + ptr = (unsigned char *)info->scsi.SCp.buffer->address; + length = info->scsi.SCp.buffer->length; + } else { + ptr = NULL; + length = 0; + } + } + + info->scsi.SCp.ptr = ptr; + info->scsi.SCp.this_residual = length; +} + +/* Function: void fas216_starttransfer(FAS216_Info *info, + * fasdmadir_t direction) + * Purpose : Start a DMA/PIO transfer off of/on to card + * Params : info - interface from which device disconnected from + * direction - transfer direction (DMA_OUT/DMA_IN) + */ +static void +fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction) +{ + fasdmatype_t dmatype; + + info->scsi.phase = (direction == DMA_OUT) ? + PHASE_DATAOUT : PHASE_DATAIN; + + if (info->dma.transfer_type == fasdma_real_block || + info->dma.transfer_type == fasdma_real_all) { + unsigned long total, residual; + + if (info->dma.transfer_type == fasdma_real_block) + total = info->scsi.SCp.this_residual; + else + total = info->SCpnt->request_bufflen; + + residual = (inb(REG_CFIS(info)) & CFIS_CF) + + inb(REG_CTCL(info)) + + (inb(REG_CTCM(info)) << 8) + + (inb(REG_CTCH(info)) << 16); + fas216_updateptrs (info, total - residual); + info->dma.transfer_type = fasdma_none; + } + + if (!info->scsi.SCp.ptr) { + printk ("scsi%d.%c: null buffer passed to " + "fas216_starttransfer\n", info->host->host_no, + fas216_target (info)); + return; + } + + dmatype = fasdma_none; + if (info->dma.setup) + dmatype = info->dma.setup(info->host, &info->scsi.SCp, + direction); + + info->dma.transfer_type = dmatype; + + switch (dmatype) { + case fasdma_none: + outb(info->scsi.SCp.this_residual, REG_STCL(info)); + outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); + outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + outb(CMD_TRANSFERINFO, REG_CMD(info)); + fas216_pio (info, direction); + break; + + case fasdma_pseudo: { + int transferred; + + outb(info->scsi.SCp.this_residual, REG_STCL(info)); + outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); + outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); + + transferred = + info->dma.pseudo(info->host, &info->scsi.SCp, + direction, info->SCpnt->transfersize); + + fas216_updateptrs (info, transferred); + } + break; + + case fasdma_real_block: + outb(info->scsi.SCp.this_residual, REG_STCL(info)); + outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); + outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + + outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); + break; + + case fasdma_real_all: + outb(info->SCpnt->request_bufflen, REG_STCL(info)); + outb(info->SCpnt->request_bufflen >> 8, REG_STCM(info)); + outb(info->SCpnt->request_bufflen >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + + outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); + break; + } +} + +/* Function: void fas216_stoptransfer (FAS216_Info *info) + * Purpose : Stop a DMA transfer onto / off of the card + * Params : info - interface from which device disconnected from + */ +static void +fas216_stoptransfer (FAS216_Info *info) +{ + if (info->dma.transfer_type == fasdma_real_block || + info->dma.transfer_type == fasdma_real_all) { + unsigned long total, residual; + + if (info->dma.stop) + info->dma.stop (info->host, &info->scsi.SCp); + + if (info->dma.transfer_type == fasdma_real_block) + total = info->scsi.SCp.this_residual; + else + total = info->SCpnt->request_bufflen; + + residual = (inb(REG_CFIS(info)) & CFIS_CF) + + inb(REG_CTCL(info)) + + (inb(REG_CTCM(info)) << 8) + + (inb(REG_CTCH(info)) << 16); + fas216_updateptrs (info, total - residual); + + info->dma.transfer_type = fasdma_none; + } +} + +/* Function: void fas216_disconnected_intr (FAS216_Info *info) + * Purpose : handle device disconnection + * Params : info - interface from which device disconnected from + */ +static void +fas216_disconnect_intr (FAS216_Info *info) +{ +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no, + fas216_target (info), info->scsi.phase); +#endif + msgqueue_flush (&info->scsi.msgs); + + switch (info->scsi.phase) { + case PHASE_SELECTION: /* while selecting - no target */ + fas216_done (info, DID_NO_CONNECT); + break; + + case PHASE_DISCONNECT: /* message in - disconnecting */ + outb(CMD_ENABLESEL, REG_CMD(info)); + info->scsi.disconnectable = 1; + info->scsi.reconnected.tag = 0; + info->scsi.phase = PHASE_IDLE; + info->stats.disconnects += 1; + break; + + case PHASE_DONE: /* at end of command - complete */ + fas216_done (info, DID_OK); + break; + + case PHASE_AFTERMSGOUT: /* message out - possible ABORT message */ + if (info->scsi.last_message == ABORT) { + info->scsi.aborting = 0; + fas216_done (info, DID_ABORT); + break; + } + + default: /* huh? */ + printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %d\n", + info->host->host_no, fas216_target (info), info->scsi.phase); + fas216_stoptransfer(info); + fas216_done (info, DID_ERROR); + break; + } +} + +/* Function: void fas216_reselected_intr (FAS216_Info *info) + * Purpose : Start reconnection of a device + * Params : info - interface which was reselected + */ +static void +fas216_reselected_intr (FAS216_Info *info) +{ + unsigned char target, identify_msg, ok; + + if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) { + Scsi_Cmnd *SCpnt = info->SCpnt; + + info->origSCpnt = SCpnt; + info->SCpnt = NULL; + + if (info->device[SCpnt->target].negstate == syncneg_sent) + info->device[SCpnt->target].negstate = syncneg_start; + } + +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: reconnect phase=%02X\n", info->host->host_no, + fas216_target (info), info->scsi.phase); +#endif + + msgqueue_flush (&info->scsi.msgs); + + if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { + printk (KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", + info->host->host_no); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT; + outb(CMD_MSGACCEPTED, REG_CMD(info)); + return; + } + + target = inb(REG_FF(info)); + identify_msg = inb(REG_FF(info)); + + ok = 1; + if (!(target & (1 << info->host->this_id))) { + printk (KERN_ERR "scsi%d.H: invalid host id on reselect\n", info->host->host_no); + ok = 0; + } + + if (!(identify_msg & 0x80)) { + printk (KERN_ERR "scsi%d.H: no IDENTIFY message on reselect, got msg %02X\n", + info->host->host_no, identify_msg); + ok = 0; + } + + if (!ok) { + /* + * Something went wrong - abort the command on + * the target. Should this be INITIATOR_ERROR ? + */ + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + outb(CMD_MSGACCEPTED, REG_CMD(info)); + return; + } + + target &= ~(1 << info->host->this_id); + switch (target) { + case 1: target = 0; break; + case 2: target = 1; break; + case 4: target = 2; break; + case 8: target = 3; break; + case 16: target = 4; break; + case 32: target = 5; break; + case 64: target = 6; break; + case 128: target = 7; break; + default: target = info->host->this_id; break; + } + + identify_msg &= 7; + info->scsi.reconnected.target = target; + info->scsi.reconnected.lun = identify_msg; + info->scsi.reconnected.tag = 0; + + ok = 0; + if (info->scsi.disconnectable && info->SCpnt && + info->SCpnt->target == target && info->SCpnt->lun == identify_msg) + ok = 1; + + if (!ok && queue_probetgtlun (&info->queues.disconnected, target, identify_msg)) + ok = 1; + + if (ok) { + info->scsi.phase = PHASE_RECONNECTED; + outb(target, REG_SDID(info)); + } else { + /* + * Our command structure not found - abort the command on the target + * Should this be INITIATOR_ERROR ? + */ + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + } + outb(CMD_MSGACCEPTED, REG_CMD(info)); +} + +/* Function: void fas216_finish_reconnect (FAS216_Info *info) + * Purpose : finish reconnection sequence for device + * Params : info - interface which caused function done interrupt + */ +static void +fas216_finish_reconnect (FAS216_Info *info) +{ +#ifdef DEBUG_CONNECT +printk ("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n", + info->SCpnt->target, info->SCpnt->lun, info->SCpnt->tag, + info->scsi.reconnected.target, info->scsi.reconnected.lun, + info->scsi.reconnected.tag); +#endif + + if (info->scsi.disconnectable && info->SCpnt) { + info->scsi.disconnectable = 0; + if (info->SCpnt->target == info->scsi.reconnected.target && + info->SCpnt->lun == info->scsi.reconnected.lun && + info->SCpnt->tag == info->scsi.reconnected.tag) { +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: reconnected", + info->host->host_no, fas216_target (info)); +#endif + } else { + queue_add_cmd_tail (&info->queues.disconnected, info->SCpnt); +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: had to move command to disconnected queue\n", + info->host->host_no, fas216_target (info)); +#endif + info->SCpnt = NULL; + } + } + if (!info->SCpnt) { + info->SCpnt = queue_remove_tgtluntag (&info->queues.disconnected, + info->scsi.reconnected.target, + info->scsi.reconnected.lun, + info->scsi.reconnected.tag); +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: had to get command", + info->host->host_no, fas216_target (info)); +#endif + } + if (!info->SCpnt) { + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + info->scsi.aborting = 1; + } else { + /* + * Restore data pointer from SAVED data pointer + */ + info->scsi.SCp = info->SCpnt->SCp; +#ifdef DEBUG_CONNECT + printk (", data pointers: [%p, %X]", + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + } +#ifdef DEBUG_CONNECT + printk ("\n"); +#endif +} + +/* Function: void fas216_message (FAS216_Info *info) + * Purpose : handle a function done interrupt from FAS216 chip + * Params : info - interface which caused function done interrupt + */ +static void fas216_message (FAS216_Info *info) +{ + unsigned char message[16]; + unsigned int msglen = 1; + + message[0] = inb(REG_FF(info)); + + if (message[0] == EXTENDED_MESSAGE) { + message[1] = inb(REG_FF(info)); + + for (msglen = 2; msglen < message[1]; msglen++) + message[msglen] = inb(REG_FF(info)); + } + +#ifdef DEBUG_MESSAGES + { + int i; + + printk ("scsi%d.%c: message in: ", + info->host->host_no, fas216_target (info)); + for (i = 0; i < msglen; i++) + printk ("%02X ", message[i]); + printk ("\n"); + } +#endif + if (info->scsi.phase == PHASE_RECONNECTED) { + if (message[0] == SIMPLE_QUEUE_TAG) + info->scsi.reconnected.tag = message[1]; + fas216_finish_reconnect (info); + info->scsi.phase = PHASE_MSGIN; + } + + switch (message[0]) { + case COMMAND_COMPLETE: + printk ("fas216: command complete with no status in MESSAGE_IN?\n"); + break; + + case SAVE_POINTERS: + /* + * Save current data pointer to SAVED data pointer + */ + info->SCpnt->SCp = info->scsi.SCp; +#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) + printk ("scsi%d.%c: save data pointers: [%p, %X]\n", + info->host->host_no, fas216_target (info), + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + break; + + case RESTORE_POINTERS: + /* + * Restore current data pointer from SAVED data pointer + */ + info->scsi.SCp = info->SCpnt->SCp; +#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) + printk ("scsi%d.%c: restore data pointers: [%p, %X]\n", + info->host->host_no, fas216_target (info), + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + break; + + case DISCONNECT: + info->scsi.phase = PHASE_DISCONNECT; + break; + + case MESSAGE_REJECT: + printk ("scsi%d.%c: reject, last message %04X\n", + info->host->host_no, fas216_target (info), + info->scsi.last_message); + break; + + case SIMPLE_QUEUE_TAG: + /* handled above */ + printk ("scsi%d.%c: reconnect queue tag %02X\n", + info->host->host_no, fas216_target (info), + message[1]); + break; + + case EXTENDED_MESSAGE: + switch (message[2]) { + case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ + + case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ + /* We don't do wide transfers - reject message */ + default: + printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n", + info->host->host_no, fas216_target (info), + message[2]); + msgqueue_flush (&info->scsi.msgs); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT; + break; + } + break; + + default: + printk ("scsi%d.%c: unrecognised message %02X, rejecting\n", + info->host->host_no, fas216_target (info), + message[0]); + msgqueue_flush (&info->scsi.msgs); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT; + break; + } + outb(CMD_MSGACCEPTED, REG_CMD(info)); +} + +/* Function: void fas216_busservice_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) + * Purpose : handle a bus service interrupt from FAS216 chip + * Params : info - interface which caused bus service interrupt + * stat - Status register contents + * ssr - SCSI Status register contents + */ +static void fas216_busservice_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) +{ + int i; +#ifdef DEBUG_BUSSERVICE + printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n", + info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase); +#endif + switch (ssr & IS_BITS) { + case IS_COMPLETE: /* last action completed */ + outb(CMD_NOP, REG_CMD(info)); + + switch (info->scsi.phase) { + case PHASE_SELECTION: /* while selecting - selected target */ + switch (stat & STAT_BUSMASK) { + case STAT_DATAOUT: /* data out phase */ + fas216_starttransfer (info, DMA_OUT); + break; + + case STAT_DATAIN: /* data in phase */ + fas216_starttransfer (info, DMA_IN); + break; + + case STAT_STATUS: /* status phase */ + info->scsi.phase = PHASE_STATUS; + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_MESGIN: /* message in phase */ + info->scsi.phase = PHASE_MSGIN; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: /* other */ + printk ("scsi%d.%c: bus phase %s after connect?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + break; + } + break; + + case PHASE_DATAIN: /* while transfering data in */ + switch (stat & STAT_BUSMASK) { + case STAT_DATAIN: /* continue data in phase */ + fas216_starttransfer (info, DMA_IN); + break; + + case STAT_STATUS: + fas216_stoptransfer(info); + info->scsi.phase = PHASE_STATUS; + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_MESGIN: /* message in phase */ + fas216_stoptransfer(info); + info->scsi.phase = PHASE_MSGIN; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after data in?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_DATAOUT: /* while transfering data out */ + switch (stat & STAT_BUSMASK) { + case STAT_DATAOUT: + fas216_starttransfer (info, DMA_OUT); + break; + + case STAT_STATUS: + fas216_stoptransfer(info); + info->scsi.phase = PHASE_STATUS; + outb(CMD_FLUSHFIFO, REG_CMD(info)); + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_MESGIN: /* message in phase */ + fas216_stoptransfer(info); + info->scsi.phase = PHASE_MSGIN; + outb(CMD_FLUSHFIFO, REG_CMD(info)); + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after data out?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_RECONNECTED: /* newly reconnected device */ + /* + * Command reconnected - if MESGIN, get message - it may be + * the tag. If not, get command out of the disconnected queue + */ + switch (stat & STAT_BUSMASK) { + case STAT_MESGIN: + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + case STAT_STATUS: + fas216_finish_reconnect (info); + info->scsi.phase = PHASE_STATUS; + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_DATAOUT: /* data out phase */ + fas216_finish_reconnect (info); + fas216_starttransfer (info, DMA_OUT); + break; + + case STAT_DATAIN: /* data in phase */ + fas216_finish_reconnect (info); + fas216_starttransfer (info, DMA_IN); + break; + + default: + printk ("scsi%d.%c: bus phase %s after reconnect?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_MSGIN: + switch (stat & STAT_BUSMASK) { + case STAT_MESGIN: + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after message in?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_MSGOUT: + if ((stat & STAT_BUSMASK) != STAT_MESGOUT) { + printk ("scsi%d.%c: didn't manage MESSAGE OUT phase\n", + info->host->host_no, fas216_target (info)); + } else { + unsigned int msglen; + + msglen = msgqueue_msglength (&info->scsi.msgs); + + outb(CMD_FLUSHFIFO, REG_CMD(info)); + + if (msglen == 0) + outb(NOP, REG_FF(info)); + else { + char *msg; + + while ((msg = msgqueue_getnextmsg (&info->scsi.msgs, &msglen)) != NULL) { + for (i = 0; i < msglen; i++) + outb(msg[i], REG_FF(info)); + } + } + outb(CMD_TRANSFERINFO, REG_CMD(info)); + info->scsi.phase = PHASE_AFTERMSGOUT; + } + break; + + case PHASE_AFTERMSGOUT: + switch (stat & STAT_BUSMASK) { + case STAT_MESGIN: + info->scsi.phase = PHASE_MSGIN; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after message out\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_DISCONNECT: + printk ("scsi%d.%c: disconnect message received, but bus service %s?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + info->scsi.aborting = 1; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: internal phase %d for bus service?" + " What do I do with this?\n", + info->host->host_no, fas216_target (info), + info->scsi.phase); + } + break; + + default: + printk ("scsi%d.%c: bus service at step %d?\n", + info->host->host_no, fas216_target (info), + ssr & IS_BITS); + } +} + +/* Function: void fas216_funcdone_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) + * Purpose : handle a function done interrupt from FAS216 chip + * Params : info - interface which caused function done interrupt + * stat - Status register contents + * ssr - SCSI Status register contents + */ +static void fas216_funcdone_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) +{ + int status, message; +#ifdef DEBUG_FUNCTIONDONE + printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n", + info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase); +#endif + switch (info->scsi.phase) { + case PHASE_STATUS: /* status phase - read status and msg */ + status = inb(REG_FF(info)); + message = inb(REG_FF(info)); + info->scsi.SCp.Message = message; + info->scsi.SCp.Status = status; + info->scsi.phase = PHASE_DONE; + outb(CMD_MSGACCEPTED, REG_CMD(info)); + break; + + case PHASE_IDLE: /* reselected? */ + case PHASE_MSGIN: /* message in phase */ + case PHASE_RECONNECTED: /* reconnected command */ + if ((stat & STAT_BUSMASK) == STAT_MESGIN) { + fas216_message (info); + break; + } + + default: + printk ("scsi%d.%c: internal phase %d for function done?" + " What do I do with this?\n", + info->host->host_no, fas216_target (info), + info->scsi.phase); + } +} + +/* Function: void fas216_intr (struct Scsi_Host *instance) + * Purpose : handle interrupts from the interface to progress a command + * Params : instance - interface to service + */ +void fas216_intr (struct Scsi_Host *instance) +{ + FAS216_Info *info = (FAS216_Info *)instance->hostdata; + unsigned char isr, ssr, stat; + + stat = inb(REG_STAT(info)); + ssr = inb(REG_IS(info)); + isr = inb(REG_INST(info)); + + if (isr & INST_BUSRESET) + printk ("scsi%d.H: fas216: bus reset detected\n", instance->host_no); + else if (isr & INST_ILLEGALCMD) + printk (KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no); + else if (isr & INST_DISCONNECT) + fas216_disconnect_intr (info); + else if (isr & INST_RESELECTED) /* reselected */ + fas216_reselected_intr (info); + else if (isr & INST_BUSSERVICE) /* bus service request */ + fas216_busservice_intr (info, stat, ssr); + else if (isr & INST_FUNCDONE) /* function done */ + fas216_funcdone_intr (info, stat, ssr); + else + printk ("scsi%d.%c: unknown interrupt received:" + " phase %d isr %02X ssr %02X stat %02X\n", + instance->host_no, fas216_target (info), + info->scsi.phase, isr, ssr, stat); +} + +/* Function: void fas216_kick (FAS216_Info *info) + * Purpose : kick a command to the interface - interface should be idle + * Params : info - our host interface to kick + * Notes : Interrupts are always disabled! + */ +static void fas216_kick (FAS216_Info *info) +{ + Scsi_Cmnd *SCpnt; + int i, msglen, from_queue = 0; + + if (info->origSCpnt) { + SCpnt = info->origSCpnt; + info->origSCpnt = NULL; + } else + SCpnt = NULL; + + /* retrieve next command */ + if (!SCpnt) { + SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns); + from_queue = 1; + } + + if (!SCpnt) /* no command pending - just exit */ + return; + + if (info->scsi.disconnectable && info->SCpnt) { + queue_add_cmd_tail (&info->queues.disconnected, info->SCpnt); + info->scsi.disconnectable = 0; + info->SCpnt = NULL; + printk("scsi%d.%c: moved command to disconnected queue\n", + info->host->host_no, fas216_target (info)); + } + + /* + * tagged queuing - allocate a new tag to this command + */ + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + SCpnt->device->current_tag += 1; + if (SCpnt->device->current_tag == 0) + SCpnt->device->current_tag = 1; + SCpnt->tag = SCpnt->device->current_tag; + } + + /* + * claim host busy + */ + info->scsi.phase = PHASE_SELECTION; + info->SCpnt = SCpnt; + info->scsi.SCp = SCpnt->SCp; + info->dma.transfer_type = fasdma_none; + +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: starting cmd %02X", + info->host->host_no, '0' + SCpnt->target, + SCpnt->cmnd[0]); +#endif + + if (from_queue) { +#ifdef SCSI2_TAG + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + SCpnt->device->current_tag += 1; + if (SCpnt->device->current_tag == 0) + SCpnt->device->current_tag = 1; + SCpnt->tag = SCpnt->device->current_tag; + } else +#endif + set_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns); + + info->stats.removes += 1; + switch (SCpnt->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + info->stats.writes += 1; + break; + case READ_6: + case READ_10: + case READ_12: + info->stats.reads += 1; + break; + default: + info->stats.miscs += 1; + break; + } + } + + /* build outgoing message bytes */ + msgqueue_flush (&info->scsi.msgs); + if (info->device[SCpnt->target].disconnect_ok) + msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun)); + else + msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun)); + + /* add tag message if required */ + if (SCpnt->tag) + msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); + + /* add synchronous negociation */ + if (info->device[SCpnt->target].negstate == syncneg_start) { + info->device[SCpnt->target].negstate = syncneg_sent; + msgqueue_addmsg(&info->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + 1000 / info->ifcfg.clockrate, + info->ifcfg.sync_max_depth); + } + + /* following what the ESP driver says */ + outb(0, REG_STCL(info)); + outb(0, REG_STCM(info)); + outb(0, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + + /* flush FIFO */ + outb(CMD_FLUSHFIFO, REG_CMD(info)); + + /* load bus-id and timeout */ + outb(BUSID(SCpnt->target), REG_SDID(info)); + outb(info->ifcfg.select_timeout, REG_STIM(info)); + + /* synchronous transfers */ + outb(info->device[SCpnt->target].sof, REG_SOF(info)); + outb(info->device[SCpnt->target].stp, REG_STP(info)); + + msglen = msgqueue_msglength (&info->scsi.msgs); + + if (msglen == 1 || msglen == 3) { + char *msg; + + /* load message bytes */ + while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { + for (i = 0; i < msglen; i++) + outb(msg[i], REG_FF(info)); + } + + /* load command */ + for (i = 0; i < SCpnt->cmd_len; i++) + outb(SCpnt->cmnd[i], REG_FF(info)); + + if (msglen == 1) + outb(CMD_SELECTATN, REG_CMD(info)); + else + outb(CMD_SELECTATN3, REG_CMD(info)); + } else { + outb(CMD_SELECTATNSTOP, REG_CMD(info)); + } + +#ifdef DEBUG_CONNECT + printk(", data pointers [%p, %X]\n", + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + /* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */ +} + +/* Function: void fas216_done (FAS216_Info *info, unsigned int result) + * Purpose : complete processing for command + * Params : info - interface that completed + * result - driver byte of result + */ +static void fas216_done (FAS216_Info *info, unsigned int result) +{ + Scsi_Cmnd *SCpnt = info->SCpnt; + + if (info->scsi.aborting) { + printk ("scsi%d.%c: uncaught abort - returning DID_ABORT\n", + info->host->host_no, fas216_target (info)); + result = DID_ABORT; + info->scsi.aborting = 0; + } + + info->stats.fins += 1; + + if (SCpnt) { + info->scsi.phase = PHASE_IDLE; + info->SCpnt = NULL; + + SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 | + info->scsi.SCp.Status; + + /* + * In theory, this should not happen, but just in case it does. + */ + if (info->scsi.SCp.ptr && result == DID_OK) { + switch (status_byte (SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk (KERN_ERR "scsi%d.H: incomplete data transfer " + "detected: result=%08X command=", + info->host->host_no, SCpnt->result); + print_command (SCpnt->cmnd); + } + } +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: scsi command (%p) complete, result=%08X\n", + info->host->host_no, fas216_target (info), + SCpnt, SCpnt->result); +#endif + + if (!SCpnt->scsi_done) + panic ("scsi%d.H: null scsi_done function in fas216_done", info->host->host_no); + + clear_bit (SCpnt->target * 8 + SCpnt->lun, info->busyluns); + + SCpnt->scsi_done (SCpnt); + } else + panic ("scsi%d.H: null command in fas216_done", info->host->host_no); + + if (info->scsi.irq != NO_IRQ) + fas216_kick (info); +} + +/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) + * Purpose : queue a command for adapter to process. + * Params : SCpnt - Command to queue + * done - done function to call once command is complete + * Returns : 0 - success, else error + */ +int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: received queuable command (%p) %02X\n", + SCpnt->host->host_no, '0' + SCpnt->target, + SCpnt, SCpnt->cmnd[0]); +#endif + + SCpnt->scsi_done = done; + SCpnt->host_scribble = NULL; + SCpnt->result = 0; + SCpnt->SCp.Message = 0; + SCpnt->SCp.Status = 0; + + if (SCpnt->use_sg) { + unsigned long len = 0; + int buf; + + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + /* + * Calculate correct buffer length + */ + for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++) + len += SCpnt->SCp.buffer[buf].length; + SCpnt->request_bufflen = len; + } else { + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + } + + info->stats.queues += 1; + SCpnt->tag = 0; + + if (info->scsi.irq != NO_IRQ) { + unsigned long flags; + + /* add command into execute queue and let it complete under + * the drivers interrupts. + */ + if (!queue_add_cmd_ordered (&info->queues.issue, SCpnt)) { + SCpnt->result = DID_ERROR << 16; + done (SCpnt); + } + save_flags_cli (flags); + if (!info->SCpnt || info->scsi.disconnectable) + fas216_kick (info); + restore_flags (flags); + } else { + /* no interrupts to rely on - we'll have to handle the + * command ourselves. For now, we give up. + */ + SCpnt->result = DID_ERROR << 16; + done (SCpnt); + } + return 0; +} + +/* Function: void fas216_internal_done (Scsi_Cmnd *SCpnt) + * Purpose : trigger restart of a waiting thread in fas216_command + * Params : SCpnt - Command to wake + */ +static void fas216_internal_done (Scsi_Cmnd *SCpnt) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + + info->internal_done = 1; +} + +/* Function: int fas216_command (Scsi_Cmnd *SCpnt) + * Purpose : queue a command for adapter to process. + * Params : SCpnt - Command to queue + * Returns : scsi result code + */ +int fas216_command (Scsi_Cmnd *SCpnt) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + unsigned long flags; + + info->internal_done = 0; + fas216_queue_command (SCpnt, fas216_internal_done); + + /* + * This wastes time, since we can't return until the command is + * complete. We can't seep either since we may get re-entered! + * However, we must re-enable interrupts, or else we'll be + * waiting forever. + */ + save_flags (flags); + sti (); + + while (!info->internal_done) + barrier (); + + restore_flags (flags); + + return SCpnt->result; +} + +/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1, + * Scsi_Cmnd **SCpntp2, int result) + * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 + * Params : SCpntp1 - pointer to command to return + * SCpntp2 - pointer to command to check + * result - result to pass back to mid-level done function + * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command + * structure as *SCpntp2. + */ +static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, + int result) +{ + Scsi_Cmnd *SCpnt = *SCpntp1; + + if (SCpnt) { + *SCpntp1 = NULL; + + SCpnt->result = result; + SCpnt->scsi_done (SCpnt); + } + + if (SCpnt == *SCpntp2) + *SCpntp2 = NULL; +} + +/* Function: int fas216_abort (Scsi_Cmnd *SCpnt) + * Purpose : abort a command if something horrible happens. + * Params : SCpnt - Command that is believed to be causing a problem. + * Returns : one of SCSI_ABORT_ macros. + */ +int fas216_abort (Scsi_Cmnd *SCpnt) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + int result = SCSI_ABORT_SNOOZE; + + info->stats.aborts += 1; + + printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no); + + do { + /* If command is waiting in the issue queue, then we can + * simply remove the command and return abort status + */ + if (queue_removecmd (&info->queues.issue, SCpnt)) { + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); + printk ("command on issue queue"); + result = SCSI_ABORT_SUCCESS; + break; + } + + /* If the command is on the disconencted queue, we need to + * reconnect to the device + */ + if (queue_cmdonqueue (&info->queues.disconnected, SCpnt)) + printk ("command on disconnected queue"); + + /* If the command is connected, we need to flag that the + * command needs to be aborted + */ + if (info->SCpnt == SCpnt) + printk ("command executing"); + + /* If the command is pending for execution, then again + * this is simple - we remove it and report abort status + */ + if (info->origSCpnt == SCpnt) { + info->origSCpnt = NULL; + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); + printk ("command waiting for execution"); + result = SCSI_ABORT_SUCCESS; + break; + } + } while (0); + + printk ("\n"); + + return result; +} + +/* Function: void fas216_reset_state(FAS216_Info *info) + * Purpose : Initialise driver internal state + * Params : info - state to initialise + */ +static void fas216_reset_state(FAS216_Info *info) +{ + int i; + + /* + * Clear out all stale info in our state structure + */ + memset (info->busyluns, 0, sizeof (info->busyluns)); + msgqueue_flush(&info->scsi.msgs); + info->scsi.reconnected.target = 0; + info->scsi.reconnected.lun = 0; + info->scsi.reconnected.tag = 0; + info->scsi.disconnectable = 0; + info->scsi.last_message = 0; + info->scsi.aborting = 0; + info->scsi.phase = PHASE_IDLE; + + for (i = 0; i < 8; i++) { +#ifndef NO_DISCONNECTS + info->device[i].disconnect_ok = 1; +#else + info->device[i].disconnect_ok = 0; +#endif + info->device[i].stp = fas216_syncperiod(info->ifcfg.asyncperiod); + info->device[i].sof = 0; +#ifdef SCSI2SYNC + info->device[i].negstate = syncneg_start; +#else + info->device[i].negstate = syncneg_complete; +#endif + } +} + +/* Function: void fas216_init_chip(FAS216_Info *info) + * Purpose : Initialise FAS216 state after reset + * Params : info - state structure for interface + */ +static void fas216_init_chip(FAS216_Info *info) +{ + outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info)); + outb(info->scsi.cfg[0], REG_CNTL1(info)); + outb(info->scsi.cfg[1], REG_CNTL2(info)); + outb(info->scsi.cfg[2], REG_CNTL3(info)); + outb(info->ifcfg.select_timeout, REG_STIM(info)); + outb(0, REG_SOF(info)); + outb(fas216_syncperiod(info->ifcfg.asyncperiod), REG_STP(info)); + outb(info->scsi.cfg[0], REG_CNTL1(info)); +} + +/* Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Purpose : resets the adapter if something horrible happens. + * Params : SCpnt - Command that is believed to be causing a problem. + * reset_flags - flags indicating reset type that is believed + * to be required. + * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET + * macros. + */ +int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + Scsi_Cmnd *SCptr; + int result = 0; + + info->stats.resets += 1; + + printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no); + + outb(info->scsi.cfg[3], REG_CNTL3(info)); + + fas216_stoptransfer(info); + fas216_reset_state(info); + + if (reset_flags & SCSI_RESET_SUGGEST_HOST_RESET) { + outb(CMD_RESETCHIP, REG_CMD(info)); + outb(CMD_NOP, REG_CMD(info)); + result |= SCSI_RESET_HOST_RESET; + } + + if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) { + outb(CMD_RESETSCSI, REG_CMD(info)); + outb(CMD_NOP, REG_CMD(info)); + result |= SCSI_RESET_BUS_RESET; + } + + if (!(reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET|SCSI_RESET_SUGGEST_HOST_RESET))) { + outb(CMD_RESETCHIP, REG_CMD(info)); + outb(CMD_NOP, REG_CMD(info)); + outb(CMD_RESETSCSI, REG_CMD(info)); + result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET; + } + + if (result & SCSI_RESET_HOST_RESET) + fas216_init_chip(info); + + /* + * Signal all commands in progress have been reset + */ + fas216_reportstatus (&info->SCpnt, &SCpnt, DID_RESET << 16); + + while ((SCptr = queue_remove (&info->queues.disconnected)) != NULL) + fas216_reportstatus (&SCptr, &SCpnt, DID_RESET << 16); + + if (SCpnt) { + /* + * Command not found on disconnected queue, nor currently + * executing command - check pending commands + */ + if (info->origSCpnt == SCpnt) + info->origSCpnt = NULL; + + queue_removecmd(&info->queues.issue, SCpnt); + + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done (SCpnt); + } + + printk ("\n"); + + return result | SCSI_RESET_SUCCESS; +} + +/* Function: int fas216_init (struct Scsi_Host *instance) + * Purpose : initialise FAS/NCR/AMD SCSI ic. + * Params : instance - a driver-specific filled-out structure + * Returns : 0 on success + */ +int fas216_init (struct Scsi_Host *instance) +{ + FAS216_Info *info = (FAS216_Info *)instance->hostdata; + unsigned long flags; + int target_jiffies; + + info->host = instance; + info->scsi.cfg[0] = instance->this_id; + info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE; + info->scsi.cfg[2] = CNTL3_ADDIDCHK | CNTL3_G2CB | CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->scsi.type = "unknown"; + info->SCpnt = NULL; + fas216_reset_state(info); + + memset (&info->stats, 0, sizeof (info->stats)); + + msgqueue_initialise (&info->scsi.msgs); + + if (!queue_initialise (&info->queues.issue)) + return 1; + + if (!queue_initialise (&info->queues.disconnected)) { + queue_free (&info->queues.issue); + return 1; + } + + outb(0, REG_CNTL3(info)); + outb(CNTL2_S2FE, REG_CNTL2(info)); + + if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) { + info->scsi.type = "NCR53C90"; + } else { + outb(0, REG_CNTL2(info)); + outb(0, REG_CNTL3(info)); + outb(5, REG_CNTL3(info)); + if (inb(REG_CNTL3(info)) != 5) { + info->scsi.type = "NCR53C90A"; + } else { + outb(0, REG_CNTL3(info)); + info->scsi.type = "NCR53C9x"; + } + } + + + outb(CNTL3_IDENABLE, REG_CNTL3(info)); + outb(0, REG_CNTL3(info)); + + outb(CMD_RESETCHIP, REG_CMD(info)); + outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info)); + outb(CNTL2_ENF, REG_CNTL2(info)); + outb(CMD_RESETCHIP, REG_CMD(info)); + switch (inb(REG1_ID(info))) { + case 12: + info->scsi.type = "Am53CF94"; + break; + default: + break; + } + + udelay (300); + + /* now for the real initialisation */ + fas216_init_chip(info); + + outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info)); + outb(CMD_RESETSCSI, REG_CMD(info)); + + /* scsi standard says 250ms */ + target_jiffies = jiffies + (25 * HZ) / 100; + save_flags (flags); + sti (); + + while (jiffies < target_jiffies) barrier (); + + restore_flags (flags); + + outb(info->scsi.cfg[0], REG_CNTL1(info)); + inb(REG_INST(info)); + + return 0; +} + +/* Function: int fas216_release (struct Scsi_Host *instance) + * Purpose : release all resources and put everything to bed for + * FAS/NCR/AMD SCSI ic. + * Params : instance - a driver-specific filled-out structure + * Returns : 0 on success + */ +int fas216_release (struct Scsi_Host *instance) +{ + FAS216_Info *info = (FAS216_Info *)instance->hostdata; + + outb(CMD_RESETCHIP, REG_CMD(info)); + queue_free (&info->queues.disconnected); + queue_free (&info->queues.issue); + + return 0; +} + +EXPORT_SYMBOL(fas216_init); +EXPORT_SYMBOL(fas216_abort); +EXPORT_SYMBOL(fas216_reset); +EXPORT_SYMBOL(fas216_queue_command); +EXPORT_SYMBOL(fas216_command); +EXPORT_SYMBOL(fas216_intr); +EXPORT_SYMBOL(fas216_release); + +#ifdef MODULE +int init_module (void) +{ + return 0; +} + +void cleanup_module (void) +{ +} +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h --- v2.1.87/linux/drivers/acorn/scsi/fas216.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/fas216.h Wed Feb 18 14:13:52 1998 @@ -0,0 +1,357 @@ +/* + * FAS216 generic driver + * + * Copyright (C) 1997-1998 Russell King + * + * NOTE! This file should be viewed using a console with + * >100 character width (since it uses 8-space tabs) + * (it used to fit in 80-columns with 4 space) + */ +#ifndef FAS216_H +#define FAS216_H + +#ifndef NO_IRQ +#define NO_IRQ 255 +#endif + +#include "queue.h" +#include "msgqueue.h" + +/* FAS register definitions */ + +/* transfer count low */ +#define REG_CTCL(x) ((x)->scsi.io_port) +#define REG_STCL(x) ((x)->scsi.io_port) + +/* transfer count medium */ +#define REG_CTCM(x) ((x)->scsi.io_port + (1 << (x)->scsi.io_shift)) +#define REG_STCM(x) ((x)->scsi.io_port + (1 << (x)->scsi.io_shift)) + +/* fifo data */ +#define REG_FF(x) ((x)->scsi.io_port + (2 << (x)->scsi.io_shift)) + +/* command */ +#define REG_CMD(x) ((x)->scsi.io_port + (3 << (x)->scsi.io_shift)) +#define CMD_NOP 0x00 +#define CMD_FLUSHFIFO 0x01 +#define CMD_RESETCHIP 0x02 +#define CMD_RESETSCSI 0x03 + +#define CMD_TRANSFERINFO 0x10 +#define CMD_INITCMDCOMPLETE 0x11 +#define CMD_MSGACCEPTED 0x12 +#define CMD_SETATN 0x1a +#define CMD_RSETATN 0x1b + +#define CMD_SELECTWOATN 0x41 +#define CMD_SELECTATN 0x42 +#define CMD_SELECTATNSTOP 0x43 +#define CMD_ENABLESEL 0x44 +#define CMD_DISABLESEL 0x45 +#define CMD_SELECTATN3 0x46 +#define CMD_RESEL3 0x47 + +#define CMD_WITHDMA 0x80 + +/* status register (read) */ +#define REG_STAT(x) ((x)->scsi.io_port + (4 << (x)->scsi.io_shift)) +#define STAT_IO (1 << 0) /* IO phase */ +#define STAT_CD (1 << 1) /* CD phase */ +#define STAT_MSG (1 << 2) /* MSG phase */ +#define STAT_TRANSFERDONE (1 << 3) /* Transfer completed */ +#define STAT_TRANSFERCNTZ (1 << 4) /* Transfer counter is zero */ +#define STAT_PARITYERROR (1 << 5) /* Parity error */ +#define STAT_REALBAD (1 << 6) /* Something bad */ +#define STAT_INT (1 << 7) /* Interrupt */ + +#define STAT_BUSMASK (STAT_MSG|STAT_CD|STAT_IO) +#define STAT_DATAOUT (0) /* Data out */ +#define STAT_DATAIN (STAT_IO) /* Data in */ +#define STAT_COMMAND (STAT_CD) /* Command out */ +#define STAT_STATUS (STAT_CD|STAT_IO) /* Status In */ +#define STAT_MESGOUT (STAT_MSG|STAT_CD) /* Message out */ +#define STAT_MESGIN (STAT_MSG|STAT_CD|STAT_IO) /* Message In */ + +/* bus ID for select / reselect */ +#define REG_SDID(x) ((x)->scsi.io_port + (4 << (x)->scsi.io_shift)) +#define BUSID(target) ((target) & 7) + +/* Interrupt status register (read) */ +#define REG_INST(x) ((x)->scsi.io_port + (5 << (x)->scsi.io_shift)) +#define INST_SELWOATN (1 << 0) /* Select w/o ATN */ +#define INST_SELATN (1 << 1) /* Select w/ATN */ +#define INST_RESELECTED (1 << 2) /* Reselected */ +#define INST_FUNCDONE (1 << 3) /* Function done */ +#define INST_BUSSERVICE (1 << 4) /* Bus service */ +#define INST_DISCONNECT (1 << 5) /* Disconnect */ +#define INST_ILLEGALCMD (1 << 6) /* Illegal command */ +#define INST_BUSRESET (1 << 7) /* SCSI Bus reset */ + +/* Timeout register (write) */ +#define REG_STIM(x) ((x)->scsi.io_port + (5 << (x)->scsi.io_shift)) + +/* Sequence step register (read) */ +#define REG_IS(x) ((x)->scsi.io_port + (6 << (x)->scsi.io_shift)) +#define IS_BITS 0x07 +#define IS_SELARB 0x00 /* Select & Arb ok */ +#define IS_MSGBYTESENT 0x01 /* One byte message sent*/ +#define IS_NOTCOMMAND 0x02 /* Not in command state */ +#define IS_EARLYPHASE 0x03 /* Early phase change */ +#define IS_COMPLETE 0x04 /* Command ok */ + +/* Transfer period step (write) */ +#define REG_STP(x) ((x)->scsi.io_port + (6 << (x)->scsi.io_shift)) + +/* Synchronous Offset (write) */ +#define REG_SOF(x) ((x)->scsi.io_port + (7 << (x)->scsi.io_shift)) + +/* Fifo state register (read) */ +#define REG_CFIS(x) ((x)->scsi.io_port + (7 << (x)->scsi.io_shift)) +#define CFIS_CF 0x1f /* Num bytes in FIFO */ +#define CFIS_IS 0xe0 /* Step */ + +/* config register 1 */ +#define REG_CNTL1(x) ((x)->scsi.io_port + (8 << (x)->scsi.io_shift)) +#define CNTL1_CID (7 << 0) /* Chip ID */ +#define CNTL1_STE (1 << 3) /* Self test enable */ +#define CNTL1_PERE (1 << 4) /* Parity enable reporting en. */ +#define CNTL1_PTE (1 << 5) /* Parity test enable */ +#define CNTL1_DISR (1 << 6) /* Disable Irq on SCSI reset */ +#define CNTL1_ETM (1 << 7) /* Extended Timing Mode */ + +/* Clock conversion factor (read) */ +#define REG_CLKF(x) ((x)->scsi.io_port + (9 << (x)->scsi.io_shift)) +#define CLKF_F37MHZ 0x00 /* 35.01 - 40 MHz */ +#define CLKF_F10MHZ 0x02 /* 10 MHz */ +#define CLKF_F12MHZ 0x03 /* 10.01 - 15 MHz */ +#define CLKF_F17MHZ 0x04 /* 15.01 - 20 MHz */ +#define CLKF_F22MHZ 0x05 /* 20.01 - 25 MHz */ +#define CLKF_F27MHZ 0x06 /* 25.01 - 30 MHz */ +#define CLKF_F32MHZ 0x07 /* 30.01 - 35 MHz */ + +/* Chip test register (write) */ +#define REG0_FTM(x) ((x)->scsi.io_port + (10 << (x)->scsi.io_shift)) +#define TEST_FTM 0x01 /* Force target mode */ +#define TEST_FIM 0x02 /* Force initiator mode */ +#define TEST_FHI 0x04 /* Force high impedance mode */ + +/* Configuration register 2 (read/write) */ +#define REG_CNTL2(x) ((x)->scsi.io_port + (11 << (x)->scsi.io_shift)) +#define CNTL2_PGDP (1 << 0) /* Pass Th/Generate Data Parity */ +#define CNTL2_PGRP (1 << 1) /* Pass Th/Generate Reg Parity */ +#define CNTL2_ACDPE (1 << 2) /* Abort on Cmd/Data Parity Err */ +#define CNTL2_S2FE (1 << 3) /* SCSI2 Features Enable */ +#define CNTL2_TSDR (1 << 4) /* Tristate DREQ */ +#define CNTL2_SBO (1 << 5) /* Select Byte Order */ +#define CNTL2_ENF (1 << 6) /* Enable features */ +#define CNTL2_DAE (1 << 7) /* Data Alignment Enable */ + +/* Configuration register 3 (read/write) */ +#define REG_CNTL3(x) ((x)->scsi.io_port + (12 << (x)->scsi.io_shift)) +#define CNTL3_BS8 (1 << 0) /* Burst size 8 */ +#define CNTL3_MDM (1 << 1) /* Modify DMA mode */ +#define CNTL3_LBTM (1 << 2) /* Last Byte Transfer mode */ +#define CNTL3_FASTCLK (1 << 3) /* Fast SCSI clocking */ +#define CNTL3_FASTSCSI (1 << 4) /* Fast SCSI */ +#define CNTL3_G2CB (1 << 5) /* Group2 SCSI support */ +#define CNTL3_QTAG (1 << 6) /* Enable 3 byte msgs */ +#define CNTL3_ADIDCHK (1 << 7) /* Additional ID check */ + +/* High transfer count (read/write) */ +#define REG_CTCH(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) +#define REG_STCH(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) + +/* ID reigster (read only) */ +#define REG1_ID(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) + +/* Data alignment */ +#define REG0_DAL(x) ((x)->scsi.io_port + (15 << (x)->scsi.io_shift)) + +typedef enum { + PHASE_IDLE, /* we're not planning on doing anything */ + PHASE_SELECTION, /* selecting a device */ + PHASE_RECONNECTED, /* reconnected */ + PHASE_DATAOUT, /* data out to device */ + PHASE_DATAIN, /* data in from device */ + PHASE_MSGIN, /* message in from device */ + PHASE_MSGOUT, /* message out to device */ + PHASE_AFTERMSGOUT, /* after message out phase */ + PHASE_STATUS, /* status from device */ + PHASE_DISCONNECT, /* disconnecting from bus */ + PHASE_DONE /* Command complete */ +} phase_t; + +typedef enum { + DMA_OUT, /* DMA from memory to chip */ + DMA_IN /* DMA from chip to memory */ +} fasdmadir_t; + +typedef enum { + fasdma_none, /* No dma */ + fasdma_pseudo, /* Pseudo DMA */ + fasdma_real_block, /* Real DMA, on block by block basis */ + fasdma_real_all /* Real DMA, on request by request */ +} fasdmatype_t; + +typedef enum { + syncneg_start, /* Negociate with device for Sync xfers */ + syncneg_sent, /* Sync Xfer negociation sent */ + syncnsg_complete /* Sync Xfer complete */ +} syncneg_t; + +typedef struct { + struct Scsi_Host *host; /* host */ + Scsi_Cmnd *SCpnt; /* currently processing command */ + Scsi_Cmnd *origSCpnt; /* original connecting command */ + + /* driver information */ + struct { + unsigned int io_port; /* base address of FAS216 */ + unsigned int io_shift; /* shift to adjust reg offsets by */ + unsigned char irq; /* interrupt */ + unsigned char cfg[4]; /* configuration registers */ + const char *type; /* chip type */ + phase_t phase; /* current phase */ + + struct { + unsigned char target; /* reconnected target */ + unsigned char lun; /* reconnected lun */ + unsigned char tag; /* reconnected tag */ + } reconnected; + + Scsi_Pointer SCp; /* current commands data pointer */ + + MsgQueue_t msgs; /* message queue for connected device */ + + unsigned short last_message; /* last message to be sent */ + + unsigned char disconnectable:1; /* this command can be disconnected */ + unsigned char aborting:1; /* aborting command */ + } scsi; + + /* statistics information */ + struct { + unsigned int queues; + unsigned int removes; + unsigned int fins; + unsigned int reads; + unsigned int writes; + unsigned int miscs; + unsigned int disconnects; + unsigned int aborts; + unsigned int resets; + } stats; + + /* configuration information */ + struct { + unsigned char clockrate; /* clock rate of FAS device (MHz) */ + unsigned char select_timeout; /* timeout (R5) */ + unsigned int asyncperiod; /* Async transfer period (ns) */ + unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */ + } ifcfg; + + /* queue handling */ + struct { + Queue_t issue; /* issue queue */ + Queue_t disconnected; /* disconnected command queue */ + } queues; + + /* per-device info */ + struct { + unsigned char disconnect_ok:1; /* device can disconnect */ + unsigned char stp; /* synchronous transfer period */ + unsigned char sof; /* synchronous offset register */ + syncneg_t negstate; /* synchronous transfer mode */ + } device[8]; + unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + + /* dma */ + struct { + fasdmatype_t transfer_type; /* current type of DMA transfer */ + fasdmatype_t (*setup) (struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction); + int (*pseudo)(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer); + void (*stop) (struct Scsi_Host *host, Scsi_Pointer *SCp); + } dma; + + /* miscellaneous */ + int internal_done; /* flag to indicate request done */ +} FAS216_Info; + +/* + * Function: int fas216_init (struct Scsi_Host *instance) + * + * Purpose : initialise FAS/NCR/AMD SCSI ic. + * + * Params : instance - a driver-specific filled-out structure + * + * Returns : 0 on success + */ +extern int fas216_init (struct Scsi_Host *instance); + +/* + * Function: int fas216_abort (Scsi_Cmnd *SCpnt) + * + * Purpose : abort a command if something horrible happens. + * + * Params : SCpnt - Command that is believed to be causing a problem. + * + * Returns : one of SCSI_ABORT_ macros. + */ +extern int fas216_abort (Scsi_Cmnd *); + +/* + * Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * + * Purpose : resets the adapter if something horrible happens. + * + * Params : SCpnt - Command that is believed to be causing a problem. + * reset_flags - flags indicating reset type that is believed to be required. + * + * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET macros. + */ +extern int fas216_reset (Scsi_Cmnd *, unsigned int); + +/* + * Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) + * + * Purpose : queue a command for adapter to process. + * + * Params : SCpnt - Command to queue + * done - done function to call once command is complete + * + * Returns : 0 - success, else error + */ +extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); + +/* + * Function: int fas216_command (Scsi_Cmnd *SCpnt) + * + * Purpose : queue a command for adapter to process. + * + * Params : SCpnt - Command to queue + * + * Returns : scsi result code + */ +extern int fas216_command (Scsi_Cmnd *); + +/* + * Function: void fas216_intr (struct Scsi_Host *instance) + * + * Purpose : handle interrupts from the interface to progress a command + * + * Params : instance - interface to service + */ +extern void fas216_intr (struct Scsi_Host *instance); + +/* + * Function: int fas216_release (struct Scsi_Host *instance) + * + * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. + * + * Params : instance - a driver-specific filled-out structure + * + * Returns : 0 on success + */ +extern int fas216_release (struct Scsi_Host *instance); + +#endif /* FAS216_H */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/msgqueue.c linux/drivers/acorn/scsi/msgqueue.c --- v2.1.87/linux/drivers/acorn/scsi/msgqueue.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/msgqueue.c Sat Feb 7 07:17:46 1998 @@ -0,0 +1,175 @@ +/* + * drivers/acorn/scsi/msgqueue.c: message queue handling + * + * Copyright (C) 1997,8 Russell King + */ + +#include +#include +#include + +#include "msgqueue.h" + +/* + * Function: struct msgqueue_entry *mqe_alloc (MsgQueue_t *msgq) + * Purpose : Allocate a message queue entry + * Params : msgq - message queue to claim entry for + * Returns : message queue entry or NULL. + */ +static struct msgqueue_entry *mqe_alloc (MsgQueue_t *msgq) +{ + struct msgqueue_entry *mq; + + if ((mq = msgq->free) != NULL) + msgq->free = mq->next; + + return mq; +} + +/* + * Function: void mqe_free (MsgQueue_t *msgq, struct msgqueue_entry *mq) + * Purpose : free a message queue entry + * Params : msgq - message queue to free entry from + * mq - message queue entry to free + */ +static void mqe_free (MsgQueue_t *msgq, struct msgqueue_entry *mq) +{ + if (mq) { + mq->next = msgq->free; + msgq->free = mq; + } +} + +/* + * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Purpose : initialise a message queue + * Params : msgq - queue to initialise + */ +void msgqueue_initialise (MsgQueue_t *msgq) +{ + int i; + + msgq->qe = NULL; + msgq->free = &msgq->entries[0]; + + for (i = 0; i < NR_MESSAGES; i++) + msgq->entries[i].next = &msgq->entries[i + 1]; + + msgq->entries[NR_MESSAGES - 1].next = NULL; +} + + +/* + * Function: void msgqueue_free (MsgQueue_t *msgq) + * Purpose : free a queue + * Params : msgq - queue to free + */ +void msgqueue_free (MsgQueue_t *msgq) +{ +} + +/* + * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Purpose : calculate the total length of all messages on the message queue + * Params : msgq - queue to examine + * Returns : number of bytes of messages in queue + */ +int msgqueue_msglength (MsgQueue_t *msgq) +{ + struct msgqueue_entry *mq = msgq->qe; + int length = 0; + + for (mq = msgq->qe; mq; mq = mq->next) + length += mq->length; + + return length; +} + +/* + * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Purpose : return a message & its length + * Params : msgq - queue to obtain message from + * length - pointer to int for message length + * Returns : pointer to message string + */ +char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) +{ + struct msgqueue_entry *mq; + + if ((mq = msgq->qe) != NULL) { + msgq->qe = mq->next; + mqe_free (msgq, mq); + *length = mq->length; + } + + return mq ? mq->msg : NULL; +} + +/* + * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Purpose : add a message onto a message queue + * Params : msgq - queue to add message on + * length - length of message + * ... - message bytes + * Returns : != 0 if successful + */ +int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) +{ + struct msgqueue_entry *mq = mqe_alloc (msgq); + va_list ap; + + if (mq) { + struct msgqueue_entry **mqp; + int i; + + va_start (ap, length); + for (i = 0; i < length; i++) + mq->msg[i] = va_arg (ap, unsigned char); + va_end (ap); + + mq->length = length; + mq->next = NULL; + + mqp = &msgq->qe; + while (*mqp) + mqp = &(*mqp)->next; + + *mqp = mq; + } + + return mq != NULL; +} + +/* + * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Purpose : flush all messages from message queue + * Params : msgq - queue to flush + */ +void msgqueue_flush (MsgQueue_t *msgq) +{ + struct msgqueue_entry *mq, *mqnext; + + for (mq = msgq->qe; mq; mq = mqnext) { + mqnext = mq->next; + mqe_free (msgq, mq); + } + msgq->qe = NULL; +} + +EXPORT_SYMBOL(msgqueue_initialise); +EXPORT_SYMBOL(msgqueue_free); +EXPORT_SYMBOL(msgqueue_msglength); +EXPORT_SYMBOL(msgqueue_getnextmsg); +EXPORT_SYMBOL(msgqueue_addmsg); +EXPORT_SYMBOL(msgqueue_flush); + +#ifdef MODULE +int init_module (void) +{ + return 0; +} + +void cleanup_module (void) +{ +} +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/msgqueue.h linux/drivers/acorn/scsi/msgqueue.h --- v2.1.87/linux/drivers/acorn/scsi/msgqueue.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/msgqueue.h Sat Oct 4 09:14:47 1997 @@ -0,0 +1,71 @@ +/* + * msgqueue.h: message queue handling + * + * (c) 1997 Russell King + */ +#ifndef MSGQUEUE_H +#define MSGQUEUE_H + +struct msgqueue_entry { + char msg[8]; + int length; + struct msgqueue_entry *next; +}; + +#define NR_MESSAGES 4 + +typedef struct { + struct msgqueue_entry *qe; + struct msgqueue_entry *free; + struct msgqueue_entry entries[NR_MESSAGES]; +} MsgQueue_t; + +/* + * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Purpose : initialise a message queue + * Params : msgq - queue to initialise + */ +extern void msgqueue_initialise (MsgQueue_t *msgq); + +/* + * Function: void msgqueue_free (MsgQueue_t *msgq) + * Purpose : free a queue + * Params : msgq - queue to free + */ +extern void msgqueue_free (MsgQueue_t *msgq); + +/* + * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Purpose : calculate the total length of all messages on the message queue + * Params : msgq - queue to examine + * Returns : number of bytes of messages in queue + */ +extern int msgqueue_msglength (MsgQueue_t *msgq); + +/* + * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Purpose : return a message & its length + * Params : msgq - queue to obtain message from + * length - pointer to int for message length + * Returns : pointer to message string + */ +extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length); + +/* + * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Purpose : add a message onto a message queue + * Params : msgq - queue to add message on + * length - length of message + * ... - message bytes + * Returns : != 0 if successful + */ +extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...); + +/* + * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Purpose : flush all messages from message queue + * Params : msgq - queue to flush + */ +extern void msgqueue_flush (MsgQueue_t *msgq); + +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c --- v2.1.87/linux/drivers/acorn/scsi/oak.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/oak.c Fri Feb 6 16:26:57 1998 @@ -0,0 +1,228 @@ +#define AUTOSENSE +/*#define PSEUDO_DMA*/ + +/* + * Oak Generic NCR5380 driver + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + */ + +/* + * $Log: oak.c,v $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "oak.h" +#include "../../scsi/NCR5380.h" +#include "../../scsi/constants.h" + +#undef START_DMA_INITIATOR_RECEIVE_REG +#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128) + +static const card_ids oakscsi_cids[] = { + { MANU_OAK, PROD_OAK_SCSI }, + { 0xffff, 0xffff } +}; + +static struct proc_dir_entry proc_scsi_oakscsi = { + PROC_SCSI_PAS16, 7, "oakscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0)) +#define OAK_IRQ(card) (IRQ_NONE) +/* + * Function : int oakscsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes oak NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ +static struct expansion_card *ecs[4]; + +int oakscsi_detect(Scsi_Host_Template * tpnt) +{ + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_oakscsi; + + memset (ecs, 0, sizeof (ecs)); + + ecard_startfind (); + + while(1) { + if ((ecs[count] = ecard_find(0, oakscsi_cids)) == NULL) + break; + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + instance->io_port = OAK_ADDRESS(ecs[count]); + instance->irq = OAK_IRQ(ecs[count]); + + NCR5380_init(instance, 0); + ecard_claim(ecs[count]); + + instance->n_io_port = 255; + request_region (instance->io_port, instance->n_io_port, "Oak SCSI"); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq != IRQ_NONE) { + printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); + printk("scsi%d: that the board had an interrupt!\n", instance->host_no); + } + + printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + CAN_QUEUE, CMD_PER_LUN, OAKSCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + + ++count; + } +#ifdef MODULE + if(count == 0) + printk("No oak scsi devices found\n"); +#endif + return count; +} + +int oakscsi_release (struct Scsi_Host *shpnt) +{ + int i; + + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + if (shpnt->io_port) + release_region (shpnt->io_port, shpnt->n_io_port); + + for (i = 0; i < 4; i++) + if (shpnt->io_port == OAK_ADDRESS(ecs[i])) + ecard_release (ecs[i]); + return 0; +} + +const char * oakscsi_info (struct Scsi_Host *spnt) { + return ""; +} + +#define STAT(p) inw(p + 144) +extern void inswb(int from, void *to, int len); + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; +printk("writing %p len %d\n",addr, len); + if(!len) return -1; + + while(1) + { + int status; + while(((status = STAT(iobase)) & 0x100)==0); + } +} + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; +printk("reading %p len %d\n", addr, len); + while(len > 0) + { + int status, timeout; + unsigned long b; + + timeout = 0x01FFFFFF; + + while(((status = STAT(iobase)) & 0x100)==0) + { + timeout--; + if(status & 0x200 || !timeout) + { + printk("status = %08X\n",status); + return 1; + } + } + if(len >= 128) + { + inswb(iobase + 136, addr, 128); + addr += 128; + len -= 128; + } + else + { + b = (unsigned long) inw(iobase + 136); + *addr ++ = b; + len -= 1; + if(len) + *addr ++ = b>>8; + len -= 1; + } + } + return 0; +} + +#define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg))) +#define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg))) + +#undef STAT + +#include "../../scsi/NCR5380.c" + +#ifdef MODULE + +Scsi_Host_Template driver_template = OAK_NCR5380; + +#include "../../scsi/scsi_module.c" +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/oak.h linux/drivers/acorn/scsi/oak.h --- v2.1.87/linux/drivers/acorn/scsi/oak.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/oak.h Sun Dec 28 09:20:10 1997 @@ -0,0 +1,97 @@ +/* + * Cumana Generic NCR5380 driver defines + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 440-4894 + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * $Log: oak_NCR5380.h,v $ + */ + +#ifndef OAK_NCR5380_H +#define OAK_NCR5380_H + +#define OAKSCSI_PUBLIC_RELEASE 1 + + +#ifndef ASM +int oakscsi_abort(Scsi_Cmnd *); +int oakscsi_detect(Scsi_Host_Template *); +int oakscsi_release(struct Scsi_Host *); +const char *oakscsi_info(struct Scsi_Host *); +int oakscsi_reset(Scsi_Cmnd *, unsigned int); +int oakscsi_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int oakscsi_proc_info (char *buffer, char **start, off_t off, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#define OAK_NCR5380 { \ +proc_info: oakscsi_proc_info, \ +name: "Oak 16-bit SCSI", \ +detect: oakscsi_detect, \ +release: oakscsi_release, /* Release */ \ +info: oakscsi_info, \ +queuecommand: oakscsi_queue_command, \ +abort: oakscsi_abort, \ +reset: oakscsi_reset, \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: 7, /* id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C +#define NCR5380_implementation_fields \ + int port, ctrl + +#define NCR5380_local_declare() \ + struct Scsi_Host *_instance + +#define NCR5380_setup(instance) \ + _instance = instance + +#define NCR5380_read(reg) oakscsi_read(_instance, reg) +#define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value) +#define NCR5380_intr oakscsi_intr +#define NCR5380_queue_command oakscsi_queue_command +#define NCR5380_abort oakscsi_abort +#define NCR5380_reset oakscsi_reset +#define NCR5380_proc_info oakscsi_proc_info + +#define BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#endif /* else def HOSTS_C */ +#endif /* ndef ASM */ +#endif /* OAK_NCR5380_H */ + diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c --- v2.1.87/linux/drivers/acorn/scsi/powertec.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/powertec.c Wed Feb 18 14:55:07 1998 @@ -0,0 +1,410 @@ +/* + * linux/arch/arm/drivers/scsi/powertec.c + * + * Copyright (C) 1997 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 01-10-1997 RMK Created, READONLY version + * 15-02-1998 RMK Added DMA support and hardware definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../scsi/sd.h" +#include "../../scsi/hosts.h" +#include "powertec.h" + +/* Configuration */ +#define POWERTEC_XTALFREQ 40 +#define POWERTEC_ASYNC_PERIOD 200 +#define POWERTEC_SYNC_DEPTH 16 + +/* + * List of devices that the driver will recognise + */ +#define POWERTECSCSI_LIST { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI } + +#define POWERTEC_FAS216_OFFSET 0xc00 +#define POWERTEC_FAS216_SHIFT 4 +#define POWERTEC_INTR_STATUS 0x800 +#define POWERTEC_INTR_BIT 0x80 +#define POWERTEC_INTR_CONTROL 0x407 +#define POWERTEC_INTR_ENABLE 1 +#define POWERTEC_INTR_DISABLE 0 + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 1 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_powertec = { + PROC_SCSI_QLOGICISP, 8, "powertec", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* Function: void powertecscsi_irqenable(ec, irqnr) + * Purpose : Enable interrupts on powertec SCSI card + * Params : ec - expansion card structure + * : irqnr - interrupt number + */ +static void +powertecscsi_irqenable(struct expansion_card *ec, int irqnr) +{ + unsigned int port = (unsigned int)ec->irq_data; + outb(POWERTEC_INTR_ENABLE, port); +} + +/* Function: void powertecscsi_irqdisable(ec, irqnr) + * Purpose : Disable interrupts on powertec SCSI card + * Params : ec - expansion card structure + * : irqnr - interrupt number + */ +static void +powertecscsi_irqdisable(struct expansion_card *ec, int irqnr) +{ + unsigned int port = (unsigned int)ec->irq_data; + outb(POWERTEC_INTR_DISABLE, port); +} + +static const expansioncard_ops_t powertecscsi_ops = { + powertecscsi_irqenable, + powertecscsi_irqdisable, + NULL, + NULL +}; + +/* Function: void powertecscsi_intr(int irq, void *dev_id, + * struct pt_regs *regs) + * Purpose : handle interrupts from Powertec SCSI card + * Params : irq - interrupt number + * dev_id - user-defined (Scsi_Host structure) + * regs - processor registers at interrupt + */ +static void +powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *instance = (struct Scsi_Host *)dev_id; + + fas216_intr(instance); +} + +static void +powertecscsi_invalidate(char *addr, long len, fasdmadir_t direction) +{ + unsigned int page; + + if (direction == DMA_OUT) { + for (page = (unsigned int) addr; len > 0; + page += PAGE_SIZE, len -= PAGE_SIZE) + flush_page_to_ram(page); + } else + flush_cache_range(current->mm, (unsigned long)addr, + (unsigned long)addr + len); +} + +/* Function: fasdmatype_t powertecscsi_dma_setup(instance, SCpnt, direction) + * Purpose : initialises DMA/PIO + * Params : instance - host + * SCpnt - command + * direction - DMA on to/off of card + * Returns : type of transfer to be performed + */ +static fasdmatype_t +powertecscsi_dma_setup(struct Scsi_Host *instance, Scsi_Pointer *SCp, + fasdmadir_t direction) +{ + if (instance->dma_channel != NO_DMA && SCp->this_residual >= 512) { + int buf; +static dmasg_t dmasg[256]; + + for (buf = 1; buf <= SCp->buffers_residual; buf++) { + dmasg[buf].address = __virt_to_bus( + (unsigned long)SCp->buffer[buf].address); + dmasg[buf].length = SCp->buffer[buf].length; + + powertecscsi_invalidate(SCp->buffer[buf].address, + SCp->buffer[buf].length, + direction); + } + + dmasg[0].address = __virt_to_phys((unsigned long)SCp->ptr); + dmasg[0].length = SCp->this_residual; + powertecscsi_invalidate(SCp->ptr, + SCp->this_residual, direction); + + disable_dma(instance->dma_channel); + set_dma_sg(instance->dma_channel, dmasg, buf); + set_dma_mode(instance->dma_channel, + direction == DMA_OUT ? DMA_MODE_WRITE : + DMA_MODE_READ); + enable_dma(instance->dma_channel); + return fasdma_real_all; + } + /* + * We don't do DMA, we only do slow PIO + */ + return fasdma_none; +} + +/* Function: int powertecscsi_dma_stop(instance, SCpnt) + * Purpose : stops DMA/PIO + * Params : instance - host + * SCpnt - command + */ +static void +powertecscsi_dma_stop(struct Scsi_Host *instance, Scsi_Pointer *SCp) +{ + if (instance->dma_channel != NO_DMA) + disable_dma(instance->dma_channel); +} + +/* Function: int powertecscsi_detect(Scsi_Host_Template * tpnt) + * Purpose : initialises PowerTec SCSI driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int +powertecscsi_detect(Scsi_Host_Template *tpnt) +{ + static const card_ids powertecscsi_cids[] = + { POWERTECSCSI_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_powertec; + memset(ecs, 0, sizeof (ecs)); + + ecard_startfind(); + + while(1) { + PowerTecScsi_Info *info; + + ecs[count] = ecard_find(0, powertecscsi_cids); + if (!ecs[count]) + break; + + ecard_claim(ecs[count]); + + instance = scsi_register(tpnt, sizeof (PowerTecScsi_Info)); + if (!instance) { + ecard_release(ecs[count]); + break; + } + + instance->io_port = ecard_address(ecs[count], ECARD_IOC, 0); + instance->irq = ecs[count]->irq; + + ecs[count]->irqaddr = (unsigned char *) + ioaddr(instance->io_port + POWERTEC_INTR_STATUS); + ecs[count]->irqmask = POWERTEC_INTR_BIT; + ecs[count]->irq_data = (void *) + (instance->io_port + POWERTEC_INTR_CONTROL); + ecs[count]->ops = (expansioncard_ops_t *)&powertecscsi_ops; + + request_region(instance->io_port + POWERTEC_FAS216_OFFSET, + 16 << POWERTEC_FAS216_SHIFT, "powertec2-fas"); + + if (request_irq(instance->irq, powertecscsi_intr, + SA_INTERRUPT, "powertec", instance)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = NO_IRQ; + } + + info = (PowerTecScsi_Info *)instance->hostdata; + + instance->dma_channel = 3; /* slot 1 */ + if (request_dma(instance->dma_channel, "powertec")) { + printk("scsi%d: DMA%d not free, DMA disabled\n", + instance->host_no, instance->dma_channel); + instance->dma_channel = NO_DMA; + } + + info->info.scsi.io_port = + instance->io_port + POWERTEC_FAS216_OFFSET; + info->info.scsi.io_shift= POWERTEC_FAS216_SHIFT; + info->info.scsi.irq = instance->irq; + info->info.ifcfg.clockrate = POWERTEC_XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD; + info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH; + info->info.dma.setup = powertecscsi_dma_setup; + info->info.dma.pseudo = NULL; + info->info.dma.stop = powertecscsi_dma_stop; + + fas216_init(instance); + ++count; + } + return count; +} + +/* Function: int powertecscsi_release(struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int powertecscsi_release(struct Scsi_Host *instance) +{ + int i; + + fas216_release(instance); + + if (instance->irq != NO_IRQ) + free_irq(instance->irq, instance); + if (instance->dma_channel != NO_DMA) + free_dma(instance->dma_channel); + release_region(instance->io_port + POWERTEC_FAS216_OFFSET, + 16 << POWERTEC_FAS216_SHIFT); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && + instance->io_port == ecard_address(ecs[i], ECARD_IOC, 0)) + ecard_release(ecs[i]); + return 0; +} + +/* Function: const char *powertecscsi_info(struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *powertecscsi_info(struct Scsi_Host *host) +{ + PowerTecScsi_Info *info = (PowerTecScsi_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf(string, "%s at port %X ", + host->hostt->name, host->io_port); + + if (host->irq != NO_IRQ) + p += sprintf(p, "irq %d ", host->irq); + else + p += sprintf(p, "NO IRQ "); + + if (host->dma_channel != NO_DMA) + p += sprintf(p, "dma %d ", host->dma_channel); + else + p += sprintf(p, "NO DMA "); + + p += sprintf(p, "v%d.%d.%d scsi %s", + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* Function: int powertecscsi_proc_info(char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int powertecscsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin; + struct Scsi_Host *host = scsi_hostlist; + PowerTecScsi_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (PowerTecScsi_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf(buffer, + "PowerTec SCSI driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf(buffer + pos, + "Address: %08X IRQ : %d DMA : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, host->dma_channel, + info->info.scsi.type); + + pos += sprintf(buffer+pos, + "Queued commands: %-10d Issued commands: %-10d\n" + "Done commands : %-10d Reads : %-10d\n" + "Writes : %-10d Others : %-10d\n" + "Disconnects : %-10d Aborts : %-10d\n" + "Resets : %-10d\n", + info->info.stats.queues, info->info.stats.removes, + info->info.stats.fins, info->info.stats.reads, + info->info.stats.writes, info->info.stats.miscs, + info->info.stats.disconnects, info->info.stats.aborts, + info->info.stats.resets); + + pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + + for (scd = host->host_queue; scd; scd = scd->next) { + int len; + + proc_print_scsidevice (scd, buffer, &len, pos); + pos += len; + pos += sprintf (buffer+pos, "Extensions: "); + if (scd->tagged_supported) + pos += sprintf (buffer+pos, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + pos += sprintf (buffer+pos, "\n"); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = POWERTECSCSI; + +#include "../../scsi/scsi_module.c" +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/powertec.h linux/drivers/acorn/scsi/powertec.h --- v2.1.87/linux/drivers/acorn/scsi/powertec.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/powertec.h Sun Feb 15 07:56:11 1998 @@ -0,0 +1,69 @@ +/* + * PowerTec SCSI driver + * + * Copyright (C) 1997 Russell King + */ +#ifndef POWERTECSCSI_H +#define POWERTECSCSI_H + +extern int powertecscsi_detect (Scsi_Host_Template *); +extern int powertecscsi_release (struct Scsi_Host *); +extern const char *powertecscsi_info (struct Scsi_Host *); +extern int powertecscsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#include "fas216.h" + +#define POWERTECSCSI { \ +proc_info: powertecscsi_proc_info, \ +name: "PowerTec SCSI", \ +detect: powertecscsi_detect, /* detect */ \ +release: powertecscsi_release, /* release */ \ +info: powertecscsi_info, /* info */ \ +command: fas216_command, /* command */ \ +queuecommand: fas216_queue_command, /* queuecommand */ \ +abort: fas216_abort, /* abort */ \ +reset: fas216_reset, /* reset */ \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: SCSI_ID, /* scsi host id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: ENABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ +} PowerTecScsi_Info; + +#endif /* HOSTS_C */ + +#endif /* POWERTECSCSI_H */ diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/queue.c linux/drivers/acorn/scsi/queue.c --- v2.1.87/linux/drivers/acorn/scsi/queue.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/queue.c Sat Feb 7 07:15:19 1998 @@ -0,0 +1,432 @@ +/* + * queue.c: queue handling primitives + * + * (c) 1997 Russell King + * + * Changelog: + * 15-Sep-1997 RMK Created. + * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude + * not updating internal linked list properly + * (was causing commands to go missing). + */ + +#define SECTOR_SIZE 512 + +#include +#include +#include +#include +#include + +#include "../../scsi/scsi.h" + +typedef struct queue_entry { + struct queue_entry *next; + struct queue_entry *prev; + unsigned long magic; + Scsi_Cmnd *SCpnt; +} QE_t; + +#define QUEUE_MAGIC_FREE 0xf7e1c9a3 +#define QUEUE_MAGIC_USED 0xf7e1cc33 + +#include "queue.h" + +/* + * Function: void queue_initialise (Queue_t *queue) + * Purpose : initialise a queue + * Params : queue - queue to initialise + */ +int queue_initialise (Queue_t *queue) +{ + unsigned int nqueues; + QE_t *q; + + queue->alloc = queue->free = q = (QE_t *) kmalloc (SECTOR_SIZE, GFP_KERNEL); + if (q) { + nqueues = SECTOR_SIZE / sizeof (QE_t); + + for (; nqueues; q++, nqueues--) { + q->next = q + 1; + q->prev = NULL; + q->magic = QUEUE_MAGIC_FREE; + q->SCpnt = NULL; + } + q->next = NULL; + } + + return q != NULL; +} + +/* + * Function: void queue_free (Queue_t *queue) + * Purpose : free a queue + * Params : queue - queue to free + */ +void queue_free (Queue_t *queue) +{ + if (queue->alloc) + kfree (queue->alloc); +} + + +/* + * Function: int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head. + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + QE_t *q; + + save_flags_cli (flags); + q = queue->free; + if (q) + queue->free = q->next; + + if (q) { + if (q->magic != QUEUE_MAGIC_FREE) { + restore_flags (flags); + panic ("scsi queues corrupted - queue entry not free"); + } + + q->magic = QUEUE_MAGIC_USED; + q->SCpnt = SCpnt; + + if (SCpnt->cmnd[0] == REQUEST_SENSE) { /* request_sense gets put on the queue head */ + if (queue->head) { + q->prev = NULL; + q->next = queue->head; + queue->head->prev = q; + queue->head = q; + } else { + q->next = q->prev = NULL; + queue->head = queue->tail = q; + } + } else { /* others get put on the tail */ + if (queue->tail) { + q->next = NULL; + q->prev = queue->tail; + queue->tail->next = q; + queue->tail = q; + } else { + q->next = q->prev = NULL; + queue->head = queue->tail = q; + } + } + } + restore_flags (flags); + + return q != NULL; +} + +/* + * Function: int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, adding onto tail of list + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + QE_t *q; + + save_flags_cli (flags); + q = queue->free; + if (q) + queue->free = q->next; + + if (q) { + if (q->magic != QUEUE_MAGIC_FREE) { + restore_flags (flags); + panic ("scsi queues corrupted - queue entry not free"); + } + + q->magic = QUEUE_MAGIC_USED; + q->SCpnt = SCpnt; + + if (queue->tail) { + q->next = NULL; + q->prev = queue->tail; + queue->tail->next = q; + queue->tail = q; + } else { + q->next = q->prev = NULL; + queue->head = queue->tail = q; + } + } + restore_flags (flags); + + return q != NULL; +} + +/* + * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude) + * Purpose : remove a SCSI command from a queue + * Params : queue - queue to remove command from + * exclude - bit array of target&lun which is busy + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned char *exclude) +{ + unsigned long flags; + Scsi_Cmnd *SCpnt; + QE_t *q, *prev; + + save_flags_cli (flags); + for (q = queue->head, prev = NULL; q; q = q->next) { + if (exclude && !test_bit (q->SCpnt->target * 8 + q->SCpnt->lun, exclude)) + break; + prev = q; + } + + if (q) { + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("q_remove_exclude: scsi queues corrupted - queue entry not used"); + } + if (q->prev != prev) + panic ("q_remove_exclude: scsi queues corrupted - q->prev != prev"); + + if (!prev) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + } else { + prev->next = q->next; + if (prev->next) + prev->next->prev = prev; + else + queue->tail = prev; + } + + SCpnt = q->SCpnt; + + q->next = queue->free; + queue->free = q; + q->magic = QUEUE_MAGIC_FREE; + } else + SCpnt = NULL; + + restore_flags (flags); + + return SCpnt; +} + +/* + * Function: Scsi_Cmnd *queue_remove (queue) + * Purpose : removes first SCSI command from a queue + * Params : queue - queue to remove command from + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +Scsi_Cmnd *queue_remove (Queue_t *queue) +{ + unsigned long flags; + Scsi_Cmnd *SCpnt; + QE_t *q; + + save_flags_cli (flags); + q = queue->head; + if (q) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("scsi queues corrupted - queue entry not used"); + } + + SCpnt = q->SCpnt; + + q->next = queue->free; + queue->free = q; + q->magic = QUEUE_MAGIC_FREE; + } else + SCpnt = NULL; + + restore_flags (flags); + + return SCpnt; +} + +/* + * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) + * Purpose : remove a SCSI command from the queue for a specified target/lun/tag + * Params : queue - queue to remove command from + * target - target that we want + * lun - lun on device + * tag - tag on device + * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements + */ +Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag) +{ + unsigned long flags; + Scsi_Cmnd *SCpnt; + QE_t *q, *prev; + + save_flags_cli (flags); + for (q = queue->head, prev = NULL; q; q = q->next) { + if (q->SCpnt->target == target && + q->SCpnt->lun == lun && + q->SCpnt->tag == tag) + break; + + prev = q; + } + + if (q) { + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("q_remove_tgtluntag: scsi queues corrupted - queue entry not used"); + } + if (q->prev != prev) + panic ("q_remove_tgtluntag: scsi queues corrupted - q->prev != prev"); + + if (!prev) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + } else { + prev->next = q->next; + if (prev->next) + prev->next->prev = prev; + else + queue->tail = prev; + } + + SCpnt = q->SCpnt; + + q->magic = QUEUE_MAGIC_FREE; + q->next = queue->free; + queue->free = q; + } else + SCpnt = NULL; + + restore_flags (flags); + + return SCpnt; +} + +/* + * Function: int queue_probetgtlun (queue, target, lun) + * Purpose : check to see if we have a command in the queue for the specified + * target/lun. + * Params : queue - queue to look in + * target - target we want to probe + * lun - lun on target + * Returns : 0 if not found, != 0 if found + */ +int queue_probetgtlun (Queue_t *queue, int target, int lun) +{ + QE_t *q; + + for (q = queue->head; q; q = q->next) + if (q->SCpnt->target == target && + q->SCpnt->lun == lun) + break; + + return q != NULL; +} + +/* + * Function: int queue_cmdonqueue (queue, SCpnt) + * Purpose : check to see if we have a command on the queue + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found, != 0 if found + */ +int queue_cmdonqueue (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + QE_t *q; + + for (q = queue->head; q; q = q->next) + if (q->SCpnt == SCpnt) + break; + + return q != NULL; +} + +/* + * Function: int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : remove a specific command from the queues + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found + */ +int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + QE_t *q, *prev; + + save_flags_cli (flags); + for (q = queue->head, prev = NULL; q; q = q->next) { + if (q->SCpnt == SCpnt) + break; + + prev = q; + } + + if (q) { + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("q_removecmd: scsi queues corrupted - queue entry not used"); + } + if (q->prev != prev) + panic ("q_removecmd: scsi queues corrupted - q->prev != prev"); + + if (!prev) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + } else { + prev->next = q->next; + if (prev->next) + prev->next->prev = prev; + else + queue->tail = prev; + } + + q->magic = QUEUE_MAGIC_FREE; + q->next = queue->free; + queue->free = q; + } + + restore_flags (flags); + + return q != NULL; +} + +EXPORT_SYMBOL(queue_initialise); +EXPORT_SYMBOL(queue_free); +EXPORT_SYMBOL(queue_remove); +EXPORT_SYMBOL(queue_remove_exclude); +EXPORT_SYMBOL(queue_add_cmd_ordered); +EXPORT_SYMBOL(queue_add_cmd_tail); +EXPORT_SYMBOL(queue_remove_tgtluntag); +EXPORT_SYMBOL(queue_probetgtlun); +EXPORT_SYMBOL(queue_cmdonqueue); +EXPORT_SYMBOL(queue_removecmd); + +#ifdef MODULE +int init_module (void) +{ + return 0; +} + +void cleanup_module (void) +{ +} +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/acorn/scsi/queue.h linux/drivers/acorn/scsi/queue.h --- v2.1.87/linux/drivers/acorn/scsi/queue.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/scsi/queue.h Thu Sep 25 14:35:09 1997 @@ -0,0 +1,106 @@ +/* + * queue.h: queue handling + * + * (c) 1997 Russell King + */ +#ifndef QUEUE_H +#define QUEUE_H + +typedef struct { + struct queue_entry *head; /* head of queue */ + struct queue_entry *tail; /* tail of queue */ + struct queue_entry *free; /* free list */ + void *alloc; /* start of allocated mem */ +} Queue_t; + +/* + * Function: void queue_initialise (Queue_t *queue) + * Purpose : initialise a queue + * Params : queue - queue to initialise + */ +extern int queue_initialise (Queue_t *queue); + +/* + * Function: void queue_free (Queue_t *queue) + * Purpose : free a queue + * Params : queue - queue to free + */ +extern void queue_free (Queue_t *queue); + +/* + * Function: Scsi_Cmnd *queue_remove (queue) + * Purpose : removes first SCSI command from a queue + * Params : queue - queue to remove command from + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +extern Scsi_Cmnd *queue_remove (Queue_t *queue); + +/* + * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude, ref) + * Purpose : remove a SCSI command from a queue + * Params : queue - queue to remove command from + * exclude - array of busy LUNs + * ref - a reference that can be used to put the command back + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned char *exclude); + +/* + * Function: int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, queueing REQUEST_SENSE first + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +extern int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt); + +/* + * Function: int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, queueing at end of list + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +extern int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt); + +/* + * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) + * Purpose : remove a SCSI command from the queue for a specified target/lun/tag + * Params : queue - queue to remove command from + * target - target that we want + * lun - lun on device + * tag - tag on device + * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements + */ +extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag); + +/* + * Function: int queue_probetgtlun (queue, target, lun) + * Purpose : check to see if we have a command in the queue for the specified + * target/lun. + * Params : queue - queue to look in + * target - target we want to probe + * lun - lun on target + * Returns : 0 if not found, != 0 if found + */ +extern int queue_probetgtlun (Queue_t *queue, int target, int lun); + +/* + * Function: int queue_cmdonqueue (queue, SCpnt) + * Purpose : check to see if we have a command on the queue + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found, != 0 if found + */ +int queue_cmdonqueue (Queue_t *queue, Scsi_Cmnd *SCpnt); + +/* + * Function: int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : remove a specific command from the queues + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found + */ +int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt); + +#endif /* QUEUE_H */ diff -u --recursive --new-file v2.1.87/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c --- v2.1.87/linux/drivers/ap1000/ddv.c Sun Jan 4 10:40:15 1998 +++ linux/drivers/ap1000/ddv.c Fri Feb 20 18:28:22 1998 @@ -14,7 +14,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.1.87/linux/drivers/block/acsi.c Fri Jan 16 20:35:26 1998 +++ linux/drivers/block/acsi.c Fri Feb 20 17:55:45 1998 @@ -59,8 +59,11 @@ #include #include #include - #include +#include /* for SCSI_IOCTL_GET_IDLUN */ +typedef void Scsi_Device; /* hack to avoid including scsi.h */ +#include +#include /* for HDIO_GETGEO */ #include #include @@ -70,7 +73,7 @@ #include #include #include -#include +#include #define DEBUG @@ -386,7 +389,7 @@ #ifdef CONFIG_ATARI_SLM -extern void attach_slm( int target, int lun ); +extern int attach_slm( int target, int lun ); extern int slm_init( void ); #endif @@ -1121,12 +1124,30 @@ if (dev >= NDevices) return -EINVAL; switch (cmd) { - /* I left out the GETGEO cmd; This doesn't make much sense for - * ACSI disks... - */ + case HDIO_GETGEO: + /* HDIO_GETGEO is supported more for getting the partition's start + * sector... */ + { struct hd_geometry *geo = (struct hd_geometry *)arg; + /* just fake some geometry here, it's nonsense anyway; to make it + * easy, use Adaptec's usual 64/32 mapping */ + put_user( 64, &geo->heads ); + put_user( 32, &geo->sectors ); + put_user( acsi_info[dev].size >> 11, &geo->cylinders ); + put_user( acsi_part[MINOR(inode->i_rdev)].start_sect, &geo->start ); + return 0; + } + + case SCSI_IOCTL_GET_IDLUN: + /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ + put_user( acsi_info[dev].target | (acsi_info[dev].lun << 8), + &((Scsi_Idlun *) arg)->dev_id ); + put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); + return 0; + case BLKGETSIZE: /* Return device size */ return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects, (long *) arg); + case BLKFLSBUF: if(!suser()) return -EACCES; if(!inode->i_rdev) return -EINVAL; @@ -1784,8 +1805,8 @@ return -EBUSY; } - if (!(acsi_buffer = (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, - ACSI_BUFFER_ORDER))) { + if (!(acsi_buffer = + (char *)atari_stram_alloc( ACSI_BUFFER_SIZE, NULL, "acsi" ))) { printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" ); unregister_blkdev( MAJOR_NR, "ad" ); return -ENOMEM; @@ -1824,14 +1845,17 @@ del_timer( &acsi_timer ); blk_dev[MAJOR_NR].request_fn = 0; - free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER ); + atari_stram_free( acsi_buffer ); if (unregister_blkdev( MAJOR_NR, "ad" ) != 0) printk( KERN_ERR "acsi: cleanup_module failed\n"); + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) if (*gdp == &acsi_gendisk) break; - if (*gdp) + if (!*gdp) + printk( KERN_ERR "acsi: entry in disk chain missing!\n" ); + else *gdp = (*gdp)->next; } #endif @@ -1861,7 +1885,7 @@ static int revalidate_acsidisk( int dev, int maxusage ) { - int device, major; + int device; struct gendisk * gdev; int max_p, start, i; struct acsi_info_struct *aip; @@ -1880,14 +1904,19 @@ max_p = gdev->max_p; start = device << gdev->minor_shift; - major = MAJOR_NR << 8; for( i = max_p - 1; i >= 0 ; i-- ) { - sync_dev( major | start | i ); - invalidate_inodes( major | start | i ); - invalidate_buffers( major | start | i ); + if (gdev->part[start + i].nr_sects != 0) { + kdev_t devp = MKDEV(MAJOR_NR, start + i); + struct super_block *sb = get_super(devp); + + fsync_dev(devp); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devp); + gdev->part[start + i].nr_sects = 0; + } gdev->part[start+i].start_sect = 0; - gdev->part[start+i].nr_sects = 0; }; stdma_lock( NULL, NULL ); diff -u --recursive --new-file v2.1.87/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c --- v2.1.87/linux/drivers/block/acsi_slm.c Sat Sep 20 14:51:54 1997 +++ linux/drivers/block/acsi_slm.c Fri Feb 20 17:55:45 1998 @@ -73,6 +73,7 @@ #include #include #include +#include #include @@ -252,15 +253,15 @@ static char *slm_errstr( int stat ); static int slm_getstats( char *buffer, int device ); -static long slm_read( struct inode *node, struct file* file, char *buf, - unsigned long count ); +static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t + *ppos ); static void start_print( int device ); static void slm_interrupt(int irc, void *data, struct pt_regs *fp); static void slm_test_ready( unsigned long dummy ); static void set_dma_addr( unsigned long paddr ); static unsigned long get_dma_addr( void ); -static long slm_write( struct inode *node, struct file *file, const char *buf, - unsigned long count ); +static ssize_t slm_write( struct file *file, const char *buf, size_t count, + loff_t *ppos ); static int slm_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); static int slm_open( struct inode *inode, struct file *file ); @@ -372,10 +373,12 @@ } -static long slm_read( struct inode *node, struct file* file, - char *buf, unsigned long count ) +static ssize_t slm_read( struct file *file, char *buf, size_t count, + loff_t *ppos ) -{ unsigned long page; +{ + struct inode *node = file->f_dentry->d_inode; + unsigned long page; int length; int end; @@ -625,10 +628,12 @@ } -static long slm_write( struct inode *node, struct file *file, - const char *buf, unsigned long count ) +static ssize_t slm_write( struct file *file, const char *buf, size_t count, + loff_t *ppos ) -{ int device = MINOR( node->i_rdev ); +{ + struct inode *node = file->f_dentry->d_inode; + int device = MINOR( node->i_rdev ); int n, filled, w, h; while( SLMState == PRINTING || @@ -1005,7 +1010,7 @@ return -EBUSY; } - if (!(SLMBuffer = kmalloc( SLM_BUFFER_SIZE, GFP_KERNEL | GFP_DMA))) { + if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, NULL, "SLM" ))) { printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" ); unregister_chrdev( MAJOR_NR, "slm" ); return -ENOMEM; @@ -1037,5 +1042,6 @@ { if (unregister_chrdev( MAJOR_NR, "slm" ) != 0) printk( KERN_ERR "acsi_slm: cleanup_module failed\n"); + atari_stram_free( SLMBuffer ); } #endif diff -u --recursive --new-file v2.1.87/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.1.87/linux/drivers/block/amiflop.c Tue May 13 22:41:04 1997 +++ linux/drivers/block/amiflop.c Fri Feb 20 17:55:45 1998 @@ -219,8 +219,8 @@ static int probing = 0; /* Prevent "aliased" accesses. */ -static fd_ref[4] = { 0,0,0,0 }; -static fd_device[4] = { 0,0,0,0 }; +static int fd_ref[4] = { 0,0,0,0 }; +static int fd_device[4] = { 0,0,0,0 }; /* * Current device number. Taken either from the block header or from the @@ -678,7 +678,7 @@ static void amiga_write(int disk, unsigned long raw, unsigned char *data, int track) { - int cnt; + unsigned int cnt; unsigned long *ptr = (unsigned long *)raw; disk&=3; @@ -1376,8 +1376,8 @@ static void redo_fd_request(void) { - unsigned int block, track, sector; - int device, drive, cnt; + unsigned int cnt, block, track, sector; + int device, drive; struct amiga_floppy_struct *floppy; char *data; unsigned long flags; @@ -1511,7 +1511,7 @@ { int drive = inode->i_rdev & 3; static struct floppy_struct getprm; - int error; + struct super_block * sb; unsigned long flags; switch(cmd){ @@ -1522,9 +1522,9 @@ loc.sectors = unit[drive].sects; loc.cylinders = unit[drive].type->tracks; loc.start = 0; - if ((error = copy_to_user((void *)param, (void *)&loc, - sizeof(struct hd_geometry)))) - return error; + if (copy_to_user((void *)param, (void *)&loc, + sizeof(struct hd_geometry))) + return -EFAULT; break; } case FDFMTBEG: @@ -1566,7 +1566,9 @@ break; case FDFMTEND: floppy_off(drive); - invalidate_inodes(inode->i_rdev); + sb = get_super(inode->i_rdev); + if (sb) + invalidate_inodes(sb); invalidate_buffers(inode->i_rdev); break; case FDGETPRM: @@ -1575,15 +1577,13 @@ getprm.head=unit[drive].type->heads; getprm.sect=unit[drive].sects; getprm.size=unit[drive].blocks; - if ((error = copy_to_user((void *)param, - (void *)&getprm, - sizeof(struct floppy_struct)))) - return error; + if (copy_to_user((void *)param, + (void *)&getprm, + sizeof(struct floppy_struct))) + return -EFAULT; break; case BLKGETSIZE: - if (put_user(unit[drive].blocks,(long *)param)) - return -EFAULT; - break; + return put_user(unit[drive].blocks,(long *)param); case FDSETPRM: case FDDEFPRM: return -EINVAL; @@ -1600,10 +1600,9 @@ break; #ifdef RAW_IOCTL case IOCTL_RAW_TRACK: - error = copy_to_user((void *)param, raw_buf, - unit[drive].type->read_size); - if (error) - return error; + if (copy_to_user((void *)param, raw_buf, + unit[drive].type->read_size)) + return -EFAULT; else return unit[drive].type->read_size; #endif @@ -1691,6 +1690,7 @@ if (type >= num_dr_types) { printk(KERN_WARNING "fd_probe: unsupported drive type %08lx found\n", code); + unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */ return; } @@ -1795,9 +1795,12 @@ static int floppy_release(struct inode * inode, struct file * filp) { unsigned long flags; + struct super_block * sb; fsync_dev(inode->i_rdev); - invalidate_inodes(inode->i_rdev); + sb = get_super(inode->i_rdev); + if (sb) + invalidate_inodes(sb); invalidate_buffers(inode->i_rdev); save_flags (flags); cli(); @@ -1819,10 +1822,10 @@ return 0; } -void amiga_floppy_setup (char *str, int *ints) +__initfunc(void amiga_floppy_setup (char *str, int *ints)) { -printk ("amiflop: Setting default df0 to %x\n", ints[1]); -fd_def_df0 = ints[1]; + printk ("amiflop: Setting default df0 to %x\n", ints[1]); + fd_def_df0 = ints[1]; } static struct file_operations floppy_fops = { diff -u --recursive --new-file v2.1.87/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c --- v2.1.87/linux/drivers/block/ataflop.c Sun Sep 21 10:46:52 1997 +++ linux/drivers/block/ataflop.c Fri Feb 20 17:55:45 1998 @@ -89,6 +89,7 @@ #include #include #include +#include #define MAJOR_NR FLOPPY_MAJOR #include @@ -278,7 +279,6 @@ 15*512, 30*512, 60*512 }; -#define MAX_SECTORS (MaxSectors[DriveType]) #define BUFFER_SIZE (BufferSize[DriveType]) unsigned char *DMABuffer; /* buffer for writes */ @@ -395,6 +395,7 @@ static void fd_rwsec( void ); static void fd_readtrack_check( unsigned long dummy ); static void fd_rwsec_done( int status ); +static void fd_rwsec_done1(int status); static void fd_writetrack( void ); static void fd_writetrack_done( int status ); static void fd_times_out( unsigned long dummy ); @@ -459,6 +460,7 @@ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1); + atari_dont_touch_floppy_select = 1; restore_flags(flags); /* restore track register to saved value */ @@ -482,8 +484,12 @@ save_flags(flags); cli(); /* protect against various other ints mucking around with the PSG */ + atari_dont_touch_floppy_select = 0; sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */ + sound_ym.wd_data = (sound_ym.rd_data_reg_sel | + (MACH_IS_FALCON ? 3 : 7)); /* no drives selected */ + /* On Falcon, the drive B select line is used on the printer port, so + * leave it alone... */ SelectedDrive = -1; restore_flags(flags); } @@ -977,11 +983,12 @@ * search for the first non-existent sector and need 1 sec to * recognise that it isn't present :-( */ + del_timer (&readtrack_timer); readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ); /* 1 rot. + 5 rot.s if motor was off */ - add_timer( &readtrack_timer ); MultReadInProgress = 1; + add_timer( &readtrack_timer ); } START_TIMEOUT(); } @@ -1028,6 +1035,7 @@ * the read operation */ SET_IRQ_HANDLER( NULL ); + MultReadInProgress = 0; restore_flags(flags); DPRINT(("fd_readtrack_check(): done\n")); FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); @@ -1036,7 +1044,7 @@ /* No error until now -- the FDC would have interrupted * otherwise! */ - fd_rwsec_done( 0 ); + fd_rwsec_done1(0); } else { /* not yet finished, wait another tenth rotation */ @@ -1050,19 +1058,23 @@ static void fd_rwsec_done( int status ) { - unsigned int track; - DPRINT(("fd_rwsec_done()\n")); - STOP_TIMEOUT(); - if (read_track) { + del_timer(&readtrack_timer); if (!MultReadInProgress) return; MultReadInProgress = 0; - del_timer( &readtrack_timer ); } + fd_rwsec_done1(status); +} +static void fd_rwsec_done1(int status) +{ + unsigned int track; + + STOP_TIMEOUT(); + /* Correct the track if stretch != 0 */ if (SUDT->stretch) { track = FDC_READ( FDCREG_TRACK); @@ -1147,7 +1159,7 @@ if (!ATARIHW_PRESENT( EXTD_DMA )) copy_buffer (addr, ReqData); } else { - dma_cache_maintenance( PhysTrackBuffer, MAX_SECTORS * 512, 0 ); + dma_cache_maintenance( PhysTrackBuffer, MaxSectors[DriveType] * 512, 0 ); BufferDrive = SelectedDrive; BufferSide = ReqSide; BufferTrack = ReqTrack; @@ -1802,7 +1814,7 @@ UD.steprate = FDCSTEP_12; break; default: /* should be -1 for "not set by user" */ - if (ATARIHW_PRESENT( FDCSPEED ) || is_medusa) + if (ATARIHW_PRESENT( FDCSPEED ) || MACH_IS_MEDUSA) UD.steprate = FDCSTEP_3; else UD.steprate = FDCSTEP_6; @@ -1827,7 +1839,7 @@ unsigned char status; int ok; - if (drive > 1) return( 0 ); + if (drive >= (MACH_IS_FALCON ? 1 : 2)) return( 0 ); fd_select_drive( drive ); /* disable interrupt temporarily */ @@ -2019,6 +2031,14 @@ { int i; + if (!MACH_IS_ATARI) + /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ + return -ENXIO; + + if (MACH_IS_HADES) + /* Hades doesn't have Atari-compatible floppy */ + return -ENXIO; + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { printk(KERN_ERR "Unable to get major %d for floppy\n",MAJOR_NR); return -EBUSY; @@ -2029,7 +2049,7 @@ track buffering off for all Medusas, though it could be used with ones that have a counter card. But the test is too hard :-( */ - UseTrackbuffer = !is_medusa; + UseTrackbuffer = !MACH_IS_MEDUSA; /* initialize variables */ SelectedDrive = -1; @@ -2039,7 +2059,7 @@ timer_table[FLOPPY_TIMER].fn = check_change; timer_active &= ~(1 << FLOPPY_TIMER); - DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA); + DMABuffer = atari_stram_alloc( BUFFER_SIZE+512, NULL, "ataflop" ); if (!DMABuffer) { printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n"); unregister_blkdev(MAJOR_NR, "fd"); @@ -2071,6 +2091,7 @@ UseTrackbuffer ? "" : "no "); config_types(); + (void)do_floppy; /* avoid warning about unused variable */ return 0; } @@ -2118,7 +2139,7 @@ blk_dev[MAJOR_NR].request_fn = 0; timer_active &= ~(1 << FLOPPY_TIMER); timer_table[FLOPPY_TIMER].fn = 0; - kfree (DMABuffer); + atari_stram_free( DMABuffer ); } #endif diff -u --recursive --new-file v2.1.87/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.1.87/linux/drivers/block/ide-cd.c Fri Jan 30 11:28:06 1998 +++ linux/drivers/block/ide-cd.c Fri Feb 20 18:28:22 1998 @@ -194,7 +194,6 @@ #define IDECD_VERSION "4.10" -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.1.87/linux/drivers/block/ide-disk.c Sat Jan 10 10:42:55 1998 +++ linux/drivers/block/ide-disk.c Fri Feb 20 12:58:07 1998 @@ -105,12 +105,15 @@ int i; unsigned int msect, nsect; struct request *rq; + unsigned long flags; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { ide_error(drive, "read_intr", stat); return; } msect = drive->mult_count; + + spin_lock_irqsave(&io_request_lock,flags); read_next: rq = HWGROUP(drive)->rq; if (msect) { @@ -119,6 +122,12 @@ msect -= nsect; } else nsect = 1; + /* + * PIO input can take longish times, so we drop the spinlock. + * On SMP, bad things might happen if syscall level code adds + * a new request while we do this PIO, so we just freeze all + * request queue handling while doing the PIO. FIXME + */ idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); #ifdef DEBUG printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", @@ -136,6 +145,7 @@ goto read_next; ide_set_handler (drive, &read_intr, WAIT_CMD); } + spin_unlock_irqrestore(&io_request_lock,flags); } /* @@ -147,7 +157,10 @@ int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; + unsigned long flags; + int error = 0; + spin_lock_irqsave(&io_request_lock,flags); if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { #ifdef DEBUG printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", @@ -166,10 +179,16 @@ idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); ide_set_handler (drive, &write_intr, WAIT_CMD); } - return; + goto out; } - } - ide_error(drive, "write_intr", stat); + } else + error = 1; + +out: + spin_unlock_irqrestore(&io_request_lock,flags); + + if (error) + ide_error(drive, "write_intr", stat); } /* @@ -217,13 +236,16 @@ int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = &hwgroup->wrq; + unsigned long flags; + int error = 0; + spin_lock_irqsave(&io_request_lock,flags); if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { if (stat & DRQ_STAT) { if (rq->nr_sectors) { ide_multwrite(drive, drive->mult_count); ide_set_handler (drive, &multwrite_intr, WAIT_CMD); - return; + goto out; } } else { if (!rq->nr_sectors) { /* all done? */ @@ -232,11 +254,17 @@ i -= rq->current_nr_sectors; ide_end_request(1, hwgroup); } - return; + goto out; } } - } - ide_error(drive, "multwrite_intr", stat); + } else + error = 1; + +out: + spin_unlock_irqrestore(&io_request_lock,flags); + + if (error) + ide_error(drive, "multwrite_intr", stat); } /* @@ -354,7 +382,7 @@ return; } if (!drive->unmask) - cli(); + __cli(); if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD); diff -u --recursive --new-file v2.1.87/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.87/linux/drivers/block/ide.c Fri Jan 30 15:50:57 1998 +++ linux/drivers/block/ide.c Fri Feb 20 12:58:07 1998 @@ -170,13 +170,13 @@ unsigned long t, flags; int i; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; - restore_flags(flags); + __restore_flags(flags); return (t - i); } #endif /* DISK_RECOVERY_TIME */ @@ -314,11 +314,11 @@ #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); do_vlb_sync(IDE_NSECTOR_REG); insl(IDE_DATA_REG, buffer, wcount); - restore_flags(flags); + __restore_flags(flags); } else #endif /* SUPPORT_VLB_SYNC */ insl(IDE_DATA_REG, buffer, wcount); @@ -347,11 +347,11 @@ #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); do_vlb_sync(IDE_NSECTOR_REG); outsl(IDE_DATA_REG, buffer, wcount); - restore_flags(flags); + __restore_flags(flags); } else #endif /* SUPPORT_VLB_SYNC */ outsl(IDE_DATA_REG, buffer, wcount); @@ -573,8 +573,8 @@ ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); - save_flags(flags); - cli(); /* Why ? */ + __save_flags(flags); + __cli(); /* Why ? */ /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { @@ -584,7 +584,7 @@ OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); - restore_flags (flags); + __restore_flags (flags); return; } @@ -612,7 +612,7 @@ ide_set_handler (drive, &reset_pollfunc, HZ/20); #endif /* OK_TO_RESET_CONTROLLER */ - restore_flags (flags); + __restore_flags (flags); } /* @@ -640,15 +640,15 @@ args[2] = IN_BYTE(IDE_NSECTOR_REG); } } - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); drive->queue = rq->next; blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; if (rq->sem != NULL) up(rq->sem); - restore_flags(flags); + __restore_flags(flags); } /* @@ -659,8 +659,8 @@ unsigned long flags; byte err = 0; - save_flags (flags); - ide_sti(); + __save_flags (flags); + /* ide_sti(); HACK */ printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); @@ -713,7 +713,7 @@ #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } - restore_flags (flags); + __restore_flags (flags); return err; } @@ -814,7 +814,7 @@ byte stat = GET_STAT(); int retries = 10; - ide_sti(); + /* ide_sti(); HACK */ if ((stat & DRQ_STAT) && args && args[3]) { byte io_32bit = drive->io_32bit; drive->io_32bit = 0; @@ -872,17 +872,17 @@ udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = GET_STAT()) & BUSY_STAT) { - save_flags(flags); - ide_sti(); + __save_flags(flags); + /* ide_sti(); HACK */ timeout += jiffies; while ((stat = GET_STAT()) & BUSY_STAT) { if (0 < (signed long)(jiffies - timeout)) { - restore_flags(flags); + __restore_flags(flags); ide_error(drive, "status timeout", stat); return 1; } } - restore_flags(flags); + __restore_flags(flags); } udelay(1); /* allow status to settle, then read it again */ if (OK_STAT((stat = GET_STAT()), good, bad)) @@ -932,7 +932,7 @@ struct request *rq = drive->queue; unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; - ide_sti(); + /* ide_sti(); HACK */ #ifdef DEBUG printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); #endif @@ -1093,7 +1093,7 @@ */ void ide_do_request (ide_hwgroup_t *hwgroup) { - cli(); /* paranoia */ + __cli(); /* paranoia */ if (hwgroup->handler != NULL) { printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); return; @@ -1108,7 +1108,7 @@ blk_dev[hwif->major].current_request = hwgroup->rq = drive->queue; drive->service_start = jiffies; do_request(hwgroup, hwif, drive); - cli(); + __cli(); } else { ide_leave_hwgroup(hwgroup); /* no work left for this hwgroup */ return; @@ -1157,27 +1157,27 @@ } } -void do_ide0_request (void) /* invoked with cli() */ +void do_ide0_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[0].hwgroup); } #if MAX_HWIFS > 1 -void do_ide1_request (void) /* invoked with cli() */ +void do_ide1_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[1].hwgroup); } #endif /* MAX_HWIFS > 1 */ #if MAX_HWIFS > 2 -void do_ide2_request (void) /* invoked with cli() */ +void do_ide2_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[2].hwgroup); } #endif /* MAX_HWIFS > 2 */ #if MAX_HWIFS > 3 -void do_ide3_request (void) /* invoked with cli() */ +void do_ide3_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[3].hwgroup); } @@ -1190,8 +1190,8 @@ ide_handler_t *handler; unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if ((handler = hwgroup->handler) != NULL) { hwgroup->handler = NULL; @@ -1202,7 +1202,7 @@ (void) hwgroup->hwif->dmaproc (ide_dma_end, drive); ide_error(drive, "irq timeout", GET_STAT()); } - cli(); + __cli(); if (hwgroup->handler == NULL) { set_recovery_timer(HWIF(drive)); drive->service_time = jiffies - drive->service_start; @@ -1210,7 +1210,7 @@ } } else do_hwgroup_request (hwgroup); - restore_flags(flags); + __restore_flags(flags); } /* @@ -1223,7 +1223,7 @@ * drive enters "idle", "standby", or "sleep" mode, so if the status looks * "good", we just ignore the interrupt completely. * - * This routine assumes cli() is in effect when called. + * This routine assumes __cli() is in effect when called. * * If an unexpected interrupt happens on irq15 while we are handling irq14 * and if the two interfaces are "serialized" (CMD640), then it looks like @@ -1261,10 +1261,11 @@ } /* - * entry point for all interrupts, caller does cli() for us + * entry point for all interrupts, caller does __cli() for us */ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; ide_hwgroup_t *hwgroup = dev_id; ide_hwif_t *hwif = hwgroup->hwif; ide_handler_t *handler; @@ -1290,19 +1291,21 @@ #endif /* temporary */ hwgroup->handler = NULL; del_timer(&(hwgroup->timer)); - if (drive->unmask) - ide_sti(); + /* if (drive->unmask) + ide_sti(); HACK */ handler(drive); - cli(); /* this is necessary, as next rq may be different irq */ + /* this is necessary, as next rq may be different irq */ + spin_lock_irqsave(&io_request_lock,flags); if (hwgroup->handler == NULL) { set_recovery_timer(HWIF(drive)); drive->service_time = jiffies - drive->service_start; ide_do_request(hwgroup); } + spin_unlock_irqrestore(&io_request_lock,flags); } else { unexpected_intr(irq, hwgroup); } - cli(); + __cli(); hwif = hwgroup->hwif; do { if (hwif->irq != irq) enable_irq(hwif->irq); @@ -1390,8 +1393,8 @@ if (action == ide_wait) rq->sem = &sem; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); cur_rq = drive->queue; if (cur_rq == NULL || action == ide_preempt) { @@ -1409,11 +1412,11 @@ } if (!hwgroup->active) { do_hwgroup_request(hwgroup); - cli(); + __cli(); } if (action == ide_wait && rq->rq_status != RQ_INACTIVE) down(&sem); /* wait for it to be serviced */ - restore_flags(flags); + __restore_flags(flags); return rq->errors ? -EIO : 0; /* return -EIO if errors */ } @@ -1435,15 +1438,15 @@ return -ENODEV; major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (drive->busy || (drive->usage > 1)) { - restore_flags(flags); + __restore_flags(flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; - restore_flags(flags); + __restore_flags(flags); for (p = 0; p < (1<part[p].nr_sects > 0) { @@ -1589,8 +1592,8 @@ if (index >= MAX_HWIFS) return; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; @@ -1680,7 +1683,7 @@ } init_hwif_data (index); /* restore hwif data to pristine status */ abort: - restore_flags(flags); + __restore_flags(flags); } int ide_register (int arg1, int arg2, int irq) @@ -1825,8 +1828,8 @@ return -EPERM; if (val < setting->min || val > setting->max) return -EINVAL; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (setting->set) rc = setting->set(drive, val); else switch (setting->data_type) { @@ -1845,7 +1848,7 @@ *p = val; break; } - restore_flags(flags); + __restore_flags(flags); return rc; } @@ -2697,16 +2700,16 @@ { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) { - restore_flags(flags); + __restore_flags(flags); return 1; } drive->driver = driver; setup_driver_defaults(drive); - restore_flags(flags); + __restore_flags(flags); if (drive->autotune != 2) { if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); @@ -2723,17 +2726,17 @@ { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) { - restore_flags(flags); + __restore_flags(flags); return 1; } ide_remove_proc_entries(drive, DRIVER(drive)->proc); ide_remove_proc_entries(drive, generic_subdriver_entries); auto_remove_settings(drive); drive->driver = NULL; - restore_flags(flags); + __restore_flags(flags); return 0; } diff -u --recursive --new-file v2.1.87/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.1.87/linux/drivers/block/ll_rw_blk.c Tue Feb 17 13:12:46 1998 +++ linux/drivers/block/ll_rw_blk.c Fri Feb 20 15:42:05 1998 @@ -22,6 +22,9 @@ #include #include +#define ATOMIC_ON() do { } while (0) +#define ATOMIC_OFF() do { } while (0) + /* * The request-struct contains all necessary data * to load a nr of sectors into memory @@ -37,7 +40,7 @@ /* * Protect the request list against multiple users.. */ -spinlock_t current_lock = SPIN_LOCK_UNLOCKED; +spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED; /* * used to wait on when there are no free requests @@ -340,6 +343,7 @@ unsigned int sector, count; struct request * req; int rw_ahead, max_req, max_sectors; + unsigned long flags; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -407,13 +411,20 @@ * Try to coalesce the new request with old requests */ max_sectors = get_max_sectors(bh->b_rdev); - cli(); + + /* + * Now we acquire the request spinlock, we have to be mega careful + * not to schedule or do something nonatomic + */ + spin_lock_irqsave(&io_request_lock,flags); + ATOMIC_ON(); + req = *get_queue(bh->b_rdev); if (!req) { /* MD and loop can't handle plugging without deadlocking */ if (major != MD_MAJOR && major != LOOP_MAJOR && major != DDV_MAJOR) - plug_device(blk_dev + major); + plug_device(blk_dev + major); /* is atomic */ } else switch (major) { case IDE0_MAJOR: /* same as HD_MAJOR */ case IDE1_MAJOR: @@ -467,14 +478,18 @@ continue; mark_buffer_clean(bh); - sti(); + ATOMIC_OFF(); + spin_unlock_irqrestore(&io_request_lock,flags); return; + } while ((req = req->next) != NULL); } /* find an unused request. */ req = get_request(max_req, bh->b_rdev); - sti(); + + ATOMIC_OFF(); + spin_unlock_irqrestore(&io_request_lock,flags); /* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */ if (!req) { @@ -646,9 +661,12 @@ if (j == 0) { req[j] = get_request_wait(max_req, rdev); } else { - cli(); + unsigned long flags; + spin_lock_irqsave(&io_request_lock,flags); + ATOMIC_ON(); req[j] = get_request(max_req, rdev); - sti(); + ATOMIC_OFF(); + spin_unlock_irqrestore(&io_request_lock,flags); if (req[j] == NULL) break; } diff -u --recursive --new-file v2.1.87/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c --- v2.1.87/linux/drivers/block/rz1000.c Wed Dec 17 11:11:51 1997 +++ linux/drivers/block/rz1000.c Fri Feb 20 18:28:22 1998 @@ -15,6 +15,7 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ +#include /* for CONFIG_BLK_DEV_IDEPCI */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v2.1.87/linux/drivers/char/amigamouse.c Sat Sep 13 11:07:27 1997 +++ linux/drivers/char/amigamouse.c Fri Feb 20 17:55:45 1998 @@ -44,17 +44,17 @@ #include #include #include +#include #include #include #include #include -#include #include #include -#define MSE_INT_ON() mouseint_allowed = 1 -#define MSE_INT_OFF() mouseint_allowed = 0 +#define AMI_MSE_INT_ON() mouseint_allowed = 1 +#define AMI_MSE_INT_OFF() mouseint_allowed = 0 static struct mouse_status mouse; @@ -72,7 +72,7 @@ if(!mouseint_allowed) return; - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); /* * This routine assumes, just like Kickstart, that the mouse @@ -156,7 +156,7 @@ if (mouse.fasyncptr) kill_fasync(mouse.fasyncptr, SIGIO); } - MSE_INT_ON(); + AMI_MSE_INT_ON(); } static int fasync_mouse(struct file *filp, int on) @@ -178,7 +178,7 @@ if (--mouse.active) return 0; free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); MOD_DEC_USE_COUNT; return 0; } @@ -211,7 +211,7 @@ mouse.buttons = 0x87; mouse.active = 1; MOD_INC_USE_COUNT; - MSE_INT_ON(); + AMI_MSE_INT_ON(); return 0; } @@ -219,8 +219,8 @@ * writes are disallowed */ -static long write_mouse(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) +static ssize_t write_mouse(struct file * file, const char * buffer, + size_t count, loff_t *ppos) { return -EINVAL; } @@ -229,18 +229,15 @@ * read mouse data. Currently never blocks. */ -static long read_mouse(struct inode * inode, struct file * file, - char * buffer, unsigned long count) +static ssize_t read_mouse(struct file * file, char * buffer, + size_t count, loff_t *ppos) { - int r; int dx; int dy; unsigned char buttons; if (count < 3) return -EINVAL; - if ((r = verify_area(VERIFY_WRITE, buffer, count))) - return r; if (!mouse.ready) return -EAGAIN; @@ -251,7 +248,7 @@ * so paging in put_user() does not effect mouse tracking. */ - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); dx = mouse.dx; dy = mouse.dy; if (dx < -127) @@ -268,14 +265,17 @@ mouse.dx -= dx; mouse.dy -= dy; mouse.ready = 0; - MSE_INT_ON(); + AMI_MSE_INT_ON(); - put_user(buttons | 0x80, buffer); - put_user((char)dx, buffer + 1); - put_user((char)dy, buffer + 2); - for (r = 3; r < count; r++) - put_user(0x00, buffer + r); - return r; + if ((put_user(buttons | 0x80, buffer++)) || + put_user((char)dx, buffer++) || + put_user((char)dy, buffer++)) + return -EINVAL; + + if (count > 3) + if (clear_user(buffer, count - 3)) + return -EFAULT; + return count; } /* @@ -315,7 +315,7 @@ custom.joytest = 0; /* reset counters */ - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); mouse.active = 0; mouse.ready = 0; diff -u --recursive --new-file v2.1.87/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v2.1.87/linux/drivers/char/apm_bios.c Thu Feb 12 20:56:05 1998 +++ linux/drivers/char/apm_bios.c Thu Feb 19 14:58:40 1998 @@ -141,6 +141,8 @@ * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification * [Confirmed by BIOS disassembly] * P: Toshiba 1950S: battery life information only gets updated after resume + * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking + * broken in BIOS [Reported by Garst R. Reese ] * * Legend: U = unusable with APM patches * P = partially usable with APM patches @@ -279,9 +281,15 @@ : "a" (0x530a), "b" (1) \ APM_BIOS_CALL_END -#define APM_GET_EVENT(event, error) \ +#define APM_GET_BATTERY_STATUS(which, bx, cx, dx, si, error) \ APM_BIOS_CALL(al) \ - : "=a" (error), "=b" (event) \ + : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx), "=S" (si) \ + : "a" (0x530a), "b" (0x8000 | (which)) \ + APM_BIOS_CALL_END + +#define APM_GET_EVENT(event, info, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error), "=b" (event), "=c" (info) \ : "a" (0x530b) \ APM_BIOS_CALL_END @@ -356,7 +364,8 @@ "critical suspend", "user standby", "user suspend", - "system standby resume" + "system standby resume", + "capabilities change" }; #define NR_APM_EVENT_NAME \ (sizeof(apm_event_name) / sizeof(apm_event_name[0])) @@ -406,6 +415,8 @@ { APM_BAD_DEVICE, "Unrecognized device ID" }, { APM_BAD_PARAM, "Parameter out of range" }, { APM_NOT_ENGAGED, "Interface not engaged" }, + { APM_BAD_FUNCTION, "Function not supported" }, + { APM_RESUME_DISABLED, "Resume timer disabled" }, { APM_BAD_STATE, "Unable to enter requested state" }, /* N/A { APM_NO_EVENTS, "No events pending" }, */ { APM_NOT_PRESENT, "No APM present" } @@ -423,13 +434,15 @@ return APM_SUCCESS; } -static int apm_get_event(apm_event_t *event) +static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) { u_short error; - APM_GET_EVENT(*event, error); + APM_GET_EVENT(*event, *info, error); if (error & 0xff) return (error >> 8); + if (apm_bios_info.version < 0x0102) + *info = ~0; /* indicate info not valid */ return APM_SUCCESS; } @@ -481,6 +494,24 @@ return APM_SUCCESS; } +static int apm_get_battery_status(u_short which, + u_short *bat, u_short *life, u_short *nbat) +{ + u_short status, error; + + if (apm_bios_info.version < 0x0102) { + /* pretend we only have one battery. */ + if (which!=1) return APM_BAD_DEVICE; + *nbat = 1; + return apm_get_power_status(&status, bat, life); + } + + APM_GET_BATTERY_STATUS(which, status, *bat, *life, *nbat, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} + static inline int apm_engage_power_management(u_short device) { u_short error; @@ -652,10 +683,12 @@ { int error; apm_event_t event; + apm_eventinfo_t info; static int notified = 0; - error = apm_get_event(&event); + /* we don't use the eventinfo */ + error = apm_get_event(&event, &info); if (error == APM_SUCCESS) return event; @@ -718,6 +751,7 @@ case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: + case APM_CAPABILITY_CHANGE: send_event(event, 0, NULL); break; @@ -1106,12 +1140,17 @@ if (apm_bios_info.version == 0x001) apm_bios_info.version = 0x100; + /* BIOS < 1.2 doesn't set cseg_16_len */ + if (apm_bios_info.version < 0x102) + apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */ + printk(KERN_INFO " Entry %x:%lx cseg16 %x dseg %x", apm_bios_info.cseg, apm_bios_info.offset, apm_bios_info.cseg_16, apm_bios_info.dseg); if (apm_bios_info.version > 0x100) - printk(" cseg len %x, dseg len %x", - apm_bios_info.cseg_len, apm_bios_info.dseg_len); + printk(" cseg len %x, cseg16 len %x, dseg len %x", + apm_bios_info.cseg_len, apm_bios_info.cseg_16_len, + apm_bios_info.dseg_len); printk("\n"); /* @@ -1146,19 +1185,25 @@ set_limit(gdt[APM_DS >> 3], 64 * 1024); #else set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len); - set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); + set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len); set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len); #endif - apm_bios_info.version = 0x0101; + /* The APM 1.2 docs state that the apm_driver_version + * call can fail if we try to connect as 1.2 to a 1.1 bios. + */ + apm_bios_info.version = 0x0102; error = apm_driver_version(&apm_bios_info.version); - if (error != 0) + if (error != 0) { /* Fall back to an APM 1.1 connection. */ + apm_bios_info.version = 0x0101; + error = apm_driver_version(&apm_bios_info.version); + } + if (error != 0) /* Fall back to an APM 1.0 connection. */ apm_bios_info.version = 0x100; else { apm_engage_power_management(0x0001); printk( " Connection version %d.%d\n", (apm_bios_info.version >> 8) & 0xff, apm_bios_info.version & 0xff ); - apm_bios_info.version = 0x0101; } } diff -u --recursive --new-file v2.1.87/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v2.1.87/linux/drivers/char/atarimouse.c Sat Sep 13 11:07:27 1997 +++ linux/drivers/char/atarimouse.c Fri Feb 20 17:55:45 1998 @@ -90,14 +90,14 @@ return 0; } -static long write_mouse(struct inode *inode, struct file *file, - const char *buffer, unsigned long count) +static ssize_t write_mouse(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; } -static long read_mouse(struct inode *inode, struct file *file, - char *buffer, unsigned long count) +static ssize_t read_mouse(struct file * file, char * buffer, + size_t count, loff_t *ppos) { int dx, dy, buttons; diff -u --recursive --new-file v2.1.87/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.87/linux/drivers/char/bttv.c Tue Feb 17 13:12:46 1998 +++ linux/drivers/char/bttv.c Fri Feb 20 18:28:22 1998 @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -1684,7 +1683,7 @@ return -1; if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_jmp =(dword *) kmalloc(1024, GFP_KERNEL))) + if (!(btv->risc_jmp =(dword *) kmalloc(2048, GFP_KERNEL))) return -1; btv->vbi_odd=btv->risc_jmp+12; btv->vbi_even=btv->vbi_odd+256; diff -u --recursive --new-file v2.1.87/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.87/linux/drivers/char/bw-qcam.c Fri Jan 23 18:10:31 1998 +++ linux/drivers/char/bw-qcam.c Fri Feb 20 18:28:22 1998 @@ -43,7 +43,6 @@ ******************************************************************/ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.1.87/linux/drivers/char/c-qcam.c Fri Jan 23 18:10:31 1998 +++ linux/drivers/char/c-qcam.c Fri Feb 20 18:28:22 1998 @@ -9,7 +9,6 @@ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.1.87/linux/drivers/char/dsp56k.c Mon Jan 19 13:43:25 1998 +++ linux/drivers/char/dsp56k.c Fri Feb 20 18:28:22 1998 @@ -23,7 +23,6 @@ * for more details. */ -#include #include #include #include /* for kmalloc() and kfree() */ @@ -207,9 +206,10 @@ return 0; } -static long dsp56k_read(struct inode *inode, struct file *file, - char *buf, unsigned long count) +static ssize_t dsp56k_read(struct file *file, char *buf, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int dev = MINOR(inode->i_rdev) & 0x0f; switch(dev) @@ -269,9 +269,10 @@ } } -static long dsp56k_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static ssize_t dsp56k_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int dev = MINOR(inode->i_rdev) & 0x0f; switch(dev) diff -u --recursive --new-file v2.1.87/linux/drivers/char/ftape/compressor/zftape-compress.c linux/drivers/char/ftape/compressor/zftape-compress.c --- v2.1.87/linux/drivers/char/ftape/compressor/zftape-compress.c Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/compressor/zftape-compress.c Fri Feb 20 18:28:22 1998 @@ -31,7 +31,6 @@ char zftc_rev[] = "$Revision: 1.1.6.1 $"; char zftc_dat[] = "$Date: 1997/11/16 15:15:56 $"; -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/ftape/lowlevel/fdc-io.c linux/drivers/char/ftape/lowlevel/fdc-io.c --- v2.1.87/linux/drivers/char/ftape/lowlevel/fdc-io.c Fri Jan 30 11:28:07 1998 +++ linux/drivers/char/ftape/lowlevel/fdc-io.c Fri Feb 20 18:28:22 1998 @@ -26,6 +26,7 @@ * Linux. */ +#include /* for CONFIG_FT_* */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/ftape/zftape/zftape-rw.c linux/drivers/char/ftape/zftape/zftape-rw.c --- v2.1.87/linux/drivers/char/ftape/zftape/zftape-rw.c Tue Nov 25 14:45:28 1997 +++ linux/drivers/char/ftape/zftape/zftape-rw.c Fri Feb 20 18:28:22 1998 @@ -24,6 +24,7 @@ * zftape. */ +#include /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/ftape/zftape/zftape-rw.h linux/drivers/char/ftape/zftape/zftape-rw.h --- v2.1.87/linux/drivers/char/ftape/zftape/zftape-rw.h Tue Nov 25 14:45:28 1997 +++ linux/drivers/char/ftape/zftape/zftape-rw.h Fri Feb 20 18:28:22 1998 @@ -28,6 +28,7 @@ * */ +#include /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include "../zftape/zftape-buffers.h" #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) diff -u --recursive --new-file v2.1.87/linux/drivers/char/ftape/zftape/zftape_syms.c linux/drivers/char/ftape/zftape/zftape_syms.c --- v2.1.87/linux/drivers/char/ftape/zftape/zftape_syms.c Tue Nov 25 14:45:28 1997 +++ linux/drivers/char/ftape/zftape/zftape_syms.c Fri Feb 20 18:28:22 1998 @@ -24,7 +24,6 @@ * the ftape floppy tape driver exports */ -#include #define __NO_VERSION__ #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/hfmodem/main.c linux/drivers/char/hfmodem/main.c --- v2.1.87/linux/drivers/char/hfmodem/main.c Sun Nov 30 10:30:19 1997 +++ linux/drivers/char/hfmodem/main.c Fri Feb 20 18:28:22 1998 @@ -31,6 +31,7 @@ /*****************************************************************************/ +#include /* for CONFIG_HFMODEM_WSS and CONFIG_HFMODEM_SBC */ #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/joystick.c linux/drivers/char/joystick.c --- v2.1.87/linux/drivers/char/joystick.c Mon Dec 1 11:05:41 1997 +++ linux/drivers/char/joystick.c Fri Feb 20 18:28:22 1998 @@ -10,7 +10,6 @@ * and credits. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.1.87/linux/drivers/char/pc110pad.c Sat Nov 29 10:33:19 1997 +++ linux/drivers/char/pc110pad.c Fri Feb 20 18:28:22 1998 @@ -16,7 +16,6 @@ * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/pms.c linux/drivers/char/pms.c --- v2.1.87/linux/drivers/char/pms.c Fri Jan 23 18:10:31 1998 +++ linux/drivers/char/pms.c Fri Feb 20 18:28:22 1998 @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.1.87/linux/drivers/char/rocket.c Thu Feb 12 20:56:06 1998 +++ linux/drivers/char/rocket.c Fri Feb 20 18:28:22 1998 @@ -55,12 +55,10 @@ #include #endif #include -#include #else /* !NEW_MODULES */ #ifdef MODVERSIONS #define MODULE #endif -#include #include #endif /* NEW_MODULES */ diff -u --recursive --new-file v2.1.87/linux/drivers/char/selection.c linux/drivers/char/selection.c --- v2.1.87/linux/drivers/char/selection.c Mon Jun 16 16:35:55 1997 +++ linux/drivers/char/selection.c Fri Feb 20 18:28:22 1998 @@ -11,7 +11,6 @@ * Now that /dev/vcs exists, most of this can disappear again. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/isdn/isdn_syms.c linux/drivers/isdn/isdn_syms.c --- v2.1.87/linux/drivers/isdn/isdn_syms.c Thu Feb 27 10:57:30 1997 +++ linux/drivers/isdn/isdn_syms.c Fri Feb 20 18:28:22 1998 @@ -21,7 +21,6 @@ * Added GPL-Header, Id and Log * */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/macintosh/aty.c linux/drivers/macintosh/aty.c --- v2.1.87/linux/drivers/macintosh/aty.c Mon Jan 12 15:18:13 1998 +++ linux/drivers/macintosh/aty.c Fri Feb 20 18:28:22 1998 @@ -11,6 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include /* for CONFIG_CHIP_ID and CONFIG_STAT0 */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.1.87/linux/drivers/misc/parport_ax.c Fri Jan 30 11:28:07 1998 +++ linux/drivers/misc/parport_ax.c Fri Feb 20 18:28:22 1998 @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.87/linux/drivers/misc/parport_pc.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/misc/parport_pc.c Fri Feb 20 18:28:22 1998 @@ -39,7 +39,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.1.87/linux/drivers/net/3c503.c Sun Jan 4 10:55:08 1998 +++ linux/drivers/net/3c503.c Thu Feb 19 14:58:40 1998 @@ -675,10 +675,10 @@ struct device *dev = &dev_el2[this_dev]; if (dev->priv != NULL) { /* NB: el2_close() handles free_irq */ + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, EL2_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.1.87/linux/drivers/net/3c505.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/3c505.c Thu Feb 19 14:58:40 1998 @@ -1694,10 +1694,10 @@ for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { struct device *dev = &dev_3c505[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, ELP_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.1.87/linux/drivers/net/3c509.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/3c509.c Fri Feb 20 18:28:22 1998 @@ -34,7 +34,7 @@ #include -#include +#include /* for CONFIG_MCA */ #include #include #include @@ -47,7 +47,6 @@ #include #include #include -#include /* for CONFIG_MCA */ #include /* for udelay() */ #include @@ -864,11 +863,11 @@ for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) { struct device *dev = &dev_3c509[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree_s(dev->priv,sizeof(struct el3_private)); dev->priv = NULL; free_irq(dev->irq, dev); release_region(dev->base_addr, EL3_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.1.87/linux/drivers/net/3c59x.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/3c59x.c Fri Feb 20 18:28:22 1998 @@ -44,7 +44,6 @@ #define RX_RING_SIZE 32 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#include #ifdef MODULE #ifdef MODVERSIONS #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.87/linux/drivers/net/Makefile Fri Jan 30 15:50:57 1998 +++ linux/drivers/net/Makefile Fri Feb 20 18:24:17 1998 @@ -92,6 +92,22 @@ endif endif +ifeq ($(CONFIG_ARM_AM79C961A),y) +L_OBJS += am79c961a.o +else + ifeq ($(CONFIG_ARM_AM79C961A),m) + M_OBJS += am79c961a.o + endif +endif + +ifeq ($(CONFIG_ARM_ETHERH),y) +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_ARM_ETHERH),m) + CONFIG_8390_MODULE = y + endif +endif + ifeq ($(CONFIG_WD80x3),y) L_OBJS += wd.o diff -u --recursive --new-file v2.1.87/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.87/linux/drivers/net/Space.c Tue Dec 9 09:49:58 1997 +++ linux/drivers/net/Space.c Fri Feb 20 18:24:17 1998 @@ -277,6 +277,12 @@ #ifdef CONFIG_MIPS_JAZZ_SONIC && sonic_probe(dev) #endif +#ifdef CONFIG_ARCH_ACORN + && acorn_ethif_probe(dev) +#endif +#ifdef CONFIG_ARM_AM79C961A + && am79c961_probe(dev) +#endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ } diff -u --recursive --new-file v2.1.87/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v2.1.87/linux/drivers/net/ac3200.c Mon Nov 3 09:29:30 1997 +++ linux/drivers/net/ac3200.c Thu Feb 19 14:58:40 1998 @@ -366,12 +366,12 @@ for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { struct device *dev = &dev_ac32[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; /* Someday free_irq may be in ac_close_card() */ free_irq(dev->irq, dev); release_region(dev->base_addr, AC_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c --- v2.1.87/linux/drivers/net/am79c961a.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/am79c961a.c Mon Feb 16 15:50:21 1998 @@ -0,0 +1,638 @@ +/* + * linux/drivers/net/am79c961.c + * + * Derived from various things including skeleton.c + * + * R.M.King 1995. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define TX_BUFFERS 15 +#define RX_BUFFERS 25 + +#include "am79c961a.h" + +static unsigned int net_debug = NET_DEBUG; +static void am79c961_setmulticastlist (struct device *dev); + +static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n"; + +static void write_rreg (unsigned long base, unsigned int reg, unsigned short val) +{ + __asm__(" + strh %1, [%2] @ NET_RAP + strh %0, [%2, #-4] @ NET_RDP + " : : "r" (val), "r" (reg), "r" (0xf0000464)); +} + +static inline void +write_ireg (unsigned long base, unsigned int reg, unsigned short val) +{ + __asm__(" + strh %1, [%2] @ NET_RAP + strh %0, [%2, #8] @ NET_RDP + " : : "r" (val), "r" (reg), "r" (0xf0000464)); +} + +#define am_writeword(dev,off,val)\ + __asm__("\ + strh %0, [%1]\ + " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); + +static inline void am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length) +{ + offset = 0xe0000000 + (offset << 1); + length = (length + 1) & ~1; + if ((int)buf & 2) { + __asm__ __volatile__(" + strh %2, [%0], #4 + " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + buf += 2; + length -= 2; + } + while (length > 8) + { + unsigned int tmp, tmp2; + __asm__ __volatile__(" + ldmia %1!, {%2, %3} + strh %2, [%0], #4 + mov %2, %2, lsr #16 + strh %2, [%0], #4 + strh %3, [%0], #4 + mov %3, %3, lsr #16 + strh %3, [%0], #4 + " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) + : "0" (offset), "1" (buf)); + length -= 8; + } + while (length > 0) { + __asm__ __volatile__(" + strh %2, [%0], #4 + " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + buf += 2; + length -= 2; + } +} + +static inline unsigned short +read_rreg (unsigned int base_addr, unsigned int reg) +{ + unsigned short v; + __asm__(" + strh %1, [%2] @ NET_RAP + ldrh %0, [%2, #-4] @ NET_IDP + " : "=r" (v): "r" (reg), "r" (0xf0000464)); + return v; +} + +static inline unsigned short am_readword (struct device *dev, unsigned long off) +{ + unsigned long address = 0xe0000000 + (off << 1); + unsigned short val; + + __asm__(" + ldrh %0, [%1] + " : "=r" (val): "r" (address)); + return val; +} + +static inline void am_readbuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length) +{ + offset = 0xe0000000 + (offset << 1); + length = (length + 1) & ~1; + if ((int)buf & 2) { + unsigned int tmp; + __asm__ __volatile__(" + ldrh %2, [%0], #4 + strb %2, [%1], #1 + mov %2, %2, lsr #8 + strb %2, [%1], #1 + " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); + length -= 2; + } + while (length > 8) { + unsigned int tmp, tmp2, tmp3; + __asm__ __volatile__(" + ldrh %2, [%0], #4 + ldrh %3, [%0], #4 + orr %2, %2, %3, lsl #16 + ldrh %3, [%0], #4 + ldrh %4, [%0], #4 + orr %3, %3, %4, lsl #16 + stmia %1!, {%2, %3} + " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) + : "0" (offset), "1" (buf)); + length -= 8; + } + while (length > 0) { + unsigned int tmp; + __asm__ __volatile__(" + ldrh %2, [%0], #4 + strb %2, [%1], #1 + mov %2, %2, lsr #8 + strb %2, [%1], #1 + " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); + length -= 2; + } +} + +/* + * From here on is mostly non ARM specific. Watch the fact it knows + * the chip can hit all memory (kmalloc). + */ + +static int am79c961_ramtest(struct device *dev, unsigned int val) +{ + unsigned char *buffer = kmalloc (65536, GFP_KERNEL); + int i, error = 0, errorcount = 0; + + if (!buffer) + return 0; + memset (buffer, val, 65536); + am_writebuffer(dev, 0, buffer, 65536); + memset (buffer, val ^ 255, 65536); + am_readbuffer(dev, 0, buffer, 65536); + for (i = 0; i < 65536; i++) { + if (buffer[i] != val && !error) { + printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i); + error = 1; + errorcount ++; + } else if (error && buffer[i] == val) { + printk ("%05X\n", i); + error = 0; + } + } + if (error) + printk ("10000\n"); + kfree (buffer); + return errorcount; +} + +static void am79c961_init_for_open(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + unsigned long hdr_addr, first_free_addr; + unsigned long flags; + unsigned char *p; + int i; + + save_flags_cli (flags); + + write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ + write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP); + + restore_flags (flags); + + first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16; + hdr_addr = 0; + + priv->rxhead = 0; + priv->rxtail = 0; + priv->rxhdr = hdr_addr; + + for (i = 0; i < RX_BUFFERS; i++) + { + priv->rxbuffer[i] = first_free_addr; + am_writeword (dev, hdr_addr, first_free_addr); + am_writeword (dev, hdr_addr + 2, RMD_OWN); + am_writeword (dev, hdr_addr + 4, (-1600)); + am_writeword (dev, hdr_addr + 6, 0); + first_free_addr += 1600; + hdr_addr += 8; + } + priv->txhead = 0; + priv->txtail = 0; + priv->txhdr = hdr_addr; + for (i = 0; i < TX_BUFFERS; i++) + { + priv->txbuffer[i] = first_free_addr; + am_writeword (dev, hdr_addr, first_free_addr); + am_writeword (dev, hdr_addr + 2, 0); + am_writeword (dev, hdr_addr + 4, 0); + am_writeword (dev, hdr_addr + 6, 0); + first_free_addr += 1600; + hdr_addr += 8; + } + + for (i = LADRL; i <= LADRH; i++) + write_rreg (dev->base_addr, i, 0); + + for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) + write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); + + i = MODE_PORT0; + if (dev->flags & IFF_PROMISC) + i |= MODE_PROMISC; + + write_rreg (dev->base_addr, MODE, i); + write_rreg (dev->base_addr, BASERXL, priv->rxhdr); + write_rreg (dev->base_addr, BASERXH, 0); + write_rreg (dev->base_addr, BASETXL, priv->txhdr); + write_rreg (dev->base_addr, BASERXH, 0); + write_rreg (dev->base_addr, POLLINT, 0); + write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); + write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); + write_rreg (dev->base_addr, CSR0, CSR0_STOP); + write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM); + write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); +} + +static int am79c961_init(struct device *dev) +{ + unsigned long flags; + + am79c961_ramtest(dev, 0x66); + am79c961_ramtest(dev, 0x99); + + save_flags_cli (flags); + + write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ + write_rreg (dev->base_addr, CSR0, CSR0_STOP); + write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); + + restore_flags (flags); + + return 0; +} + +/* + * This is the real probe routine. + */ + +static int am79c961_probe1(struct device *dev) +{ + static unsigned version_printed = 0; + struct dev_priv *priv; + int i; + + if (!dev->priv) + { + dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; + } + + priv = (struct dev_priv *) dev->priv; + memset (priv, 0, sizeof(struct dev_priv)); + + /* + * The PNP initialisation should have been done by the ether bootp loader. + */ + + inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */ + + udelay (5); + + if (inb (dev->base_addr >> 1) != 0x08 || + inb ((dev->base_addr >> 1) + 1) != 00 || + inb ((dev->base_addr >> 1) + 2) != 0x2b) + { + kfree (dev->priv); + dev->priv = NULL; + return -ENODEV; + } + + /* + * Ok, we've found a valid hw ID + */ + + if (net_debug && version_printed++ == 0) + printk (KERN_INFO "%s", version); + + printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq); + request_region (dev->base_addr, 0x18, "am79c961"); + + /* Retrive and print the ethernet address. */ + for (i = 0; i < 6; i++) + { + dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff; + printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); + } + + if (am79c961_init(dev)) + { + kfree (dev->priv); + dev->priv = NULL; + return -ENODEV; + } + + dev->open = am79c961_open; + dev->stop = am79c961_close; + dev->hard_start_xmit = am79c961_sendpacket; + dev->get_stats = am79c961_getstats; + dev->set_multicast_list = am79c961_setmulticastlist; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; +} + +int am79c961_probe(struct device *dev) +{ + static int initialised = 0; + + if (initialised) + return -ENODEV; + initialised = 1; + + dev->base_addr = 0x220; + dev->irq = 3; + + return am79c961_probe1(dev); +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ + +static int am79c961_open(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + + MOD_INC_USE_COUNT; + + memset (&priv->stats, 0, sizeof (priv->stats)); + + if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) + return -EAGAIN; + + am79c961_init_for_open(dev); + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + return 0; +} + +/* + * The inverse routine to am79c961_open(). + */ + +static int am79c961_close(struct device *dev) +{ + dev->tbusy = 1; + dev->start = 0; + + am79c961_init(dev); + free_irq (dev->irq, dev); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Get the current statistics. This may be called with the card open or + * closed. + */ + +static struct enet_statistics *am79c961_getstats (struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + return &priv->stats; +} + +/* + * Set or clear promiscuous/multicast mode filter for this adaptor. + * + * We don't attempt any packet filtering. The card may have a SEEQ 8004 + * in which does not have the other ethernet address registers present... + */ + +static void am79c961_setmulticastlist (struct device *dev) +{ + unsigned long flags; + int i; + + dev->flags &= ~IFF_ALLMULTI; + + i = MODE_PORT0; + if (dev->flags & IFF_PROMISC) + i |= MODE_PROMISC; + + save_flags_cli (flags); + write_rreg (dev->base_addr, MODE, i); + restore_flags (flags); +} + +/* + * Transmit a packet + */ + +static int am79c961_sendpacket(struct sk_buff *skb, struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + + if (!dev->tbusy) + { +again: + if (!test_and_set_bit(0, (void*)&dev->tbusy)) + { + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int hdraddr, bufaddr; + unsigned long flags; + + hdraddr = priv->txhdr + (priv->txhead << 3); + bufaddr = priv->txbuffer[priv->txhead]; + priv->txhead ++; + if (priv->txhead >= TX_BUFFERS) + priv->txhead = 0; + + am_writebuffer (dev, bufaddr, skb->data, length); + am_writeword (dev, hdraddr + 4, -length); + am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); + + save_flags_cli (flags); + write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); + dev->trans_start = jiffies; + restore_flags (flags); + + if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)) + dev->tbusy = 0; + dev_kfree_skb (skb, FREE_WRITE); + return 0; + } + else + { + printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); + return 1; + } + } + else + { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name); + /* Try to restart the adaptor. */ + dev->tbusy = 0; + dev->trans_start = jiffies; + goto again; + } +} + +static void am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct dev_priv *priv = (struct dev_priv *)dev->priv; + unsigned int status; + +#if NET_DEBUG > 1 + if(net_debug & DEBUG_INT) + printk(KERN_DEBUG "am79c961irq: %d ", irq); +#endif + + dev->interrupt = 1; + status = read_rreg (dev->base_addr, CSR0); + write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); + + if (status & CSR0_RINT) /* Got a packet(s). */ + am79c961_rx (dev, priv); + if (status & CSR0_TINT) /* Packets transmitted */ + am79c961_tx (dev, priv); + if (status & CSR0_MISS) + priv->stats.rx_dropped ++; + + dev->interrupt = 0; + +#if NET_DEBUG > 1 + if(net_debug & DEBUG_INT) + printk("done\n"); +#endif +} + +/* + * If we have a good packet(s), get it/them out of the buffers. + */ + +static void am79c961_rx(struct device *dev, struct dev_priv *priv) +{ + unsigned long hdraddr; + unsigned long pktaddr; + + do + { + unsigned long status; + struct sk_buff *skb; + int len; + + hdraddr = priv->rxhdr + (priv->rxtail << 3); + pktaddr = priv->rxbuffer[priv->rxtail]; + + status = am_readword (dev, hdraddr + 2); + if (status & RMD_OWN) /* do we own it? */ + break; + + priv->rxtail ++; + if (priv->rxtail >= RX_BUFFERS) + priv->rxtail = 0; + + if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) + { + am_writeword (dev, hdraddr + 2, RMD_OWN); + priv->stats.rx_errors ++; + if (status & RMD_ERR) + { + if (status & RMD_FRAM) + priv->stats.rx_frame_errors ++; + if (status & RMD_CRC) + priv->stats.rx_crc_errors ++; + } + else if (status & RMD_STP) + priv->stats.rx_length_errors ++; + continue; + } + + len = am_readword (dev, hdraddr + 6); + skb = dev_alloc_skb (len + 2); + + if (skb) { + unsigned char *buf; + + skb->dev = dev; + skb_reserve (skb, 2); + buf = skb_put (skb, len); + + am_readbuffer (dev, pktaddr, buf, len); + am_writeword (dev, hdraddr + 2, RMD_OWN); + skb->protocol = eth_type_trans(skb, dev); + netif_rx (skb); + priv->stats.rx_packets ++; + } else { + am_writeword (dev, hdraddr + 2, RMD_OWN); + printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped ++; + break; + } + } while (1); +} + +/* + * Update stats for the transmitted packet + */ + +static void am79c961_tx(struct device *dev, struct dev_priv *priv) +{ + do { + unsigned long hdraddr; + unsigned long status; + + hdraddr = priv->txhdr + (priv->txtail << 3); + status = am_readword (dev, hdraddr + 2); + if (status & TMD_OWN) + break; + + priv->txtail ++; + if (priv->txtail >= TX_BUFFERS) + priv->txtail = 0; + + if (status & TMD_ERR) { + unsigned long status2; + + priv->stats.tx_errors ++; + + status2 = am_readword (dev, hdraddr + 6); + am_writeword (dev, hdraddr + 6, 0); + + if (status2 & TST_RTRY) + priv->stats.collisions += 1; + if (status2 & TST_LCOL) + priv->stats.tx_window_errors ++; + if (status2 & TST_LCAR) + priv->stats.tx_carrier_errors ++; + if (status2 & TST_UFLO) + priv->stats.tx_fifo_errors ++; + continue; + } + priv->stats.tx_packets ++; + } while (priv->txtail != priv->txhead); + + dev->tbusy = 0; + mark_bh (NET_BH); +} + diff -u --recursive --new-file v2.1.87/linux/drivers/net/am79c961a.h linux/drivers/net/am79c961a.h --- v2.1.87/linux/drivers/net/am79c961a.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/am79c961a.h Mon Feb 16 15:50:21 1998 @@ -0,0 +1,128 @@ +/* + * linux/drivers/net/am79c961.h + */ + +#ifndef _LINUX_am79c961a_H +#define _LINUX_am79c961a_H + +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */ +#define DEBUG_TX 2 +#define DEBUG_RX 4 +#define DEBUG_INT 8 +#define DEBUG_IC 16 +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +#define NET_UID 0 +#define NET_RDP 0x10 +#define NET_RAP 0x12 +#define NET_RESET 0x14 +#define NET_IDP 0x16 + +/* + * RAP registers + */ +#define CSR0 0 +#define CSR0_INIT 0x0001 +#define CSR0_STRT 0x0002 +#define CSR0_STOP 0x0004 +#define CSR0_TDMD 0x0008 +#define CSR0_TXON 0x0010 +#define CSR0_RXON 0x0020 +#define CSR0_IENA 0x0040 +#define CSR0_INTR 0x0080 +#define CSR0_IDON 0x0100 +#define CSR0_TINT 0x0200 +#define CSR0_RINT 0x0400 +#define CSR0_MERR 0x0800 +#define CSR0_MISS 0x1000 +#define CSR0_CERR 0x2000 +#define CSR0_BABL 0x4000 +#define CSR0_ERR 0x8000 + +#define CSR3 3 +#define CSR3_EMBA 0x0008 +#define CSR3_DXMT2PD 0x0010 +#define CSR3_LAPPEN 0x0020 +#define CSR3_IDONM 0x0100 +#define CSR3_TINTM 0x0200 +#define CSR3_RINTM 0x0400 +#define CSR3_MERRM 0x0800 +#define CSR3_MISSM 0x1000 +#define CSR3_BABLM 0x4000 +#define CSR3_MASKALL 0x5F00 + +#define LADRL 8 +#define LADRM1 9 +#define LADRM2 10 +#define LADRH 11 +#define PADRL 12 +#define PADRM 13 +#define PADRH 14 + +#define MODE 15 +#define MODE_DISRX 0x0001 +#define MODE_DISTX 0x0002 +#define MODE_LOOP 0x0004 +#define MODE_DTCRC 0x0008 +#define MODE_COLL 0x0010 +#define MODE_DRETRY 0x0020 +#define MODE_INTLOOP 0x0040 +#define MODE_PORT0 0x0080 +#define MODE_DRXPA 0x2000 +#define MODE_DRXBA 0x4000 +#define MODE_PROMISC 0x8000 + +#define BASERXL 24 +#define BASERXH 25 +#define BASETXL 30 +#define BASETXH 31 + +#define POLLINT 47 + +#define SIZERXR 76 +#define SIZETXR 78 + +#define RMD_ENP 0x0100 +#define RMD_STP 0x0200 +#define RMD_CRC 0x0800 +#define RMD_FRAM 0x2000 +#define RMD_ERR 0x4000 +#define RMD_OWN 0x8000 + +#define TMD_ENP 0x0100 +#define TMD_STP 0x0200 +#define TMD_MORE 0x1000 +#define TMD_ERR 0x4000 +#define TMD_OWN 0x8000 + +#define TST_RTRY 0x0200 +#define TST_LCAR 0x0400 +#define TST_LCOL 0x1000 +#define TST_UFLO 0x4000 + +struct dev_priv { + struct enet_statistics stats; + unsigned long rxbuffer[RX_BUFFERS]; + unsigned long txbuffer[TX_BUFFERS]; + unsigned char txhead; + unsigned char txtail; + unsigned char rxhead; + unsigned char rxtail; + unsigned long rxhdr; + unsigned long txhdr; +}; + +extern int am79c961_probe (struct device *dev); +static int am79c961_probe1 (struct device *dev); +static int am79c961_open (struct device *dev); +static int am79c961_sendpacket (struct sk_buff *skb, struct device *dev); +static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static void am79c961_rx (struct device *dev, struct dev_priv *priv); +static void am79c961_tx (struct device *dev, struct dev_priv *priv); +static int am79c961_close (struct device *dev); +static struct enet_statistics *am79c961_getstats (struct device *dev); +static void am79c961_setmulticastlist (struct device *dev); + +#endif diff -u --recursive --new-file v2.1.87/linux/drivers/net/arc-rimi.c linux/drivers/net/arc-rimi.c --- v2.1.87/linux/drivers/net/arc-rimi.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/arc-rimi.c Fri Feb 20 18:28:22 1998 @@ -26,7 +26,6 @@ #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/atarilance.c linux/drivers/net/atarilance.c --- v2.1.87/linux/drivers/net/atarilance.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/atarilance.c Fri Feb 20 17:55:45 1998 @@ -819,6 +819,7 @@ head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; dev_kfree_skb( skb ); lp->cur_tx++; + lp->stats.tx_bytes += skb->len; while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { lp->cur_tx -= TX_RING_SIZE; lp->dirty_tx -= TX_RING_SIZE; @@ -1027,6 +1028,7 @@ skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/com20020.c linux/drivers/net/com20020.c --- v2.1.87/linux/drivers/net/com20020.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/com20020.c Fri Feb 20 18:28:22 1998 @@ -28,7 +28,6 @@ #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/com90io.c linux/drivers/net/com90io.c --- v2.1.87/linux/drivers/net/com90io.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/com90io.c Fri Feb 20 18:28:22 1998 @@ -28,7 +28,6 @@ #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/com90xx.c linux/drivers/net/com90xx.c --- v2.1.87/linux/drivers/net/com90xx.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/com90xx.c Fri Feb 20 18:28:22 1998 @@ -26,7 +26,6 @@ #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/cops.c linux/drivers/net/cops.c --- v2.1.87/linux/drivers/net/cops.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/cops.c Fri Feb 20 18:28:22 1998 @@ -47,7 +47,6 @@ #include #endif -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.1.87/linux/drivers/net/cs89x0.c Thu Feb 12 20:56:07 1998 +++ linux/drivers/net/cs89x0.c Fri Feb 20 18:28:22 1998 @@ -44,7 +44,6 @@ /* Always include 'config.h' first in case the user wants to turn on or override something. */ -#include #ifdef MODULE #include #include @@ -1078,11 +1077,11 @@ if (dev_cs89x0.priv != NULL) { /* Free up the private structure, or leak memory :-) */ + unregister_netdev(&dev_cs89x0); kfree(dev_cs89x0.priv); dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ /* If we don't do this, we can't re-insmod it later. */ release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); - unregister_netdev(&dev_cs89x0); } } #endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/dlci.c linux/drivers/net/dlci.c --- v2.1.87/linux/drivers/net/dlci.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/dlci.c Fri Feb 20 18:28:22 1998 @@ -28,6 +28,7 @@ * 2 of the License, or (at your option) any later version. */ +#include /* for CONFIG_DLCI_COUNT */ #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.1.87/linux/drivers/net/e2100.c Sun Jan 4 10:55:08 1998 +++ linux/drivers/net/e2100.c Thu Feb 19 14:58:40 1998 @@ -441,10 +441,10 @@ struct device *dev = &dev_e21[this_dev]; if (dev->priv != NULL) { /* NB: e21_close() handles free_irq */ + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, E21_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.87/linux/drivers/net/eepro100.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/eepro100.c Fri Feb 20 18:28:22 1998 @@ -38,7 +38,6 @@ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 200; -#include #ifdef MODULE #ifdef MODVERSIONS #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.1.87/linux/drivers/net/eexpress.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/eexpress.c Thu Feb 19 14:58:40 1998 @@ -1558,10 +1558,10 @@ for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { struct device *dev = &dev_eexp[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, EEXP_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/es3210.c linux/drivers/net/es3210.c --- v2.1.87/linux/drivers/net/es3210.c Sun Jan 4 10:55:08 1998 +++ linux/drivers/net/es3210.c Thu Feb 19 14:58:40 1998 @@ -430,11 +430,11 @@ for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { struct device *dev = &dev_es3210[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(dev->base_addr, ES_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.1.87/linux/drivers/net/ewrk3.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/ewrk3.c Thu Feb 19 14:58:40 1998 @@ -1904,13 +1904,13 @@ void cleanup_module(void) { + unregister_netdev(&thisEthwrk); if (thisEthwrk.priv) { kfree(thisEthwrk.priv); thisEthwrk.priv = NULL; } thisEthwrk.irq = 0; - unregister_netdev(&thisEthwrk); release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v2.1.87/linux/drivers/net/hp-plus.c Sun Jan 4 10:55:08 1998 +++ linux/drivers/net/hp-plus.c Thu Feb 19 14:58:40 1998 @@ -466,10 +466,10 @@ if (dev->priv != NULL) { /* NB: hpp_close() handles free_irq */ int ioaddr = dev->base_addr - NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(ioaddr, HP_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.1.87/linux/drivers/net/hp.c Thu Jan 15 14:33:06 1998 +++ linux/drivers/net/hp.c Thu Feb 19 14:58:40 1998 @@ -433,11 +433,11 @@ struct device *dev = &dev_hp[this_dev]; if (dev->priv != NULL) { int ioaddr = dev->base_addr - NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(ioaddr, HP_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c --- v2.1.87/linux/drivers/net/lapbether.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/lapbether.c Fri Feb 20 18:28:22 1998 @@ -18,7 +18,6 @@ * LAPBETH 001 Jonathan Naylor Cloned from bpqether.c */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.87/linux/drivers/net/ltpc.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/ltpc.c Fri Feb 20 18:28:22 1998 @@ -180,7 +180,6 @@ #define DEBUG_UPPER 2 #define DEBUG_LOWER 4 -#include /* for CONFIG_MAX_16M */ #ifdef MODULE #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.1.87/linux/drivers/net/ne.c Fri Jan 30 11:28:07 1998 +++ linux/drivers/net/ne.c Thu Feb 19 14:58:40 1998 @@ -782,11 +782,11 @@ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct device *dev = &dev_ne[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(dev->base_addr, NE_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.1.87/linux/drivers/net/ni52.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/ni52.c Thu Feb 19 14:58:40 1998 @@ -1338,9 +1338,9 @@ void cleanup_module(void) { release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); + unregister_netdev(&dev_ni52); kfree(dev_ni52.priv); dev_ni52.priv = NULL; - unregister_netdev(&dev_ni52); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.1.87/linux/drivers/net/ni65.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/ni65.c Thu Feb 19 14:58:40 1998 @@ -1202,10 +1202,10 @@ } disable_dma(dev_ni65.dma); free_dma(dev_ni65.dma); + unregister_netdev(&dev_ni65); release_region(dev_ni65.base_addr,cards[p->cardno].total_size); ni65_free_buffer(p); dev_ni65.priv = NULL; - unregister_netdev(&dev_ni65); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.87/linux/drivers/net/plip.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/plip.c Fri Feb 20 18:28:22 1998 @@ -80,7 +80,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.87/linux/drivers/net/ppp.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/ppp.c Fri Feb 20 18:28:22 1998 @@ -50,6 +50,7 @@ /* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */ +#include /* for CONFIG_KERNELD */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/sdla.c linux/drivers/net/sdla.c --- v2.1.87/linux/drivers/net/sdla.c Sat Nov 29 10:33:20 1997 +++ linux/drivers/net/sdla.c Fri Feb 20 18:28:22 1998 @@ -32,6 +32,7 @@ * 2 of the License, or (at your option) any later version. */ +#include /* for CONFIG_DLCI_MAX */ #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.87/linux/drivers/net/sdla_ppp.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/sdla_ppp.c Fri Feb 20 18:28:22 1998 @@ -59,6 +59,7 @@ #error This code MUST be compiled as a kernel module! #endif +#include /* CONFIG_SANGOMA_MANAGER */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c --- v2.1.87/linux/drivers/net/sdladrv.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/sdladrv.c Fri Feb 20 18:28:22 1998 @@ -81,7 +81,6 @@ #if defined(_LINUX_) /****** Linux *******************************/ -#include /* OS configuration options */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c --- v2.1.87/linux/drivers/net/seeq8005.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/seeq8005.c Thu Feb 19 14:58:40 1998 @@ -209,10 +209,7 @@ #endif outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */ - SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(5); outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD); if (net_debug) { @@ -626,10 +623,7 @@ int i; outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */ - SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(5); outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */ @@ -638,7 +632,7 @@ for(i=0;i<6;i++) { /* set Station address */ outb(dev->dev_addr[i], SEEQ_BUFFER); - SLOW_DOWN_IO; + udelay(2); } outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */ diff -u --recursive --new-file v2.1.87/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.1.87/linux/drivers/net/slip.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/slip.c Thu Feb 19 14:58:40 1998 @@ -969,11 +969,12 @@ switch(cmd) { case SIOCGIFNAME: - err = verify_area(VERIFY_WRITE, arg, strlen(sl->dev->name) + 1); - if (err) { - return err; - } - copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1); + /* Please, do not put this line under copy_to_user, + it breaks my old poor gcc on alpha --ANK + */ + tmp = strlen(sl->dev->name) + 1; + if (copy_to_user(arg, sl->dev->name, tmp) < 0) + return -EFAULT; return 0; case SIOCGIFENCAP: diff -u --recursive --new-file v2.1.87/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c --- v2.1.87/linux/drivers/net/smc-mca.c Mon Nov 3 09:29:31 1997 +++ linux/drivers/net/smc-mca.c Thu Feb 19 14:58:40 1998 @@ -367,10 +367,10 @@ { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v2.1.87/linux/drivers/net/smc-ultra.c Sun Jan 4 10:55:08 1998 +++ linux/drivers/net/smc-ultra.c Thu Feb 19 14:58:40 1998 @@ -475,10 +475,10 @@ if (dev->priv != NULL) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/wd.c linux/drivers/net/wd.c --- v2.1.87/linux/drivers/net/wd.c Sun Jan 4 10:55:09 1998 +++ linux/drivers/net/wd.c Thu Feb 19 14:58:40 1998 @@ -497,11 +497,11 @@ struct device *dev = &dev_wd[this_dev]; if (dev->priv != NULL) { int ioaddr = dev->base_addr - WD_NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(ioaddr, WD_IO_EXTENT); - unregister_netdev(dev); } } } diff -u --recursive --new-file v2.1.87/linux/drivers/net/x25_asy.c linux/drivers/net/x25_asy.c --- v2.1.87/linux/drivers/net/x25_asy.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/x25_asy.c Fri Feb 20 18:28:22 1998 @@ -11,7 +11,6 @@ * checksum routines from ppp.c */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.1.87/linux/drivers/pci/proc.c Fri Jan 30 11:28:08 1998 +++ linux/drivers/pci/proc.c Fri Feb 20 18:28:22 1998 @@ -6,7 +6,6 @@ * Copyright (c) 1997 Martin Mares */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/sbus/audio/amd7930.c linux/drivers/sbus/audio/amd7930.c --- v2.1.87/linux/drivers/sbus/audio/amd7930.c Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/audio/amd7930.c Fri Feb 20 18:28:22 1998 @@ -15,7 +15,6 @@ * databook which has all the programming information and gain tables. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.1.87/linux/drivers/sbus/audio/cs4231.c Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/audio/cs4231.c Fri Feb 20 18:28:22 1998 @@ -8,7 +8,6 @@ * sun4m machines. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/sbus/char/mach64.c linux/drivers/sbus/char/mach64.c --- v2.1.87/linux/drivers/sbus/char/mach64.c Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/char/mach64.c Fri Feb 20 18:28:22 1998 @@ -8,6 +8,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include /* for CONFIG_CHIP_ID */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.1.87/linux/drivers/scsi/53c7xx.c Sat May 24 09:10:24 1997 +++ linux/drivers/scsi/53c7xx.c Fri Feb 20 18:28:22 1998 @@ -100,8 +100,6 @@ * the fourth byte from 50 to 25. */ -#include - /* * Sponsored by * iX Multiuser Multitasking Magazine @@ -233,7 +231,6 @@ #endif #include - #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c --- v2.1.87/linux/drivers/scsi/gdth_proc.c Tue Nov 4 09:17:30 1997 +++ linux/drivers/scsi/gdth_proc.c Fri Feb 20 18:55:44 1998 @@ -620,12 +620,12 @@ oldto = scp->timeout; scp->timeout = timeout; if (timeout > 0) { - if (timer_table[SCSI_TIMER].expires == 0) { - timer_table[SCSI_TIMER].expires = jiffies + timeout; - timer_active |= 1 << SCSI_TIMER; + if (timer_table[GDTH_TIMER].expires == 0) { + timer_table[GDTH_TIMER].expires = jiffies + timeout; + timer_active |= 1 << GDTH_TIMER; } else { - if (jiffies + timeout < timer_table[SCSI_TIMER].expires) - timer_table[SCSI_TIMER].expires = jiffies + timeout; + if (jiffies + timeout < timer_table[GDTH_TIMER].expires) + timer_table[GDTH_TIMER].expires = jiffies + timeout; } } diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.1.87/linux/drivers/scsi/hosts.h Tue Feb 17 13:12:47 1998 +++ linux/drivers/scsi/hosts.h Fri Feb 20 19:13:25 1998 @@ -377,7 +377,7 @@ * alignment to a 4-byte boundary. */ unsigned long hostdata[0] /* Used for storage of host specific stuff */ - __attribute__ ((aligned (4))); + __attribute__ ((aligned (sizeof(unsigned long)))); }; extern struct Scsi_Host * scsi_hostlist; diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h --- v2.1.87/linux/drivers/scsi/ppa.h Fri Feb 6 15:33:47 1998 +++ linux/drivers/scsi/ppa.h Fri Feb 20 19:13:32 1998 @@ -15,6 +15,7 @@ /* Use the following to enable certain chipset support * Default is PEDANTIC = 3 */ +#include /* for CONFIG_SCSI_PPA_HAVE_PEDANTIC */ #ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC #define CONFIG_SCSI_PPA_HAVE_PEDANTIC 3 #endif diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.87/linux/drivers/scsi/scsi.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/scsi/scsi.c Fri Feb 20 18:58:26 1998 @@ -51,6 +51,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -122,6 +123,8 @@ 12, 12, 10, 10 }; static unsigned long serial_number = 0; static Scsi_Cmnd * scsi_bh_queue_head = NULL; +static Scsi_Cmnd * scsi_bh_queue_tail = NULL; +static spinlock_t scsi_bh_queue_spin = SPIN_LOCK_UNLOCKED; static FreeSectorBitmap * dma_malloc_freelist = NULL; static int need_isa_bounce_buffers; static unsigned int dma_sectors = 0; @@ -1523,7 +1526,6 @@ scsi_done (Scsi_Cmnd * SCpnt) { unsigned long flags; - Scsi_Cmnd * SCswap; /* * We don't have to worry about this one timing out any more. @@ -1551,35 +1553,20 @@ * If it was NULL before, then everything is fine, and we are done * (this is the normal case). If it was not NULL, then we block interrupts, * and link them together. + * We need a spinlock here, or compare and exchange if we can reorder incoming + * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times + * before bh is serviced. -jj */ - - SCswap = (Scsi_Cmnd *) xchg(&scsi_bh_queue_head, SCpnt); - if( SCswap != NULL ) - { - /* - * If we assume that the interrupt handler doesn't dawdle, then it is safe to - * say that we should come in here extremely rarely. Under very heavy load, - * the requests might not be removed from the list fast enough so that we - * *do* end up stacking them, and that would be bad. - */ - save_flags(flags); - cli(); - - /* - * See if the pointer is NULL - it might have been serviced already - */ - if( scsi_bh_queue_head == NULL ) - { - scsi_bh_queue_head = SCswap; - } - else - { - SCswap->bh_next = scsi_bh_queue_head; - scsi_bh_queue_head = SCswap; - } - - restore_flags(flags); + + spin_lock_irqsave(&scsi_bh_queue_spin, flags); + if (!scsi_bh_queue_head) { + scsi_bh_queue_head = SCpnt; + scsi_bh_queue_tail = SCpnt; + } else { + scsi_bh_queue_tail->bh_next = SCpnt; + scsi_bh_queue_tail = SCpnt; } + spin_unlock_irqrestore(&scsi_bh_queue_spin, flags); /* * Mark the bottom half handler to be run. @@ -1603,7 +1590,7 @@ Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCnext; static atomic_t recursion_depth; - + unsigned long flags; while(1==1) { @@ -1622,15 +1609,17 @@ } /* - * This is an atomic operation - swap the pointer with a NULL pointer + * We need to hold the spinlock, so that nobody is tampering with the queue. -jj * We will process everything we find in the list here. */ - SCpnt = xchg(&scsi_bh_queue_head, NULL); + + spin_lock_irqsave(&scsi_bh_queue_spin, flags); + SCpnt = scsi_bh_queue_head; + scsi_bh_queue_head = NULL; + spin_unlock_irqrestore(&scsi_bh_queue_spin, flags); if( SCpnt == NULL ) - { return; - } atomic_inc(&recursion_depth); diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.87/linux/drivers/scsi/scsi.h Tue Feb 17 13:12:47 1998 +++ linux/drivers/scsi/scsi.h Fri Feb 20 19:13:25 1998 @@ -15,6 +15,8 @@ #ifndef _SCSI_H #define _SCSI_H +#include /* for CONFIG_SCSI_LOGGING */ + /* * Some of the public constants are being moved to this file. * We include it here so that what came from where is transparent. @@ -685,7 +687,7 @@ #define INIT_SCSI_REQUEST \ if (!CURRENT) { \ CLEAR_INTR; \ - spin_unlock_irqrestore(¤t_lock,flags); \ + spin_unlock_irqrestore(&io_request_lock,flags); \ return; \ } \ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \ diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.87/linux/drivers/scsi/scsi_obsolete.c Thu Jan 8 20:35:43 1998 +++ linux/drivers/scsi/scsi_obsolete.c Fri Feb 20 18:28:22 1998 @@ -47,6 +47,7 @@ * driver uses the new code this *ENTIRE* file will be nuked. */ +#include /* for CONFIG_KERNELD */ #define __NO_VERSION__ #include diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c --- v2.1.87/linux/drivers/scsi/scsi_proc.c Sun Dec 21 17:04:49 1997 +++ linux/drivers/scsi/scsi_proc.c Fri Feb 20 18:28:22 1998 @@ -16,6 +16,7 @@ * Michael A. Griffith */ +#include /* for CONFIG_PROC_FS */ #define __NO_VERSION__ #include @@ -291,7 +292,7 @@ *size = y; return; } -#endif /* CONFIG_SCSI_PROC */ +#endif /* CONFIG_PROC_FS */ /* * Overrides for Emacs so that we get a uniform tabbing style. diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.87/linux/drivers/scsi/sd.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/scsi/sd.c Fri Feb 20 12:58:56 1998 @@ -517,10 +517,10 @@ int flag = 0; while (1==1){ - spin_lock_irqsave(¤t_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - spin_unlock_irqrestore(¤t_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -535,7 +535,7 @@ */ if( SDev->host->in_recovery ) { - spin_unlock_irqrestore(¤t_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -555,7 +555,7 @@ */ if( SDev->removable && !in_interrupt() ) { - spin_unlock(¤t_lock); + spin_unlock_irqrestore(&io_request_lock, flags); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); /* scsi_ioctl may allow CURRENT to change, so start over. */ SDev->was_reset = 0; @@ -587,7 +587,7 @@ * Using a "sti()" gets rid of the latency problems but causes * race conditions and crashes. */ - spin_unlock_irqrestore(¤t_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); /* This is a performance enhancement. We dig down into the request * list and try to find a queueable request (i.e. device not busy, @@ -605,7 +605,7 @@ if (!SCpnt && sd_template.nr_dev > 1){ struct request *req1; req1 = NULL; - spin_lock_irqsave(¤t_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); req = CURRENT; while(req){ SCpnt = scsi_request_queueable(req, @@ -620,7 +620,7 @@ else req1->next = req->next; } - spin_unlock_irqrestore(¤t_lock, flags); + spin_unlock_irqrestore(&io_request_lock, flags); } if (!SCpnt) return; /* Could not find anything to do */ diff -u --recursive --new-file v2.1.87/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.87/linux/drivers/scsi/sr.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/scsi/sr.c Fri Feb 20 18:28:22 1998 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -432,10 +431,10 @@ int flag = 0; while (1==1){ - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; }; @@ -451,6 +450,7 @@ */ if( SDev->host->in_recovery ) { + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -469,7 +469,11 @@ */ if( SDev->removable && !in_interrupt() ) { + spin_unlock_irqrestore(&io_request_lock, flags); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); + /* scsi_ioctl may allow CURRENT to change, so start over. * + SDev->was_reset = 0; + continue; } SDev->was_reset = 0; } @@ -489,7 +493,7 @@ SCpnt = scsi_allocate_device(&CURRENT, scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); else SCpnt = NULL; - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); /* This is a performance enhancement. We dig down into the request list and * try to find a queueable request (i.e. device not busy, and host able to @@ -501,8 +505,7 @@ if (!SCpnt && sr_template.nr_dev > 1){ struct request *req1; req1 = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); req = CURRENT; while(req){ SCpnt = scsi_request_queueable(req, @@ -510,15 +513,15 @@ if(SCpnt) break; req1 = req; req = req->next; - }; + } if (SCpnt && req->rq_status == RQ_INACTIVE) { if (req == CURRENT) CURRENT = CURRENT->next; else req1->next = req->next; - }; - restore_flags(flags); - }; + } + spin_unlock_irqrestore(&io_request_lock, flags); + } if (!SCpnt) return; /* Could not find anything to do */ @@ -527,7 +530,7 @@ /* Queue command */ requeue_sr_request(SCpnt); - }; /* While */ + } /* While */ } void requeue_sr_request (Scsi_Cmnd * SCpnt) diff -u --recursive --new-file v2.1.87/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c --- v2.1.87/linux/drivers/sgi/char/sgiserial.c Wed Dec 10 10:31:11 1997 +++ linux/drivers/sgi/char/sgiserial.c Fri Feb 20 18:28:22 1998 @@ -3,6 +3,7 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ +#include /* for CONFIG_REMOTE_DEBUG */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/sound/Defines linux/drivers/sound/Defines --- v2.1.87/linux/drivers/sound/Defines Tue Jan 13 21:12:57 1998 +++ linux/drivers/sound/Defines Thu Feb 19 14:46:14 1998 @@ -129,18 +129,6 @@ endif endif -ifdef CONFIG_GUS -ifneq ($(CONFIG_GUSHW),Y) -CONFIG_GUSHW=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_SSCAPEHW),Y) -CONFIG_SSCAPEHW=y -endif -endif - ifdef CONFIG_PAS ifneq ($(CONFIG_SEQUENCER),Y) CONFIG_SEQUENCER=y diff -u --recursive --new-file v2.1.87/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.87/linux/drivers/sound/ad1848.c Tue Jan 6 19:32:46 1998 +++ linux/drivers/sound/ad1848.c Thu Feb 19 14:46:14 1998 @@ -1716,7 +1716,7 @@ char dev_name[100]; int e; - ad1848_info *devc = &adev_info[nr_ad1848_devs]; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; ad1848_port_info *portc = NULL; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.87/linux/drivers/sound/audio.c Fri Jan 30 11:28:08 1998 +++ linux/drivers/sound/audio.c Thu Feb 19 14:46:14 1998 @@ -13,9 +13,15 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Thomas Sailer : moved several static variables into struct audio_operations + * (which is grossly misnamed btw.) because they have the same + * lifetime as the rest in there and dynamic allocation saves + * 12k or so */ #include +#include +#include #include "sound_config.h" @@ -26,51 +32,40 @@ #define NEUTRAL8 0x80 #define NEUTRAL16 0x00 -static int audio_mode[MAX_AUDIO_DEV]; -static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */ -#define AM_NONE 0 -#define AM_WRITE OPEN_WRITE -#define AM_READ OPEN_READ int dma_ioctl(int dev, unsigned int cmd, caddr_t arg); - -static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV]; -static int local_conversion[MAX_AUDIO_DEV]; - -#define CNV_MU_LAW 0x00000001 - static int set_format(int dev, int fmt) { if (fmt != AFMT_QUERY) { - local_conversion[dev] = 0; + audio_devs[dev]->local_conversion = 0; if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ { if (fmt == AFMT_MU_LAW) { fmt = AFMT_U8; - local_conversion[dev] = CNV_MU_LAW; + audio_devs[dev]->local_conversion = CNV_MU_LAW; } else fmt = AFMT_U8; /* This is always supported */ } - audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt); - local_format[dev] = fmt; + audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt); + audio_devs[dev]->local_format = fmt; } else - return local_format[dev]; + return audio_devs[dev]->local_format; - return local_format[dev]; + return audio_devs[dev]->local_format; } -int audio_open(int dev, struct fileinfo *file) +int audio_open(int dev, struct file *file) { int ret; int bits; int dev_type = dev & 0x0f; - int mode = file->mode & O_ACCMODE; + int mode = translate_mode(file); dev = dev >> 4; @@ -96,15 +91,15 @@ } } - local_conversion[dev] = 0; + audio_devs[dev]->local_conversion = 0; if (dev_type == SND_DEV_AUDIO) - set_format(dev, AFMT_MU_LAW); + set_format(dev, AFMT_MU_LAW); else set_format(dev, bits); - audio_mode[dev] = AM_NONE; - dev_nblock[dev] = 0; + audio_devs[dev]->audio_mode = AM_NONE; + audio_devs[dev]->dev_nblock = 0; return ret; @@ -154,12 +149,11 @@ dmap->flags |= DMA_DIRTY; } -void audio_release(int dev, struct fileinfo *file) +void audio_release(int dev, struct file *file) { - int mode; + int mode = translate_mode(file); dev = dev >> 4; - mode = file->mode & O_ACCMODE; audio_devs[dev]->dmap_out->closing = 1; audio_devs[dev]->dmap_in->closing = 1; @@ -202,7 +196,7 @@ #endif -int audio_write(int dev, struct fileinfo *file, const char *buf, int count) +int audio_write(int dev, struct file *file, const char *buf, int count) { int c, p, l, buf_size; int err; @@ -217,9 +211,9 @@ return -EPERM; if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_WRITE; + audio_devs[dev]->audio_mode |= AM_WRITE; else - audio_mode[dev] = AM_WRITE; + audio_devs[dev]->audio_mode = AM_WRITE; if (!count) /* Flush output */ { @@ -229,10 +223,10 @@ while (c) { - if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) + if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, audio_devs[dev]->dev_nblock)) < 0) { /* Handle nonblocking mode */ - if (dev_nblock[dev] && err == -EAGAIN) + if (audio_devs[dev]->dev_nblock && err == -EAGAIN) return p; /* No more space. Return # of accepted bytes */ return err; } @@ -259,7 +253,7 @@ } else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l); - if (local_conversion[dev] & CNV_MU_LAW) + if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { /* * This just allows interrupts while the conversion is running @@ -276,7 +270,7 @@ return count; } -int audio_read(int dev, struct fileinfo *file, char *buf, int count) +int audio_read(int dev, struct file *file, char *buf, int count) { int c, p, l; char *dmabuf; @@ -289,24 +283,24 @@ if (!(audio_devs[dev]->open_mode & OPEN_READ)) return -EPERM; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) sync_output(dev); if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_READ; + audio_devs[dev]->audio_mode |= AM_READ; else - audio_mode[dev] = AM_READ; + audio_devs[dev]->audio_mode = AM_READ; while(c) { if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, - dev_nblock[dev])) < 0) + audio_devs[dev]->dev_nblock)) < 0) { /* * Nonblocking mode handling. Return current # of bytes */ - if (dev_nblock[dev] && buf_no == -EAGAIN) + if (audio_devs[dev]->dev_nblock && buf_no == -EAGAIN) return p; if (p > 0) /* Avoid throwing away data */ @@ -321,7 +315,7 @@ * Insert any local processing here. */ - if (local_conversion[dev] & CNV_MU_LAW) + if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { /* * This just allows interrupts while the conversion is running @@ -347,8 +341,7 @@ return count - c; } -int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used, - unsigned int cmd, caddr_t arg) +int audio_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) { int val, count; unsigned long flags; @@ -356,7 +349,7 @@ dev = dev >> 4; - if (((cmd >> 8) & 0xff) == 'C') { + if (_IOC_TYPE(cmd) == 'C') { if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); /* else @@ -386,7 +379,7 @@ return 0; case SNDCTL_DSP_RESET: - audio_mode[dev] = AM_NONE; + audio_devs[dev]->audio_mode = AM_NONE; DMAbuf_reset(dev); return 0; @@ -403,19 +396,19 @@ case SNDCTL_DSP_GETISPACE: if (!(audio_devs[dev]->open_mode & OPEN_READ)) return 0; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; + if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; return dma_ioctl(dev, cmd, arg); case SNDCTL_DSP_GETOSPACE: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -EPERM; - if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; + if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; return dma_ioctl(dev, cmd, arg); case SNDCTL_DSP_NONBLOCK: - dev_nblock[dev] = 1; + audio_devs[dev]->dev_nblock = 1; return 0; case SNDCTL_DSP_GETCAPS: @@ -797,7 +790,9 @@ info.fragments = info.bytes / dmap->fragment_size; info.bytes -= dmap->user_counter % dmap->fragment_size; } - return copy_to_user(arg, &info, sizeof(info)); + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + return 0; case SNDCTL_DSP_SETTRIGGER: if (get_user(bits, (int *)arg)) @@ -863,7 +858,9 @@ if (dmap_in->mapping_flags & DMA_MAP_MAPPED) dmap_in->qlen = 0; /* Reset interrupt counter */ restore_flags(flags); - return copy_to_user(arg, &cinfo, sizeof(cinfo)); + if (copy_to_user(arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + return 0; case SNDCTL_DSP_GETOPTR: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) @@ -880,7 +877,9 @@ if (dmap_out->mapping_flags & DMA_MAP_MAPPED) dmap_out->qlen = 0; /* Reset interrupt counter */ restore_flags(flags); - return copy_to_user(arg, &cinfo, sizeof(cinfo)); + if (copy_to_user(arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + return 0; case SNDCTL_DSP_GETODELAY: if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) diff -u --recursive --new-file v2.1.87/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.1.87/linux/drivers/sound/cs4232.c Tue Jan 20 16:44:57 1998 +++ linux/drivers/sound/cs4232.c Thu Feb 19 14:46:14 1998 @@ -67,17 +67,19 @@ 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a }; +static void sleep(unsigned howlong) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + howlong; + schedule(); + current->timeout = 0; +} + int probe_cs4232(struct address_info *hw_config) { int i, n; int base = hw_config->io_base, irq = hw_config->irq; int dma1 = hw_config->dma, dma2 = hw_config->dma2; - unsigned long tlimit; - - static struct wait_queue *cs_sleeper = NULL; - static volatile struct snd_wait cs_sleep_flag = { - 0 - }; /* * Verify that the I/O port range is free. @@ -104,9 +106,7 @@ * first time. */ - for (n = 0; n < 4; n++) - { - cs_sleep_flag.opts = WK_NONE; + for (n = 0; n < 4; n++) { /* * Wake up the card by sending a 32 byte Crystal key to the key port. @@ -115,15 +115,7 @@ for (i = 0; i < 32; i++) CS_OUT(crystal_key[i]); - current->timeout = tlimit = jiffies + (HZ / 10); - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; + sleep(HZ / 10); /* * Now set the CSN (Card Select Number). @@ -154,15 +146,7 @@ CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */ - current->timeout = tlimit = jiffies + (HZ / 10); - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; + sleep(HZ / 10); /* * Initialize logical device 3 (MPU) @@ -184,15 +168,7 @@ CS_OUT(0x79); - current->timeout = tlimit = jiffies + (HZ / 5); - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; + sleep(HZ / 5); /* * Then try to detect the codec part of the chip @@ -200,16 +176,8 @@ if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) return 1; - - current->timeout = tlimit = jiffies + (HZ); - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; + + sleep(HZ); } return 0; } diff -u --recursive --new-file v2.1.87/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.1.87/linux/drivers/sound/dev_table.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/sound/dev_table.c Thu Feb 19 14:46:14 1998 @@ -438,6 +438,8 @@ return -(ENOMEM); } memset((char *) op, 0, sizeof(struct audio_operations)); + init_waitqueue(&op->in_sleeper); + init_waitqueue(&op->out_sleeper); if (driver_size < sizeof(struct audio_driver)) memset((char *) d, 0, sizeof(struct audio_driver)); diff -u --recursive --new-file v2.1.87/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.1.87/linux/drivers/sound/dev_table.h Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/dev_table.h Thu Feb 19 14:46:14 1998 @@ -221,6 +221,27 @@ int min_fragment; /* 0 == unlimited */ int max_fragment; /* 0 == unlimited */ int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ + + /* fields formerly in dmabuf.c */ + struct wait_queue *in_sleeper; + struct wait_queue *out_sleeper; + + /* fields formerly in audio.c */ + int audio_mode; + /* why dont we use file->f_flags & O_NONBLOCK for the following? - ts */ + int dev_nblock; /* 1 if in nonblocking mode */ + +#define AM_NONE 0 +#define AM_WRITE OPEN_WRITE +#define AM_READ OPEN_READ + + int local_format; + int audio_format; + int local_conversion; +#define CNV_MU_LAW 0x00000001 + + /* large structures at the end to keep offsets small */ + struct dma_buffparms dmaps[2]; }; int *load_mixer_volumes(char *name, int *levels, int present); @@ -367,7 +388,7 @@ #ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif -#ifdef CONFIG_GUSHW +#ifdef CONFIG_GUS {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif @@ -418,7 +439,7 @@ #endif #endif -#ifdef CONFIG_SSCAPEHW +#ifdef CONFIG_SSCAPE {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, #endif @@ -633,15 +654,11 @@ int sndtable_identify_card(char *name); void sound_setup (char *str, int *ints); -int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan); -void sound_free_dmap (int dev, struct dma_buffparms *dmap, int chn); extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); int sndtable_probe (int unit, struct address_info *hw_config); int sndtable_init_card (int unit, struct address_info *hw_config); int sndtable_start_card (int unit, struct address_info *hw_config); void sound_timer_init (struct sound_lowlev_timer *t, char *name); -int sound_start_dma(int dev, struct dma_buffparms *dmap, int chan, - unsigned long physaddr, int count, int dma_mode, int autoinit); void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan); #define AUDIO_DRIVER_VERSION 2 diff -u --recursive --new-file v2.1.87/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.87/linux/drivers/sound/dmabuf.c Fri Jan 30 15:50:57 1998 +++ linux/drivers/sound/dmabuf.c Thu Feb 19 14:46:14 1998 @@ -9,6 +9,15 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * Thomas Sailer : moved several static variables into struct audio_operations + * (which is grossly misnamed btw.) because they have the same + * lifetime as the rest in there and dynamic allocation saves + * 12k or so + * Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to + * determine if it was woken up by the expiring timeout or by + * an explicit wake_up. current->timeout can be used instead; + * if 0, the wakeup was due to the timeout. */ #include @@ -17,37 +26,132 @@ #include "sound_config.h" -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW) +#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) -static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = { - NULL -}; -static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = { - {0} -}; +static void dma_reset_output(int dev); +static void dma_reset_input(int dev); +static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode); + -static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = { - NULL -}; -static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = { - {0} -}; +static int debugmem = 0; /* switched off by default */ +static int dma_buffsize = DSP_BUFFSIZE; + +static void dmabuf_set_timeout(struct dma_buffparms *dmap) +{ + unsigned long tmout; -static int ndmaps = 0; + tmout = (dmap->fragment_size * HZ) / dmap->data_rate; + tmout += HZ / 5; /* Some safety distance */ + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + current->timeout = jiffies + tmout; +} -#define MAX_DMAP (MAX_AUDIO_DEV*2) +static int sound_alloc_dmap(struct dma_buffparms *dmap) +{ + char *start_addr, *end_addr; + int i, dma_pagesize; + int sz, size; + + dmap->mapping_flags &= ~DMA_MAP_MAPPED; + + if (dmap->raw_buf != NULL) + return 0; /* Already done */ + if (dma_buffsize < 4096) + dma_buffsize = 4096; + dma_pagesize = (dmap->dma < 4) ? (64 * 1024) : (128 * 1024); + dmap->raw_buf = NULL; + dmap->buffsize = dma_buffsize; + if (dmap->buffsize > dma_pagesize) + dmap->buffsize = dma_pagesize; + start_addr = NULL; + /* + * Now loop until we get a free buffer. Try to get smaller buffer if + * it fails. Don't accept smaller than 8k buffer for performance + * reasons. + */ + while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) { + for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); + dmap->buffsize = PAGE_SIZE * (1 << sz); + start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); + if (start_addr == NULL) + dmap->buffsize /= 2; + } + + if (start_addr == NULL) { + printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n"); + return -ENOMEM; + } else { + /* make some checks */ + end_addr = start_addr + dmap->buffsize - 1; -static struct dma_buffparms dmaps[MAX_DMAP] = { - {0} -}; + if (debugmem) + printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); + + /* now check if it fits into the same dma-pagesize */ -static void dma_reset_output(int dev); -static void dma_reset_input(int dev); -static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode); + if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) + || end_addr >= (char *) (MAX_DMA_ADDRESS)) { + printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); + return -EFAULT; + } + } + dmap->raw_buf = start_addr; + dmap->raw_buf_phys = virt_to_bus(start_addr); + + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + set_bit(PG_reserved, &mem_map[i].flags);; + return 0; +} + +static void sound_free_dmap(struct dma_buffparms *dmap) +{ + int sz, size, i; + unsigned long start_addr, end_addr; + + if (dmap->raw_buf == NULL) + return; + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return; /* Don't free mmapped buffer. Will use it next time */ + for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); + + start_addr = (unsigned long) dmap->raw_buf; + end_addr = start_addr + dmap->buffsize; + + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + clear_bit(PG_reserved, &mem_map[i].flags);; + + free_pages((unsigned long) dmap->raw_buf, sz); + dmap->raw_buf = NULL; +} + + +/* Intel version !!!!!!!!! */ -static void dma_init_buffers(int dev, struct dma_buffparms *dmap) +static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, int count, int dma_mode) +{ + unsigned long flags; + int chan = dmap->dma; + + /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ + save_flags(flags); + cli(); + disable_dma(chan); + clear_dma_ff(chan); + set_dma_mode(chan, dma_mode); + set_dma_addr(chan, physaddr); + set_dma_count(chan, count); + enable_dma(chan); + restore_flags(flags); + + return 0; +} + +static void dma_init_buffers(struct dma_buffparms *dmap) { dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; dmap->byte_counter = 0; @@ -64,26 +168,24 @@ dmap->flags = DMA_BUSY; /* Other flags off */ } -static int open_dmap(int dev, int mode, struct dma_buffparms *dmap, int chan) +static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffparms *dmap) { int err; if (dmap->flags & DMA_BUSY) return -EBUSY; - if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0) + if ((err = sound_alloc_dmap(dmap)) < 0) return err; - if (dmap->raw_buf == NULL) - { + if (dmap->raw_buf == NULL) { printk(KERN_WARNING "Sound: DMA buffers not available\n"); return -ENOSPC; /* Memory allocation failed during boot */ } - if (sound_open_dma(chan, audio_devs[dev]->name)) - { - printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", chan); + if (sound_open_dma(dmap->dma, adev->name)) { + printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma); return -EBUSY; } - dma_init_buffers(dev, dmap); + dma_init_buffers(dmap); dmap->open_mode = mode; dmap->subdivision = dmap->underrun_count = 0; dmap->fragment_size = 0; @@ -94,19 +196,12 @@ dmap->needs_reorg = 1; dmap->audio_callback = NULL; dmap->callback_parm = 0; - - - if (dmap->dma_mode & DMODE_OUTPUT) - out_sleep_flag[dev].opts = WK_NONE; - else - in_sleep_flag[dev].opts = WK_NONE; return 0; } -static void close_dmap(int dev, struct dma_buffparms *dmap, int chan) +static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap) { - sound_close_dma(chan); - + sound_close_dma(dmap->dma); if (dmap->flags & DMA_BUSY) dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; @@ -157,74 +252,49 @@ int DMAbuf_open(int dev, int mode) { + struct audio_operations *adev = audio_devs[dev]; int retval; struct dma_buffparms *dmap_in = NULL; struct dma_buffparms *dmap_out = NULL; - if (dev >= num_audiodevs || audio_devs[dev] == NULL) - return -ENXIO; - - if (!audio_devs[dev]) + if (!adev) return -ENXIO; + if (!(adev->flags & DMA_DUPLEX)) + adev->dmap_in = adev->dmap_out; + check_driver(adev->d); - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; - } - check_driver(audio_devs[dev]->d); - - if ((retval = audio_devs[dev]->d->open(dev, mode)) < 0) + if ((retval = adev->d->open(dev, mode)) < 0) return retval; - - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; - + dmap_out = adev->dmap_out; + dmap_in = adev->dmap_in; if (dmap_in == dmap_out) - audio_devs[dev]->flags &= ~DMA_DUPLEX; + adev->flags &= ~DMA_DUPLEX; - if (mode & OPEN_WRITE) - { - if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) - { - audio_devs[dev]->d->close(dev); + if (mode & OPEN_WRITE) { + if ((retval = open_dmap(adev, mode, dmap_out)) < 0) { + adev->d->close(dev); return retval; } } - audio_devs[dev]->enable_bits = mode; + adev->enable_bits = mode; - if (mode == OPEN_READ || (mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) - { - audio_devs[dev]->d->close(dev); + if (mode == OPEN_READ || (mode != OPEN_WRITE && adev->flags & DMA_DUPLEX)) { + if ((retval = open_dmap(adev, mode, dmap_in)) < 0) { + adev->d->close(dev); if (mode & OPEN_WRITE) - { - close_dmap(dev, dmap_out, audio_devs[dev]->dmap_out->dma); - } + close_dmap(adev, dmap_out); return retval; } } - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; - - if (mode & OPEN_READ) - in_sleep_flag[dev].opts = WK_NONE; + adev->open_mode = mode; + adev->go = 1; - if (mode & OPEN_WRITE) - out_sleep_flag[dev].opts = WK_NONE; - - audio_devs[dev]->d->set_bits(dev, 8); - audio_devs[dev]->d->set_channels(dev, 1); - audio_devs[dev]->d->set_speed(dev, DSP_DEFAULT_SPEED); - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset(audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } + adev->d->set_bits(dev, 8); + adev->d->set_channels(dev, 1); + adev->d->set_speed(dev, DSP_DEFAULT_SPEED); + if (adev->dmap_out->dma_mode == DMODE_OUTPUT) + memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, + adev->dmap_out->bytes_in_use); return 0; } @@ -239,9 +309,9 @@ static void dma_reset_output(int dev) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; - int tmout; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = adev->dmap_out; if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ return; @@ -251,162 +321,111 @@ */ save_flags(flags); cli(); + adev->dmap_out->flags |= DMA_SYNCING; - tmout = (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - if (!signal_pending(current) - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; + adev->dmap_out->underrun_count = 0; + if (!signal_pending(current) && adev->dmap_out->qlen && + adev->dmap_out->underrun_count == 0) { + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->out_sleeper); + current->timeout = 0; } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* * Finally shut the device off */ - - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_output) - audio_devs[dev]->d->halt_io(dev); + if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_output) + adev->d->halt_io(dev); else - audio_devs[dev]->d->halt_output(dev); - audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; - restore_flags(flags); - + adev->d->halt_output(dev); + adev->dmap_out->flags &= ~DMA_STARTED; clear_dma_ff(dmap->dma); disable_dma(dmap->dma); + restore_flags(flags); dmap->byte_counter = 0; - reorganize_buffers(dev, audio_devs[dev]->dmap_out, 0); + reorganize_buffers(dev, adev->dmap_out, 0); dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; } static void dma_reset_input(int dev) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct dma_buffparms *dmap = adev->dmap_in; save_flags(flags); cli(); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_input) - audio_devs[dev]->d->halt_io(dev); + if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input) + adev->d->halt_io(dev); else - audio_devs[dev]->d->halt_input(dev); - audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; + adev->d->halt_input(dev); + adev->dmap_in->flags &= ~DMA_STARTED; restore_flags(flags); dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; dmap->byte_counter = 0; - reorganize_buffers(dev, audio_devs[dev]->dmap_in, 1); + reorganize_buffers(dev, adev->dmap_in, 1); } void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) { - if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) + struct audio_operations *adev = audio_devs[dev]; + + if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT)) return; /* Don't start DMA yet */ dmap->dma_mode = DMODE_OUTPUT; - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - if (!(dmap->flags & DMA_STARTED)) - { + if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + if (!(dmap->flags & DMA_STARTED)) { reorganize_buffers(dev, dmap, 0); - if (audio_devs[dev]->d->prepare_for_output(dev, - dmap->fragment_size, dmap->nbufs)) + if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs)) return; if (!(dmap->flags & DMA_NODMA)) - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE); + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE); dmap->flags |= DMA_STARTED; } if (dmap->counts[dmap->qhead] == 0) dmap->counts[dmap->qhead] = dmap->fragment_size; - dmap->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev,audio_devs[dev]->enable_bits * audio_devs[dev]->go); + adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1); + if (adev->d->trigger) + adev->d->trigger(dev,adev->enable_bits * adev->go); } dmap->flags |= DMA_ACTIVE; } int DMAbuf_sync(int dev) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; - int tmout, n = 0; + int n = 0; + struct dma_buffparms *dmap; - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT)) return 0; - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { + dmap = adev->dmap_out; save_flags(flags); cli(); - - tmout = (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - if (dmap->qlen > 0) - if (!(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output(dev, dmap); - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - audio_devs[dev]->dmap_out->underrun_count = 0; - while (!signal_pending(current) && n++ <= audio_devs[dev]->dmap_out->nbufs && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; + if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, dmap); + adev->dmap_out->flags |= DMA_SYNCING; + adev->dmap_out->underrun_count = 0; + while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && + adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->out_sleeper); + if (!current->timeout) { + adev->dmap_out->flags &= ~DMA_SYNCING; restore_flags(flags); - return audio_devs[dev]->dmap_out->qlen; + return adev->dmap_out->qlen; } + current->timeout = 0; } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); restore_flags(flags); /* @@ -416,195 +435,138 @@ save_flags(flags); cli(); - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - { - while (!signal_pending(current) && audio_devs[dev]->d->local_qlen(dev)) - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; + if (adev->d->local_qlen) { /* Device has hidden buffers */ + while (!signal_pending(current) && adev->d->local_qlen(dev)) { + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->out_sleeper); + current->timeout = 0; } } restore_flags(flags); } - audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; - return audio_devs[dev]->dmap_out->qlen; + adev->dmap_out->dma_mode = DMODE_NONE; + return adev->dmap_out->qlen; } int DMAbuf_release(int dev, int mode) { - unsigned long flags; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->closing = 1; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->closing = 1; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) - if (!signal_pending(current) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) - { + if (adev->open_mode & OPEN_WRITE) + adev->dmap_out->closing = 1; + if (adev->open_mode & OPEN_READ) + adev->dmap_in->closing = 1; + + if (adev->open_mode & OPEN_WRITE) + if (!(adev->dmap_in->mapping_flags & DMA_MAP_MAPPED)) + if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) DMAbuf_sync(dev); - } - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset(audio_devs[dev]->dmap_out->raw_buf, audio_devs[dev]->dmap_out->neutral_byte, audio_devs[dev]->dmap_out->bytes_in_use); - } + if (adev->dmap_out->dma_mode == DMODE_OUTPUT) + memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use); save_flags(flags); cli(); DMAbuf_reset(dev); - audio_devs[dev]->d->close(dev); + adev->d->close(dev); - if (audio_devs[dev]->open_mode & OPEN_WRITE) - close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + if (adev->open_mode & OPEN_WRITE) + close_dmap(adev, adev->dmap_out); - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->open_mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); - } - audio_devs[dev]->open_mode = 0; + if (adev->open_mode == OPEN_READ || + (adev->open_mode != OPEN_WRITE && + adev->flags & DMA_DUPLEX)) + close_dmap(adev, adev->dmap_in); + adev->open_mode = 0; restore_flags(flags); return 0; } int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) { - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; + struct audio_operations *adev = audio_devs[dev]; + int err; - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) + if (!(adev->open_mode & OPEN_READ)) return 0; - - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ - { + if (!(adev->enable_bits & PCM_ENABLE_INPUT)) + return 0; + if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ DMAbuf_sync(dev); DMAbuf_reset(dev); dmap->dma_mode = DMODE_NONE; } - if (!dmap->dma_mode) - { - int err; - + if (!dmap->dma_mode) { reorganize_buffers(dev, dmap, 1); - if ((err = audio_devs[dev]->d->prepare_for_input(dev, + if ((err = adev->d->prepare_for_input(dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; dmap->dma_mode = DMODE_INPUT; } - if (!(dmap->flags & DMA_ACTIVE)) - { + if (!(dmap->flags & DMA_ACTIVE)) { if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); - audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); + adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 0); dmap->flags |= DMA_ACTIVE; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); + if (adev->d->trigger) + adev->d->trigger(dev, adev->enable_bits * adev->go); } return 0; } int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; int err = 0, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct dma_buffparms *dmap = adev->dmap_in; + int go; - if (!(audio_devs[dev]->open_mode & OPEN_READ)) + if (!(adev->open_mode & OPEN_READ)) return -EIO; if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - save_flags(flags); cli(); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - { + if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) { /* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ restore_flags(flags); return -EINVAL; - } - else while (dmap->qlen <= 0 && n++ < 10) - { - int tmout; - unsigned long tlimit; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || !audio_devs[dev]->go) - { + } else while (dmap->qlen <= 0 && n++ < 10) { + if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { restore_flags(flags); return -EAGAIN; } - if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) - { + if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { restore_flags(flags); return err; } /* Wait for the next block */ - if (dontblock) - { + if (dontblock) { restore_flags(flags); return -EAGAIN; } - if (!audio_devs[dev]->go) - tmout = 0; - else - { - tmout = (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; - } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) - { + if (!(go = adev->go)) + current->timeout = 0; + else + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->in_sleeper); + if (go && !current->timeout) { /* FIXME: include device name */ err = -EIO; printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); dma_reset_input(dev); - } - else + } else err = -EINTR; + current->timeout = 0; } restore_flags(flags); if (dmap->qlen <= 0) - { - if (err == 0) - err = -EINTR; - return err; - } + return err ? err : -EINTR; *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; @@ -613,7 +575,8 @@ int DMAbuf_rmchars(int dev, int buff_no, int c) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; int p = dmap->counts[dmap->qhead] + c; if (dmap->mapping_flags & DMA_MAP_MAPPED) @@ -623,8 +586,7 @@ } else if (dmap->qlen <= 0) return -EIO; - else if (p >= dmap->fragment_size) - { /* This buffer is completely empty */ + else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ dmap->counts[dmap->qhead] = 0; dmap->qlen--; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; @@ -648,24 +610,19 @@ cli(); if (!(dmap->flags & DMA_ACTIVE)) pos = 0; - else - { + else { int chan = dmap->dma; clear_dma_ff(chan); disable_dma(dmap->dma); pos = get_dma_residue(chan); pos = dmap->bytes_in_use - pos; - if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) - { - if (direction == DMODE_OUTPUT) - { + if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) { + if (direction == DMODE_OUTPUT) { if (dmap->qhead == 0) if (pos > dmap->fragment_size) pos = 0; - } - else - { + } else { if (dmap->qtail == 0) if (pos > dmap->fragment_size) pos = 0; @@ -687,35 +644,33 @@ * DMAbuf_start_devices() is called by the /dev/music driver to start * one or more audio devices at desired moment. */ - -static void DMAbuf_start_device(int dev) -{ - if (audio_devs[dev]->open_mode != 0) - { - if (!audio_devs[dev]->go) - { - /* OK to start the device */ - audio_devs[dev]->go = 1; - - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev,audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - } -} void DMAbuf_start_devices(unsigned int devmask) { + struct audio_operations *adev; int dev; - for (dev = 0; dev < num_audiodevs; dev++) - if ((devmask & (1 << dev)) && audio_devs[dev] != NULL) - DMAbuf_start_device(dev); + for (dev = 0; dev < num_audiodevs; dev++) { + if (!(devmask & (1 << dev))) + continue; + if (!(adev = audio_devs[dev])) + continue; + if (adev->open_mode == 0) + continue; + if (adev->go) + continue; + /* OK to start the device */ + adev->go = 1; + if (adev->d->trigger) + adev->d->trigger(dev,adev->enable_bits * adev->go); + } } int DMAbuf_space_in_queue(int dev) { + struct audio_operations *adev = audio_devs[dev]; int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = adev->dmap_out; int lim = dmap->nbufs; if (lim < 2) @@ -734,13 +689,10 @@ max = lim; len = dmap->qlen; - if (audio_devs[dev]->d->local_qlen) - { - tmp = audio_devs[dev]->d->local_qlen(dev); + if (adev->d->local_qlen) { + tmp = adev->d->local_qlen(dev); if (tmp && len) - tmp--; /* - * This buffer has been counted twice - */ + tmp--; /* This buffer has been counted twice */ len += tmp; } if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ @@ -753,62 +705,42 @@ static int output_sleep(int dev, int dontblock) { - int tmout; + struct audio_operations *adev = audio_devs[dev]; int err = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long tlimit; + struct dma_buffparms *dmap = adev->dmap_out; + int timeout; if (dontblock) return -EAGAIN; - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + if (!(adev->enable_bits & PCM_ENABLE_OUTPUT)) return -EAGAIN; /* * Wait for free space */ - - if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) - tmout = 0; - else - { - tmout = (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - if (signal_pending(current)) return -EIO; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); + timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); + if (timeout) + dmabuf_set_timeout(dmap); else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { + current->timeout = 0; + interruptible_sleep_on(&adev->out_sleeper); + if (timeout && !current->timeout) { printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); dma_reset_output(dev); + } else { + current->timeout = 0; + if (signal_pending(current)) + err = -EINTR; } - else if (signal_pending(current)) - err = -EINTR; return err; } static int find_output_space(int dev, char **buf, int *size) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; unsigned long flags; unsigned long active_offs; long len, offs; @@ -816,7 +748,6 @@ int occupied_bytes = (dmap->user_counter % dmap->fragment_size); *buf = dmap->raw_buf; - if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) return 0; save_flags(flags); @@ -833,8 +764,7 @@ #endif offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP; - if (offs < 0 || offs >= dmap->bytes_in_use) - { + if (offs < 0 || offs >= dmap->bytes_in_use) { printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs); printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); return 0; @@ -845,53 +775,45 @@ if ((offs + len) > dmap->bytes_in_use) len = dmap->bytes_in_use - offs; - if (len < 0) - { + if (len < 0) { restore_flags(flags); return 0; } if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) len = (maxfrags * dmap->fragment_size) - occupied_bytes; - *size = len & ~SAMPLE_ROUNDUP; - restore_flags(flags); return (*size > 0); } int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; int err = -EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = adev->dmap_out; if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { + if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ return -EINVAL; } - if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ - { - DMAbuf_reset(dev); - dmap->dma_mode = DMODE_NONE; + if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; } dmap->dma_mode = DMODE_OUTPUT; save_flags(flags); cli(); - - while (find_output_space(dev, buf, size) <= 0) - { - if ((err = output_sleep(dev, dontblock)) < 0) - { + while (find_output_space(dev, buf, size) <= 0) { + if ((err = output_sleep(dev, dontblock)) < 0) { restore_flags(flags); return err; } } - restore_flags(flags); return 0; @@ -899,7 +821,8 @@ int DMAbuf_move_wrpointer(int dev, int l) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; unsigned long end_ptr, p; int post = (dmap->flags & DMA_POST); @@ -909,10 +832,9 @@ dmap->user_counter += l; dmap->flags |= DMA_DIRTY; - if (dmap->user_counter >= dmap->max_byte_counter) - { /* Wrap the byte counters */ + if (dmap->user_counter >= dmap->max_byte_counter) { + /* Wrap the byte counters */ long decr = dmap->user_counter; - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->user_counter; dmap->byte_counter -= decr; @@ -923,8 +845,7 @@ dmap->neutral_byte = dmap->raw_buf[p]; /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) - { + while (ptr < end_ptr) { dmap->counts[dmap->qtail] = dmap->fragment_size; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; dmap->qlen++; @@ -937,137 +858,85 @@ * Let the low level driver to perform some postprocessing to * the written data. */ - if (audio_devs[dev]->d->postprocess_write) - audio_devs[dev]->d->postprocess_write(dev); + if (adev->d->postprocess_write) + adev->d->postprocess_write(dev); if (!(dmap->flags & DMA_ACTIVE)) - { - if (dmap->qlen > 1 || - (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - DMAbuf_launch_output(dev, dmap); - } + if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) + DMAbuf_launch_output(dev, dmap); return 0; } int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { + if (dmap->raw_buf == NULL) { printk(KERN_ERR "sound: DMA buffer(1) == NULL\n"); - printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); + printk("Device %d, chn=%s\n", dev, (dmap == adev->dmap_out) ? "out" : "in"); return 0; } - if (chan < 0) + if (dmap->dma < 0) return 0; - - sound_start_dma(dev, dmap, chan, physaddr, count, dma_mode, 0); - + sound_start_dma(dmap, physaddr, count, dma_mode); return count; } -static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) +static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; + struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { + if (dmap->raw_buf == NULL) { printk(KERN_ERR "sound: DMA buffer(2) == NULL\n"); - printk(KERN_ERR "Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); + printk(KERN_ERR "Device %s, chn=%s\n", adev->name, (dmap == adev->dmap_out) ? "out" : "in"); return 0; } if (dmap->flags & DMA_NODMA) - { return 1; - } - if (chan < 0) + if (dmap->dma < 0) return 0; - - sound_start_dma(dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); + sound_start_dma(dmap, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode | DMA_AUTOINIT); dmap->flags |= DMA_STARTED; - return count; } static void finish_output_interrupt(int dev, struct dma_buffparms *dmap) { - unsigned long flags; + struct audio_operations *adev = audio_devs[dev]; if (dmap->audio_callback != NULL) dmap->audio_callback(dev, dmap->callback_parm); - - save_flags(flags); - cli(); - if ((out_sleep_flag[dev].opts & WK_SLEEP)) - { - out_sleep_flag[dev].opts = WK_WAKEUP; - wake_up(&out_sleeper[dev]); - } - restore_flags(flags); + wake_up(&adev->out_sleeper); } static void do_outputintr(int dev, int dummy) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = adev->dmap_out; int this_fragment; -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_out->dma >= 0) - sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); -#endif - - if (dmap->raw_buf == NULL) - { + if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: Error. Audio interrupt (%d) after freeing buffers.\n", dev); return; } - if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ - { + if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* Virtual memory mapped access */ /* mmapped access */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { + if (dmap->qhead == 0) { /* Wrapped */ dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->byte_counter; dmap->user_counter -= decr; } } dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; dmap->counts[dmap->qhead] = dmap->fragment_size; - DMAbuf_launch_output(dev, dmap); finish_output_interrupt(dev, dmap); return; @@ -1079,53 +948,43 @@ this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { + if (dmap->qhead == 0) { /* Wrapped */ dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->byte_counter; dmap->user_counter -= decr; } } - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; - - while (dmap->qlen <= 0) - { + while (dmap->qlen <= 0) { dmap->underrun_count++; dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) - { + if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) { dmap->flags &= ~DMA_DIRTY; - memset(audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->buffsize); + memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, + adev->dmap_out->buffsize); } dmap->user_counter += dmap->fragment_size; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } - if (dmap->qlen > 0) DMAbuf_launch_output(dev, dmap); - restore_flags(flags); finish_output_interrupt(dev, dmap); } void DMAbuf_outputintr(int dev, int notify_only) { + struct audio_operations *adev = audio_devs[dev]; unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct dma_buffparms *dmap = adev->dmap_out; save_flags(flags); cli(); - - if (!(dmap->flags & DMA_NODMA)) - { + if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; clear_dma_ff(chan); disable_dma(dmap->dma); @@ -1145,29 +1004,19 @@ static void do_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_in->dma >= 0) - sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); -#endif + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; - if (dmap->raw_buf == NULL) - { + if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: Fatal error. Audio interrupt after freeing buffers.\n"); return; } - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { + if (dmap->mapping_flags & DMA_MAP_MAPPED) { dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { + if (dmap->qtail == 0) { /* Wrapped */ dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->byte_counter; dmap->user_counter -= decr; @@ -1175,79 +1024,58 @@ } dmap->qlen++; - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { + if (!(adev->flags & DMA_AUTOMODE)) { if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_READ); - audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev,audio_devs[dev]->enable_bits * audio_devs[dev]->go); + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_READ); + adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1); + if (adev->d->trigger) + adev->d->trigger(dev, adev->enable_bits * adev->go); } dmap->flags |= DMA_ACTIVE; - } - else if (dmap->qlen >= (dmap->nbufs - 1)) - { + } else if (dmap->qlen >= (dmap->nbufs - 1)) { printk(KERN_WARNING "Sound: Recording overrun\n"); dmap->underrun_count++; /* Just throw away the oldest fragment but keep the engine running */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) - { + } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) { dmap->qlen++; dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { + if (dmap->qtail == 0) { /* Wrapped */ dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ long decr = dmap->byte_counter; - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; decr -= dmap->byte_counter; dmap->user_counter -= decr; } } } - if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); - audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev,audio_devs[dev]->enable_bits * audio_devs[dev]->go); + if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); + adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1); + if (adev->d->trigger) + adev->d->trigger(dev,adev->enable_bits * adev->go); } dmap->flags |= DMA_ACTIVE; - - save_flags(flags); - cli(); if (dmap->qlen > 0) - { - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up(&in_sleeper[dev]); - } - } - restore_flags(flags); + wake_up(&adev->in_sleeper); } void DMAbuf_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; unsigned long flags; save_flags(flags); cli(); - if (!(dmap->flags & DMA_NODMA)) - { + if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; - clear_dma_ff(chan); disable_dma(dmap->dma); pos = dmap->bytes_in_use - get_dma_residue(chan); @@ -1260,8 +1088,7 @@ n = 0; while (dmap->qtail != pos && ++n < dmap->nbufs) do_inputintr(dev); - } - else + } else do_inputintr(dev); restore_flags(flags); } @@ -1271,25 +1098,22 @@ /* * NOTE! This routine opens only the primary DMA channel (output). */ - - int chan = audio_devs[dev]->dmap_out->dma; + struct audio_operations *adev = audio_devs[dev]; int err; - if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) + if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0) return -EBUSY; - dma_init_buffers(dev, audio_devs[dev]->dmap_out); - out_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; + dma_init_buffers(adev->dmap_out); + adev->dmap_out->flags |= DMA_ALLOC_DONE; + adev->dmap_out->fragment_size = adev->dmap_out->buffsize; - if (chan >= 0) - { + if (adev->dmap_out->dma >= 0) { unsigned long flags; save_flags(flags); cli(); - disable_dma(audio_devs[dev]->dmap_out->dma); - clear_dma_ff(chan); + clear_dma_ff(adev->dmap_out->dma); + disable_dma(adev->dmap_out->dma); restore_flags(flags); } return 0; @@ -1297,147 +1121,107 @@ void DMAbuf_close_dma(int dev) { - close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out); } void DMAbuf_init(int dev, int dma1, int dma2) { + struct audio_operations *adev = audio_devs[dev]; /* * NOTE! This routine could be called several times. */ - if (audio_devs[dev] && audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) + if (adev && adev->dmap_out == NULL) { + if (adev->d == NULL) panic("OSS: audio_devs[%d]->d == NULL\n", dev); - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; - - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } - else - { - audio_devs[dev]->dmap_out = audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; - audio_devs[dev]->dmap_out->dma = dma1; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; - audio_devs[dev]->dmap_in->dma = dma2; + if (adev->parent_dev) { /* Use DMA map of the parent dev */ + int parent = adev->parent_dev - 1; + adev->dmap_out = audio_devs[parent]->dmap_out; + adev->dmap_in = audio_devs[parent]->dmap_in; + } else { + adev->dmap_out = adev->dmap_in = &adev->dmaps[0]; + adev->dmap_out->dma = dma1; + if (adev->flags & DMA_DUPLEX) { + adev->dmap_in = &adev->dmaps[1]; + adev->dmap_in->dma = dma2; } } } } -int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +static unsigned int poll_input(int dev, poll_table *wait) { - struct dma_buffparms *dmap; - unsigned long flags; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - dmap = audio_devs[dev]->dmap_in; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - save_flags(flags); - cli(); - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&in_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - if (dmap->dma_mode != DMODE_INPUT) - { - if (dmap->dma_mode == DMODE_NONE && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && audio_devs[dev]->go) - { - unsigned long flags; - save_flags(flags); - cli(); - DMAbuf_activate_recording(dev, dmap); - restore_flags(flags); - } - return 0; - } - if (!dmap->qlen) - { - save_flags(flags); - cli(); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&in_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - return 1; - - case SEL_OUT: - dmap = audio_devs[dev]->dmap_out; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags(flags); - cli(); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&out_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - - if (dmap->dma_mode == DMODE_INPUT) - return 0; - - if (dmap->dma_mode == DMODE_NONE) - return 1; - - if (!DMAbuf_space_in_queue(dev)) - { - save_flags(flags); - cli(); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&out_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - return 1; - break; + if (!(adev->open_mode & OPEN_READ)) + return 0; + if (dmap->mapping_flags & DMA_MAP_MAPPED) { + poll_wait(&adev->in_sleeper, wait); + if (dmap->qlen) + return POLLIN | POLLRDNORM; + return 0; + } + if (dmap->dma_mode != DMODE_INPUT) { + if (dmap->dma_mode == DMODE_NONE && + adev->enable_bits & PCM_ENABLE_INPUT && + !dmap->qlen && adev->go) { + unsigned long flags; + + poll_wait(&adev->in_sleeper, wait); + save_flags(flags); + cli(); + DMAbuf_activate_recording(dev, dmap); + restore_flags(flags); + } + return 0; + } + poll_wait(&adev->in_sleeper, wait); + if (!dmap->qlen) + return 0; + return POLLIN | POLLRDNORM; +} - case SEL_EX: - return 0; +static unsigned int poll_output(int dev, poll_table *wait) +{ + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; + + if (!(adev->open_mode & OPEN_WRITE)) + return 0; + if (dmap->mapping_flags & DMA_MAP_MAPPED) { + poll_wait(&adev->out_sleeper, wait); + if (dmap->qlen) + return POLLOUT | POLLWRNORM; + return 0; } + if (dmap->dma_mode == DMODE_INPUT) + return 0; + poll_wait(&adev->out_sleeper, wait); + if (dmap->dma_mode == DMODE_NONE) + return POLLOUT | POLLWRNORM; + if (!DMAbuf_space_in_queue(dev)) + return 0; + return POLLOUT | POLLWRNORM; +} - return 0; +unsigned int DMAbuf_poll(int dev, poll_table *wait) +{ + return poll_input(dev, wait) | poll_output(dev, wait); } void DMAbuf_deinit(int dev) { -/* This routine is called when driver is being unloaded */ + struct audio_operations *adev = audio_devs[dev]; + /* This routine is called when driver is being unloaded */ + if (!adev) + return; #ifdef RUNTIME_DMA_ALLOC - if (audio_devs[dev]) - sound_free_dmap (dev, audio_devs[dev]->dmap_out, - audio_devs[dev]->dmap_out->dma); - - if (audio_devs[dev] && audio_devs[dev]->flags & DMA_DUPLEX) - sound_free_dmap (dev, audio_devs[dev]->dmap_in, - audio_devs[dev]->dmap_in->dma); + sound_free_dmap(adev->dmap_out); + + if (adev->flags & DMA_DUPLEX) + sound_free_dmap(adev->dmap_in); #endif } diff -u --recursive --new-file v2.1.87/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.87/linux/drivers/sound/gus_card.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/sound/gus_card.c Thu Feb 19 14:46:14 1998 @@ -16,7 +16,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #include "gus_hw.h" @@ -167,7 +167,7 @@ void attach_gus_db16(struct address_info *hw_config) { -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) gus_pcm_volume = 100; gus_wave_volume = 90; #endif diff -u --recursive --new-file v2.1.87/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.1.87/linux/drivers/sound/gus_midi.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/sound/gus_midi.c Thu Feb 19 14:46:14 1998 @@ -17,7 +17,7 @@ #include "gus_hw.h" -#if ( defined(CONFIG_GUSHW) && defined(CONFIG_MIDI) ) || defined (MODULE) +#if ( defined(CONFIG_GUS) && defined(CONFIG_MIDI) ) || defined (MODULE) static int midi_busy = 0, input_opened = 0; static int my_dev; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c --- v2.1.87/linux/drivers/sound/gus_vol.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/sound/gus_vol.c Thu Feb 19 14:46:14 1998 @@ -12,7 +12,7 @@ #include #include "sound_config.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume diff -u --recursive --new-file v2.1.87/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.87/linux/drivers/sound/gus_wave.c Fri Jan 23 18:10:32 1998 +++ linux/drivers/sound/gus_wave.c Thu Feb 19 14:46:14 1998 @@ -22,7 +22,7 @@ #include #include "gus_hw.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) @@ -115,9 +115,6 @@ static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ static struct wait_queue *dram_sleeper = NULL; -static volatile struct snd_wait dram_sleep_flag = { - 0 -}; /* * Variables and buffers for PCM output @@ -1102,7 +1099,9 @@ { case SNDCTL_SYNTH_INFO: gus_info.nr_voices = nr_voices; - return copy_to_user(arg, &gus_info, sizeof(gus_info)); + if (copy_to_user(arg, &gus_info, sizeof(gus_info))) + return -EFAULT; + return 0; case SNDCTL_SEQ_RESETSAMPLES: reset_sample_memory(); @@ -1658,7 +1657,7 @@ else gus_no_dma = 0; - dram_sleep_flag.opts = WK_NONE; + init_waitqueue(&dram_sleeper); gus_busy = 1; active_device = GUS_DEV_WAVE; @@ -1848,7 +1847,6 @@ unsigned long address, hold_address; unsigned char dma_command; unsigned long flags; - unsigned long tlimit; if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) { @@ -1921,17 +1919,11 @@ */ active_device = GUS_DEV_WAVE; - current->timeout = tlimit = jiffies + HZ; - dram_sleep_flag.opts = WK_SLEEP; + current->timeout = jiffies + HZ; interruptible_sleep_on(&dram_sleeper); - if (!(dram_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - dram_sleep_flag.opts |= WK_TIMEOUT; - } - dram_sleep_flag.opts &= ~WK_SLEEP; - if ((dram_sleep_flag.opts & WK_TIMEOUT)) - printk(KERN_WARNING "GUS: DMA Transfer timed out\n"); + if (!current->timeout) + printk("GUS: DMA Transfer timed out\n"); + current->timeout = 0; restore_flags(flags); } @@ -3405,11 +3397,7 @@ switch (active_device) { case GUS_DEV_WAVE: - if ((dram_sleep_flag.opts & WK_SLEEP)) - { - dram_sleep_flag.opts = WK_WAKEUP; - wake_up(&dram_sleeper); - } + wake_up(&dram_sleeper); break; case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ diff -u --recursive --new-file v2.1.87/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.1.87/linux/drivers/sound/ics2101.c Mon Jan 5 09:39:52 1998 +++ linux/drivers/sound/ics2101.c Thu Feb 19 14:46:14 1998 @@ -17,7 +17,7 @@ #include "sound_config.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #include #include "gus_hw.h" diff -u --recursive --new-file v2.1.87/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c --- v2.1.87/linux/drivers/sound/lowlevel/aci.c Tue Oct 28 02:10:49 1997 +++ linux/drivers/sound/lowlevel/aci.c Fri Feb 20 18:28:22 1998 @@ -58,6 +58,7 @@ * */ +#include /* for CONFIG_ACI_MIXER */ #include "lowlevel.h" #include "../sound_config.h" #include "lowlevel.h" diff -u --recursive --new-file v2.1.87/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.1.87/linux/drivers/sound/maui.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/maui.c Thu Feb 19 14:46:14 1998 @@ -48,202 +48,178 @@ static int maui_osLen = 0; #endif -static struct wait_queue *maui_sleeper = NULL; -static volatile struct snd_wait maui_sleep_flag = -{0}; - -static int -maui_wait(int mask) +static int maui_wait(int mask) { - int i; + int i; -/* - * Perform a short initial wait without sleeping - */ + /* + * Perform a short initial wait without sleeping + */ for (i = 0; i < 100; i++) - { - if (inb(HOST_STAT_PORT) & mask) - { - return 1; - } - } + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + } -/* - * Wait up to 15 seconds with sleeping - */ + /* + * Wait up to 15 seconds with sleeping + */ for (i = 0; i < 150; i++) - { - if (inb(HOST_STAT_PORT) & mask) - { - return 1; - } - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - maui_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&maui_sleeper); - if (!(maui_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - maui_sleep_flag.opts |= WK_TIMEOUT; - } - maui_sleep_flag.opts &= ~WK_SLEEP; - }; - if (signal_pending(current)) - { - return 0; - } - } - + { + if (inb(HOST_STAT_PORT) & mask) + return 1; + current->timeout = jiffies + HZ / 10; + current->state = TASK_INTERRUPTIBLE; + schedule(); + current->timeout = 0; + if (signal_pending(current)) + return 0; + } return 0; } -static int -maui_read(void) +static int maui_read(void) { if (maui_wait(STAT_RX_AVAIL)) return inb(HOST_DATA_PORT); - return -1; } -static int -maui_write(unsigned char data) +static int maui_write(unsigned char data) { if (maui_wait(STAT_TX_AVAIL)) - { - outb((data), HOST_DATA_PORT); - return 1; - } - printk("Maui: Write timeout\n"); - + { + outb((data), HOST_DATA_PORT); + return 1; + } + printk(KERN_WARNING "Maui: Write timeout\n"); return 0; } -static void -mauiintr(int irq, void *dev_id, struct pt_regs *dummy) +static void mauiintr(int irq, void *dev_id, struct pt_regs *dummy) { irq_ok = 1; } -static int -download_code(void) +static int download_code(void) { - int i, lines = 0; - int eol_seen = 0, done = 0; - int skip = 1; + int i, lines = 0; + int eol_seen = 0, done = 0; + int skip = 1; - printk("Code download (%d bytes): ", maui_osLen); + printk(KERN_INFO "Code download (%d bytes): ", maui_osLen); for (i = 0; i < maui_osLen; i++) - { - if (maui_os[i] != '\r') - if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) - { - skip = 0; - - if (maui_os[i] == '\n') - eol_seen = skip = 1; - else if (maui_os[i] == 'S') - { - if (maui_os[i + 1] == '8') - done = 1; - if (!maui_write(0xF1)) - goto failure; - if (!maui_write('S')) - goto failure; - } else - { - if (!maui_write(maui_os[i])) - goto failure; - } - - if (eol_seen) - { - int c = 0; - - int n; - - eol_seen = 0; - - for (n = 0; n < 2; n++) - if (maui_wait(STAT_RX_AVAIL)) - { - c = inb(HOST_DATA_PORT); - break; - } - if (c != 0x80) - { - printk("Download not acknowledged\n"); - return 0; - } else if (!(lines++ % 10)) - printk("."); - - if (done) + { + if (maui_os[i] != '\r') + { + if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) + { + skip = 0; + + if (maui_os[i] == '\n') + eol_seen = skip = 1; + else if (maui_os[i] == 'S') + { + if (maui_os[i + 1] == '8') + done = 1; + if (!maui_write(0xF1)) + goto failure; + if (!maui_write('S')) + goto failure; + } + else + { + if (!maui_write(maui_os[i])) + goto failure; + } + + if (eol_seen) + { + int c = 0; + int n; + + eol_seen = 0; + + for (n = 0; n < 2; n++) + { + if (maui_wait(STAT_RX_AVAIL)) { - printk("\nDownload complete\n"); - return 1; + c = inb(HOST_DATA_PORT); + break; } - } - } - } - - failure: - - printk("\nDownload failed!!!\n"); + } + if (c != 0x80) + { + printk("Download not acknowledged\n"); + return 0; + } + else if (!(lines++ % 10)) + printk("."); + + if (done) + { + printk("\n"); + printk(KERN_INFO "Download complete\n"); + return 1; + } + } + } + } + } + +failure: + printk("\n"); + printk(KERN_ERR "Download failed!!!\n"); return 0; } -static int -maui_init(int irq) +static int maui_init(int irq) { - int i; - unsigned char bits; +#ifdef __SMP__ + int i; +#endif + unsigned char bits; switch (irq) - { - case 9: - bits = 0x00; - break; - case 5: - bits = 0x08; - break; - case 12: - bits = 0x10; - break; - case 15: - bits = 0x18; - break; - - default: - printk("Maui: Invalid IRQ %d\n", irq); - return 0; - } + { + case 9: + bits = 0x00; + break; + case 5: + bits = 0x08; + break; + case 12: + bits = 0x10; + break; + case 15: + bits = 0x18; + break; + default: + printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq); + return 0; + } outb((0x00), HOST_CTRL_PORT); /* Reset */ - outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */ outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ - outb((0x80), HOST_CTRL_PORT); /* Leave reset */ outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ +#ifndef __SMP__ for (i = 0; i < 1000000 && !irq_ok; i++); if (!irq_ok) return 0; - +#endif outb((0x80), HOST_CTRL_PORT); /* Leave reset */ - printk("Turtle Beach Maui initialization\n"); + printk(KERN_INFO "Turtle Beach Maui initialization\n"); if (!download_code()) return 0; @@ -255,54 +231,51 @@ maui_write(0xf0); maui_write(1); if (maui_read() != 0x80) - { - maui_write(0xf0); - maui_write(1); - if (maui_read() != 0x80) - printk("Maui didn't acknowledge set HW mode command\n"); - } - printk("Maui initialized OK\n"); + { + maui_write(0xf0); + maui_write(1); + if (maui_read() != 0x80) + printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n"); + } + printk(KERN_INFO "Maui initialized OK\n"); return 1; } -static int -maui_short_wait(int mask) +static int maui_short_wait(int mask) { - int i; + int i; for (i = 0; i < 1000; i++) - { - if (inb(HOST_STAT_PORT) & mask) - { - return 1; - } - } - + { + if (inb(HOST_STAT_PORT) & mask) + { + return 1; + } + } return 0; } -static int -maui_load_patch(int dev, int format, const char *addr, +static int maui_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { struct sysex_info header; - unsigned long left, src_offs; - int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; - int i; + unsigned long left, src_offs; + int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; + int i; if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ return orig_load_patch(dev, format, addr, offs, count, pmgr_flag); if (format != MAUI_PATCH) - { - printk("Maui: Unknown patch format\n"); - } + { + printk(KERN_WARNING "Maui: Unknown patch format\n"); + } if (count < hdr_size) - { - printk("Maui error: Patch header too short\n"); + { +/* printk("Maui error: Patch header too short\n");*/ return -EINVAL; - } + } count -= hdr_size; /* @@ -310,43 +283,43 @@ * been transferred already. */ - copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); + if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs)) + return -EFAULT; if (count < header.len) - { - printk("Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); + { + printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); header.len = count; - } + } left = header.len; src_offs = 0; for (i = 0; i < left; i++) - { - unsigned char data; + { + unsigned char data; - get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); - if (i == 0 && !(data & 0x80)) - return -EINVAL; - - if (maui_write(data) == -1) - return -EIO; - } + if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i]))) + return -EFAULT; + if (i == 0 && !(data & 0x80)) + return -EINVAL; + + if (maui_write(data) == -1) + return -EIO; + } if ((i = maui_read()) != 0x80) - { - if (i != -1) - printk("Maui: Error status %02x\n", i); - - return -EIO; - } + { + if (i != -1) + printk("Maui: Error status %02x\n", i); + return -EIO; + } return 0; } -int -probe_maui(struct address_info *hw_config) +int probe_maui(struct address_info *hw_config) { - int i; - int tmp1, tmp2, ret; + int i; + int tmp1, tmp2, ret; if (check_region(hw_config->io_base, 8)) return 0; @@ -357,42 +330,41 @@ if (snd_set_irq_handler(hw_config->irq, mauiintr, "Maui", maui_osp) < 0) return 0; - maui_sleep_flag.opts = WK_NONE; -/* - * Initialize the processor if necessary - */ + /* + * Initialize the processor if necessary + */ if (maui_osLen > 0) - { - if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || - !maui_write(0x9F) || /* Report firmware version */ - !maui_short_wait(STAT_RX_AVAIL) || - maui_read() == -1 || maui_read() == -1) - if (!maui_init(hw_config->irq)) - { - snd_release_irq(hw_config->irq); - return 0; - } - } + { + if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || + !maui_write(0x9F) || /* Report firmware version */ + !maui_short_wait(STAT_RX_AVAIL) || + maui_read() == -1 || maui_read() == -1) + if (!maui_init(hw_config->irq)) + { + snd_release_irq(hw_config->irq); + return 0; + } + } if (!maui_write(0xCF)) /* Report hardware version */ - { - printk("No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq(hw_config->irq); - return 0; - } + { + printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); + snd_release_irq(hw_config->irq); + return 0; + } if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) - { - printk("No WaveFront firmware detected (card uninitialized?)\n"); - snd_release_irq(hw_config->irq); - return 0; - } + { + printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); + snd_release_irq(hw_config->irq); + return 0; + } if (tmp1 == 0xff || tmp2 == 0xff) - { + { snd_release_irq(hw_config->irq); return 0; - } + } if (trace_init) - printk("WaveFront hardware version %d.%d\n", tmp1, tmp2); + printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); if (!maui_write(0x9F)) /* Report firmware version */ return 0; @@ -400,17 +372,17 @@ return 0; if (trace_init) - printk("WaveFront firmware version %d.%d\n", tmp1, tmp2); + printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2); if (!maui_write(0x85)) /* Report free DRAM */ return 0; tmp1 = 0; for (i = 0; i < 4; i++) - { - tmp1 |= maui_read() << (7 * i); - } + { + tmp1 |= maui_read() << (7 * i); + } if (trace_init) - printk("Available DRAM %dk\n", tmp1 / 1024); + printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024); for (i = 0; i < 1000; i++) if (probe_mpu401(hw_config)) @@ -424,10 +396,9 @@ return ret; } -void -attach_maui(struct address_info *hw_config) +void attach_maui(struct address_info *hw_config) { - int this_dev; + int this_dev; conf_printf("Maui", hw_config); @@ -436,75 +407,71 @@ attach_mpu401(hw_config); if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ - { - struct synth_operations *synth; + { + struct synth_operations *synth; - this_dev = hw_config->slots[1]; + this_dev = hw_config->slots[1]; - /* - * Intercept patch loading calls so that they can be handled - * by the Maui driver. - */ + /* + * Intercept patch loading calls so that they can be handled + * by the Maui driver. + */ - synth = midi_devs[this_dev]->converter; - synth->id = "MAUI"; + synth = midi_devs[this_dev]->converter; + synth->id = "MAUI"; - if (synth != NULL) - { - orig_load_patch = synth->load_patch; - synth->load_patch = &maui_load_patch; - } else - printk(KERN_ERR "Maui: Can't install patch loader\n"); - } + if (synth != NULL) + { + orig_load_patch = synth->load_patch; + synth->load_patch = &maui_load_patch; + } + else + printk(KERN_ERR "Maui: Can't install patch loader\n"); + } } -void -unload_maui(struct address_info *hw_config) +void unload_maui(struct address_info *hw_config) { - int irq = hw_config->irq; - + int irq = hw_config->irq; release_region(hw_config->io_base + 2, 6); - unload_mpu401(hw_config); if (irq < 0) irq = -irq; - if (irq > 0) snd_release_irq(irq); } #ifdef MODULE -int io = -1; -int irq = -1; +int io = -1; +int irq = -1; -static int fw_load = 0; +static int fw_load = 0; struct address_info cfg; /* - * Install a CS4232 based card. Need to have ad1848 and mpu401 - * loaded ready. + * Install a CS4232 based card. Need to have ad1848 and mpu401 + * loaded ready. */ -int -init_module(void) +int init_module(void) { - printk("Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); if (io == -1 || irq == -1) - { - printk("maui: irq and io must be set.\n"); - return -EINVAL; - } + { + printk(KERN_INFO "maui: irq and io must be set.\n"); + return -EINVAL; + } cfg.io_base = io; cfg.irq = irq; if (maui_os == NULL) - { - fw_load = 1; - maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); - } + { + fw_load = 1; + maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); + } if (probe_maui(&cfg) == 0) return -ENODEV; attach_maui(&cfg); @@ -512,8 +479,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { if (fw_load && maui_os) kfree(maui_os); diff -u --recursive --new-file v2.1.87/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v2.1.87/linux/drivers/sound/midi_synth.c Tue Dec 30 10:59:17 1997 +++ linux/drivers/sound/midi_synth.c Thu Feb 19 14:46:14 1998 @@ -24,10 +24,6 @@ #define _MIDI_SYNTH_C_ -static struct wait_queue *sysex_sleeper = NULL; -static volatile struct snd_wait sysex_sleep_flag = -{0}; - #include "midi_synth.h" static int midi2synth[MAX_MIDI_DEV]; @@ -270,7 +266,9 @@ switch (cmd) { case SNDCTL_SYNTH_INFO: - return __copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info)); + if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info))) + return -EFAULT; + return 0; case SNDCTL_SYNTH_MEMAVL: return 0x7fffffff; @@ -448,8 +446,6 @@ inc->m_prev_status = 0x00; restore_flags(flags); - sysex_sleep_flag.opts = WK_NONE; - return 1; } @@ -521,8 +517,6 @@ left = sysex.len; src_offs = 0; - sysex_sleep_flag.opts = WK_NONE; - for (i = 0; i < left && !signal_pending(current); i++) { unsigned char data; @@ -544,23 +538,7 @@ } while (!midi_devs[orig_dev]->outputc(orig_dev, (unsigned char) (data & 0xff)) && !signal_pending(current)) - - { - unsigned long tlimit; - - if (1) - current->timeout = tlimit = jiffies + (1); - else - tlimit = (unsigned long) -1; - sysex_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&sysex_sleeper); - if (!(sysex_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sysex_sleep_flag.opts |= WK_TIMEOUT; - } - sysex_sleep_flag.opts &= ~WK_SLEEP; - }; /* Wait for timeout */ + schedule(); if (!first_byte && data & 0x80) return 0; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.1.87/linux/drivers/sound/midibuf.c Tue Dec 30 11:02:39 1997 +++ linux/drivers/sound/midibuf.c Thu Feb 19 14:46:14 1998 @@ -14,6 +14,8 @@ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) */ #include +#include +#include #define MIDIBUF_C @@ -27,41 +29,33 @@ #define MAX_QUEUE_SIZE 4000 -static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] = -{NULL}; -static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = -{ - {0}}; -static struct wait_queue *input_sleeper[MAX_MIDI_DEV] = -{NULL}; -static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = -{ - {0}}; +static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] = {NULL}; +static struct wait_queue *input_sleeper[MAX_MIDI_DEV] = {NULL}; struct midi_buf - { - int len, head, tail; - unsigned char queue[MAX_QUEUE_SIZE]; - }; +{ + int len, head, tail; + unsigned char queue[MAX_QUEUE_SIZE]; +}; struct midi_parms - { - int prech_timeout; /* - * Timeout before the first ch - */ - }; +{ + int prech_timeout; /* + * Timeout before the first ch + */ +}; -static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = -{NULL}; -static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = -{NULL}; +static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL}; +static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL}; static struct midi_parms parms[MAX_MIDI_DEV]; -static void midi_poll(unsigned long dummy); +static void midi_poll(unsigned long dummy); + +static struct timer_list poll_timer = { + NULL, NULL, 0, 0, midi_poll +}; -static struct timer_list poll_timer = -{NULL, NULL, 0, 0, midi_poll}; static volatile int open_devs = 0; #define DATA_AVAIL(q) (q->len) @@ -87,8 +81,7 @@ restore_flags(flags); \ } -static void -drain_midi_queue(int dev) +static void drain_midi_queue(int dev) { /* @@ -96,29 +89,15 @@ */ if (midi_devs[dev]->buffer_status != NULL) - while (!signal_pending(current) && - midi_devs[dev]->buffer_status(dev)) - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; + while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) + { + current->timeout = jiffies + HZ / 10; + interruptible_sleep_on(&midi_sleeper[dev]); + current->timeout = 0; + } } -static void -midi_input_intr(int dev, unsigned char data) +static void midi_input_intr(int dev, unsigned char data) { if (midi_in_buf[dev] == NULL) return; @@ -130,27 +109,20 @@ * Ignore */ - if (SPACE_AVAIL(midi_in_buf[dev])) - { - QUEUE_BYTE(midi_in_buf[dev], data); - if ((input_sleep_flag[dev].opts & WK_SLEEP)) - { - input_sleep_flag[dev].opts = WK_WAKEUP; - wake_up(&input_sleeper[dev]); - }; - } + if (SPACE_AVAIL(midi_in_buf[dev])) { + QUEUE_BYTE(midi_in_buf[dev], data); + wake_up(&input_sleeper[dev]); + } } -static void -midi_output_intr(int dev) +static void midi_output_intr(int dev) { /* * Currently NOP */ } -static void -midi_poll(unsigned long dummy) +static void midi_poll(unsigned long dummy) { unsigned long flags; int dev; @@ -158,116 +130,99 @@ save_flags(flags); cli(); if (open_devs) - { - for (dev = 0; dev < num_midis; dev++) - if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) - { - int ok = 1; - - while (DATA_AVAIL(midi_out_buf[dev]) && ok) - { - int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; - - restore_flags(flags); /* Give some time to others */ - ok = midi_devs[dev]->outputc(dev, c); - save_flags(flags); - cli(); - midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; - midi_out_buf[dev]->len--; - } - - if (DATA_AVAIL(midi_out_buf[dev]) < 100 && - (midi_sleep_flag[dev].opts & WK_SLEEP)) - { - midi_sleep_flag[dev].opts = WK_WAKEUP; - wake_up(&midi_sleeper[dev]); - }; - } - { - poll_timer.expires = (1) + jiffies; - add_timer(&poll_timer); - }; /* - * Come back later - */ - } + { + for (dev = 0; dev < num_midis; dev++) + if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL) + { + int ok = 1; + + while (DATA_AVAIL(midi_out_buf[dev]) && ok) + { + int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head]; + + restore_flags(flags); /* Give some time to others */ + ok = midi_devs[dev]->outputc(dev, c); + cli(); + midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; + midi_out_buf[dev]->len--; + } + + if (DATA_AVAIL(midi_out_buf[dev]) < 100) + wake_up(&midi_sleeper[dev]); + } + poll_timer.expires = (1) + jiffies; + add_timer(&poll_timer); + /* + * Come back later + */ + } restore_flags(flags); } -int -MIDIbuf_open(int dev, struct fileinfo *file) +int MIDIbuf_open(int dev, struct file *file) { - int mode, err; + int mode, err; dev = dev >> 4; - mode = file->mode & O_ACCMODE; + mode = translate_mode(file); if (num_midis > MAX_MIDI_DEV) - { - printk("Sound: FATAL ERROR: Too many midi interfaces\n"); - num_midis = MAX_MIDI_DEV; - } + { + printk(KERN_ERR "midi: Too many midi interfaces\n"); + num_midis = MAX_MIDI_DEV; + } if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) - { - printk("Sound: Nonexistent MIDI interface %d\n", dev); return -ENXIO; - } /* - * Interrupts disabled. Be careful + * Interrupts disabled. Be careful */ if ((err = midi_devs[dev]->open(dev, mode, midi_input_intr, midi_output_intr)) < 0) - { - return err; - } - parms[dev].prech_timeout = 0; + return err; + parms[dev].prech_timeout = 0; midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); if (midi_in_buf[dev] == NULL) - { - printk("midi: Can't allocate buffer\n"); - midi_devs[dev]->close(dev); - return -EIO; - } + { + printk(KERN_WARNING "midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + return -EIO; + } midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); if (midi_out_buf[dev] == NULL) - { - printk("midi: Can't allocate buffer\n"); - midi_devs[dev]->close(dev); - vfree(midi_in_buf[dev]); - midi_in_buf[dev] = NULL; - return -EIO; - } + { + printk(KERN_WARNING "midi: Can't allocate buffer\n"); + midi_devs[dev]->close(dev); + vfree(midi_in_buf[dev]); + midi_in_buf[dev] = NULL; + return -EIO; + } midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; open_devs++; - midi_sleep_flag[dev].opts = WK_NONE; - input_sleep_flag[dev].opts = WK_NONE; + init_waitqueue(&midi_sleeper[dev]); + init_waitqueue(&input_sleeper[dev]); if (open_devs < 2) /* This was first open */ - { - ; - - { - poll_timer.expires = (1) + jiffies; - add_timer(&poll_timer); - }; /* Start polling */ - } + { + poll_timer.expires = 1 + jiffies; + add_timer(&poll_timer); /* Start polling */ + } return err; } -void -MIDIbuf_release(int dev, struct fileinfo *file) +void MIDIbuf_release(int dev, struct file *file) { - int mode; - unsigned long flags; + int mode; + unsigned long flags; dev = dev >> 4; - mode = file->mode & O_ACCMODE; + mode = translate_mode(file); if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL) return; @@ -276,42 +231,26 @@ cli(); /* - * Wait until the queue is empty + * Wait until the queue is empty */ if (mode != OPEN_READ) - { - midi_devs[dev]->outputc(dev, 0xfe); /* + { + midi_devs[dev]->outputc(dev, 0xfe); /* * Active sensing to shut the * devices */ - while (!signal_pending(current) && - DATA_AVAIL(midi_out_buf[dev])) - - { - unsigned long tlimit; - - if (0) - current->timeout = tlimit = jiffies + (0); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; /* - * Sync - */ + while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev])) + interruptible_sleep_on(&midi_sleeper[dev]); + /* + * Sync + */ - drain_midi_queue(dev); /* - * Ensure the output queues are empty - */ - } + drain_midi_queue(dev); /* + * Ensure the output queues are empty + */ + } restore_flags(flags); midi_devs[dev]->close(dev); @@ -325,12 +264,11 @@ open_devs--; } -int -MIDIbuf_write(int dev, struct fileinfo *file, const char *buf, int count) +int MIDIbuf_write(int dev, struct file *file, const char *buf, int count) { - unsigned long flags; - int c, n, i; - unsigned char tmp_data; + unsigned long flags; + int c, n, i; + unsigned char tmp_data; dev = dev >> 4; @@ -343,192 +281,143 @@ c = 0; while (c < count) - { - n = SPACE_AVAIL(midi_out_buf[dev]); + { + n = SPACE_AVAIL(midi_out_buf[dev]); - if (n == 0) /* + if (n == 0) { /* * No space just now. We have to sleep */ - { - - { - unsigned long tlimit; - - if (0) - current->timeout = tlimit = jiffies + (0); - else - tlimit = (unsigned long) -1; - midi_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag[dev].opts |= WK_TIMEOUT; - } - midi_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if (signal_pending(current)) - { - restore_flags(flags); - return -EINTR; - } - n = SPACE_AVAIL(midi_out_buf[dev]); - } - if (n > (count - c)) - n = count - c; - - for (i = 0; i < n; i++) - { - copy_from_user((char *) &tmp_data, &(buf)[c], 1); - QUEUE_BYTE(midi_out_buf[dev], tmp_data); - c++; - } - } + interruptible_sleep_on(&midi_sleeper[dev]); + if (signal_pending(current)) + { + restore_flags(flags); + return -EINTR; + } + n = SPACE_AVAIL(midi_out_buf[dev]); + } + if (n > (count - c)) + n = count - c; + for (i = 0; i < n; i++) + { + /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */ + copy_from_user((char *) &tmp_data, &(buf)[c], 1); + QUEUE_BYTE(midi_out_buf[dev], tmp_data); + c++; + } + } restore_flags(flags); - return c; } -int -MIDIbuf_read(int dev, struct fileinfo *file, char *buf, int count) +int MIDIbuf_read(int dev, struct file *file, char *buf, int count) { - int n, c = 0; - unsigned long flags; - unsigned char tmp_data; + int n, c = 0; + unsigned long flags; + unsigned char tmp_data; dev = dev >> 4; save_flags(flags); cli(); - if (!DATA_AVAIL(midi_in_buf[dev])) /* + if (!DATA_AVAIL(midi_in_buf[dev])) { /* * No data yet, wait */ - { - - { - unsigned long tlimit; - - if (parms[dev].prech_timeout) - current->timeout = tlimit = jiffies + (parms[dev].prech_timeout); - else - tlimit = (unsigned long) -1; - input_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&input_sleeper[dev]); - if (!(input_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - input_sleep_flag[dev].opts |= WK_TIMEOUT; - } - input_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if (signal_pending(current)) - c = -EINTR; /* - * The user is getting restless - */ - } + current->timeout = parms[dev].prech_timeout ? jiffies + parms[dev].prech_timeout : 0; + interruptible_sleep_on(&input_sleeper[dev]); + current->timeout = 0; + if (signal_pending(current)) + c = -EINTR; /* The user is getting restless */ + } if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /* * Got some bytes */ - { - n = DATA_AVAIL(midi_in_buf[dev]); - if (n > count) - n = count; - c = 0; - - while (c < n) - { - REMOVE_BYTE(midi_in_buf[dev], tmp_data); - { - char *fixit = (char *) &tmp_data; - - copy_to_user(&(buf)[c], fixit, 1); - }; - c++; - } - } + { + n = DATA_AVAIL(midi_in_buf[dev]); + if (n > count) + n = count; + c = 0; + + while (c < n) + { + char *fixit; + REMOVE_BYTE(midi_in_buf[dev], tmp_data); + fixit = (char *) &tmp_data; + /* BROKE BROKE BROKE */ + copy_to_user(&(buf)[c], fixit, 1); + c++; + } + } restore_flags(flags); - return c; } -int MIDIbuf_ioctl(int dev, struct fileinfo *file, +int MIDIbuf_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) { int val; dev = dev >> 4; - if (((cmd >> 8) & 0xff) == 'C') { - if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ - return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0); - printk("/dev/midi%d: No coprocessor for this device\n", dev); - return -ENXIO; - } else - switch (cmd) { - case SNDCTL_MIDI_PRETIME: - if (__get_user(val, (int *)arg)) - return -EFAULT; - if (val < 0) - val = 0; - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return __put_user(val, (int *)arg); + + if (((cmd >> 8) & 0xff) == 'C') + { + if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ + return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0); +/* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/ + return -ENXIO; + } + else + { + switch (cmd) + { + case SNDCTL_MIDI_PRETIME: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val < 0) + val = 0; + val = (HZ * val) / 10; + parms[dev].prech_timeout = val; + return put_user(val, (int *)arg); - default: - if (!midi_devs[dev]->ioctl) - return -EINVAL; - return midi_devs[dev]->ioctl(dev, cmd, arg); + default: + if (!midi_devs[dev]->ioctl) + return -EINVAL; + return midi_devs[dev]->ioctl(dev, cmd, arg); } + } } -int -MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait) { + unsigned int mask = 0; + dev = dev >> 4; - switch (sel_type) - { - case SEL_IN: - if (!DATA_AVAIL(midi_in_buf[dev])) - { - - input_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&input_sleeper[dev], wait); - return 0; - } - return 1; - break; - - case SEL_OUT: - if (SPACE_AVAIL(midi_out_buf[dev])) - { - - midi_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&midi_sleeper[dev], wait); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } + /* input */ + poll_wait(&input_sleeper[dev], wait); + if (DATA_AVAIL(midi_in_buf[dev])) + mask |= POLLIN | POLLRDNORM; - return 0; + /* output */ + poll_wait(&midi_sleeper[dev], wait); + if (!SPACE_AVAIL(midi_out_buf[dev])) + mask |= POLLOUT | POLLWRNORM; + + return mask; } -void -MIDIbuf_init(void) +void MIDIbuf_init(void) { } -int -MIDIbuf_avail(int dev) +int MIDIbuf_avail(int dev) { - return DATA_AVAIL (midi_in_buf[dev]); + if (midi_in_buf[dev]) + return DATA_AVAIL (midi_in_buf[dev]); + return 0; } diff -u --recursive --new-file v2.1.87/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.1.87/linux/drivers/sound/mpu401.c Tue Dec 30 10:59:17 1997 +++ linux/drivers/sound/mpu401.c Thu Feb 19 14:46:14 1998 @@ -772,7 +772,9 @@ return -EFAULT; if ((ret = mpu401_command(dev, &rec)) < 0) return ret; - return __copy_to_user(arg, &rec, sizeof(rec)); + if (__copy_to_user(arg, &rec, sizeof(rec))) + return -EFAULT; + return 0; default: return -EINVAL; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.1.87/linux/drivers/sound/opl3.c Tue Dec 30 10:59:17 1997 +++ linux/drivers/sound/opl3.c Thu Feb 19 14:46:14 1998 @@ -15,6 +15,7 @@ */ #include #include +#include /* * Major improvements to the FM handling 30AUG92 by Rob Hooft, @@ -120,7 +121,9 @@ case SNDCTL_SYNTH_INFO: devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - return __copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info)); + if (__copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info))) + return -EFAULT; + return 0; case SNDCTL_SYNTH_MEMAVL: return 0x7fffffff; @@ -215,17 +218,17 @@ int tmp; outb((0x02), ioaddr - 8); /* Select OPL4 ID register */ - tenmicrosec(devc->osp); + udelay(10); tmp = inb(ioaddr - 7); /* Read it */ - tenmicrosec(devc->osp); + udelay(10); if (tmp == 0x20) /* OPL4 should return 0x20 here */ { detected_model = 4; outb((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */ - tenmicrosec(devc->osp); + udelay(10); outb((0x1B), ioaddr - 7); /* Write value */ - tenmicrosec(devc->osp); + udelay(10); } else detected_model = 3; @@ -707,7 +710,7 @@ outb(((unsigned char) (addr & 0xff)), io_addr); if (devc->model != 2) - tenmicrosec(devc->osp); + udelay(10); else for (i = 0; i < 2; i++) inb(io_addr); @@ -715,11 +718,7 @@ outb(((unsigned char) (val & 0xff)), io_addr + 1); if (devc->model != 2) - { - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); - } + udelay(30); else for (i = 0; i < 2; i++) inb(io_addr); diff -u --recursive --new-file v2.1.87/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v2.1.87/linux/drivers/sound/os.h Mon Jan 5 10:13:36 1998 +++ linux/drivers/sound/os.h Thu Feb 19 14:46:14 1998 @@ -41,10 +41,6 @@ #define FALSE 0 #define TRUE 1 -struct snd_wait { - volatile int opts; - }; - extern int sound_alloc_dma(int chn, char *deviceID); extern int sound_open_dma(int chn, char *deviceID); extern void sound_free_dma(int chn); diff -u --recursive --new-file v2.1.87/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.1.87/linux/drivers/sound/pss.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/pss.c Thu Feb 19 14:46:14 1998 @@ -546,7 +546,7 @@ mbuf->len = i; /* feed back number of WORDs sent */ err = __copy_to_user(arg, mbuf, sizeof(copr_msg)); vfree(mbuf); - return err ? err : -EIO; + return err ? -EFAULT : -EIO; } } restore_flags(flags); @@ -594,7 +594,9 @@ } dbuf.parm1 = tmp; restore_flags(flags); - return __copy_to_user(arg, &dbuf, sizeof(dbuf)); + if (__copy_to_user(arg, &dbuf, sizeof(dbuf))) + return -EFAULT; + return 0; case SNDCTL_COPR_WDATA: if (__copy_from_user(&dbuf, arg, sizeof(dbuf))) @@ -667,7 +669,9 @@ } dbuf.parm1 |= tmp & 0x00ff; restore_flags(flags); - return __copy_to_user(arg, &dbuf, sizeof(dbuf)); + if (__copy_to_user(arg, &dbuf, sizeof(dbuf))) + return -EFAULT; + return 0; default: return -EINVAL; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.87/linux/drivers/sound/sb_common.c Sat Nov 29 10:33:21 1997 +++ linux/drivers/sound/sb_common.c Thu Feb 19 14:46:14 1998 @@ -11,6 +11,7 @@ * for more info. */ #include +#include #include "sound_config.h" @@ -27,12 +28,13 @@ static sb_devc *detected_devc = NULL; /* For communication from probe to init */ static sb_devc *last_devc = NULL; /* For MPU401 initialization */ -static sb_devc *irq2devc[16] = -{NULL}; -static unsigned char jazz_irq_bits[] = -{0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}; -static unsigned char jazz_dma_bits[] = -{0, 1, 0, 2, 0, 3, 0, 4}; +static sb_devc *irq2devc[16] = {NULL}; +static unsigned char jazz_irq_bits[] = { + 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 +}; +static unsigned char jazz_dma_bits[] = { + 0, 1, 0, 2, 0, 3, 0, 4 +}; /* * Jazz16 chipset specific control variables @@ -54,8 +56,7 @@ #endif -int -sb_dsp_command(sb_devc * devc, unsigned char val) +int sb_dsp_command(sb_devc * devc, unsigned char val) { int i; unsigned long limit; @@ -70,33 +71,31 @@ */ for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb(DSP_STATUS) & 0x80) == 0) - { - outb((val), DSP_COMMAND); - return 1; - } - } + { + if ((inb(DSP_STATUS) & 0x80) == 0) + { + outb((val), DSP_COMMAND); + return 1; + } + } - printk("Sound Blaster: DSP Command(%x) Timeout.\n", val); + printk(KERN_WARNING "Sound Blaster: DSP Command(%x) Timeout.\n", val); return 0; } -static int -sb_dsp_get_byte(sb_devc * devc) +static int sb_dsp_get_byte(sb_devc * devc) { int i; for (i = 1000; i; i--) if (inb(DSP_DATA_AVAIL) & 0x80) - { - return inb(DSP_READ); - } + { + return inb(DSP_READ); + } return 0xffff; } -int -ess_write(sb_devc * devc, unsigned char reg, unsigned char data) +int ess_write(sb_devc * devc, unsigned char reg, unsigned char data) { /* Write a byte to an extended mode register of ES1688 */ @@ -106,8 +105,7 @@ return sb_dsp_command(devc, data); } -int -ess_read(sb_devc * devc, unsigned char reg) +int ess_read(sb_devc * devc, unsigned char reg) { /* Read a byte from an extended mode register of ES1688 */ @@ -120,61 +118,61 @@ return sb_dsp_get_byte(devc); } -static void -sbintr(int irq, void *dev_id, struct pt_regs *dummy) +static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) { - int status; + int status; unsigned char src = 0xff; - sb_devc *devc = irq2devc[irq]; + sb_devc *devc = irq2devc[irq]; if (devc == NULL || devc->irq != irq) - { - DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq)); - return; - } + { + DEB(printk("sbintr: Bogus interrupt IRQ%d\n", irq)); + return; + } devc->irq_ok = 1; if (devc->model == MDL_SB16) - { - - src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ + { + src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ #if defined(CONFIG_MIDI)&& (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) - if (src & 4) - uart401intr(devc->irq, NULL, NULL); /* MPU401 interrupt */ + if (src & 4) + uart401intr(devc->irq, NULL, NULL); /* MPU401 interrupt */ #endif - if (!(src & 3)) - return; /* Not a DSP interrupt */ - } + if (!(src & 3)) + return; /* Not a DSP interrupt */ + } if (devc->intr_active) + { switch (devc->irq_mode) - { - case IMODE_OUTPUT: - DMAbuf_outputintr(devc->dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr(devc->dev); - break; + { + case IMODE_OUTPUT: + DMAbuf_outputintr(devc->dev, 1); + break; + + case IMODE_INPUT: + DMAbuf_inputintr(devc->dev); + break; - case IMODE_INIT: - break; + case IMODE_INIT: + break; - case IMODE_MIDI: + case IMODE_MIDI: #if defined(CONFIG_MIDI) - sb_midi_interrupt(devc); + sb_midi_interrupt(devc); #endif - break; + break; - default: - /* printk( "Sound Blaster: Unexpected interrupt\n"); */ - ; - } -/* - * Acknowledge interrupts - */ + default: + /* printk( "Sound Blaster: Unexpected interrupt\n"); */ + ; + } + } + /* + * Acknowledge interrupts + */ if (src & 0x01) status = inb(DSP_DATA_AVAIL); @@ -184,31 +182,28 @@ } -int -sb_dsp_reset(sb_devc * devc) +int sb_dsp_reset(sb_devc * devc) { - int loopc; + int loopc; DEB(printk("Entered sb_dsp_reset()\n")); if (devc->model == MDL_ESS) - outb((3), DSP_RESET); /* Reset FIFO too */ + outb(3, DSP_RESET); /* Reset FIFO too */ else - outb((1), DSP_RESET); + outb(1, DSP_RESET); - tenmicrosec(devc->osp); - outb((0), DSP_RESET); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); + udelay(10); + outb(0, DSP_RESET); + udelay(30); for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++); if (inb(DSP_READ) != 0xAA) - { - DDB(printk("sb: No response to RESET\n")); - return 0; /* Sorry */ - } + { + DDB(printk("sb: No response to RESET\n")); + return 0; /* Sorry */ + } if (devc->model == MDL_ESS) sb_dsp_command(devc, 0xc6); /* Enable extended mode */ @@ -216,10 +211,9 @@ return 1; } -static void -dsp_get_vers(sb_devc * devc) +static void dsp_get_vers(sb_devc * devc) { - int i; + int i; unsigned long flags; @@ -230,32 +224,31 @@ sb_dsp_command(devc, 0xe1); /* Get version */ for (i = 100000; i; i--) - { - if (inb(DSP_DATA_AVAIL) & 0x80) - { - if (devc->major == 0) - devc->major = inb(DSP_READ); - else - { - devc->minor = inb(DSP_READ); - break; - } - } - } + { + if (inb(DSP_DATA_AVAIL) & 0x80) + { + if (devc->major == 0) + devc->major = inb(DSP_READ); + else + { + devc->minor = inb(DSP_READ); + break; + } + } + } DDB(printk("DSP version %d.%d\n", devc->major, devc->minor)); restore_flags(flags); } -static int -sb16_set_dma_hw(sb_devc * devc) +static int sb16_set_dma_hw(sb_devc * devc) { - int bits; + int bits; if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) - { - printk("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); - return 0; - } + { + printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); + return 0; + } bits = (1 << devc->dma8); if (devc->dma16 >= 5 && devc->dma16 <= 7) @@ -266,90 +259,84 @@ } #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) -static void -sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) +static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config) { -/* - * This routine initializes new MIDI port setup register of SB Vibra (CT2502). - */ + /* + * This routine initializes new MIDI port setup register of SB Vibra (CT2502). + */ unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; switch (hw_config->io_base) - { - case 0x300: - sb_setmixer(devc, 0x84, bits | 0x04); - break; - - case 0x330: - sb_setmixer(devc, 0x84, bits | 0x00); - break; - - default: - sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ - printk("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); - } + { + case 0x300: + sb_setmixer(devc, 0x84, bits | 0x04); + break; + + case 0x330: + sb_setmixer(devc, 0x84, bits | 0x00); + break; + + default: + sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */ + printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); + } } #endif -static int -sb16_set_irq_hw(sb_devc * devc, int level) +static int sb16_set_irq_hw(sb_devc * devc, int level) { - int ival; + int ival; switch (level) - { - case 5: - ival = 2; - break; - case 7: - ival = 4; - break; - case 9: - ival = 1; - break; - case 10: - ival = 8; - break; - default: - printk("SB16 IRQ%d is not possible\n", level); - return 0; - } + { + case 5: + ival = 2; + break; + case 7: + ival = 4; + break; + case 9: + ival = 1; + break; + case 10: + ival = 8; + break; + default: + printk(KERN_ERR "SB16 IRQ%d is not possible\n", level); + return 0; + } sb_setmixer(devc, IRQ_NR, ival); return 1; } -static void -relocate_Jazz16(sb_devc * devc, struct address_info *hw_config) +static void relocate_Jazz16(sb_devc * devc, struct address_info *hw_config) { - unsigned char bits = 0; - unsigned long flags; + unsigned char bits = 0; + unsigned long flags; if (jazz16_base != 0 && jazz16_base != hw_config->io_base) return; switch (hw_config->io_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - - default: - return; - } - + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + default: + return; + } bits = jazz16_bits = bits << 5; - jazz16_base = hw_config->io_base; -/* - * Magic wake up sequence by writing to 0x201 (aka Joystick port) - */ + /* + * Magic wake up sequence by writing to 0x201 (aka Joystick port) + */ save_flags(flags); cli(); outb((0xAF), 0x201); @@ -358,15 +345,13 @@ restore_flags(flags); } -static int -init_Jazz16(sb_devc * devc, struct address_info *hw_config) +static int init_Jazz16(sb_devc * devc, struct address_info *hw_config) { - char name[100]; - -/* - * First try to check that the card has Jazz16 chip. It identifies itself - * by returning 0x12 as response to DSP command 0xfa. - */ + char name[100]; + /* + * First try to check that the card has Jazz16 chip. It identifies itself + * by returning 0x12 as response to DSP command 0xfa. + */ if (!sb_dsp_command(devc, 0xfa)) return 0; @@ -374,32 +359,32 @@ if (sb_dsp_get_byte(devc) != 0x12) return 0; -/* - * OK so far. Now configure the IRQ and DMA channel used by the card. - */ + /* + * OK so far. Now configure the IRQ and DMA channel used by the card. + */ if (hw_config->irq < 1 || hw_config->irq > 15 || jazz_irq_bits[hw_config->irq] == 0) - { - printk("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); + return 0; + } if (hw_config->dma < 0 || hw_config->dma > 3 || jazz_dma_bits[hw_config->dma] == 0) - { - printk("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); + { + printk(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); return 0; - } + } if (hw_config->dma2 < 0) - { - printk("Jazz16: No 16 bit DMA channel defined\n"); - return 0; - } + { + printk(KERN_ERR "Jazz16: No 16 bit DMA channel defined\n"); + return 0; + } if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || jazz_dma_bits[hw_config->dma2] == 0) - { - printk("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); - return 0; - } + { + printk(KERN_ERR "Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); + return 0; + } devc->dma16 = hw_config->dma2; if (!sb_dsp_command(devc, 0xfb)) @@ -412,52 +397,45 @@ if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq])) return 0; -/* - * Now we have configured a standard Jazz16 device. - */ + /* + * Now we have configured a standard Jazz16 device. + */ devc->model = MDL_JAZZ; strcpy(name, "Jazz16"); - - hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc(strlen(name + 1))); - sound_mem_sizes[sound_nblocks] = strlen(name + 1); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (hw_config->name != NULL) - strcpy(hw_config->name, name); + hw_config->name = "Jazz16"; devc->caps |= SB_NO_MIDI; return 1; } -static void -relocate_ess1688(sb_devc * devc) +static void relocate_ess1688(sb_devc * devc) { - unsigned char bits; + unsigned char bits; switch (devc->base) - { - case 0x220: - bits = 0x04; - break; - case 0x230: - bits = 0x05; - break; - case 0x240: - bits = 0x06; - break; - case 0x250: - bits = 0x07; - break; - default: - return; /* Wrong port */ - } + { + case 0x220: + bits = 0x04; + break; + case 0x230: + bits = 0x05; + break; + case 0x240: + bits = 0x06; + break; + case 0x250: + bits = 0x07; + break; + default: + return; /* Wrong port */ + } DDB(printk("Doing ESS1688 address selection\n")); - -/* - * ES1688 supports two alternative ways for software address config. - * First try the so called Read-Sequence-Key method. - */ + + /* + * ES1688 supports two alternative ways for software address config. + * First try the so called Read-Sequence-Key method. + */ /* Reset the sequence logic */ inb(0x229); @@ -479,9 +457,9 @@ return; #if 0 /* This causes system lockups (Nokia 386/25 at least) */ -/* - * The last resort is the system control register method. - */ + /* + * The last resort is the system control register method. + */ outb((0x00), 0xfb); /* 0xFB is the unlock register */ outb((0x00), 0xe0); /* Select index 0 */ @@ -490,130 +468,123 @@ #endif } -static int -ess_init(sb_devc * devc, struct address_info *hw_config) +static int ess_init(sb_devc * devc, struct address_info *hw_config) { - unsigned char cfg, irq_bits = 0, dma_bits = 0; - int ess_major = 0, ess_minor = 0; - int i; - char name[100]; + unsigned char cfg, irq_bits = 0, dma_bits = 0; + int ess_major = 0, ess_minor = 0; + int i; + static char name[100]; -/* - * Try to detect ESS chips. - */ + /* + * Try to detect ESS chips. + */ sb_dsp_command(devc, 0xe7); /* Return identification */ for (i = 1000; i; i--) - { - if (inb(DSP_DATA_AVAIL) & 0x80) - { - if (ess_major == 0) - ess_major = inb(DSP_READ); - else - { - ess_minor = inb(DSP_READ); - break; - } - } - } + { + if (inb(DSP_DATA_AVAIL) & 0x80) + { + if (ess_major == 0) + ess_major = inb(DSP_READ); + else + { + ess_minor = inb(DSP_READ); + break; + } + } + } if (ess_major == 0) return 0; if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) - { - sprintf(name, "ESS ES488 AudioDrive (rev %d)", + { + sprintf(name, "ESS ES488 AudioDrive (rev %d)", ess_minor & 0x0f); - hw_config->name = name; - devc->model = MDL_SBPRO; - return 1; - } else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) - { - char *chip = "ES688"; - - if ((ess_minor & 0x0f) >= 8) - chip = "ES1688"; - - sprintf(name, - "ESS %s AudioDrive (rev %d)", - chip, ess_minor & 0x0f); - } else + hw_config->name = name; + devc->model = MDL_SBPRO; + return 1; + } + else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) + { + char *chip = "ES688"; + + if ((ess_minor & 0x0f) >= 8) + chip = "ES1688"; + + sprintf(name,"ESS %s AudioDrive (rev %d)", + chip, ess_minor & 0x0f); + } + else strcpy(name, "Jazz16"); devc->model = MDL_ESS; devc->submodel = ess_minor & 0x0f; - - hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc(strlen(name + 1))); - sound_mem_sizes[sound_nblocks] = strlen(name + 1); - if (sound_nblocks < 1024) - sound_nblocks++;; - if (hw_config->name != NULL) - strcpy(hw_config->name, name); - - + hw_config->name = name; sb_dsp_reset(devc); /* Turn on extended mode */ -/* - * Set IRQ configuration register - */ + /* + * Set IRQ configuration register + */ cfg = 0x50; /* Enable only DMA counter interrupt */ switch (devc->irq) - { - case 2: - case 9: - irq_bits = 0; - break; - - case 5: - irq_bits = 1; - break; - - case 7: - irq_bits = 2; - break; - - case 10: - irq_bits = 3; - break; - - default: - irq_bits = 0; - cfg = 0x10; /* Disable all interrupts */ - printk("\nESS1688: Invalid IRQ %d\n", devc->irq); - return 0; - } + { + case 2: + case 9: + irq_bits = 0; + break; + + case 5: + irq_bits = 1; + break; + + case 7: + irq_bits = 2; + break; + + case 10: + irq_bits = 3; + break; + + default: + irq_bits = 0; + cfg = 0x10; /* Disable all interrupts */ + printk(KERN_ERR "ESS1688: Invalid IRQ %d\n", devc->irq); + return 0; + } if (!ess_write(devc, 0xb1, cfg | (irq_bits << 2))) - printk("\nESS1688: Failed to write to IRQ config register\n"); + printk(KERN_ERR "ESS1688: Failed to write to IRQ config register\n"); -/* - * Set DMA configuration register - */ + /* + * Set DMA configuration register + */ cfg = 0x50; /* Extended mode DMA enable */ if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2) - { - dma_bits = 0; - cfg = 0x00; /* Disable all DMA */ - printk("\nESS1688: Invalid DMA %d\n", devc->dma8); - } else - { - if (devc->dma8 == 3) - dma_bits = 3; - else - dma_bits = devc->dma8 + 1; - } + { + dma_bits = 0; + cfg = 0x00; /* Disable all DMA */ + printk(KERN_ERR "ESS1688: Invalid DMA %d\n", devc->dma8); + } + else + { + if (devc->dma8 == 3) + dma_bits = 3; + else + dma_bits = devc->dma8 + 1; + } if (!ess_write(devc, 0xb2, cfg | (dma_bits << 2))) - printk("\nESS1688: Failed to write to DMA config register\n"); + printk(KERN_ERR "ESS1688: Failed to write to DMA config register\n"); -/* - * Enable joystick and OPL3 - */ + /* + * Enable joystick and OPL3 + */ cfg = sb_getmixer(devc, 0x40); sb_setmixer(devc, 0x40, cfg | 0x03); @@ -623,26 +594,27 @@ return 1; } -int -sb_dsp_detect(struct address_info *hw_config) +int sb_dsp_detect(struct address_info *hw_config) { - sb_devc sb_info; - sb_devc *devc = &sb_info; + sb_devc sb_info; + sb_devc *devc = &sb_info; sb_info.my_mididev = -1; sb_info.my_mixerdev = -1; sb_info.my_dev = -1; -/* - * Initialize variables - */ + + /* + * Initialize variables + */ + DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base)); if (check_region(hw_config->io_base, 16)) - { + { #ifdef MODULE - printk("sb: I/O region in use.\n"); + printk(KERN_INFO "sb: I/O region in use.\n"); #endif - return 0; - } + return 0; + } memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ devc->type = hw_config->card_subtype; @@ -654,24 +626,24 @@ devc->dma16 = -1; if (acer) - { - cli(); - inb(devc->base + 0x09); - inb(devc->base + 0x09); - inb(devc->base + 0x09); - inb(devc->base + 0x0b); - inb(devc->base + 0x09); - inb(devc->base + 0x0b); - inb(devc->base + 0x09); - inb(devc->base + 0x09); - inb(devc->base + 0x0b); - inb(devc->base + 0x09); - inb(devc->base + 0x00); - sti(); - } -/* - * Detect the device - */ + { + cli(); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x09); + inb(devc->base + 0x0b); + inb(devc->base + 0x09); + inb(devc->base + 0x00); + sti(); + } + /* + * Detect the device + */ if (sb_dsp_reset(devc)) dsp_get_vers(devc); @@ -686,36 +658,36 @@ relocate_ess1688(devc); if (!sb_dsp_reset(devc)) - { - DDB(printk("SB reset failed\n")); + { + DDB(printk("SB reset failed\n")); #ifdef MODULE - printk("sb: dsp reset failed.\n"); + printk(KERN_INFO "sb: dsp reset failed.\n"); #endif - return 0; - } + return 0; + } if (devc->major == 0) dsp_get_vers(devc); if (devc->major == 3 && devc->minor == 1) - { - if (devc->type == MDL_AZTECH) /* SG Washington? */ - { - if (sb_dsp_command(devc, 0x09)) - if (sb_dsp_command(devc, 0x00)) /* Enter WSS mode */ - { - int i; - - /* Have some delay */ - for (i = 0; i < 10000; i++) - inb(DSP_DATA_AVAIL); - devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ - devc->model = MDL_AZTECH; - } - } - } -/* - * Save device information for sb_dsp_init() - */ + { + if (devc->type == MDL_AZTECH) /* SG Washington? */ + { + if (sb_dsp_command(devc, 0x09)) + if (sb_dsp_command(devc, 0x00)) /* Enter WSS mode */ + { + int i; + + /* Have some delay */ + for (i = 0; i < 10000; i++) + inb(DSP_DATA_AVAIL); + devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ + devc->model = MDL_AZTECH; + } + } + } + /* + * Save device information for sb_dsp_init() + */ detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(sb_devc))); @@ -724,22 +696,20 @@ sound_nblocks++;; if (detected_devc == NULL) - { - printk(KERN_ERR "sb: Can't allocate memory for device information\n"); - return 0; - } + { + printk(KERN_ERR "sb: Can't allocate memory for device information\n"); + return 0; + } memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc)); - MDB(printk("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base)); return 1; } -void -sb_dsp_init(struct address_info *hw_config) +void sb_dsp_init(struct address_info *hw_config) { - sb_devc *devc; - char name[100]; - extern int sb_be_quiet; + sb_devc *devc; + char name[100]; + extern int sb_be_quiet; /* * Check if we had detected a SB device earlier @@ -748,130 +718,131 @@ name[0] = 0; if (detected_devc == NULL) - { - MDB(printk("No detected device\n")); - return; - } + { + MDB(printk("No detected device\n")); + return; + } devc = detected_devc; detected_devc = NULL; if (devc->base != hw_config->io_base) - { - DDB(printk("I/O port mismatch\n")); - return; - } -/* - * Now continue initialization of the device - */ + { + DDB(printk("I/O port mismatch\n")); + return; + } + /* + * Now continue initialization of the device + */ devc->dev = sound_alloc_audiodev(); if (devc->dev == -1) - { - printk(KERN_WARNING "sb: too many audio devices.\n"); - return; - } + { + printk(KERN_WARNING "sb: too many audio devices.\n"); + return; + } devc->caps = hw_config->driver_use_1; - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && - hw_config->irq > 0) - { /* IRQ setup */ - if (snd_set_irq_handler(hw_config->irq, - sbintr, "soundblaster", devc->osp) < 0) - { - printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); - sound_unload_audiodev(devc->dev); - return; - } - irq2devc[hw_config->irq] = devc; - devc->irq_ok = 0; - - if (devc->major == 4) - if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ - { - snd_release_irq(devc->irq); - sound_unload_audiodev(devc->dev); - irq2devc[hw_config->irq] = NULL; - return; - } - if ((devc->type == 0 || devc->type == MDL_ESS) && - devc->major == 3 && devc->minor == 1) - { /* Handle various chipsets which claim they are SB Pro compatible */ - if ((devc->type != 0 && devc->type != MDL_ESS) || + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && hw_config->irq > 0) + { /* IRQ setup */ + if (snd_set_irq_handler(hw_config->irq, sbintr, "soundblaster", devc->osp) < 0) + { + printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); + sound_unload_audiodev(devc->dev); + return; + } + irq2devc[hw_config->irq] = devc; + devc->irq_ok = 0; + + if (devc->major == 4) + if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ + { + snd_release_irq(devc->irq); + sound_unload_audiodev(devc->dev); + irq2devc[hw_config->irq] = NULL; + return; + } + if ((devc->type == 0 || devc->type == MDL_ESS) && + devc->major == 3 && devc->minor == 1) + { /* Handle various chipsets which claim they are SB Pro compatible */ + if ((devc->type != 0 && devc->type != MDL_ESS) || !ess_init(devc, hw_config)) - if ((devc->type != 0 && devc->type != MDL_JAZZ && + { + if ((devc->type != 0 && devc->type != MDL_JAZZ && devc->type != MDL_SMW) || !init_Jazz16(devc, hw_config)) - { - DDB(printk("This is a genuine SB Pro\n")); - } - } -#if defined(__SMP__) || defined(__FreeBSD__) - /* Skip IRQ detection if SMP (doesn't work) */ - devc->irq_ok = 1; + { + DDB(printk("This is a genuine SB Pro\n")); + } + } + } +#if defined(__SMP__) + /* Skip IRQ detection if SMP (doesn't work) */ + devc->irq_ok = 1; #else - if (devc->major == 4 && devc->minor <= 11) /* Won't work */ - devc->irq_ok = 1; - else - { - int n; - - for (n = 0; n < 3 && devc->irq_ok == 0; n++) - if (sb_dsp_command(devc, 0xf2)) /* Cause interrupt immediately */ - { - int i; - - for (i = 0; !devc->irq_ok && i < 10000; i++); - } - if (!devc->irq_ok) - { - printk("sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); - } else - { - DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq)); - } - - } + if (devc->major == 4 && devc->minor <= 11) /* Won't work */ + devc->irq_ok = 1; + else + { + int n; + + for (n = 0; n < 3 && devc->irq_ok == 0; n++) + { + if (sb_dsp_command(devc, 0xf2)) /* Cause interrupt immediately */ + { + int i; + + for (i = 0; !devc->irq_ok && i < 10000; i++); + } + } + if (!devc->irq_ok) + printk(KERN_WARNING "sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq); + else + { + DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq)); + } + } #endif /* __SMP__ */ - } /* IRQ setup */ + } /* IRQ setup */ request_region(hw_config->io_base, 16, "soundblaster"); switch (devc->major) - { - case 1: /* SB 1.0 or 1.5 */ - devc->model = hw_config->card_subtype = MDL_SB1; - break; - - case 2: /* SB 2.x */ - if (devc->minor == 0) - devc->model = hw_config->card_subtype = MDL_SB2; - else - devc->model = hw_config->card_subtype = MDL_SB201; - break; - - case 3: /* SB Pro and most clones */ - if (devc->model == 0) - { - devc->model = hw_config->card_subtype = MDL_SBPRO; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; - } - break; - - case 4: - devc->model = hw_config->card_subtype = MDL_SB16; - if (hw_config->name == NULL) - hw_config->name = "Sound Blaster 16"; - - if (hw_config->dma2 == -1) - devc->dma16 = devc->dma8; - else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) - { - printk("SB16: Bad or missing 16 bit DMA channel\n"); - devc->dma16 = devc->dma8; - } else - devc->dma16 = hw_config->dma2; - - sb16_set_dma_hw(devc); - devc->caps |= SB_NO_MIDI; - } + { + case 1: /* SB 1.0 or 1.5 */ + devc->model = hw_config->card_subtype = MDL_SB1; + break; + + case 2: /* SB 2.x */ + if (devc->minor == 0) + devc->model = hw_config->card_subtype = MDL_SB2; + else + devc->model = hw_config->card_subtype = MDL_SB201; + break; + + case 3: /* SB Pro and most clones */ + if (devc->model == 0) + { + devc->model = hw_config->card_subtype = MDL_SBPRO; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; + } + break; + + case 4: + devc->model = hw_config->card_subtype = MDL_SB16; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster 16"; + + if (hw_config->dma2 == -1) + devc->dma16 = devc->dma8; + else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) + { + printk(KERN_WARNING "SB16: Bad or missing 16 bit DMA channel\n"); + devc->dma16 = devc->dma8; + } + else + devc->dma16 = hw_config->dma2; + + sb16_set_dma_hw(devc); + devc->caps |= SB_NO_MIDI; + } if (!(devc->caps & SB_NO_MIXER)) if (devc->major == 3 || devc->major == 4) @@ -888,62 +859,63 @@ sprintf(name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); conf_printf(name, hw_config); -/* - * Assuming that a soundcard is Sound Blaster (compatible) is the most common - * configuration error and the mother of all problems. Usually soundcards - * emulate SB Pro but in addition they have a 16 bit native mode which should be - * used in Unix. See Readme.cards for more information about configuring OSS/Free - * properly. - */ + /* + * Assuming that a soundcard is Sound Blaster (compatible) is the most common + * configuration error and the mother of all problems. Usually soundcards + * emulate SB Pro but in addition they have a 16 bit native mode which should be + * used in Unix. See Readme.cards for more information about configuring OSS/Free + * properly. + */ if (devc->model <= MDL_SBPRO) + { if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1 (rare ones may have 3.2). */ - { - printk("This soundcard may not be fully Sound Blaster Pro compatible.\n"); - printk("In many cases there is another way to configure OSS so that\n"); - printk("it works properly with OSS (for example in 16 bit mode).\n"); - printk("Please ignore this message if you _really_ have a SB Pro.\n"); - } else if (!sb_be_quiet && devc->model == MDL_SBPRO) - { - printk("SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); - printk("several years old (8 bit only device)\n"); - printk("or alternatively the sound driver is incorrectly configured.\n"); - } + { + printk(KERN_INFO "This soundcard may not be fully Sound Blaster Pro compatible.\n"); + printk(KERN_INFO "In many cases there is another way to configure OSS so that\n"); + printk(KERN_INFO "it works properly with OSS (for example in 16 bit mode).\n"); + printk(KERN_INFO "Please ignore this message if you _really_ have a SB Pro.\n"); + } + else if (!sb_be_quiet && devc->model == MDL_SBPRO) + { + printk(KERN_INFO "SB DSP version is just %d.%d which means that your card is\n", devc->major, devc->minor); + printk(KERN_INFO "several years old (8 bit only device) or alternatively the sound driver\n"); + printk(KERN_INFO "is incorrectly configured.\n"); + } + } hw_config->card_subtype = devc->model; last_devc = devc; /* For SB MPU detection */ if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0) - { - if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) - { - printk("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); - } - if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) - { - printk("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); - } - sb_audio_init(devc, name); - } else - { - MDB(printk("sb: No audio devices found.\n")); - } + { + if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) + { + printk(KERN_WARNING "SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); + } + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) + { + printk(KERN_WARNING "SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + } + sb_audio_init(devc, name); + } + else + { + MDB(printk("sb: No audio devices found.\n")); + } } -void -sb_dsp_disable_midi(int io_base) +void sb_dsp_disable_midi(int io_base) { } -void -sb_dsp_disable_recording(int io_base) +void sb_dsp_disable_recording(int io_base) { } -void -sb_dsp_unload(struct address_info *hw_config) +void sb_dsp_unload(struct address_info *hw_config) { - sb_devc *devc; - int irq = hw_config->irq; + sb_devc *devc; + int irq = hw_config->irq; if (irq < 0) irq *= -1; @@ -954,36 +926,33 @@ devc = NULL; if (devc && devc->base == hw_config->io_base) - { - release_region(devc->base, 16); + { + release_region(devc->base, 16); - if (!(devc->caps & SB_NO_AUDIO)) - { - sound_free_dma(devc->dma8); - - if (devc->dma16 >= 0) - sound_free_dma(devc->dma16); - } - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && - devc->irq > 0) - { - snd_release_irq(devc->irq); - irq2devc[devc->irq] = NULL; - sound_unload_mixerdev(devc->my_mixerdev); - sound_unload_mididev(devc->my_mididev); - sound_unload_audiodev(devc->my_dev); - } - } else + if (!(devc->caps & SB_NO_AUDIO)) + { + sound_free_dma(devc->dma8); + if (devc->dma16 >= 0) + sound_free_dma(devc->dma16); + } + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0) + { + snd_release_irq(devc->irq); + irq2devc[devc->irq] = NULL; + sound_unload_mixerdev(devc->my_mixerdev); + sound_unload_mididev(devc->my_mididev); + sound_unload_audiodev(devc->my_dev); + } + } + else release_region(hw_config->io_base, 16); - } /* - * Mixer access routines + * Mixer access routines */ -void -sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) +void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) { unsigned long flags; @@ -991,43 +960,38 @@ cli(); outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); + udelay(20); outb(((unsigned char) (value & 0xff)), MIXER_DATA); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); + udelay(20); restore_flags(flags); } -unsigned int -sb_getmixer(sb_devc * devc, unsigned int port) +unsigned int sb_getmixer(sb_devc * devc, unsigned int port) { - unsigned int val; - unsigned long flags; + unsigned int val; + unsigned long flags; save_flags(flags); cli(); outb(((unsigned char) (port & 0xff)), MIXER_ADDR); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); + udelay(20); val = inb(MIXER_DATA); - tenmicrosec(devc->osp); - tenmicrosec(devc->osp); + udelay(20); restore_flags(flags); return val; } #if defined(CONFIG_MIDI) + /* - * MPU401 MIDI initialization. + * MPU401 MIDI initialization. */ -static void -smw_putmem(sb_devc * devc, int base, int addr, unsigned char val) +static void smw_putmem(sb_devc * devc, int base, int addr, unsigned char val) { - unsigned long flags; + unsigned long flags; save_flags(flags); cli(); @@ -1039,11 +1003,10 @@ restore_flags(flags); } -static unsigned char -smw_getmem(sb_devc * devc, int base, int addr) +static unsigned char smw_getmem(sb_devc * devc, int base, int addr) { - unsigned long flags; - unsigned char val; + unsigned long flags; + unsigned char val; save_flags(flags); cli(); @@ -1056,42 +1019,40 @@ return val; } -static int -smw_midi_init(sb_devc * devc, struct address_info *hw_config) +static int smw_midi_init(sb_devc * devc, struct address_info *hw_config) { - int mpu_base = hw_config->io_base; - int mp_base = mpu_base + 4; /* Microcontroller base */ - int i; - unsigned char control; + int mpu_base = hw_config->io_base; + int mp_base = mpu_base + 4; /* Microcontroller base */ + int i; + unsigned char control; /* - * Reset the microcontroller so that the RAM can be accessed + * Reset the microcontroller so that the RAM can be accessed */ control = inb(mpu_base + 7); outb((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */ outb(((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */ - for (i = 0; i < 300; i++) /* Wait at least 1ms */ - tenmicrosec(devc->osp); + udelay(3000); /* Wait at least 1ms */ outb((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */ /* - * Detect microcontroller by probing the 8k RAM area + * Detect microcontroller by probing the 8k RAM area */ smw_putmem(devc, mp_base, 0, 0x00); smw_putmem(devc, mp_base, 1, 0xff); - tenmicrosec(devc->osp); + udelay(10); if (smw_getmem(devc, mp_base, 0) != 0x00 || smw_getmem(devc, mp_base, 1) != 0xff) - { - DDB(printk("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(devc, mp_base, 0), smw_getmem(devc, mp_base, 1))); - return 0; /* No RAM */ - } + { + DDB(printk("SM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(devc, mp_base, 0), smw_getmem(devc, mp_base, 1))); + return 0; /* No RAM */ + } /* - * There is RAM so assume it's really a SM Wave + * There is RAM so assume it's really a SM Wave */ devc->model = MDL_SMW; @@ -1099,179 +1060,173 @@ #ifdef MODULE if (!smw_ucode) - { - extern void *smw_free; + { + extern void *smw_free; - smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); - smw_free = smw_ucode; - } + smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode); + smw_free = smw_ucode; + } #endif if (smw_ucodeLen > 0) - { - if (smw_ucodeLen != 8192) - { - printk("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); - return 1; - } - /* - * Download microcode - */ - - for (i = 0; i < 8192; i++) - smw_putmem(devc, mp_base, i, smw_ucode[i]); - - /* - * Verify microcode - */ - - for (i = 0; i < 8192; i++) - if (smw_getmem(devc, mp_base, i) != smw_ucode[i]) - { - printk("SM Wave: Microcode verification failed\n"); - return 0; - } - } + { + if (smw_ucodeLen != 8192) + { + printk(KERN_ERR "SM Wave: Invalid microcode (MIDI0001.BIN) length\n"); + return 1; + } + /* + * Download microcode + */ + + for (i = 0; i < 8192; i++) + smw_putmem(devc, mp_base, i, smw_ucode[i]); + + /* + * Verify microcode + */ + + for (i = 0; i < 8192; i++) + if (smw_getmem(devc, mp_base, i) != smw_ucode[i]) + { + printk(KERN_ERR "SM Wave: Microcode verification failed\n"); + return 0; + } + } control = 0; #ifdef SMW_SCSI_IRQ /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. + * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt + * is disabled by default. + * + * FIXME - make this a module option + * + * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. */ { - static unsigned char scsi_irq_bits[] = - {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; - + static unsigned char scsi_irq_bits[] = { + 0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0 + }; control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; } #endif #ifdef SMW_OPL4_ENABLE /* - * Make the OPL4 chip visible on the PC bus at 0x380. - * - * There is no need to enable this feature since this driver - * doesn't support OPL4 yet. Also there is no RAM in SM Wave so - * enabling OPL4 is pretty useless. + * Make the OPL4 chip visible on the PC bus at 0x380. + * + * There is no need to enable this feature since this driver + * doesn't support OPL4 yet. Also there is no RAM in SM Wave so + * enabling OPL4 is pretty useless. */ control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ /* control |= 0x20; Uncomment this if you want to use IRQ7 */ #endif - outb((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */ hw_config->name = "SoundMan Wave"; return 1; } -static int -ess_midi_init(sb_devc * devc, struct address_info *hw_config) +static int ess_midi_init(sb_devc * devc, struct address_info *hw_config) { unsigned char cfg, tmp; cfg = sb_getmixer(devc, 0x40) & 0x03; if (devc->submodel < 8) - { - sb_setmixer(devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ - return 0; /* ES688 doesn't support MPU401 mode */ - } + { + sb_setmixer(devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ + return 0; /* ES688 doesn't support MPU401 mode */ + } tmp = (hw_config->io_base & 0x0f0) >> 4; if (tmp > 3) - { - sb_setmixer(devc, 0x40, cfg); - return 0; - } + { + sb_setmixer(devc, 0x40, cfg); + return 0; + } cfg |= tmp << 3; tmp = 1; /* MPU enabled without interrupts */ switch (hw_config->irq) - { - case 9: - tmp = 0x4; - break; - case 5: - tmp = 0x5; - break; - case 7: - tmp = 0x6; - break; - case 10: - tmp = 0x7; - break; - default: - return 0; - } + { + case 9: + tmp = 0x4; + break; + case 5: + tmp = 0x5; + break; + case 7: + tmp = 0x6; + break; + case 10: + tmp = 0x7; + break; + default: + return 0; + } cfg |= tmp << 5; - sb_setmixer(devc, 0x40, cfg | 0x03); return 1; } -static int -init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config) +static int init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config) { - int mpu_base = hw_config->io_base; - int sb_base = devc->base; - int irq = hw_config->irq; + int mpu_base = hw_config->io_base; + int sb_base = devc->base; + int irq = hw_config->irq; - unsigned char bits = 0; - unsigned long flags; + unsigned char bits = 0; + unsigned long flags; if (irq < 0) irq *= -1; if (irq < 1 || irq > 15 || jazz_irq_bits[irq] == 0) - { - printk("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); - return 0; - } + { + printk(KERN_ERR "Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); + return 0; + } switch (sb_base) - { - case 0x220: - bits = 1; - break; - case 0x240: - bits = 2; - break; - case 0x260: - bits = 3; - break; - - default: - return 0; - } - + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + default: + return 0; + } bits = jazz16_bits = bits << 5; - switch (mpu_base) - { - case 0x310: - bits |= 1; - break; - case 0x320: - bits |= 2; - break; - case 0x330: - bits |= 3; - break; - - default: - printk("Jazz16: Invalid MIDI I/O port %x\n", mpu_base); - return 0; - } -/* - * Magic wake up sequence by writing to 0x201 (aka Joystick port) - */ + { + case 0x310: + bits |= 1; + break; + case 0x320: + bits |= 2; + break; + case 0x330: + bits |= 3; + break; + default: + printk(KERN_ERR "Jazz16: Invalid MIDI I/O port %x\n", mpu_base); + return 0; + } + /* + * Magic wake up sequence by writing to 0x201 (aka Joystick port) + */ save_flags(flags); cli(); - outb((0xAF), 0x201); - outb((0x50), 0x201); - outb((bits), 0x201); + outb(0xAF, 0x201); + outb(0x50, 0x201); + outb(bits, 0x201); restore_flags(flags); hw_config->name = "Jazz16"; @@ -1291,19 +1246,17 @@ return 1; } -void -attach_sbmpu(struct address_info *hw_config) +void attach_sbmpu(struct address_info *hw_config) { #if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) attach_uart401(hw_config); #endif } -int -probe_sbmpu(struct address_info *hw_config) +int probe_sbmpu(struct address_info *hw_config) { #if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) - sb_devc *devc = last_devc; + sb_devc *devc = last_devc; if (last_devc == NULL) return 0; @@ -1314,53 +1267,51 @@ return 0; if (check_region(hw_config->io_base, 4)) - { - printk("sbmpu: I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } switch (devc->model) - { - case MDL_SB16: - if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) - { - printk("SB16: Invalid MIDI port %x\n", hw_config->irq); - return 0; - } - hw_config->name = "Sound Blaster 16"; - hw_config->irq = -devc->irq; + { + case MDL_SB16: + if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) + { + printk(KERN_ERR "SB16: Invalid MIDI port %x\n", hw_config->irq); + return 0; + } + hw_config->name = "Sound Blaster 16"; + hw_config->irq = -devc->irq; #if defined(CONFIG_MIDI) && defined(CONFIG_UART401) - if (devc->minor > 12) /* What is Vibra's version??? */ - sb16_set_mpu_port(devc, hw_config); + if (devc->minor > 12) /* What is Vibra's version??? */ + sb16_set_mpu_port(devc, hw_config); #endif - break; + break; - case MDL_ESS: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!ess_midi_init(devc, hw_config)) - return 0; - hw_config->name = "ESS ES1688"; - break; - - case MDL_JAZZ: - if (hw_config->irq < 3 || hw_config->irq == devc->irq) - hw_config->irq = -devc->irq; - if (!init_Jazz16_midi(devc, hw_config)) - return 0; - break; - - default: - return 0; - } + case MDL_ESS: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!ess_midi_init(devc, hw_config)) + return 0; + hw_config->name = "ESS ES1688"; + break; + + case MDL_JAZZ: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!init_Jazz16_midi(devc, hw_config)) + return 0; + break; + default: + return 0; + } return probe_uart401(hw_config); #else return 0; #endif } -void -unload_sbmpu(struct address_info *hw_config) +void unload_sbmpu(struct address_info *hw_config) { #if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) unload_uart401(hw_config); @@ -1368,22 +1319,18 @@ } #else /* !CONFIG_MIDI */ -void -unload_sbmpu(struct address_info *hw_config) +void unload_sbmpu(struct address_info *hw_config) { } -int -probe_sbmpu(struct address_info *hw_config) +int probe_sbmpu(struct address_info *hw_config) { return 0; } -void -attach_sbmpu(struct address_info *hw_config) +void attach_sbmpu(struct address_info *hw_config) { } #endif - #endif diff -u --recursive --new-file v2.1.87/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.87/linux/drivers/sound/sequencer.c Thu Feb 12 20:56:10 1998 +++ linux/drivers/sound/sequencer.c Thu Feb 19 14:46:15 1998 @@ -52,15 +52,7 @@ static int seq_mode = SEQ_1; static struct wait_queue *seq_sleeper = NULL; - -static volatile struct snd_wait seq_sleep_flag = { - 0 -}; - static struct wait_queue *midi_sleeper = NULL; -static volatile struct snd_wait midi_sleep_flag = { - 0 -}; static int midi_opened[MAX_MIDI_DEV] = { 0 @@ -98,7 +90,7 @@ #error Too many synthesizer devices enabled. #endif -int sequencer_read(int dev, struct fileinfo *file, char *buf, int count) +int sequencer_read(int dev, struct file *file, char *buf, int count) { int c = count, p = 0; int ev_len; @@ -113,25 +105,13 @@ if (!iqlen) { - unsigned long tlimit; - if ((file->flags & (O_NONBLOCK) ? 1 : 0)) - { - restore_flags(flags); - return -EAGAIN; - } - if (pre_event_timeout) - current->timeout = tlimit = jiffies + (pre_event_timeout); - else - tlimit = (unsigned long) -1; - midi_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&midi_sleeper); - if (!(midi_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - midi_sleep_flag.opts |= WK_TIMEOUT; - } - midi_sleep_flag.opts &= ~WK_SLEEP; - + if (file->f_flags & O_NONBLOCK) { + restore_flags(flags); + return -EAGAIN; + } + current->timeout = pre_event_timeout ? jiffies + pre_event_timeout : 0; + interruptible_sleep_on(&midi_sleeper); + current->timeout = 0; if (!iqlen) { restore_flags(flags); @@ -180,12 +160,7 @@ memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - - if ((midi_sleep_flag.opts & WK_SLEEP)) - { - midi_sleep_flag.opts = WK_WAKEUP; - wake_up(&midi_sleeper); - } + wake_up(&midi_sleeper); restore_flags(flags); } @@ -243,12 +218,12 @@ seq_copy_to_input(event_rec, len); } -int sequencer_write(int dev, struct fileinfo *file, const char *buf, int count) +int sequencer_write(int dev, struct file *file, const char *buf, int count) { unsigned char event_rec[EV_SZ], ev_code; int p = 0, c, ev_size; int err; - int mode = file->mode & O_ACCMODE; + int mode = translate_mode(file); dev = dev >> 4; @@ -325,7 +300,7 @@ /*printk("Sequencer Error: Nonexistent MIDI device %d\n", dev);*/ return -ENXIO; } - mode = file->mode & O_ACCMODE; + mode = translate_mode(file); if ((err = midi_devs[dev]->open(dev, mode, sequencer_midi_input, sequencer_midi_output)) < 0) @@ -337,14 +312,14 @@ midi_opened[dev] = 1; } } - if (!seq_queue(event_rec, (file->flags & (O_NONBLOCK) ? 1 : 0))) + if (!seq_queue(event_rec, (file->f_flags & (O_NONBLOCK) ? 1 : 0))) { int processed = count - c; if (!seq_playing) seq_startplay(); - if (!processed && (file->flags & (O_NONBLOCK) ? 1 : 0)) + if (!processed && (file->f_flags & O_NONBLOCK)) return -EAGAIN; else return processed; @@ -372,15 +347,12 @@ * Give chance to drain the queue */ - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP)) - { + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !waitqueue_active(&seq_sleeper)) { /* * Sleep until there is enough space on the queue */ - - seq_sleep_flag.opts = WK_SLEEP; + current->timeout = 0; interruptible_sleep_on(&seq_sleeper); - seq_sleep_flag.opts &= ~WK_SLEEP;; } if (qlen >= SEQ_MAX_QUEUE) { @@ -667,20 +639,8 @@ int ret; if ((ret = tmr->event(tmr_no, event_rec)) == TIMER_ARMED) - { if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - } - restore_flags(flags); - } - } + wake_up(&seq_sleeper); return ret; } switch (cmd) @@ -708,18 +668,7 @@ request_sound_timer(time); if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - } - restore_flags(flags); - } + wake_up(&seq_sleeper); return TIMER_ARMED; } break; @@ -847,20 +796,7 @@ request_sound_timer(time); if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; - } - restore_flags(flags); - } + wake_up(&seq_sleeper); /* * The timer is now active and will reinvoke this function * after the timer expires. Return to the caller now. @@ -991,20 +927,7 @@ seq_playing = 0; if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) - { - unsigned long flags; - - save_flags(flags); - cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; - } - restore_flags(flags); - } + wake_up(&seq_sleeper); } static void reset_controllers(int dev, unsigned char *controller, int update_dev) @@ -1048,7 +971,7 @@ seq_mode = SEQ_2; } -int sequencer_open(int dev, struct fileinfo *file) +int sequencer_open(int dev, struct file *file) { int retval, mode, i; int level, tmp; @@ -1060,7 +983,7 @@ level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; dev = dev >> 4; - mode = file->mode & O_ACCMODE; + mode = translate_mode(file); DEB(printk("sequencer_open(dev=%d)\n", dev)); @@ -1187,8 +1110,8 @@ if (seq_mode == SEQ_2) tmr->open(tmr_no, seq_mode); - seq_sleep_flag.opts = WK_NONE; - midi_sleep_flag.opts = WK_NONE; + init_waitqueue(&seq_sleeper); + init_waitqueue(&midi_sleeper); output_threshold = SEQ_MAX_QUEUE / 2; return 0; @@ -1218,27 +1141,18 @@ * Let's have a delay */ - if (n) - { - unsigned long tlimit; - - current->timeout = tlimit = jiffies + (HZ / 10); - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - } + if (n) { + current->timeout = jiffies + HZ / 10; + interruptible_sleep_on(&seq_sleeper); + current->timeout = 0; + } } } -void sequencer_release(int dev, struct fileinfo *file) +void sequencer_release(int dev, struct file *file) { int i; - int mode = file->mode & O_ACCMODE; + int mode = translate_mode(file); dev = dev >> 4; @@ -1248,21 +1162,15 @@ * Wait until the queue is empty (if we don't have nonblock) */ - if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ? 1 : 0)) + if (mode != OPEN_READ && !(file->f_flags & O_NONBLOCK)) { while (!signal_pending(current) && qlen > 0) { - unsigned long tlimit; - seq_sync(); - current->timeout = tlimit = jiffies + (3 * HZ); - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; + seq_sync(); + current->timeout = jiffies + 3 * HZ; + interruptible_sleep_on(&seq_sleeper); + current->timeout = 0; + /* Extra delay */ } } @@ -1313,21 +1221,11 @@ save_flags(flags); cli(); - if (qlen > 0) - { - unsigned long tlimit; - - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - } + if (qlen > 0) { + current->timeout = jiffies + HZ; + interruptible_sleep_on(&seq_sleeper); + current->timeout = 0; + } restore_flags(flags); return qlen; } @@ -1351,21 +1249,12 @@ save_flags(flags); cli(); - while (n && !midi_devs[dev]->outputc(dev, data)) - { - unsigned long tlimit; - - current->timeout = tlimit = jiffies + (4); - seq_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&seq_sleeper); - if (!(seq_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - seq_sleep_flag.opts |= WK_TIMEOUT; - } - seq_sleep_flag.opts &= ~WK_SLEEP; - n--; - } + while (n && !midi_devs[dev]->outputc(dev, data)) { + current->timeout = jiffies + 4; + interruptible_sleep_on(&seq_sleeper); + current->timeout = 0; + n--; + } restore_flags(flags); } @@ -1441,13 +1330,9 @@ save_flags(flags); cli(); - if ((seq_sleep_flag.opts & WK_SLEEP)) - { + if (waitqueue_active(&seq_sleeper)) { /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ - { - seq_sleep_flag.opts = WK_WAKEUP; - wake_up(&seq_sleeper); - }; + wake_up(&seq_sleeper); } restore_flags(flags); } @@ -1473,11 +1358,10 @@ */ } -int sequencer_ioctl(int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg) +int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) { int midi_dev, orig_dev, val, err; - int mode = file->mode & O_ACCMODE; + int mode = translate_mode(file); struct synth_info inf; struct seq_event_rec event_rec; unsigned long flags; @@ -1684,44 +1568,26 @@ return put_user(val, (int *)arg); } -int sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait) { - unsigned long flags; + unsigned long flags; + unsigned int mask = 0; dev = dev >> 4; - switch (sel_type) - { - case SEL_IN: - save_flags(flags); - cli(); - if (!iqlen) - { - midi_sleep_flag.opts = WK_SLEEP; - poll_wait(&midi_sleeper, wait); - restore_flags(flags); - return 0; - } - restore_flags(flags); - return 1; - - case SEL_OUT: - save_flags(flags); - cli(); - if ((SEQ_MAX_QUEUE - qlen) < output_threshold) - { - seq_sleep_flag.opts = WK_SLEEP; - poll_wait(&seq_sleeper, wait); - restore_flags(flags); - return 0; - } - restore_flags(flags); - return 1; - - case SEL_EX: - return 0; - } - return 0; + save_flags(flags); + cli(); + /* input */ + poll_wait(&midi_sleeper, wait); + if (iqlen) + mask |= POLLIN | POLLRDNORM; + + /* output */ + poll_wait(&seq_sleeper, wait); + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + mask |= POLLOUT | POLLWRNORM; + restore_flags(flags); + return mask; } diff -u --recursive --new-file v2.1.87/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.1.87/linux/drivers/sound/softoss.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/softoss.c Thu Feb 19 14:46:15 1998 @@ -762,7 +762,9 @@ case SNDCTL_SYNTH_INFO: softsyn_info.nr_voices = devc->maxvoice; - return __copy_to_user(arg, &softsyn_info, sizeof(softsyn_info)); + if (__copy_to_user(arg, &softsyn_info, sizeof(softsyn_info))) + return -EFAULT; + return 0; case SNDCTL_SEQ_RESETSAMPLES: stop_engine(devc); @@ -992,8 +994,8 @@ return 0; softsynth_disabled = 0; - devc->finfo.mode = OPEN_WRITE; - devc->finfo.flags = 0; + devc->finfo.f_mode = FMODE_WRITE; + devc->finfo.f_flags = 0; if (softoss_dev >= num_audiodevs) softoss_dev = num_audiodevs - 1; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/softoss.h linux/drivers/sound/softoss.h --- v2.1.87/linux/drivers/sound/softoss.h Sun Dec 21 17:41:24 1997 +++ linux/drivers/sound/softoss.h Thu Feb 19 14:46:15 1998 @@ -105,7 +105,7 @@ int bits; int default_max_voices; int max_playahead; - struct fileinfo finfo; + struct file finfo; int fragsize; int samples_per_fragment; diff -u --recursive --new-file v2.1.87/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.1.87/linux/drivers/sound/sound_calls.h Thu Feb 12 20:56:10 1998 +++ linux/drivers/sound/sound_calls.h Thu Feb 19 14:46:15 1998 @@ -22,24 +22,23 @@ int DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap); int DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction); void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap); -int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); +unsigned int DMAbuf_poll(int dev, poll_table *wait); void DMAbuf_start_devices(unsigned int devmask); void DMAbuf_reset (int dev); int DMAbuf_sync (int dev); +unsigned int DMAbuf_poll(int dev, poll_table *wait); /* * System calls for /dev/dsp and /dev/audio (audio.c) */ -int audio_read (int dev, struct fileinfo *file, char *buf, int count); -int audio_write (int dev, struct fileinfo *file, const char *buf, int count); -int audio_open (int dev, struct fileinfo *file); -void audio_release (int dev, struct fileinfo *file); -int audio_ioctl (int dev, struct fileinfo *file, +int audio_read (int dev, struct file *file, char *buf, int count); +int audio_write (int dev, struct file *file, const char *buf, int count); +int audio_open (int dev, struct file *file); +void audio_release (int dev, struct file *file); +int audio_ioctl (int dev, struct file *file, unsigned int cmd, caddr_t arg); void audio_init_devices (void); - -int audio_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); void reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording); int dma_ioctl (int dev, unsigned int cmd, caddr_t arg); @@ -47,13 +46,12 @@ * System calls for the /dev/sequencer */ -int sequencer_read (int dev, struct fileinfo *file, char *buf, int count); -int sequencer_write (int dev, struct fileinfo *file, const char *buf, int count); -int sequencer_open (int dev, struct fileinfo *file); -void sequencer_release (int dev, struct fileinfo *file); -int sequencer_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg); -int sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); +int sequencer_read (int dev, struct file *file, char *buf, int count); +int sequencer_write (int dev, struct file *file, const char *buf, int count); +int sequencer_open (int dev, struct file *file); +void sequencer_release (int dev, struct file *file); +int sequencer_ioctl (int dev, struct file *file, unsigned int cmd, caddr_t arg); +unsigned int sequencer_poll(int dev, struct file *file, poll_table * wait); void sequencer_init (void); void sequencer_unload (void); @@ -68,13 +66,12 @@ * System calls for the /dev/midi */ -int MIDIbuf_read (int dev, struct fileinfo *file, char *buf, int count); -int MIDIbuf_write (int dev, struct fileinfo *file, const char *buf, int count); -int MIDIbuf_open (int dev, struct fileinfo *file); -void MIDIbuf_release (int dev, struct fileinfo *file); -int MIDIbuf_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, caddr_t arg); -int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); +int MIDIbuf_read (int dev, struct file *file, char *buf, int count); +int MIDIbuf_write (int dev, struct file *file, const char *buf, int count); +int MIDIbuf_open (int dev, struct file *file); +void MIDIbuf_release (int dev, struct file *file); +int MIDIbuf_ioctl (int dev, struct file *file, unsigned int cmd, caddr_t arg); +unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait); int MIDIbuf_avail(int dev); void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); @@ -86,9 +83,6 @@ */ /* From soundcard.c */ -#if !defined(__bsdi__) && !defined(__NjetBSD__) -void tenmicrosec(int *osp); -#endif void request_sound_timer (int count); void sound_stop_timer(void); int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp); diff -u --recursive --new-file v2.1.87/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v2.1.87/linux/drivers/sound/sound_config.h Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/sound_config.h Thu Feb 19 14:46:15 1998 @@ -10,7 +10,7 @@ * for more info. */ - +#include #include "local.h.master" #include #include "os.h" @@ -18,9 +18,6 @@ - - - #ifndef SND_DEFAULT_ENABLE #define SND_DEFAULT_ENABLE 1 #endif @@ -91,21 +88,12 @@ #define DSP_DEFAULT_SPEED 8000 -#define ON 1 -#define OFF 0 - #define MAX_AUDIO_DEV 5 #define MAX_MIXER_DEV 5 #define MAX_SYNTH_DEV 5 #define MAX_MIDI_DEV 6 #define MAX_TIMER_DEV 4 -struct fileinfo { - int mode; /* Open mode */ - int flags; - int dummy; /* Reference to file-flags. OS-dependent. */ - }; - struct address_info { int io_base; int irq; @@ -154,6 +142,24 @@ #define OPEN_WRITE PCM_ENABLE_OUTPUT #define OPEN_READWRITE (OPEN_READ|OPEN_WRITE) +#if OPEN_READ == FMODE_READ && OPEN_WRITE == FMODE_WRITE + +extern __inline__ int translate_mode(struct file *file) +{ + return file->f_mode; +} + +#else + +extern __inline__ int translate_mode(struct file *file) +{ + return ((file->f_mode & FMODE_READ) ? OPEN_READ : 0) | + ((file->f_mode & FMODE_WRITE) ? OPEN_WRITE : 0); +} + +#endif + + #include "sound_calls.h" #include "dev_table.h" @@ -175,7 +181,3 @@ #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 - - - - diff -u --recursive --new-file v2.1.87/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.1.87/linux/drivers/sound/sound_timer.c Thu Feb 12 20:56:10 1998 +++ linux/drivers/sound/sound_timer.c Thu Feb 19 14:46:15 1998 @@ -239,9 +239,6 @@ break; case SNDCTL_TMR_METRONOME: - /* NOP */ - break; - default: return -EINVAL; } diff -u --recursive --new-file v2.1.87/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.87/linux/drivers/sound/soundcard.c Thu Feb 12 20:56:10 1998 +++ linux/drivers/sound/soundcard.c Thu Feb 19 14:46:15 1998 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #ifdef __KERNEL__ #include #include @@ -60,8 +62,6 @@ static int soundcard_configured = 0; -static struct fileinfo files[SND_NDEVS]; - static char dma_alloc_map[8] = {0}; @@ -118,7 +118,9 @@ if (__copy_from_user(&buf, arg, sizeof(buf))) return -EFAULT; load_mixer_volumes(buf.name, buf.levels, 0); - return __copy_to_user(arg, &buf, sizeof(buf)); + if (__copy_to_user(arg, &buf, sizeof(buf))) + return -EFAULT; + return 0; } static int get_mixer_levels(caddr_t arg) @@ -129,7 +131,9 @@ return -EFAULT; if (n < 0 || n >= num_mixer_volumes) return -EINVAL; - return __copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table)); + if (__copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table))) + return -EFAULT; + return 0; } static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length, int inout) @@ -351,7 +355,6 @@ { int dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { case SND_DEV_STATUS: @@ -361,18 +364,18 @@ case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return audio_read(dev, &files[dev], buf, count); + return audio_read(dev, file, buf, count); #endif #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - return sequencer_read(dev, &files[dev], buf, count); + return sequencer_read(dev, file, buf, count); #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - return MIDIbuf_read(dev, &files[dev], buf, count); + return MIDIbuf_read(dev, file, buf, count); #endif default:; @@ -384,25 +387,24 @@ { int dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - return sequencer_write(dev, &files[dev], buf, count); + return sequencer_write(dev, file, buf, count); #endif #ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return audio_write(dev, &files[dev], buf, count); + return audio_write(dev, file, buf, count); #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - return MIDIbuf_write(dev, &files[dev], buf, count); + return MIDIbuf_write(dev, file, buf, count); #endif } return -EINVAL; @@ -416,7 +418,6 @@ static int sound_open(struct inode *inode, struct file *file) { int dev, retval; - struct fileinfo tmp_file; if (is_unloading) { /* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/ @@ -427,15 +428,6 @@ /* printk("SoundCard Error: The soundcard system has not been configured\n");*/ return -ENXIO; } - tmp_file.mode = 0; - tmp_file.flags = file->f_flags; - - if ((tmp_file.flags & O_ACCMODE) == O_RDWR) - tmp_file.mode = OPEN_READWRITE; - if ((tmp_file.flags & O_ACCMODE) == O_RDONLY) - tmp_file.mode = OPEN_READ; - if ((tmp_file.flags & O_ACCMODE) == O_WRONLY) - tmp_file.mode = OPEN_WRITE; DEB(printk("sound_open(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) { printk(KERN_ERR "Invalid minor device %d\n", dev); @@ -446,21 +438,29 @@ break; case SND_DEV_CTL: - if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) + dev >>= 4; +#ifdef CONFIG_KERNELD + if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { + char modname[20]; + sprintf(modname, "mixer%d", dev); + request_module(modname); + } +#endif + if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) return -ENXIO; break; #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - if ((retval = sequencer_open(dev, &tmp_file)) < 0) + if ((retval = sequencer_open(dev, file)) < 0) return retval; break; #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - if ((retval = MIDIbuf_open(dev, &tmp_file)) < 0) + if ((retval = MIDIbuf_open(dev, file)) < 0) return retval; break; #endif @@ -469,7 +469,7 @@ case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - if ((retval = audio_open(dev, &tmp_file)) < 0) + if ((retval = audio_open(dev, file)) < 0) return retval; break; #endif @@ -482,7 +482,6 @@ #ifdef MODULE SOUND_INC_USE_COUNT; #endif - memcpy(&files[dev], &tmp_file, sizeof(tmp_file)); return 0; } @@ -490,7 +489,6 @@ { int dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_STATUS: @@ -500,13 +498,13 @@ #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - sequencer_release(dev, &files[dev]); + sequencer_release(dev, file); break; #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - MIDIbuf_release(dev, &files[dev]); + MIDIbuf_release(dev, file); break; #endif @@ -514,7 +512,7 @@ case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - audio_release(dev, &files[dev]); + audio_release(dev, file); break; #endif @@ -531,14 +529,10 @@ static int get_mixer_info(int dev, caddr_t arg) { mixer_info info; - int i; - if (dev < 0 || dev >= num_mixers) - return -ENXIO; - strcpy(info.id, mixer_devs[dev]->id); - for (i = 0; i < 32 && mixer_devs[dev]->name; i++) - info.name[i] = mixer_devs[dev]->name[i]; - info.name[i] = 0; + strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); + strncpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); + info.name[sizeof(info.name)-1] = 0; info.modify_counter = mixer_devs[dev]->modify_counter; if (__copy_to_user(arg, &info, sizeof(info))) return -EFAULT; @@ -548,21 +542,29 @@ static int get_old_mixer_info(int dev, caddr_t arg) { _old_mixer_info info; - int i; - if (dev < 0 || dev >= num_mixers) - return -ENXIO; - strcpy(info.id, mixer_devs[dev]->id); - for (i = 0; i < 32 && mixer_devs[dev]->name; i++) - info.name[i] = mixer_devs[dev]->name[i]; - info.name[i] = 0; - if (__copy_to_user(arg, &info, sizeof(info))) + strncpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); + strncpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); + info.name[sizeof(info.name)-1] = 0; + if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; return 0; } static int sound_mixer_ioctl(int mixdev, unsigned int cmd, caddr_t arg) { + if (mixdev < 0 || mixdev >= MAX_MIXER_DEV) + return -ENXIO; +#ifdef CONFIG_KERNELD + /* Try to load the mixer... */ + if (mixer_devs[mixdev] == NULL) { + char modname[20]; + sprintf(modname, "mixer%d", mixdev); + request_module(modname); + } +#endif /* CONFIG_KERNELD */ + if (mixdev >= num_mixers || !mixer_devs[mixdev]) + return -ENXIO; if (cmd == SOUND_MIXER_INFO) return get_mixer_info(mixdev, arg); if (cmd == SOUND_OLD_MIXER_INFO) @@ -577,10 +579,9 @@ static int sound_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int err, len = 0, dtype, mixdev; + int err, len = 0, dtype; int dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { /* * Have to validate the address given by the process. @@ -599,55 +600,47 @@ if (cmd == OSS_GETVERSION) return __put_user(SOUND_VERSION, (int *)arg); - if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ - if ((dev & 0x0f) != SND_DEV_CTL) { - dtype = dev & 0x0f; - switch (dtype) { + if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ + (dev & 0x0f) != SND_DEV_CTL) { + dtype = dev & 0x0f; + switch (dtype) { #ifdef CONFIG_AUDIO - case SND_DEV_DSP: - case SND_DEV_DSP16: - case SND_DEV_AUDIO: - mixdev = audio_devs[dev >> 4]->mixer_dev; - if (mixdev < 0 || mixdev >= num_mixers) - return -ENXIO; - return sound_mixer_ioctl(mixdev, cmd, (caddr_t)arg); -#endif - - default: - return sound_mixer_ioctl(dev, cmd, (caddr_t)arg); - } + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, + cmd, (caddr_t)arg); +#endif + + default: + return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg); } + } switch (dev & 0x0f) { case SND_DEV_CTL: if (cmd == SOUND_MIXER_GETLEVELS) return get_mixer_levels((caddr_t)arg); if (cmd == SOUND_MIXER_SETLEVELS) return set_mixer_levels((caddr_t)arg); - if (!num_mixers) - return -ENXIO; - dev = dev >> 4; - if (dev >= num_mixers) - return -ENXIO; - return sound_mixer_ioctl(dev, cmd, (caddr_t)arg); - break; + return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg); #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - return sequencer_ioctl(dev, &files[dev], cmd, (caddr_t)arg); + return sequencer_ioctl(dev, file, cmd, (caddr_t)arg); #endif #ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return audio_ioctl(dev, &files[dev], cmd, (caddr_t)arg); + return audio_ioctl(dev, file, cmd, (caddr_t)arg); break; #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - return MIDIbuf_ioctl(dev, &files[dev], cmd, (caddr_t)arg); + return MIDIbuf_ioctl(dev, file, cmd, (caddr_t)arg); break; #endif @@ -655,47 +648,34 @@ return -EINVAL; } -static int sound_select(struct inode *inode, struct file *file, int sel_type, poll_table * wait) +static unsigned int sound_poll(struct file *file, poll_table * wait) { + struct inode *inode = file->f_dentry->d_inode; int dev = MINOR(inode->i_rdev); - files[dev].flags = file->f_flags; - DEB(printk("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); + DEB(printk("sound_poll(dev=%d)\n", dev)); switch (dev & 0x0f) { #if defined(CONFIG_SEQUENCER) || defined(MODULE) case SND_DEV_SEQ: case SND_DEV_SEQ2: - return sequencer_select(dev, &files[dev], sel_type, wait); + return sequencer_poll(dev, file, wait); #endif #if defined(CONFIG_MIDI) case SND_DEV_MIDIN: - return MIDIbuf_select(dev, &files[dev], sel_type, wait); + return MIDIbuf_poll(dev, file, wait); #endif #if defined(CONFIG_AUDIO) || defined(MODULE) case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait); + return DMAbuf_poll(dev >> 4, wait); #endif } return 0; } -static unsigned int sound_poll(struct file *file, poll_table * wait) -{ - struct inode *inode; - int ret = 0; - - inode = file->f_dentry->d_inode; - if (sound_select(inode, file, SEL_IN, wait)) - ret |= POLLIN; - if (sound_select(inode, file, SEL_OUT, wait)) - ret |= POLLOUT; - return ret; -} - static int sound_mmap(struct file *file, struct vm_area_struct *vma) { int dev_class; @@ -703,8 +683,6 @@ struct dma_buffparms *dmap = NULL; int dev = MINOR(file->f_dentry->d_inode->i_rdev); - files[dev].flags = file->f_flags; - dev_class = dev & 0x0f; dev >>= 4; @@ -832,8 +810,6 @@ #endif -static int debugmem = 0; /* switched off by default */ - static int sound[20] = {0}; @@ -918,11 +894,6 @@ } #endif -void tenmicrosec(int *osp) -{ - udelay(10); -} - int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) { int retcode; @@ -1053,143 +1024,6 @@ } #endif -#ifdef CONFIG_AUDIO - -static int dma_buffsize = DSP_BUFFSIZE; - -int sound_alloc_dmap(int dev, struct dma_buffparms *dmap, int chan) -{ - char *start_addr, *end_addr; - int i, dma_pagesize; - - dmap->mapping_flags &= ~DMA_MAP_MAPPED; - - if (dmap->raw_buf != NULL) - return 0; /* Already done */ - - if (dma_buffsize < 4096) - dma_buffsize = 4096; - - if (chan < 4) - dma_pagesize = 64 * 1024; - else - dma_pagesize = 128 * 1024; - - dmap->raw_buf = NULL; - - dmap->buffsize = dma_buffsize; - - if (dmap->buffsize > dma_pagesize) - dmap->buffsize = dma_pagesize; - - start_addr = NULL; - -/* - * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. Don't accept smaller than 8k buffer for performance - * reasons. - */ - - while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) - { - int sz, size; - - for (sz = 0, size = PAGE_SIZE; - size < dmap->buffsize; - sz++, size <<= 1); - - dmap->buffsize = PAGE_SIZE * (1 << sz); - - if ((start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz)) == NULL) - dmap->buffsize /= 2; - } - - if (start_addr == NULL) - { - printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n"); - return -ENOMEM; - } - else - { - /* make some checks */ - end_addr = start_addr + dmap->buffsize - 1; - - if (debugmem) - printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); - - /* now check if it fits into the same dma-pagesize */ - - if (((long) start_addr & ~(dma_pagesize - 1)) - != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) - { - printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); - return -EFAULT; - } - } - dmap->raw_buf = start_addr; - dmap->raw_buf_phys = virt_to_bus(start_addr); - - for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) - { - set_bit(PG_reserved, &mem_map[i].flags);; - } - - return 0; -} - -void sound_free_dmap(int dev, struct dma_buffparms *dmap, int chan) -{ - int sz, size, i; - unsigned long start_addr, end_addr; - - if (dmap->raw_buf == NULL) - return; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return; /* Don't free mmapped buffer. Will use it next time */ - - for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); - - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + dmap->buffsize; - - for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) - { - clear_bit(PG_reserved, &mem_map[i].flags);; - } - - free_pages((unsigned long) dmap->raw_buf, sz); - dmap->raw_buf = NULL; -} - - -/* Intel version !!!!!!!!! */ - -int sound_start_dma(int dev, struct dma_buffparms *dmap, int chan, - unsigned long physaddr, - int count, int dma_mode, int autoinit) -{ - unsigned long flags; - - /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - if (autoinit) - dma_mode |= DMA_AUTOINIT; - save_flags(flags); - cli(); - disable_dma(chan); - clear_dma_ff(chan); - set_dma_mode(chan, dma_mode); - set_dma_addr(chan, physaddr); - set_dma_count(chan, count); - enable_dma(chan); - restore_flags(flags); - - return 0; -} - -#endif - void conf_printf(char *name, struct address_info *hw_config) { if (!trace_init) @@ -1258,4 +1092,3 @@ ct++; } } - diff -u --recursive --new-file v2.1.87/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.1.87/linux/drivers/sound/sscape.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/sscape.c Thu Feb 19 14:46:15 1998 @@ -22,7 +22,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_SSCAPEHW) || defined(MODULE) +#if defined(CONFIG_SSCAPE) || defined(MODULE) #include "coproc.h" @@ -101,11 +101,6 @@ static struct sscape_info *devc = &adev_info; static int sscape_mididev = -1; -static struct wait_queue *sscape_sleeper = NULL; -static volatile struct snd_wait sscape_sleep_flag = { - 0 -}; - /* Some older cards have assigned interrupt bits differently than new ones */ static char valid_interrupts_old[] = { 9, 7, 5, 15 @@ -127,6 +122,14 @@ static char old_hardware = 0; #endif +static void sleep(unsigned howlong) +{ + current->timeout = jiffies + 1; + current->state = TASK_INTERRUPTIBLE; + schedule(); + current->timeout = 0; +} + static unsigned char sscape_read(struct sscape_info *devc, int reg) { unsigned long flags; @@ -317,7 +320,6 @@ if (!verify_mpu(devc)) return -EIO; } - sscape_sleep_flag.opts = WK_NONE; return 0; } @@ -333,7 +335,6 @@ sscape_write(devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ devc->dma_allocated = 0; } - sscape_sleep_flag.opts = WK_NONE; restore_flags(flags); return; } @@ -398,27 +399,17 @@ * Wait until transfer completes. */ - sscape_sleep_flag.opts = WK_NONE; done = 0; timeout_val = 30; while (!done && timeout_val-- > 0) { int resid; - unsigned long tlimit; - current->timeout = tlimit = jiffies + (HZ / 50); - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; + + if (HZ / 50) + sleep(HZ / 50); clear_dma_ff(devc->dma); if ((resid = get_dma_residue(devc->dma)) == 0) - { done = 1; - } } restore_flags(flags); @@ -448,18 +439,8 @@ while (!done && timeout_val-- > 0) { unsigned char x; - unsigned long tlimit; - - current->timeout = tlimit = jiffies + 1; - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; + sleep(1); x = inb(PORT(HOST_DATA)); if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ { @@ -481,16 +462,7 @@ timeout_val = 5 * HZ; while (!done && timeout_val-- > 0) { - unsigned long tlimit; - current->timeout = tlimit = jiffies + (1); - sscape_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&sscape_sleeper); - if (!(sscape_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - sscape_sleep_flag.opts |= WK_TIMEOUT; - } - sscape_sleep_flag.opts &= ~WK_SLEEP; + sleep(1); if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ done = 1; } diff -u --recursive --new-file v2.1.87/linux/drivers/video/dn_fb.c linux/drivers/video/dn_fb.c --- v2.1.87/linux/drivers/video/dn_fb.c Mon Nov 24 01:18:53 1997 +++ linux/drivers/video/dn_fb.c Fri Feb 20 18:28:22 1998 @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c --- v2.1.87/linux/drivers/video/fbcon-afb.c Tue Sep 16 02:29:29 1997 +++ linux/drivers/video/fbcon-afb.c Fri Feb 20 18:28:22 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c --- v2.1.87/linux/drivers/video/fbcon-cfb16.c Tue Sep 16 02:29:31 1997 +++ linux/drivers/video/fbcon-cfb16.c Fri Feb 20 18:28:22 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c --- v2.1.87/linux/drivers/video/fbcon-cfb8.c Tue Sep 16 02:29:34 1997 +++ linux/drivers/video/fbcon-cfb8.c Fri Feb 20 18:28:22 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-cyber.c linux/drivers/video/fbcon-cyber.c --- v2.1.87/linux/drivers/video/fbcon-cyber.c Tue Sep 16 02:29:36 1997 +++ linux/drivers/video/fbcon-cyber.c Fri Feb 20 18:28:22 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c --- v2.1.87/linux/drivers/video/fbcon-ilbm.c Tue Sep 16 02:29:39 1997 +++ linux/drivers/video/fbcon-ilbm.c Fri Feb 20 18:28:22 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c --- v2.1.87/linux/drivers/video/fbcon-iplan2p2.c Mon Nov 24 01:18:54 1997 +++ linux/drivers/video/fbcon-iplan2p2.c Fri Feb 20 18:28:22 1998 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c --- v2.1.87/linux/drivers/video/fbcon-iplan2p4.c Mon Nov 24 01:18:55 1997 +++ linux/drivers/video/fbcon-iplan2p4.c Fri Feb 20 18:28:22 1998 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c --- v2.1.87/linux/drivers/video/fbcon-iplan2p8.c Mon Nov 24 01:18:56 1997 +++ linux/drivers/video/fbcon-iplan2p8.c Fri Feb 20 18:28:23 1998 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c --- v2.1.87/linux/drivers/video/fbcon-mfb.c Mon Nov 10 05:20:37 1997 +++ linux/drivers/video/fbcon-mfb.c Fri Feb 20 18:28:23 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fbcon-retz3.c linux/drivers/video/fbcon-retz3.c --- v2.1.87/linux/drivers/video/fbcon-retz3.c Tue Sep 16 02:29:50 1997 +++ linux/drivers/video/fbcon-retz3.c Fri Feb 20 18:28:23 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.87/linux/drivers/video/fonts.c linux/drivers/video/fonts.c --- v2.1.87/linux/drivers/video/fonts.c Mon Nov 24 01:18:58 1997 +++ linux/drivers/video/fonts.c Fri Feb 20 18:28:23 1998 @@ -9,6 +9,7 @@ */ +#include /* for CONFIG_AMIGA */ #include #include #ifdef __mc68000__ diff -u --recursive --new-file v2.1.87/linux/fs/adfs/super.c linux/fs/adfs/super.c --- v2.1.87/linux/fs/adfs/super.c Tue Feb 17 13:12:47 1998 +++ linux/fs/adfs/super.c Thu Feb 19 14:46:15 1998 @@ -331,7 +331,7 @@ #ifdef MODULE int init_module (void) { - return (init_adfs_fs()); + return init_adfs_fs(); } void cleanup_module (void) diff -u --recursive --new-file v2.1.87/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.87/linux/fs/buffer.c Thu Jan 15 21:01:04 1998 +++ linux/fs/buffer.c Thu Feb 19 01:09:47 1998 @@ -52,10 +52,14 @@ #define NR_RESERVED (2*MAX_BUF_PER_PAGE) #define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this number of unused buffer heads */ -#define HASH_PAGES 4 /* number of pages to use for the hash table */ -#define HASH_PAGES_ORDER 2 -#define NR_HASH (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *)) -#define HASH_MASK (NR_HASH-1) + +/* + * How large a hash table do we need? + */ +#define HASH_PAGES_ORDER 4 +#define HASH_PAGES (1UL << HASH_PAGES_ORDER) +#define NR_HASH (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *)) +#define HASH_MASK (NR_HASH-1) static int grow_buffers(int pri, int size); diff -u --recursive --new-file v2.1.87/linux/fs/coda/psdev.c linux/fs/coda/psdev.c --- v2.1.87/linux/fs/coda/psdev.c Tue Jan 6 10:00:21 1998 +++ linux/fs/coda/psdev.c Fri Feb 20 18:28:23 1998 @@ -17,6 +17,7 @@ * Copyright (c) 1997 Carnegie-Mellon University */ +#include /* for CONFIG_PROC_FS */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/coda/super.c linux/fs/coda/super.c --- v2.1.87/linux/fs/coda/super.c Thu Feb 12 20:56:11 1998 +++ linux/fs/coda/super.c Fri Feb 20 18:28:23 1998 @@ -9,7 +9,6 @@ */ #define __NO_VERSION__ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c --- v2.1.87/linux/fs/coda/sysctl.c Sun Dec 21 14:45:14 1997 +++ linux/fs/coda/sysctl.c Fri Feb 20 18:28:23 1998 @@ -8,7 +8,6 @@ */ /* sysctl entries for Coda! */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.1.87/linux/fs/ext2/namei.c Thu Feb 12 20:56:12 1998 +++ linux/fs/ext2/namei.c Fri Feb 20 15:08:37 1998 @@ -853,9 +853,7 @@ struct ext2_dir_entry * old_de, * new_de; int retval; - old_inode = new_inode = NULL; old_bh = new_bh = dir_bh = NULL; - new_de = NULL; retval = -ENAMETOOLONG; if (old_dentry->d_name.len > EXT2_NAME_LEN) goto end_rename; @@ -875,7 +873,8 @@ goto end_rename; new_inode = new_dentry->d_inode; - new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de); + new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name, + new_dentry->d_name.len, &new_de); if (new_bh) { if (!new_inode) { brelse (new_bh); @@ -895,6 +894,9 @@ retval = -EINVAL; if (is_subdir(new_dentry, old_dentry)) goto end_rename; + /* Prune any children before testing for busy */ + if (new_dentry->d_count > 1) + shrink_dcache_parent(new_dentry); retval = -ENOTEMPTY; if (!empty_dir (new_inode)) goto end_rename; @@ -927,11 +929,13 @@ if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX) goto end_rename; } - if (!new_bh) - new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de, - &retval); - if (!new_bh) - goto end_rename; + if (!new_bh) { + new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name, + new_dentry->d_name.len, &new_de, + &retval); + if (!new_bh) + goto end_rename; + } new_dir->i_version = ++event; /* @@ -975,6 +979,7 @@ /* Update the dcache */ d_move(old_dentry, new_dentry); retval = 0; + end_rename: brelse (dir_bh); brelse (old_bh); diff -u --recursive --new-file v2.1.87/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c --- v2.1.87/linux/fs/fat/fatfs_syms.c Thu Jan 8 14:02:41 1998 +++ linux/fs/fat/fatfs_syms.c Fri Feb 20 18:28:23 1998 @@ -6,7 +6,6 @@ */ #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/hfs/super.c linux/fs/hfs/super.c --- v2.1.87/linux/fs/hfs/super.c Mon Jan 12 14:46:24 1998 +++ linux/fs/hfs/super.c Fri Feb 20 18:28:23 1998 @@ -27,6 +27,7 @@ #include #include +#include /* for CONFIG_MAC_PARTITION */ #include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/locks.c linux/fs/locks.c --- v2.1.87/linux/fs/locks.c Tue Dec 2 22:20:18 1997 +++ linux/fs/locks.c Fri Feb 20 15:04:45 1998 @@ -441,30 +441,32 @@ return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); } -/* This function is called when the file is closed. +/* + * This function is called when the file is being removed + * from the task's fd array. */ -void locks_remove_locks(struct task_struct *task, struct file *filp) +void locks_remove_posix(struct task_struct *task, struct file *filp) { + struct inode * inode = filp->f_dentry->d_inode; struct file_lock file_lock, *fl; struct file_lock **before; - struct inode * inode; - /* For POSIX locks we free all locks on this file for the given task. - * For FLOCK we only free locks on this *open* file if it is the last - * close on that file. + /* + * For POSIX locks we free all locks on this file for the given task. */ - inode = filp->f_dentry->d_inode; repeat: before = &inode->i_flock; while ((fl = *before) != NULL) { - if (((fl->fl_flags & FL_POSIX) && (fl->fl_owner == task)) || - ((fl->fl_flags & FL_FLOCK) && (fl->fl_file == filp) && - (filp->f_count == 1))) { - file_lock = *fl; - locks_delete_lock(before, 0); - if (filp->f_op->lock) { + if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == task) { + int (*lock)(struct file *, int, struct file_lock *); + lock = filp->f_op->lock; + if (lock) { + file_lock = *fl; file_lock.fl_type = F_UNLCK; - filp->f_op->lock(filp, F_SETLK, &file_lock); + } + locks_delete_lock(before, 0); + if (lock) { + lock(filp, F_SETLK, &file_lock); /* List may have changed: */ goto repeat; } @@ -472,8 +474,37 @@ } before = &fl->fl_next; } +} - return; +/* + * This function is called on the last close of an open file. + */ +void locks_remove_flock(struct file *filp) +{ + struct inode * inode = filp->f_dentry->d_inode; + struct file_lock file_lock, *fl; + struct file_lock **before; + +repeat: + before = &inode->i_flock; + while ((fl = *before) != NULL) { + if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) { + int (*lock)(struct file *, int, struct file_lock *); + lock = filp->f_op->lock; + if (lock) { + file_lock = *fl; + file_lock.fl_type = F_UNLCK; + } + locks_delete_lock(before, 0); + if (lock) { + lock(filp, F_SETLK, &file_lock); + /* List may have changed: */ + goto repeat; + } + continue; + } + before = &fl->fl_next; + } } struct file_lock * diff -u --recursive --new-file v2.1.87/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c --- v2.1.87/linux/fs/msdos/msdosfs_syms.c Mon Jun 16 16:35:57 1997 +++ linux/fs/msdos/msdosfs_syms.c Fri Feb 20 18:28:23 1998 @@ -5,7 +5,6 @@ * These symbols are used by umsdos. */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/ntfs/support.c linux/fs/ntfs/support.c --- v2.1.87/linux/fs/ntfs/support.c Fri Jan 2 01:42:59 1998 +++ linux/fs/ntfs/support.c Fri Feb 20 18:28:23 1998 @@ -7,9 +7,6 @@ * */ -#ifdef NTFS_IN_LINUX_KERNEL -#include -#endif #include "types.h" #include "struct.h" #include "support.h" diff -u --recursive --new-file v2.1.87/linux/fs/open.c linux/fs/open.c --- v2.1.87/linux/fs/open.c Fri Jan 23 18:10:32 1998 +++ linux/fs/open.c Fri Feb 20 15:04:45 1998 @@ -745,17 +745,14 @@ int close_fp(struct file *filp) { - struct dentry *dentry; - struct inode *inode; + struct dentry *dentry = filp->f_dentry; if (filp->f_count == 0) { printk("VFS: Close: file count is 0\n"); return 0; } - dentry = filp->f_dentry; - inode = dentry->d_inode; - if (inode) - locks_remove_locks(current, filp); + if (dentry->d_inode) + locks_remove_posix(current, filp); return fput(filp); } diff -u --recursive --new-file v2.1.87/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.1.87/linux/fs/romfs/inode.c Sun Jan 4 00:53:43 1998 +++ linux/fs/romfs/inode.c Fri Feb 20 18:28:23 1998 @@ -48,7 +48,6 @@ * to squeeze some more bytes out of this code.. :) */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.1.87/linux/fs/sysv/inode.c Wed Feb 4 11:36:01 1998 +++ linux/fs/sysv/inode.c Fri Feb 20 18:28:23 1998 @@ -20,7 +20,6 @@ * the superblock. */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c --- v2.1.87/linux/fs/ufs/ufs_super.c Tue Feb 17 13:12:48 1998 +++ linux/fs/ufs/ufs_super.c Fri Feb 20 18:28:23 1998 @@ -32,7 +32,6 @@ /*#define DEBUG_UFS_SUPER 1*/ /* Uncomment the line above when hacking ufs superblock code */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt --- v2.1.87/linux/fs/umsdos/README-WIP.txt Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/README-WIP.txt Fri Feb 20 09:44:57 1998 @@ -1,7 +1,14 @@ Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing (started by Peter T. Waltenberg ) -Current status (980211) - UMSDOS dentry-WIP-Beta 0.82: +--------- WARNING --------- WARNING --------- WARNING ----------- +THIS IS TRULY EXPERIMENTAL. IT IS NOT BETA YET. PLEASE EXCUSE MY +YELLING, BUT ANY USE OF THIS MODULES MAY VERY WELL DESTROY YOUR +UMSDOS FILESYSTEM, AND MAYBE EVEN OTHER FILESYSTEMS IN USE. +YOU'VE BEEN WARNED. +--------- WARNING --------- WARNING --------- WARNING ----------- + +Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-1: (1) pure MSDOS (no --linux-.--- EMD file): @@ -19,40 +26,49 @@ (2) umsdos (with --linux-.--- EMD file): -- readdir - works. problems with symlink/hardlink resolving. see below. -- lookup - works. problems with symlink/hardlink resolving. see below. +- readdir - works. +- lookup - works. - permissions/owners stuff - works - long file names - works - read file - works -- switching MSDOS/UMSDOS - untested +- switching MSDOS/UMSDOS - works? - switching UMSDOS/MSDOS - untested - pseudo root things - commented out mostly currently. To be fixed when dentries stuff is straightened out. -- resolve symlink - seems to work (ls -l shows both symlink and filename it - points to, but dereferencing does not work. see below) -- dereference symlink - for some strange reason does not work. Is - follow_symlink now obligatory (in contrary what is said in - linux/Documentation/fs/vfs.txt ?) - working on it -- hard links - totally defunct currently. +- resolve symlink - seems to work fully now! +- dereference symlink - seems to work fully now! +- hard links - seems to work now - special files (block/char device, fifos, sockets...) - seems to work ok. - other ioctls - mostly untested +- dangling symlink - UNTESTED ! -- create symlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- create hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- creat file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- write file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- mkdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rmdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- umssyncing - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- create symlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- create hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- create file - creates, but corrupts. after reboot seem ok ? +- create special file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- write to file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- rename file (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- rename file (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- rename dir (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- rename dir (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- delete file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- delete hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- mkdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- rmdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- umssyncing - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -Notes: heavy dentry kernel structures trashing. Probably some other kernel -structures compromised. Have SysRq support compiled in, and use +Notes: moderate dentry/inode kernel structures trashing. Probably some other +kernel structures compromised. Have SysRq support compiled in, and use Sync/Emergency-remount-RO. And don't try mounting read/write yet - and then -you should have no big problems... +you should have no big problems... Notes2: kernel structures trashing seems to be _MUCH_ lower if no symlinks/hardlink present. (hardlinks seem to be biggest problem) +Notes3: Notes2 is probably somewhat outdated now that hardlink/symlink stuff +is supposed to be fixed enough to work, but I haven't got the time to test +it. + ------------------------------------------------------------------------------ Some general notes: @@ -61,16 +77,20 @@ most of them off, or 4 to turn all but really fatal ones off. Probably good idea to kill klogd/syslogd so it will only go to console. -It should work enough to test it, but probably not enough to give you second -chance to umount/rmmod module, recompile it, and reinsert it again. This is -first on my list of things to get fixed, as it would greatly improve speed -of compile/test/reboot/set_environment/recompile cycle by removing -'reboot/set_environment' component. +It should work enough to test it, even enough to give you few chances to +umount/rmmod module, recompile it, and reinsert it again (but probably +screaming about still used inodes on device and stuff). This is first on +my list of things to get fixed, as it would greatly improve speed of +compile/test/reboot/set_environment/recompile cycle by removing +'reboot/set_environment' component that now occures every few cycles. But I need some help from someone knowing about dentries/inodes use more -than I. If you can help, please contact me... +than I. If you can help, please contact me... I'm mostly worries about +iget/iput and dget/dput, and deallocating temporary dentries we create. +should we destroy temp dentries ? using d_invalidate ? using d_drop ? just +dput them ? -I'm unfortunatelly totally out of time to read linux-kernel, but I do check +I'm unfortunatelly somewhat out of time to read linux-kernel, but I do check for any messages having UMSDOS in subject, and read them. I should reply to any direct Email in few days. If I don't - probably I never got your message. You can try mnalis@open.hr or mnalis@voyager.hr; however @@ -80,10 +100,11 @@ some of my notes for myself: -- hardlinks/symlinks. test with files in not_the_same_dir ++ hardlinks/symlinks. test with files in not_the_same_dir - also test not_the_same_dir for other file operations like rename etc. - iput: device 00:00 inode 318 still has aliases! problem. Check in iput() for device 0,0. Probably null pointer passed arount when it shouldn't be ? - dput/iput problem... - what about .dotfiles ? working ? multiple dots ? etc.... +- fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular? diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.1.87/linux/fs/umsdos/dir.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/dir.c Fri Feb 20 09:44:57 1998 @@ -30,18 +30,6 @@ I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS uses. It's easier to do once than hack all the other instances. Probably safer as well */ -int compat_UMSDOS_lookup(struct inode *dir,const char *name,int len, struct inode **inode) -{ - int rv; - struct dentry *dentry; - - dentry = creat_dentry (name, len, NULL); - rv = UMSDOS_lookup(dir,dentry); - - if (inode) *inode = dentry->d_inode; - return rv; -} - int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct inode **inode) { @@ -102,12 +90,7 @@ int ret = -EINVAL; struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; if (d->count == 0){ -#if 0 - char zname[100]; - memcpy (zname,dentry->d_name,dentry->d_len); - zname[name_len] = '\0'; - Printk ((KERN_DEBUG "dir_once :%s: offset %Ld\n",zname,offset)); -#endif + PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", dentry->d_len, dentry->d_name, offset)); ret = d->filldir (d->dirbuf,name,len,offset,ino); d->stop = ret < 0; d->count = 1; @@ -218,9 +201,9 @@ emd_dir = umsdos_emd_dir_lookup(dir,0); if (emd_dir != NULL){ off_t start_fpos = filp->f_pos; - Printk (("umsdos_readdir_x: emd_dir->i_ino=%d\n",emd_dir->i_ino)); + Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n",emd_dir->i_ino)); if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0; - Printk (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size)); + Printk (("f_pos %Ld i_size %ld\n",filp->f_pos,emd_dir->i_size)); ret = 0; while (filp->f_pos < emd_dir->i_size){ struct umsdos_dirent entry; @@ -342,7 +325,7 @@ while (ret == 0 && bufk.stop == 0){ struct umsdos_dirent entry; bufk.count = 0; - Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%d)\n",dir,filp,&bufk,0,&entry,1,umsdos_dir_once)); + Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n",dir,filp,&bufk,0,&entry,1,umsdos_dir_once)); ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once); if (bufk.count == 0) break; count += bufk.count; @@ -639,7 +622,7 @@ if (ret == 0){ ptbpath -= entry.name_len; memcpy (ptbpath,entry.name,entry.name_len); - Printk (("ptbpath :%s: ",ptbpath)); + Printk (("ptbpath :%.*s: ",entry.name_len,ptbpath)); } } }else{ @@ -657,7 +640,7 @@ ptbpath -= entry.name_len; memcpy (ptbpath,entry.name,entry.name_len); dir = adir; - Printk (("ptbpath :%s: ",ptbpath)); + Printk (("ptbpath :%.*s: ",entry.name_len,ptbpath)); }else{ break; } @@ -697,7 +680,7 @@ Check if a file exist in the current directory. Return 0 if ok, negative error code if not (ex: -ENOENT). */ -static int umsdos_lookup_x ( +int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)/* Don't care about pseudo root mode */ @@ -760,7 +743,7 @@ struct umsdos_info info; ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); if (ret == 0) ret = umsdos_findentry (dir,&info,0); - Printk (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret + Printk (("lookup %.*s pos %lu ret %d len %d ",info.fake.len,info.fake.fname,info.f_pos,ret ,info.fake.len)); if (ret == 0){ /* #Specification: umsdos / lookup @@ -776,14 +759,14 @@ ret = compat_umsdos_real_lookup (dir,info.fake.fname,info.fake.len,&inode); - Printk (("umsdos_lookup_x: compat_umsdos_real_lookup for %25s returned %d with inode=%p\n", info.fake.fname, ret, inode)); + Printk ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %d with inode=%p\n", info.fake.len, info.fake.fname, ret, inode)); if (inode == NULL){ - printk (KERN_WARNING "UMSDOS: Erase entry %s, out of sync with MsDOS\n" - ,info.fake.fname); + printk (KERN_WARNING "UMSDOS: Erase entry %.*s, out of sync with MsDOS\n" + ,info.fake.len, info.fake.fname); umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode)); }else{ - Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%d\n",inode->i_ino)); + Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino)); /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */ dentry->d_inode = iget(dir->i_sb, inode->i_ino); @@ -792,7 +775,7 @@ Printk (("lookup ino %ld flags %d\n",inode->i_ino ,info.entry.flags)); if (info.entry.flags & UMSDOS_HLINK){ - Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ HLINK\n")); + Printk ((KERN_DEBUG "umsdos_lookup_x: here goes HLINK\n")); ret = umsdos_hlink2inode (inode,&dentry->d_inode); } if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo){ @@ -830,7 +813,18 @@ struct inode *dir, struct dentry *dentry) { - return umsdos_lookup_x(dir,dentry,0); + int ret; + ret = umsdos_lookup_x(dir,dentry,0); + +#if 1 + if (ret == -ENOENT) { + Printk ((KERN_INFO "UMSDOS_lookup: converting -ENOENT to negative dentry !\n")); + d_add (dentry, NULL); /* create negative dentry if not found */ + ret = 0; + } +#endif + + return ret; } @@ -895,17 +889,18 @@ if (dir->u.umsdos_i.i_emd_dir == 0){ /* This is a DOS directory */ - Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %20s\n", dentry_dst->d_name.name)); + Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name)); ret = umsdos_rlookup_x(dir,dentry_dst,1); }else{ - Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %20s\n", dentry_dst->d_name.name)); + Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name)); ret = umsdos_lookup_x(dir,dentry_dst,1); } Printk ((" returned %d\n", ret)); + *result = dentry_dst->d_inode; /* /mn/ ok ? */ Printk (("h2n lookup :%s: -> %d ",start,ret)); if (ret == 0 && *pt != '\0'){ - dir = dentry_dst->d_inode; + dir = *result; }else{ break; } @@ -914,7 +909,7 @@ Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n")); iput (hlink); /* FIXME */ } - Printk (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result)); + Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result)); kfree (path); } return ret; diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.1.87/linux/fs/umsdos/emd.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/emd.c Fri Feb 20 09:44:57 1998 @@ -28,15 +28,15 @@ * */ -struct dentry *creat_dentry (const char *name, const int len, const struct inode *inode) +struct dentry *creat_dentry (const char *name, const int len, struct inode *inode) { struct dentry *ret, *parent=NULL; /* FIXME /mn/: whatis parent ?? */ struct qstr qname; if (inode) - Printk (("/mn/ creat_dentry: creating dentry with inode=%d for %20s\n", inode->i_ino, name)); + Printk (("/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); else - Printk (("/mn/ creat_dentry: creating empty dentry for %20s\n", name)); + Printk (("/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name)); qname.name = name; qname.len = len; @@ -44,6 +44,7 @@ ret = d_alloc (parent,&qname); /* create new dentry */ ret->d_inode = inode; + return ret; } @@ -71,20 +72,20 @@ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); *offs = filp->f_pos; - Printk ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%ld, offs=%p\n", filp, buf, count, offs)); - Printk ((KERN_DEBUG " using emd=%d\n", emd_dir->i_ino)); - Printk ((KERN_DEBUG " inode=%d, i_size=%d\n", filp->f_dentry->d_inode->i_ino,filp->f_dentry->d_inode->i_size)); - Printk ((KERN_DEBUG " ofs=%ld\n", *offs)); - Printk ((KERN_DEBUG " f_pos=%ld\n", filp->f_pos)); - Printk ((KERN_DEBUG " name=%12s\n", filp->f_dentry->d_name.name)); - Printk ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); - Printk ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); - Printk ((KERN_DEBUG " f_owner=%d\n", filp->f_owner)); - Printk ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); - Printk ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); + PRINTK ((KERN_DEBUG " using emd=%ld\n", emd_dir->i_ino)); + PRINTK ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + PRINTK ((KERN_DEBUG " ofs=%ld\n",(unsigned long) *offs)); + PRINTK ((KERN_DEBUG " f_pos=%Lu\n", filp->f_pos)); + PRINTK ((KERN_DEBUG " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + PRINTK ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + PRINTK ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + PRINTK ((KERN_DEBUG " f_owner=%d\n", filp->f_owner.uid)); + PRINTK ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); + PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); ret = fat_file_read(filp,buf,count,offs); - Printk ((KERN_DEBUG "fat_file_read returned with %ld!\n", ret)); + PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret)); filp->f_pos = *offs; /* we needed *filp only for this? grrrr... /mn/ */ /* FIXME: I have no idea what f_pos is used for. It seems to be used this way before offs was introduced. @@ -98,24 +99,24 @@ /* FIXME: we probably need to destroy originl filp->f_dentry first ? Do we ? And how ? this way we leave all sorts of dentries, inodes etc. lying around */ /* Also FIXME: all the same problems in umsdos_file_write_kmem */ - Printk ((KERN_DEBUG " (ret) using emd=%d\n", emd_dir->i_ino)); - Printk ((KERN_DEBUG " (ret) inode=%d, i_size=%d\n", filp->f_dentry->d_inode->i_ino,filp->f_dentry->d_inode->i_size)); - Printk ((KERN_DEBUG " (ret) ofs=%ld\n", *offs)); - Printk ((KERN_DEBUG " (ret) f_pos=%ld\n", filp->f_pos)); - Printk ((KERN_DEBUG " (ret) name=%12s\n", filp->f_dentry->d_name.name)); - Printk ((KERN_DEBUG " (ret) i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); - Printk ((KERN_DEBUG " (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); - Printk ((KERN_DEBUG " (ret) f_owner=%d\n", filp->f_owner)); - Printk ((KERN_DEBUG " (ret) f_version=%ld\n", filp->f_version)); - Printk ((KERN_DEBUG " (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + PRINTK ((KERN_DEBUG " (ret) using emd=%lu\n", emd_dir->i_ino)); + PRINTK ((KERN_DEBUG " (ret) inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + PRINTK ((KERN_DEBUG " (ret) ofs=%Lu\n", *offs)); + PRINTK ((KERN_DEBUG " (ret) f_pos=%Lu\n", filp->f_pos)); + PRINTK ((KERN_DEBUG " (ret) name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + PRINTK ((KERN_DEBUG " (ret) i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + PRINTK ((KERN_DEBUG " (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + PRINTK ((KERN_DEBUG " (ret) f_owner=%d\n", filp->f_owner.uid)); + PRINTK ((KERN_DEBUG " (ret) f_version=%ld\n", filp->f_version)); + PRINTK ((KERN_DEBUG " (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); #if 0 { struct umsdos_dirent *mydirent=buf; - Printk ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); - Printk ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); - Printk ((KERN_DEBUG " (DDD) name=>%20s<\n",mydirent->name)); + PRINTK ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); + PRINTK ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); + PRINTK ((KERN_DEBUG " (DDD) name=>%.20s<\n",mydirent->name)); } #endif @@ -136,18 +137,29 @@ { int ret; mm_segment_t old_fs = get_fs(); - struct dentry *old_dentry; /* FIXME /mn/: whatis parent ?? */ + struct dentry *old_dentry; - set_fs (KERNEL_DS); - ret = fat_file_write(filp,buf,count,offs); + Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); + Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); + Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs)); + Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos)); + Printk ((KERN_ERR " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + Printk ((KERN_ERR " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + Printk ((KERN_ERR " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid)); + Printk ((KERN_ERR " f_version=%ld\n", filp->f_version)); + Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + + set_fs (KERNEL_DS); old_dentry=filp->f_dentry; /* save it */ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); - *offs = filp->f_pos; - ret = fat_file_write (filp,buf,count,offs); - PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret)); + ret = fat_file_write (filp, buf, count, offs); + PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); filp->f_pos = *offs; filp->f_dentry=old_dentry; @@ -189,7 +201,9 @@ #endif if (offs) myofs=*offs; /* if offs is not NULL, read it */ + Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %ld, %Ld\n", emd_dir, filp, buf, count, myofs)); written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs); + Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n")); if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ #ifdef __BIG_ENDIAN @@ -264,32 +278,32 @@ { struct inode *ret = NULL; int res; - Printk (("Entering umsdos_emd_dir_lookup\n")); + PRINTK ((KERN_DEBUG "Entering umsdos_emd_dir_lookup\n")); if (dir->u.umsdos_i.i_emd_dir != 0){ ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n" ,dir->u.umsdos_i.i_emd_dir,ret)); } else { - Printk ((KERN_DEBUG "umsdos /mn/: Looking for %20s -", UMSDOS_EMD_FILE)); + PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -", UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE)); res = compat_umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, &ret); - Printk ((KERN_DEBUG "-returned %d\n", res)); - Printk ((KERN_DEBUG "emd_dir_lookup ")); + PRINTK ((KERN_DEBUG "-returned %d\n", res)); + Printk ((KERN_INFO "emd_dir_lookup ")); if (ret != NULL){ - Printk ((KERN_DEBUG "Found --linux ")); + Printk (("Found --linux ")); dir->u.umsdos_i.i_emd_dir = ret->i_ino; } else if (creat) { int code; - Printk ((KERN_ERR " * ERROR * /mn/: creat not yet implemented!!!!" )); + Printk ((" * ERROR * /mn/: creat not yet implemented!!!!" )); Printk ((KERN_DEBUG "avant create ")); - atomic_inc(&dir->i_count); + dir->i_count++; code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN ,S_IFREG|0777,&ret); - Printk ((KERN_DEBUG "Creat EMD code %d ret %x ",code,ret)); + Printk ((KERN_WARNING "Creat EMD code %d ret %p ", code, ret)); if (ret != NULL){ dir->u.umsdos_i.i_emd_dir = ret->i_ino; }else{ - printk ("UMSDOS: Can't create EMD file\n"); + printk (KERN_WARNING "UMSDOS: Can't create EMD file\n"); } } @@ -300,8 +314,10 @@ } - Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret)); - if (ret != NULL) Printk ((KERN_DEBUG " debug : returning ino=%d\n",ret->i_ino)); +#if 0 + PRINTK ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret)); + if (ret != NULL) PRINTK ((KERN_DEBUG " debug : returning ino=%lu\n", ret->i_ino)); +#endif return ret; } @@ -316,7 +332,7 @@ struct inode *ret = NULL; if (dir->u.umsdos_i.i_emd_dir != 0){ ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir); - Printk (("deja trouve %d %x",dir->u.umsdos_i.i_emd_dir,ret)); + Printk (("deja trouve %lu %p", dir->u.umsdos_i.i_emd_dir, ret)); }else{ int code; @@ -329,7 +345,7 @@ FIXME, I think I need a new dentry here */ code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN, S_IFREG|0777, &ret); - Printk (("Creat EMD code %d ret %x ",code,ret)); + Printk (("Creat EMD code %d ret %p ", code, ret)); if (ret != NULL){ dir->u.umsdos_i.i_emd_dir = ret->i_ino; }else{ @@ -358,7 +374,7 @@ { int ret; Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n")); - Printk (("umsdos_emd_dir_readentry /mn/: trying to lookup %12s (ino=%d) using EMD %d\n", filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, emd_dir->i_ino)); + Printk (("umsdos_emd_dir_readentry /mn/: trying to lookup %.*s (ino=%lu) using EMD %lu\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, emd_dir->i_ino)); ret = umsdos_emd_dir_read(emd_dir, filp, (char*)entry, UMSDOS_REC_SIZE, NULL); if (ret == 0){ /* note /mn/: is this wrong? ret is allways 0 or -EIO. but who knows. It used to work this way... */ @@ -389,14 +405,13 @@ int free_entry) /* This entry is deleted, so Write all 0's */ { int ret = 0; + struct dentry *emd_dentry; struct file filp; struct umsdos_dirent *entry = &info->entry; struct umsdos_dirent entry0; Printk (("umsdos_writeentry /mn/: entering...\n")); - - Printk ((KERN_ERR "umsdos_writeentry /mn/: FIXME! this is READ ONLY FOR NOW. RETURNING...\n")); - return -EIO; + emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir); if (free_entry){ /* #Specification: EMD file / empty entries @@ -421,9 +436,15 @@ Printk (("umsdos_writeentry /mn/: if passed...\n")); + if (!info) printk (KERN_ERR "umsdosfs: /mn/ info is empty ! ooops...\n"); filp.f_pos = info->f_pos; filp.f_reada = 0; - ret = umsdos_emd_dir_write(emd_dir, &filp,(char*)entry,info->recsize,NULL); + filp.f_flags = O_RDWR; + filp.f_dentry = emd_dentry; + filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + + ret = umsdos_emd_dir_write (emd_dir, &filp, (char*)entry, info->recsize, NULL); + Printk (("emd_dir_write returned !\n")); if (ret != 0){ printk ("UMSDOS: problem with EMD file. Can't write\n"); }else{ @@ -435,6 +456,8 @@ return ret; } + + #define CHUNK_SIZE (8*UMSDOS_REC_SIZE) struct find_buffer{ char buffer[CHUNK_SIZE]; @@ -462,7 +485,7 @@ int mustread; int remain; - Printk ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %d, buf=%p\n",inode->i_ino, buf)); + PRINTK ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %lu, buf=%p\n", inode->i_ino, buf)); if (mustmove > 0){ memcpy (buf->buffer,buf->buffer+buf->pos,mustmove); @@ -518,8 +541,8 @@ record, multiple contiguous record are allocated. */ int ret = -ENOENT; - /* FIXME */ - struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1); + /* FIXME -- /mn/ fixed ? */ + struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1); if (emd_dir != NULL){ struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v2.1.87/linux/fs/umsdos/inode.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/inode.c Fri Feb 20 09:44:57 1998 @@ -38,8 +38,8 @@ void UMSDOS_put_inode(struct inode *inode) { - Printk ((KERN_DEBUG "put inode %x (%d) owner %x pos %d dir %x\n",inode, inode->i_ino - ,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos + PRINTK ((KERN_DEBUG "put inode %p (%lu) owner %lu pos %lu dir %lu\n", inode, inode->i_ino + ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos ,inode->u.umsdos_i.i_emd_dir)); if (inode && pseudo_root && inode == pseudo_root){ printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n"); @@ -55,7 +55,7 @@ void UMSDOS_put_super(struct super_block *sb) { - Printk (("UMSDOS_put_super: /mn/ entering\n")); + Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n")); msdos_put_super(sb); MOD_DEC_USE_COUNT; } @@ -73,10 +73,10 @@ { int ret; - Printk (("umsdos_real_lookup /mn/: looking for %s /",dentry->d_name.name)); + PRINTK ((KERN_DEBUG "umsdos_real_lookup /mn/: looking for %s /",dentry->d_name.name)); dir->i_count++; /* /mn/ what is this and why ? locking? */ ret = msdos_lookup (dir,dentry); - Printk (("/ returned %d\n", ret)); + PRINTK (("/ returned %d\n", ret)); return ret; } @@ -95,13 +95,13 @@ extern struct inode_operations umsdos_rdir_inode_operations; emd_dir = umsdos_emd_dir_lookup (inode,0); - Printk (("umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n",inode,emd_dir)); + Printk ((KERN_DEBUG "umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n",inode,emd_dir)); if (emd_dir == NULL) { - Printk (("umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. NOT using EMD.\n")); + Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. NOT using EMD.\n")); inode->i_op = &umsdos_rdir_inode_operations; } else { - Printk (("umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. using EMD.\n")); + Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. using EMD.\n")); inode->i_op = &umsdos_dir_inode_operations; } @@ -120,7 +120,7 @@ { struct inode *emd_owner; /* FIXME, I don't have a clue on this one */ - Printk (("umsdos_set_dirinfo: /mn/ FIXME: no clue\n")); + Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue\n")); emd_owner = umsdos_emd_dir_lookup(dir,1); inode->u.umsdos_i.i_dir_owner = dir->i_ino; inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; @@ -169,14 +169,17 @@ them at the end. Doing that now introduce a problem. unmount always fail because some inodes are in use. */ + + Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", inode->i_ino)); + if (!umsdos_isinit(inode)){ inode->u.umsdos_i.i_emd_dir = 0; if (S_ISREG(inode->i_mode)){ if (inode->i_op->bmap != NULL){ - Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); inode->i_op = &umsdos_file_inode_operations; }else{ - Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); inode->i_op = &umsdos_file_inode_operations_no_bmap; } }else if (S_ISDIR(inode->i_mode)){ @@ -184,16 +187,16 @@ umsdos_setup_dir_inode(inode); } }else if (S_ISLNK(inode->i_mode)){ - Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n")); + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n")); inode->i_op = &umsdos_symlink_inode_operations; }else if (S_ISCHR(inode->i_mode)){ - Printk (("umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n")); + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n")); inode->i_op = &chrdev_inode_operations; }else if (S_ISBLK(inode->i_mode)){ - Printk (("umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n")); + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n")); inode->i_op = &blkdev_inode_operations; }else if (S_ISFIFO(inode->i_mode)){ - Printk (("umsdos_patch_inode /mn/: uhm, init_fifo\n")); + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n")); init_fifo(inode); } if (dir != NULL){ @@ -207,7 +210,7 @@ This is done last because it also control the status of umsdos_isinit() */ - Printk (("umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%d)\n", inode, dir, f_pos)); + PRINTK ((KERN_DEBUG "umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%lu)\n", inode, dir, f_pos)); umsdos_set_dirinfo (inode,dir,f_pos); } }else if (dir != NULL){ @@ -217,7 +220,7 @@ */ /* FIXME, again, not a clue */ struct inode *emd_owner; - Printk (("umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n")); + Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n")); emd_owner = umsdos_emd_dir_lookup(dir,1); iput (emd_owner); if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){ @@ -259,14 +262,14 @@ */ void UMSDOS_read_inode(struct inode *inode) { - Printk (("UMSDOS_read_inode %x ino = %d ",inode,inode->i_ino)); + PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",inode,inode->i_ino)); msdos_read_inode(inode); - PRINTK (("ino after msdos_read_inode= %d\n",inode->i_ino)); + PRINTK (("ino after msdos_read_inode= %lu\n",inode->i_ino)); if (S_ISDIR(inode->i_mode) && (inode->u.umsdos_i.u.dir_info.creating != 0 || inode->u.umsdos_i.u.dir_info.looking != 0 || waitqueue_active(&inode->u.umsdos_i.u.dir_info.p))){ - Printk (("read inode %d %d %p\n" + PRINTK (("read inode %d %d %p\n" ,inode->u.umsdos_i.u.dir_info.creating ,inode->u.umsdos_i.u.dir_info.looking ,inode->u.umsdos_i.u.dir_info.p)); @@ -319,7 +322,7 @@ int ret = 0; struct inode *inode = dentry->d_inode; - Printk (("UMSDOS_notify_change: /mn/ completly untested\n")); + Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n")); if ((ret = inode_change_ok(inode, attr)) != 0) return ret; @@ -363,7 +366,7 @@ offs = 0; filp.f_pos = inode->u.umsdos_i.pos; filp.f_reada = 0; - Printk (("pos = %d ",filp.f_pos)); + Printk (("pos = %Lu ", filp.f_pos)); /* Read only the start of the entry since we don't touch */ /* the name */ ret = umsdos_emd_dir_read (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); @@ -386,9 +389,9 @@ offs = 0; /* FIXME */ ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); - Printk (("notify pos %d ret %d nlink %d " + Printk (("notify pos %lu ret %d nlink %d " ,inode->u.umsdos_i.pos - ,ret,entry.nlink)); + ,ret, entry.nlink)); /* #Specification: notify_change / msdos fs notify_change operation are done only on the EMD file. The msdos fs is not even called. @@ -449,21 +452,21 @@ */ struct super_block *res; struct inode *pseudo=NULL; - Printk (("UMSDOS /mn/: starting UMSDOS_read_super\n")); + Printk ((KERN_DEBUG "UMSDOS /mn/: starting UMSDOS_read_super\n")); MOD_INC_USE_COUNT; - Printk (("UMSDOS /mn/: sb = %p\n",sb)); + PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb)); res = msdos_read_super(sb,data,silent); - Printk (("UMSDOS /mn/: res = %p\n",res)); - printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); + PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res)); + printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-1 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; } MSDOS_SB(res)->options.dotsOK = 0; /* disable hidden==dotfile */ res->s_op = &umsdos_sops; - Printk (("umsdos /mn/: here goes the iget ROOT_INO\n")); + Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n")); pseudo = iget(res,UMSDOS_ROOT_INO); - Printk (("umsdos_read_super %p\n",pseudo)); + Printk ((KERN_DEBUG "umsdos_read_super %p\n",pseudo)); umsdos_setup_dir_inode (pseudo); @@ -506,13 +509,13 @@ root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL); sbin = creat_dentry ("sbin", 4, NULL); - Printk (("Mounting root\n")); + Printk ((KERN_DEBUG "Mounting root\n")); if (umsdos_real_lookup (pseudo,root)==0 && (root->d_inode != NULL) && S_ISDIR(root->d_inode->i_mode)){ int pseudo_ok = 0; - Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME)); + Printk ((KERN_DEBUG "/%s is there\n",UMSDOS_PSDROOT_NAME)); etc = creat_dentry ("etc", 3, NULL); @@ -520,7 +523,7 @@ if(umsdos_real_lookup(pseudo, etc) == 0 && S_ISDIR(etc->d_inode->i_mode)){ - Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); + Printk ((KERN_DEBUG "/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); init = creat_dentry ("init", 4, NULL); etc_rc = creat_dentry ("rc", 2, NULL); @@ -542,7 +545,7 @@ && umsdos_real_lookup(pseudo, sbin) == 0 && S_ISDIR(sbin->d_inode->i_mode)){ - Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME)); + Printk ((KERN_DEBUG "/%s/sbin is there\n",UMSDOS_PSDROOT_NAME)); /* if (umsdos_real_lookup (sbin,"init",4,init)==0 */ if(umsdos_real_lookup(pseudo, init) == 0 && S_ISREG(init->d_inode->i_mode)){ @@ -553,7 +556,7 @@ } if (pseudo_ok){ umsdos_setup_dir_inode (pseudo); - Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); + Printk ((KERN_INFO "Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME)); pseudo_root = pseudo; pseudo->i_count++; pseudo = NULL; @@ -565,14 +568,14 @@ */ } - Printk (("umsdos_read_super /mn/: Pseudo should be iput-ed here...\n")); + Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n")); iput (pseudo); /* FIXME */ } #endif /* disabled */ - Printk (("umsdos_read_super /mn/: returning %p\n",res)); + PRINTK ((KERN_DEBUG "umsdos_read_super /mn/: returning %p\n",res)); return res; } diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v2.1.87/linux/fs/umsdos/namei.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/namei.c Fri Feb 20 09:44:57 1998 @@ -238,8 +238,8 @@ struct inode *inode = dentry->d_inode; umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); Printk (("inode %p[%d] ",inode,inode->i_count)); - Printk (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino - ,info.fake.fname,current->pid,info.f_pos)); + Printk (("Creation OK: [%lu] %.*s %d pos %ld\n", dir->i_ino, + info.fake.len, info.fake.fname, current->pid, info.f_pos)); }else{ /* #Specification: create / file exist in DOS Here is a situation. Trying to create a file with @@ -265,13 +265,13 @@ */ if (ret == -EEXIST){ printk ("UMSDOS: out of sync, Creation error [%ld], " - "deleting %s %d %d pos %ld\n",dir->i_ino - ,info.fake.fname,-ret,current->pid,info.f_pos); + "deleting %.*s %d %d pos %ld\n",dir->i_ino + ,info.fake.len,info.fake.fname,-ret,current->pid,info.f_pos); } umsdos_delentry (dir,&info,0); } - Printk (("umsdos_create %s ret = %d pos %d\n" - ,info.fake.fname,ret,info.f_pos)); + Printk (("umsdos_create %.*s ret = %d pos %ld\n", + info.fake.len, info.fake.fname, ret, info.f_pos)); } umsdos_unlockcreate(dir); } @@ -379,7 +379,7 @@ chkstk(); if (ret == 0){ /* - This UMSDOS_lookup does not look very useful. + This umsdos_lookup_x does not look very useful. It makes sure that the inode of the file will be correctly setup (umsdos_patch_inode()) in case it is already in use. @@ -388,13 +388,13 @@ */ struct inode *inode; new_dir->i_count++; - PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags)); - ret = UMSDOS_lookup (new_dir,new_dentry); + PRINTK ((KERN_DEBUG "rename lookup len %d %d -- ",new_len,new_info.entry.flags)); + ret = umsdos_lookup_x (new_dir, new_dentry, 0); inode = new_dentry->d_inode; chkstk(); if (ret != 0){ - printk ("UMSDOS: partial rename for file %s\n" - ,new_info.entry.name); + printk ("UMSDOS: partial rename for file %.*s\n" + ,new_info.entry.name_len,new_info.entry.name); }else{ /* Update f_pos so notify_change will succeed @@ -459,7 +459,8 @@ filp.f_pos = 0; /* Make the inode acceptable to MSDOS FIXME */ Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n")); - ret = umsdos_file_write_kmem (dentry->d_inode->i_ino, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... */ + ret = umsdos_file_write_kmem (dentry->d_inode, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... + PTW dentry->d_inode is "less incorrect" */ /* dput(dentry); ?? where did this come from FIXME */ if (ret >= 0){ if (ret != len){ @@ -580,16 +581,16 @@ }else if ((ret = umsdos_nevercreat(dir,dentry,-EPERM))==0){ struct inode *olddir; ret = umsdos_get_dirowner(oldinode,&olddir); - Printk (("umsdos_link dir_owner = %d -> %p [%d] " - ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count)); + Printk (("umsdos_link dir_owner = %lu -> %p [%d] ", + oldinode->u.umsdos_i.i_dir_owner, olddir, olddir->i_count)); if (ret == 0){ struct umsdos_dirent entry; umsdos_lockcreate2(dir,olddir); ret = umsdos_inode2entry (olddir,oldinode,&entry); if (ret == 0){ - Printk (("umsdos_link :%s: ino %d flags %d " - ,entry.name - ,oldinode->i_ino,entry.flags)); + Printk (("umsdos_link :%.*s: ino %lu flags %d " + ,entry.name_len, entry.name + ,oldinode->i_ino, entry.flags)); if (!(entry.flags & UMSDOS_HIDDEN)){ /* #Specification: hard link / first hard link The first time a hard link is done on a file, this @@ -882,7 +883,7 @@ if (ret == 0){ volatile struct inode *sdir; dir->i_count++; - ret = UMSDOS_lookup (dir, dentry); + ret = umsdos_lookup_x (dir, dentry, 0); sdir = dentry->d_inode; Printk (("rmdir lookup %d ",ret)); if (ret == 0){ @@ -892,7 +893,7 @@ ret = -EBUSY; }else if ((empty = umsdos_isempty (sdir)) != 0){ struct dentry *tdentry; - tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_FILE, NULL); + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); Printk (("isempty %d i_count %d ",empty,sdir->i_count)); /* check sticky bit */ if ( !(dir->i_mode & S_ISVTX) || fsuser() || @@ -959,7 +960,7 @@ umsdos_lockcreate(dir); ret = umsdos_findentry(dir,&info,1); if (ret == 0){ - Printk (("UMSDOS_unlink %s ",info.fake.fname)); + Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname)); /* check sticky bit */ if ( !(dir->i_mode & S_ISVTX) || fsuser() || current->fsuid == info.entry.uid || @@ -979,7 +980,7 @@ */ struct inode *inode; dir->i_count++; - ret = UMSDOS_lookup (dir,dentry); + ret = umsdos_lookup_x (dir, dentry, 0); inode = dentry->d_inode; if (ret == 0){ Printk (("unlink nlink = %d ",inode->i_nlink)); @@ -1006,11 +1007,11 @@ ret = umsdos_delentry (dir,&info,0); if (ret == 0){ struct dentry *temp; - Printk (("Avant msdos_unlink %s ",info.fake.fname)); + Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname)); dir->i_count++; temp = creat_dentry (info.fake.fname, info.fake.len, NULL); ret = msdos_unlink_umsdos (dir, temp); - Printk (("msdos_unlink %s %o ret %d ",info.fake.fname + Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname ,info.entry.mode,ret)); } } diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.1.87/linux/fs/umsdos/rdir.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/rdir.c Fri Feb 20 09:44:57 1998 @@ -39,9 +39,9 @@ { int ret = 0; struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf; - Printk ((KERN_DEBUG "rdir_filldir /mn/: entering\n")); + PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n")); if (d->real_root){ - Printk ((KERN_DEBUG "rdir_filldir /mn/: real root!\n")); + PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n")); /* real root of a pseudo_rooted partition */ if (name_len != UMSDOS_PSDROOT_LEN || memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){ @@ -56,8 +56,8 @@ } }else{ /* Any DOS directory */ - Printk ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %12s (%d)\n",d->filldir,name,ino)); - ret = d->filldir (d->dirbuf,name,name_len,offset,ino); + PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino)); + ret = d->filldir (d->dirbuf, name, name_len, offset, ino); } return ret; } @@ -71,7 +71,7 @@ struct RDIR_FILLDIR bufk; struct inode *dir = filp->f_dentry->d_inode; - Printk ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf)); + PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf)); bufk.filldir = filldir; @@ -79,7 +79,7 @@ bufk.real_root = pseudo_root && dir == iget(dir->i_sb,UMSDOS_ROOT_INO) && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO); - Printk ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n",filldir)); + PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n",filldir)); return fat_readdir(filp, &bufk, rdir_filldir); } @@ -106,7 +106,7 @@ && dir == iget(dir->i_sb,UMSDOS_ROOT_INO) && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO) ){ /* *result = pseudo_root;*/ - Printk (("umsdos_rlookup_x: we are at pseudo-root thingy?\n")); + Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n")); pseudo_root->i_count++; ret = 0; /* #Specification: pseudo root / DOS/.. @@ -115,13 +115,17 @@ */ }else{ ret = umsdos_real_lookup (dir, dentry); inode=dentry->d_inode; - Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %s in %d returned %d\n", name, dir->i_ino, ret)); + +#if 0 + Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret)); Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode)); if (inode) { /* /mn/ FIXME: DEL_ME */ - Printk ((KERN_DEBUG "i_ino=%d\n",inode->i_ino)); + Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino)); } else { Printk ((KERN_DEBUG "NONE!\n")); } +#endif + if ((ret == 0) && inode){ if (pseudo_root && inode == pseudo_root && !nopseudo){ @@ -129,20 +133,20 @@ Even in the real root directory (c:\), the directory /linux won't show */ - Printk (("umsdos_rlookup_x: do the pseudo-thingy...\n")); + Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n")); ret = -ENOENT; iput (pseudo_root); }else if (S_ISDIR(inode->i_mode)){ /* We must place the proper function table */ /* depending if this is a MsDOS directory or an UMSDOS directory */ - Printk (("umsdos_rlookup_x: setting up setup_dir_inode %d...\n", inode->i_ino)); + Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino)); umsdos_setup_dir_inode (inode); } } } iput (dir); - Printk ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); + PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); return ret; } @@ -152,7 +156,7 @@ struct dentry *dentry ) { - Printk ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%d in %20s\n",dir->i_ino,dentry->d_name.name)); + PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name)); return umsdos_rlookup_x(dir,dentry,0); } diff -u --recursive --new-file v2.1.87/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c --- v2.1.87/linux/fs/umsdos/symlink.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/symlink.c Fri Feb 20 09:44:57 1998 @@ -28,19 +28,21 @@ /* Read the data associate with the symlink. Return length read in buffer or a negative error code. - FIXME, this is messed up. - /mn/ WIP fixing... */ + static int umsdos_readlink_x ( struct dentry *dentry, char *buffer, int bufsiz) { - int ret = dentry->d_inode->i_size; + int ret; loff_t loffs = 0; struct file filp; + + ret = dentry->d_inode->i_size; + memset (&filp, 0, sizeof (filp)); filp.f_pos = 0; @@ -51,34 +53,33 @@ if (ret > bufsiz) ret = bufsiz; - Printk ((KERN_WARNING "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%ld, offs=%d\n", &filp, buffer, ret, loffs)); - Printk ((KERN_WARNING " f_op=%p\n", filp.f_op)); - Printk ((KERN_WARNING " inode=%d, i_size=%d\n", filp.f_dentry->d_inode->i_ino,filp.f_dentry->d_inode->i_size)); - Printk ((KERN_WARNING " f_pos=%ld\n", filp.f_pos)); - Printk ((KERN_WARNING " name=%12s\n", filp.f_dentry->d_name.name)); - Printk ((KERN_WARNING " i_binary(sb)=%d\n", MSDOS_I(filp.f_dentry->d_inode)->i_binary )); - Printk ((KERN_WARNING " f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags)); - Printk ((KERN_WARNING " f_owner=%d\n", filp.f_owner)); - Printk ((KERN_WARNING " f_version=%ld\n", filp.f_version)); - Printk ((KERN_WARNING " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin)); + PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs)); + PRINTK ((KERN_DEBUG " f_op=%p\n", filp.f_op)); + PRINTK ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp.f_dentry->d_inode->i_ino, filp.f_dentry->d_inode->i_size)); + PRINTK ((KERN_DEBUG " f_pos=%Lu\n", filp.f_pos)); + PRINTK ((KERN_DEBUG " name=%.*s\n", (int) filp.f_dentry->d_name.len, filp.f_dentry->d_name.name)); + PRINTK ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp.f_dentry->d_inode)->i_binary )); + PRINTK ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags)); + PRINTK ((KERN_DEBUG " f_owner=%d\n", filp.f_owner.uid)); + PRINTK ((KERN_DEBUG " f_version=%ld\n", filp.f_version)); + PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin)); - /* FIXME */ - Printk (("umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %ld)\n", &filp, buffer, ret, loffs)); + PRINTK ((KERN_DEBUG"umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs)); if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret){ ret = -EIO; } -#if 0 +#if 0 /* DEBUG */ { struct umsdos_dirent *mydirent=buffer; - Printk ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); - Printk ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); - Printk ((KERN_DEBUG " (DDD) name=>%20s<\n",mydirent->name)); + PRINTK ((KERN_DEBUG " (DDD) uid=%d\n",mydirent->uid)); + PRINTK ((KERN_DEBUG " (DDD) gid=%d\n",mydirent->gid)); + PRINTK ((KERN_DEBUG " (DDD) name=>%.20s<\n",mydirent->name)); } #endif - Printk (("umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%ld ret=%d\n", loffs, ret)); + PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%Lu ret=%d\n", loffs, ret)); return ret; } @@ -88,33 +89,57 @@ { int ret; - Printk (("UMSDOS_readlink: calling umsdos_readlink_x for %20s\n", dentry->d_name.name)); + PRINTK ((KERN_DEBUG "UMSDOS_readlink: calling umsdos_readlink_x for %.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); ret = umsdos_readlink_x (dentry, buffer, buflen); - Printk (("readlink %d bufsiz %d\n", ret, buflen)); + PRINTK ((KERN_DEBUG "readlink %d bufsiz %d\n", ret, buflen)); /* dput(dentry); / * FIXME /mn/ */ - Printk (("UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret)); + Printk ((KERN_WARNING "UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret)); return ret; } -static struct dentry *UMSDOS_followlink(struct dentry * dentry, struct dentry * base) +/* this one mostly stolen from romfs :) */ +static struct dentry *UMSDOS_followlink(struct dentry *dentry, struct dentry *base) { - int ret; - char symname[256]; struct inode *inode = dentry->d_inode; + char *symname=NULL; + int len, cnt; mm_segment_t old_fs = get_fs(); - Printk ((KERN_ERR "UMSDOS_followlink /mn/: (%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name)); + Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: (%.*s/%.*s)\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, (int) dentry->d_name.len, dentry->d_name.name)); + + len = inode->i_size; - set_fs (KERNEL_DS); /* we read into kernel space */ - ret = umsdos_readlink_x (dentry, &symname, 256); + if (!(symname = kmalloc(len+1, GFP_KERNEL))) { + dentry = ERR_PTR(-EAGAIN); /* correct? */ + goto outnobuf; + } + + set_fs (KERNEL_DS); /* we read into kernel space this time */ + PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: Here goes umsdos_readlink_x %p, %p, %d\n", dentry, symname, len)); + cnt = umsdos_readlink_x (dentry, symname, len); + PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: back from umsdos_readlink_x %p, %p, %d!\n", dentry, symname, len)); set_fs (old_fs); + Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: link name is %.*s with len %d\n", cnt, symname, cnt)); - base = creat_dentry (symname, ret, NULL); -/* UMSDOS_lookup (dentry->d_parent->d_inode, base);*/ - - return base; + if (len != cnt) { + dentry = ERR_PTR(-EIO); + goto out; + } else + symname[len] = 0; + + dentry = lookup_dentry(symname, base, 1); + kfree(symname); + + if (0) { +out: + kfree(symname); +outnobuf: + dput(base); + } + return dentry; } + static struct file_operations umsdos_symlink_operations = { NULL, /* lseek - default */ NULL, /* read */ @@ -141,7 +166,7 @@ NULL, /* mknod */ NULL, /* rename */ UMSDOS_readlink, /* readlink */ - NULL/*UMSDOS_followlink*/, /* followlink */ /* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */ + UMSDOS_followlink, /* followlink */ /* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */ generic_readpage, /* readpage */ /* in original NULL. changed to generic_readpage. FIXME? /mn/ */ NULL, /* writepage */ fat_bmap, /* bmap */ /* in original NULL. changed to fat_bmap. FIXME? /mn/ */ diff -u --recursive --new-file v2.1.87/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.1.87/linux/fs/vfat/namei.c Tue Feb 17 13:12:48 1998 +++ linux/fs/vfat/namei.c Fri Feb 20 18:28:23 1998 @@ -10,7 +10,6 @@ * the problem, send a script that demonstrates it. */ -#include #define __NO_VERSION__ #include diff -u --recursive --new-file v2.1.87/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h --- v2.1.87/linux/include/asm-alpha/dma.h Mon Jun 3 20:06:38 1996 +++ linux/include/asm-alpha/dma.h Thu Feb 19 14:46:15 1998 @@ -313,6 +313,8 @@ /* These are in kernel/dma.c: */ extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ extern void free_dma(unsigned int dmanr); /* release it again */ +#define KERNEL_HAVE_CHECK_DMA +extern int check_dma(unsigned int dmanr); #endif /* _ASM_DMA_H */ diff -u --recursive --new-file v2.1.87/linux/include/asm-i386/floppy.h linux/include/asm-i386/floppy.h --- v2.1.87/linux/include/asm-i386/floppy.h Fri Feb 6 15:33:06 1998 +++ linux/include/asm-i386/floppy.h Fri Feb 20 19:12:50 1998 @@ -60,7 +60,7 @@ register unsigned char st; #undef TRACE_FLPY_INT -#undef NO_FLOPPY_ASSEMBLER +#define NO_FLOPPY_ASSEMBLER #ifdef TRACE_FLPY_INT static int calls=0; @@ -123,10 +123,10 @@ outb_p(*lptr, virtual_dma_port+5); else *lptr = inb_p(virtual_dma_port+5); - st = inb(virtual_dma_port+4); } virtual_dma_count = lcount; virtual_dma_addr = lptr; + st = inb(virtual_dma_port+4); } #endif @@ -223,7 +223,7 @@ _CROSS_64KB(addr, size, 0)) use_virtual_dma = 1; else - use_virtual_dma = 1; + use_virtual_dma = 0; } else { use_virtual_dma = can_use_virtual_dma & 1; } diff -u --recursive --new-file v2.1.87/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h --- v2.1.87/linux/include/asm-m68k/io.h Tue Feb 17 13:12:49 1998 +++ linux/include/asm-m68k/io.h Fri Feb 20 18:28:23 1998 @@ -3,6 +3,7 @@ #ifdef __KERNEL__ +#include /* CONFIG_ATARI, CONFIG_HADES */ #include #ifdef CONFIG_ATARI diff -u --recursive --new-file v2.1.87/linux/include/asm-m68k/keyboard.h linux/include/asm-m68k/keyboard.h --- v2.1.87/linux/include/asm-m68k/keyboard.h Tue Feb 17 13:12:49 1998 +++ linux/include/asm-m68k/keyboard.h Fri Feb 20 18:28:23 1998 @@ -8,6 +8,7 @@ * This file contains the m68k architecture specific keyboard definitions */ +#include /* CONFIG_MAGIC_SYSRQ */ #ifndef __M68K_KEYBOARD_H #define __M68K_KEYBOARD_H diff -u --recursive --new-file v2.1.87/linux/include/asm-mips/inventory.h linux/include/asm-mips/inventory.h --- v2.1.87/linux/include/asm-mips/inventory.h Tue Dec 16 12:46:06 1997 +++ linux/include/asm-mips/inventory.h Fri Feb 20 18:25:09 1998 @@ -26,31 +26,3 @@ #define init_inventory() #endif #endif /* defined(CONFIG_BINFMT_IRIX) */ -/* - * $Id: inventory.h,v 1.2 1997/12/06 12:39:03 ralf Exp $ - */ -#ifndef __ASM_MIPS_INVENTORY_H -#define __ASM_MIPS_INVENTORY_H - -#include - -#ifdef CONFIG_BINFMT_IRIX -typedef struct inventory_s { - struct inventory_s *inv_next; - int inv_class; - int inv_type; - int inv_controller; - int inv_unit; - int inv_state; -} inventory_t; - -extern int inventory_items; -void add_to_inventory (int class, int type, int controller, int unit, int state); -int dump_inventory_to_user (void *userbuf, int size); -void init_inventory (void); - -#else -#define add_to_inventory(c,t,o,u,s) -#define init_inventory() -#endif -#endif /* defined(CONFIG_BINFMT_IRIX) */ diff -u --recursive --new-file v2.1.87/linux/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h --- v2.1.87/linux/include/asm-ppc/prom.h Mon Jan 12 15:18:13 1998 +++ linux/include/asm-ppc/prom.h Fri Feb 20 18:28:23 1998 @@ -5,8 +5,6 @@ * Copyright (C) 1996 Paul Mackerras. */ -#include - typedef void *phandle; typedef void *ihandle; diff -u --recursive --new-file v2.1.87/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v2.1.87/linux/include/linux/apm_bios.h Thu Feb 12 20:56:13 1998 +++ linux/include/linux/apm_bios.h Thu Feb 19 14:46:15 1998 @@ -19,6 +19,7 @@ */ typedef unsigned short apm_event_t; +typedef unsigned short apm_eventinfo_t; #ifdef __KERNEL__ @@ -35,6 +36,7 @@ unsigned short dseg; unsigned short flags; unsigned short cseg_len; + unsigned short cseg_16_len; unsigned short dseg_len; }; @@ -111,6 +113,7 @@ #define APM_USER_STANDBY 0x0009 #define APM_USER_SUSPEND 0x000a #define APM_STANDBY_RESUME 0x000b +#define APM_CAPABILITY_CHANGE 0x000c /* * Error codes @@ -126,6 +129,8 @@ #define APM_BAD_DEVICE 0x09 #define APM_BAD_PARAM 0x0a #define APM_NOT_ENGAGED 0x0b +#define APM_BAD_FUNCTION 0x0c +#define APM_RESUME_DISABLED 0x0d #define APM_BAD_STATE 0x60 #define APM_NO_EVENTS 0x80 #define APM_NOT_PRESENT 0x86 diff -u --recursive --new-file v2.1.87/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.1.87/linux/include/linux/blk.h Tue Feb 17 13:12:49 1998 +++ linux/include/linux/blk.h Fri Feb 20 19:12:39 1998 @@ -12,7 +12,7 @@ * is mucked around with in interrupts on potentially * multiple CPU's.. */ -extern spinlock_t current_lock; +extern spinlock_t io_request_lock; /* * NR_REQUEST is the number of entries in the request-queue. @@ -445,6 +445,11 @@ #if ! SCSI_BLK_MAJOR(MAJOR_NR) +/* + * The [*_]end_request() handler has to be called with the request queue + * spinlock aquired. All functions called within end_request() _must be_ + * atomic. + */ #if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); #else diff -u --recursive --new-file v2.1.87/linux/include/linux/blkdev.h linux/include/linux/blkdev.h --- v2.1.87/linux/include/linux/blkdev.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/blkdev.h Fri Feb 20 19:12:38 1998 @@ -38,6 +38,9 @@ struct blk_dev_struct { request_fn_proc *request_fn; + /* + * queue_proc has to be atomic + */ queue_proc *queue; void *data; struct request *current_request; diff -u --recursive --new-file v2.1.87/linux/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h --- v2.1.87/linux/include/linux/coda_psdev.h Tue Jan 6 10:00:22 1998 +++ linux/include/linux/coda_psdev.h Fri Feb 20 18:28:23 1998 @@ -4,8 +4,6 @@ #define CODA_PSDEV_MAJOR 67 #define MAX_CODADEVS 5 /* how many do we allow */ -#include - extern struct vcomm psdev_vcomm[]; /* queue stuff; the rest is static to psdev.c */ diff -u --recursive --new-file v2.1.87/linux/include/linux/file.h linux/include/linux/file.h --- v2.1.87/linux/include/linux/file.h Sun Jul 13 21:20:10 1997 +++ linux/include/linux/file.h Fri Feb 20 15:04:45 1998 @@ -29,6 +29,7 @@ int error = 0; if (!count) { + locks_remove_flock(file); error = __fput(file); file->f_count = 0; remove_filp(file); diff -u --recursive --new-file v2.1.87/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.87/linux/include/linux/fs.h Thu Feb 12 20:56:13 1998 +++ linux/include/linux/fs.h Fri Feb 20 19:12:38 1998 @@ -446,7 +446,10 @@ extern int fcntl_getlk(unsigned int fd, struct flock *l); extern int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l); -extern void locks_remove_locks(struct task_struct *task, struct file *filp); + +/* fs/locks.c */ +extern void locks_remove_posix(struct task_struct *, struct file *); +extern void locks_remove_flock(struct file *); extern struct file_lock *posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, unsigned int); extern void posix_block_lock(struct file_lock *, struct file_lock *); diff -u --recursive --new-file v2.1.87/linux/include/linux/in_route.h linux/include/linux/in_route.h --- v2.1.87/linux/include/linux/in_route.h Mon Jan 12 15:28:18 1998 +++ linux/include/linux/in_route.h Thu Feb 19 14:46:15 1998 @@ -11,6 +11,7 @@ #define RTCF_NOTIFY 0x00010000 #define RTCF_DIRECTDST 0x00020000 #define RTCF_REDIRECTED 0x00040000 +#define RTCF_TPROXY 0x00080000 #define RTCF_FAST 0x00200000 #define RTCF_MASQ 0x00400000 diff -u --recursive --new-file v2.1.87/linux/include/linux/ipx.h linux/include/linux/ipx.h --- v2.1.87/linux/include/linux/ipx.h Fri Feb 6 15:33:34 1998 +++ linux/include/linux/ipx.h Fri Feb 20 19:13:19 1998 @@ -76,5 +76,12 @@ #define SIOCAIPXITFCRT (SIOCPROTOPRIVATE) #define SIOCAIPXPRISLT (SIOCPROTOPRIVATE+1) #define SIOCIPXCFGDATA (SIOCPROTOPRIVATE+2) -#endif +#ifdef __KERNEL__ +#include + +extern int ipxrtr_route_skb(struct sk_buff *); +extern int ipx_if_offset(unsigned long ipx_net_number); +#endif /* def __KERNEL__ */ + +#endif /* def _IPX_H_ */ diff -u --recursive --new-file v2.1.87/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.87/linux/include/linux/swap.h Thu Jan 15 20:13:21 1998 +++ linux/include/linux/swap.h Tue Feb 17 10:36:57 1998 @@ -81,7 +81,7 @@ * * Will go away eventually.. */ -#define SHM_SWP_TYPE 0x40 +#define SHM_SWP_TYPE 0x20 /* * swap cache stuff (in linux/mm/swap_state.c) diff -u --recursive --new-file v2.1.87/linux/include/linux/timer.h linux/include/linux/timer.h --- v2.1.87/linux/include/linux/timer.h Wed Feb 4 11:36:01 1998 +++ linux/include/linux/timer.h Fri Feb 20 18:29:38 1998 @@ -20,6 +20,7 @@ #define GSCD_TIMER 9 /* Goldstar CDROM */ #define COMTROL_TIMER 10 /* Comtrol serial */ #define DIGI_TIMER 11 /* Digi serial */ +#define GDTH_TIMER 12 /* Ugh - gdth scsi driver */ #define COPRO_TIMER 31 /* 387 timeout for buggy hardware (boot only) */ diff -u --recursive --new-file v2.1.87/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p --- v2.1.87/linux/include/linux/umsdos_fs.p Tue Feb 17 13:12:49 1998 +++ linux/include/linux/umsdos_fs.p Fri Feb 20 09:44:57 1998 @@ -1,6 +1,14 @@ /* check.c 23/01/95 03.38.30 */ void check_page_tables (void); /* dir.c 22/06/95 00.22.12 */ +struct dentry *creat_dentry (const char *name, + const int len, + struct inode *inode); +int compat_msdos_create(struct inode *dir, + const char *name, + int len, + int mode, + struct inode **inode); int UMSDOS_dir_read ( struct file *filp, char *buf, size_t size, @@ -14,10 +22,10 @@ struct umsdos_dirent *entry); int umsdos_locate_path (struct inode *inode, char *path); int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); -int compat_UMSDOS_lookup (struct inode *dir, - const char *name, - int len, - struct inode **result); +int umsdos_lookup_x ( + struct inode *dir, + struct dentry *dentry, + int nopseudo); int UMSDOS_lookup(struct inode *dir,struct dentry *dentry); int umsdos_hlink2inode (struct inode *hlink, struct inode **result); diff -u --recursive --new-file v2.1.87/linux/include/net/ip_masq.h linux/include/net/ip_masq.h --- v2.1.87/linux/include/net/ip_masq.h Fri Feb 6 15:35:11 1998 +++ linux/include/net/ip_masq.h Fri Feb 20 19:14:58 1998 @@ -2,6 +2,7 @@ * IP masquerading functionality definitions */ +#include /* for CONFIG_IP_MASQ_NDEBUG */ #ifndef _IP_MASQ_H #define _IP_MASQ_H diff -u --recursive --new-file v2.1.87/linux/include/net/ipx.h linux/include/net/ipx.h --- v2.1.87/linux/include/net/ipx.h Fri Feb 6 15:33:34 1998 +++ linux/include/net/ipx.h Fri Feb 20 19:13:19 1998 @@ -1,4 +1,3 @@ - /* * The following information is in its entirety obtained from: * @@ -12,7 +11,6 @@ #define _NET_INET_IPX_H_ #include -#include #include #include @@ -44,8 +42,6 @@ }; #include -extern int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); -extern void ipxrtr_device_down(struct device *dev); typedef struct ipx_interface { /* IPX address */ @@ -80,4 +76,4 @@ #define IPX_MIN_EPHEMERAL_SOCKET 0x4000 #define IPX_MAX_EPHEMERAL_SOCKET 0x7fff -#endif +#endif /* def _NET_INET_IPX_H_ */ diff -u --recursive --new-file v2.1.87/linux/include/net/profile.h linux/include/net/profile.h --- v2.1.87/linux/include/net/profile.h Fri Feb 6 15:33:34 1998 +++ linux/include/net/profile.h Fri Feb 20 18:28:23 1998 @@ -1,3 +1,4 @@ +#include /* for CONFIG_NET_PROFILE */ #ifndef _NET_PROFILE_H_ #define _NET_PROFILE_H_ 1 diff -u --recursive --new-file v2.1.87/linux/include/net/route.h linux/include/net/route.h --- v2.1.87/linux/include/net/route.h Fri Feb 6 15:34:56 1998 +++ linux/include/net/route.h Fri Feb 20 19:14:44 1998 @@ -61,6 +61,9 @@ #include +#define RTO_ONLINK 0x01 +#define RTO_TPROXY 0x80000000 + struct rt_key { __u32 dst; @@ -111,7 +114,7 @@ u32 src, u8 tos, struct device *dev); extern void ip_rt_advice(struct rtable **rp, int advice); extern void rt_cache_flush(int how); -extern int ip_route_output(struct rtable **, u32 dst, u32 src, u8 tos, int oif); +extern int ip_route_output(struct rtable **, u32 dst, u32 src, u32 tos, int oif); extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct device *devin); extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu); extern void ip_rt_send_redirect(struct sk_buff *skb); diff -u --recursive --new-file v2.1.87/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.87/linux/include/net/tcp.h Fri Feb 6 15:34:58 1998 +++ linux/include/net/tcp.h Fri Feb 20 19:14:46 1998 @@ -275,6 +275,9 @@ struct tcp_v6_open_req v6_req; #endif } af; +#ifdef CONFIG_IP_TRANSPARENT_PROXY + __u16 lcl_port; /* LVE */ +#endif }; /* SLAB cache for open requests. */ diff -u --recursive --new-file v2.1.87/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c --- v2.1.87/linux/net/802/llc_macinit.c Thu Feb 12 20:56:13 1998 +++ linux/net/802/llc_macinit.c Fri Feb 20 18:28:23 1998 @@ -19,7 +19,6 @@ * Started restructuring handlers */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/802/p8022.c linux/net/802/p8022.c --- v2.1.87/linux/net/802/p8022.c Thu Feb 12 20:56:14 1998 +++ linux/net/802/p8022.c Fri Feb 20 18:28:23 1998 @@ -16,7 +16,6 @@ * 4 entries at most). The current demux assumes this. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/802/p8022tr.c linux/net/802/p8022tr.c --- v2.1.87/linux/net/802/p8022tr.c Thu Feb 12 20:56:14 1998 +++ linux/net/802/p8022tr.c Fri Feb 20 18:28:23 1998 @@ -8,7 +8,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/802/psnap.c linux/net/802/psnap.c --- v2.1.87/linux/net/802/psnap.c Thu Feb 12 20:56:14 1998 +++ linux/net/802/psnap.c Fri Feb 20 18:28:23 1998 @@ -10,7 +10,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/802/tr.c linux/net/802/tr.c --- v2.1.87/linux/net/802/tr.c Thu Sep 4 13:25:28 1997 +++ linux/net/802/tr.c Thu Feb 19 14:59:53 1998 @@ -50,7 +50,7 @@ unsigned char addr[TR_ALEN]; unsigned char iface[5]; __u16 rcf; - __u8 rseg[8]; + __u16 rseg[8]; rif_cache next; unsigned long last_used; unsigned char local_ring; @@ -441,7 +441,7 @@ int len=0; off_t begin=0; off_t pos=0; - int size,i,j,rcf_len; + int size,i,j,rcf_len,segment,brdgnmb; unsigned long now=jiffies; rif_cache entry; @@ -466,10 +466,18 @@ rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2; if (rcf_len) rcf_len >>= 1; - for(j = 0; j < rcf_len; j++) { - len+=size; - pos=begin+len; - size=sprintf(buffer+len," %04X",ntohs(entry->rseg[j])); + for(j = 1; j < rcf_len; j++) { + if(j==1) { + segment=ntohs(entry->rseg[j-1])>>4; + len+=size; + pos=begin+len; + size=sprintf(buffer+len," %03X",segment); + }; + segment=ntohs(entry->rseg[j])>>4; + brdgnmb=ntohs(entry->rseg[j-1])&0x00f; + len+=size; + pos=begin+len; + size=sprintf(buffer+len,"-%01X-%03X",brdgnmb,segment); } len+=size; pos=begin+len; diff -u --recursive --new-file v2.1.87/linux/net/Config.in linux/net/Config.in --- v2.1.87/linux/net/Config.in Tue Jan 13 20:15:35 1998 +++ linux/net/Config.in Thu Feb 19 14:46:15 1998 @@ -27,7 +27,7 @@ comment ' ' tristate 'The IPX protocol' CONFIG_IPX if [ "$CONFIG_IPX" != "n" ]; then - bool 'Full internal IPX network' CONFIG_IPX_INTERN + source net/ipx/Config.in fi tristate 'Appletalk DDP' CONFIG_ATALK if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --recursive --new-file v2.1.87/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c --- v2.1.87/linux/net/ax25/sysctl_net_ax25.c Mon Jul 7 08:19:59 1997 +++ linux/net/ax25/sysctl_net_ax25.c Fri Feb 20 18:28:23 1998 @@ -8,7 +8,6 @@ #include #include #include -#include #include static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; diff -u --recursive --new-file v2.1.87/linux/net/core/firewall.c linux/net/core/firewall.c --- v2.1.87/linux/net/core/firewall.c Tue May 13 22:41:21 1997 +++ linux/net/core/firewall.c Fri Feb 20 18:28:23 1998 @@ -6,7 +6,6 @@ * much hacked by: Alan Cox */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.1.87/linux/net/ipv4/Config.in Thu Jan 15 14:33:07 1998 +++ linux/net/ipv4/Config.in Thu Feb 19 14:46:15 1998 @@ -37,14 +37,16 @@ fi fi bool 'IP: accounting' CONFIG_IP_ACCT -bool 'IP: masquerading' CONFIG_IP_MASQUERADE -if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then - comment 'Protocol-specific masquerading support will be built as modules.' - bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP - comment 'Protocol-specific masquerading support will be built as modules.' - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW - tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW +if [ "$CONFIG_IP_FIREWALL" = "y" ]; then + bool 'IP: masquerading' CONFIG_IP_MASQUERADE + if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then + comment 'Protocol-specific masquerading support will be built as modules.' + bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP + comment 'Protocol-specific masquerading support will be built as modules.' + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW + tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW + fi fi fi bool 'IP: optimize as router not host' CONFIG_IP_ROUTER diff -u --recursive --new-file v2.1.87/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.87/linux/net/ipv4/arp.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/arp.c Thu Feb 19 14:46:15 1998 @@ -899,7 +899,6 @@ int len=0; off_t pos=0; int size; - struct neighbour *n; char hbuffer[HBUFFERLEN]; int i,j,k; const char hexbuf[] = "0123456789ABCDEF"; @@ -912,6 +911,7 @@ neigh_table_lock(&arp_tbl); for(i=0; i<=NEIGH_HASHMASK; i++) { + struct neighbour *n; for (n=arp_tbl.hash_buckets[i]; n; n=n->next) { struct device *dev = n->dev; int hatype = dev->type; @@ -957,6 +957,32 @@ size += sprintf(buffer+len+size, " %-17s %s\n", "*", dev->name); + + len += size; + pos += size; + + if (pos <= offset) + len=0; + if (pos >= offset+length) + goto done; + } + } + + for (i=0; i<=PNEIGH_HASHMASK; i++) { + struct pneigh_entry *n; + for (n=arp_tbl.phash_buckets[i]; n; n=n->next) { + struct device *dev = n->dev; + int hatype = dev ? dev->type : 0; + + size = sprintf(buffer+len, + "%-17s0x%-10x0x%-10x%s", + in_ntoa(*(u32*)n->key), + hatype, + ATF_PUBL|ATF_PERM, + "00:00:00:00:00:00"); + size += sprintf(buffer+len+size, + " %-17s %s\n", + "*", dev ? dev->name : "*"); len += size; pos += size; diff -u --recursive --new-file v2.1.87/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.1.87/linux/net/ipv4/devinet.c Tue Feb 17 13:12:50 1998 +++ linux/net/ipv4/devinet.c Thu Feb 19 14:46:16 1998 @@ -418,6 +418,7 @@ break; case SIOCSIFFLAGS: + case SIOCSIFPFLAGS: /* Set per device sysctl controls */ if (!suser()) return -EACCES; rtnl_lock(); @@ -427,7 +428,6 @@ case SIOCSIFBRDADDR: /* Set the broadcast address */ case SIOCSIFDSTADDR: /* Set the destination address */ case SIOCSIFNETMASK: /* Set the netmask for the interface */ - case SIOCSIFPFLAGS: /* Set per device sysctl controls */ if (!suser()) return -EACCES; if (sin->sin_family != AF_INET) diff -u --recursive --new-file v2.1.87/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.1.87/linux/net/ipv4/fib_frontend.c Mon Jan 12 15:28:27 1998 +++ linux/net/ipv4/fib_frontend.c Thu Feb 19 14:46:16 1998 @@ -536,6 +536,10 @@ rt_cache_flush(0); arp_ifdown(dev); break; + case NETDEV_CHANGEMTU: + case NETDEV_CHANGE: + rt_cache_flush(1*HZ); + break; } return NOTIFY_DONE; } diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.1.87/linux/net/ipv4/ip_fw.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/ip_fw.c Fri Feb 20 18:28:23 1998 @@ -90,7 +90,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c --- v2.1.87/linux/net/ipv4/ip_gre.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/ip_gre.c Thu Feb 19 14:46:16 1998 @@ -628,7 +628,7 @@ goto tx_error; addr6 = (struct in6_addr*)&neigh->primary_key; - addr_type = neigh->type; + addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { addr6 = &skb->nh.ipv6h->daddr; diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c --- v2.1.87/linux/net/ipv4/ip_masq_ftp.c Wed Dec 10 09:45:16 1997 +++ linux/net/ipv4/ip_masq_ftp.c Fri Feb 20 18:28:23 1998 @@ -37,7 +37,6 @@ * */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c --- v2.1.87/linux/net/ipv4/ip_masq_irc.c Wed Dec 10 09:45:16 1997 +++ linux/net/ipv4/ip_masq_irc.c Fri Feb 20 18:28:23 1998 @@ -40,7 +40,6 @@ * */ -#include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_masq_quake.c linux/net/ipv4/ip_masq_quake.c --- v2.1.87/linux/net/ipv4/ip_masq_quake.c Wed Dec 10 09:45:16 1997 +++ linux/net/ipv4/ip_masq_quake.c Fri Feb 20 18:28:23 1998 @@ -21,7 +21,6 @@ * */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c --- v2.1.87/linux/net/ipv4/ip_masq_raudio.c Wed Dec 10 09:45:16 1997 +++ linux/net/ipv4/ip_masq_raudio.c Fri Feb 20 18:28:23 1998 @@ -62,7 +62,6 @@ * */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.1.87/linux/net/ipv4/ip_output.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/ip_output.c Thu Feb 19 14:46:16 1998 @@ -29,6 +29,7 @@ * Alexey Kuznetsov: use new route cache * Andi Kleen: Fix broken PMTU recovery and remove * some redundant tests. + * Vitaly E. Lavrov : Transparent proxy revived after year coma. */ #include @@ -91,6 +92,13 @@ daddr = opt->faddr; err = ip_route_output(&rt, daddr, saddr, RT_TOS(sk->ip_tos) | +#ifdef CONFIG_IP_TRANSPARENT_PROXY + /* Rationale: this routine is used only + by TCP, so that validity of saddr is already + checked and we can safely use RTO_TPROXY. + */ + RTO_TPROXY | +#endif (sk->localroute||0), sk->bound_dev_if); if (err) { diff -u --recursive --new-file v2.1.87/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c --- v2.1.87/linux/net/ipv4/ipip.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/ipip.c Fri Feb 20 18:28:23 1998 @@ -93,7 +93,6 @@ */ -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.1.87/linux/net/ipv4/route.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/route.c Thu Feb 19 14:46:16 1998 @@ -46,6 +46,7 @@ * Alexey Kuznetsov : End of old history. Splitted to fib.c and * route.c and rewritten from scratch. * Andi Kleen : Load-limit warning messages. + * Vitaly E. Lavrov : Transparent proxy revived after year coma. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -161,7 +162,7 @@ pos = 128; if (offset<128) { - sprintf(buffer,"%-127s\n", "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\tMetric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\tHHUptod\tSpecDst\tHash"); + sprintf(buffer,"%-127s\n", "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\tMetric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\tHHUptod\tSpecDst"); len = 128; } @@ -179,8 +180,7 @@ len = 0; continue; } - - sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X\t%02X", + sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X", r->u.dst.dev ? r->u.dst.dev->name : "*", (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway, @@ -193,8 +193,7 @@ (int)r->u.dst.rtt, r->key.tos, r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1, r->u.dst.hh ? (r->u.dst.hh->hh_output == ip_acct_output) : 0, - r->rt_spec_dst, - i); + r->rt_spec_dst); sprintf(buffer+len,"%-127s\n",temp); len += 128; if (pos >= offset+length) @@ -278,14 +277,8 @@ for (i=0; iu.rt_next; @@ -1110,7 +1103,7 @@ * Major route resolver routine. */ -int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u8 tos, int oif) +int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) { struct rt_key key; struct fib_result res; @@ -1118,14 +1111,17 @@ struct rtable *rth; struct device *dev_out = NULL; unsigned hash; +#ifdef CONFIG_IP_TRANSPARENT_PROXY + u32 nochecksrc = (tos & RTO_TPROXY); +#endif - tos &= IPTOS_TOS_MASK|1; + tos &= IPTOS_TOS_MASK|RTO_ONLINK; key.dst = daddr; key.src = saddr; key.tos = tos&IPTOS_TOS_MASK; key.iif = loopback_dev.ifindex; key.oif = oif; - key.scope = (tos&1) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; + key.scope = (tos&RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; res.fi = NULL; if (saddr) { @@ -1134,8 +1130,19 @@ /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(saddr); +#ifdef CONFIG_IP_TRANSPARENT_PROXY + /* If address is not local, test for transparent proxy flag; + if address is local --- clear the flag. + */ + if (dev_out == NULL) { + if (nochecksrc == 0) + return -EINVAL; + flags |= RTCF_TPROXY; + } +#else if (dev_out == NULL) return -EINVAL; +#endif /* I removed check for oif == dev_out->oif here. It was wrong by three reasons: @@ -1145,7 +1152,11 @@ of another iface. --ANK */ - if (oif == 0 && (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) { + if (oif == 0 && +#ifdef CONFIG_IP_TRANSPARENT_PROXY + dev_out && +#endif + (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) { /* Special hack: user can direct multicasts and limited broadcast via necessary interface without fiddling with IP_MULTICAST_IF or IP_TXINFO. @@ -1343,7 +1354,7 @@ return 0; } -int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u8 tos, int oif) +int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) { unsigned hash; struct rtable *rth; @@ -1356,7 +1367,13 @@ rth->key.src == saddr && rth->key.iif == 0 && rth->key.oif == oif && - rth->key.tos == tos) { +#ifndef CONFIG_IP_TRANSPARENT_PROXY + rth->key.tos == tos +#else + !((rth->key.tos^tos)&(IPTOS_TOS_MASK|RTO_ONLINK)) && + ((tos&RTO_TPROXY) || !(rth->rt_flags&RTCF_TPROXY)) +#endif + ) { rth->u.dst.lastuse = jiffies; atomic_inc(&rth->u.dst.use); atomic_inc(&rth->u.dst.refcnt); diff -u --recursive --new-file v2.1.87/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.87/linux/net/ipv4/tcp_ipv4.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/tcp_ipv4.c Thu Feb 19 14:46:16 1998 @@ -42,6 +42,7 @@ * NEW_LISTEN for now) * Juan Jose Ciarlante: ip_dynaddr bits * Andi Kleen: various fixes. + * Vitaly E. Lavrov : Transparent proxy revived after year coma. */ #include @@ -1082,7 +1083,12 @@ memset(th, 0, sizeof(struct tcphdr)); th->syn = 1; th->ack = 1; + th->source = +#ifdef CONFIG_IP_TRANSPARENT_PROXY + req->lcl_port; /* LVE */ +#else th->source = sk->dummy_th.source; +#endif th->dest = req->rmt_port; skb->seq = req->snt_isn; skb->end_seq = skb->seq + 1; @@ -1239,6 +1245,9 @@ req->snd_wscale = tp.snd_wscale; req->wscale_ok = tp.wscale_ok; req->rmt_port = th->source; +#ifdef CONFIG_IP_TRANSPARENT_PROXY + req->lcl_port = th->dest ; /* LVE */ +#endif req->af.v4_req.loc_addr = daddr; req->af.v4_req.rmt_addr = saddr; @@ -1361,7 +1370,12 @@ tcp_init_xmit_timers(newsk); - newsk->dummy_th.source = sk->dummy_th.source; + newsk->dummy_th.source = +#ifdef CONFIG_IP_TRANSPARENT_PROXY + req->lcl_port; /* LVE */ +#else + sk->dummy_th.source; +#endif newsk->dummy_th.dest = req->rmt_port; newsk->sock_readers=0; @@ -1371,6 +1385,13 @@ newsk->socket = NULL; +#ifdef CONFIG_IP_TRANSPARENT_PROXY + /* + * Deal with possibly redirected traffic by setting num to + * the intended destination port of the received packet. + */ + newsk->num = ntohs(skb->h.th->dest); +#endif newsk->daddr = req->af.v4_req.rmt_addr; newsk->saddr = req->af.v4_req.loc_addr; newsk->rcv_saddr = req->af.v4_req.loc_addr; diff -u --recursive --new-file v2.1.87/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.87/linux/net/ipv4/udp.c Thu Feb 12 20:56:14 1998 +++ linux/net/ipv4/udp.c Thu Feb 19 14:46:16 1998 @@ -55,6 +55,7 @@ * Olaf Kirch : Don't linearise iovec on sendmsg. * Andi Kleen : Some cleanups, cache destination entry * for connect. + * Vitaly E. Lavrov : Transparent proxy revived after year coma. * * * This program is free software; you can redistribute it and/or @@ -360,14 +361,14 @@ #ifdef CONFIG_IP_TRANSPARENT_PROXY #define secondlist(hpnum, sk, fpass) \ ({ struct sock *s1; if(!(sk) && (fpass)--) \ - s1 = udp_hash[(hpnum) & (TCP_HTABLE_SIZE - 1)]; \ + s1 = udp_hash[(hpnum) & (UDP_HTABLE_SIZE - 1)]; \ else \ s1 = (sk); \ s1; \ }) #define udp_v4_proxy_loop_init(hnum, hpnum, sk, fpass) \ - secondlist((hpnum), udp_hash[(hnum)&(TCP_HTABLE_SIZE-1)],(fpass)) + secondlist((hpnum), udp_hash[(hnum)&(UDP_HTABLE_SIZE-1)],(fpass)) #define udp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \ secondlist((hpnum),(sk)->next,(fpass)) @@ -641,8 +642,15 @@ if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; +#ifdef CONFIG_IP_TRANSPARENT_PROXY + if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT|MSG_PROXY)) + return -EINVAL; + if ((msg->msg_flags&MSG_PROXY) && !suser() ) + return -EPERM; +#else if (msg->msg_flags&~(MSG_DONTROUTE|MSG_DONTWAIT)) return -EINVAL; +#endif /* * Get and verify the address. @@ -685,8 +693,27 @@ */ rt = (struct rtable *)dst_check(&sk->dst_cache, 0); } +#ifdef CONFIG_IP_TRANSPARENT_PROXY + if (msg->msg_flags&MSG_PROXY) { + /* + * We map the first 8 bytes of a second sockaddr_in + * into the last 8 (unused) bytes of a sockaddr_in. + */ + struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name; + from = (struct sockaddr_in *)&from->sin_zero; + if (from->sin_family != AF_INET) + return -EINVAL; + ipc.addr = from->sin_addr.s_addr; + ufh.uh.source = from->sin_port; + if (ipc.addr == 0) + ipc.addr = sk->saddr; + } else +#endif + { + ipc.addr = sk->saddr; + ufh.uh.source = sk->dummy_th.source; + } - ipc.addr = sk->saddr; ipc.opt = NULL; ipc.oif = sk->bound_dev_if; if (msg->msg_controllen) { @@ -710,7 +737,7 @@ tos = RT_TOS(sk->ip_tos); if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || (ipc.opt && ipc.opt->is_strictroute)) { - tos |= 1; + tos |= RTO_ONLINK; rt = NULL; /* sorry */ } @@ -722,7 +749,11 @@ } if (rt == NULL) { - err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif); + err = ip_route_output(&rt, daddr, ufh.saddr, +#ifdef CONFIG_IP_TRANSPARENT_PROXY + (msg->msg_flags&MSG_PROXY ? RTO_TPROXY : 0) | +#endif + tos, ipc.oif); if (err) goto out; localroute = 1; @@ -735,7 +766,6 @@ ufh.saddr = rt->rt_src; if (!ipc.addr) ufh.daddr = ipc.addr = rt->rt_dst; - ufh.uh.source = sk->dummy_th.source; ufh.uh.len = htons(ulen); ufh.uh.check = 0; ufh.other = (htons(ulen) << 16) + IPPROTO_UDP*256; diff -u --recursive --new-file v2.1.87/linux/net/ipv6/Config.in linux/net/ipv6/Config.in --- v2.1.87/linux/net/ipv6/Config.in Mon Jan 12 15:28:28 1998 +++ linux/net/ipv6/Config.in Thu Feb 19 14:46:16 1998 @@ -3,7 +3,7 @@ # bool 'IPv6: enable EUI-64 token format' CONFIG_IPV6_EUI64 if [ "$CONFIG_IPV6_EUI64" = "y" ]; then - bool 'IPv6: disable provided based addresses' CONFIG_IPV6_NO_PB + bool 'IPv6: disable provider based addresses' CONFIG_IPV6_NO_PB fi if [ "$CONFIG_NETLINK" = "y" ]; then if [ "$CONFIG_RTNETLINK" = "n" ]; then diff -u --recursive --new-file v2.1.87/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.87/linux/net/ipv6/addrconf.c Tue Feb 17 13:12:50 1998 +++ linux/net/ipv6/addrconf.c Thu Feb 19 14:59:53 1998 @@ -1091,8 +1091,12 @@ } break; + case NETDEV_CHANGEMTU: + case NETDEV_CHANGE: + /* BUGGG... Should scan FIB to change pmtu on routes. --ANK */ + break; }; - + return NOTIFY_OK; } diff -u --recursive --new-file v2.1.87/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.1.87/linux/net/ipv6/route.c Tue Feb 17 13:12:50 1998 +++ linux/net/ipv6/route.c Thu Feb 19 14:59:53 1998 @@ -836,7 +836,7 @@ if (fn->fn_flags & RTN_ROOT) break; if (fn->fn_flags & RTN_RTINFO) { - rt = rt6_device_match(rt, dev, RTF_LINKRT); + rt = rt6_device_match(fn->leaf, dev, RTF_LINKRT); goto restart; } } @@ -1743,7 +1743,7 @@ struct sk_buff *skb; int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); - skb = alloc_skb(size, GFP_KERNEL); + skb = alloc_skb(size, GFP_ATOMIC); if (!skb) { netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS); return; diff -u --recursive --new-file v2.1.87/linux/net/ipv6/sit.c linux/net/ipv6/sit.c --- v2.1.87/linux/net/ipv6/sit.c Thu Feb 12 20:56:15 1998 +++ linux/net/ipv6/sit.c Fri Feb 20 18:28:23 1998 @@ -14,7 +14,6 @@ * 2 of the License, or (at your option) any later version. */ -#include #define __NO_VERSION__ #include #include @@ -404,7 +403,7 @@ } addr6 = (struct in6_addr*)&neigh->primary_key; - addr_type = neigh->type; + addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { addr6 = &skb->nh.ipv6h->daddr; diff -u --recursive --new-file v2.1.87/linux/net/ipx/Config.in linux/net/ipx/Config.in --- v2.1.87/linux/net/ipx/Config.in Wed Dec 31 16:00:00 1969 +++ linux/net/ipx/Config.in Thu Feb 19 14:46:15 1998 @@ -0,0 +1,6 @@ +# +# IPX configuration +# + +comment 'IPX options' +bool 'Full internal IPX network' CONFIG_IPX_INTERN diff -u --recursive --new-file v2.1.87/linux/net/ipx/Makefile linux/net/ipx/Makefile --- v2.1.87/linux/net/ipx/Makefile Mon Apr 7 11:35:33 1997 +++ linux/net/ipx/Makefile Thu Feb 19 14:46:15 1998 @@ -1,5 +1,5 @@ # -# Makefile for the Linux TCP/IP (INET) layer. +# Makefile for the Linux IPX layer. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -7,12 +7,14 @@ # # Note 2! The CFLAGS definition is now in the main makefile... +# We only get in/to here if CONFIG_IPX = 'y' or 'm' + O_TARGET := ipx.o -O_OBJS := af_ipx.o M_OBJS := $(O_TARGET) +OX_OBJS += af_ipx.o ifeq ($(CONFIG_SYSCTL),y) -O_OBJS += sysctl_net_ipx.o + O_OBJS += sysctl_net_ipx.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.87/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.1.87/linux/net/ipx/af_ipx.c Thu Feb 12 20:56:15 1998 +++ linux/net/ipx/af_ipx.c Thu Feb 19 14:46:15 1998 @@ -214,7 +214,6 @@ } sk_free(sk); - MOD_DEC_USE_COUNT; } /* The following code is used to support IPX Interfaces (IPXITF). An @@ -682,7 +681,6 @@ static const char * ipx_frame_name(unsigned short); static const char * ipx_device_name(ipx_interface *); -static int ipxrtr_route_skb(struct sk_buff *); static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb) { @@ -1391,7 +1389,7 @@ rt->ir_router_node : ipx->ipx_dest.node); } -static int ipxrtr_route_skb(struct sk_buff *skb) +int ipxrtr_route_skb(struct sk_buff *skb) { struct ipxhdr *ipx = skb->nh.ipxh; ipx_route *r; @@ -1720,8 +1718,11 @@ switch(sock->type) { case SOCK_DGRAM: - sock->ops = &ipx_dgram_ops; - break; + sock->ops = &ipx_dgram_ops; + break; + case SOCK_STREAM: /* Allow higher levels to piggyback */ + case SOCK_SEQPACKET: + printk(KERN_CRIT "IPX: _create-ing non_DGRAM socket\n"); default: sk_free(sk); return(-ESOCKTNOSUPPORT); @@ -1744,6 +1745,9 @@ sk->dead=1; sock->sk=NULL; ipx_destroy_socket(sk); + if ( sock->type == SOCK_DGRAM ) { + MOD_DEC_USE_COUNT; + } return(0); } @@ -1819,7 +1823,9 @@ sk->protinfo.af_ipx.node, sk->protinfo.af_ipx.port) != NULL) { - SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", (int)addr->sipx_port); + SOCK_DEBUG(sk, + "IPX: bind failed because port %X in use.\n", + ntohs((int)addr->sipx_port)); return -EADDRINUSE; } } @@ -1834,7 +1840,9 @@ IPX_NODE_LEN); if(ipxitf_find_socket(intrfc, addr->sipx_port)!=NULL) { - SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", (int)addr->sipx_port); + SOCK_DEBUG(sk, + "IPX: bind failed because port %X in use.\n", + ntohs((int)addr->sipx_port)); return -EADDRINUSE; } } @@ -1845,7 +1853,8 @@ an interface routed to IPX with the ipx routing ioctl() */ if(ipxitf_find_socket(intrfc, addr->sipx_port)!=NULL) { - SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", (int)addr->sipx_port); + SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", + ntohs((int)addr->sipx_port)); return -EADDRINUSE; } @@ -1853,7 +1862,8 @@ ipxitf_insert_socket(intrfc, sk); sk->zapped=0; - SOCK_DEBUG(sk, "IPX: socket is bound.\n"); + SOCK_DEBUG(sk, "IPX: bound socket 0x%04X.\n", ntohs(addr->sipx_port) ); + return 0; } @@ -1894,8 +1904,10 @@ memcpy(sk->protinfo.af_ipx.dest_addr.node, addr->sipx_node,IPX_NODE_LEN); sk->protinfo.af_ipx.type=addr->sipx_type; - sock->state = SS_CONNECTED; - sk->state=TCP_ESTABLISHED; + if(sock->type == SOCK_DGRAM ) { + sock->state = SS_CONNECTED; + sk->state=TCP_ESTABLISHED; + } return 0; } @@ -2346,6 +2358,19 @@ printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n"); } +/* Higher layers need this info to prep tx pkts */ +int ipx_if_offset(unsigned long ipx_net_number) +{ + ipx_route *rt = NULL; + + rt = ipxrtr_lookup(ipx_net_number); + return ( rt ? rt->ir_intrfc->if_ipx_offset : -ENETUNREACH ); +} + +/* Export symbols for higher layers */ +EXPORT_SYMBOL(ipxrtr_route_skb); +EXPORT_SYMBOL(ipx_if_offset); + #ifdef MODULE /* Note on MOD_{INC,DEC}_USE_COUNT: * @@ -2399,8 +2424,6 @@ return; } - -EXPORT_NO_SYMBOLS; int init_module(void) { diff -u --recursive --new-file v2.1.87/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c --- v2.1.87/linux/net/sched/sch_sfq.c Thu Feb 12 20:56:15 1998 +++ linux/net/sched/sch_sfq.c Fri Feb 20 18:28:23 1998 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.1.87/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.1.87/linux/net/sunrpc/clnt.c Mon Jan 12 14:39:07 1998 +++ linux/net/sunrpc/clnt.c Fri Feb 20 18:28:23 1998 @@ -21,8 +21,6 @@ * Copyright (C) 1995,1996 Olaf Kirch */ -#include - #include #include diff -u --recursive --new-file v2.1.87/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c --- v2.1.87/linux/net/wanrouter/wanmain.c Fri Jan 30 11:28:10 1998 +++ linux/net/wanrouter/wanmain.c Fri Feb 20 18:28:23 1998 @@ -27,7 +27,6 @@ #include /* offsetof(), etc. */ #include /* return codes */ -#include /* OS configuration options */ #include #include /* support for loadable modules */ #include /* kmalloc(), kfree() */