diff -u --recursive --new-file v2.0.0/linux/Documentation/Changes linux/Documentation/Changes --- v2.0.0/linux/Documentation/Changes Thu Jun 6 22:35:43 1996 +++ linux/Documentation/Changes Sat Jun 29 12:00:45 1996 @@ -491,8 +491,13 @@ Linux C++ Library ================= +ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.4.bin.tar.gz + +Use libc5.2.18 with 2.7.1.3, libc5.3.12 with 2.7.1.4 + Installation notes: +ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.4 Dynamic Linker diff -u --recursive --new-file v2.0.0/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v2.0.0/linux/Documentation/devices.tex Mon May 13 23:02:46 1996 +++ linux/Documentation/devices.tex Mon Jun 10 08:14:43 1996 @@ -42,7 +42,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: May 12, 1996} +\date{Last revised: June 9, 1996} \maketitle % \noindent @@ -78,6 +78,10 @@ In particular, please don't sent patches for this list to Linus, at least not without contacting me first. +I do not have any information about these devices beyond what appears +on this list. Any such information requests will be deleted without +reply. + \section{Major numbers} \begin{devicelist} @@ -157,7 +161,7 @@ \major{39}{}{char }{ML-16P experimental I/O board} \major{ }{}{block}{Reserved for Linux/AP+} \major{40}{}{char }{Matrox Meteor frame grabber} -\major{ }{}{block}{Syquest EZ135 removable drive} +\major{ }{}{block}{Syquest EZ135 parallel port removable drive} \major{41}{}{char }{Yet Another Micro Monitor} \major{42}{}{}{Demo/sample use} \major{43}{}{char }{isdn4linux virtual modem} @@ -169,7 +173,9 @@ \major{49}{}{char }{SDL RISCom serial card -- alternate devices} \major{50}{}{char }{Reserved for GLINT} \major{51}{}{char }{Baycom radio modem} -\major{52}{--59}{}{Unallocated} +\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} +\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers} +\major{54}{--59}{}{Unallocated} \major{60}{--63}{}{Local/experimental use} \major{64}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} @@ -972,8 +978,8 @@ \major{40}{}{char }{Matrox Meteor frame grabber} \minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber} \\ -\major{ }{}{block}{Syquest EZ135 removable drive} - \minor{0}{/dev/eza}{First EZ135 drive whole disk} +\major{ }{}{block}{Syquest EZ135 parallel port removable drive} + \minor{0}{/dev/eza}{Parallel EZ135 drive whole disk} \end{devicelist} \noindent @@ -1065,7 +1071,32 @@ \end{devicelist} \begin{devicelist} -\major{52}{--59}{}{Unallocated} +\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} + \minor{0}{/dev/dcbri0}{First DataComm card} + \minor{1}{/dev/dcbri1}{Second DataComm card} + \minor{2}{/dev/dcbri2}{Third DataComm card} + \minor{3}{/dev/dcbri3}{Fourth DataComm card} +\end{devicelist} + +\begin{devicelist} +\major{53}{}{char }{BDM interface for remote debugging MC683xx +microcontrollers} + \minor{0}{/dev/pd\_bdm0}{PD BDM interface on {\file lp0}} + \minor{1}{/dev/pd\_bdm1}{PD BDM interface on {\file lp1}} + \minor{2}{/dev/pd\_bdm2}{PD BDM interface on {\file lp2}} + \minor{4}{/dev/icd\_bdm0}{ICD BDM interface on {\file lp0}} + \minor{5}{/dev/icd\_bdm1}{ICD BDM interface on {\file lp1}} + \minor{6}{/dev/icd\_bdm2}{ICD BDM interface on {\file lp2}} +\end{devicelist} + +\noindent +This device is used for the interfacing to the MC683xx +microcontrollers via Background Debug Mode by use of a Parallel Port +interface. PD is the Motorola Public Domain Interface and ICD is the +commercial interface by P\&E. + +\begin{devicelist} +\major{54}{--59}{}{Unallocated} \end{devicelist} \begin{devicelist} @@ -1119,7 +1150,8 @@ \end{nodelist} \noindent -Note: The last device is: letter {\tt X}-digit {\tt 0}-letter {\tt R}. +Note: The last device is: $<$letter {\tt X}$>$-$<$digit {\tt +0}$>$-$<$letter {\tt R}$>$. \subsection{Recommended links} @@ -1128,6 +1160,7 @@ \begin{nodelist} \link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility} \link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility} +\link{/dev/ftape}{rft0}{symbolic}{Backward compatibility} \link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs} %\link{/dev/fd?H*}{fd?D*}{hard}{Compatible floppy formats} %\link{/dev/fd?E*}{fd?D*}{hard}{Compatible floppy formats} diff -u --recursive --new-file v2.0.0/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.0.0/linux/Documentation/devices.txt Mon May 13 23:02:46 1996 +++ linux/Documentation/devices.txt Mon Jun 10 08:14:47 1996 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - Last revised: May 12, 1996 + Last revised: June 9, 1996 This list is the successor to Rick Miller's Linux Device List, which he stopped maintaining when he got busy with other things in 1993. It @@ -35,6 +35,10 @@ In particular, please don't sent patches for this list to Linus, at least not without contacting me first. +I do not have any information about these devices beyond what appears +on this list. Any such information requests will be deleted without +reply. + 0 Unnamed devices (e.g. non-device mounts) 0 = reserved as null device number @@ -461,7 +465,14 @@ 3 = /dev/sbpcd7 Panasonic CD-ROM controller 1 unit 3 27 char QIC-117 tape - 0 = /dev/ftape QIC-117 tape + 0 = /dev/rft0 Unit 0, rewind-on-close + 1 = /dev/rft1 Unit 1, rewind-on-close + 2 = /dev/rft2 Unit 2, rewind-on-close + 3 = /dev/rft3 Unit 3, rewind-on-close + 4 = /dev/nrft0 Unit 0, no rewind-on-close + 5 = /dev/nrft1 Unit 1, no rewind-on-close + 6 = /dev/nrft2 Unit 2, no rewind-on-close + 7 = /dev/nrft3 Unit 3, no rewind-on-close block Third Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd8 Panasonic CD-ROM controller 2 unit 0 1 = /dev/sbpcd9 Panasonic CD-ROM controller 2 unit 1 @@ -670,8 +681,8 @@ 40 char Matrox Meteor frame grabber 0 = /dev/mmetfgrab Matrox Meteor frame grabber - block Syquest EZ135 removable drive - 0 = /dev/eza First EZ135 drive, whole disk + block Syquest EZ135 parallel port removable drive + 0 = /dev/eza Parallel EZ135 drive, whole disk Partitions are handled in the same way as IDE disks (see major number 3). @@ -740,7 +751,27 @@ 1 = /dev/bc1 Second Baycom radio modem ... - 52-59 UNALLOCATED + 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 + + 53 char BDM interface for remote debugging MC683xx microcontrollers + 0 = /dev/pd_bdm0 PD BDM interface on lp0 + 1 = /dev/pd_bdm1 PD BDM interface on lp1 + 2 = /dev/pd_bdm2 PD BDM interface on lp2 + 4 = /dev/icd_bdm0 ICD BDM interface on lp0 + 5 = /dev/icd_bdm1 ICD BDM interface on lp1 + 6 = /dev/icd_bdm2 ICD BDM interface on lp2 + + This device is used for the interfacing to the MC683xx + microcontrollers via Background Debug Mode by use of a + Parallel Port interface. PD is the Motorola Public + Domain Interface and ICD is the commercial interface + by P&E. + + 54-59 UNALLOCATED 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not @@ -780,7 +811,7 @@ /dev/nfsd socksys symbolic Required by iBCS-2 /dev/X0R null symbolic Required by iBCS-2 -Note: the last device is letter X-digit 0-letter R. +Note: the last device is --. Recommended links @@ -788,6 +819,7 @@ /dev/core /proc/kcore symbolic Backward compatibility /dev/ramdisk ram0 symbolic Backward compatibility +/dev/ftape rft0 symbolic Backward compatibility /dev/scd? sr? hard Alternate SCSI CD-ROM name diff -u --recursive --new-file v2.0.0/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.0.0/linux/Documentation/ioctl-number.txt Sat Jun 1 20:11:29 1996 +++ linux/Documentation/ioctl-number.txt Wed Jun 26 11:05:25 1996 @@ -1,5 +1,5 @@ Ioctl Numbers -29 May 1996 +12 Jun 1996 Michael Chastain @@ -98,6 +98,7 @@ 't' 80-8F linux/isdn_ppp.h 'u' all linux/smb_fs.h 'v' all linux/ext2_fs.h +'w' all CERN SCI driver (in development) 0x89 00-0F asm-i386/sockios.h 0x89 10-FF linux/sockios.h 0x90 00 linux/sbpcd.h diff -u --recursive --new-file v2.0.0/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v2.0.0/linux/Documentation/isdn/INTERFACE Mon May 20 08:20:58 1996 +++ linux/Documentation/isdn/INTERFACE Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.2 1996/05/18 15:58:53 fritz Exp $ +$Id: INTERFACE,v 1.3 1996/06/25 17:52:41 fritz Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -255,7 +255,7 @@ This command is intended for performing ioctl-calls for configuring hardware or similar purposes (setting port-addresses, loading firmware etc.) For this purpose, in the LL all ioctl-calls with an argument - >= ISDN_IOCTL_DRVIOCTL (0x100) will be handed transparently to this + >= IIOCDRVCTL (0x100) will be handed transparently to this function after subtracting 0x100 and placing the result in arg. Example: If a userlevel-program calls ioctl(0x101,...) the function gets @@ -264,7 +264,7 @@ Parameter: driver = driver-Id. command = ISDN_CMD_IOCTL - arg = Original ioctl-cmd - ISDN_IOCTL_DRVIOCTL + arg = Original ioctl-cmd - IIOCDRVCTL num = first bytes filled with (unsigned long)arg Returnvalue: diff -u --recursive --new-file v2.0.0/linux/Documentation/isdn/README.teles linux/Documentation/isdn/README.teles --- v2.0.0/linux/Documentation/isdn/README.teles Wed Feb 28 08:32:54 1996 +++ linux/Documentation/isdn/README.teles Sat Jun 29 20:36:22 1996 @@ -43,8 +43,9 @@ 4 D channel Q.931 (call control messages) 8 D channel Q.921 16 B channel X.75 + 32 Lowlevel (irq and Layer1 stuff) -For example 'teles/telesctrl MyTeles 1 31' enables full +For example 'teles/telesctrl MyTeles 1 63' enables full debugging. Questions diff -u --recursive --new-file v2.0.0/linux/Documentation/logo.txt linux/Documentation/logo.txt --- v2.0.0/linux/Documentation/logo.txt Sun Jun 9 13:28:41 1996 +++ linux/Documentation/logo.txt Sun Jun 9 18:01:04 1996 @@ -1,4 +1,4 @@ -This is the full-colour version of the currenly unofficial Linux logo +This is the full-colour version of the currently unofficial Linux logo ("currently unofficial" just means that there has been no paperwork and that I haven't really announced it yet). It was created by Larry Ewing, and is freely usable as long as you acknowledge Larry as the original diff -u --recursive --new-file v2.0.0/linux/Documentation/modules.txt linux/Documentation/modules.txt --- v2.0.0/linux/Documentation/modules.txt Sun Jun 9 13:28:41 1996 +++ linux/Documentation/modules.txt Sun Jun 9 18:01:04 1996 @@ -148,7 +148,7 @@ Whenever a program wants the kernel to use a feature that is only available as a loadable module, and if the kernel hasn't got the -module installed yet, the kernel will ask the kerneld deamon to take +module installed yet, the kernel will ask the kerneld daemon to take care of the situation and make the best of it. This is what happens: @@ -166,7 +166,7 @@ has decided that the kernel needs. Every module will be configured according to the "options" lines in "/etc/conf.modules". - modprobe exits and kerneld tells the kernel that the request - succeded (or failed...) + succeeded (or failed...) - The kernel uses the freshly installed feature just as if it had been configured into the kernel as a "resident" part. diff -u --recursive --new-file v2.0.0/linux/Makefile linux/Makefile --- v2.0.0/linux/Makefile Sun Jun 9 13:28:41 1996 +++ linux/Makefile Mon Jun 10 08:15:28 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 0 +SUBLEVEL = 1 ARCH = i386 diff -u --recursive --new-file v2.0.0/linux/README linux/README --- v2.0.0/linux/README Thu Jun 6 22:35:43 1996 +++ linux/README Wed Jun 26 11:05:26 1996 @@ -76,14 +76,14 @@ the current directory, but an alternative directory can be specified as the second argument. - - make sure your /usr/include/linux and /usr/include/asm directories - are just symlinks to the kernel sources: + - make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi + directories are just symlinks to the kernel sources: cd /usr/include - rm -rf linux - rm -rf asm - ln -s /usr/src/linux/include/linux linux + rm -rf asm linux scsi ln -s /usr/src/linux/include/asm-i386 asm + ln -s /usr/src/linux/include/linux linux + ln -s /usr/src/linux/include/scsi scsi - make sure you have no stale .o files and dependencies lying around: @@ -138,6 +138,9 @@ in your A: drive, and do a "make zdisk". It is also possible to do "make zlilo" if you have lilo installed to suit the kernel makefiles, but you may want to check your particular lilo setup first. + + - if your kernel is too large for "make zImage", use "make bzImage" + instead. - if you configured any of the parts of the kernel as `modules', you will have to do "make modules" followed by "make modules_install". diff -u --recursive --new-file v2.0.0/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.0.0/linux/arch/alpha/defconfig Sun Jun 9 13:28:41 1996 +++ linux/arch/alpha/defconfig Tue Jul 2 19:08:29 1996 @@ -24,18 +24,19 @@ # CONFIG_ALPHA_EB66 is not set # CONFIG_ALPHA_EB66P is not set # CONFIG_ALPHA_EB64P is not set -CONFIG_ALPHA_EB164=y +# CONFIG_ALPHA_EB164 is not set # CONFIG_ALPHA_PC164 is not set # CONFIG_ALPHA_JENSEN is not set # CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_MIKASA is not set -# CONFIG_ALPHA_ALCOR is not set +CONFIG_ALPHA_ALCOR=y # CONFIG_ALPHA_P2K is not set CONFIG_PCI=y CONFIG_ALPHA_EV5=y CONFIG_ALPHA_CIA=y +CONFIG_ALPHA_SRM=y # CONFIG_SERIAL_ECHO is not set -# CONFIG_TGA_CONSOLE is not set +CONFIG_TGA_CONSOLE=y CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y @@ -126,13 +127,11 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set -CONFIG_SCSI_NCR53C7xx=y -CONFIG_SCSI_NCR53C7xx_sync=y -CONFIG_SCSI_NCR53C7xx_FAST=y -# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set +# CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PPA is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC_FAS is not set +CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.0.0/linux/arch/alpha/kernel/head.S Fri Dec 22 08:22:04 1995 +++ linux/arch/alpha/kernel/head.S Mon Jul 1 20:06:05 1996 @@ -10,7 +10,7 @@ #define __ASSEMBLY__ #include -#define halt .long PAL_halt +#define halt call_pal PAL_halt .globl swapper_pg_dir .globl _stext @@ -32,7 +32,7 @@ .globl wrent .ent wrent wrent: - .long PAL_wrent + call_pal PAL_wrent ret ($26) .end wrent @@ -40,7 +40,7 @@ .globl wrkgp .ent wrkgp wrkgp: - .long PAL_wrkgp + call_pal PAL_wrkgp ret ($26) .end wrkgp @@ -48,7 +48,7 @@ .globl wrusp .ent wrusp wrusp: - .long PAL_wrusp + call_pal PAL_wrusp ret ($26) .end wrusp @@ -56,7 +56,7 @@ .globl rdusp .ent rdusp rdusp: - .long PAL_rdusp + call_pal PAL_rdusp ret ($26) .end rdusp @@ -64,7 +64,7 @@ .globl tbi .ent tbi tbi: - .long PAL_tbi + call_pal PAL_tbi ret ($26) .end tbi @@ -72,7 +72,7 @@ .globl imb .ent imb imb: - .long PAL_imb + call_pal PAL_imb ret ($26) .end imb diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.0.0/linux/arch/alpha/kernel/irq.c Sun Jun 9 13:28:41 1996 +++ linux/arch/alpha/kernel/irq.c Mon Jul 1 20:06:05 1996 @@ -28,109 +28,83 @@ extern void timer_interrupt(struct pt_regs * regs); -static unsigned char cache_21 = 0xff; -static unsigned char cache_A1 = 0xff; - -#if NR_IRQS == 48 - static unsigned int cache_irq_mask = 0x7fffffff; /* enable EISA */ -#elif NR_IRQS == 33 - static unsigned int cache_804 = 0x00ffffef; -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - static unsigned short cache_536 = 0xffff; -#else - static unsigned char cache_26 = 0xdf; - static unsigned char cache_27 = 0xff; -#endif +#if NR_IRQS > 64 +# error Unable to handle more than 64 irq levels. #endif -static void mask_irq(int irq) -{ - unsigned long mask; +/* + * Shadow-copy of masked interrupts. + * The bits are used as follows: + * 0.. 7 first ISA PIC (irq level 0..7) + * 8..15 second ISA PIC (irq level 8..15) + * Systems with 32 PCI interrupt lines (e.g., Alcor): + * 16..47 PCI interrupts 0..31 (int at GRU_INT_MASK) + * Mikasa: + * 16..31 PCI interrupts 0..15 (short at I/O port 536) + * Other systems (not Mikasa) with 16 PCI interrupt lines: + * 16..23 PCI interrupts 0.. 7 (char at I/O port 26) + * 24..31 PCI interrupts 8..15 (char at I/O port 27) + * Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164): + * 16..32 PCI interrupts 0..31 (int at I/O port 804) + */ +static unsigned long irq_mask = ~0UL; - if (irq < 16) { - mask = 1 << (irq & 7); - if (irq < 8) { - cache_21 |= mask; - outb(cache_21, 0x21); - } else { - cache_A1 |= mask; - outb(cache_A1, 0xA1); - } + +/* + * Update the hardware with the irq mask passed in MASK. The function + * exploits the fact that it is known that only bit IRQ has changed. + */ +static void update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { #if NR_IRQS == 48 - } else { - mask = 1 << (irq - 16); - cache_irq_mask |= mask; - *(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */ + default: + /* note inverted sense of mask bits: */ + *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); + mb(); + break; + #elif NR_IRQS == 33 - } else { - mask = 1 << (irq - 16); - cache_804 |= mask; - outl(cache_804, 0x804); + default: + outl(mask >> 16, 0x804); + break; + +#elif defined(CONFIG_ALPHA_MIKASA) + default: + outw(~(mask >> 16), 0x536); /* note invert */ + break; + #elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - } else { - mask = 1 << (irq & 15); - cache_536 |= mask; - outw(~cache_536, 0x536); /* note invert */ -#else - } else { - mask = 1 << (irq & 7); - if (irq < 24) { - cache_26 |= mask; - outb(cache_26, 0x26); - } else { - cache_27 |= mask; - outb(cache_27, 0x27); - } -#endif + case 16 ... 23: + outb(mask >> 16, 0x26); + break; + + default: + outb(mask >> 24, 0x27); + break; #endif + /* handle ISA irqs last---fast devices belong on PCI... */ + + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + + case 8 ...15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; } } -static void unmask_irq(unsigned long irq) +static inline void mask_irq(unsigned long irq) { - unsigned long mask; - - if (irq < 16) { - mask = ~(1 << (irq & 7)); - if (irq < 8) { - cache_21 &= mask; - outb(cache_21, 0x21); - } else { - cache_A1 &= mask; - outb(cache_A1, 0xA1); - } -#if NR_IRQS == 48 - } else { - mask = ~(1 << (irq - 16)); - cache_irq_mask &= mask; - *(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */ -#elif NR_IRQS == 33 - } else { - mask = ~(1 << (irq - 16)); - cache_804 &= mask; - outl(cache_804, 0x804); -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - } else { - mask = ~(1 << (irq & 15)); - cache_536 &= mask; - outw(~cache_536, 0x536); /* note invert */ -#else - } else { - mask = ~(1 << (irq & 7)); + irq_mask |= (1UL << irq); + update_hw(irq, irq_mask); +} - if (irq < 24) { - cache_26 &= mask; - outb(cache_26, 0x26); - } else { - cache_27 &= mask; - outb(cache_27, 0x27); - } -#endif -#endif - } +static inline void unmask_irq(unsigned long irq) +{ + irq_mask &= ~(1UL << irq); + update_hw(irq, irq_mask); } void disable_irq(unsigned int irq_nr) @@ -193,13 +167,16 @@ /* .. then the master */ outb(0xE0 | irq, 0x20); } +#if 0 + /* This is not needed since all interrupt are level-sensitive */ #if defined(CONFIG_ALPHA_ALCOR) /* on ALCOR, need to dismiss interrupt via GRU */ - *(int *)GRU_INT_CLEAR = 0x80000000; + *(int *)GRU_INT_CLEAR = 0x80000000; mb(); *(int *)GRU_INT_CLEAR = 0x00000000; mb(); #endif /* CONFIG_ALPHA_ALCOR */ +#endif } int request_irq(unsigned int irq, @@ -344,17 +321,6 @@ kstat.interrupts[irq]++; action = irq_action[irq]; - if (action) { - /* quick interrupts get executed with no extra overhead */ - if (action->flags & SA_INTERRUPT) { - while (action) { - action->handler(irq, action->dev_id, regs); - action = action->next; - } - ack_irq(ack); - return; - } - } /* * For normal interrupts, we mask it out, and then ACK it. * This way another (more timing-critical) interrupt can @@ -370,10 +336,10 @@ return; if (action->flags & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - while (action) { + do { action->handler(irq, action->dev_id, regs); action = action->next; - } + } while (action); unmask_irq(ack); } @@ -436,8 +402,8 @@ * write only. This is not true. */ pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ - pic &= ~((cache_A1 << 8) | cache_21); /* apply mask */ - pic &= 0xFFFB; /* mask out cascade */ + pic &= ~irq_mask; /* apply mask */ + pic &= 0xFFFB; /* mask out cascade & hibits */ while (pic) { j = ffz(~pic); @@ -568,17 +534,13 @@ restore_flags(flags) ; } -#if NR_IRQS > 64 -# error Number of irqs limited to 64 due to interrupt-probing. -#endif - /* * Start listening for interrupts.. */ unsigned long probe_irq_on(void) { struct irqaction * action; - unsigned long irqs = 0, irqmask; + unsigned long irqs = 0; unsigned long delay; unsigned int i; @@ -589,27 +551,15 @@ irqs |= (1 << i); } } - - /* wait for spurious interrupts to mask themselves out again */ + /* + * Wait about 100ms for spurious interrupts to mask themselves + * out again... + */ for (delay = jiffies + HZ/10; delay > jiffies; ) - /* about 100 ms delay */; - + barrier(); + /* now filter out any obviously spurious interrupts */ - irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21; -#if NR_IRQS == 48 - irqmask |= (unsigned long) cache_irq_mask << 16; -#elif NR_IRQS == 33 - irqmask |= (unsigned long) cache_804 << 16; -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - irqmask |= (unsigned long) cache_536 << 16; -#else - irqmask |= ((((unsigned long)cache_26)<<16) | - (((unsigned long)cache_27)<<24)); -#endif -#endif - irqs &= ~irqmask; - return irqs; + return irqs & ~irq_mask; } /* @@ -619,23 +569,9 @@ */ int probe_irq_off(unsigned long irqs) { - unsigned long irqmask; int i; - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; -#if NR_IRQS == 48 - irqmask |= (unsigned long) cache_irq_mask << 16; -#elif NR_IRQS == 33 - irqmask |= (unsigned long) cache_804 << 16; -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - irqmask |= (unsigned long) cache_536 << 16; -#else - irqmask |= ((((unsigned long)cache_26)<<16) | - (((unsigned long)cache_27)<<24)); -#endif -#endif - irqs &= irqmask & ~1; /* always mask out irq 0---it's the unused timer */ + irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */ #ifdef CONFIG_ALPHA_P2K irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */ #endif @@ -687,11 +623,11 @@ #elif NR_IRQS == 33 cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA +# ifdef CONFIG_ALPHA_MIKASA # error we got a problem here Charlie MIKASA should be SRM console -#else +# else eb66_and_eb64p_device_interrupt(vector, ®s); -#endif +# endif #elif NR_IRQS == 16 isa_device_interrupt(vector, ®s); #endif @@ -715,16 +651,18 @@ dma_outb(0, DMA1_CLR_MASK_REG); dma_outb(0, DMA2_CLR_MASK_REG); #if NR_IRQS == 48 - *(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */ + *(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); /* invert */ + mb(); + enable_irq(16 + 31); /* enable EISA PIC cascade */ #elif NR_IRQS == 33 - outl(cache_804, 0x804); + outl(irq_mask >> 16, 0x804); + enable_irq(16 + 4); /* enable SIO cascade */ +#elif defined(CONFIG_ALPHA_MIKASA) + outw(~(irq_mask >> 16), 0x536); /* note invert */ #elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - outw(~cache_536, 0x536); /* note invert */ -#else - outb(cache_26, 0x26); - outb(cache_27, 0x27); -#endif + outb(irq_mask >> 16, 0x26); + outb(irq_mask >> 24, 0x27); + enable_irq(16 + 5); /* enable SIO cascade */ #endif enable_irq(2); /* enable cascade */ } diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.0.0/linux/arch/alpha/kernel/osf_sys.c Fri Apr 12 15:51:45 1996 +++ linux/arch/alpha/kernel/osf_sys.c Wed Jun 26 11:05:40 1996 @@ -125,14 +125,22 @@ return count - buf.count; } -asmlinkage int osf_getpriority(int which, int who) +/* + * Alpha syscall convention has no problem returning negative + * values: + */ +asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4, + int a5, struct pt_regs regs) { extern int sys_getpriority(int, int); - /* - * Alpha syscall convention has no problem returning negative - * values: - */ - return 20 - sys_getpriority(which, who); + int prio; + + prio = sys_getpriority(which, who); + if (prio < 0) + return prio; + + regs.r0 = 0; /* special return: no errors */ + return 20 - prio; } @@ -177,6 +185,7 @@ if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); return do_mmap(file, addr, len, prot, flags, off); } diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.0.0/linux/arch/alpha/kernel/process.c Wed Feb 28 12:00:49 1996 +++ linux/arch/alpha/kernel/process.c Tue Jul 2 19:08:34 1996 @@ -8,6 +8,7 @@ * This file handles the architecture-dependent parts of process handling.. */ +#include #include #include #include @@ -52,6 +53,11 @@ void hard_reset_now(void) { +#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR) + /* who said DEC engineer's have no sense of humor? ;-)) */ + *(int *) GRU_RESET = 0x0000dead; + mb(); +#endif halt(); } diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.0.0/linux/arch/alpha/kernel/signal.c Fri Apr 19 10:07:57 1996 +++ linux/arch/alpha/kernel/signal.c Tue Jul 2 19:08:34 1996 @@ -130,24 +130,28 @@ /* * Set up a signal frame... */ -static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp, - unsigned long pc, struct pt_regs * regs, +static void setup_frame(struct sigaction * sa, + struct pt_regs * regs, struct switch_stack * sw, int signr, unsigned long oldmask) { int i; + unsigned long oldsp; struct sigcontext_struct * sc; - sc = *fp; + oldsp = rdusp(); + sc = ((struct sigcontext_struct *) oldsp) - 1; + /* check here if we would need to switch stacks.. */ - sc--; if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) do_exit(SIGSEGV); + wrusp((unsigned long) sc); + put_fs_quad(oldmask, &sc->sc_mask); put_fs_quad(8, &sc->sc_ps); - put_fs_quad(pc, &sc->sc_pc); - put_fs_quad((unsigned long)*fp, sc->sc_regs+30); + put_fs_quad(regs->pc, &sc->sc_pc); + put_fs_quad(oldsp, sc->sc_regs+30); put_fs_quad(regs->r0 , sc->sc_regs+0); put_fs_quad(regs->r1 , sc->sc_regs+1); @@ -193,14 +197,51 @@ */ put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0); put_fs_quad(0x0000000000000083, sc->sc_retcode+1); + imb(); + + /* "return" to the handler */ + regs->r27 = regs->pc = (unsigned long) sa->sa_handler; regs->r26 = (unsigned long) sc->sc_retcode; regs->r16 = signr; /* a0: signal number */ regs->r17 = 0; /* a1: exception code; see gentrap.h */ regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */ - *fp = sc; } /* + * OK, we're invoking a handler + */ +static inline void handle_signal(unsigned long signr, struct sigaction *sa, + unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw) +{ + setup_frame(sa,regs,sw,signr,oldmask); + + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + if (!(sa->sa_flags & SA_NOMASK)) + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; +} + +static inline void syscall_restart(unsigned long r0, unsigned long r19, + struct pt_regs * regs, struct sigaction * sa) +{ + switch (regs->r0) { + case ERESTARTNOHAND: + no_system_call_restart: + regs->r0 = EINTR; + break; + case ERESTARTSYS: + if (!(sa->sa_flags & SA_RESTART)) + goto no_system_call_restart; + /* fallthrough */ + case ERESTARTNOINTR: + regs->r0 = r0; /* reset v0 and a3 and replay syscall */ + regs->r19 = r19; + regs->pc -= 4; + } +} + + +/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. @@ -219,9 +260,6 @@ unsigned long r0, unsigned long r19) { unsigned long mask = ~current->blocked; - unsigned long handler_signal = 0; - struct sigcontext_struct *frame = NULL; - unsigned long pc = 0; unsigned long signr, single_stepping; struct sigaction * sa; @@ -264,7 +302,10 @@ case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; @@ -289,16 +330,13 @@ do_exit(signr); } } - /* - * OK, we're invoking a handler - */ - if (r0) { - if (regs->r0 == ERESTARTNOHAND || - (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART))) - regs->r0 = EINTR; + if (r0) + syscall_restart(r0, r19, regs, sa); + handle_signal(signr, sa, oldmask, regs, sw); + if (single_stepping) { + ptrace_set_bpt(current); /* re-set breakpoint */ } - handler_signal |= 1 << (signr-1); - mask &= ~sa->sa_mask; + return 1; } if (r0 && (regs->r0 == ERESTARTNOHAND || @@ -308,34 +346,8 @@ regs->r19 = r19; regs->pc -= 4; } - if (!handler_signal) { /* no handler will be called - return 0 */ - if (single_stepping) { - ptrace_set_bpt(current); /* re-set breakpoint */ - } - return 0; - } - pc = regs->pc; - frame = (struct sigcontext_struct *) rdusp(); - signr = 1; - sa = current->sig->action; - for (mask = 1 ; mask ; sa++,signr++,mask += mask) { - if (mask > handler_signal) - break; - if (!(mask & handler_signal)) - continue; - setup_frame(sa,&frame,pc,regs,sw,signr,oldmask); - pc = (unsigned long) sa->sa_handler; - regs->r27 = pc; - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - current->blocked |= sa->sa_mask; - oldmask |= sa->sa_mask; - } - imb(); - wrusp((unsigned long) frame); - regs->pc = pc; /* "return" to the first handler */ if (single_stepping) { ptrace_set_bpt(current); /* re-set breakpoint */ } - return 1; + return 0; } diff -u --recursive --new-file v2.0.0/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c --- v2.0.0/linux/arch/i386/kernel/ksyms.c Thu Feb 15 07:13:13 1996 +++ linux/arch/i386/kernel/ksyms.c Sat Jun 29 12:00:45 1996 @@ -14,6 +14,7 @@ #ifdef __SMP__ X(apic_reg), /* Needed internally for the I386 inlines */ X(cpu_data), + X(syscall_count), #endif #include }; diff -u --recursive --new-file v2.0.0/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.0.0/linux/arch/i386/kernel/signal.c Tue May 7 16:22:17 1996 +++ linux/arch/i386/kernel/signal.c Tue Jul 2 19:08:34 1996 @@ -248,7 +248,8 @@ if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - current->blocked |= sa->sa_mask; + if (!(sa->sa_flags & SA_NOMASK)) + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; } /* @@ -310,7 +311,10 @@ case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; diff -u --recursive --new-file v2.0.0/linux/drivers/block/README.md linux/drivers/block/README.md --- v2.0.0/linux/drivers/block/README.md Mon Feb 26 13:51:45 1996 +++ linux/drivers/block/README.md Tue Jun 11 13:00:11 1996 @@ -1,4 +1,4 @@ Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr -in public/Linux/md034.tar.gz. +in public/Linux/md035.tar.gz. Marc ZYNGIER diff -u --recursive --new-file v2.0.0/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.0.0/linux/drivers/block/ide.c Thu Jun 6 17:42:32 1996 +++ linux/drivers/block/ide.c Tue Jul 2 19:08:34 1996 @@ -1794,7 +1794,7 @@ unsigned long flags; if ((drive = get_info_ptr(inode->i_rdev)) == NULL) - return -ENODEV; + return -ENXIO; save_flags(flags); cli(); while (drive->busy) diff -u --recursive --new-file v2.0.0/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.0.0/linux/drivers/block/loop.c Tue May 7 16:22:22 1996 +++ linux/drivers/block/loop.c Tue Jul 2 19:08:41 1996 @@ -6,6 +6,7 @@ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is * permitted under the GNU Public License. * + * more DES encryption plus IDEA encryption by Nicholas J. Leon, June 20, 1996 * DES encryption plus some minor changes by Werner Almesberger, 30-MAY-1993 * * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994 @@ -15,6 +16,7 @@ #include +#include #include #include #include @@ -22,9 +24,14 @@ #include -#ifdef DES_AVAILABLE -#include "des.h" +#ifdef CONFIG_BLK_DEV_LOOP_DES +#include +#endif + +#ifdef CONFIG_BLK_DEV_LOOP_IDEA +#include #endif + #include /* must follow des.h */ #define MAJOR_NR LOOP_MAJOR @@ -113,6 +120,23 @@ } #endif +#ifdef IDEA_AVAILABLE + +extern void idea_encrypt_block(idea_key,char *,char *,int); + +static int transfer_idea(struct loop_device *lo, int cmd, char *raw_buf, + char *loop_buf, int size) +{ + if (cmd==READ) { + idea_encrypt_block(lo->lo_idea_en_key,raw_buf,loop_buf,size); + } + else { + idea_encrypt_block(lo->lo_idea_de_key,loop_buf,raw_buf,size); + } + return 0; +} +#endif + static transfer_proc_t xfer_funcs[MAX_LOOP] = { transfer_none, /* LO_CRYPT_NONE */ transfer_xor, /* LO_CRYPT_XOR */ @@ -121,7 +145,11 @@ #else NULL, /* LO_CRYPT_DES */ #endif - 0 /* LO_CRYPT_IDEA */ +#ifdef IDEA_AVAILABLE /* LO_CRYPT_IDEA */ + transfer_idea +#else + NULL +#endif }; @@ -225,8 +253,10 @@ brelse(bh); goto error_out; } - if (CURRENT->cmd == WRITE) + if (CURRENT->cmd == WRITE) { + mark_buffer_uptodate(bh, 1); mark_buffer_dirty(bh, 1); + } brelse(bh); dest_addr += size; len -= size; @@ -335,6 +365,20 @@ memcpy(lo->lo_des_init,info.lo_init,8); break; #endif +#ifdef IDEA_AVAILABLE + case LO_CRYPT_IDEA: + { + uint16 tmpkey[8]; + + if (info.lo_encrypt_key_size != IDEAKEYSIZE) + return -EINVAL; + /* create key in lo-> from info.lo_encrypt_key */ + memcpy(tmpkey,info.lo_encrypt_key,sizeof(tmpkey)); + en_key_idea(tmpkey,lo->lo_idea_en_key); + de_key_idea(lo->lo_idea_en_key,lo->lo_idea_de_key); + break; + } +#endif default: return -EINVAL; } @@ -494,6 +538,12 @@ } #ifndef MODULE printk("loop: registered device at major %d\n", MAJOR_NR); +#ifdef DES_AVAILABLE + printk("loop: DES encryption available\n"); +#endif +#ifdef IDEA_AVAILABLE + printk("loop: IDEA encryption available\n"); +#endif #endif blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; diff -u --recursive --new-file v2.0.0/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.0.0/linux/drivers/block/md.c Tue May 21 19:52:34 1996 +++ linux/drivers/block/md.c Sun Jun 30 00:04:00 1996 @@ -163,6 +163,7 @@ { md_dev[minor].devices[i].size &= ~(min - 1); md_size[minor] += md_dev[minor].devices[i].size; + md_dev[minor].devices[i].offset=i ? (md_dev[minor].devices[i-1].offset + md_dev[minor].devices[i-1].size) : 0; } md_dev[minor].pers=pers[pnum]; @@ -218,6 +219,7 @@ clear_inode (md_dev[minor].devices[i].inode); md_dev[minor].nb_dev=md_size[minor]=0; + md_hd_struct[minor].nr_sects=0; md_dev[minor].pers=NULL; set_ra (); /* calculate new read_ahead */ @@ -257,14 +259,7 @@ /* Sizes are now rounded at run time */ md_dev[minor].devices[i].size=gen_real->sizes[MINOR(dev)]; - md_dev[minor].devices[i].offset=i ? - (md_dev[minor].devices[i-1].offset + md_dev[minor].devices[i-1].size) : 0; - - if (!i) - md_size[minor]=0; - - md_size[minor]+=md_dev[minor].devices[i].size; - + printk ("REGISTER_DEV %s to md%x done\n", partition_name(dev), minor); return (0); } @@ -372,11 +367,33 @@ } +static int md_read (struct inode *inode, struct file *file, + char *buf, int count) +{ + int minor=MINOR(inode->i_rdev); + + if (!md_dev[minor].pers) /* Check if device is being run */ + return -ENXIO; + + return block_read (inode, file, buf, count); +} + +static int md_write (struct inode *inode, struct file *file, + const char *buf, int count) +{ + int minor=MINOR(inode->i_rdev); + + if (!md_dev[minor].pers) /* Check if device is being run */ + return -ENXIO; + + return block_write (inode, file, buf, count); +} + static struct file_operations md_fops= { NULL, - block_read, - block_write, + md_read, + md_write, NULL, NULL, md_ioctl, @@ -431,6 +448,7 @@ { md_blocksizes[i] = 1024; md_gendisk.part[i].start_sect=-1; /* avoid partition check */ + md_gendisk.part[i].nr_sects=0; md_dev[i].pers=NULL; } @@ -448,7 +466,7 @@ int get_md_status (char *page) { - int sz=0, i, j; + int sz=0, i, j, size; sz+=sprintf( page+sz, "Personalities : "); for (i=0; iname); + size=0; for (j=0; ji_rdev) >= NUM_RAMDISKS) - return -ENODEV; + return -ENXIO; MOD_INC_USE_COUNT; diff -u --recursive --new-file v2.0.0/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.0.0/linux/drivers/block/xd.c Thu Jun 6 17:42:32 1996 +++ linux/drivers/block/xd.c Tue Jul 2 19:08:41 1996 @@ -211,7 +211,7 @@ return (0); } else - return (-ENODEV); + return -ENXIO; } /* do_xd_request: handle an incoming request */ diff -u --recursive --new-file v2.0.0/linux/drivers/char/baycom.c linux/drivers/char/baycom.c --- v2.0.0/linux/drivers/char/baycom.c Thu Jun 6 17:42:34 1996 +++ linux/drivers/char/baycom.c Sat Jun 29 12:00:45 1996 @@ -236,7 +236,6 @@ unsigned int dcd_shreg; unsigned long descram; unsigned long scram; - unsigned char last_rxbit; }; struct modem_state { @@ -581,8 +580,7 @@ /* ---------------------------------------------------------------------- */ /* - * The HDLC routines could be more efficient; they could take more than - * one bit per call + * The HDLC routines */ static inline int hdlc_rx_add_bytes(struct baycom_state *bc, @@ -1212,7 +1210,7 @@ { register struct baycom_state *bc = (struct baycom_state *)dev_id; int i; - unsigned int data, rawdata, mask, mask2; + unsigned int data, mask, mask2; if (!bc || bc->magic != BAYCOM_MAGIC) return; @@ -1270,7 +1268,7 @@ /* * do receiver; differential decode and descramble on the fly */ - for(rawdata = data = i = 0; i < PAR96_BURSTBITS; i++) { + for(data = i = 0; i < PAR96_BURSTBITS; i++) { unsigned int descx; bc->modem.par96.descram = (bc->modem.par96.descram << 1); if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT) @@ -1281,14 +1279,9 @@ outb(PAR97_POWER | PAR96_PTT, LPT_DATA(bc->iobase)); descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ (descx >> PAR96_DESCRAM_TAPSH2)); - if (descx & 1) - bc->modem.par96.last_rxbit = - !bc->modem.par96.last_rxbit; data >>= 1; - if (bc->modem.par96.last_rxbit) + if (!(descx & 1)) data |= 0x8000; - rawdata <<= 1; - rawdata |= !(descx & 1); outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, LPT_DATA(bc->iobase)); } @@ -1304,16 +1297,16 @@ * do DCD algorithm */ if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { - bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg << 16) - | rawdata; + bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16) + | (data << 16); /* search for flags and set the dcd counter appropriately */ - for(mask = 0x7f8000, mask2 = 0x3f0000, i = 0; - i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1) + for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; + i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) if ((bc->modem.par96.dcd_shreg & mask) == mask2) bc->modem.par96.dcd_count = BAYCOM_MAXFLEN+4; /* check for abort/noise sequences */ - for(mask = 0x3f8000, mask2 = 0x3f8000, i = 0; - i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1) + for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; + i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) if ((bc->modem.par96.dcd_shreg & mask) == mask2) if (bc->modem.par96.dcd_count >= 0) bc->modem.par96.dcd_count -= diff -u --recursive --new-file v2.0.0/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.0.0/linux/drivers/char/console.c Fri May 17 15:32:14 1996 +++ linux/drivers/char/console.c Tue Jul 2 19:08:41 1996 @@ -306,7 +306,7 @@ int vc_allocate(unsigned int i) /* return 0 on success */ { if (i >= MAX_NR_CONSOLES) - return -ENODEV; + return -ENXIO; if (!vc_cons[i].d) { long p, q; diff -u --recursive --new-file v2.0.0/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.0.0/linux/drivers/char/lp.c Tue May 7 16:22:24 1996 +++ linux/drivers/char/lp.c Tue Jul 2 19:08:41 1996 @@ -322,9 +322,9 @@ unsigned int irq; if (minor >= LP_NO) - return -ENODEV; + return -ENXIO; if ((LP_F(minor) & LP_EXIST) == 0) - return -ENODEV; + return -ENXIO; if (LP_F(minor) & LP_BUSY) return -EBUSY; diff -u --recursive --new-file v2.0.0/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.0.0/linux/drivers/char/mem.c Sat Apr 27 15:19:51 1996 +++ linux/drivers/char/mem.c Tue Jul 2 19:08:41 1996 @@ -358,7 +358,7 @@ filp->f_op = &urandom_fops; break; default: - return -ENODEV; + return -ENXIO; } if (filp->f_op && filp->f_op->open) return filp->f_op->open(inode,filp); diff -u --recursive --new-file v2.0.0/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.0.0/linux/drivers/char/n_tty.c Wed Apr 24 17:00:38 1996 +++ linux/drivers/char/n_tty.c Tue Jul 2 19:08:41 1996 @@ -201,7 +201,7 @@ tty->read_head = tty->canon_head; return; } - if (!L_ECHOK(tty) || !L_ECHOKE(tty)) { + if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { tty->read_cnt -= ((tty->read_head - tty->canon_head) & (N_TTY_BUF_SIZE - 1)); tty->read_head = tty->canon_head; @@ -236,7 +236,7 @@ tty->erasing = 1; } echo_char(c, tty); - } else if (!L_ECHOE(tty)) { + } else if (kill_type == ERASE && !L_ECHOE(tty)) { echo_char(ERASE_CHAR(tty), tty); } else if (c == '\t') { unsigned int col = tty->canon_column; @@ -290,11 +290,11 @@ finish_erasing(tty); } -static void isig(int sig, struct tty_struct *tty) +static inline void isig(int sig, struct tty_struct *tty, int flush) { if (tty->pgrp > 0) kill_pg(tty->pgrp, sig, 1); - if (!L_NOFLSH(tty)) { + if (flush || !L_NOFLSH(tty)) { n_tty_flush_buffer(tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); @@ -306,7 +306,7 @@ if (I_IGNBRK(tty)) return; if (I_BRKINT(tty)) { - isig(SIGINT, tty); + isig(SIGINT, tty, 1); return; } if (I_PARMRK(tty)) { @@ -340,8 +340,10 @@ put_tty_queue('\377', tty); put_tty_queue('\0', tty); put_tty_queue(c, tty); - } else + } else if (I_INPCK(tty)) put_tty_queue('\0', tty); + else + put_tty_queue(c, tty); wake_up_interruptible(&tty->read_wait); } @@ -415,17 +417,17 @@ } } if (L_ISIG(tty)) { - if (c == INTR_CHAR(tty)) { - isig(SIGINT, tty); - return; - } - if (c == QUIT_CHAR(tty)) { - isig(SIGQUIT, tty); - return; - } + int signal; + signal = SIGINT; + if (c == INTR_CHAR(tty)) + goto send_signal; + signal = SIGQUIT; + if (c == QUIT_CHAR(tty)) + goto send_signal; + signal = SIGTSTP; if (c == SUSP_CHAR(tty)) { - if (!is_orphaned_pgrp(tty->pgrp)) - isig(SIGTSTP, tty); +send_signal: + isig(signal, tty, 0); return; } } diff -u --recursive --new-file v2.0.0/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.0.0/linux/drivers/char/pty.c Thu Jun 6 22:35:44 1996 +++ linux/drivers/char/pty.c Tue Jul 2 19:08:42 1996 @@ -244,6 +244,12 @@ return retval; } +static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + tty->termios->c_cflag &= ~(CSIZE | PARENB); + tty->termios->c_cflag |= (CS8 | CREAD); +} + int pty_init(void) { memset(&pty_state, 0, sizeof(pty_state)); @@ -274,6 +280,7 @@ pty_driver.flush_buffer = pty_flush_buffer; pty_driver.chars_in_buffer = pty_chars_in_buffer; pty_driver.unthrottle = pty_unthrottle; + pty_driver.set_termios = pty_set_termios; pty_slave_driver = pty_driver; pty_slave_driver.name = "ttyp"; diff -u --recursive --new-file v2.0.0/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.0.0/linux/drivers/char/random.c Thu Jun 6 22:35:44 1996 +++ linux/drivers/char/random.c Tue Jul 2 19:08:42 1996 @@ -357,8 +357,6 @@ #if (!defined (__i386__)) extern inline __u32 rotate_left(int i, __u32 word) { - __u32 nbits = 0; - return (word << i) | (word >> (32 - i)); } diff -u --recursive --new-file v2.0.0/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.0.0/linux/drivers/char/serial.c Sun Jun 9 13:28:42 1996 +++ linux/drivers/char/serial.c Tue Jul 2 19:08:42 1996 @@ -2755,9 +2755,8 @@ serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.init_termios.c_lflag &=~ (ISIG | ICANON | ECHO); + serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; diff -u --recursive --new-file v2.0.0/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.0.0/linux/drivers/char/softdog.c Mon May 13 23:02:48 1996 +++ linux/drivers/char/softdog.c Sat Jun 29 12:00:46 1996 @@ -73,6 +73,7 @@ /* * Activate timer */ + del_timer(&watchdog_ticktock); watchdog_ticktock.expires=jiffies + (soft_margin * HZ); add_timer(&watchdog_ticktock); timer_alive++; diff -u --recursive --new-file v2.0.0/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.0.0/linux/drivers/char/tty_io.c Thu Jun 6 22:35:44 1996 +++ linux/drivers/char/tty_io.c Tue Jul 2 19:08:42 1996 @@ -330,7 +330,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { - return -EIO; + return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) @@ -475,8 +475,10 @@ { struct tty_struct *tty = current->tty; struct task_struct *p; + int tty_pgrp = -1; if (tty) { + tty_pgrp = tty->pgrp; if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { @@ -486,9 +488,10 @@ } return; } - if (tty->pgrp > 0) { - kill_pg(tty->pgrp, SIGHUP, on_exit); - kill_pg(tty->pgrp, SIGCONT, on_exit); + if (tty_pgrp > 0) { + kill_pg(tty_pgrp, SIGHUP, on_exit); + if (!on_exit) + kill_pg(tty_pgrp, SIGCONT, on_exit); } current->tty_old_pgrp = 0; @@ -1496,6 +1499,8 @@ return 0; case TIOCSPGRP: retval = tty_check_change(real_tty); + if (retval == -EIO) + return -ENOTTY; if (retval) return retval; if (!current->tty || @@ -1816,7 +1821,7 @@ memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); tty_std_termios.c_iflag = ICRNL | IXON; tty_std_termios.c_oflag = OPOST | ONLCR; - tty_std_termios.c_cflag = B38400 | CS8 | CREAD; + tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.0.0/linux/drivers/isdn/icn/icn.c Sun Jun 9 13:28:42 1996 +++ linux/drivers/isdn/icn/icn.c Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.24 1996/06/06 13:58:33 fritz Exp $ +/* $Id: icn.c,v 1.28 1996/06/28 17:02:53 fritz Exp $ * * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,23 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.28 1996/06/28 17:02:53 fritz + * replaced memcpy_fromfs_toio. + * + * Revision 1.27 1996/06/25 18:38:59 fritz + * Fixed function name in error message. + * + * Revision 1.26 1996/06/24 17:20:35 fritz + * Bugfixes in pollbchan_send(): + * - Using lock field of skbuff breaks networking. + * - Added channel locking + * - changed dequeuing scheme. + * Eliminated misc. compiler warnings. + * + * Revision 1.25 1996/06/11 22:53:35 tsbogend + * fixed problem with large array on stack + * made the driver working on Linux/alpha + * * Revision 1.24 1996/06/06 13:58:33 fritz * Changed code to be architecture independent * @@ -119,7 +136,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.24 $"; +*revision = "$Revision: 1.28 $"; static int icn_addcard(int, char *, char *); @@ -135,10 +152,8 @@ save_flags(flags); cli(); - while ((skb = skb_dequeue(queue))) { - skb->free = 1; - kfree_skb(skb, FREE_WRITE); - } + while ((skb = skb_dequeue(queue))) + dev_kfree_skb(skb, FREE_WRITE); restore_flags(flags); } @@ -312,7 +327,7 @@ if (icn_trymaplock_channel(card,mch)) { while (rbavl) { - cnt = rbuf_l; + cnt = readb(&rbuf_l); if ((card->rcvidx[channel] + cnt) > 4000) { printk(KERN_WARNING "icn: (%s) bogus packet on ch%d, dropping.\n", @@ -322,9 +337,9 @@ eflag = 0; } else { memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]], - rbuf_d, cnt); + &rbuf_d, cnt); card->rcvidx[channel] += cnt; - eflag = rbuf_f; + eflag = readb(&rbuf_f); } rbnext; icn_maprelease_channel(card, mch & 2); @@ -367,36 +382,37 @@ while (sbfree && card->sndcount[channel]) { save_flags(flags); cli(); - skb = skb_peek(&card->spqueue[channel]); - if (!skb) { - restore_flags(flags); - break; - } - if (skb->lock) { + if (card->xmit_lock[channel]) { restore_flags(flags); break; } - skb->lock = 1; + card->xmit_lock[channel]++; restore_flags(flags); - cnt = - (sbuf_l = - (skb->len > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), skb->len)); - memcpy(sbuf_d, skb->data, cnt); + skb = skb_dequeue(&card->spqueue[channel]); + if (!skb) + break; + if (skb->len > ICN_FRAGSIZE) { + writeb (0xff, &sbuf_f); + cnt = ICN_FRAGSIZE; + } else { + writeb (0x0, &sbuf_f); + cnt = skb->len; + } + writeb (cnt, &sbuf_l); + memcpy_toio(&sbuf_d, skb->data, cnt); skb_pull(skb, cnt); card->sndcount[channel] -= cnt; sbnext; /* switch to next buffer */ icn_maprelease_channel(card, mch & 2); if (!skb->len) { - skb = skb_dequeue(&card->spqueue[channel]); - skb->free = 1; - skb->lock = 0; - kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb, FREE_WRITE); cmd.command = ISDN_STAT_BSENT; cmd.driver = card->myid; cmd.arg = channel; card->interface.statcallb(&cmd); } else - skb->lock = 0; + skb_queue_head(&card->spqueue[channel], skb); + card->xmit_lock[channel] = 0; if (!icn_trymaplock_channel(card, mch)) break; } @@ -426,6 +442,7 @@ /* schedule b-channel polling again */ save_flags(flags); cli(); + del_timer(&card->rb_timer); card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; add_timer(&card->rb_timer); card->flags |= ICN_FLAGS_RBTIMER; @@ -649,6 +666,7 @@ /* schedule again */ save_flags(flags); cli(); + del_timer(&card->st_timer); card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; add_timer(&card->st_timer); restore_flags(flags); @@ -671,8 +689,8 @@ unsigned long flags; if (len > 4000) { - skb->free = 1; - kfree_skb(skb, FREE_WRITE); + printk(KERN_WARNING + "icn: Send packet too large\n"); return -EINVAL; } if (len) { @@ -685,7 +703,6 @@ card->sndcount[channel] += len; skb_queue_tail(&card->spqueue[channel], skb); restore_flags(flags); - icn_pollbchan_send(channel, card); } return len; } @@ -751,13 +768,17 @@ { int ret; ulong flags; - unsigned char codebuf[ICN_CODE_STAGE1]; + u_char *codebuf; #ifdef BOOT_DEBUG printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer); #endif if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1))) return ret; + if (!(codebuf = kmalloc(ICN_CODE_STAGE1,GFP_KERNEL))) { + printk(KERN_WARNING "icn: Could not allocate code buffer\n"); + return -ENOMEM; + } save_flags(flags); cli(); if (!card->rvalid) { @@ -768,6 +789,7 @@ card->port, card->port + ICN_PORTLEN); restore_flags(flags); + kfree(codebuf); return -EBUSY; } request_region(card->port, ICN_PORTLEN, card->regname); @@ -804,8 +826,8 @@ icn_lock_channel(card,0); /* Lock Bank 0 */ restore_flags(flags); SLEEP(1); - memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); /* Copy code */ - memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); + memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); + memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG printk(KERN_DEBUG "Bootloader transfered\n"); #endif @@ -821,12 +843,12 @@ icn_lock_channel(card,2); /* Lock Bank 8 */ restore_flags(flags); SLEEP(1); - memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); /* Copy code */ - memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); + memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG printk(KERN_DEBUG "Bootloader transfered\n"); #endif } + kfree(codebuf); SLEEP(1); OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */ if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) @@ -849,6 +871,7 @@ static int icn_loadproto(u_char * buffer, icn_card * card) { register u_char *p = buffer; + u_char codebuf[256]; uint left = ICN_CODE_STAGE2; uint cnt; int timer; @@ -874,7 +897,8 @@ while (left) { if (sbfree) { /* If there is a free buffer... */ cnt = MIN(256, left); - memcpy_fromfs(&sbuf_l, p, cnt); /* copy data */ + memcpy_fromfs(codebuf, p, cnt); + memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */ sbnext; /* switch to next buffer */ p += cnt; left -= cnt; @@ -892,7 +916,7 @@ schedule(); } } - sbuf_n = 0x20; + writeb (0x20, &sbuf_n); timer = 0; while (1) { if (readb(&cmd_o) || readb(&cmd_i)) { @@ -1094,7 +1118,7 @@ } break; case ICN_IOCTL_GETMMIO: - return (int) dev.shmem; + return (long) dev.shmem; case ICN_IOCTL_SETPORT: if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330 || a == 0x340 || a == 0x350 || a == 0x360 || @@ -1391,7 +1415,8 @@ if (card) return (icn_command(c, card)); printk(KERN_ERR - "icn: if_command called with invalid driverId!\n"); + "icn: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); return -ENODEV; } @@ -1433,7 +1458,7 @@ return (icn_sendbuf(channel, skb, card)); } printk(KERN_ERR - "icn: if_readstatus called with invalid driverId!\n"); + "icn: if_sendbuf called with invalid driverId!\n"); return -ENODEV; } @@ -1455,9 +1480,6 @@ card->interface.channels = ICN_BCH; card->interface.maxbufsize = 4000; card->interface.command = if_command; - /* - card->interface.writebuf = if_sendbuf; - */ card->interface.writebuf_skb = if_sendbuf; card->interface.writecmd = if_writecmd; card->interface.readstat = if_readstatus; @@ -1558,7 +1580,7 @@ char rev[10]; memset(&dev, 0, sizeof(icn_dev)); - dev.shmem = (icn_shmem *) (membase & 0x0ffc000); + dev.shmem = (icn_shmem *) ((unsigned long)membase & 0x0ffc000); dev.channel = -1; dev.mcard = NULL; @@ -1571,8 +1593,8 @@ *p = 0; } else strcpy(rev, " ??? "); - printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08x\n", rev, - (uint) dev.shmem); + printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev, + (ulong) dev.shmem); return (icn_addcard(portbase,icn_id,icn_id2)); } diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.0.0/linux/drivers/isdn/icn/icn.h Sun Jun 9 13:28:42 1996 +++ linux/drivers/isdn/icn/icn.h Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.19 1996/06/06 13:58:35 fritz Exp $ +/* $Id: icn.h,v 1.20 1996/06/24 17:20:37 fritz Exp $ * * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -19,6 +19,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.h,v $ + * Revision 1.20 1996/06/24 17:20:37 fritz + * Bugfixes in pollbchan_send(): + * - Using lock field of skbuff breaks networking. + * - Added channel locking + * - changed dequeuing scheme. + * Eliminated misc. compiler warnings. + * * Revision 1.19 1996/06/06 13:58:35 fritz * Changed code to be architecture independent * @@ -155,7 +162,7 @@ #define ICN_CODE_STAGE1 4096 /* Size of bootcode */ #define ICN_CODE_STAGE2 65536 /* Size of protocol-code */ -#define ICN_MAX_SQUEUE 65536 /* Max. outstanding send-data */ +#define ICN_MAX_SQUEUE 8000 /* Max. outstanding send-data (2* hw-buf.) */ #define ICN_FRAGSIZE (250) /* Max. size of send-fragments */ #define ICN_BCH 2 /* Number of supported channels per card */ @@ -240,6 +247,7 @@ struct sk_buff_head spqueue[ICN_BCH]; /* Sendqueue */ char regname[35]; /* Name used for request_region */ + u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send() */ } icn_card; /* diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.0.0/linux/drivers/isdn/isdn_common.c Sun Jun 9 13:28:43 1996 +++ linux/drivers/isdn/isdn_common.c Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.18 1996/06/06 14:51:51 fritz Exp $ +/* $Id: isdn_common.c,v 1.23 1996/06/25 18:35:38 fritz Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.23 1996/06/25 18:35:38 fritz + * Fixed bogus memory access in isdn_set_allcfg(). + * + * Revision 1.22 1996/06/24 17:37:37 fritz + * Bugfix: isdn_timer_ctrl() did restart timer, even if it + * was already running. + * lowlevel driver locking did use wrong parameters. + * + * Revision 1.21 1996/06/15 14:58:20 fritz + * Added version signatures for data structures used + * by userlevel programs. + * + * Revision 1.20 1996/06/12 16:01:49 fritz + * Bugfix: Remote B-channel hangup sometimes did not result + * in a NO CARRIER on tty. + * + * Revision 1.19 1996/06/11 14:52:04 hipp + * minor bugfix in isdn_writebuf_skb_stub() + * * Revision 1.18 1996/06/06 14:51:51 fritz * Changed to support DTMF decoding on audio playback also. * @@ -115,11 +134,12 @@ /* Debugflags */ #undef ISDN_DEBUG_STATCALLB +#define NEW_ISDN_TIMER_CTRL isdn_dev *dev = (isdn_dev *) 0; static int has_exported = 0; -static char *isdn_revision = "$Revision: 1.18 $"; +static char *isdn_revision = "$Revision: 1.23 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -222,8 +242,10 @@ save_flags(flags); cli(); - del_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; + del_timer(&dev->timer); +#ifndef NEW_ISDN_TIMER_CTRL + dev->timer.function = isdn_timer_funct; +#endif dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); restore_flags(flags); @@ -245,12 +267,20 @@ dev->tflags |= tf; else dev->tflags &= ~tf; +#ifdef NEW_ISDN_TIMER_CTRL + if (dev->tflags) { + if (!del_timer(&dev->timer)) /* del_timer is 1, when active */ + dev->timer.expires = jiffies + ISDN_TIMER_RES; + add_timer(&dev->timer); + } +#else if (dev->tflags) { - del_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; + del_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); } +#endif restore_flags(flags); } @@ -277,6 +307,7 @@ if (isdn_net_rcv_skb(i, skb)) return; /* No network-device found, deliver to tty or raw-channel */ + skb->free = 1; if (skb->len) { if ((midx = dev->m_idx[i])<0) { /* if midx is invalid, drop packet */ @@ -599,9 +630,9 @@ info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); - if (info->online) + if (info->msr & UART_MSR_DCD) isdn_tty_modem_result(3, info); + info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); #endif @@ -807,6 +838,8 @@ return (dev->chanmap[minor]); } +#define INF_DV 0x01 /* Data version for /dev/isdninfo */ + static char * isdn_statstr(void) { @@ -1043,7 +1076,8 @@ restore_flags(flags); return ret; } - memcpy_tofs((char *) &i, src, sizeof(int)); + memcpy_fromfs((char *) &i, src, sizeof(int)); + src += sizeof(int); while (i) { char *c; char *c2; @@ -1185,6 +1219,10 @@ if (minor == ISDN_MINOR_STATUS) { switch (cmd) { + case IIOCGETDVR: + return(TTY_DV + + (NET_DV << 8) + + (INF_DV << 16)); case IIOCGETCPS: if (arg) { ulong *p = (ulong *)arg; @@ -1728,7 +1766,7 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = i; + cmd.driver = d; cmd.arg = 0; cmd.command = ISDN_CMD_LOCK; (void) dev->drv[d]->interface->command(&cmd); @@ -1739,7 +1777,7 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = i; + cmd.driver = d; cmd.arg = 0; cmd.command = ISDN_CMD_LOCK; (void) dev->drv[d]->interface->command(&cmd); @@ -1878,17 +1916,18 @@ int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb) { int ret; + int len = skb->len; /* skb pointer no longer valid after free */ if (dev->drv[drvidx]->interface->writebuf_skb) ret = dev->drv[drvidx]->interface-> writebuf_skb(drvidx, chan, skb); else { if ((ret = dev->drv[drvidx]->interface-> - writebuf(drvidx,chan,skb->data,skb->len,0)) == skb->len) + writebuf(drvidx,chan,skb->data,skb->len,0)) == len) dev_kfree_skb(skb, FREE_WRITE); } if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx,chan)] += skb->len; + dev->obytes[isdn_dc2minor(drvidx,chan)] += len; return ret; } @@ -2063,6 +2102,10 @@ return -EIO; } memset((char *) dev, 0, sizeof(isdn_dev)); +#ifdef NEW_ISDN_TIMER_CTRL + init_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; +#endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.0.0/linux/drivers/isdn/isdn_net.c Sun Jun 9 13:28:43 1996 +++ linux/drivers/isdn/isdn_net.c Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.13 1996/06/06 14:25:44 fritz Exp $ +/* $Id: isdn_net.c,v 1.17 1996/06/25 18:37:37 fritz Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.17 1996/06/25 18:37:37 fritz + * Fixed return count for empty return string in isdn_net_getphones(). + * + * Revision 1.16 1996/06/24 17:48:08 fritz + * Bugfixes: + * - Did not free channel on unbinding. + * - ioctl returned wrong callback settings. + * + * Revision 1.15 1996/06/16 17:42:54 tsbogend + * fixed problem with IP addresses on Linux/Alpha (long is 8 byte there) + * + * Revision 1.14 1996/06/11 14:54:08 hipp + * minor bugfix in isdn_net_send_skb + * changes in BSENT callback handler for syncPPP + * added lp->sav_skb stuff + * * Revision 1.13 1996/06/06 14:25:44 fritz * Changed loglevel of "incoming ... without OAD" message, since * with audio support this is quite normal. @@ -105,7 +121,7 @@ extern void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -char *isdn_net_revision = "$Revision: 1.13 $"; +char *isdn_net_revision = "$Revision: 1.17 $"; /* * Code for raw-networking over ISDN @@ -133,9 +149,9 @@ isdn_net_reset(dev); dev->start = 1; /* Fill in the MAC-level header. */ - for (i = 0; i < ETH_ALEN - sizeof(ulong); i++) + for (i = 0; i < ETH_ALEN - sizeof(u32); i++) dev->dev_addr[i] = 0xfc; - memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(ulong)); + memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32)); /* If this interface has slaves, start them also */ @@ -182,6 +198,10 @@ dev_kfree_skb(lp->first_skb,FREE_WRITE); lp->first_skb = NULL; } + if(lp->sav_skb) { + dev_kfree_skb(lp->sav_skb,FREE_WRITE); + lp->sav_skb = NULL; + } dev_purge_queues(&lp->netdev->dev); lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; @@ -263,14 +283,19 @@ if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { lp->stats.tx_packets++; - if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->first_skb) { - if(!isdn_net_send_skb(&lp->netdev->dev,lp,lp->first_skb)) { - dev_kfree_skb(lp->first_skb,FREE_WRITE); - lp->first_skb = NULL; + if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) { + struct device *mdev; + if(lp->master) + mdev = lp->master; + else + mdev = &lp->netdev->dev; + if(!isdn_net_send_skb(mdev,lp,lp->sav_skb)) { + lp->sav_skb = NULL; mark_bh(NET_BH); } - else + else { return 1; + } } if (clear_bit(0,(void*)&(p->dev.tbusy))) mark_bh(NET_BH); @@ -293,8 +318,14 @@ /* Either D-Channel-hangup or error during dialout */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { lp->flags &= ~ISDN_NET_CONNECTED; - if(lp->first_skb) + if(lp->first_skb) { dev_kfree_skb(lp->first_skb,FREE_WRITE); + lp->first_skb = NULL; + } + if(lp->sav_skb) { + dev_kfree_skb(lp->sav_skb,FREE_WRITE); + lp->sav_skb = NULL; + } isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP @@ -596,35 +627,20 @@ { isdn_net_local *lp = (isdn_net_local *) d->priv; isdn_ctrl cmd; - ulong flags; - save_flags(flags); - cli(); - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb,FREE_WRITE); - lp->first_skb = NULL; - } - dev_purge_queues(d); if (lp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); - lp->dialstate = 0; - dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; - dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; - isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif - lp->flags &= ~ISDN_NET_CONNECTED; cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_HANGUP; cmd.arg = lp->isdn_channel; (void) dev->drv[cmd.driver]->interface->command(&cmd); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - lp->isdn_device = -1; - lp->isdn_channel = -1; } - restore_flags(flags); + isdn_net_unbind_channel(lp); } typedef struct { @@ -732,13 +748,21 @@ struct sk_buff *skb) { int ret; + int len = skb->len; /* save len */ - lp->transcount += skb->len; ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb); - if (ret == skb->len) { + if (ret == len) { + lp->transcount += len; clear_bit(0, (void *)&(ndev->tbusy)); return 0; } + if (ret < 0) { + skb->free = 1; + dev_kfree_skb(skb, FREE_WRITE); + lp->stats.tx_errors++; + clear_bit(0, (void *)&(ndev->tbusy)); + return 0; + } return 1; } @@ -762,8 +786,7 @@ /* For the other encaps the header has already been built */ #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - ndev->tbusy = ret = isdn_ppp_xmit(skb, ndev); - return ret; + return isdn_ppp_xmit(skb, ndev); } #endif /* Reset hangup-timeout */ @@ -877,7 +900,7 @@ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { /* no 'first_skb' handling for syncPPP */ if (isdn_ppp_bind(lp) < 0) { - lp->first_skb = skb; /* net_unbind will free skb */ + dev_kfree_skb(skb,FREE_WRITE); isdn_net_unbind_channel(lp); restore_flags(flags); return 0; /* STN (skb to nirvana) ;) */ @@ -1241,7 +1264,7 @@ * guaranteed to be invalid. Need that to check * for already compressed packets in isdn_ppp_xmit(). */ - *((unsigned long *)skb_push(skb, len)) = 0; + *((u32 *)skb_push(skb, len)) = 0; break; #endif } @@ -1251,7 +1274,7 @@ /* We don't need to send arp, because we have point-to-point connections. */ static int -isdn_net_rebuild_header(void *buff, struct device *dev, ulong dst, +isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst, struct sk_buff *skb) { isdn_net_local *lp = dev->priv; @@ -1266,8 +1289,8 @@ if(eth->h_proto != htons(ETH_P_IP)) { printk(KERN_WARNING - "isdn_net_rebuild_header: Don't know how to resolve type %d addresses?\n", - (int)eth->h_proto); + "isdn_net: %s don't know how to resolve type %d addresses?\n", + dev->name, (int)eth->h_proto); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); return 0; } @@ -1275,7 +1298,7 @@ * Try to get ARP to resolve the header. */ #ifdef CONFIG_INET - ret = arp_find((unsigned char *)&(eth->h_dest), dst, dev, dev->pa_addr,skb)? 1 : 0; + ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; #endif } return ret; @@ -2034,6 +2057,7 @@ p->local.exclusive = -1; if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) { isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel); + isdn_free_channel(p->local.pre_device, p->local.pre_channel,ISDN_USAGE_NET); drvidx = -1; chidx = -1; } @@ -2059,7 +2083,7 @@ p->local.flags &= ~ISDN_NET_CBHUP; switch (cfg->callback) { case 0: - p->local.flags &= ~(ISDN_NET_CALLBACK&ISDN_NET_CBOUT); + p->local.flags &= ~(ISDN_NET_CALLBACK|ISDN_NET_CBOUT); break; case 1: p->local.flags |= ISDN_NET_CALLBACK; @@ -2126,7 +2150,9 @@ cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0; cfg->callback = 0; if (p->local.flags & ISDN_NET_CALLBACK) - cfg->callback = (p->local.flags & ISDN_NET_CBOUT)?2:1; + cfg->callback = 1; + if (p->local.flags & ISDN_NET_CBOUT) + cfg->callback = 2; cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0; cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0; cfg->ihup = (p->local.hupflags & 8) ? 1 : 0; @@ -2186,10 +2212,7 @@ save_flags(flags); cli(); inout &= 1; - n = p->local.phone[inout]; - if (n) - count++; - while (n) { + for (n = p->local.phone[inout]; n; n = n->next) { if (more) { put_fs_byte(' ', phones++); count++; @@ -2201,10 +2224,10 @@ memcpy_tofs(phones, n->num, strlen(n->num) + 1); phones += strlen(n->num); count += strlen(n->num); - n = n->next; more = 1; } put_fs_byte(0,phones); + count++; restore_flags(flags); return count; } diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.0.0/linux/drivers/isdn/isdn_ppp.c Mon May 20 08:20:59 1996 +++ linux/drivers/isdn/isdn_ppp.c Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.9 1996/05/18 01:37:01 fritz Exp $ +/* $Id: isdn_ppp.c,v 1.12 1996/06/24 17:42:03 fritz Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.12 1996/06/24 17:42:03 fritz + * Minor bugfixes. + * + * Revision 1.11 1996/06/16 17:46:05 tsbogend + * changed unsigned long to u32 to make Alpha people happy + * + * Revision 1.10 1996/06/11 14:50:29 hipp + * Lot of changes and bugfixes. + * New scheme to resend packets to busy LL devices. + * * Revision 1.9 1996/05/18 01:37:01 fritz * Added spelling corrections and some minor changes * to stay in sync with kernel. @@ -69,7 +79,7 @@ #endif /* Prototypes */ -static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor); +static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor); static int isdn_ppp_closewait(int); static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); @@ -83,7 +93,7 @@ int BEbyte, int *sqno, int min_sqno); #endif -char *isdn_ppp_revision = "$Revision: 1.9 $"; +char *isdn_ppp_revision = "$Revision: 1.12 $"; struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; extern int isdn_net_force_dial_lp(isdn_net_local *); @@ -95,10 +105,13 @@ int isdn_ppp_free(isdn_net_local *lp) { isdn_net_local *master_lp=lp; + unsigned long flags; if (lp->ppp_minor < 0) return 0; + save_flags(flags); + cli(); #ifdef CONFIG_ISDN_MPP if(lp->master) master_lp = (isdn_net_local *) lp->master->priv; @@ -123,7 +136,7 @@ ippp_table[lp->ppp_minor]->lp = NULL; /* link is down .. set lp to NULL */ lp->ppp_minor = -1; /* is this OK ?? */ - + restore_flags(flags); return 0; } @@ -286,6 +299,7 @@ #ifdef CONFIG_ISDN_PPP_VJ slhc_free(ippp_table[minor]->slcomp); + ippp_table[minor]->slcomp = NULL; kfree(ippp_table[minor]->cbuf); #endif @@ -394,7 +408,25 @@ case PPPIOCSMAXCID: /* set the maximum compression slot id */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor]->maxcid = val; + val++; + if(ippp_table[minor]->maxcid != val) { +#ifdef CONFIG_ISDN_PPP_VJ + struct slcompress *sltmp; +#endif + if(ippp_table[minor]->debug & 0x1) + printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val); + ippp_table[minor]->maxcid = val; +#ifdef CONFIG_ISDN_PPP_VJ + sltmp = slhc_init(16,val); + if(!sltmp) { + printk(KERN_ERR "ippp, can't realloc slhc struct\n"); + return -ENOMEM; + } + if(ippp_table[minor]->slcomp) + slhc_free(ippp_table[minor]->slcomp); + ippp_table[minor]->slcomp = sltmp; +#endif + } break; case PPPIOCGDEBUG: if ((r = set_arg((void *) arg, ippp_table[minor]->debug))) @@ -453,10 +485,11 @@ * fill up isdn_ppp_read() queue .. */ -static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor) +static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor) { struct ippp_buf_queue *bf, *bl; unsigned long flags; + unsigned char *nbuf; if (minor < 0 || minor >= ISDN_MAX_CHANNELS) { printk(KERN_WARNING "ippp: illegal minor.\n"); @@ -466,6 +499,18 @@ printk(KERN_DEBUG "ippp: device not activated.\n"); return 0; } + + nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC); + if(!nbuf) { + printk(KERN_WARNING "ippp: Can't alloc buf\n"); + return 0; + } + nbuf[0] = PPP_ALLSTATIONS; + nbuf[1] = PPP_UI; + nbuf[2] = proto >> 8; + nbuf[3] = proto & 0xff; + memcpy(nbuf+4, buf, len); + save_flags(flags); cli(); @@ -478,20 +523,9 @@ kfree(bf->buf); ippp_table[minor]->first = bf; } - bl->buf = (char *) kmalloc(len+4, GFP_ATOMIC); - if (!bl->buf) { - printk(KERN_WARNING "ippp: Can't alloc buf\n"); - restore_flags(flags); - return 0; - } + bl->buf = (char *) nbuf; bl->len = len+4; - bl->buf[0] = PPP_ALLSTATIONS; - bl->buf[1] = PPP_UI; - bl->buf[2] = proto >> 8; - bl->buf[3] = proto & 0xff; - memcpy(bl->buf+4, buf, len); - ippp_table[minor]->last = bl->next; restore_flags(flags); @@ -561,9 +595,23 @@ return 0; if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 && - (lp->flags & ISDN_NET_CONNECTED)) - isdn_writebuf_stub(lp->isdn_device,lp->isdn_channel, - buf, count, 1); + (lp->flags & ISDN_NET_CONNECTED)) { + struct sk_buff *skb; + skb = dev_alloc_skb(count); + if(!skb) { + printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); + return count; + } + skb->free = 1; + memcpy_fromfs(skb_put(skb, count), buf, count); + if(isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb) != count) { + if(lp->sav_skb) { + dev_kfree_skb(lp->sav_skb,FREE_WRITE); + printk(KERN_INFO "isdn_ppp_write: freeing sav_skb!\n"); + } + lp->sav_skb = skb; + } + } } return count; @@ -617,6 +665,11 @@ if(ippp_table[lp->ppp_minor]->debug & 0x4) printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len); + if(net_dev->local.master) { + printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n"); + net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev; + } + if(skb->data[0] == 0xff && skb->data[1] == 0x03) skb_pull(skb,2); else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) { @@ -819,8 +872,13 @@ skb->mac.raw = skb->data; pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb_old->len); - skb_trim(skb, pkt_len); dev_kfree_skb(skb_old,FREE_WRITE); + if(pkt_len < 0) { + dev_kfree_skb(skb,FREE_WRITE); + lp->stats.rx_dropped++; + return; + } + skb_trim(skb, pkt_len); skb->protocol = htons(ETH_P_IP); } #else @@ -848,6 +906,7 @@ * send ppp frame .. we expect a PIDCOMPressable proto -- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) */ + int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) { struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */ @@ -861,32 +920,43 @@ else mlp = (isdn_net_local *) (dev->priv); nd = mlp->netdev; /* get master lp */ - lp = nd->queue; /* get lp on top of queue */ - ipt = ippp_table[lp->ppp_minor]; ipts = ippp_table[mlp->ppp_minor]; - if (!(ipt->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel); + if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ + printk(KERN_INFO "%s: IP frame delayed.\n",dev->name); return 1; } + + lp = nd->queue; /* get lp on top of queue */ + if(lp->sav_skb) { /* find a non-busy device */ + isdn_net_local *nlp = lp->next; + while(lp->sav_skb) { + if(lp == nlp) + return 1; + nlp = nd->queue = nd->queue->next; + } + lp = nlp; + } + ipt = ippp_table[lp->ppp_minor]; + lp->huptimer = 0; /* If packet is to be resent, it has already been processed and * therefore its first bytes are already initialized. In this case * send it immediately ... */ - if (*((unsigned long *)skb->data) != 0) + if (*((u32 *)skb->data) != 0) { + printk(KERN_ERR "%s: Whoops .. packet resend should no longer happen!\n",dev->name); return (isdn_net_send_skb(dev , lp , skb)); + } /* ... else packet needs processing. */ -/* future: step to next 'lp' when this lp is 'tbusy' */ - if(ippp_table[lp->ppp_minor]->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len); #ifdef CONFIG_ISDN_PPP_VJ - if (ipt->pppcfg & SC_COMP_TCP) { /* ipt or ipts ? -> check this again! */ + if (ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but check again */ u_char *buf = skb->data; int pktlen; int len = 4; @@ -947,7 +1017,15 @@ skb->data[3] = proto & 0xff; /* tx-stats are now updated via BSENT-callback */ - return (isdn_net_send_skb(dev , lp , skb)); + if(isdn_net_send_skb(dev , lp , skb)) { + if(lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ + printk(KERN_ERR "%s: whoops .. there is another stored skb!\n!",dev->name); + dev_kfree_skb(skb,FREE_WRITE); + } + else + lp->sav_skb = skb; + } + return 0; } void isdn_ppp_free_sqqueue(isdn_net_dev * p) @@ -1165,6 +1243,9 @@ static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno) { +#ifdef CONFIG_ISDN_PPP_VJ + int toss = 0; +#endif /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft: eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen wenn sqnolast; dev_kfree_skb(q->skb,FREE_WRITE); kfree(q); +#ifdef CONFIG_ISDN_PPP_VJ + toss = 1; +#endif q = ql; } q = dev->mp_last; @@ -1191,6 +1275,11 @@ } else break; } +#ifdef CONFIG_ISDN_PPP_VJ + /* did we free a stale frame ? */ + if(toss) + slhc_toss(ippp_table[dev->local.ppp_minor]->slcomp); +#endif } /* @@ -1207,7 +1296,7 @@ while (net_dev) { isdn_net_local *lp = &net_dev->local; - if (net_dev->ib.modify) { /* interface locked? */ + if (net_dev->ib.modify || lp->master) { /* interface locked or slave?*/ net_dev = net_dev->next; continue; } @@ -1215,6 +1304,13 @@ q = net_dev->ib.sq; while (q) { if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) { + +#ifdef CONFIG_ISDN_PPP_VJ + /* did we step over a missing frame ? */ + if(q->sqno_start != net_dev->ib.next_num) + slhc_toss(ippp_table[lp->ppp_minor]->slcomp); +#endif + ql = net_dev->ib.sq; net_dev->ib.sq = q->next; net_dev->ib.next_num = q->sqno_end + 1; @@ -1234,6 +1330,49 @@ #endif } +/* + * network device ioctl handlers + */ + +static int isdn_ppp_dev_ioctl_stats(int minor,struct ifreq *ifr,struct device *dev) +{ + struct ppp_stats *res, t; + isdn_net_local *lp = (isdn_net_local *) dev->priv; + int err; + + res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; + err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats)); + + if(err) + return err; + + /* build a temporary stat struct and copy it to user space */ + + memset (&t, 0, sizeof(struct ppp_stats)); + if(dev->flags & IFF_UP) { + t.p.ppp_ipackets = lp->stats.rx_packets; + t.p.ppp_ierrors = lp->stats.rx_errors; + t.p.ppp_opackets = lp->stats.tx_packets; + t.p.ppp_oerrors = lp->stats.tx_errors; +#ifdef CONFIG_ISDN_PPP_VJ + if(minor >= 0 && ippp_table[minor]->slcomp) { + struct slcompress *slcomp = ippp_table[minor]->slcomp; + t.vj.vjs_packets = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed; + t.vj.vjs_compressed = slcomp->sls_o_compressed; + t.vj.vjs_searches = slcomp->sls_o_searches; + t.vj.vjs_misses = slcomp->sls_o_misses; + t.vj.vjs_errorin = slcomp->sls_i_error; + t.vj.vjs_tossed = slcomp->sls_i_tossed; + t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed; + t.vj.vjs_compressedin = slcomp->sls_i_compressed; + } +#endif + } + memcpy_tofs (res, &t, sizeof (struct ppp_stats)); + return 0; + +} + int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { int error; @@ -1241,19 +1380,27 @@ int len; isdn_net_local *lp = (isdn_net_local *) dev->priv; +#if 1 + printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_minor); +#endif + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) return -EINVAL; switch (cmd) { - case SIOCGPPPVER: - r = (char *) ifr->ifr_ifru.ifru_data; - len = strlen(PPP_VERSION) + 1; - error = verify_area(VERIFY_WRITE, r, len); - if (!error) - memcpy_tofs(r, PPP_VERSION, len); - break; - default: - error = -EINVAL; + case SIOCGPPPVER: + r = (char *) ifr->ifr_ifru.ifru_data; + len = strlen(PPP_VERSION) + 1; + error = verify_area(VERIFY_WRITE, r, len); + if (!error) + memcpy_tofs(r, PPP_VERSION, len); + break; + case SIOCGPPPSTATS: + error = isdn_ppp_dev_ioctl_stats (lp->ppp_minor, ifr, dev); + break; + default: + error = -EINVAL; + break; } return error; } diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.0.0/linux/drivers/isdn/isdn_tty.c Sun Jun 9 13:28:43 1996 +++ linux/drivers/isdn/isdn_tty.c Sat Jun 29 20:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.18 1996/06/07 11:17:33 tsbogend Exp $ +/* $Id: isdn_tty.c,v 1.21 1996/06/24 17:40:28 fritz Exp $ * * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.21 1996/06/24 17:40:28 fritz + * Bugfix: Did not compile without CONFIG_ISDN_AUDIO + * + * Revision 1.20 1996/06/15 14:59:39 fritz + * Fixed isdn_tty_tint() to handle partially sent + * sk_buffs. + * + * Revision 1.19 1996/06/12 15:53:56 fritz + * Bugfix: AT+VTX and AT+VRX could be executed without + * having a connection. + * Missing check for NULL tty in isdn_tty_flush_buffer(). + * * Revision 1.18 1996/06/07 11:17:33 tsbogend * added missing #ifdef CONFIG_ISDN_AUDIO to make compiling without * audio support possible @@ -127,7 +139,7 @@ static int bit2si[8] = {1,5,7,7,7,7,7,7}; static int si2bit[8] = {4,1,4,4,4,4,4,4}; -char *isdn_tty_revision = "$Revision: 1.18 $"; +char *isdn_tty_revision = "$Revision: 1.21 $"; #define DLE 0x10 #define ETX 0x03 @@ -262,10 +274,13 @@ static void isdn_tty_tint(modem_info *info) { struct sk_buff *skb = skb_dequeue(&info->xmit_queue); + int len, slen; if (!skb) return; - if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel, skb) > 0) { + len = skb->len; + if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, + info->isdn_channel, skb)) == len) { struct tty_struct *tty = info->tty; info->send_outstanding++; info->msr |= UART_MSR_CTS; @@ -276,6 +291,8 @@ wake_up_interruptible(&tty->write_wait); return; } + if (slen > 0) + skb_pull(skb,slen); skb_queue_head(&info->xmit_queue, skb); } @@ -369,10 +386,11 @@ } return 0; } -#endif /* CONFIG_ISDN_AUDIO */ static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 }; +#endif /* CONFIG_ISDN_AUDIO */ + /* isdn_tty_senddown() is called either directly from within isdn_tty_write() * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls * outgoing data from the tty's xmit-buffer, handles voice-decompression or @@ -398,8 +416,8 @@ return; } skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; - if (info->vonline & 2) { #ifdef CONFIG_ISDN_AUDIO + if (info->vonline & 2) { /* For now, ifmt is fixed to 1 (alaw), since this * is used with ISDN everywhere in the world, except * US, Canada and Japan. @@ -454,8 +472,8 @@ if (!info->vonline) isdn_tty_at_cout("\r\nVCON\r\n",info); } -#endif /* CONFIG_ISDN_AUDIO */ } else { +#endif /* CONFIG_ISDN_AUDIO */ skb = dev_alloc_skb(buflen + skb_res); if (!skb) { printk(KERN_WARNING @@ -467,7 +485,9 @@ memcpy(skb_put(skb,buflen),buf,buflen); info->xmit_count = 0; restore_flags(flags); +#ifdef CONFIG_ISDN_AUDIO } +#endif skb->free = 1; if (info->emu.mdmreg[13] & 2) /* Add T.70 simplified header */ @@ -591,6 +611,9 @@ if (!info) return; +#ifdef ISDN_DEBUG_MODEM_HUP + printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); +#endif info->rcvsched = 0; info->online = 0; isdn_tty_flush_buffer(info->tty); @@ -896,13 +919,20 @@ static void isdn_tty_flush_buffer(struct tty_struct *tty) { - modem_info *info = (modem_info *) tty->driver_data; + modem_info *info; unsigned long flags; - if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) - return; save_flags(flags); cli(); + if (!tty) { + restore_flags(flags); + return; + } + info = (modem_info *) tty->driver_data; + if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) { + restore_flags(flags); + return; + } isdn_tty_cleanup_xmit(info); info->xmit_count = 0; restore_flags(flags); @@ -2324,6 +2354,10 @@ /* AT+VRX - Start recording */ if (!m->vpar[0]) PARSE_ERROR1; + if (info->online != 1) { + isdn_tty_modem_result(8, info); + return 1; + } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); if (!info->dtmf_state) { printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); @@ -2430,6 +2464,10 @@ /* AT+VTX - Start sending */ if (!m->vpar[0]) PARSE_ERROR1; + if (info->online != 1) { + isdn_tty_modem_result(8, info); + return 1; + } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); if (!info->dtmf_state) { printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c --- v2.0.0/linux/drivers/isdn/pcbit/callbacks.c Wed Apr 24 17:00:39 1996 +++ linux/drivers/isdn/pcbit/callbacks.c Sat Jun 29 20:36:22 1996 @@ -59,7 +59,8 @@ * - kfree when msg has been sent */ - if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb)) < 0) + if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, + chan->proto)) < 0) { printk("capi_conn_req failed\n"); return; diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c --- v2.0.0/linux/drivers/isdn/pcbit/capi.c Wed Apr 24 17:00:39 1996 +++ linux/drivers/isdn/pcbit/capi.c Sat Jun 29 20:36:22 1996 @@ -58,7 +58,7 @@ * */ -int capi_conn_req(const char * calledPN, struct sk_buff **skb) +int capi_conn_req(const char * calledPN, struct sk_buff **skb, int proto) { ushort len; @@ -80,6 +80,9 @@ len = 18 + strlen(calledPN); + if (proto == ISDN_PROTO_L2_TRANS) + len++; + if ((*skb = dev_alloc_skb(len)) == NULL) { printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n"); @@ -89,11 +92,21 @@ /* InfoElmMask */ *((ushort*) skb_put(*skb, 2)) = AppInfoMask; - - /* Bearer Capability - Mandatory*/ - *(skb_put(*skb, 1)) = 2; /* BC0.Length */ - *(skb_put(*skb, 1)) = 0x88; /* BC0.Octect3 - Digital Information */ - *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 - */ + if (proto == ISDN_PROTO_L2_TRANS) + { + /* Bearer Capability - Mandatory*/ + *(skb_put(*skb, 1)) = 3; /* BC0.Length */ + *(skb_put(*skb, 1)) = 0x80; /* Speech */ + *(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */ + *(skb_put(*skb, 1)) = 0x23; /* A-law */ + } + else + { + /* Bearer Capability - Mandatory*/ + *(skb_put(*skb, 1)) = 2; /* BC0.Length */ + *(skb_put(*skb, 1)) = 0x88; /* Digital Information */ + *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */ + } /* Bearer Capability - Optional*/ *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */ @@ -220,16 +233,19 @@ *(skb_put(*skb, 1)) = 0x05; /* LAPB */ break; case ISDN_PROTO_L2_HDLC: -#ifdef DEBUG - printk(KERN_DEBUG "HDLC\n"); /* HDLC */ -#endif *(skb_put(*skb, 1)) = 0x02; break; + case ISDN_PROTO_L2_TRANS: + /* + * Voice (a-law) + */ + *(skb_put(*skb, 1)) = 0x06; + break; default: #ifdef DEBUG printk(KERN_DEBUG "Transparent\n"); #endif - *(skb_put(*skb, 1)) = 0x03; + *(skb_put(*skb, 1)) = 0x03; break; } diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/capi.h linux/drivers/isdn/pcbit/capi.h --- v2.0.0/linux/drivers/isdn/pcbit/capi.h Wed Apr 24 17:00:39 1996 +++ linux/drivers/isdn/pcbit/capi.h Sat Jun 29 20:36:22 1996 @@ -22,7 +22,8 @@ #define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER /* Connection Setup */ -extern int capi_conn_req(const char * calledPN, struct sk_buff **buf); +extern int capi_conn_req(const char * calledPN, struct sk_buff **buf, + int proto); extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb, int *complete); diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.0.0/linux/drivers/isdn/pcbit/drv.c Mon May 20 08:21:00 1996 +++ linux/drivers/isdn/pcbit/drv.c Sat Jun 29 20:36:22 1996 @@ -11,6 +11,14 @@ * PCBIT-D interface with isdn4linux */ +/* + * Fixes: + * + * Nuno Grilo + * fixed msn_list NULL pointer dereference. + * + */ + #define __NO_VERSION__ #include @@ -109,7 +117,7 @@ dev->b2->id = 1; - dev->qdelivery.next = 0; + dev->qdelivery.next = NULL; dev->qdelivery.sync = 0; dev->qdelivery.routine = pcbit_deliver; dev->qdelivery.data = dev; @@ -152,8 +160,8 @@ dev_if->channels = 2; - dev_if->features = ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_L2_HDLC; + dev_if->features = (ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS ); dev_if->writebuf_skb = pcbit_xmit; dev_if->writebuf = NULL; @@ -1051,7 +1059,8 @@ static void pcbit_set_msn(struct pcbit_dev *dev, char *list) { - struct msn_entry *ptr, *back; + struct msn_entry *ptr; + struct msn_entry *back = NULL; char *cp, *sp; int len; @@ -1070,7 +1079,8 @@ return; } - for (back=dev->msn_list; back->next; back=back->next); + if (dev->msn_list) + for (back=dev->msn_list; back->next; back=back->next); sp = list; @@ -1128,10 +1138,3 @@ return 0; } - - - - - - - diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c --- v2.0.0/linux/drivers/isdn/pcbit/edss1.c Wed Apr 24 17:00:39 1996 +++ linux/drivers/isdn/pcbit/edss1.c Sat Jun 29 20:36:22 1996 @@ -288,15 +288,10 @@ save_flags(flags); cli(); - if (chan->fsm_timer.function) { - del_timer(&chan->fsm_timer); - chan->fsm_timer.function = NULL; - } for (action = fsm_table; action->init != 0xff; action++) if (action->init == chan->fsm_state && action->event == event) break; - if (action->init == 0xff) { @@ -304,6 +299,11 @@ event, chan->fsm_state); return; } + + if (chan->fsm_timer.function) { + del_timer(&chan->fsm_timer); + chan->fsm_timer.function = NULL; + } chan->fsm_state = action->final; diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c --- v2.0.0/linux/drivers/isdn/pcbit/layer2.c Wed Apr 24 17:00:39 1996 +++ linux/drivers/isdn/pcbit/layer2.c Sat Jun 29 20:36:22 1996 @@ -58,16 +58,7 @@ /* * task queue struct */ -struct tq_struct *tq_delivery=NULL; -static void do_pcbit_bh(task_queue *list) -{ - run_task_queue(list); -} - -struct tq_struct run_delivery= { - 0, 0, (void *)(void *) do_pcbit_bh, &tq_delivery, -}; /* @@ -87,7 +78,6 @@ static void pcbit_transmit(struct pcbit_dev * dev); static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); -static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq); static void pcbit_l2_error(struct pcbit_dev *dev); static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info); @@ -95,11 +85,10 @@ static void pcbit_firmware_bug(struct pcbit_dev * dev); -static void pcbit_sched_delivery(struct pcbit_dev *dev) +static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev) { - queue_task_irq_off(&dev->qdelivery, &tq_delivery); - queue_task_irq_off(&run_delivery, &tq_immediate); - mark_bh(IMMEDIATE_BH); + queue_task(&dev->qdelivery, &tq_immediate); + mark_bh(IMMEDIATE_BH); } @@ -195,11 +184,10 @@ unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07; - if (dev->free > 16 && dev->write_queue && unacked < 7) { - - save_flags(flags); - cli(); + save_flags(flags); + cli(); + if (dev->free > 16 && dev->write_queue && unacked < 7) { if (!dev->w_busy) dev->w_busy = 1; @@ -209,11 +197,12 @@ return; } - restore_flags(flags); frame = dev->write_queue; free = dev->free; + restore_flags(flags); + if (frame->copied == 0) { /* Type 0 frame */ @@ -311,12 +300,15 @@ dev->w_busy = 0; restore_flags(flags); } -#ifdef DEBUG else + { + restore_flags(flags); +#ifdef DEBUG printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", unacked, dev->free, dev->write_queue ? "not empty" : - "empty"); + "empty"); #endif + } } @@ -334,29 +326,31 @@ save_flags(flags); cli(); - /* get frame from queue */ - if (!(frame=dev->read_queue)) { + while((frame=dev->read_queue)) + { + dev->read_queue = frame->next; restore_flags(flags); - return; - } - dev->read_queue = frame->next; - restore_flags(flags); + msg.cpu = 0; + msg.proc = 0; + msg.cmd = frame->skb->data[2]; + msg.scmd = frame->skb->data[3]; - msg.cpu = 0; - msg.proc = 0; - msg.cmd = frame->skb->data[2]; - msg.scmd = frame->skb->data[3]; + frame->refnum = *((ushort*) frame->skb->data + 4); + frame->msg = *((ulong*) &msg); + + skb_pull(frame->skb, 6); - frame->refnum = *((ushort*) frame->skb->data + 4); - frame->msg = *((ulong*) &msg); - - skb_pull(frame->skb, 6); + pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, + frame->refnum); - pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, - frame->refnum); + kfree(frame); - kfree(frame); + save_flags(flags); + cli(); + } + + restore_flags(flags); } /* @@ -517,8 +511,7 @@ } else dev->read_queue = frame; - - pcbit_sched_delivery(dev); + restore_flags(flags); } @@ -572,7 +565,6 @@ { struct pcbit_dev * dev; u_char info, ack_seq, read_seq; - u_char ack_int = 1; dev = (struct pcbit_dev *) devptr; @@ -618,33 +610,27 @@ read_seq = (info & 0x07U); dev->interrupt = 0; - sti(); - - /* - * Bottom Half - * Runs with ints enabled - */ if (read_seq != dev->rcv_seq) { - pcbit_frame_read(dev, read_seq); - ack_int = 0; + while (read_seq != dev->rcv_seq) + { + pcbit_receive(dev); + dev->rcv_seq = (dev->rcv_seq + 1) % 8; + } + pcbit_sched_delivery(dev); } if (ack_seq != dev->unack_seq) { pcbit_recv_ack(dev, ack_seq); - ack_int = 0; } - if (ack_int) - { - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; + + info = dev->rcv_seq << 3; + info |= dev->send_seq; - writeb(info, dev->sh_mem + BANK4); - } + writeb(info, dev->sh_mem + BANK4); } @@ -685,17 +671,19 @@ del_timer(&dev->error_recover_timer); if (dev->w_busy || dev->r_busy) - { - init_timer(&dev->error_recover_timer); - dev->error_recover_timer.expires = jiffies + ERRTIME; - add_timer(&dev->error_recover_timer); - return; - } + { + init_timer(&dev->error_recover_timer); + dev->error_recover_timer.expires = jiffies + ERRTIME; + add_timer(&dev->error_recover_timer); + return; + } dev->w_busy = dev->r_busy = 1; - if (dev->read_frame) { - if (dev->read_frame->skb) { + if (dev->read_frame) + { + if (dev->read_frame->skb) + { dev->read_frame->skb->free = 1; kfree_skb(dev->read_frame->skb, FREE_READ); } @@ -704,7 +692,8 @@ } - if (dev->write_queue) { + if (dev->write_queue) + { frame = dev->write_queue; #ifdef FREE_ON_ERROR dev->write_queue = dev->write_queue->next; @@ -775,14 +764,20 @@ { if (dev->send_seq > dev->unack_seq) - if (ack <= dev->unack_seq || ack > dev->send_seq) + if (ack <= dev->unack_seq || ack > dev->send_seq) { - printk("layer 2 ack unacceptable - dev %d", dev->id); + printk(KERN_DEBUG + "layer 2 ack unacceptable - dev %d", + dev->id); + pcbit_l2_error(dev); } else - if (ack > dev->send_seq && ack <= dev->unack_seq) { - printk("layer 2 ack unacceptable - dev %d", dev->id); + if (ack > dev->send_seq && ack <= dev->unack_seq) + { + printk(KERN_DEBUG + "layer 2 ack unacceptable - dev %d", + dev->id); pcbit_l2_error(dev); } @@ -805,55 +800,9 @@ if (dev->send_seq == lsend_seq) break; - count++; - } - - if (!count) { - u_char info; - - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; - - writeb(info, dev->sh_mem + BANK4); - } + count++; + } } else printk(KERN_DEBUG "recv_ack: unacked = 0\n"); } - -static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq) -{ - unsigned long flags; - int busy; - u_char info; - - save_flags(flags); - cli(); - if (!(busy=dev->r_busy)) - dev->r_busy = 1; - restore_flags(flags); - - if (busy) - return; - - - while (read_seq != dev->rcv_seq) { - pcbit_receive(dev); - dev->rcv_seq = (dev->rcv_seq + 1) % 8; - } - - dev->r_busy = 0; - - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; - - writeb(info, dev->sh_mem + BANK4); -} - - - - - - diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c --- v2.0.0/linux/drivers/isdn/teles/callc.c Sun Jun 9 13:28:43 1996 +++ linux/drivers/isdn/teles/callc.c Sat Jun 29 20:36:23 1996 @@ -1,6 +1,12 @@ -/* $Id: callc.c,v 1.11 1996/06/07 12:32:20 fritz Exp $ +/* $Id: callc.c,v 1.13 1996/06/24 17:15:55 fritz Exp $ * * $Log: callc.c,v $ + * Revision 1.13 1996/06/24 17:15:55 fritz + * corrected return code of teles_writebuf() + * + * Revision 1.12 1996/06/12 16:15:33 fritz + * Extended user-configurable debugging flags. + * * Revision 1.11 1996/06/07 12:32:20 fritz * More changes to support suspend/resume. * @@ -1297,8 +1303,10 @@ chanlist[i].ds.l2.l2m.debug = debugflags & 16; } for (i = 0; i < nrcards; i++) - if (cards[i].sp) + if (cards[i].sp) { cards[i].sp->dlogflag = debugflags & 4; + cards[i].sp->debug = debugflags & 32; + } } int @@ -1419,12 +1427,15 @@ if (!chanp->data_open) { printk(KERN_DEBUG "teles_writebuf: channel not open\n"); - return -ENOMEM; + return -EIO; } err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21); if (err) - return -ENOMEM; + /* Must return 0 here, since this is not an error + * but a temporary lack of resources. + */ + return 0; ptr = DATAPTR(ibh); if (chanp->lc_b.l2_establish) diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c --- v2.0.0/linux/drivers/isdn/teles/card.c Sun Jun 9 13:28:43 1996 +++ linux/drivers/isdn/teles/card.c Sat Jun 29 20:36:23 1996 @@ -1,4 +1,4 @@ -/* $Id: card.c,v 1.9 1996/06/06 14:42:09 fritz Exp $ +/* $Id: card.c,v 1.12 1996/06/24 17:16:52 fritz Exp $ * * card.c low level stuff for the Teles S0 isdn card * @@ -7,6 +7,16 @@ * Beat Doebeli log all D channel traffic * * $Log: card.c,v $ + * Revision 1.12 1996/06/24 17:16:52 fritz + * Added check for misconfigured membase. + * + * Revision 1.11 1996/06/14 03:30:37 fritz + * Added recovery from EXIR 40 interrupt. + * Some cleanup. + * + * Revision 1.10 1996/06/11 14:57:20 hipp + * minor changes to ensure, that SKBs are sent in the right order + * * Revision 1.9 1996/06/06 14:42:09 fritz * Bugfix: forgot hsp-> in last change. * @@ -52,7 +62,6 @@ #include #undef DCHAN_VERBOSE -#define FRITZ_EXPERIMENTAL extern void tei_handler(struct PStack *st, byte pr, struct BufHeader *ibh); @@ -215,16 +224,9 @@ static inline void waitforXFW_0(byte * base, byte hscx) { -#ifdef FRITZ_EXPERIMENTAL long to = 20; while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) { -#else - long to = 10; - - waitforCEC_0(base, hscx); - while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x40)) && to) { -#endif udelay(5); to--; } @@ -235,16 +237,9 @@ static inline void waitforXFW_3(int iobase, byte hscx) { -#ifdef FRITZ_EXPERIMENTAL long to = 20; while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) { -#else - long to = 10; - - waitforCEC_3(iobase, hscx); - while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x40)) && to) { -#endif udelay(5); to--; } @@ -507,10 +502,10 @@ } else { if (hsp->releasebuf) BufPoolRelease(hsp->xmtibh); - hsp->xmtibh = NULL; hsp->sendptr = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; } if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { hsp->releasebuf = !0; @@ -709,7 +704,7 @@ static void teles_interrupt(int intno, void *dev_id, struct pt_regs *regs) { - byte val, val2, r, exval; + byte val, r, exval; struct IsdnCardState *sp; unsigned int count; struct HscxState *hsp; @@ -725,11 +720,20 @@ if (val & 0x01) { hsp = sp->hs + 1; exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR); - if ((hsp->mode == 1) || (exval == 0x40)) - hscx_fill_fifo(hsp); - else - printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n", - exval, (long) hsp->xmtibh, (long) hsp->rcvibh); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + WRITEHSCX_CMDR(hsp->membase, hsp->iobase, + hsp->hscx, 0x01); + printk(KERN_DEBUG "HSCX B EXIR %x\n", exval); + } + } else + printk(KERN_WARNING "HSCX B EXIR %x\n", exval); } if (val & 0xf8) { if (sp->debug) @@ -739,33 +743,28 @@ if (val & 0x02) { hsp = sp->hs; exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR); - if ((hsp->mode == 1) && (exval == 0x40)) - hscx_fill_fifo(hsp); - else - printk(KERN_WARNING "HSCX A EXIR %x\n",exval); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + WRITEHSCX_CMDR(hsp->membase, hsp->iobase, + hsp->hscx, 0x01); + printk(KERN_DEBUG "HSCX A EXIR %x\n", exval); + } + } else + printk(KERN_WARNING "HSCX A EXIR %x\n", exval); } - -/* ??? Why do that vvvvvvvvvvvvvvvvvvvvv different on Teles 16-3 ??? */ - if (sp->membase) { - if (val & 0x04) { - val = readhscx_0(sp->membase, 0, HSCX_ISTA); - if (sp->debug) - printk(KERN_DEBUG "HSCX A interrupt %x\n", - val); - hscx_interrupt(sp, val, 0); - } - } else { - val2 = readhscx_3(sp->iobase, 0, HSCX_ISTA); + if (val & 0x04) { + val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA); if (sp->debug) - printk(KERN_DEBUG "HSCX A ISTA %x\n", val2); - if (val & 0x04) { - if (sp->debug) - printk(KERN_DEBUG "HSCX A interrupt %x\n", - val2); - hscx_interrupt(sp, val2, 0); - } + printk(KERN_DEBUG "HSCX A interrupt %x\n", + val); + hscx_interrupt(sp, val, 0); } -/* ??? Why do that ^^^^^^^^^^^^^^^^^^^^^ different on Teles 16-3 ??? */ val = READISAC(sp->membase, sp->iobase, ISAC_ISTA); @@ -1083,6 +1082,13 @@ byte cfval, val; struct IsdnCard *card = cards + cardnr; + if (card->membase) + if ((unsigned long)card->membase < 0x10000) { + (unsigned long)card->membase <<= 4; + printk(KERN_INFO + "Teles membase configured DOSish, assuming 0x%lx\n", + (unsigned long)card->membase); + } if (!card->iobase) { if (card->membase) { printk(KERN_NOTICE @@ -1090,7 +1096,7 @@ (long) card->membase, card->interrupt, (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : "EDSS1"); - printk(KERN_INFO "HSCX version A: %x B:%x\n", + printk(KERN_INFO "HSCX version A:%x B:%x\n", readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf, readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf); } @@ -1736,12 +1742,18 @@ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; struct HscxState *hsp = sp->hs + st->l1.hscx; + long flags; switch (pr) { case (PH_DATA): - if (hsp->xmtibh) + save_flags(flags); + cli(); + if (hsp->xmtibh) { BufQueueLink(&hsp->sq, ibh); + restore_flags(flags); + } else { + restore_flags(flags); hsp->xmtibh = ibh; hsp->sendptr = 0; hsp->releasebuf = !0; diff -u --recursive --new-file v2.0.0/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.0.0/linux/drivers/net/de4x5.c Sat Jun 1 20:11:32 1996 +++ linux/drivers/net/de4x5.c Sat Jun 29 11:12:16 1996 @@ -1,4 +1,4 @@ -/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux. +/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE450/DE500 ethernet driver for Linux. Copyright 1994, 1995 Digital Equipment Corporation. @@ -191,15 +191,25 @@ Fix bug in dc21040 and dc21041 autosense code. Remove buffer copies on receive for Intels. Change sk_buff handling during media disconnects to - eliminate DUP packets. + eliminate DUP packets. Add dynamic TX thresholding. Change all chips to use perfect multicast filtering. Fix alloc_device() bug + 0.43 21-Jun-96 Fix unconnected media TX retry bug. + Add Accton to the list of broken cards. + Fix TX under-run bug for non DC21140 chips. + Fix boot command probe bug in alloc_device() as + reported by and + . + Add cache locks to prevent a race condition as + reported by and + . + Upgraded alloc_device() code. ========================================================================= */ -static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n"; +static const char *version = "de4x5.c:v0.43 96/6/21 davies@wanton.lkg.dec.com\n"; #include @@ -226,6 +236,7 @@ #include #include #include +#include #include "de4x5.h" @@ -274,10 +285,12 @@ ** Define special SROM detection cases */ static c_char enet_det[][ETH_ALEN] = { - {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00} + {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00} }; -#define SMC 1 +#define SMC 1 +#define ACCTON 2 #ifdef DE4X5_DEBUG @@ -511,6 +524,7 @@ struct { void *priv; /* Original kmalloc'd mem addr */ void *buf; /* Original kmalloc'd mem addr */ + int lock; /* Lock the cache accesses */ s32 csr0; /* Saved Bus Mode Register */ s32 csr6; /* Saved Operating Mode Reg. */ s32 csr7; /* Saved IRQ Mask Register */ @@ -633,12 +647,15 @@ static void eisa_probe(struct device *dev, u_long iobase); static void pci_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); +static struct device *insert_device(struct device *dev, u_long iobase, + int (*init)(struct device *)); static char *build_setup_frame(struct device *dev, int mode); static void disable_ast(struct device *dev); static void enable_ast(struct device *dev, u32 time_out); static long de4x5_switch_to_srl(struct device *dev); static long de4x5_switch_to_mii(struct device *dev); static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec); +static int de4x5_dev_index(char *s); static void de4x5_dbg_open(struct device *dev); static void de4x5_dbg_mii(struct device *dev, int k); static void de4x5_dbg_media(struct device *dev); @@ -683,7 +700,7 @@ { int tmp = num_de4x5s, status = -ENODEV; u_long iobase = dev->base_addr; - + eisa_probe(dev, iobase); pci_probe(dev, iobase); @@ -691,7 +708,7 @@ printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name, iobase); } - + /* ** Walk the device list to check that at least one device ** initialised OK @@ -1076,6 +1093,7 @@ return 0; } + set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */ if (lp->tx_enable == NO) { /* Cannot send for now */ return -1; } @@ -1085,11 +1103,13 @@ ** interrupts are lost by delayed descriptor status updates relative to ** the irq assertion, especially with a busy PCI bus. */ - set_bit(0, (void*)&dev->tbusy); cli(); de4x5_tx(dev); sti(); - + + /* Test if cache is already locked - requeue skb if so */ + if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1; + /* Transmit descriptor ring full or stale skb */ if (dev->tbusy || lp->tx_skb[lp->tx_new]) { if (dev->interrupt) { @@ -1130,6 +1150,8 @@ } } + lp->cache.lock = 0; + return status; } @@ -1195,8 +1217,11 @@ } /* Load the TX ring with any locally stored packets */ - while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { - de4x5_queue_pkt(de4x5_get_cache(dev), dev); + if (!set_bit(0, (void *)&lp->cache.lock)) { + while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { + de4x5_queue_pkt(de4x5_get_cache(dev), dev); + } + lp->cache.lock = 0; } dev->interrupt = UNMASK_INTERRUPTS; @@ -1376,7 +1401,7 @@ int omr; omr = inl(DE4X5_OMR); - if (!(omr & OMR_SF)) { + if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) { omr &= ~(OMR_ST|OMR_SR); outl(omr, DE4X5_OMR); while (inl(DE4X5_STS) & STS_TS); @@ -1564,6 +1589,7 @@ u_long iobase; struct bus_type *lp = &bus; char name[DE4X5_STRLEN]; + struct device *tmp; if (!ioaddr && autoprobed) return; /* Been here before ! */ @@ -1589,15 +1615,14 @@ DevicePresent(EISA_APROM); /* Write the PCI Configuration Registers */ outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); - outl(0x00004000, PCI_CFLT); + outl(0x00006000, PCI_CFLT); outl(iobase, PCI_CBIO); if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if ((status = de4x5_hw_init(dev, iobase)) == 0) { + if ((tmp = alloc_device(dev, iobase)) != NULL) { + if ((status = de4x5_hw_init(tmp, iobase)) == 0) { num_de4x5s++; } - num_eth++; } } else if (autoprobed) { printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase); @@ -1632,6 +1657,7 @@ u_int class = DE4X5_CLASS_CODE; u_int iobase; struct bus_type *lp = &bus; + struct device *tmp; if ((!ioaddr || !loading_module) && autoprobed) return; @@ -1639,14 +1665,14 @@ lp->bus = PCI; - if (ioaddr < 0x1000) { + if ((ioaddr < 0x1000) && loading_module) { pbus = (u_short)(ioaddr >> 8); dnum = (u_short)(ioaddr & 0xff); } else { pbus = 0; dnum = 0; } - + for (index=0; (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { @@ -1667,7 +1693,7 @@ /* Get the board I/O address */ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase); iobase &= CBIO_MASK; - + /* Fetch the IRQ to be used */ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq); if ((irq == 0) || (irq == (u_char) 0xff)) continue; @@ -1684,12 +1710,11 @@ DevicePresent(DE4X5_APROM); if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { + if ((tmp = alloc_device(dev, iobase)) != NULL) { + tmp->irq = irq; + if ((status = de4x5_hw_init(tmp, iobase)) == 0) { num_de4x5s++; } - num_eth++; } } else if (autoprobed) { printk("%s: region already allocated at 0x%04x.\n", dev->name, @@ -1702,109 +1727,95 @@ } /* -** Allocate the device by pointing to the next available space in the -** device structure. Should one not be available, it is created. +** Search the entire 'eth' device list for a fixed probe. If a match isn't +** found then check for an autoprobe or unused device location. If they +** are not available then insert a new device structure at the end of +** the current list. */ static struct device * alloc_device(struct device *dev, u_long iobase) { - int addAutoProbe = 0; - struct device *tmp = NULL, *ret; - int (*init)(struct device *) = NULL; - + struct device *adev = NULL; + int fixed = 0, new_dev = 0; + + num_eth = de4x5_dev_index(dev->name); if (loading_module) return dev; - /* - ** Check the device structures for an end of list or unused device - */ - while (dev->next != NULL) { - if ((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0)) break; - dev = dev->next; /* walk through eth device list */ - num_eth++; /* increment eth device number */ + while (1) { + if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) { + adev=dev; + } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "eth", 3) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) break; + dev = dev->next; + num_eth++; } - - /* - ** If an autoprobe is requested for another device, we must re-insert - ** the request later in the list. Remember the current position first. - */ - if ((dev->base_addr == 0) && (num_de4x5s > 0)) { - addAutoProbe++; - tmp = dev->next; /* point to the next device */ - init = dev->init; /* remember the probe function */ + if (adev && !fixed) { + dev = adev; + num_eth = de4x5_dev_index(dev->name); + new_dev = 0; + } + + if (((dev->next == NULL) && + ((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_eth++; /* New device */ + dev = insert_device(dev, iobase, de4x5_probe); } - /* - ** If at end of list and can't use current entry, malloc one up. - ** If memory could not be allocated, print an error message. - */ - if ((dev->next == NULL) && - !((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0))) { - dev->next = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); - dev = dev->next; /* point to the new device */ - if (dev == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", num_eth); + return dev; +} + +/* +** If at end of eth device list and can't use current entry, malloc +** one up. If memory could not be allocated, print an error message. +*/ +static struct device * +insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)) +{ + struct device *new; + + new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); + if (new == NULL) { + printk("eth%d: Device not initialised, insufficient memory\n",num_eth); + return NULL; + } else { + new->next = dev->next; + dev->next = new; + dev = dev->next; /* point to the new device */ + dev->name = (char *)(dev + 1); + if (num_eth > 9999) { + sprintf(dev->name,"eth????");/* New device name */ } else { - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ - dev->name = (char *)(dev + 1); - if (num_eth > 9999) { - sprintf(dev->name,"eth????");/* New device name */ - } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ - } - dev->base_addr = iobase; /* assign the io address */ - dev->next = NULL; /* mark the end of list */ - dev->init = &de4x5_probe; /* initialisation routine */ - num_de4x5s++; + sprintf(dev->name,"eth%d", num_eth);/* New device name */ } + dev->base_addr = iobase; /* assign the io address */ + dev->init = init; /* initialisation routine */ } - ret = dev; /* return current struct, or NULL */ - - /* - ** Now figure out what to do with the autoprobe that has to be inserted. - ** Firstly, search the (possibly altered) list for an empty space. - */ - if (ret != NULL) { - if (addAutoProbe) { - for (; (tmp->next!=NULL) && (tmp->base_addr!=DE4X5_NDA); tmp=tmp->next); - /* - ** If no more device structures and can't use the current one, - ** malloc one up. If memory could not be allocated, print an error - **message. - */ - if ((tmp->next == NULL) && !(tmp->base_addr == DE4X5_NDA)) { - tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - tmp = tmp->next; /* point to the new device */ - if (tmp == NULL) { - printk("%s: Insufficient memory to extend the device list.\n", - dev->name); - } else { - /* - ** If the memory was allocated, point to the new memory - ** area and initialize it (name, I/O address, next device - ** (NULL) and initialisation probe routine). - */ - tmp->name = (char *)(tmp + 1); - if (num_eth > 9999) { - sprintf(tmp->name,"eth????"); - } else { /* New device name */ - sprintf(tmp->name,"eth%d", num_eth); - } - tmp->base_addr = 0; /* re-insert the io address */ - tmp->next = NULL; /* mark the end of list */ - tmp->init = init; /* initialisation routine */ - } - } else { /* structure already exists */ - tmp->base_addr = 0; /* re-insert the io address */ - } - } + + return dev; +} + +static int +de4x5_dev_index(char *s) +{ + int i=0, j=0; + + for (;*s; s++) { + if (isdigit(*s)) { + j=1; + i = (i * 10) + (*s - '0'); + } else if (j) break; } - - return ret; + + return i; } /* @@ -2381,8 +2392,10 @@ de4x5_setup_intr(dev); lp->lostMedia = 0; lp->tx_enable = YES; + dev->tbusy = 0; sti(); outl(POLL_DEMAND, DE4X5_TPD); + mark_bh(NET_BH); return; } @@ -2643,8 +2656,9 @@ ret = lp->rx_skb[index]; lp->rx_skb[index] = p; - if ((unsigned long) ret > 1) - skb_put(ret, len); + if ((u_long) ret > 1) { + skb_put(ret, len); + } return ret; @@ -2675,7 +2689,7 @@ int i; for (i=0; irxRingSize; i++) { - if ((unsigned long) lp->rx_skb[i] > 1) { + if ((u_long) lp->rx_skb[i] > 1) { dev_kfree_skb(lp->rx_skb[i], FREE_WRITE); } lp->rx_ring[i].status = 0; @@ -2728,7 +2742,6 @@ de4x5_cache_state(dev, DE4X5_SAVE_STATE); de4x5_sw_reset(dev); de4x5_cache_state(dev, DE4X5_RESTORE_STATE); - dev->tbusy = 0; lp->cache.save_cnt++; START_DE4X5; } @@ -2748,7 +2761,6 @@ de4x5_cache_state(dev, DE4X5_SAVE_STATE); de4x5_sw_reset(dev); de4x5_cache_state(dev, DE4X5_RESTORE_STATE); - dev->tbusy = 0; lp->cache.save_cnt--; START_DE4X5; } @@ -3074,7 +3086,7 @@ } else if (!broken) { dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++; dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++; - } else if (broken == SMC) { /* Assume SMC9332 for now */ + } else if ((broken == SMC) || (broken == ACCTON)) { dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++; dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++; } @@ -3118,7 +3130,11 @@ for (i=0; isrom, (char *)&enet_det[i], 3) && !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) { - status = SMC; + if (i == 0) { + status = SMC; + } else if (i == 1) { + status = ACCTON; + } break; } } @@ -4123,8 +4139,8 @@ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c" + * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * - * compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c" + * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * End: */ diff -u --recursive --new-file v2.0.0/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.0.0/linux/drivers/net/net_init.c Mon Mar 25 08:58:21 1996 +++ linux/drivers/net/net_init.c Sat Jun 29 12:00:46 1996 @@ -20,6 +20,8 @@ Use dev_close cleanly so we always shut things down tidily. Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses. + + 14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function. */ #include @@ -144,6 +146,14 @@ return 0; } +static int eth_change_mtu(struct device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 1500)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + void ether_setup(struct device *dev) { int i; @@ -165,6 +175,7 @@ } } + dev->change_mtu = eth_change_mtu; dev->hard_header = eth_header; dev->rebuild_header = eth_rebuild_header; dev->set_mac_address = eth_mac_addr; diff -u --recursive --new-file v2.0.0/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.0.0/linux/drivers/net/slhc.c Mon May 20 08:21:02 1996 +++ linux/drivers/net/slhc.c Tue Jun 25 12:03:29 1996 @@ -107,29 +107,27 @@ memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { - comp->rstate = - (struct cstate *)kmalloc(rslots * sizeof(struct cstate), - GFP_KERNEL); + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); if (! comp->rstate) { kfree((unsigned char *)comp); return NULL; } - memset(comp->rstate, 0, rslots * sizeof(struct cstate)); + memset(comp->rstate, 0, rsize); comp->rslot_limit = rslots - 1; } if ( tslots > 0 && tslots < 256 ) { - comp->tstate = - (struct cstate *)kmalloc(tslots * sizeof(struct cstate), - GFP_KERNEL); + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); if (! comp->tstate) { kfree((unsigned char *)comp->rstate); kfree((unsigned char *)comp); return NULL; } - memset(comp->tstate, 0, tslots * sizeof(struct cstate)); + memset(comp->tstate, 0, tsize); comp->tslot_limit = tslots - 1; } diff -u --recursive --new-file v2.0.0/linux/drivers/net/wic.c linux/drivers/net/wic.c --- v2.0.0/linux/drivers/net/wic.c Fri Apr 19 10:07:59 1996 +++ linux/drivers/net/wic.c Tue Jul 2 19:08:42 1996 @@ -49,7 +49,7 @@ #include #include #include -#include +#include #define NET_DEBUG 1 /* Use 0 for production, 1 for verification, >2 for debug */ diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.0.0/linux/drivers/scsi/Config.in Thu Jun 6 17:42:36 1996 +++ linux/drivers/scsi/Config.in Tue Jul 2 19:08:42 1996 @@ -48,9 +48,7 @@ dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate 'Qlogic ISP SCSI support (EXPERIMENTAL)' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI - fi + dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v2.0.0/linux/drivers/scsi/README.st Tue May 7 16:22:32 1996 +++ linux/drivers/scsi/README.st Mon Jul 1 07:08:27 1996 @@ -1,5 +1,8 @@ This file contains brief information about the SCSI tape driver. -Last modified: Wed May 1 11:51:35 1996 by root@kai.makisara.fi +The driver is currently maintained by Kai M{kisara (email +Kai.Makisara@metla.fi) + +Last modified: Sun Jun 30 15:47:14 1996 by root@kai.makisara.fi BASICS @@ -85,13 +88,15 @@ compile time and/or at run time (via ioctl): Buffering of data across write calls in fixed block mode (define -ST_BUFFER_WRITES). This should be disabled if reliable detection of -end of medium (EOM) for fixed block mode is desired. +ST_BUFFER_WRITES). Asynchronous writing. Writing the buffer contents to the tape is started and the write call returns immediately. The status is checked -at the next tape operation. Should not used if reliable EOM detection -is desired. +at the next tape operation. + +Buffered writes and asynchronous writes may in some rare cases cause +problems in multivolume operations if there is not enough space after +the early-warning mark to flush the driver buffer. Read ahead for fixed block mode (ST_READ_AHEAD). Filling the buffer is attempted even if the user does not want to get all of the data at @@ -187,7 +192,8 @@ control of compression. Some drives (like the Exabytes) use density codes for compression control. Some drives use another mode page but this page has not been implemented in the - driver. + driver. Some drives without compression capability will accept + any compression mode without error. MTSETPART Moves the tape to the partition given by the argument at the next tape operation. The block at which the tape is positioned is the block where the tape was previously positioned in the @@ -310,5 +316,3 @@ time or the MT_ST_CAN_BSR bit is set for the drive with an ioctl. (The driver always backs over a filemark crossed by read ahead if the user does not request data that far.) - -Kai M{kisara diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.0.0/linux/drivers/scsi/hosts.h Mon May 20 08:21:02 1996 +++ linux/drivers/scsi/hosts.h Mon Jul 1 20:06:05 1996 @@ -244,7 +244,7 @@ unsigned short extra_bytes; volatile unsigned char host_busy; char host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ - int last_reset; + unsigned long last_reset; struct wait_queue *host_wait; Scsi_Cmnd *host_queue; Scsi_Host_Template * hostt; diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.0.0/linux/drivers/scsi/qlogicisp.c Thu Jun 6 17:42:36 1996 +++ linux/drivers/scsi/qlogicisp.c Mon Jul 1 20:06:05 1996 @@ -63,7 +63,7 @@ the latest firmware provided by QLogic. This may be an earlier/later revision than supplied by your board. */ -#define RELOAD_FIRMWARE 1 +#define RELOAD_FIRMWARE 0 /* Set the following macro to 1 to reload the ISP1020's defaults from nvram. If you are not sure of your settings, leave this alone, the driver will @@ -76,6 +76,7 @@ #define DEBUG_ISP1020 0 #define DEBUG_ISP1020_INT 0 #define DEBUG_ISP1020_SETUP 0 +#define TRACE_ISP 0 #define DEFAULT_LOOP_COUNT 1000000 @@ -83,6 +84,38 @@ #include +#if TRACE_ISP + +# define TRACE_BUF_LEN (32*1024) + +struct { + u_long next; + struct { + u_long time; + u_int index; + u_int addr; + u_char * name; + } buf[TRACE_BUF_LEN]; +} trace; + +#define TRACE(w, i, a) \ +{ \ + unsigned long flags; \ + \ + save_flags(flags); \ + cli(); \ + trace.buf[trace.next].name = (w); \ + trace.buf[trace.next].time = jiffies; \ + trace.buf[trace.next].index = (i); \ + trace.buf[trace.next].addr = (long) (a); \ + trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ + restore_flags(flags); \ +} + +#else +# define TRACE(w, i, a) +#endif + #if DEBUG_ISP1020 #define ENTER(x) printk("isp1020 : entering %s()\n", x); #define LEAVE(x) printk("isp1020 : leaving %s()\n", x); @@ -146,10 +179,10 @@ #define EXECUTION_TIMEOUT_RESET 0x8006 struct Entry_header { - u_char entry_type; - u_char entry_cnt; - u_char sys_def_1; - u_char flags; + u_char entry_type; + u_char entry_cnt; + u_char sys_def_1; + u_char flags; }; /* entry header type commands */ @@ -166,25 +199,22 @@ #define EFLAG_BAD_PAYLOAD 8 struct dataseg { - u_int d_base; - u_int d_count; + u_int d_base; + u_int d_count; }; struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short cdb_length; - u_short control_flags; - u_short rsvd; - u_short time_out; - u_short segment_cnt; - u_char cdb[12]; - struct dataseg dataseg0; - struct dataseg dataseg1; - struct dataseg dataseg2; - struct dataseg dataseg3; + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[12]; + struct dataseg dataseg[4]; }; /* command entry control flag definitions */ @@ -197,38 +227,32 @@ #define CFLAG_WRITE 0x40 struct Ext_Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short cdb_length; - u_short control_flags; - u_short rsvd; - u_short time_out; - u_short segment_cnt; - u_char cdb[44]; + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[44]; }; struct Continuation_Entry { - struct Entry_header hdr; - u_int reserved; - struct dataseg dataseg0; - struct dataseg dataseg1; - struct dataseg dataseg2; - struct dataseg dataseg3; - struct dataseg dataseg4; - struct dataseg dataseg5; - struct dataseg dataseg6; + struct Entry_header hdr; + u_int reserved; + struct dataseg dataseg[7]; }; struct Marker_Entry { - struct Entry_header hdr; - u_int reserved; - u_char target_lun; - u_char target_id; - u_char modifier; - u_char rsvd; - u_char rsvds[52]; + struct Entry_header hdr; + u_int reserved; + u_char target_lun; + u_char target_id; + u_char modifier; + u_char rsvd; + u_char rsvds[52]; }; /* marker entry modifier definitions */ @@ -237,17 +261,17 @@ #define SYNC_ALL 2 struct Status_Entry { - struct Entry_header hdr; - u_int handle; - u_short scsi_status; - u_short completion_status; - u_short state_flags; - u_short status_flags; - u_short time; - u_short req_sense_len; - u_int residual; - u_char rsvd[8]; - u_char req_sense_data[32]; + struct Entry_header hdr; + u_int handle; + u_short scsi_status; + u_short completion_status; + u_short state_flags; + u_short status_flags; + u_short time; + u_short req_sense_len; + u_int residual; + u_char rsvd[8]; + u_char req_sense_data[32]; }; /* status entry completion status definitions */ @@ -366,93 +390,93 @@ #define PACKB(a, b) (((a)<<4)|(b)) -u_char mbox_param[] = { - PACKB(1, 1), /* MBOX_NO_OP */ - PACKB(5, 5), /* MBOX_LOAD_RAM */ - PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ - PACKB(5, 5), /* MBOX_DUMP_RAM */ - PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */ - PACKB(2, 3), /* MBOX_READ_RAM_WORD */ - PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ - PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ - PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ - PACKB(0, 0), /* 0x0009 */ - PACKB(0, 0), /* 0x000a */ - PACKB(0, 0), /* 0x000b */ - PACKB(0, 0), /* 0x000c */ - PACKB(0, 0), /* 0x000d */ - PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ - PACKB(0, 0), /* 0x000f */ - PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ - PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ - PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ - PACKB(2, 2), /* MBOX_WAKE_UP */ - PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ - PACKB(4, 4), /* MBOX_ABORT */ - PACKB(2, 2), /* MBOX_ABORT_DEVICE */ - PACKB(3, 3), /* MBOX_ABORT_TARGET */ - PACKB(2, 2), /* MBOX_BUS_RESET */ - PACKB(2, 3), /* MBOX_STOP_QUEUE */ - PACKB(2, 3), /* MBOX_START_QUEUE */ - PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ - PACKB(2, 3), /* MBOX_ABORT_QUEUE */ - PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ - PACKB(0, 0), /* 0x001e */ - PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ - PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ - PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ - PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ - PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ - PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ - PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ - PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ - PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */ - PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ - PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ - PACKB(0, 0), /* 0x002a */ - PACKB(0, 0), /* 0x002b */ - PACKB(0, 0), /* 0x002c */ - PACKB(0, 0), /* 0x002d */ - PACKB(0, 0), /* 0x002e */ - PACKB(0, 0), /* 0x002f */ - PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ - PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ - PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ - PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ - PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ - PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ - PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ - PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */ - PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ - PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ - PACKB(0, 0), /* 0x003a */ - PACKB(0, 0), /* 0x003b */ - PACKB(0, 0), /* 0x003c */ - PACKB(0, 0), /* 0x003d */ - PACKB(0, 0), /* 0x003e */ - PACKB(0, 0), /* 0x003f */ - PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ - PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ - PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */ +const u_char mbox_param[] = { + PACKB(1, 1), /* MBOX_NO_OP */ + PACKB(5, 5), /* MBOX_LOAD_RAM */ + PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ + PACKB(5, 5), /* MBOX_DUMP_RAM */ + PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */ + PACKB(2, 3), /* MBOX_READ_RAM_WORD */ + PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ + PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ + PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ + PACKB(0, 0), /* 0x0009 */ + PACKB(0, 0), /* 0x000a */ + PACKB(0, 0), /* 0x000b */ + PACKB(0, 0), /* 0x000c */ + PACKB(0, 0), /* 0x000d */ + PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ + PACKB(0, 0), /* 0x000f */ + PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ + PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ + PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ + PACKB(2, 2), /* MBOX_WAKE_UP */ + PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ + PACKB(4, 4), /* MBOX_ABORT */ + PACKB(2, 2), /* MBOX_ABORT_DEVICE */ + PACKB(3, 3), /* MBOX_ABORT_TARGET */ + PACKB(2, 2), /* MBOX_BUS_RESET */ + PACKB(2, 3), /* MBOX_STOP_QUEUE */ + PACKB(2, 3), /* MBOX_START_QUEUE */ + PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ + PACKB(2, 3), /* MBOX_ABORT_QUEUE */ + PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ + PACKB(0, 0), /* 0x001e */ + PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ + PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ + PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ + PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ + PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ + PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ + PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ + PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ + PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */ + PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ + PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ + PACKB(0, 0), /* 0x002a */ + PACKB(0, 0), /* 0x002b */ + PACKB(0, 0), /* 0x002c */ + PACKB(0, 0), /* 0x002d */ + PACKB(0, 0), /* 0x002e */ + PACKB(0, 0), /* 0x002f */ + PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ + PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ + PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ + PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ + PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ + PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ + PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ + PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */ + PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ + PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ + PACKB(0, 0), /* 0x003a */ + PACKB(0, 0), /* 0x003b */ + PACKB(0, 0), /* 0x003c */ + PACKB(0, 0), /* 0x003d */ + PACKB(0, 0), /* 0x003e */ + PACKB(0, 0), /* 0x003f */ + PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ + PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ + PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */ }; #define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) struct host_param { - u_short fifo_threshold; - u_short host_adapter_enable; - u_short initiator_scsi_id; - u_short bus_reset_delay; - u_short retry_count; - u_short retry_delay; - u_short async_data_setup_time; - u_short req_ack_active_negation; - u_short data_line_active_negation; - u_short data_dma_burst_enable; - u_short command_dma_burst_enable; - u_short tag_aging; - u_short selection_timeout; - u_short max_queue_depth; + u_short fifo_threshold; + u_short host_adapter_enable; + u_short initiator_scsi_id; + u_short bus_reset_delay; + u_short retry_count; + u_short retry_delay; + u_short async_data_setup_time; + u_short req_ack_active_negation; + u_short data_line_active_negation; + u_short data_dma_burst_enable; + u_short command_dma_burst_enable; + u_short tag_aging; + u_short selection_timeout; + u_short max_queue_depth; }; /* @@ -471,1082 +495,1219 @@ */ struct dev_param { - u_short device_flags; - u_short execution_throttle; - u_short synchronous_period; - u_short synchronous_offset; - u_short device_enable; - u_short reserved; /* pad */ + u_short device_flags; + u_short execution_throttle; + u_short synchronous_period; + u_short synchronous_offset; + u_short device_enable; + u_short reserved; /* pad */ }; -#define REQ_QUEUE_LEN 32 -#define RES_QUEUE_LEN 32 +/* + * The result queue can be quite a bit smaller since continuation entries + * do not show up there: + */ +#define RES_QUEUE_LEN ((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1) #define QUEUE_ENTRY_LEN 64 struct isp1020_hostdata { - u_int io_base; - u_char irq; - u_char bus; - u_char revision; - u_char device_fn; - u_short res_queue_in_ptr; - u_short res_queue_out_ptr; - u_short req_queue_in_ptr; - u_short req_queue_out_ptr; - struct host_param host_param; - struct dev_param dev_param[MAX_TARGETS]; - char res_queue[RES_QUEUE_LEN][QUEUE_ENTRY_LEN]; - char req_queue[REQ_QUEUE_LEN][QUEUE_ENTRY_LEN]; -}; + u_char bus; + u_char revision; + u_char device_fn; + struct host_param host_param; + struct dev_param dev_param[MAX_TARGETS]; + + /* result and request queues (shared with isp1020): */ + u_int req_in_ptr; /* index of next request slot */ + u_int res_out_ptr; /* index of next result slot */ -struct isp1020_hostdata *irq2host[NR_IRQS]; + /* this is here so the queues are nicely aligned */ + long send_marker; /* do we need to send a marker? */ -void isp1020_enable_irqs(struct isp1020_hostdata *); -void isp1020_disable_irqs(struct isp1020_hostdata *); -int isp1020_init(struct Scsi_Host *); -int isp1020_reset_hardware(struct isp1020_hostdata *); -int isp1020_get_defaults(struct isp1020_hostdata *); -int isp1020_set_defaults(struct isp1020_hostdata *); -int isp1020_load_parameters(struct isp1020_hostdata *); -int isp1020_mbox_command(struct isp1020_hostdata *, u_short []); -u_short isp1020_read_nvram_word(struct isp1020_hostdata *, u_short); -int isp1020_verify_nvram(struct isp1020_hostdata *); -void isp1020_print_status_entry(struct Status_Entry *); -void isp1020_print_scsi_cmd(Scsi_Cmnd *); -void isp1020_scsi_done(Scsi_Cmnd *); -int isp1020_return_status(struct Status_Entry *); -void isp1020_intr_handler(int, void *, struct pt_regs *); - -struct proc_dir_entry proc_scsi_isp1020 = { - PROC_SCSI_QLOGICISP, 7, "isp1020", - S_IFDIR | S_IRUGO | S_IXUGO, 2 + char res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; + char req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; }; -int isp1020_detect(Scsi_Host_Template *tmpt) -{ - int hosts = 0; - u_short index; - u_char bus, device_fn; - struct Scsi_Host *scsihost; - struct isp1020_hostdata *hostdata; +/* queue length's _must_ be power of two: */ +#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) +#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ + QLOGICISP_REQ_QUEUE_LEN) +#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) + +struct Scsi_Host *irq2host[NR_IRQS]; + +static void isp1020_enable_irqs(struct Scsi_Host *); +static void isp1020_disable_irqs(struct Scsi_Host *); +static int isp1020_init(struct Scsi_Host *); +static int isp1020_reset_hardware(struct Scsi_Host *); +static int isp1020_set_defaults(struct Scsi_Host *); +static int isp1020_load_parameters(struct Scsi_Host *); +static int isp1020_mbox_command(struct Scsi_Host *, u_short []); +static int isp1020_return_status(struct Status_Entry *); +static void isp1020_intr_handler(int, void *, struct pt_regs *); + +#if USE_NVRAM_DEFAULTS +static int isp1020_get_defaults(struct Scsi_Host *); +static int isp1020_verify_nvram(struct Scsi_Host *); +static u_short isp1020_read_nvram_word(struct Scsi_Host *, u_short); +#endif + +#if DEBUG_ISP1020 +static void isp1020_print_scsi_cmd(Scsi_Cmnd *); +#endif +#if DEBUG_ISP1020_INTR +static void isp1020_print_status_entry(struct Status_Entry *); +#endif - ENTER("isp1020_detect"); +static struct proc_dir_entry proc_scsi_isp1020 = { + PROC_SCSI_QLOGICISP, 7, "isp1020", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; - tmpt->proc_dir = &proc_scsi_isp1020; - if (pcibios_present() == 0) { - printk("qlogicisp : PCI bios not present\n"); - return 0; - } +static inline void isp1020_enable_irqs(struct Scsi_Host *host) +{ + outw(ISP_EN_INT|ISP_EN_RISC, host->io_port + PCI_INTF_CTL); +} - memset(irq2host, 0, sizeof(irq2host)); - for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC, - PCI_DEVICE_ID_QLOGIC_ISP1020, index, &bus, &device_fn) == 0; - index++) { +static inline void isp1020_disable_irqs(struct Scsi_Host *host) +{ + outw(0x0, host->io_port + PCI_INTF_CTL); +} - scsihost = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); - hostdata = (struct isp1020_hostdata *) scsihost->hostdata; - memset(hostdata, 0, sizeof(struct isp1020_hostdata)); - hostdata->bus = bus; - hostdata->device_fn = device_fn; +int isp1020_detect(Scsi_Host_Template *tmpt) +{ + int hosts = 0; + u_short index; + u_char bus, device_fn; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_detect"); + + tmpt->proc_dir = &proc_scsi_isp1020; + + if (pcibios_present() == 0) { + printk("qlogicisp : PCI bios not present\n"); + return 0; + } + + memset(irq2host, 0, sizeof(irq2host)); + + for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC, + PCI_DEVICE_ID_QLOGIC_ISP1020, + index, &bus, &device_fn) == 0; + index++) + { + host = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); + hostdata = (struct isp1020_hostdata *) host->hostdata; + + memset(hostdata, 0, sizeof(struct isp1020_hostdata)); + hostdata->bus = bus; + hostdata->device_fn = device_fn; - if (isp1020_init(scsihost) || isp1020_reset_hardware(hostdata) + if (isp1020_init(host) || isp1020_reset_hardware(host) #if USE_NVRAM_DEFAULTS - || isp1020_get_defaults(hostdata) + || isp1020_get_defaults(host) #else - || isp1020_set_defaults(hostdata) + || isp1020_set_defaults(host) #endif /* USE_NVRAM_DEFAULTS */ - || isp1020_load_parameters(hostdata)) { - scsi_unregister(scsihost); - continue; - } - - scsihost->this_id = hostdata->host_param.initiator_scsi_id; - - if (request_irq(hostdata->irq, isp1020_intr_handler, SA_INTERRUPT, - "qlogicisp", NULL)) { - printk("qlogicisp : interrupt %d already in use\n", hostdata->irq); - scsi_unregister(scsihost); - continue; - } - - if (check_region(hostdata->io_base, 0xff)) { - printk("qlogicisp : i/o region 0x%04x-0x%04x already in use\n", - hostdata->io_base, hostdata->io_base + 0xff); - free_irq(hostdata->irq, NULL); - scsi_unregister(scsihost); - continue; - } - - request_region(hostdata->io_base, 0xff, "qlogicisp"); - irq2host[hostdata->irq] = hostdata; - - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - isp1020_enable_irqs(hostdata); + || isp1020_load_parameters(host)) { + scsi_unregister(host); + continue; + } + + host->this_id = hostdata->host_param.initiator_scsi_id; + + if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT, + "qlogicisp", NULL)) + { + printk("qlogicisp : interrupt %d already in use\n", + host->irq); + scsi_unregister(host); + continue; + } + + if (check_region(host->io_port, 0xff)) { + printk("qlogicisp : i/o region 0x%04x-0x%04x already " + "in use\n", + host->io_port, host->io_port + 0xff); + free_irq(host->irq, NULL); + scsi_unregister(host); + continue; + } + + request_region(host->io_port, 0xff, "qlogicisp"); + irq2host[host->irq] = host; + + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + isp1020_enable_irqs(host); - hosts++; - } + hosts++; + } - LEAVE("isp1020_detect"); + LEAVE("isp1020_detect"); - return hosts; + return hosts; } int isp1020_release(struct Scsi_Host *host) { - struct isp1020_hostdata *hostdata; + struct isp1020_hostdata *hostdata; - ENTER("isp1020_release"); + ENTER("isp1020_release"); - hostdata = (struct isp1020_hostdata *) host->hostdata; + hostdata = (struct isp1020_hostdata *) host->hostdata; - outw(0x0, hostdata->io_base + PCI_INTF_CTL); - free_irq(hostdata->irq, NULL); + outw(0x0, host->io_port + PCI_INTF_CTL); + free_irq(host->irq, NULL); - release_region(hostdata->io_base, 0xff); + release_region(host->io_port, 0xff); - LEAVE("isp1020_release"); + LEAVE("isp1020_release"); - return 0; + return 0; } const char *isp1020_info(struct Scsi_Host *host) { - static char buf[80]; - struct isp1020_hostdata *hostdata; + static char buf[80]; + struct isp1020_hostdata *hostdata; - ENTER("isp1020_info"); + ENTER("isp1020_info"); - hostdata = (struct isp1020_hostdata *) host->hostdata; - sprintf(buf, "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x", - hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, hostdata->irq, - hostdata->io_base); + hostdata = (struct isp1020_hostdata *) host->hostdata; + sprintf(buf, + "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x", + hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, host->irq, + host->io_port); - LEAVE("isp1020_info"); + LEAVE("isp1020_info"); - return buf; + return buf; } -#define REQ_QUEUE_DEPTH() \ - (hostdata->req_queue_in_ptr >= hostdata->req_queue_out_ptr \ - ? hostdata->req_queue_in_ptr - hostdata->req_queue_out_ptr \ - : (REQ_QUEUE_LEN - hostdata->req_queue_out_ptr) \ - + hostdata->req_queue_in_ptr) - - -int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *)) +/* + * The middle SCSI layer ensures that queuecommand never gets invoked + * concurrently with itself or the interrupt handler (though the + * interrupt handler may call this routine as part of + * request-completion handling). + */ +int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *)) { - int i, *iptr, sg_count; - struct scatterlist *sg; - struct Command_Entry *cmd; - struct isp1020_hostdata *hostdata; - unsigned long flags; - - ENTER("isp1020_queuecommand"); + int i, sg_count, n, num_free; + u_int in_ptr, out_ptr; + struct dataseg * ds; + struct scatterlist *sg; + struct Command_Entry *cmd; + struct Continuation_Entry *cont; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_queuecommand"); + + host = Cmnd->host; + hostdata = (struct isp1020_hostdata *) host->hostdata; + Cmnd->scsi_done = done; + + DEBUG(isp1020_print_scsi_cmd(Cmnd)); + + out_ptr = inw(host->io_port + MBOX4); + in_ptr = hostdata->req_in_ptr; + + DEBUG(printk("qlogicisp : request queue depth %d\n", + REQ_QUEUE_DEPTH(in_ptr, out_ptr))); + + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; + if (in_ptr == out_ptr) { + printk("qlogicisp : request queue overflow\n"); + return 1; + } + + if (hostdata->send_marker) { + struct Marker_Entry *marker; + + TRACE("queue marker", in_ptr, 0); + + DEBUG(printk("qlogicisp : adding marker entry\n")); + marker = (struct Marker_Entry *) cmd; + memset(marker, 0, sizeof(struct Marker_Entry)); + + marker->hdr.entry_type = ENTRY_MARKER; + marker->hdr.entry_cnt = 1; + marker->modifier = SYNC_ALL; + + hostdata->send_marker = 0; + + if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) { + outw(in_ptr, host->io_port + MBOX4); + hostdata->req_in_ptr = in_ptr; + printk("qlogicisp : request queue overflow\n"); + return 1; + } + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; + } + + TRACE("queue command", in_ptr, Cmnd); + + memset(cmd, 0, sizeof(struct Command_Entry)); + + cmd->hdr.entry_type = ENTRY_COMMAND; + cmd->hdr.entry_cnt = 1; + + cmd->handle = (u_int) virt_to_bus(Cmnd); + cmd->target_lun = Cmnd->lun; + cmd->target_id = Cmnd->target; + cmd->cdb_length = Cmnd->cmd_len; + cmd->control_flags = CFLAG_READ | CFLAG_WRITE; + cmd->time_out = 30; + + memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); + + if (Cmnd->use_sg) { + cmd->segment_cnt = sg_count = Cmnd->use_sg; + sg = (struct scatterlist *) Cmnd->request_buffer; + ds = cmd->dataseg; + + /* fill in first four sg entries: */ + n = sg_count; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + ds[i].d_base = (u_int) virt_to_bus(sg->address); + ds[i].d_count = sg->length; + ++sg; + } + sg_count -= 4; + + while (sg_count > 0) { + ++cmd->hdr.entry_cnt; + cont = (struct Continuation_Entry *) + &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; + if (in_ptr == out_ptr) { + printk("isp1020: unexpected request queue " + "overflow\n"); + return 1; + } + TRACE("queue continuation", in_ptr, 0); + cont->hdr.entry_type = ENTRY_CONTINUATION; + cont->hdr.entry_cnt = 0; + cont->hdr.sys_def_1 = 0; + cont->hdr.flags = 0; + cont->reserved = 0; + ds = cont->dataseg; + n = sg_count; + if (n > 7) + n = 7; + for (i = 0; i < n; ++i) { + ds[i].d_base = (u_int)virt_to_bus(sg->address); + ds[i].d_count = sg->length; + ++sg; + } + sg_count -= n; + } + } else { + cmd->dataseg[0].d_base = + (u_int) virt_to_bus(Cmnd->request_buffer); + cmd->dataseg[0].d_count = + (u_int) Cmnd->request_bufflen; + cmd->segment_cnt = 1; + } + + outw(in_ptr, host->io_port + MBOX4); + hostdata->req_in_ptr = in_ptr; + + num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); + host->can_queue = host->host_busy + num_free; + host->sg_tablesize = QLOGICISP_MAX_SG(num_free); - hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; - Cmnd->scsi_done = done; + LEAVE("isp1020_queuecommand"); - DEBUG(isp1020_print_scsi_cmd(Cmnd);) - - save_flags(flags); - cli(); - - hostdata->req_queue_out_ptr = inw(hostdata->io_base + MBOX4); - - if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN == - hostdata->req_queue_out_ptr) { - restore_flags(flags); - printk("qlogicisp : request queue overflow\n"); - return 1; - } - - DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH())); + return 0; +} - cmd = (struct Command_Entry *) - &hostdata->req_queue[hostdata->req_queue_in_ptr][0]; - memset(cmd, 0, sizeof(struct Command_Entry)); +#define ASYNC_EVENT_INTERRUPT 0x01 - cmd->hdr.entry_type = ENTRY_COMMAND; - cmd->hdr.entry_cnt = 1; +void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + Scsi_Cmnd *Cmnd; + struct Status_Entry *sts; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + u_int in_ptr, out_ptr; + u_short status; + + ENTER_INTR("isp1020_intr_handler"); + + host = irq2host[irq]; + if (!host) { + printk("qlogicisp : unexpected interrupt on line %d\n", irq); + return; + } + hostdata = (struct isp1020_hostdata *) host->hostdata; + + DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq)); + + if (!(inw(host->io_port + PCI_INTF_STS) & 0x04)) { + /* spurious interrupts can happen legally */ + DEBUG_INTR(printk("qlogicisp: got spurious interrupt\n")); + return; + } + in_ptr = inw(host->io_port + MBOX5); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + + if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { + status = inw(host->io_port + MBOX0); + + DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", + status)); + + switch (status) { + case ASYNC_SCSI_BUS_RESET: + case EXECUTION_TIMEOUT_RESET: + hostdata->send_marker = 1; + break; + case INVALID_COMMAND: + case HOST_INTERFACE_ERROR: + case COMMAND_ERROR: + case COMMAND_PARAM_ERROR: + printk("qlogicisp : bad mailbox return status\n"); + break; + } + outw(0x0, host->io_port + PCI_SEMAPHORE); + } + out_ptr = hostdata->res_out_ptr; + + DEBUG_INTR(printk("qlogicisp : response queue update\n")); + DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", + QUEUE_DEPTH(in_ptr, out_ptr))); + + while (out_ptr != in_ptr) { + sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; + out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; + + Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle); + + TRACE("done", out_ptr, Cmnd); + + if (sts->completion_status == CS_RESET_OCCURRED + || sts->completion_status == CS_ABORTED + || (sts->status_flags & STF_BUS_RESET)) + hostdata->send_marker = 1; + + if (sts->state_flags & SF_GOT_SENSE) + memcpy(Cmnd->sense_buffer, sts->req_sense_data, + sizeof(Cmnd->sense_buffer)); + + DEBUG_INTR(isp1020_print_status_entry(sts)); + + if (sts->hdr.entry_type == ENTRY_STATUS) + Cmnd->result = isp1020_return_status(sts); + else + Cmnd->result = DID_ERROR << 16; + + outw(out_ptr, host->io_port + MBOX5); + (*Cmnd->scsi_done)(Cmnd); + } + hostdata->res_out_ptr = out_ptr; - cmd->handle = (u_int) virt_to_bus(Cmnd); - cmd->target_lun = Cmnd->lun; - cmd->target_id = Cmnd->target; - cmd->cdb_length = Cmnd->cmd_len; - cmd->control_flags = CFLAG_READ | CFLAG_WRITE; - cmd->time_out = 30; + LEAVE_INTR("isp1020_intr_handler"); +} - for (i = 0; i < Cmnd->cmd_len; i++) - cmd->cdb[i] = Cmnd->cmnd[i]; - if (Cmnd->use_sg) { - cmd->segment_cnt = sg_count = Cmnd->use_sg; - sg = (struct scatterlist *) Cmnd->request_buffer; - iptr = (int *) &cmd->dataseg0.d_base; +static int isp1020_return_status(struct Status_Entry *sts) +{ + int host_status = DID_ERROR; +#if DEBUG_ISP1020_INTR + static char *reason[] = { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif /* DEBUG_ISP1020_INTR */ - for (i = 0; sg_count > 0; sg_count--, i++) { - *iptr++ = (int) virt_to_bus(sg[i].address); - *iptr++ = sg[i].length; - } - } - else { - cmd->dataseg0.d_base = (u_int) virt_to_bus(Cmnd->request_buffer); - cmd->dataseg0.d_count = (u_int) Cmnd->request_bufflen; - cmd->segment_cnt = 1; - } + ENTER("isp1020_return_status"); - hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1) - % REQ_QUEUE_LEN; + DEBUG(printk("qlogicisp : completion status = 0x%04x\n", + sts->completion_status)); - outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4); + switch(sts->completion_status) { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_INCOMPLETE: + if (!(sts->state_flags & SF_GOT_BUS)) + host_status = DID_NO_CONNECT; + else if (!(sts->state_flags & SF_GOT_TARGET)) + host_status = DID_BAD_TARGET; + else if (!(sts->state_flags & SF_SENT_CDB)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_STATUS)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_SENSE)) + host_status = DID_ERROR; + break; + case CS_DMA_ERROR: + case CS_TRANSPORT_ERROR: + host_status = DID_ERROR; + break; + case CS_RESET_OCCURRED: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: + case CS_COMMAND_OVERRUN: + case CS_STATUS_OVERRUN: + case CS_BAD_MESSAGE: + case CS_NO_MESSAGE_OUT: + case CS_EXT_ID_FAILED: + case CS_IDE_MSG_FAILED: + case CS_ABORT_MSG_FAILED: + case CS_NOP_MSG_FAILED: + case CS_PARITY_ERROR_MSG_FAILED: + case CS_DEVICE_RESET_MSG_FAILED: + case CS_ID_MSG_FAILED: + case CS_UNEXP_BUS_FREE: + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + host_status = DID_OK; + break; + default: + printk("qlogicisp : unknown completion status 0x%04x\n", + sts->completion_status); + host_status = DID_ERROR; + break; + } - restore_flags(flags); + DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", + reason[host_status], sts->scsi_status)); - LEAVE("isp1020_queuecommand"); + LEAVE("isp1020_return_status"); - return 0; + return (sts->scsi_status & STATUS_MASK) | (host_status << 16); } -#define RES_QUEUE_DEPTH() \ - (hostdata->res_queue_in_ptr >= hostdata->res_queue_out_ptr \ - ? hostdata->res_queue_in_ptr - hostdata->res_queue_out_ptr \ - : (RES_QUEUE_LEN - hostdata->res_queue_out_ptr) \ - + hostdata->res_queue_in_ptr) - - int isp1020_abort(Scsi_Cmnd *Cmnd) { - u_short param[6]; - struct isp1020_hostdata *hostdata; - int return_status = SCSI_ABORT_SUCCESS; - u_int cmdaddr = virt_to_bus(Cmnd); - - ENTER("isp1020_abort"); + u_short param[6]; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + int return_status = SCSI_ABORT_SUCCESS; + u_int cmdaddr = virt_to_bus(Cmnd); - hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + ENTER("isp1020_abort"); - isp1020_disable_irqs(hostdata); + host = Cmnd->host; + hostdata = (struct isp1020_hostdata *) host->hostdata; - DEBUG(printk("qlogicisp : response queue depth %d\n", RES_QUEUE_DEPTH())); + isp1020_disable_irqs(host); - param[0] = MBOX_ABORT; - param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; - param[2] = cmdaddr >> 16; - param[3] = cmdaddr & 0xffff; + param[0] = MBOX_ABORT; + param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; + param[2] = cmdaddr >> 16; + param[3] = cmdaddr & 0xffff; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : scsi abort failure: %x\n", param[0]); - return_status = SCSI_ABORT_ERROR; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : scsi abort failure: %x\n", param[0]); + return_status = SCSI_ABORT_ERROR; + } - isp1020_enable_irqs(hostdata); + isp1020_enable_irqs(host); - LEAVE("isp1020_abort"); + LEAVE("isp1020_abort"); - return return_status; + return return_status; } int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) { - u_short param[6]; - struct isp1020_hostdata *hostdata; - int return_status = SCSI_RESET_SUCCESS; + u_short param[6]; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + int return_status = SCSI_RESET_SUCCESS; - ENTER("isp1020_reset"); + ENTER("isp1020_reset"); - hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + host = Cmnd->host; + hostdata = (struct isp1020_hostdata *) host->hostdata; - param[0] = MBOX_BUS_RESET; - param[1] = hostdata->host_param.bus_reset_delay; + param[0] = MBOX_BUS_RESET; + param[1] = hostdata->host_param.bus_reset_delay; - isp1020_disable_irqs(hostdata); + isp1020_disable_irqs(host); - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : scsi bus reset failure: %x\n", param[0]); - return_status = SCSI_RESET_ERROR; - } - - isp1020_enable_irqs(hostdata); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : scsi bus reset failure: %x\n", param[0]); + return_status = SCSI_RESET_ERROR; + } + + isp1020_enable_irqs(host); - LEAVE("isp1020_reset"); + LEAVE("isp1020_reset"); - return return_status;; + return return_status;; } int isp1020_biosparam(Disk *disk, kdev_t n, int ip[]) { - int size = disk->capacity; + int size = disk->capacity; - ENTER("isp1020_biosparam"); + ENTER("isp1020_biosparam"); - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - if (ip[2] > 1024) { - ip[0] = 255; - ip[1] = 63; - ip[2] = size / (ip[0] * ip[1]); - if (ip[2] > 1023) - ip[2] = 1023; - } + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + if (ip[2] > 1024) { + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } - LEAVE("isp1020_biosparam"); + LEAVE("isp1020_biosparam"); - return 0; + return 0; } -int isp1020_reset_hardware(struct isp1020_hostdata *hostdata) +static int isp1020_reset_hardware(struct Scsi_Host *host) { - u_short param[6]; - int loop_count; + u_short param[6]; + int loop_count; - ENTER("isp1020_reset_hardware"); + ENTER("isp1020_reset_hardware"); - outw(ISP_RESET, hostdata->io_base + PCI_INTF_CTL); - outw(HCCR_RESET, hostdata->io_base + HOST_HCCR); - outw(HCCR_RELEASE, hostdata->io_base + HOST_HCCR); - outw(HCCR_BIOS_DISABLE, hostdata->io_base + HOST_HCCR); + outw(ISP_RESET, host->io_port + PCI_INTF_CTL); + outw(HCCR_RESET, host->io_port + HOST_HCCR); + outw(HCCR_RELEASE, host->io_port + HOST_HCCR); + outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(hostdata->io_base + HOST_HCCR) == RISC_BUSY) - barrier(); - if (!loop_count) - printk("qlogicisp: reset_hardware loop timeout\n"); + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) + barrier(); + if (!loop_count) + printk("qlogicisp: reset_hardware loop timeout\n"); - outw(0, hostdata->io_base + ISP_CFG1); + outw(0, host->io_port + ISP_CFG1); #if DEBUG_ISP1020 - printk("qlogicisp : mbox 0 0x%04x \n", inw(hostdata->io_base + MBOX0)); - printk("qlogicisp : mbox 1 0x%04x \n", inw(hostdata->io_base + MBOX1)); - printk("qlogicisp : mbox 2 0x%04x \n", inw(hostdata->io_base + MBOX2)); - printk("qlogicisp : mbox 3 0x%04x \n", inw(hostdata->io_base + MBOX3)); - printk("qlogicisp : mbox 4 0x%04x \n", inw(hostdata->io_base + MBOX4)); - printk("qlogicisp : mbox 5 0x%04x \n", inw(hostdata->io_base + MBOX5)); + printk("qlogicisp : mbox 0 0x%04x \n", inw(host->io_port + MBOX0)); + printk("qlogicisp : mbox 1 0x%04x \n", inw(host->io_port + MBOX1)); + printk("qlogicisp : mbox 2 0x%04x \n", inw(host->io_port + MBOX2)); + printk("qlogicisp : mbox 3 0x%04x \n", inw(host->io_port + MBOX3)); + printk("qlogicisp : mbox 4 0x%04x \n", inw(host->io_port + MBOX4)); + printk("qlogicisp : mbox 5 0x%04x \n", inw(host->io_port + MBOX5)); #endif /* DEBUG_ISP1020 */ - DEBUG(printk("qlogicisp : loading risc ram\n");) + DEBUG(printk("qlogicisp : loading risc ram\n")); #if RELOAD_FIRMWARE - { int i; - for (i = 0; i < risc_code_length01; i++) { - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = risc_code_addr01 + i; - param[2] = risc_code01[i]; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : firmware load failure\n"); - return 1; - } - } - } + { + int i; + for (i = 0; i < risc_code_length01; i++) { + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = risc_code_addr01 + i; + param[2] = risc_code01[i]; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : firmware load failure\n"); + return 1; + } + } + } #endif /* RELOAD_FIRMWARE */ - DEBUG(printk("qlogicisp : verifying checksum\n");) + DEBUG(printk("qlogicisp : verifying checksum\n")); - param[0] = MBOX_VERIFY_CHECKSUM; - param[1] = risc_code_addr01; + param[0] = MBOX_VERIFY_CHECKSUM; + param[1] = risc_code_addr01; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : ram checksum failure\n"); - return 1; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : ram checksum failure\n"); + return 1; + } - DEBUG(printk("qlogicisp : executing firmware\n");) + DEBUG(printk("qlogicisp : executing firmware\n")); - param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr01; + param[0] = MBOX_EXEC_FIRMWARE; + param[1] = risc_code_addr01; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - param[0] = MBOX_ABOUT_FIRMWARE; + param[0] = MBOX_ABOUT_FIRMWARE; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : about firmware failure\n"); - return 1; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : about firmware failure\n"); + return 1; + } - DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]);) - DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]);) + DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1])); + DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2])); - LEAVE("isp1020_reset_hardware"); + LEAVE("isp1020_reset_hardware"); - return 0; + return 0; } -int isp1020_init(struct Scsi_Host *sh) +static int isp1020_init(struct Scsi_Host *sh) { - u_int io_base; - struct isp1020_hostdata *hostdata; - u_char bus, device_fn, revision, irq; - u_short vendor_id, device_id, command; + u_int io_base; + struct isp1020_hostdata *hostdata; + u_char bus, device_fn, revision, irq; + u_short vendor_id, device_id, command; - ENTER("isp1020_init"); + ENTER("isp1020_init"); - hostdata = (struct isp1020_hostdata *) sh->hostdata; - bus = hostdata->bus; - device_fn = hostdata->device_fn; + hostdata = (struct isp1020_hostdata *) sh->hostdata; + bus = hostdata->bus; + device_fn = hostdata->device_fn; - if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id) + if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id) || pcibios_read_config_word(bus, device_fn, - PCI_DEVICE_ID, &device_id) + PCI_DEVICE_ID, &device_id) || pcibios_read_config_word(bus, device_fn, - PCI_COMMAND, &command) + PCI_COMMAND, &command) || pcibios_read_config_dword(bus, device_fn, - PCI_BASE_ADDRESS_0, &io_base) + PCI_BASE_ADDRESS_0, &io_base) || pcibios_read_config_byte(bus, device_fn, - PCI_CLASS_REVISION, &revision) + PCI_CLASS_REVISION, &revision) || pcibios_read_config_byte(bus, device_fn, - PCI_INTERRUPT_LINE, &irq)) { - printk("qlogicisp : error reading PCI configuration\n"); - return 1; - } - - if (vendor_id != PCI_VENDOR_ID_QLOGIC) { - printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", vendor_id); - return 1; - } - - if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) { - printk("qlogicisp : 0x%04x does not match ISP1020 device id\n", - device_id); - return 1; - } - - if (command & PCI_COMMAND_IO && (io_base & 3) == 1) - io_base &= PCI_BASE_ADDRESS_IO_MASK; - else { - printk("qlogicisp : i/o mapping is disabled\n"); - return 1; - } - - if (!(command & PCI_COMMAND_MASTER)) { - printk("qlogicisp : bus mastering is disabled\n"); - return 1; - } - - if (revision != ISP1020_REV_ID) - printk("qlogicisp : new isp1020 revision ID (%d)\n", revision); - - if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC - || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) { - printk("qlogicisp : can't decode i/o address space\n"); - return 1; - } - - hostdata->io_base = io_base; - hostdata->revision = revision; - hostdata->irq = irq; - - LEAVE("isp1020_init"); - - return 0; -} - - -int isp1020_get_defaults(struct isp1020_hostdata *hostdata) -{ - int i; - u_short value; - - ENTER("isp1020_get_defaults"); - - if (!isp1020_verify_nvram(hostdata)) { - printk("qlogicisp : nvram checksum failure\n"); - printk("qlogicisp : attempting to use default parameters\n"); - return isp1020_set_defaults(hostdata); - } - - value = isp1020_read_nvram_word(hostdata, 2); - hostdata->host_param.fifo_threshold = (value >> 8) & 0x03; - hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01; - hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f; - - value = isp1020_read_nvram_word(hostdata, 3); - hostdata->host_param.bus_reset_delay = value & 0xff; - hostdata->host_param.retry_count = value >> 8; - - value = isp1020_read_nvram_word(hostdata, 4); - hostdata->host_param.retry_delay = value & 0xff; - hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f; - hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01; - hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01; - hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01; - hostdata->host_param.command_dma_burst_enable = (value >> 15); + PCI_INTERRUPT_LINE, &irq)) + { + printk("qlogicisp : error reading PCI configuration\n"); + return 1; + } + + if (vendor_id != PCI_VENDOR_ID_QLOGIC) { + printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", + vendor_id); + return 1; + } + + if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) { + printk("qlogicisp : 0x%04x does not match ISP1020 device id\n", + device_id); + return 1; + } + + if (command & PCI_COMMAND_IO && (io_base & 3) == 1) + io_base &= PCI_BASE_ADDRESS_IO_MASK; + else { + printk("qlogicisp : i/o mapping is disabled\n"); + return 1; + } + + if (!(command & PCI_COMMAND_MASTER)) { + printk("qlogicisp : bus mastering is disabled\n"); + return 1; + } + + if (revision != ISP1020_REV_ID) + printk("qlogicisp : new isp1020 revision ID (%d)\n", revision); + + if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC + || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) + { + printk("qlogicisp : can't decode i/o address space\n"); + return 1; + } - value = isp1020_read_nvram_word(hostdata, 5); - hostdata->host_param.tag_aging = value & 0xff; + hostdata->revision = revision; - value = isp1020_read_nvram_word(hostdata, 6); - hostdata->host_param.selection_timeout = value & 0xffff; + sh->irq = irq; + sh->io_port = io_base; - value = isp1020_read_nvram_word(hostdata, 7); - hostdata->host_param.max_queue_depth = value & 0xffff; + LEAVE("isp1020_init"); -#if DEBUG_ISP1020_SETUP - printk("qlogicisp : fifo threshold=%d\n", - hostdata->host_param.fifo_threshold); - printk("qlogicisp : initiator scsi id=%d\n", - hostdata->host_param.initiator_scsi_id); - printk("qlogicisp : bus reset delay=%d\n", - hostdata->host_param.bus_reset_delay); - printk("qlogicisp : retry count=%d\n", - hostdata->host_param.retry_count); - printk("qlogicisp : retry delay=%d\n", - hostdata->host_param.retry_delay); - printk("qlogicisp : async data setup time=%d\n", - hostdata->host_param.async_data_setup_time); - printk("qlogicisp : req/ack active negation=%d\n", - hostdata->host_param.req_ack_active_negation); - printk("qlogicisp : data line active negation=%d\n", - hostdata->host_param.data_line_active_negation); - printk("qlogicisp : data DMA burst enable=%d\n", - hostdata->host_param.data_dma_burst_enable); - printk("qlogicisp : command DMA burst enable=%d\n", - hostdata->host_param.command_dma_burst_enable); - printk("qlogicisp : tag age limit=%d\n", - hostdata->host_param.tag_aging); - printk("qlogicisp : selection timeout limit=%d\n", - hostdata->host_param.selection_timeout); - printk("qlogicisp : max queue depth=%d\n", - hostdata->host_param.max_queue_depth); -#endif /* DEBUG_ISP1020_SETUP */ - - for (i = 0; i < MAX_TARGETS; i++) { - - value = isp1020_read_nvram_word(hostdata, 14 + i * 3); - hostdata->dev_param[i].device_flags = value & 0xff; - hostdata->dev_param[i].execution_throttle = value >> 8; - - value = isp1020_read_nvram_word(hostdata, 15 + i * 3); - hostdata->dev_param[i].synchronous_period = value & 0xff; - hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f; - hostdata->dev_param[i].device_enable = (value >> 12) & 0x01; - -#if DEBUG_ISP1020_SETUP - printk("qlogicisp : target 0x%02x\n", i); - printk("qlogicisp : device flags=0x%02x\n", - hostdata->dev_param[i].device_flags); - printk("qlogicisp : execution throttle=%d\n", - hostdata->dev_param[i].execution_throttle); - printk("qlogicisp : synchronous period=%d\n", - hostdata->dev_param[i].synchronous_period); - printk("qlogicisp : synchronous offset=%d\n", - hostdata->dev_param[i].synchronous_offset); - printk("qlogicisp : device enable=%d\n", - hostdata->dev_param[i].device_enable); -#endif /* DEBUG_ISP1020_SETUP */ - } - - LEAVE("isp1020_get_defaults"); - - return 0; + return 0; } -int isp1020_set_defaults(struct isp1020_hostdata *hostdata) -{ - int i; - - ENTER("isp1020_set_defaults"); - - hostdata->host_param.fifo_threshold = 2; - hostdata->host_param.host_adapter_enable = 1; - hostdata->host_param.initiator_scsi_id = 7; - hostdata->host_param.bus_reset_delay = 3; - hostdata->host_param.retry_count = 0; - hostdata->host_param.retry_delay = 1; - hostdata->host_param.async_data_setup_time = 6; - hostdata->host_param.req_ack_active_negation = 1; - hostdata->host_param.data_line_active_negation = 1; - hostdata->host_param.data_dma_burst_enable = 1; - hostdata->host_param.command_dma_burst_enable = 1; - hostdata->host_param.tag_aging = 8; - hostdata->host_param.selection_timeout = 250; - hostdata->host_param.max_queue_depth = 256; - - for (i = 0; i < MAX_TARGETS; i++) { - hostdata->dev_param[i].device_flags = 0xfd; - hostdata->dev_param[i].execution_throttle = 16; - hostdata->dev_param[i].synchronous_period = 25; - hostdata->dev_param[i].synchronous_offset = 12; - hostdata->dev_param[i].device_enable = 1; - } - - LEAVE("isp1020_set_defaults"); - - return 0; -} - +#if USE_NVRAM_DEFAULTS -int isp1020_load_parameters(struct isp1020_hostdata *hostdata) +static int isp1020_get_defaults(struct Scsi_Host *host) { - int i, k; - u_int queue_addr; - u_short param[6]; - u_short isp_cfg1; - unsigned long flags; - - ENTER("isp1020_load_parameters"); - - save_flags(flags); - cli(); - - outw(hostdata->host_param.fifo_threshold, hostdata->io_base + ISP_CFG1); - - param[0] = MBOX_SET_INIT_SCSI_ID; - param[1] = hostdata->host_param.initiator_scsi_id; + int i; + u_short value; + struct isp1020_hostdata *hostdata = + (struct isp1020_hostdata *) host->hostdata; + + ENTER("isp1020_get_defaults"); + + if (!isp1020_verify_nvram(host)) { + printk("qlogicisp : nvram checksum failure\n"); + printk("qlogicisp : attempting to use default parameters\n"); + return isp1020_set_defaults(host); + } + + value = isp1020_read_nvram_word(host, 2); + hostdata->host_param.fifo_threshold = (value >> 8) & 0x03; + hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01; + hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f; + + value = isp1020_read_nvram_word(host, 3); + hostdata->host_param.bus_reset_delay = value & 0xff; + hostdata->host_param.retry_count = value >> 8; + + value = isp1020_read_nvram_word(host, 4); + hostdata->host_param.retry_delay = value & 0xff; + hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f; + hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01; + hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01; + hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01; + hostdata->host_param.command_dma_burst_enable = (value >> 15); - isp1020_mbox_command(hostdata, param); + value = isp1020_read_nvram_word(host, 5); + hostdata->host_param.tag_aging = value & 0xff; - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set initiator id failure\n"); - return 1; - } - - param[0] = MBOX_SET_RETRY_COUNT; - param[1] = hostdata->host_param.retry_count; - param[2] = hostdata->host_param.retry_delay; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set retry count failure\n"); - return 1; - } + value = isp1020_read_nvram_word(host, 6); + hostdata->host_param.selection_timeout = value & 0xffff; - param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; - param[1] = hostdata->host_param.async_data_setup_time; + value = isp1020_read_nvram_word(host, 7); + hostdata->host_param.max_queue_depth = value & 0xffff; - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : async data setup time failure\n"); - return 1; - } - - param[0] = MBOX_SET_ACTIVE_NEG_STATE; - param[1] = (hostdata->host_param.req_ack_active_negation << 4) - | (hostdata->host_param.data_line_active_negation << 5); - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set active negation state failure\n"); - return 1; - } - - param[0] = MBOX_SET_PCI_CONTROL_PARAMS; - param[1] = hostdata->host_param.data_dma_burst_enable << 1; - param[2] = hostdata->host_param.command_dma_burst_enable << 1; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set pci control parameter failure\n"); - return 1; - } - - isp_cfg1 = inw(hostdata->io_base + ISP_CFG1); - - if (hostdata->host_param.data_dma_burst_enable - || hostdata->host_param.command_dma_burst_enable) - isp_cfg1 |= 0x0004; - else - isp_cfg1 &= 0xfffb; - - outw(isp_cfg1, hostdata->io_base + ISP_CFG1); - - param[0] = MBOX_SET_TAG_AGE_LIMIT; - param[1] = hostdata->host_param.tag_aging; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set tag age limit failure\n"); - return 1; - } - - param[0] = MBOX_SET_SELECT_TIMEOUT; - param[1] = hostdata->host_param.selection_timeout; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set selection timeout failure\n"); - return 1; - } - - for (i = 0; i < MAX_TARGETS; i++) { - - if (!hostdata->dev_param[i].device_enable) - continue; - - param[0] = MBOX_SET_TARGET_PARAMS; - param[1] = i << 8; - param[2] = hostdata->dev_param[i].device_flags << 8; - param[3] = (hostdata->dev_param[i].synchronous_offset << 8) - | hostdata->dev_param[i].synchronous_period; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set target parameter failure\n"); - return 1; - } - - for (k = 0; k < MAX_LUNS; k++) { - - param[0] = MBOX_SET_DEV_QUEUE_PARAMS; - param[1] = (i << 8) | k; - param[2] = hostdata->host_param.max_queue_depth; - param[3] = hostdata->dev_param[i].execution_throttle; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set device queue parameter failure\n"); - return 1; - } - } - } - - queue_addr = (u_int) virt_to_bus(&hostdata->res_queue[0][0]); - - param[0] = MBOX_INIT_RES_QUEUE; - param[1] = RES_QUEUE_LEN; - param[2] = (u_short) (queue_addr >> 16); - param[3] = (u_short) (queue_addr & 0xffff); - param[4] = 0; - param[5] = 0; +#if DEBUG_ISP1020_SETUP + printk("qlogicisp : fifo threshold=%d\n", + hostdata->host_param.fifo_threshold); + printk("qlogicisp : initiator scsi id=%d\n", + hostdata->host_param.initiator_scsi_id); + printk("qlogicisp : bus reset delay=%d\n", + hostdata->host_param.bus_reset_delay); + printk("qlogicisp : retry count=%d\n", + hostdata->host_param.retry_count); + printk("qlogicisp : retry delay=%d\n", + hostdata->host_param.retry_delay); + printk("qlogicisp : async data setup time=%d\n", + hostdata->host_param.async_data_setup_time); + printk("qlogicisp : req/ack active negation=%d\n", + hostdata->host_param.req_ack_active_negation); + printk("qlogicisp : data line active negation=%d\n", + hostdata->host_param.data_line_active_negation); + printk("qlogicisp : data DMA burst enable=%d\n", + hostdata->host_param.data_dma_burst_enable); + printk("qlogicisp : command DMA burst enable=%d\n", + hostdata->host_param.command_dma_burst_enable); + printk("qlogicisp : tag age limit=%d\n", + hostdata->host_param.tag_aging); + printk("qlogicisp : selection timeout limit=%d\n", + hostdata->host_param.selection_timeout); + printk("qlogicisp : max queue depth=%d\n", + hostdata->host_param.max_queue_depth); +#endif /* DEBUG_ISP1020_SETUP */ - isp1020_mbox_command(hostdata, param); + for (i = 0; i < MAX_TARGETS; i++) { - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set response queue failure\n"); - return 1; - } + value = isp1020_read_nvram_word(host, 14 + i * 3); + hostdata->dev_param[i].device_flags = value & 0xff; + hostdata->dev_param[i].execution_throttle = value >> 8; + + value = isp1020_read_nvram_word(host, 15 + i * 3); + hostdata->dev_param[i].synchronous_period = value & 0xff; + hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f; + hostdata->dev_param[i].device_enable = (value >> 12) & 0x01; - queue_addr = (u_int) virt_to_bus(&hostdata->req_queue[0][0]); +#if DEBUG_ISP1020_SETUP + printk("qlogicisp : target 0x%02x\n", i); + printk("qlogicisp : device flags=0x%02x\n", + hostdata->dev_param[i].device_flags); + printk("qlogicisp : execution throttle=%d\n", + hostdata->dev_param[i].execution_throttle); + printk("qlogicisp : synchronous period=%d\n", + hostdata->dev_param[i].synchronous_period); + printk("qlogicisp : synchronous offset=%d\n", + hostdata->dev_param[i].synchronous_offset); + printk("qlogicisp : device enable=%d\n", + hostdata->dev_param[i].device_enable); +#endif /* DEBUG_ISP1020_SETUP */ + } - param[0] = MBOX_INIT_REQ_QUEUE; - param[1] = REQ_QUEUE_LEN; - param[2] = (u_short) (queue_addr >> 16); - param[3] = (u_short) (queue_addr & 0xffff); - param[4] = 0; + LEAVE("isp1020_get_defaults"); - isp1020_mbox_command(hostdata, param); + return 0; +} - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set request queue failure\n"); - return 1; - } - restore_flags(flags); +#define ISP1020_NVRAM_LEN 0x40 +#define ISP1020_NVRAM_SIG1 0x5349 +#define ISP1020_NVRAM_SIG2 0x2050 - LEAVE("isp1020_load_parameters"); +static int isp1020_verify_nvram(struct Scsi_Host *host) +{ + int i; + u_short value; + u_char checksum = 0; + + for (i = 0; i < ISP1020_NVRAM_LEN; i++) { + value = isp1020_read_nvram_word(host, i); + + switch (i) { + case 0: + if (value != ISP1020_NVRAM_SIG1) return 0; + break; + case 1: + if (value != ISP1020_NVRAM_SIG2) return 0; + break; + case 2: + if ((value & 0xff) != 0x02) return 0; + break; + } + checksum += value & 0xff; + checksum += value >> 8; + } - return 0; + return (checksum == 0); } +#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */ -/* - * currently, this is only called during initialization or abort/reset, - * at which times interrupts are disabled, so polling is OK, I guess... - */ -int isp1020_mbox_command(struct isp1020_hostdata *hostdata, u_short param[]) + +u_short isp1020_read_nvram_word(struct Scsi_Host *host, u_short byte) { - int loop_count; + int i; + u_short value, output, input; - if (mbox_param[param[0]] == 0) - return 1; + byte &= 0x3f; byte |= 0x0180; - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(hostdata->io_base + HOST_HCCR) & 0x0080) - barrier(); - if (!loop_count) - printk("qlogicisp: mbox_command loop timeout #1\n"); - - switch(mbox_param[param[0]] >> 4) { - case 6: outw(param[5], hostdata->io_base + MBOX5); - case 5: outw(param[4], hostdata->io_base + MBOX4); - case 4: outw(param[3], hostdata->io_base + MBOX3); - case 3: outw(param[2], hostdata->io_base + MBOX2); - case 2: outw(param[1], hostdata->io_base + MBOX1); - case 1: outw(param[0], hostdata->io_base + MBOX0); - } - - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - outw(HCCR_SET_HOST_INTR, hostdata->io_base + HOST_HCCR); - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && !(inw(hostdata->io_base + PCI_INTF_STS) & 0x04)) - barrier(); - if (!loop_count) - printk("qlogicisp: mbox_command loop timeout #2\n"); - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(hostdata->io_base + MBOX0) == 0x04) - barrier(); - if (!loop_count) - printk("qlogicisp: mbox_command loop timeout #3\n"); - - switch(mbox_param[param[0]] & 0xf) { - case 6: param[5] = inw(hostdata->io_base + MBOX5); - case 5: param[4] = inw(hostdata->io_base + MBOX4); - case 4: param[3] = inw(hostdata->io_base + MBOX3); - case 3: param[2] = inw(hostdata->io_base + MBOX2); - case 2: param[1] = inw(hostdata->io_base + MBOX1); - case 1: param[0] = inw(hostdata->io_base + MBOX0); - } + for (i = 8; i >= 0; i--) { + output = ((byte >> i) & 0x1) ? 0x4 : 0x0; + outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + outw(output | 0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + } + + for (i = 0xf, value = 0; i >= 0; i--) { + value <<= 1; + outw(0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + input = inw(host->io_port + PCI_NVRAM); NVRAM_DELAY(); + outw(0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + if (input & 0x8) value |= 1; + } - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); + outw(0x0, host->io_port + PCI_NVRAM); NVRAM_DELAY(); - return 0; + return value; } +#endif /* USE_NVRAM_DEFAULTS */ -#define MAILBOX_INTERRUPT 0x01 -void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +static int isp1020_set_defaults(struct Scsi_Host *host) { - Scsi_Cmnd *Cmnd; - struct Status_Entry *sts; - struct Marker_Entry *marker; - u_short status, add_marker = 0; - struct isp1020_hostdata *hostdata; - int loop_count; - - ENTER_INTR("isp1020_intr_handler"); - - if ((hostdata = irq2host[irq]) == NULL) { - printk("qlogicisp : unexpected interrupt on line %d\n", irq); - return; - } - - DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq);) - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && !(inw(hostdata->io_base + PCI_INTF_STS) & 0x04)) - barrier(); - if (!loop_count) - printk("qlogicisp: intr_handler loop timeout\n"); - - status = inw(hostdata->io_base + PCI_SEMAPHORE); - - if ((status & MAILBOX_INTERRUPT) == 0) { + struct isp1020_hostdata *hostdata = + (struct isp1020_hostdata *) host->hostdata; + int i; + + ENTER("isp1020_set_defaults"); + + hostdata->host_param.fifo_threshold = 2; + hostdata->host_param.host_adapter_enable = 1; + hostdata->host_param.initiator_scsi_id = 7; + hostdata->host_param.bus_reset_delay = 3; + hostdata->host_param.retry_count = 0; + hostdata->host_param.retry_delay = 1; + hostdata->host_param.async_data_setup_time = 6; + hostdata->host_param.req_ack_active_negation = 1; + hostdata->host_param.data_line_active_negation = 1; + hostdata->host_param.data_dma_burst_enable = 1; + hostdata->host_param.command_dma_burst_enable = 1; + hostdata->host_param.tag_aging = 8; + hostdata->host_param.selection_timeout = 250; + hostdata->host_param.max_queue_depth = 256; + + for (i = 0; i < MAX_TARGETS; i++) { + hostdata->dev_param[i].device_flags = 0xfd; + hostdata->dev_param[i].execution_throttle = 16; + hostdata->dev_param[i].synchronous_period = 25; + hostdata->dev_param[i].synchronous_offset = 12; + hostdata->dev_param[i].device_enable = 1; + } + + LEAVE("isp1020_set_defaults"); + + return 0; +} - hostdata->res_queue_in_ptr = inw(hostdata->io_base + MBOX5); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - DEBUG_INTR(printk("qlogicisp : response queue update\n");) - DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", - RES_QUEUE_DEPTH());) +static int isp1020_load_parameters(struct Scsi_Host *host) +{ + int i, k; + u_int queue_addr; + u_short param[6]; + u_short isp_cfg1; + unsigned long flags; + struct isp1020_hostdata *hostdata = + (struct isp1020_hostdata *) host->hostdata; - while (hostdata->res_queue_out_ptr != hostdata->res_queue_in_ptr) { + ENTER("isp1020_load_parameters"); - sts = (struct Status_Entry *) - &hostdata->res_queue[hostdata->res_queue_out_ptr][0]; + save_flags(flags); + cli(); - Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle); + outw(hostdata->host_param.fifo_threshold, host->io_port + ISP_CFG1); - if (sts->completion_status == CS_RESET_OCCURRED - || sts->completion_status == CS_ABORTED - || (sts->status_flags & STF_BUS_RESET)) - add_marker++; + param[0] = MBOX_SET_INIT_SCSI_ID; + param[1] = hostdata->host_param.initiator_scsi_id; - if (sts->state_flags & SF_GOT_SENSE) - memcpy(Cmnd->sense_buffer, sts->req_sense_data, - sizeof(Cmnd->sense_buffer)); + isp1020_mbox_command(host, param); - DEBUG_INTR(isp1020_print_status_entry(sts);) + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set initiator id failure\n"); + return 1; + } - if (sts->hdr.entry_type == ENTRY_STATUS) - Cmnd->result = isp1020_return_status(sts); - else - Cmnd->result = DID_ERROR << 16; + param[0] = MBOX_SET_RETRY_COUNT; + param[1] = hostdata->host_param.retry_count; + param[2] = hostdata->host_param.retry_delay; - hostdata->res_queue_out_ptr = (hostdata->res_queue_out_ptr + 1) - % RES_QUEUE_LEN; + isp1020_mbox_command(host, param); - outw(hostdata->res_queue_out_ptr, hostdata->io_base + MBOX5); + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set retry count failure\n"); + return 1; + } - (Cmnd->scsi_done)(Cmnd); - } - } - else { + param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; + param[1] = hostdata->host_param.async_data_setup_time; - status = inw(hostdata->io_base + MBOX0); + isp1020_mbox_command(host, param); - DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", status);) + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : async data setup time failure\n"); + return 1; + } - switch (status) { - case ASYNC_SCSI_BUS_RESET: - case EXECUTION_TIMEOUT_RESET: - add_marker++; - break; - case INVALID_COMMAND: - case HOST_INTERFACE_ERROR: - case COMMAND_ERROR: - case COMMAND_PARAM_ERROR: - printk("qlogicisp : bad mailbox return status\n"); - break; - } + param[0] = MBOX_SET_ACTIVE_NEG_STATE; + param[1] = (hostdata->host_param.req_ack_active_negation << 4) + | (hostdata->host_param.data_line_active_negation << 5); - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - } + isp1020_mbox_command(host, param); - if (add_marker) { -#if 0 - unsigned long flags; + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set active negation state failure\n"); + return 1; + } - save_flags(flags); - cli(); -#endif + param[0] = MBOX_SET_PCI_CONTROL_PARAMS; + param[1] = hostdata->host_param.data_dma_burst_enable << 1; + param[2] = hostdata->host_param.command_dma_burst_enable << 1; - DEBUG_INTR(printk("qlogicisp : adding marker entry\n");) + isp1020_mbox_command(host, param); - if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN - == hostdata->req_queue_out_ptr) { -#if 0 - restore_flags(flags); -#endif - printk("qlogicisp : request queue overflow\n"); - return; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set pci control parameter failure\n"); + return 1; + } - marker = (struct Marker_Entry *) - &hostdata->req_queue[hostdata->req_queue_in_ptr][0]; + isp_cfg1 = inw(host->io_port + ISP_CFG1); - memset(marker, 0, sizeof(struct Marker_Entry)); - - marker->hdr.entry_type = ENTRY_MARKER; - marker->hdr.entry_cnt = 1; - marker->modifier = SYNC_ALL; - - hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1) - % REQ_QUEUE_LEN; - - outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4); + if (hostdata->host_param.data_dma_burst_enable + || hostdata->host_param.command_dma_burst_enable) + isp_cfg1 |= 0x0004; + else + isp_cfg1 &= 0xfffb; + + outw(isp_cfg1, host->io_port + ISP_CFG1); + + param[0] = MBOX_SET_TAG_AGE_LIMIT; + param[1] = hostdata->host_param.tag_aging; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set tag age limit failure\n"); + return 1; + } + + param[0] = MBOX_SET_SELECT_TIMEOUT; + param[1] = hostdata->host_param.selection_timeout; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set selection timeout failure\n"); + return 1; + } + + for (i = 0; i < MAX_TARGETS; i++) { + + if (!hostdata->dev_param[i].device_enable) + continue; + + param[0] = MBOX_SET_TARGET_PARAMS; + param[1] = i << 8; + param[2] = hostdata->dev_param[i].device_flags << 8; + param[3] = (hostdata->dev_param[i].synchronous_offset << 8) + | hostdata->dev_param[i].synchronous_period; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set target parameter failure\n"); + return 1; + } + + for (k = 0; k < MAX_LUNS; k++) { + + param[0] = MBOX_SET_DEV_QUEUE_PARAMS; + param[1] = (i << 8) | k; + param[2] = hostdata->host_param.max_queue_depth; + param[3] = hostdata->dev_param[i].execution_throttle; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set device queue " + "parameter failure\n"); + return 1; + } + } + } + + queue_addr = (u_int) virt_to_bus(&hostdata->res[0][0]); + + param[0] = MBOX_INIT_RES_QUEUE; + param[1] = RES_QUEUE_LEN + 1; + param[2] = (u_short) (queue_addr >> 16); + param[3] = (u_short) (queue_addr & 0xffff); + param[4] = 0; + param[5] = 0; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set response queue failure\n"); + return 1; + } + + queue_addr = (u_int) virt_to_bus(&hostdata->req[0][0]); + + param[0] = MBOX_INIT_REQ_QUEUE; + param[1] = QLOGICISP_REQ_QUEUE_LEN + 1; + param[2] = (u_short) (queue_addr >> 16); + param[3] = (u_short) (queue_addr & 0xffff); + param[4] = 0; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set request queue failure\n"); + return 1; + } -#if 0 restore_flags(flags); -#endif - } - isp1020_enable_irqs(hostdata); + LEAVE("isp1020_load_parameters"); - LEAVE_INTR("isp1020_intr_handler"); + return 0; } -#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */ - - -u_short isp1020_read_nvram_word(struct isp1020_hostdata *hostdata, u_short byte) -{ - int i; - u_short value, output, input; - - byte &= 0x3f; byte |= 0x0180; - - for (i = 8; i >= 0; i--) { - output = ((byte >> i) & 0x1) ? 0x4 : 0x0; - outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - outw(output | 0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - } - - for (i = 0xf, value = 0; i >= 0; i--) { - value <<= 1; - outw(0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - input = inw(hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - outw(0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - if (input & 0x8) value |= 1; - } - - outw(0x0, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - - return(value); -} - -#define ISP1020_NVRAM_LEN 0x40 -#define ISP1020_NVRAM_SIG1 0x5349 -#define ISP1020_NVRAM_SIG2 0x2050 - -int isp1020_verify_nvram(struct isp1020_hostdata *hostdata) +/* + * currently, this is only called during initialization or abort/reset, + * at which times interrupts are disabled, so polling is OK, I guess... + */ +static int isp1020_mbox_command(struct Scsi_Host *host, u_short param[]) { - int i; - u_short value; - u_char checksum = 0; - - for (i = 0; i < ISP1020_NVRAM_LEN; i++) { - value = isp1020_read_nvram_word(hostdata, i); - - switch (i) { - case 0: - if (value != ISP1020_NVRAM_SIG1) return 0; - break; - case 1: - if (value != ISP1020_NVRAM_SIG2) return 0; - break; - case 2: - if ((value & 0xff) != 0x02) return 0; - break; - } - checksum += value & 0xff; - checksum += value >> 8; - } - - return (checksum == 0); -} + int loop_count; + if (mbox_param[param[0]] == 0) + return 1; -void isp1020_enable_irqs(struct isp1020_hostdata *hostdata) -{ - outw(ISP_EN_INT|ISP_EN_RISC, hostdata->io_base + PCI_INTF_CTL); -} + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) + barrier(); + if (!loop_count) + printk("qlogicisp: mbox_command loop timeout #1\n"); + + switch(mbox_param[param[0]] >> 4) { + case 6: outw(param[5], host->io_port + MBOX5); + case 5: outw(param[4], host->io_port + MBOX4); + case 4: outw(param[3], host->io_port + MBOX3); + case 3: outw(param[2], host->io_port + MBOX2); + case 2: outw(param[1], host->io_port + MBOX1); + case 1: outw(param[0], host->io_port + MBOX0); + } + + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR); + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && !(inw(host->io_port + PCI_INTF_STS) & 0x04)) + barrier(); + if (!loop_count) + printk("qlogicisp: mbox_command loop timeout #2\n"); + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + MBOX0) == 0x04) + barrier(); + if (!loop_count) + printk("qlogicisp: mbox_command loop timeout #3\n"); + + switch(mbox_param[param[0]] & 0xf) { + case 6: param[5] = inw(host->io_port + MBOX5); + case 5: param[4] = inw(host->io_port + MBOX4); + case 4: param[3] = inw(host->io_port + MBOX3); + case 3: param[2] = inw(host->io_port + MBOX2); + case 2: param[1] = inw(host->io_port + MBOX1); + case 1: param[0] = inw(host->io_port + MBOX0); + } + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); -void isp1020_disable_irqs(struct isp1020_hostdata *hostdata) -{ - outw(0x0, hostdata->io_base + PCI_INTF_CTL); + return 0; } @@ -1554,20 +1715,20 @@ void isp1020_print_status_entry(struct Status_Entry *status) { - int i; + int i; - printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", - status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); - printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n", - status->scsi_status, status->completion_status); - printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n", - status->state_flags, status->status_flags); - printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n", - status->time, status->req_sense_len); - printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual); + printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", + status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); + printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n", + status->scsi_status, status->completion_status); + printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n", + status->state_flags, status->status_flags); + printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n", + status->time, status->req_sense_len); + printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual); - for (i = 0; i < status->req_sense_len; i++) - printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]); + for (i = 0; i < status->req_sense_len; i++) + printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]); } #endif /* DEBUG_ISP1020_INTR */ @@ -1577,105 +1738,18 @@ void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd) { - int i; + int i; - printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", - cmd->target, cmd->lun, cmd->cmd_len); - printk("qlogicisp : command = "); - for (i = 0; i < cmd->cmd_len; i++) - printk("0x%02x ", cmd->cmnd[i]); - printk("\n"); + printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + cmd->target, cmd->lun, cmd->cmd_len); + printk("qlogicisp : command = "); + for (i = 0; i < cmd->cmd_len; i++) + printk("0x%02x ", cmd->cmnd[i]); + printk("\n"); } #endif /* DEBUG_ISP1020 */ - -int isp1020_return_status(struct Status_Entry *sts) -{ - int host_status = DID_ERROR; -#if DEBUG_ISP1020_INTR - static char *reason[] = { - "DID_OK", - "DID_NO_CONNECT", - "DID_BUS_BUSY", - "DID_TIME_OUT", - "DID_BAD_TARGET", - "DID_ABORT", - "DID_PARITY", - "DID_ERROR", - "DID_RESET", - "DID_BAD_INTR" - }; -#endif /* DEBUG_ISP1020_INTR */ - - ENTER("isp1020_return_status"); - - DEBUG(printk("qlogicisp : completion status = 0x%04x\n", - sts->completion_status);) - - switch(sts->completion_status) { - case CS_COMPLETE: - host_status = DID_OK; - break; - case CS_INCOMPLETE: - if (!(sts->state_flags & SF_GOT_BUS)) - host_status = DID_NO_CONNECT; - else if (!(sts->state_flags & SF_GOT_TARGET)) - host_status = DID_BAD_TARGET; - else if (!(sts->state_flags & SF_SENT_CDB)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_STATUS)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_SENSE)) - host_status = DID_ERROR; - break; - case CS_DMA_ERROR: - case CS_TRANSPORT_ERROR: - host_status = DID_ERROR; - break; - case CS_RESET_OCCURRED: - host_status = DID_RESET; - break; - case CS_ABORTED: - host_status = DID_ABORT; - break; - case CS_TIMEOUT: - host_status = DID_TIME_OUT; - break; - case CS_DATA_OVERRUN: - case CS_COMMAND_OVERRUN: - case CS_STATUS_OVERRUN: - case CS_BAD_MESSAGE: - case CS_NO_MESSAGE_OUT: - case CS_EXT_ID_FAILED: - case CS_IDE_MSG_FAILED: - case CS_ABORT_MSG_FAILED: - case CS_NOP_MSG_FAILED: - case CS_PARITY_ERROR_MSG_FAILED: - case CS_DEVICE_RESET_MSG_FAILED: - case CS_ID_MSG_FAILED: - case CS_UNEXP_BUS_FREE: - host_status = DID_ERROR; - break; - case CS_DATA_UNDERRUN: - host_status = DID_OK; - break; - default: - printk("qlogicisp : unknown completion status 0x%04x\n", - sts->completion_status); - host_status = DID_ERROR; - break; - } - - DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", - reason[host_status], sts->scsi_status);) - - LEAVE("isp1020_return_status"); - - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); -} #ifdef MODULE Scsi_Host_Template driver_template = QLOGICISP; diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/qlogicisp.h linux/drivers/scsi/qlogicisp.h --- v2.0.0/linux/drivers/scsi/qlogicisp.h Wed Jun 5 10:41:28 1996 +++ linux/drivers/scsi/qlogicisp.h Mon Jul 1 20:06:05 1996 @@ -43,6 +43,21 @@ #ifndef _QLOGICISP_H #define _QLOGICISP_H +/* + * With the qlogic interface, every queue slot can hold a SCSI + * command with up to 4 scatter/gather entries. If we need more + * than 4 entries, continuation entries can be used that hold + * another 7 entries each. Unlike for other drivers, this means + * that the maximum number of scatter/gather entries we can + * support at any given time is a function of the number of queue + * slots available. That is, host->can_queue and host->sg_tablesize + * are dynamic and _not_ independent. This all works fine because + * requests are queued serially and the scatter/gather limit is + * determined for each queue request anew. + */ +#define QLOGICISP_REQ_QUEUE_LEN 63 /* must be power of two - 1 */ +#define QLOGICISP_MAX_SG(ql) (4 + ((ql) > 0) ? 7*((ql) - 1) : 0) + int isp1020_detect(Scsi_Host_Template *); int isp1020_release(struct Scsi_Host *); const char * isp1020_info(struct Scsi_Host *); @@ -57,28 +72,28 @@ extern struct proc_dir_entry proc_scsi_isp1020; -#define QLOGICISP { \ - /* next */ NULL, \ - /* usage_count */ NULL, \ - /* proc dir */ NULL, \ - /* procfs info */ NULL, \ - /* name */ NULL, \ - /* detect */ isp1020_detect, \ - /* release */ isp1020_release, \ - /* info */ isp1020_info, \ - /* command */ NULL, \ - /* queuecommand */ isp1020_queuecommand, \ - /* abort */ isp1020_abort, \ - /* reset */ isp1020_reset, \ - /* slave_attach */ NULL, \ - /* bios_param */ isp1020_biosparam, \ - /* can_queue */ 8, \ - /* this_id */ -1, \ - /* sg_tablesize */ 4, \ - /* cmd_per_lun */ 1, \ - /* present */ 0, \ - /* unchecked_isa_dma */ 0, \ - /* use_clustering */ DISABLE_CLUSTERING \ +#define QLOGICISP { \ + /* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc dir */ NULL, \ + /* procfs info */ NULL, \ + /* name */ NULL, \ + /* detect */ isp1020_detect, \ + /* release */ isp1020_release, \ + /* info */ isp1020_info, \ + /* command */ NULL, \ + /* queuecommand */ isp1020_queuecommand, \ + /* abort */ isp1020_abort, \ + /* reset */ isp1020_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ isp1020_biosparam, \ + /* can_queue */ QLOGICISP_REQ_QUEUE_LEN, \ + /* this_id */ -1, \ + /* sg_tablesize */ QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \ + /* cmd_per_lun */ 1, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING \ } #endif /* _QLOGICISP_H */ diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.0.0/linux/drivers/scsi/scsi.c Sun Jun 9 13:28:46 1996 +++ linux/drivers/scsi/scsi.c Mon Jul 1 20:14:55 1996 @@ -1184,27 +1184,38 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) { - int temp; + unsigned long flags, timeout; struct Scsi_Host * host; - unsigned int flags; #ifdef DEBUG_DELAY - int clock; + unsigned long clock; #endif host = SCpnt->host; - /* - * We will wait MIN_RESET_DELAY clock ticks after the last reset so - * we can avoid the drive not being ready. - */ save_flags(flags); cli(); /* Assign a unique nonzero serial_number. */ if (++serial_number == 0) serial_number = 1; SCpnt->serial_number = serial_number; - sti(); - temp = host->last_reset + MIN_RESET_DELAY; - while (jiffies < temp); + + /* + * We will wait MIN_RESET_DELAY clock ticks after the last reset so + * we can avoid the drive not being ready. + */ + timeout = host->last_reset + MIN_RESET_DELAY; + if (jiffies < timeout) { + /* + * NOTE: This may be executed from within an interrupt + * handler! This is bad, but for now, it'll do. The irq + * level of the interrupt handler has been masked out by the + * platform dependent interrupt handling code already, so the + * sti() here will not cause another call to the SCSI host's + * interrupt handler (assuming there is one irq-level per + * host). + */ + sti(); + while (jiffies < timeout) barrier(); + } restore_flags(flags); update_timeout(SCpnt, SCpnt->timeout_per_command); @@ -1245,15 +1256,16 @@ } else { - + int temp; + #ifdef DEBUG printk("command() : routine at %p\n", host->hostt->command); #endif - temp=host->hostt->command (SCpnt); + temp = host->hostt->command (SCpnt); SCpnt->result = temp; #ifdef DEBUG_DELAY clock = jiffies + 4 * HZ; - while (jiffies < clock); + while (jiffies < clock) barrier(); printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); #endif @@ -2055,10 +2067,11 @@ * Protect against races here. If the command is done, or we are * on a different command forget it. */ - if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { + if (reset_flags & SCSI_RESET_ASYNCHRONOUS) + if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { restore_flags(flags); return 0; - } + } if (SCpnt->internal_timeout & IN_RESET) { diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.0.0/linux/drivers/scsi/scsi.h Thu Jun 6 17:42:36 1996 +++ linux/drivers/scsi/scsi.h Wed Jun 26 11:05:26 1996 @@ -202,7 +202,7 @@ * Use these to separate status msg and our bytes */ -#define status_byte(result) (((result) >> 1) & 0xf) +#define status_byte(result) (((result) >> 1) & 0x1f) #define msg_byte(result) (((result) >> 8) & 0xff) #define host_byte(result) (((result) >> 16) & 0xff) #define driver_byte(result) (((result) >> 24) & 0xff) diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.0.0/linux/drivers/scsi/sg.c Sun May 5 08:52:02 1996 +++ linux/drivers/scsi/sg.c Wed Jul 3 10:12:26 1996 @@ -230,7 +230,7 @@ * Now copy the result back to the user buffer. */ device->header.pack_len=device->header.reply_len; - device->header.result=0; + if (count>=sizeof(struct sg_header)) { memcpy_tofs(buf,&device->header,sizeof(struct sg_header)); @@ -242,7 +242,7 @@ } } else - count=0; + count= device->header.result==0 ? 0 : -EIO; /* * Clean up, and release the device so that we can send another @@ -276,12 +276,7 @@ * wrong. */ memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); - if (SCpnt->sense_buffer[0]) - { - device->header.result=EIO; - } - else - device->header.result=SCpnt->result; + device->header.result=SCpnt->result; /* * Now wake up the process that is waiting for the @@ -593,6 +588,11 @@ gpnt->device = NULL; SDp->attached--; sg_template.nr_dev--; + /* + * avoid associated device /dev/sg? bying incremented + * each time module is inserted/removed , + */ + sg_template.dev_noticed--; return; } return; diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.0.0/linux/drivers/scsi/st.c Mon May 20 08:21:03 1996 +++ linux/drivers/scsi/st.c Mon Jul 1 07:08:27 1996 @@ -11,7 +11,7 @@ Copyright 1992 - 1996 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Tue May 14 17:58:12 1996 by makisara@kai.makisara.fi + Last modified: Sun Jun 30 15:26:23 1996 by root@kai.makisara.fi Some small formal changes - aeb, 950809 */ @@ -143,6 +143,8 @@ } #endif scode = sense[2] & 0x0f; + +#if !DEBUG if (!(driver_byte(result) & DRIVER_SENSE) || ((sense[0] & 0x70) == 0x70 && scode != NO_SENSE && @@ -152,15 +154,14 @@ scode != VOLUME_OVERFLOW && SCpnt->data_cmnd[0] != MODE_SENSE && SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ -#if !DEBUG if (driver_byte(result) & DRIVER_SENSE) { printk(KERN_WARNING "st%d: Error with sense data: ", dev); print_sense("st", SCpnt); } else printk(KERN_WARNING "st%d: Error %x.\n", dev, result); -#endif } +#endif if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR @@ -172,7 +173,7 @@ scsi_tapes[dev].recover_count++; scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT); #if DEBUG - if (debugging) { /* This is compiled always on purpose */ + if (debugging) { if (SCpnt->data_cmnd[0] == READ_6) stp = "read"; else if (SCpnt->data_cmnd[0] == WRITE_6) @@ -380,16 +381,17 @@ return (-EBUSY); if ((STp->buffer)->last_result_fatal != 0) { - printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40) && - (SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) { + (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) { STp->dirty = 0; (STp->buffer)->buffer_bytes = 0; result = (-ENOSPC); } - else + else { + printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); result = (-EIO); + } STp->drv_block = (-1); } else { @@ -455,7 +457,8 @@ result = st_int_ioctl(inode, MTBSR, backspace); } else if ((STp->eof == ST_FM) && !STp->eof_hit) { - (STp->mt_status)->mt_fileno++; + if ((STp->mt_status)->mt_fileno >= 0) + (STp->mt_status)->mt_fileno++; STp->drv_block = 0; } @@ -832,7 +835,13 @@ SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ - if ((STp->buffer)->last_result_fatal != 0) + if ((STp->buffer)->last_result_fatal != 0 && + ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || + (SCpnt->sense_buffer[2] & 0x4f) != 0x40 || + ((SCpnt->sense_buffer[0] & 0x80) != 0 && + (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] | + SCpnt->sense_buffer[5] | + SCpnt->sense_buffer[6]) == 0))) /* Filter out successful write at EOM */ printk(KERN_ERR "st%d: Error on write filemark.\n", dev); else { if ((STp->mt_status)->mt_fileno >= 0) @@ -1266,6 +1275,9 @@ #endif if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ + if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) + SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ + if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ if ((SCpnt->sense_buffer[0] & 0x80) != 0) @@ -1309,31 +1321,31 @@ SCpnt = NULL; } } - else if (SCpnt->sense_buffer[2] & 0x40) { - STp->eof = ST_EOM_OK; + else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */ + STp->eof = ST_FM; if (STp->block_size == 0) - (STp->buffer)->buffer_bytes = bytes - transfer; + (STp->buffer)->buffer_bytes = 0; else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; #if DEBUG if (debugging) - printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev, - (STp->buffer)->buffer_bytes); + printk(ST_DEB_MSG + "st%d: EOF detected (%d bytes read, transferred %d bytes).\n", + dev, (STp->buffer)->buffer_bytes, total); #endif } - else if (SCpnt->sense_buffer[2] & 0x80) { - STp->eof = ST_FM; + else if (SCpnt->sense_buffer[2] & 0x40) { + STp->eof = ST_EOM_OK; if (STp->block_size == 0) - (STp->buffer)->buffer_bytes = 0; + (STp->buffer)->buffer_bytes = bytes - transfer; else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; #if DEBUG if (debugging) - printk(ST_DEB_MSG - "st%d: EOF detected (%d bytes read, transferred %d bytes).\n", - dev, (STp->buffer)->buffer_bytes, total); + printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev, + (STp->buffer)->buffer_bytes); #endif } } /* end of EOF, EOM, ILI test */ @@ -1409,7 +1421,7 @@ (STp->mt_status)->mt_fileno++; } if (total == 0 && STp->eof == ST_EOM_OK) - return (-EIO); /* ST_EOM_ERROR not used in read */ + return (-ENOSPC); /* ST_EOM_ERROR not used in read */ return total; } @@ -1677,7 +1689,7 @@ SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ STp->compression_changed = TRUE; - return 0; /* Not implemented yet */ + return 0; } @@ -2085,7 +2097,16 @@ (SCpnt->sense_buffer[4] << 16) + (SCpnt->sense_buffer[5] << 8) + SCpnt->sense_buffer[6] ); - if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) { + if (cmd_in == MTWEOF && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x4f) == 0x40 && + ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) { + ioctl_result = 0; /* EOF written succesfully at EOM */ + if (fileno >= 0) + fileno++; + (STp->mt_status)->mt_fileno = fileno; + } + else if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) { if (fileno >= 0) (STp->mt_status)->mt_fileno = fileno - undone ; else @@ -2518,11 +2539,13 @@ if (STp->eof_hit) { if (mtc.mt_op == MTFSF || mtc.mt_op == MTEOM) { mtc.mt_count -= 1; - (STp->mt_status)->mt_fileno += 1; + if ((STp->mt_status)->mt_fileno >= 0) + (STp->mt_status)->mt_fileno += 1; } else if (mtc.mt_op == MTBSF) { mtc.mt_count += 1; - (STp->mt_status)->mt_fileno += 1; + if ((STp->mt_status)->mt_fileno >= 0) + (STp->mt_status)->mt_fileno += 1; } } @@ -2670,6 +2693,9 @@ (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff); if (STps->at_sm) (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff); + if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || + STp->drv_buffer != 0) + (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff); memcpy_tofs((char *)arg, (char *)(STp->mt_status), sizeof(struct mtget)); diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.blurb linux/drivers/sound/.blurb --- v2.0.0/linux/drivers/sound/.blurb Sun Mar 24 22:49:48 1996 +++ linux/drivers/sound/.blurb Sun Jun 30 11:43:44 1996 @@ -1,8 +1,9 @@ ********************************************************* * Readme.cards (this directory) contains some card * * specific instructions. * -* See http://personal.eunet.fi/pp/voxware for most up * +* See http://www.4front-tech.com/usslite for most up * * to date info. * +* (European mirror http://personal.eunet.fi/pp/voxware) * * * * DON'T USE PROGRAMS FROM SND_UTIL PACKAGE EARLIER THAN * * snd-util-3.5 WITH THIS SOUND DRIVER VERSION. * diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.object_files linux/drivers/sound/.object_files --- v2.0.0/linux/drivers/sound/.object_files Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/.object_files Sun Jun 30 11:50:18 1996 @@ -0,0 +1,35 @@ +audio.o +dmabuf.o +opl3.o +sequencer.o +midibuf.o +sb_card.o +pas2_card.o +adlib_card.o +pas2_pcm.o +pas2_mixer.o +pas2_midi.o +gus_card.o +gus_wave.o +mpu401.o +gus_midi.o +gus_vol.o +patmgr.o +sb_mixer.o +sb_common.o +midi_synth.o +uart6850.o +uart401.o +sound_timer.o +sb_midi.o +sb_audio.o +sys_timer.o +ics2101.o +ad1848.o +pss.o +sscape.o +trix.o +aedsp16.o +mad16.o +cs4232.o +maui.o diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.objects linux/drivers/sound/.objects --- v2.0.0/linux/drivers/sound/.objects Sun Mar 24 22:51:44 1996 +++ linux/drivers/sound/.objects Sun Jun 30 11:50:25 1996 @@ -29,7 +29,7 @@ endif ifdef CONFIG_MAD16 - OBJS := $(OBJS) mad16.o mad16_sb_midi.o + OBJS := $(OBJS) mad16.o endif ifdef CONFIG_MAUI @@ -65,11 +65,11 @@ endif ifdef CONFIG_SB - OBJS := $(OBJS) sb16_midi.o sb_card.o sb_dsp.o sb_midi.o sb_mixer.o - OBJS := $(OBJS) sb_card.o - OBJS := $(OBJS) sb_dsp.o sb16_dsp.o - OBJS := $(OBJS) sb_midi.o - OBJS := $(OBJS) sb_mixer.o + OBJS := $(OBJS) sb_card.o +endif + +ifdef CONFIG_SBDSP + OBJS := $(OBJS) sb_common.o sb_audio.o sb_mixer.o sb_midi.o endif ifdef CONFIG_SEQUENCER @@ -94,4 +94,8 @@ ifdef CONFIG_UART6850 OBJS := $(OBJS) uart6850.o +endif + +ifdef CONFIG_UART401 + OBJS := $(OBJS) uart401.o endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.version linux/drivers/sound/.version --- v2.0.0/linux/drivers/sound/.version Sun Mar 31 00:13:17 1996 +++ linux/drivers/sound/.version Sun Jun 30 11:43:44 1996 @@ -1,2 +1,2 @@ -3.5.2 -0x030500 +3.5.5-beta1 +0x030504 diff -u --recursive --new-file v2.0.0/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v2.0.0/linux/drivers/sound/CHANGELOG Tue May 7 16:22:34 1996 +++ linux/drivers/sound/CHANGELOG Sun Jun 30 11:43:44 1996 @@ -1,10 +1,63 @@ -Changelog for version 3.5.2 +Changelog for version 3.5.4 --------------------------- +Since 3.5.4-beta8 +- Fixed a bug in handling of non-fragment sized writes in 16 bit/stereo mode + with GUS. +- Limited minimum fragment size with some audio devices (GUS=512 and + SB=32). These devices require more time to "recover" from processing + of each fragment. + +Since 3.5.4-beta6/7 +- There seems to be problems in the OPTi 82C930 so cards based on this + chip don't necessarily work yet. There are problems in detecting the + MIDI interface. Also mixer volumes may be seriously wrong on some systems. + You can safely use this driver version with C930 if it looks to work. + However please don't complain if you have problems with it. C930 support + should be fixed in future releases. +- Got initialization of GUS PnP to work. With this version GUS PnP should + work in GUS compatible mode after initialization using isapnptools. +- Fixed a bug in handling of full duplex cards in write only mode. This has + been causing "audio device opening" errors with RealAudio player. + +Since 3.5.4.beta5 +- Changes to OPTi 82C930 driver. +- Major changes to the Soundscape driver. The driver requires now just one + DMA channel. The extra audio/dsp device (the "Not functional" one) used + for code download in the earlier versions has been eliminated. There is now + just one /dev/dsp# device which is used both for code download and audio. + +Since 3.5.4.beta4 +- Minor changes. + +Since 3.5.4-beta2 +- Fixed silent playback with ESS 688/1688. +- Got SB16 to work without the 16 bit DMA channel (only the 8 bit one + is required for 8 and 16 bit modes). +- Added the "lowlevel" subdirectory for additional low level drivers that + are not part of USS core. See lowlevel/README for more info. +- Included support for ACI mixer (by Markus Kuhn). ACI is a mixer used in + miroPCM soundcards. See lowlevel/aci.readme for more info. +- Support for Aztech Washington chipset (AZT2316 ASIC). + +Since 3.5.4-beta1 +- Reduced clicking with AD1848. +- Support for OPTi 82C930. Only half duplex at this time. 16 bit playback + is sometimes just white noise (occurs randomly). + +Since 3.5.2 +- Major changes to the SB/Jazz16/ESS driver (most parts rewritten). + The most noticeable new feature is support for multiple SB cards at the same + time. +- Renamed sb16_midi.c to uart401.c. Also modified it to work also with + other MPU401 UART compatible cards than SB16/ESS/Jazz. +- Some changes which reduce clicking in audio playback. +- Copying policy is now GPL. + Since 3.5.1 - TB Maui initialization support Since 3.5 -- Improved handling of playback underrun situations. +- Improved handling of playback underrunt situations. Since 3.5-beta10 - Bug fixing @@ -82,7 +135,7 @@ modularized version. They can be enabled by using init_trace=1 in the insmod command line (insmod sound init_trace=1). - More AIX stuff. -- Added support for synchronizing dsp/audio devices with /dev/sequencer. +- Added support for syncronizing dsp/audio devices with /dev/sequencer. - mmap() support for dsp/audio devices. Since 3.5-alpha5 @@ -106,13 +159,13 @@ - Fixed random protection fault in gus_wave.c Since 3.5-alpha1 -- Modified to work with Linux-1.3.33 and later +- Modified to work with Linux-1.3.33 and leater - Some minor changes Since 3.0.2 - Support for CS4232 based PnP cards (AcerMagic S23 etc). - Full duplex support for some CS4231, CS4232 and AD1845 based cards -(GUS MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards +(GUA MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards having a codec mentioned above). - Almost fully rewritten loadable modules support. - Fixed some bugs. @@ -255,7 +308,7 @@ Since 2.1 - Preliminary support for SB16. - - The SB16 mixer is supported in its native mode. + - The SB16 mixer is supported in it's native mode. - Digitized voice capability up to 44.1 kHz/8 bit/mono (16 bit and stereo support coming in the next release). - Fixed some bugs in the digitized voice driver for PAS16. diff -u --recursive --new-file v2.0.0/linux/drivers/sound/COPYING linux/drivers/sound/COPYING --- v2.0.0/linux/drivers/sound/COPYING Sun Mar 24 22:49:45 1996 +++ linux/drivers/sound/COPYING Sun Jun 30 11:43:45 1996 @@ -1,25 +1,339 @@ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.0.0/linux/drivers/sound/Config.in Wed Jun 5 10:41:29 1996 +++ linux/drivers/sound/Config.in Sun Jun 30 11:46:03 1996 @@ -2,11 +2,16 @@ # Sound driver configuration # #-------- -# There is another config script which is compatible with rest of +# There is another confic script which is compatible with rest of # the kernel. It can be activated by running 'make mkscript' in this # directory. Please note that this is an _experimental_ feature which -# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro). +# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). #-------- # $MAKE -C drivers/sound config || exit 1 +bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND + +if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then + bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER +fi diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Config.std linux/drivers/sound/Config.std --- v2.0.0/linux/drivers/sound/Config.std Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/Config.std Sun Jun 30 11:46:03 1996 @@ -2,11 +2,16 @@ # Sound driver configuration # #-------- -# There is another config script which is compatible with rest of +# There is another confic script which is compatible with rest of # the kernel. It can be activated by running 'make mkscript' in this # directory. Please note that this is an _experimental_ feature which -# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro). +# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). #-------- # $MAKE -C drivers/sound config || exit 1 +bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND + +if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then + bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER +fi diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.0.0/linux/drivers/sound/Makefile Sun Jun 9 13:28:46 1996 +++ linux/drivers/sound/Makefile Sun Jun 30 11:43:41 1996 @@ -5,6 +5,8 @@ # # +.PHONY: dummy +SUB_DIRS = lowlevel VERSION = `head -1 .version` TARGET_OS = linux USRINCDIR = /usr/include @@ -12,17 +14,15 @@ FIXEDOBJS = soundcard.o dev_table.o sound_switch.o +ifndef NO_LOWLEVEL + FIXEDOBJS := $(FIXEDOBJS) lowlevel/lowlevel.o +endif + ifeq (.defines,$(wildcard .defines)) include .defines include .objects else -OBJS = audio.o dmabuf.o sb_dsp.o \ - opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \ - pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \ - gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \ - sb16_midi.o midi_synth.o uart6850.o sound_timer.o \ - sys_timer.o ics2101.o ad1848.o pss.o sscape.o trix.o aedsp16.o \ - mad16.o mad16_sb_midi.o cs4232.o maui.o +OBJS = `cat .object_files` endif ifndef TOPDIR @@ -59,7 +59,7 @@ # CC = gcc HOSTCC = gcc -CFLAGS = -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 +CFLAGS = -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -pipe -m486 USE_DEPEND=y else include $(TOPDIR)/Rules.make @@ -72,7 +72,8 @@ clean: rm -f core core.* *.o *.a tmp_make *~ x y z *% - rm -f configure sound_stub.c objects/*.o + rm -f configure sound_stub.c objects/*.o + cd lowlevel;make clean indent: for n in *.c;do echo indent $$n;indent $$n;done @@ -85,9 +86,9 @@ @echo @echo @echo - @echo "NOTE! Object file dependencies may not be up to date. Run" - @echo "make again if kernel/driver doesn't link properly. Restarting" - @echo "it now may save some time." + @echo NOTE! Object file dependencies may not be up to date. Run + @echo make again if kernel/driver doesn''t link properly. Restarting + @echo it now may save some time. @echo @echo @@ -108,7 +109,9 @@ # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h -kernelconfig: setup-$(TARGET_OS) configure +kernelconfig: setup-$(TARGET_OS) + rm -f configure + $(HOSTCC) -o configure configure.c ./configure fixedlocal > local.h ./configure fixeddefines > .defines @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h @@ -117,13 +120,16 @@ # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h -mkscript: setup-$(TARGET_OS) configure +mkscript: setup-$(TARGET_OS) + rm -f configure + $(HOSTCC) -o configure configure.c ./configure script > Config.in + cat lowlevel/Config.tmpl >> Config.in ./configure fixedlocal > local.h ./configure fixeddefines > .defines clrconf: - rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h .defines + rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h maui_boot.h .defines configure: configure.c $(HOSTCC) -o configure configure.c @@ -142,6 +148,9 @@ modules: local.h sound.o ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o + +lowlevel/lowlevel.o: dummy + cd lowlevel;make ifdef USE_DEPEND # diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v2.0.0/linux/drivers/sound/Readme Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/Readme Sun Jun 30 11:43:42 1996 @@ -1,9 +1,9 @@ -Version 3.5.2 release notes --------------------------------- +USS Lite version 3.5.4 release notes +------------------------------------ Most up to date information about this driver is available from -http://personal.eunet.fi/pp/voxware. - +http://www.4front-tech.com/usslite or http://personal.eunet.fi/pp/voxware +(european mirror). @@ -12,18 +12,20 @@ date but still very useful. Information about bug fixes and such things is available from the web page (see below). -New Programmer's Guide is currently under work (Feb/March 96). Please -check http://personal.eunet.fi/pp/voxware for more info. +New Programmer's Guide is currently under work (June/July 96). Please +check http://www.4front-tech.com/pguide for more info. ==================================================== - THIS VERSION ____REQUIRES____ Linux 1.3.70 OR LATER. ==================================================== It's very likely that this driver version is incompatible with -Linux versions later than 2.x. +Linux versions later than 2.0.x. Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z" -contain useful utilities to be used with this driver. +contain usefull utilities to be used with this driver. +See http://www.4front-tech.com/usslite/getting.html for +download instructions. If you are looking for the installation instructions, please look at Readme.linux. @@ -33,14 +35,14 @@ See Readme.cards. -Please check http://personal.eunet.fi/pp/voxware if you don't find +Please check http://www.4front-tech.com/usslite if you don't find your soundcard there. Contributors ------------ This driver contains code by several contributors. In addition several other -persons have given useful suggestions. The following is a list of major +persons have given usefull suggestions. The following is a list of major contributors. (I could have forgotten some names.) Craig Metz 1/2 of the PAS16 Mixer and PCM support @@ -53,9 +55,9 @@ Jim Lowe, Amancio Hasty Jr FreeBSD/NetBSD port Anders Baekgaard Bughunting and valuable suggestions. - Joerg Schubert SB16 DSP support. + Joerg Schubert SB16 DSP support (initial version). Andrew Robinson Improvements to the GUS driver - Megens SA MIDI recording for SB and SB Pro. + Megens SA MIDI recording for SB and SB Pro (initial version). Mikael Nordqvist Linear volume support for GUS and nonblocking /dev/sequencer. Ian Hartas SVR4.2 port @@ -63,16 +65,18 @@ Risto Kankkunen Major contributions to the mixer support of GUS v3.7. Hunyue Yau Mixer support for SG NX Pro. - Marc Hoffman PSS support. - Rainer Vranken Initialization for Jazz16 (ProSonic, MV3D, SM Wave). + Marc Hoffman PSS support (initial version). + Rainer Vranken Initialization for Jazz16 (initial version). Peter Trattler Initial version of loadable module support for Linux. - JRA Gibson 16 bit mode for Jazz16 - Davor Jadrijevic MAD16 support - Gregor Hoffleit Mozart support + JRA Gibson 16 bit mode for Jazz16 (initial version) + Davor Jadrijevic MAD16 support (initial version) + Gregor Hoffleit Mozart support (initial version) Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support James Hightower Spotting a tiny but important bug in CS423x support. + + Please look at lowlevel/README for more contributors. -There are probably many other names missing. If you have sent me some +There are propably many other names missing. If you have sent me some patches and your name is not in the above list, please inform me. Sponsors etc. @@ -84,7 +88,7 @@ Novell, Inc. UnixWare personal edition + SDK The Santa Cruz Operation, Inc. A SCO OpenServer + SDK Ensoniq Corp, a SoundScape card and extensive amount of assistance -MediaTriX Peripherals Inc, a AudioTriX Pro card + SDK +MediaTrix Peripherals Inc, a AudioTrix Pro card + SDK Acer, Inc. a pair of AcerMagic S23 cards. In addition the following companies have provided me sufficient amount @@ -99,6 +103,8 @@ Integrated Circuit Systems Inc. OAK Technology OPTi +Turtle Beach +miro Ad Lib Inc. ($$) Music Quest Inc. ($$) Creative Labs ($$$) @@ -107,7 +113,7 @@ ========================= Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?). -Also look at the home page (http://personal.eunet.fi/pp/voxware). It may +Also look at the home page (http://www.4front-tech.com/usslite). It may contain info about some recent bug fixes. It's likely that you have some problems when trying to use the sound driver @@ -119,7 +125,7 @@ at /var/adm/messages for more verbose error message. -In general the easiest way to diagnose problems is to do "cat /dev/sndstat". +In general the easiest way to diagnoze problems is to do "cat /dev/sndstat". If you get an error message, there are some problems with the driver setup: @@ -127,7 +133,7 @@ the sound driver are missing. Use the script at the end of linux/drivers/sound/Readme.linux to create them. - - "No such device" shows that the sound driver is not in the kernel. + - "No such device" telss that the sound driver is not in the kernel. You have to reconfigure and recompile the kernel to have the sound driver. Compiling the driver doesn't help alone. You have to boot with the newly compiled one before the driver becomes active. @@ -142,7 +148,7 @@ this particular device. For example /dev/audio and /dev/dsp will not work if "digitized voice support" was not enabled during "make config". - - "Device or resource busy". Probably the IRQ (or DMA) channel + - "Device or resource busy". Propably the IRQ (or DMA) channel required by the soundcard is in use by some other device/driver. - "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict. @@ -161,8 +167,8 @@ Hannu Hannu Savolainen -hannu@voxware.pp.fi -(Please check http:/personal.eunet.fi/pp/voxware before mailing me). +hannu@voxware.pp.fi, hannu@4front-tech.com +(Please check http://www.4front-tech.com/usslite before mailing me). Snail mail: Hannu Savolainen Hiekkalaiturintie 3 A 8 diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards --- v2.0.0/linux/drivers/sound/Readme.cards Tue May 7 16:22:34 1996 +++ linux/drivers/sound/Readme.cards Wed Jul 3 10:12:18 1996 @@ -1,40 +1,57 @@ -Configuring version 3.5 (for Linux) with some most common soundcards -==================================================================== +Configuring version 3.5.4 (for Linux) with some most common soundcards +====================================================================== IMPORTANT! This document covers only cards that were "known" when this driver version was released. Please look at - http://personal.eunet.fi/pp/voxware for info about + http://www.4front-tech.com/usslite for info about cards introduced recently. + The following covers mainly the "old" configuration + method (make config). Most of it is valid for the "new" + configuration (make menuconfig/xconfig) too. + + Cards having some kind of loadable "microcode" such as + PSS, SM Wave, AudioTrix Pro and Maui/Tropez must be + configured using the old method. The new one will not + work with them. + + When using make xconfig and/or make menuconfig, you should + carefully check each sound configuration option (particularily + "Support for /dev/dsp and /dev/ausio"). + Cards that are not (fully) supported by this driver --------------------------------------------------- There are many soundcards which don't work with this driver version (v3.5). Support for some of them is expected to be available during/after summer 1996 (in version 3.6). Please check -http://personal.eunet.fi/pp/voxware for latest news. Please don't +http://www.4front-tech.com/usslite for latest news. Please don't mail me and ask about these cards. The unsupported cards are: - All PnP soundcards (SB PnP, GUS PnP, Soundscape PnP etc.) - (SB PnP in first 3.6-alpha version (Apr 96?), GUS PnP bit later, - Soundscape PnP probably much later, others ???). See - "Configuring PnP soundcards" below for some hints. + Schecule for availability of PnP soundcard support in + USS/Lite depends on progress made by kernel PnP team + (propably in Linux 2.1.xx versions). With Linux 2.0.x + versions there are two ways to get PnP soundcards to work: + - Use isapnptools, DOS, Win95 or PnP aware BIOS to wake up the + card before starting the sound driver. See "Configuring PnP + soundcards" below for some hints. + - Support for SB PnP and GUS PnP is present in USS/Linux (the + commercial version of this driver). - Mwave soundcards and motherboards - (Version 3.6 or 3.7. Depends on how fast I get a Mwave - card and suitable documents for it). + (Version 3.6 or 3.7. Depends on how fast I get + suitable documents for Mwave). - Emu8k (SB 32/AWE) - (Probably not before Nov/Dec 96. I know the unofficial + (Propably not _before_ summer 97. I know the unofficial AWE programmers guide so don't send me more copies of it). - Diamond Edge 3D (ASAP. In practice this may take relatively long time). - Compaq Deskpro - (Version 3.6???) - - Miro soundcards - (Early 3.6-alpha versions) - - OPTi 82C930 based soundcards - (Early 3.6-alpha versions?) + (Version 3.5.4-beta6 (already released)) - Sound Galaxy Washington/Waverider - (3.6-alpha versions. Can't promise the waverider synth). + (Audio features already in USS/Linux (USS/Lite soon). + Can't promise the waverider synth since + availability of chip specs is uncertain). - Yamaha OPL4 (on cards having _RAM_ for samples) (Late 96?. Works as OPL3 with current driver versions) @@ -52,7 +69,7 @@ soft configuring their I/O, IRQ, DMA and shared memory resources. Currently at least cards made by Creative Technology (SB32 and SB32AWE PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and -Aztech (some Sound Galaxy models) use PnP technology. The CS4232 audio +Aztech (some Sound Galazy models) use PnP technology. The CS4232 audio chip by Crystal Semiconductor (Intel Atlantis, HP Pavillon and many other motherboards) is also based on PnP technology but there is a "native" driver available for it (see information about CS4232 later in this document). @@ -60,7 +77,7 @@ PnP soundcards (as well as most other PnP ISA cards) are not supported by version 3.5 of this driver (Linux 1.3.xx and Linux 2.0.x). Proper support for them should be released during spring 96 -(see http://personal.eunet.fi/pp/voxware for latest info). +(see http://www.4front-tech.com/usslite for latest info). There is a method to get most of the PnP cards to work. The basic method is the following: @@ -76,7 +93,7 @@ your card for more info. Windows 95 could work as well as DOS but running loadlin may be somehow -difficult. Probably you should "shut down" your machine to MS-DOS mode +difficult. Propably you should "shut down" your machine to MS-DOS mode before running it. Some machines have BIOS utility for setting PnP resources. This is a good @@ -87,7 +104,11 @@ of such tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The file is called isapnptools-*. Please note that this tool is just a temporary solution which may be incompatible with future kernel versions having proper -support for PnP cards. +support for PnP cards. There are bugs in setting DMA channels in earlier +versions of isapnptools so at least version 1.6 is required with soundcards. +You can find latest version of isapnptools from +ftp://ftp.demon.co.uk/pub/unix/linux/utils/ + These two methods don't work with GUS PnP which requires some additional initialization (cards DOS/Win95 driver does it). @@ -154,7 +175,7 @@ (AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor). Currently most soundcards are based on one of the MSS compatible codec chips. The CS4231 is used in the high quality cards such as GUS MAX, - MediaTriX AudioTriX Pro and TB Tropez (GUS MAX is not MSS compatible). + MediaTrix AudioTrix Pro and TB Tropez (GUS MAX is not MSS compatible). Having a AD1848, CS4248 or CS4231 codec chip on the card is a good sign. Even if the card is not MSS compatible, it could be easy to write @@ -177,7 +198,7 @@ voices than the OPL2. The OPL4 is a new chip that has an OPL3 and a wave table synthesizer packed onto the same chip. The driver supports just the OPL3 mode directly. Most cards with an OPL4 (like - SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401 + SM Wave and AudioTrix Pro) support the OPL4 mode using MPU401 emulation. Writing a native OPL4 support is difficult since Yamaha doesn't give information about their sample ROM chip. @@ -195,7 +216,7 @@ The driver supports downloading DSP algorithms to these cards. -MediaTriX AudioTriX Pro +MediaTrix AudioTrix Pro The ATP card is built around a CS4231 codec and an OPL4 synthesizer chips. The OPL4 mode is supported by a microcontroller running a General MIDI emulator. There is also a SB 1.5 compatible playback mode. @@ -209,9 +230,10 @@ NOTE! The new PnP SoundScape is not supported yet. MAD16 and Mozart based cards - The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface + The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929) + and OPTi 82C930 interface chips are used in many different soundcards, including some - cards by Reveal and Turtle Beach (Tropez). The purpose of these + cards by Reveal miro and Turtle Beach (Tropez). The purpose of these chips is to connect other audio components to the PC bus. The interface chip performs address decoding for the other chips. NOTE! Tropez Plus is not MAD16 but CS4232 based. @@ -253,14 +275,14 @@ Latest cards are fully software configurable or they are PnP ISA compatible. There are no jumpers on the board. -The driver handles software configurable cards automatically. Just configure +The driver handles software configurable cards automaticly. Just configure the driver to use I/O, IRQ and DMA settings which are known to work. You could usually use the same values than with DOS and/or Windows. Using different settings is possible but not recommended since it may cause some trouble (for example when warm booting from an OS to another or when installing new hardware to the machine). -Sound driver sets the soft configurable parameters of the card automatically +Sound driver sets the soft configurable parameters of the card automaticly during boot. Usually you don't need to run any extra initialization programs when booting Linux but there are some exceptions. See the card specific instructions (below) for more info. @@ -357,8 +379,8 @@ since using the default _doesn't_ guarantee anything. Note also that all questions may not be asked. The configuration program -may disable some questions depending on the earlier choices. It may also -select some options automatically as well. +may disable some questions dependig on the earlier choices. It may also +select some options automaticly as well. "ProAudioSpectrum 16 support", - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_, @@ -426,19 +448,19 @@ conflict. "Ensoniq Soundscape support", - Answer 'y' if you have a soundcard based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, + chipset. Suach cards are being manufactured at least by Ensoniq, Spea and Reveal (note that Reveal makes other cards also). - "MediaTriX AudioTriX Pro support", - - Answer 'y' if you have the AudioTriX Pro. + "MediaTrix AudioTrix Pro support", + - Answer 'y' if you have the AudioTrix Pro. "Support for MAD16 and/or Mozart based cards", - Answer y if your card has a Mozart (OAK OTI-601) or MAD16 - (OPTi 82C928 or 82C929) audio interface chip. These chips are + (OPTi 82C928, 82C929 or 82C930) audio interface chip. These chips are currently quite common so it's possible that many no-name cards have one of them. In addition the MAD16 chip is used in some cards made by known manufacturers such as Turtle Beach (Tropez), Reveal (some models) and Diamond (some recent models). "Support for TB Maui" - - This enables TB Maui specific initialization. Works with TB Maui + - This enables TB Maui spesific initialization. Works with TB Maui and TB Tropez (may not work with Tropez Plus). "Audio Excel DSP 16 initialization support", @@ -521,7 +543,7 @@ was listed in the beginning of this file. In this case you should follow instructions for your card later in this file. -For other not fully SB clones you may try initialization using DOS in +For other not fully SB clones yoy may try initialization using DOS in the following way: - Boot DOS so that the card specific driver gets run. @@ -607,7 +629,7 @@ will fail. GUS PnP (with RAM) is partially supported but it needs to be initialized using -DOS before booting Linux. This may fail on machines having PnP BIOS. +DOS or isapnptools before starting the driver. MPU401 and Windows Sound System ------------------------------- @@ -655,18 +677,18 @@ It's possible to load your own DSP algorithms and run them with the card. Look at the directory pss_test of snd-util-3.0.tar.gz for more info. -AudioTriX Pro +AudioTrix Pro ------------- You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition -to the native AudioTriX driver. Don't enable MSS or MPU drivers. +to the native AudioTrix driver. Don't enable MSS or MPU drivers. Configuring ATP is little bit tricky since it uses so many I/O, IRQ and DMA numbers. Using the same values than with DOS/Win is a good idea. Don't -attempt to use the same IRQ or DMA channels twice. +attemp to use the same IRQ or DMA channels twice. The SB mode of ATP is implemented so the the ATP driver just enables SB -in the proper address. The SB driver handles the rest. You have to configure +in the proper address. The SB driver handles the rest. Yoy have to configure both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O settings. @@ -689,22 +711,27 @@ itself so you don't need to enable other drivers than SoundScape (enable also the /dev/dsp, /dev/sequencer and MIDI supports). -SoundScape driver uses the MSS compatible codec of the card. It's important -to note that /dev/dsp0 (/dev/dsp is linked to /dev/dsp0 by default) -doesn't work with SoundScape (yet). The 'ssinit' program needs /dev/dsp0 so -that's the reason why it's there. It's possible that 'primary' pcm channel -becomes supported later. Currently the card's firmware doesn't contain -support for it. - -With 3.0 of the driver you have to change your system to use /dev/dsp1 by default -so execute: cd /dev;rm dsp;ln -s dsp1 dsp after you have installed driver -version 3.0 (or later) first time. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! !!!! +!!!!! NOTE! Before version 3.5-beta6 there WERE two sets of audio !!!! +!!!!! device files (/dev/dsp0 and /dev/dsp1). The first one WAS !!!! +!!!!! used only for card initialization and the second for audio !!!! +!!!!! purposes. It WAS required to change /dev/dsp (a symlink) to !!!! +!!!!! point to /dev/dsp1. !!!! +!!!!! !!!! +!!!!! This is not required with USS versions 3.5-beta6 and later !!!! +!!!!! since there is now just one audio device file. Pleace !!!! +!!!!! change /dev/dsp to point back to /dev/dsp0 if you are !!!! +!!!!! upgrading from an earlier driver version using !!!! +!!!!! (cd /dev;rm dsp;ln -s dsp0 dsp). !!!! +!!!!! !!!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -The configuration program asks two DMA channels and two interrupts. One IRQ +The configuration program asks one DMA channel and two interrupts. One IRQ and one DMA is used by the MSS codec. The second IRQ is required for the MPU401 mode (you have to use different IRQs for both purposes). -The second DMA channel is required for initialization of the microcontroller. -You have to use separate DMA channels. +There were earlier two DMA channels for soundscape but the current driver +version requires just one. The SoundScape card has a Motorola microcontroller which must initialized _after_ boot (the driver doesn't initialize it during boot). @@ -727,7 +754,8 @@ and locate the sound driver initialization message for the SoundScape card. If the driver displays string , you have an old card and you will need to use sndscape.co1. For other cards use -soundscape.co0. +soundscape.co0. New Soundscape revisions such as Elite and PnP use +code files with higher numbers (.co2, .co3, etc.). Check /var/adm/messages after running ssinit. The driver prints the board version after downloading the microcode file. That version @@ -749,7 +777,8 @@ Mozart and OPTi 82C928 (the original MAD16) chips don't support MPU401 mode so enter just 0 when the configuration program asks the -MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) has MPU401 mode. +MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) and 82C930 chips have MPU401 +mode. TB Tropez is based on the 82C929 chip. It has two MIDI ports. The one connected to the MAD16 chip is the second one (there is a second @@ -765,8 +794,8 @@ this should not be a problem. If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer -chip (_not_ an OPL3), you have to append line containing #define MAD16_OPL4 -to the file linux/drivers/sound/local.h (after running make config). +chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4 +to the file linux/dirvers/sound/local.h (after running make config). MAD16 cards having a CS4231 codec support full duplex mode. This mode can be enabled by configuring the card to use two DMA channels. Possible @@ -785,12 +814,12 @@ problems if you have another MPU401 compatible card. In this case you must give address of the Jazz16 based MPU401 interface when the config program prompts for the MPU401 information. Then look at the MPU401 -specific section for instructions about configuring more than one MPU401 cards. +spesific section for instructions about configuring more than one MPU401 cards. Logitech Soundman Wave ---------------------- -Read the above MV Jazz specific instructions first. +Read the above MV Jazz spesific instructions first. The Logitech SoundMan Wave (don't confuse with the SM16 or SM Games) is a MV Jazz based card which has an additional OPL4 based wave table @@ -810,7 +839,7 @@ NOTE! Don't answer 'y' when the driver asks about SM Games support (the next question after the MIDI0001.BIN name). However - answering 'y' doesn't cause damage your computer so don't panic. + aneswering 'y' doesn't cause damage your computer so don't panic. Sound Galaxies -------------- @@ -821,7 +850,7 @@ The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have an EEPROM chip for storing the configuration data. There is a microcontroller -which initializes the card to match the EEPROM settings when the machine +which initializes the card to match the EEPROM settigs when the machine is powered on. These cards actually behave just like they have jumpers for all of the settings. Configure driver for MSS, MPU, SB/SB Pro and OPL3 supports with these cards. @@ -836,10 +865,10 @@ ESS ES1688 and ES688 'AudioDrive' based cards --------------------------------------------- -Support for these two ESS chips is embedded in the SB Pro driver. -Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port' +Support for these two ESS chips is embedded in the SB driver. +Configure these cards just like SB. Enable the 'SB MPU401 MIDI port' if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode -so you don't need to enable it (the driver uses normal SB MIDI automatically +so you don't need to enable it (the driver uses normal SB MIDI automaticly with ES688). NOTE! ESS cards are not compatible with MSS/WSS. @@ -879,6 +908,53 @@ configuring Linux. Having it enabled is likely to cause mysterious problems and kernel failures when sound is used. +miroSOUND +--------- + +The miroSOUND PCM12 has been used successfully. This card is based on +the MAD16, OPL4, and CS4231A chips and everything said in the section +about MAD16 cards applies here, too. The only major difference between +the PCM12 and other MAD16 cards is that instead of the mixer in the +CS4231 codec a separate mixer controlled by an on-board 80C32 +microcontroller is used. Control of the mixer takes place via the ACI +(miro's audio control interface) protocol that is implemented in a +separate lowlevel driver. Make sure you compile this ACI driver +together with the normal MAD16 support when you use a miroSOUND PCM12 +card. The ACI mixer is controlled by /dev/mixer and the CS4231 mixer +by /dev/mixer2. You usually don't want to change anything on the +CS4231 mixer. + +The miroSOUND PCM12 is capable of full duplex operation (simultaneous +PCM replay and recording), which allows you to implement nice +real-time signal processing audio effect software and network +telephones. The ACI mixer has to be configured into a special "solo" +mode for duplex operation in order to avoid feedback caused by the +mixer (input hears output signal). See lowlevel/aci.c for details on +the ioctl() for activating the "solo" mode. + +The following configuration parameters have worked fine for the PCM12 +in Markus Kuhn's system, many other configurations might work, too: +MAD16_BASE=0x530, MAD16_IRQ=11, MAD16_DMA=3, MAD16_DMA2=0, +MAD16_MPU_BASE=0x330, MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536, +SELECTED_SOUND_OPTIONS=0x00281000. + +The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12. +Perhaps the same ACI driver also works for these cards, however this +has never actually been tested. The PCM20 contains a radio tuner, +which is also controlled by ACI. This radio tuner is currently not +supported by the ACI driver, but documentation for it was provided by +miro and ACI tuner support could easily be added if someone is really +interested. + +Compaq Deskpro XL +----------------- + +The builtin sound hardware of Compaq Deskpro XL is now supported. +You need to configure the driver with MSS and OPL3 supports enabled. +In addition you need to manually edit linux/drivers/sound/local.h and +to add a line containing "#define DESKPROXL" if you used +make menuconfig/xconfig. + Others? ------- @@ -893,19 +969,19 @@ Please check which version of sound driver you are using before complaining that your card is not supported. It's possible that you are using a driver version which was released months before your card was -introduced. Driver's release date is listed after its version number +introduced. Driver's release date is listed after it's version number in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h. -First of all, there is an easy way to make most soundcards to work +First of all. There is an easy way to make most soundcards to work with Linux. Just use the DOS based driver to initialize the card to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured -to use the same I/O, IRQ and DMA numbers than DOS, the card could work. +to use the sama I/O, IRQ and DMA numbers than DOS, the card could work. (ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with new motherboards). This method works also with all/most PnP soundcards. Don't get fooled with SB compatibility. Most cards are compatible with SB but that may require a TSR which is not possible with Linux. If -the card is compatible with MSS, it's a better choice. Some cards +the card is compatible with MSS, it's a better choise. Some cards don't work in the SB and MSS modes at the same time. Then there are cards which are no longer manufactured and/or which @@ -914,7 +990,7 @@ Adding support for a new card requires much work and increases time required in maintaining the driver (some changes need to be done to all low level drivers and be tested too, maybe with multiple -operating systems). For this reason I have made a decision to not support +operating systems). For this reason I have made a desicion to not support obsolete cards. It's possible that someone else makes a separately distributed driver (diffs) for the card. Version v3.6 will be much more modular so making separately distributed drivers will be easier with it. @@ -923,17 +999,17 @@ Writing a driver for a new card is not possible if there are no programming information available about the card. If you don't find your new card from this file, look from the home page -(http://personal.eunet.fi/pp/voxware). Then please contact +(http://www.4front-tech.com/usslite). Then please contact manufacturer of the card and ask if they have (or are willing to) released technical details of the card. Do this before contacting me. I can only answer 'no' if there are no programming information available. -I have made decision to not accept code based on reverse engineering +I have made decicion to not accept code based on reverse engineering to the driver. There are three main reasons: First I don't want to break relationships to sound card manufacturers. The second reason is that -maintaining and supporting a driver without any specs will be a pain. +maintaining and supporting a driver withoun any specs will be a pain. The third reason is that companies have freedom to refuse selling their -products to other than Windows users. +products to other than Windows useres. Some companies don't give low level technical information about their products to public or at least their require signing a NDA. It's not @@ -944,7 +1020,7 @@ There are some common audio chipsets that are not supported yet. For example Sierra Aria and IBM Mwave. It's possible that these architectures get some support in future but I can't make any promises. Just look -at the home page (http://personal.eunet.fi/pp/voxware/new_cards.html) +at the home page (http://www.4front-tech.com/usslite/new_cards.html) for latest info. Information about unsupported soundcards and chipsets is welcome as well @@ -954,6 +1030,11 @@ Hannu Savolainen hannu@voxware.pp.fi -Sound driver's www home page: http://personal.eunet.fi/pp/voxware - US mirror: http://www.4Front-Tech.com/usslite + +Personal home page: http://personal.eunet.fi/pp/voxware/hannu.html +www home page of USS/Lite: http://www.4front-tech.com/usslite + European/Finnish mirror: http://personal.eunet.fi/pp/voxware + +www home page of commercial +UNIX Sound System drivers: http://www.4front-tech.com/uss.html diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux --- v2.0.0/linux/drivers/sound/Readme.linux Tue May 28 08:09:56 1996 +++ linux/drivers/sound/Readme.linux Sun Jun 30 11:43:41 1996 @@ -19,7 +19,7 @@ sources). Remove old version of linux/drivers/sound directory before installing new files. -- To build the device files you need to run the enclosed shell script +- To build the device files you need to run the enclosed shell scrip (see below). You need to do this only when installing sound driver first time or when upgrading to much recent version than the earlier one. @@ -27,13 +27,13 @@ - Configure and compile Linux as normally (remember to include the sound support during "make config"). Please refer to kernel documentation for instructions about configuring and compiling kernel. File Readme.cards - contains card specific instructions for configuring this driver for + contains card spesific instructions for configuring this driver for use with various soundcards. Boot time configuration (using lilo and insmod) ----------------------------------------------- -This information has been removed. Too many users didn't believe +This information has been removed. Too many users did't believe that it's really not necessary to use this method. Please look at Readme of sound driver version 3.0.1 if you still want to use this method. @@ -46,7 +46,7 @@ cat /dev/sndstat -and look at the output. It should display some useful info about the +and look at the output. It should display some usefull info about the driver configuration. If there is no /dev/sndstat (/dev/sndstat: No such file or directory), ensure that you have executed the soundinstall script (at the end of this file). @@ -67,7 +67,7 @@ check for possible boot (insmod) time error messages in /var/adm/messages. - Other messages or problems -Please check http://personal.eunet.fi/pp/voxware for more info. +Please check http://www.4front-tech.com/usslite for more info. Hannu Savolainen hannu@voxware.pp.fi diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules --- v2.0.0/linux/drivers/sound/Readme.modules Mon Apr 29 18:05:18 1996 +++ linux/drivers/sound/Readme.modules Sun Jun 30 11:43:43 1996 @@ -45,10 +45,10 @@ insmod sound dma_buffsize=32768 -Minimum buffer size is 4096 and the maximum depends on the DMA channel. +Minimum buffer size is 4096 and the maximum depends on the DMA channe. For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7) -it's 128k. Driver selects a suitable buffer size automatically in case -you try to specify an invalid size. +it's 128k. Driver selects a suitable buffer size automaticly in case +you try to spesify an invalid size. Q: What is the right DMA buffer size? @@ -58,17 +58,17 @@ recording to hard disk is likely to require large buffers. Very small buffers are sufficient when you are just playing 8kHz audio files -on an empty P133 system. Using a 128k buffer just wastes 120k (or 250k) +on an empty P133 system. Using a 128k byffer just wastes 120k (or 250k) of valuable physical RAM memory. -The right buffer size can be easily found by making some experiments +The right buffer sice can be easily found by making some experiments with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system and 64k on an old 386 system. NOTE! DMA buffers are used only by /dev/audio# and /dev/dsp# devices. Other device files don't use them but there are two exceptions: GUS driver uses DMA buffers when loading samples to the card. - Ensoniq SoundScape driver uses them when downloading the microcode + Ensoniq SoundScape driver uses them when doanloading the microcode file (sndscape.co[012]) to the card. Using large buffers doesn't increase performance in these cases. diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30 --- v2.0.0/linux/drivers/sound/Readme.v30 Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/Readme.v30 Sun Jun 30 11:43:43 1996 @@ -18,7 +18,7 @@ /dev/midi## ----------- -This interface should be useful for applications like MIDI sysex librarians. +This interface should be usefull for applications like MIDI sysex librarians. There are (currently) no timing features so making music could be impossible. There are as many /dev/midi## devices as there are MIDI ports in the system. @@ -53,7 +53,7 @@ If this ioctl is called with mode=1, the interface is put to the intelligent (coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called. It could have some strange effects if not called immediately after open. This -call returns EINVAL if the midi port doesn't support the MPU-401 intelligent +vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent mode. ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port @@ -81,10 +81,10 @@ data Buffer for the command arguments and returned data. -Be extremely careful with the nr_args and nr_returns fields. They +Be extremely carefull with the nr_args and nr_returns fields. They must match the command. An incorrect value will put the card and the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further -details. +datails. @@ -99,7 +99,7 @@ /dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE() like macros. The voice number parameters of the API macros have been redefined to denote MIDI channels. This means that the driver allocates voices for -the channels automatically (this is a responsibility/right of an application +the channels automaticly (this is a responsibility/right of an application with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has similar effects for a synth channel than on a MIDI port. This kind of solution provides better device independence than the /dev/sequencer. The @@ -116,12 +116,12 @@ - The new interface is used much like the ordinary /dev/sequencer. The event format is new so you have to use the API macros defined in the -sys/soundcard.h. The interface is will probably change before the final 3.0 +sys/soundcard.h. The interface is will propably change before the final 3.0 release but using the API macros should ensure compatibility in source level. The new event format is not recognized by version 2.X so don't try to distribute binaries compiled with soundcard.h of v3.X. -- The basic API usage is similar to the current one. There are some new +- The basic API useage is similar to the current one. There are some new macros but the older ones should work as earlier. The most important incompatibility is that the /dev/sequencer2 driver allocates voices itself. The other one is that the application must send SEQ_START_TIMER() as it's diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.0.0/linux/drivers/sound/ad1848.c Tue May 7 16:22:34 1996 +++ linux/drivers/sound/ad1848.c Sun Jun 30 11:43:48 1996 @@ -15,27 +15,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -64,16 +48,18 @@ unsigned char format_bits; int xfer_count; - int irq_mode; + int audio_mode; int intr_active; int opened; char *chip_name; - int mode; + int model; #define MD_1848 1 #define MD_4231 2 #define MD_4231A 3 #define MD_1845 4 #define MD_4232 5 +#define MD_C930 6 +#define MD_IWAVE 7 /* Mixer parameters */ int recmask; @@ -96,16 +82,15 @@ static int timer_installed = -1; -static char mixer2codec[MAX_MIXER_DEV] = -{0}; - -static int ad_format_mask[6 /*devc->mode */ ] = +static int ad_format_mask[8 /*devc->model */ ] = { 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM }; @@ -121,6 +106,7 @@ static int ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local); static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart); static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart); +static int ad1848_prepare_for_output (int dev, int bsize, int bcount); static int ad1848_prepare_for_IO (int dev, int bsize, int bcount); static void ad1848_reset (int dev); static void ad1848_halt (int dev); @@ -196,7 +182,8 @@ while (timeout > 0 && ad_read (devc, 11) & 0x20) timeout--; if (ad_read (devc, 11) & 0x20) - printk ("ad1848: Auto calibration timed out(3).\n"); + if (devc->model != MD_1845) + printk ("ad1848: Auto calibration timed out(3).\n"); } static void @@ -205,8 +192,6 @@ int i; unsigned char prev; - if (devc->mode != MD_1848) - return; /* * Save old register settings and mute output channels */ @@ -215,6 +200,12 @@ prev = devc->saved_regs[i] = ad_read (devc, i); ad_write (devc, i, prev | 0x80); } + +/* + * Let's have some delay + */ + for (i = 0; i < 1000; i++) + inb (devc->base); } static void @@ -222,6 +213,12 @@ { int i; +/* + * Let's have some delay + */ + for (i = 0; i < 1000; i++) + inb (devc->base); + /* * Restore back old volume registers (unmute) */ @@ -367,7 +364,7 @@ ad1848_mixer_get (ad1848_info * devc, int dev) { if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; + return -(EINVAL); return devc->levels[dev]; } @@ -401,13 +398,13 @@ right = mix_cvt[right]; if (dev > 31) - return -EINVAL; + return -(EINVAL); if (!(devc->supported_devices & (1 << dev))) - return -EINVAL; + return -(EINVAL); if (mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; + return -(EINVAL); devc->levels[dev] = retvol; @@ -442,10 +439,12 @@ { int i; - switch (devc->mode) + switch (devc->model) { case MD_4231: case MD_4231A: + case MD_C930: + case MD_IWAVE: case MD_1845: devc->supported_devices = MODE2_MIXER_DEVICES; break; @@ -469,16 +468,7 @@ static int ad1848_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { - ad1848_info *devc; - - int codec_dev = mixer2codec[dev]; - - if (!codec_dev) - return -ENXIO; - - codec_dev--; - - devc = (ad1848_info *) audio_devs[codec_dev]->devc; + ad1848_info *devc = mixer_devs[dev]->devc; if (((cmd >> 8) & 0xff) == 'M') { @@ -524,107 +514,16 @@ } } else - return -EINVAL; + return -(EINVAL); } -static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] = -{ - { - "Generic AD1848 codec", - DMA_AUTOMODE, - AFMT_U8, /* Will be set later */ - NULL, - ad1848_open, - ad1848_close, - ad1848_output_block, - ad1848_start_input, - ad1848_ioctl, - ad1848_prepare_for_IO, - ad1848_prepare_for_IO, - ad1848_reset, - ad1848_halt, - NULL, - NULL, - ad1848_halt_input, - ad1848_halt_output, - ad1848_trigger - }}; - -static struct mixer_operations ad1848_mixer_operations = -{ - "AD1848/CS4248/CS4231", - ad1848_mixer_ioctl -}; - static int -ad1848_open (int dev, int mode) +ad1848_set_speed (int dev, int arg) { - ad1848_info *devc = NULL; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (ad1848_info *) audio_devs[dev]->devc; - - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - printk ("ad1848: Already opened\n"); - return -EBUSY; - } - - - devc->dual_dma = 0; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - devc->dual_dma = 1; - } - - devc->intr_active = 0; - devc->opened = 1; - devc->irq_mode = 0; - ad1848_trigger (dev, 0); - restore_flags (flags); -/* - * Mute output until the playback really starts. This decreases clicking (hope so). - */ - ad_mute (devc); - - return 0; -} - -static void -ad1848_close (int dev) -{ - unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - DEB (printk ("ad1848_close(void)\n")); - - save_flags (flags); - cli (); - - devc->intr_active = 0; - ad1848_reset (dev); - - - devc->opened = 0; - devc->irq_mode = 0; - - ad_unmute (devc); - restore_flags (flags); -} - -static int -set_speed (ad1848_info * devc, int arg) -{ /* - * The sampling speed is encoded in the least significant nibble of I8. The + * The sampling speed is encoded in the least significant nible of I8. The * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other * three bits select the divisor (indirectly): * @@ -632,10 +531,10 @@ * the increasing order. */ typedef struct - { - int speed; - unsigned char bits; - } + { + int speed; + unsigned char bits; + } speed_struct; static speed_struct speed_table[] = @@ -661,7 +560,10 @@ n = sizeof (speed_table) / sizeof (speed_struct); - if (devc->mode == MD_1845) /* AD1845 has different timer than others */ + if (arg == 0) + return devc->speed; + + if (devc->model == MD_1845) /* AD1845 has different timer than others */ { if (arg < 4000) arg = 4000; @@ -705,9 +607,11 @@ return devc->speed; } -static int -set_channels (ad1848_info * devc, int arg) +static short +ad1848_set_channels (int dev, short arg) { + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + if (arg != 1 && arg != 2) return devc->channels; @@ -715,15 +619,16 @@ return arg; } -static int -set_format (ad1848_info * devc, int arg) +static unsigned int +ad1848_set_bits (int dev, unsigned int arg) { + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; static struct format_tbl - { - int format; - unsigned char bits; - } + { + int format; + unsigned char bits; + } format2bits[] = { { @@ -768,7 +673,10 @@ }; int i, n = sizeof (format2bits) / sizeof (struct format_tbl); - if (!(arg & ad_format_mask[devc->mode])) + if (arg == 0) + return devc->audio_format; + + if (!(arg & ad_format_mask[devc->model])) arg = AFMT_U8; devc->audio_format = arg; @@ -787,51 +695,100 @@ return devc->audio_format = AFMT_U8; } +static struct audio_driver ad1848_audio_driver = +{ + ad1848_open, + ad1848_close, + ad1848_output_block, + ad1848_start_input, + ad1848_ioctl, + ad1848_prepare_for_IO, + ad1848_prepare_for_output, + ad1848_reset, + ad1848_halt, + NULL, + NULL, + ad1848_halt_input, + ad1848_halt_output, + ad1848_trigger, + ad1848_set_speed, + ad1848_set_bits, + ad1848_set_channels +}; + +static struct mixer_operations ad1848_mixer_operations = +{ + "SOUNDPORT", + "AD1848/CS4248/CS4231", + ad1848_mixer_ioctl +}; + static int -ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +ad1848_open (int dev, int mode) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_info *devc = NULL; + unsigned long flags; + + if (dev < 0 || dev >= num_audiodevs) + return -(ENXIO); + + devc = (ad1848_info *) audio_devs[dev]->devc; + - switch (cmd) + save_flags (flags); + cli (); + if (devc->opened) { - case SOUND_PCM_WRITE_RATE: - if (local) - return set_speed (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_RATE: - if (local) - return devc->speed; - return snd_ioctl_return ((int *) arg, devc->speed); - - case SNDCTL_DSP_STEREO: - if (local) - return set_channels (devc, (int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1); - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return set_channels (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_CHANNELS: - if (local) - return devc->channels; - return snd_ioctl_return ((int *) arg, devc->channels); - - case SNDCTL_DSP_SAMPLESIZE: - if (local) - return set_format (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_BITS: - if (local) - return devc->audio_format; - return snd_ioctl_return ((int *) arg, devc->audio_format); + restore_flags (flags); + return -(EBUSY); + } - default:; + devc->dual_dma = 0; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { + devc->dual_dma = 1; } - return -EINVAL; + + devc->intr_active = 0; + devc->opened = 1; + devc->audio_mode = 0; + ad1848_trigger (dev, 0); + restore_flags (flags); +/* + * Mute output until the playback really starts. This decreases clicking (hope so). + */ + ad_mute (devc); + + return 0; +} + +static void +ad1848_close (int dev) +{ + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + DEB (printk ("ad1848_close(void)\n")); + + save_flags (flags); + cli (); + + devc->intr_active = 0; + ad1848_reset (dev); + + + devc->opened = 0; + devc->audio_mode = 0; + + ad_unmute (devc); + restore_flags (flags); +} + +static int +ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +{ + return -(EINVAL); } static void @@ -840,6 +797,9 @@ unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + if (!dma_restart) + return; + cnt = count; if (devc->audio_format == AFMT_IMA_ADPCM) @@ -855,11 +815,11 @@ cnt >>= 1; cnt--; - if (devc->irq_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == devc->xfer_count) { - devc->irq_mode |= PCM_ENABLE_OUTPUT; + devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; return; /* * Auto DMA mode on. No need to react @@ -868,20 +828,16 @@ save_flags (flags); cli (); - if (dma_restart) - { - ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Playback disable */ - /* ad1848_halt (dev); */ - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - } + /* ad_write (devc, 9, ad_read (devc, 9) & ~ 0x01); / * Playback disable */ + ad1848_halt (dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - ad_unmute (devc); devc->xfer_count = cnt; - devc->irq_mode |= PCM_ENABLE_OUTPUT; + devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; restore_flags (flags); } @@ -892,6 +848,9 @@ unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + if (!dma_restart) + return; + cnt = count; if (devc->audio_format == AFMT_IMA_ADPCM) { @@ -906,11 +865,11 @@ cnt >>= 1; cnt--; - if (devc->irq_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == devc->xfer_count) { - devc->irq_mode |= PCM_ENABLE_INPUT; + devc->audio_mode |= PCM_ENABLE_INPUT; devc->intr_active = 1; return; /* * Auto DMA mode on. No need to react @@ -926,7 +885,7 @@ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); } - if (devc->mode == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */ + if (devc->model == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */ { ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); @@ -941,12 +900,22 @@ ad_unmute (devc); devc->xfer_count = cnt; - devc->irq_mode |= PCM_ENABLE_INPUT; + devc->audio_mode |= PCM_ENABLE_INPUT; devc->intr_active = 1; restore_flags (flags); } static int +ad1848_prepare_for_output (int dev, int bsize, int bcount) +{ + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + ad_mute (devc); + + return ad1848_prepare_for_IO (dev, bsize, bcount); +} + +static int ad1848_prepare_for_IO (int dev, int bsize, int bcount) { int timeout; @@ -954,7 +923,7 @@ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - if (devc->irq_mode) + if (devc->audio_mode) return 0; save_flags (flags); @@ -964,7 +933,7 @@ if (devc->channels > 1) fs |= 0x10; - if (devc->mode == MD_1845) /* Use alternate speed select registers */ + if (devc->model == MD_1845) /* Use alternate speed select registers */ { fs &= 0xf0; /* Mask off the rate select bits */ @@ -974,7 +943,7 @@ old_fs = ad_read (devc, 8); - if (devc->mode != MD_4232) + if (devc->model != MD_4232) if (fs == old_fs) /* No change */ { restore_flags (flags); @@ -984,7 +953,7 @@ ad_enter_MCE (devc); /* Enables changes to the format select reg */ - if (devc->mode == MD_4232) + if (devc->model == MD_4232) { tmp = ad_read (devc, 16); ad_write (devc, 16, tmp | 0x30); @@ -992,21 +961,21 @@ ad_write (devc, 8, fs); /* - * Write to I8 starts resynchronization. Wait until it completes. + * Write to I8 starts resyncronization. Wait until it completes. */ timeout = 10000; while (timeout > 0 && inb (devc->base) == 0x80) timeout--; /* - * If mode == 2 (CS4231), set I28 also. It's the capture format register. + * If mode >= 2 (CS4231), set I28 also. It's the capture format register. */ - if (devc->mode != MD_1848) + if (devc->model != MD_1848) { ad_write (devc, 28, fs); /* - * Write to I28 starts resynchronization. Wait until it completes. + * Write to I28 starts resyncronization. Wait until it completes. */ timeout = 10000; while (timeout > 0 && inb (devc->base) == 0x80) @@ -1014,7 +983,7 @@ } - if (devc->mode == MD_4232) + if (devc->model == MD_4232) ad_write (devc, 16, tmp & ~0x30); ad_leave_MCE (devc); /* @@ -1064,7 +1033,7 @@ ad_mute (devc); - if (devc->mode == MD_4232) /* Use applied black magic */ + if (devc->model == MD_4232) /* Use applied black magic */ { int tmout; @@ -1085,7 +1054,7 @@ outb (0, io_Status (devc)); /* Clear interrupt status */ outb (0, io_Status (devc)); /* Clear interrupt status */ - devc->irq_mode &= ~PCM_ENABLE_INPUT; + devc->audio_mode &= ~PCM_ENABLE_INPUT; restore_flags (flags); } @@ -1100,7 +1069,7 @@ cli (); ad_mute (devc); - if (devc->mode == MD_4232) /* Use applied black magic */ + if (devc->model == MD_4232) /* Use applied black magic */ { int tmout; @@ -1121,7 +1090,7 @@ outb (0, io_Status (devc)); /* Clear interrupt status */ outb (0, io_Status (devc)); /* Clear interrupt status */ - devc->irq_mode &= ~PCM_ENABLE_OUTPUT; + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; restore_flags (flags); } @@ -1131,35 +1100,62 @@ { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; unsigned long flags; - unsigned char tmp; + unsigned char tmp, old; save_flags (flags); cli (); - state &= devc->irq_mode; + state &= devc->audio_mode; - tmp = ad_read (devc, 9) & ~0x03; + tmp = (old = ad_read (devc, 9)) & ~0x03; if (state & PCM_ENABLE_INPUT) tmp |= 0x02; if (state & PCM_ENABLE_OUTPUT) tmp |= 0x01; + + if (!(state & PCM_ENABLE_OUTPUT) && old & 0x01); + ad_mute (devc); + ad_write (devc, 9, tmp); + if (state & PCM_ENABLE_OUTPUT && !(old & 0x01)); + ad_unmute (devc); + restore_flags (flags); } int ad1848_detect (int io_base, int *ad_flags, int *osp) { + /* + * Initial values for the indirect registers of CS4248/AD1848. + */ + static int init_values[] = + { + 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, + + /* Positions 16 to 31 just for CS4231/2 and ad1845 */ + 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; unsigned char tmp; ad1848_info *devc = &dev_info[nr_ad1848_devs]; unsigned char tmp1 = 0xff, tmp2 = 0xff; + int optiC930 = 0; /* OPTi 82C930 flag */ + int interwave = 0; + int ad1847_flag = 0; + int i; DDB (printk ("ad1848_detect(%x)\n", io_base)); if (ad_flags) - *ad_flags = 0; + { + if (*ad_flags == 0x12345678) + interwave = 1; + *ad_flags = 0; + } if (nr_ad1848_devs >= MAX_AUDIO_DEV) { @@ -1179,7 +1175,7 @@ devc->irq = 0; devc->opened = 0; devc->chip_name = "AD1848"; - devc->mode = MD_1848; /* AD1848 or CS4248 */ + devc->model = MD_1848; /* AD1848 or CS4248 */ devc->osp = osp; devc->debug_flag = 0; @@ -1187,7 +1183,7 @@ * Check that the I/O address is in use. * * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power-on initialization. Just assume + * chip has performed it's power on initialization. Just assume * this has happened before the OS is starting. * * If the I/O address is unused, it typically returns 0xff. @@ -1217,23 +1213,29 @@ ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) - { - DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); - return 0; - } + if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); + return 0; + } DDB (printk ("ad1848_detect() - step C\n")); ad_write (devc, 0, 0x45); ad_write (devc, 1, 0xaa); if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) - { - DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); - return 0; - } + if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); + return 0; + } /* - * The indirect register I12 has some read only bits. Let's + * The indirect register I12 has some read only bits. Lets * try to change them. */ @@ -1259,6 +1261,22 @@ * with CS4231. */ +/* + * OPTi 82C930 has mode2 control bit in another place. This test will fail + * with it. Accept this situation as a possible indication of this chip. + */ + + DDB (printk ("ad1848_detect() - step F\n")); + ad_write (devc, 12, 0); /* Mode2=disabled */ + + for (i = 0; i < 16; i++) + if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) + { + DDB (printk ("ad1848 detect step F(%d/%x/%x) - OPTi chip?\n", i, tmp1, tmp2)); + if (!ad1847_flag) + optiC930 = 1; + break; + } /* * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). @@ -1277,7 +1295,7 @@ devc->chip_name = "CS4248"; /* Our best knowledge just now */ } - if ((tmp1 & 0xc0) == (0x80 | 0x40)) + if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) { /* * CS4231 detected - is it? @@ -1314,7 +1332,7 @@ */ devc->chip_name = "CS4231"; - devc->mode = MD_4231; + devc->model = MD_4231; /* * It could be an AD1845 or CS4231A as well. @@ -1330,17 +1348,17 @@ case 0xa0: devc->chip_name = "CS4231A"; - devc->mode = MD_4231A; + devc->model = MD_4231A; break; case 0xa2: devc->chip_name = "CS4232"; - devc->mode = MD_4232; + devc->model = MD_4232; break; case 0xb2: devc->chip_name = "CS4232A"; - devc->mode = MD_4232; + devc->model = MD_4232; break; case 0x80: @@ -1358,15 +1376,28 @@ if (ad_read (devc, 23) != tmp) /* AD1845 ? */ { devc->chip_name = "AD1845"; - devc->mode = MD_1845; + devc->model = MD_1845; + } + else if (interwave) + { + devc->model = MD_IWAVE; + devc->chip_name = "IWave"; } ad_write (devc, 23, tmp); /* Restore */ } break; - default: /* Assume CS4231 */ - devc->mode = MD_4231; + default: /* Assume CS4231 or OPTi 82C930 */ + if (optiC930) + { + devc->chip_name = "82C930"; + devc->model = MD_C930; + } + else + { + devc->model = MD_4231; + } } } @@ -1379,11 +1410,32 @@ DDB (printk ("ad1848_detect() - step L\n")); if (ad_flags) { - if (devc->mode != MD_1848) + if (devc->model != MD_1848) *ad_flags |= AD_F_CS4231; } DDB (printk ("ad1848_detect() - Detected OK\n")); + + if (devc->model == MD_1848 && ad1847_flag) + devc->chip_name = "AD1847"; + + for (i = 0; i < 16; i++) + ad_write (devc, i, init_values[i]); + + ad_mute (devc); /* Initialize some variables */ + ad_unmute (devc); /* Leave it unmuted now */ + + if (devc->model > MD_1848) + { + ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ + + if (devc->model == MD_IWAVE) + ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + + for (i = 16; i < 32; i++) + ad_write (devc, i, init_values[i]); + } + return 1; } @@ -1396,24 +1448,14 @@ * The actually used IRQ is ABS(irq). */ - /* - * Initial values for the indirect registers of CS4248/AD1848. - */ - static int init_values[] = - { - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, - /* Positions 16 to 31 just for CS4231 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - int i, my_dev; + int my_dev; + char dev_name[100]; ad1848_info *devc = &dev_info[nr_ad1848_devs]; - if (!ad1848_detect (io_base, NULL, osp)) - return; + int audio_flags = DMA_AUTOMODE; + request_region (devc->base, 4, devc->chip_name); @@ -1422,141 +1464,129 @@ devc->timer_ticks = 0; devc->osp = osp; - if (nr_ad1848_devs != 0) - { - memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs], - (char *) &ad1848_pcm_operations[0], - sizeof (struct audio_operations)); - } - - for (i = 0; i < 16; i++) - ad_write (devc, i, init_values[i]); - - ad_mute (devc); /* Initialize some variables */ - ad_unmute (devc); /* Leave it unmuted now */ - - if (devc->mode > MD_1848) + if (devc->model > MD_1848) { if (dma_capture == dma_playback || dma_capture == -1 || dma_playback == -1) { ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ - ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX; + audio_flags &= ~DMA_DUPLEX; } else { ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */ - ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_DUPLEX; + audio_flags |= DMA_DUPLEX; } - ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ - for (i = 16; i < 32; i++) - ad_write (devc, i, init_values[i]); - - - if (devc->mode == MD_1845) + if (devc->model == MD_1845) ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */ + + if (devc->model == MD_IWAVE) + { /* Some magic Interwave spesific initialization */ + ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + ad_write (devc, 17, 0xc2); /* Alternate feature enable */ + } } else { - ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX; + audio_flags &= ~DMA_DUPLEX; ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ } outb (0, io_Status (devc)); /* Clear pending interrupts */ if (name != NULL && name[0] != 0) - sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + sprintf (dev_name, "%s (%s)", name, devc->chip_name); else - sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + sprintf (dev_name, "Generic audio codec (%s)", devc->chip_name); - conf_printf2 (ad1848_pcm_operations[nr_ad1848_devs].name, + conf_printf2 (dev_name, devc->base, devc->irq, dma_playback, dma_capture); - if (num_audiodevs < MAX_AUDIO_DEV) + if (devc->model == MD_1848) + audio_flags |= DMA_HARDSTOP; + + if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, + dev_name, + &ad1848_audio_driver, + sizeof (struct audio_driver), + audio_flags, + ad_format_mask[devc->model], + devc, + dma_playback, + dma_capture)) < 0) + { + return; + } + + if (irq > 0) { - audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs]; - if (irq > 0) + irq2dev[irq] = devc->dev_no = my_dev; + if (snd_set_irq_handler (devc->irq, ad1848_interrupt, + "SoundPort", + devc->osp) < 0) { - audio_devs[my_dev]->devc = devc; - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler (devc->irq, ad1848_interrupt, - audio_devs[my_dev]->name, - devc->osp) < 0) - { - printk ("ad1848: IRQ in use\n"); - } + printk ("ad1848: IRQ in use\n"); + } -#ifdef NO_IRQ_TEST - if (devc->mode != MD_1848) - { - int x; - unsigned char tmp = ad_read (devc, 16); + if (devc->model != MD_1848) + { + int x; + unsigned char tmp = ad_read (devc, 16); - devc->timer_ticks = 0; + devc->timer_ticks = 0; - ad_write (devc, 21, 0x00); /* Timer msb */ - ad_write (devc, 20, 0x10); /* Timer lsb */ + ad_write (devc, 21, 0x00); /* Timer msb */ + ad_write (devc, 20, 0x10); /* Timer lsb */ - ad_write (devc, 16, tmp | 0x40); /* Enable timer */ - for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); - ad_write (devc, 16, tmp & ~0x40); /* Disable timer */ - - if (devc->timer_ticks == 0) - printk ("[IRQ conflict???]"); - else - devc->irq_ok = 1; + ad_write (devc, 16, tmp | 0x40); /* Enable timer */ + for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); + ad_write (devc, 16, tmp & ~0x40); /* Disable timer */ - } + if (devc->timer_ticks == 0) + printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ -#else - devc->irq_ok = 1; -#endif + devc->irq_ok = 1; } - else if (irq < 0) - irq2dev[-irq] = devc->dev_no = my_dev; - - audio_devs[my_dev]->dmachan1 = dma_playback; - audio_devs[my_dev]->dmachan2 = dma_capture; - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - audio_devs[my_dev]->devc = devc; - audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode]; - nr_ad1848_devs++; + else + devc->irq_ok = 1; /* Couldn't test. assume it's OK */ + } + else if (irq < 0) + irq2dev[-irq] = devc->dev_no = my_dev; + nr_ad1848_devs++; #ifdef CONFIG_SEQUENCER - if (devc->mode != MD_1848 && devc->mode != MD_1845 && devc->irq_ok) - ad1848_tmr_install (my_dev); + if (devc->model != MD_1848 && devc->model != MD_1845 && devc->irq_ok) + ad1848_tmr_install (my_dev); #endif - if (!share_dma) - { - if (sound_alloc_dma (dma_playback, "Sound System")) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma (dma_capture, "Sound System (capture)")) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture); - } + if (!share_dma) + { + if (sound_alloc_dma (dma_playback, "Sound System")) + printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback); - /* - * Toggle the MCE bit. It completes the initialization phase. - */ + if (dma_capture != dma_playback) + if (sound_alloc_dma (dma_capture, "Sound System (capture)")) + printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture); + } - ad_enter_MCE (devc); /* In case the bit was off */ - ad_leave_MCE (devc); + /* + * Toggle the MCE bit. It completes the initialization phase. + */ - if (num_mixers < MAX_MIXER_DEV) - { - mixer2codec[num_mixers] = my_dev + 1; - audio_devs[my_dev]->mixer_dev = num_mixers; - mixer_devs[num_mixers++] = &ad1848_mixer_operations; - ad1848_mixer_reset (devc); - } + ad_enter_MCE (devc); /* In case the bit was off */ + ad_leave_MCE (devc); + ad1848_mixer_reset (devc); + + if (sound_install_mixer (MIXER_DRIVER_VERSION, + dev_name, + &ad1848_mixer_operations, + sizeof (struct mixer_operations), + devc) >= 0) + { + audio_devs[my_dev]->mixer_dev = num_mixers - 1; } - else - printk ("AD1848: Too many PCM devices available\n"); } void @@ -1588,7 +1618,7 @@ } } else - printk ("ad1848: Can't find device to be unloaded. Base=%x\n", + printk ("ad1848: Can't find device to be undoaded. Base=%x\n", io_base); } @@ -1633,21 +1663,21 @@ if (status & 0x01) { - if (devc->mode != MD_1848) + if (devc->model != MD_1848) alt_stat = ad_read (devc, 24); - if (devc->opened && devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) + if (devc->opened && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) { DMAbuf_inputintr (dev); } - if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT && + if (devc->opened && devc->audio_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10) { DMAbuf_outputintr (dev, 1); } - if (devc->mode != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ { devc->timer_ticks++; #ifdef CONFIG_SEQUENCER @@ -1657,7 +1687,7 @@ } } - if (devc->mode != MD_1848) + if (devc->model != MD_1848) ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat); /* Selective ack */ else outb (0, io_Status (devc)); /* Clear interrupt status */ @@ -1681,11 +1711,220 @@ if (!opl3_detect (base, hw_config->osp)) return; - opl3_init (0, base, hw_config->osp); + opl3_init (base, hw_config->osp); request_region (base, 4, "OPL3/OPL2"); #endif } +#ifdef DESKPROXL +/* + * Very experimental initialization sequence for the integrated sound system + * of Compaq Deskpro XL. Will be moved somewhere else in future. + */ + +static int +init_deskpro (struct address_info *hw_config) +{ + unsigned char tmp; + + if ((tmp = inb (0xc44)) == 0xff) + { + DDB (printk ("init_deskpro: Dead port 0xc44\n")); + return 0; + } + + outb (tmp | 0x04, 0xc44); /* Select bank 1 */ + if (inb (0xc44) != 0x04) + { + DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n")); + return 0; + } + +/* + * OK. It looks like a Deskpro so let's proceed. + */ + +/* + * I/O port 0xc44 Audio configuration register. + * + * bits 0xc0: Audio revision bits + * 0x00 = Compaq Business Audio + * 0x40 = MS Sound System Compatible (reset default) + * 0x80 = Reserved + * 0xc0 = Reserved + * bit 0x20: No Wait State Enable + * 0x00 = Disabled (reset default, DMA mode) + * 0x20 = Enabled (programmed I/O mode) + * bit 0x10: MS Sound System Decode Enable + * 0x00 = Decoding disabled (reset default) + * 0x10 = Decoding enabled + * bit 0x08: FM Synthesis Decode Enable + * 0x00 = Decoding Disabled (reset default) + * 0x08 = Decoding enabled + * bit 0x04 Bank select + * 0x00 = Bank 0 + * 0x04 = Bank 1 + * bits 0x03 MSS Base address + * 0x00 = 0x530 (reset default) + * 0x01 = 0x604 + * 0x02 = 0xf40 + * 0x03 = 0xe80 + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc44 (before): "); + outb (tmp & ~0x04, 0xc44); + printk ("%02x ", inb (0xc44)); + outb (tmp | 0x04, 0xc44); + printk ("%02x\n", inb (0xc44)); +#endif + + /* Set bank 1 of the register */ + tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ + + switch (hw_config->io_base) + { + case 0x530: + tmp |= 0x00; + break; + case 0x604: + tmp |= 0x01; + break; + case 0xf40: + tmp |= 0x02; + break; + case 0xe80: + tmp |= 0x03; + break; + default: + DDB (printk ("init_deskpro: Invalid MSS port %x\n", + hw_config->io_base)); + return 0; + } + outb (tmp & ~0x04, 0xc44); /* Write to bank=0 */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc44 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc44)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc44)); +#endif + +/* + * I/O port 0xc45 FM Address Decode/MSS ID Register. + * + * bank=0, bits 0xfe: FM synthesis Decode Comare bits 7:1 (default=0x88) + * bank=0, bit 0x01: SBIC Power Control Bit + * 0x00 = Powered up + * 0x01 = Powered down + * bank=1, bits 0xfc: MSS ID (default=0x40) + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc45 (before): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc45)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc45)); +#endif + + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + outb (0x88, 0xc45); /* FM base 7:0 = 0x88 */ + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + outb (0x10, 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc45 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc45)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc45)); +#endif + + +/* + * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. + * + * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) + * bank=1, bits 0xff: Audio addressing ASIC id + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc46 (before): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc46)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc46)); +#endif + + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + outb (0x03, 0xc46); /* FM base 15:8 = 0x03 */ + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + outb (0x11, 0xc46); /* ASIC ID = 0x11 */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc46 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc46)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc46)); +#endif + +/* + * I/O port 0xc47 FM Address Decode Register. + * + * bank=0, bits 0xff: Decode enble selection for various FM address bits + * bank=1, bits 0xff: Reserved + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc47 (before): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc47)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc47)); +#endif + + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + outb (0x7c, 0xc47); /* FM decode enable bits = 0x7c */ + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + outb (0x00, 0xc47); /* Reserved bank1 = 0x00 */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc47 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc47)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc47)); +#endif + +/* + * I/O port 0xc6f = Audio Disable Function Register + */ + +#ifdef DEBUGXL + printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f)); +#endif + + outb (0x80, 0xc6f); + +#ifdef DEBUGXL + printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f)); +#endif + + return 1; +} +#endif + int probe_ms_sound (struct address_info *hw_config) { @@ -1705,9 +1944,17 @@ return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); } +#ifdef DESKPROXL + if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ + { + if (!init_deskpro (hw_config)) + return 0; + } +#endif + /* * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTriX Pro for example) + * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00 or 0x0f. */ @@ -1720,6 +1967,7 @@ return 0; return 1; } + DDB (printk ("MSS signature = %x\n", tmp & 0x3f)); if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x0f && (tmp & 0x3f) != 0x00) @@ -1766,14 +2014,15 @@ return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); } -long -attach_ms_sound (long mem_start, struct address_info *hw_config) +void +attach_ms_sound (struct address_info *hw_config) { static char interrupt_bits[12] = { -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 }; - char bits; + char bits, dma2_bit = 0; + int ad_flags = 0; static char dma_bits[4] = { @@ -1782,9 +2031,11 @@ int config_port = hw_config->io_base + 0; int version_port = hw_config->io_base + 3; + int dma = hw_config->dma; + int dma2 = hw_config->dma2; - if (!ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)) - return mem_start; + if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, hw_config->osp)) + return; if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ { @@ -1793,7 +2044,7 @@ hw_config->dma, hw_config->dma2, 0, hw_config->osp); request_region (hw_config->io_base, 4, "WSS config"); - return mem_start; + return; } /* @@ -1802,20 +2053,51 @@ bits = interrupt_bits[hw_config->irq]; if (bits == -1) - return mem_start; + return; outb (bits | 0x40, config_port); if ((inb (version_port) & 0x40) == 0) printk ("[IRQ Conflict?]"); - outb (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ +/* + * Handle the capture DMA channel + */ + + if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) + { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } + else + { + printk ("MSS: Invalid capture DMA\n"); + dma2 = dma; + } + } + else + dma2 = dma; - ad1848_init ("MS Sound System", hw_config->io_base + 4, + outb (bits | dma_bits[dma] | dma2_bit, config_port); /* Write IRQ+DMA setup */ + + ad1848_init ("MSS audio codec", hw_config->io_base + 4, hw_config->irq, - hw_config->dma, - hw_config->dma, 0, hw_config->osp); + dma, + dma2, 0, + hw_config->osp); request_region (hw_config->io_base, 4, "WSS config"); - return mem_start; } void @@ -1838,15 +2120,14 @@ return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); } -long -attach_pnp_ad1848 (long mem_start, struct address_info *hw_config) +void +attach_pnp_ad1848 (struct address_info *hw_config) { ad1848_init (hw_config->name, hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma2, 0, hw_config->osp); - return mem_start; } void @@ -1871,7 +2152,7 @@ { unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long xtal_nsecs; /* nanoseconds per xtal oscillator tick */ + unsigned long xtal_nsecs; /* nanoseconds per xtal oscillaror tick */ unsigned long divider; save_flags (flags); @@ -1888,7 +2169,7 @@ * the timer divider. */ - if (devc->mode == MD_1845) + if (devc->model == MD_1845) xtal_nsecs = 10050; else if (ad_read (devc, 8) & 0x01) xtal_nsecs = 9920; diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h --- v2.0.0/linux/drivers/sound/ad1848_mixer.h Sun Mar 24 22:49:40 1996 +++ linux/drivers/sound/ad1848_mixer.h Sun Jun 30 11:43:36 1996 @@ -5,27 +5,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ diff -u --recursive --new-file v2.0.0/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.0.0/linux/drivers/sound/adlib_card.c Sun Mar 24 22:49:51 1996 +++ linux/drivers/sound/adlib_card.c Sun Jun 30 11:43:48 1996 @@ -5,27 +5,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -34,14 +18,12 @@ #if defined(CONFIG_YM3812) -long -attach_adlib_card (long mem_start, struct address_info *hw_config) +void +attach_adlib_card (struct address_info *hw_config) { - mem_start = opl3_init (mem_start, hw_config->io_base, hw_config->osp); + opl3_init (hw_config->io_base, hw_config->osp); request_region (hw_config->io_base, 4, "OPL3/OPL2"); - - return mem_start; } int diff -u --recursive --new-file v2.0.0/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c --- v2.0.0/linux/drivers/sound/aedsp16.c Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/aedsp16.c Sun Jun 30 11:43:49 1996 @@ -170,7 +170,7 @@ I think the request regions should be done this way: if (check_region(...)) - return ERR; // I/O region already reserved + return ERR; // I/O region alredy reserved device_probe(...); device_attach(...); request_region(...); // reserve only when we are sure all is okay @@ -178,12 +178,12 @@ Request the 2x0h region in any case if we are using this card. NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region - (see code) does not mean necessarily that we are emulating sbpro. + (see code) does not mean necessarly that we are emulating sbpro. It mean that the region is the sbpro I/O ports region. We use this region to access the control registers of the card, and if emulating sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro registers are not used, in no way, to emulate an sbpro: they are - used only for configuration purposes. + used only for configuration pourposes. Someone pointed out that should be possible use both the SBPRO and MSS modes because the sound card have all the two chipsets, supposing that @@ -222,7 +222,7 @@ one sound card of the emulated type (read the NOTES above) - Moved the sb init routine from the attach to the very first probe in sb_card.c - - Rearrangements and cleanups + - Rearrangemens and cleanups - Wiped out some unnecessary code and variables: this is kernel code so it is better save some TEXT and DATA - Fixed the request_region code. We must allocate the aedsp16 (sbpro) @@ -263,7 +263,7 @@ #define CMD6 0x8c /* Enable Microsoft Sound System mode */ /* - * Offsets of AEDSP16 DSP I/O ports. The offset is added to portbase + * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase * to have the actual I/O port. * Register permissions are: * (wo) == Write Only @@ -516,7 +516,7 @@ if ((ret = ReadData (port)) == -1) return -1; /* - * We already know how many int are stored (2), so we know when the + * We alredy know how many int are stored (2), so we know when the * string is finished. */ ver[len++] = ret; @@ -536,7 +536,7 @@ { if ((ret = ReadData (port)) == -1) /* - * If no more data available, return to the caller, no error if len>0. + * If no more data availabe, return to the caller, no error if len>0. * We have no other way to know when the string is finished. */ return (len ? 0 : -1); @@ -666,7 +666,7 @@ InitAEDSP16_SBPRO (struct address_info *hw_config) { /* - * If the card is already init'ed MSS, we can not init it to SBPRO too + * If the card is alredy init'ed MSS, we can not init it to SBPRO too * because the board can not emulate simultaneously MSS and SBPRO. */ if (ae_init & INIT_MSS) @@ -683,7 +683,7 @@ { if (check_region (hw_config->io_base, 0x0f)) { - printk ("AEDSP16/SBPRO I/O port region is already in use.\n"); + printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n"); return -1; } } @@ -721,7 +721,7 @@ InitAEDSP16_MSS (struct address_info *hw_config) { /* - * If the card is already init'ed SBPRO, we can not init it to MSS too + * If the card is alredy init'ed SBPRO, we can not init it to MSS too * because the board can not emulate simultaneously MSS and SBPRO. */ if (ae_init & INIT_SBPRO) @@ -736,7 +736,7 @@ */ if (check_region (hw_config->io_base, 0x08)) { - printk ("MSS I/O port region is already in use.\n"); + printk ("MSS I/O port region is alredy in use.\n"); return -1; } @@ -748,7 +748,7 @@ { if (check_region (AEDSP16_BASE, 0x0f)) { - printk ("AEDSP16 I/O port region is already in use.\n"); + printk ("AEDSP16 I/O port region is alredy in use.\n"); return -1; } } @@ -801,7 +801,7 @@ */ if (check_region (hw_config->io_base, 0x02)) { - printk ("SB I/O port region is already in use.\n"); + printk ("SB I/O port region is alredy in use.\n"); return -1; } @@ -813,7 +813,7 @@ { if (check_region (AEDSP16_BASE, 0x0f)) { - printk ("AEDSP16 I/O port region is already in use.\n"); + printk ("AEDSP16 I/O port region is alredy in use.\n"); return -1; } } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.0.0/linux/drivers/sound/audio.c Mon Mar 25 09:25:26 1996 +++ linux/drivers/sound/audio.c Sun Jun 30 11:43:50 1996 @@ -5,27 +5,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -51,7 +35,7 @@ static int local_conversion[MAX_AUDIO_DEV]; static int -set_format (int dev, long fmt) +set_format (int dev, int fmt) { if (fmt != AFMT_QUERY) { @@ -80,7 +64,7 @@ audio_open (int dev, struct fileinfo *file) { int ret; - long bits; + int bits; int dev_type = dev & 0x0f; int mode = file->mode & O_ACCMODE; @@ -108,8 +92,9 @@ if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1) != bits) { + printk ("audio: Can't set number of bits on device %d\n", dev); audio_release (dev, file); - return -ENXIO; + return -(ENXIO); } if (dev_type == SND_DEV_AUDIO) @@ -143,7 +128,7 @@ p = dmap->qtail; - for (i = dmap->qlen; i < dmap->nbufs; i++) + for (i = dmap->qlen + 1; i < dmap->nbufs; i++) { memset (dmap->raw_buf + p * dmap->fragment_size, dmap->neutral_byte, @@ -240,7 +225,7 @@ dev_nblock[dev])) < 0) { /* Handle nonblocking mode */ - if (dev_nblock[dev] && buf_no == -EAGAIN) + if (dev_nblock[dev] && buf_no == -(EAGAIN)) return p; /* No more space. Return # of accepted bytes */ return buf_no; } @@ -251,15 +236,15 @@ if (l > (buf_size - buf_ptr)) l = (buf_size - buf_ptr); - if (!audio_devs[dev]->copy_from_user) + if (!audio_devs[dev]->d->copy_from_user) { /* * No device specific copy routine */ - memcpy_fromfs (&dma_buf[buf_ptr], &((buf)[p]), l); + memcpy_fromfs (&dma_buf[buf_ptr], &(buf)[p], l); } else - audio_devs[dev]->copy_from_user (dev, - dma_buf, buf_ptr, buf, p, l); + audio_devs[dev]->d->copy_from_user (dev, + dma_buf, buf_ptr, buf, p, l); if (local_conversion[dev] == AFMT_MU_LAW) { @@ -318,7 +303,7 @@ { /* Nonblocking mode handling. Return current # of bytes */ - if (dev_nblock[dev] && buf_no == -EAGAIN) + if (dev_nblock[dev] && buf_no == -(EAGAIN)) return p; return buf_no; @@ -341,7 +326,7 @@ translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l); } - memcpy_tofs (&((buf)[p]), dmabuf, l); + memcpy_tofs (&(buf)[p], dmabuf, l); DMAbuf_rmchars (dev, buf_no, l); @@ -366,17 +351,22 @@ else printk ("/dev/dsp%d: No coprocessor for this device\n", dev); - return -ENXIO; + return -(ENXIO); } else switch (cmd) { case SNDCTL_DSP_SYNC: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + sync_output (dev); return DMAbuf_ioctl (dev, cmd, arg, 0); break; case SNDCTL_DSP_POST: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; sync_output (dev); return 0; break; @@ -394,8 +384,10 @@ return snd_ioctl_return ((int *) arg, set_format (dev, get_fs_long ((long *) arg))); 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; + return -(EBUSY); { audio_buf_info info; @@ -405,13 +397,15 @@ if (err < 0) return err; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; } case SNDCTL_DSP_GETOSPACE: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; + return -(EBUSY); { audio_buf_info info; @@ -426,7 +420,7 @@ if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) info.bytes += buf_size - buf_ptr; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; } @@ -445,15 +439,15 @@ if (audio_devs[dev]->coproc) info |= DSP_CAP_COPROC; - if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ info |= DSP_CAP_BATCH; - if (audio_devs[dev]->trigger) /* Supports SETTRIGGER */ + if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ info |= DSP_CAP_TRIGGER; info |= DSP_CAP_MMAP; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; } break; @@ -463,13 +457,12 @@ } } -long -audio_init (long mem_start) +void +audio_init (void) { /* * NOTE! This routine could be called several times during boot. */ - return mem_start; } int diff -u --recursive --new-file v2.0.0/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v2.0.0/linux/drivers/sound/configure.c Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/configure.c Sun Jun 30 11:43:52 1996 @@ -8,27 +8,11 @@ * sound/configure.c - Configuration program for the Linux Sound Driver */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ @@ -83,14 +67,17 @@ #define AUDIO_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | \ B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \ B (OPT_SSCAPE)| B(OPT_MAD16) | B(OPT_CS4232)) -#define MIDI_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \ +#define MPU_DEVS (B(OPT_PSS)|\ + B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)) +#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SSCAPE)) +#define MIDI_CARDS (MPU_DEVS | UART401_DEVS | \ + B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \ B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16) | \ B (OPT_CS4232)|B(OPT_MAUI)) -#define MPU_DEVS (B(OPT_PSS)|B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|\ - B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)) #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\ B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\ B(OPT_SPNP)) +#define SBDSP_DEVS (B(OPT_SB)|B(OPT_SPNP)|B(OPT_MAD16)) #define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS) /* * Options that have been disabled for some reason (incompletely implemented @@ -171,7 +158,7 @@ "GUS MAX support", "Microsoft Sound System support", "Ensoniq Soundscape support", - "MediaTriX AudioTriX Pro support", + "MediaTrix AudioTrix Pro support", "Support for MAD16 and/or Mozart based cards", "Support for Crystal CS4232 based (PnP) cards", "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers", @@ -235,7 +222,7 @@ "Soundscape chipset. Such cards are being manufactured by Ensoniq,\n" "Spea and Reveal (Reveal makes other cards as well).\n", - "Enable this option if you have the AudioTriX Pro sound card\n" + "Enable this option if you have the AudioTrix Pro sound card\n" "manufactured by MediaTrix.\n", "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n" @@ -294,6 +281,14 @@ } , { + "SBDSP", SBDSP_DEVS + } + , + { + "UART401", UART401_DEVS + } + , + { "SEQUENCER", SEQUENCER_DEVS } , @@ -687,11 +682,14 @@ printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); fprintf (stderr, "Old configuration copied.\n"); +#if defined(linux) || defined(Solaris) build_defines (); +#endif old_config_used = 1; return 1; } +#if defined(linux) || defined(Solaris) void build_defines (void) { @@ -725,6 +723,7 @@ fprintf (optf, "\n"); fclose (optf); } +#endif void ask_parameters (void) @@ -764,7 +763,7 @@ "SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)", FMT_INT, 5, - "5, 6 or 7"); + "5, 6 or 7 (use 1 for 8 bit cards)"); ask_int_choice (B (OPT_SB), "SB_MPU_BASE", "MPU401 I/O base of SB16, Jazz16 and ES1688", @@ -948,7 +947,7 @@ "Soundscape MIDI I/O base", FMT_HEX, 0x330, - ""); + "320, 330, 340 or 350"); ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ", "Soundscape MIDI IRQ", @@ -974,11 +973,6 @@ 11, "7, 9, 10 or 11"); - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_DMA", - "Soundscape audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); if (selected_options & B (OPT_SSCAPE)) { @@ -995,55 +989,55 @@ } ask_int_choice (B (OPT_TRIX), "TRIX_BASE", - "AudioTriX audio I/O base", + "AudioTrix audio I/O base", FMT_HEX, 0x530, "530, 604, E80 or F40"); ask_int_choice (B (OPT_TRIX), "TRIX_IRQ", - "AudioTriX audio IRQ", + "AudioTrix audio IRQ", FMT_INT, 11, "7, 9, 10 or 11"); ask_int_choice (B (OPT_TRIX), "TRIX_DMA", - "AudioTriX audio DMA", + "AudioTrix audio DMA", FMT_INT, 0, "0, 1 or 3"); ask_int_choice (B (OPT_TRIX), "TRIX_DMA2", - "AudioTriX second (duplex) DMA", + "AudioTrix second (duplex) DMA", FMT_INT, 3, "0, 1 or 3"); ask_int_choice (B (OPT_TRIX), "TRIX_MPU_BASE", - "AudioTriX MIDI I/O base", + "AudioTrix MIDI I/O base", FMT_HEX, 0x330, "330, 370, 3B0 or 3F0"); ask_int_choice (B (OPT_TRIX), "TRIX_MPU_IRQ", - "AudioTriX MIDI IRQ", + "AudioTrix MIDI IRQ", FMT_INT, 9, "3, 4, 5, 7 or 9"); ask_int_choice (B (OPT_TRIX), "TRIX_SB_BASE", - "AudioTriX SB I/O base", + "AudioTrix SB I/O base", FMT_HEX, 0x220, "220, 210, 230, 240, 250, 260 or 270"); ask_int_choice (B (OPT_TRIX), "TRIX_SB_IRQ", - "AudioTriX SB IRQ", + "AudioTrix SB IRQ", FMT_INT, 7, "3, 4, 5 or 7"); ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA", - "AudioTriX SB DMA", + "AudioTrix SB DMA", FMT_INT, 1, "1 or 3"); @@ -1141,7 +1135,6 @@ /* * Some "hardcoded" options */ - printf ("bool 'Support for SM Wave' CONFIG_SMWAVE\n"); dump_only = 1; selected_options = 0; @@ -1437,7 +1430,7 @@ { FILE *sf = fopen ("synth-ld.h", "w"); - fprintf (sf, "/* automatically generated by configure */\n"); + fprintf (sf, "/* automaticaly generated by configure */\n"); fprintf (sf, "unsigned char pss_synth[1];\n" "#define pss_synthLen 0\n"); fclose (sf); @@ -1450,10 +1443,10 @@ if (think_positively ("Do you want to include TRXPRO.HEX in your kernel", 1, - "The MediaTriX AudioTrix Pro has an onboard microcontroller which\n" + "The MediaTrix AudioTrix Pro has an onboard microcontroller which\n" "needs to be initialized by downloading the code from the file TRXPRO.HEX\n" "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n" - "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n" + "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n" "Pro will not work without this file!\n")) { char path[512]; @@ -1467,6 +1460,15 @@ goto hex2hex_again; printf ("/*build hex2hex %s trix_boot.h trix_boot */\n", path); printf ("#define INCLUDE_TRIX_BOOT\n"); + } + } + + if (selected_options & B (OPT_MSS)) + { + if (think_positively ("Support for builtin sound of Compaq Deskpro XL", 0, + "Enable this if you have Compaq Deskpro XL.\n")) + { + printf ("#define DESKPROXL\n"); } } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.0.0/linux/drivers/sound/cs4232.c Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/cs4232.c Sun Jun 30 11:43:52 1996 @@ -5,31 +5,15 @@ * a PnP compatible chip which contains a CS4231A codec, SB emulation, * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM * interfaces. This is just a temporary driver until full PnP support - * gets implemented. Just the WSS codec, FM synth and the MIDI ports are + * gets inplemented. Just the WSS codec, FM synth and the MIDI ports are * supported. Other interfaces are left uninitialized. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -67,10 +51,9 @@ return 0; } -long -attach_cs4232_mpu (long mem_start, struct address_info *hw_config) +void +attach_cs4232_mpu (struct address_info *hw_config) { - return mem_start; } static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ @@ -122,7 +105,7 @@ for (n = 0; n < 4; n++) { - cs_sleep_flag.mode = WK_NONE; + cs_sleep_flag.flags = WK_NONE; /* * Wake up the card by sending a 32 byte Crystal key to the key port. */ @@ -131,20 +114,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Delay */ /* @@ -179,20 +162,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Delay */ /* @@ -216,20 +199,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 5) - current_set_timeout (tl = jiffies + (HZ / 5)); + current_set_timeout (tlimit = jiffies + (HZ / 5)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Delay */ /* @@ -241,28 +224,28 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Longer delay */ } return 0; } -long -attach_cs4232 (long mem_start, struct address_info *hw_config) +void +attach_cs4232 (struct address_info *hw_config) { int base = hw_config->io_base, irq = hw_config->irq; int dma1 = hw_config->dma, dma2 = hw_config->dma2; @@ -297,7 +280,7 @@ if (probe_mpu401 (&hw_config2)) { mpu_detected = 1; - mem_start = attach_mpu401 (mem_start, &hw_config2); + attach_mpu401 (&hw_config2); } else { @@ -305,7 +288,6 @@ } } #endif - return mem_start; } void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.0.0/linux/drivers/sound/dev_table.c Sun Mar 24 22:49:56 1996 +++ linux/drivers/sound/dev_table.c Sun Jun 30 11:43:53 1996 @@ -4,27 +4,11 @@ * Device call tables. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -48,36 +32,36 @@ return -1; } -static long -start_services (long mem_start) +static void +start_services (void) { int soundcards_installed; if (!(soundcards_installed = sndtable_get_cardcount ())) - return mem_start; /* No cards detected */ + return; /* No cards detected */ #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { - DMAbuf_init (0); - audio_init (0); + DMAbuf_init (); + audio_init (); } #endif #ifdef CONFIG_MIDI if (num_midis) - MIDIbuf_init (0); + MIDIbuf_init (); #endif #ifdef CONFIG_SEQUENCER if (num_midis + num_synths) - sequencer_init (0); + sequencer_init (); #endif - return mem_start; + return; } -static long -start_cards (long mem_start) +static void +start_cards (void) { int i, n = num_sound_cards; int drv; @@ -112,7 +96,7 @@ if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) { - mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config); + sound_drivers[drv].attach (&snd_installed_cards[i].config); } else @@ -123,13 +107,12 @@ if (trace_init) printk ("Sound initialization complete\n"); - return mem_start; } -long -sndtable_init (long mem_start) +void +sndtable_init (void) { - return start_cards (mem_start); + return start_cards (); } void @@ -173,6 +156,7 @@ { if ((drv = snd_find_driver (type)) != -1) { + DDB (printk (" card %d", i)); if (sound_drivers[drv].unload) { sound_drivers[drv].unload (&snd_installed_cards[i].config); @@ -181,19 +165,19 @@ } } } + DDB (printk ("\n")); save_flags (flags); cli (); restore_flags (flags); - } int sndtable_probe (int unit, struct address_info *hw_config) { - int i, sel = -1, n = num_sound_cards; + int sel = -1; DDB (printk ("sndtable_probe(%d)\n", unit)); @@ -202,10 +186,6 @@ sound_started = 1; - for (i = 0; i < n && sel == -1 && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].enabled) - if (snd_installed_cards[i].card_type == unit) - sel = i; if (sel == -1 && num_sound_cards < max_sound_cards) { @@ -247,8 +227,76 @@ if (sound_drivers[drv].probe (hw_config)) { + DDB (printk ("Hardware probed OK\n")); return TRUE; + } + + DDB (printk ("Failed to find hardware\n")); + snd_installed_cards[sel].enabled = 0; /* + * Mark as not detected + */ + return FALSE; + } + + return FALSE; +} + +int +sndtable_start_card (int unit, struct address_info *hw_config) +{ + int sel = -1; + + DDB (printk ("sndtable_probe(%d)\n", unit)); + + if (!unit) + return TRUE; + + sound_started = 1; + + if (sel == -1 && num_sound_cards < max_sound_cards) + { + int i; + + i = sel = (num_sound_cards++); + + snd_installed_cards[sel].card_type = unit; + snd_installed_cards[sel].enabled = 1; + } + + if (sel != -1) + { + int drv; + + snd_installed_cards[sel].for_driver_use = NULL; + snd_installed_cards[sel].config.io_base = hw_config->io_base; + snd_installed_cards[sel].config.irq = hw_config->irq; + snd_installed_cards[sel].config.dma = hw_config->dma; + snd_installed_cards[sel].config.dma2 = hw_config->dma2; + snd_installed_cards[sel].config.name = hw_config->name; + snd_installed_cards[sel].config.always_detect = hw_config->always_detect; + snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + snd_installed_cards[sel].config.osp = hw_config->osp; + + if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1) + { + snd_installed_cards[sel].enabled = 0; + DDB (printk ("Failed to find driver\n")); + return FALSE; + } + DDB (printk ("Driver name '%s'\n", sound_drivers[drv].name)); + + hw_config->card_subtype = + snd_installed_cards[sel].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe (hw_config)) + { DDB (printk ("Hardware probed OK\n")); + sound_drivers[drv].attach (hw_config); + start_services (); + return TRUE; } DDB (printk ("Failed to find hardware\n")); @@ -270,8 +318,7 @@ if (!unit) { - if (sndtable_init (0) != 0) - panic ("sound: Invalid memory allocation\n"); + sndtable_init (); return TRUE; } @@ -299,12 +346,11 @@ { DDB (printk ("Located card - calling attach routine\n")); - if (sound_drivers[drv].attach (0, hw_config) != 0) - panic ("sound: Invalid memory allocation\n"); + sound_drivers[drv].attach (hw_config); DDB (printk ("attach routine finished\n")); } - start_services (0); + start_services (); return TRUE; } @@ -361,7 +407,7 @@ for (i = 1; i <= ints[0]; i++) { - int card_type, ioaddr, irq, dma, ptr, j; + int card_type, ioaddr, irq, dma, dma2, ptr, j; unsigned int val; val = (unsigned int) ints[i]; @@ -379,6 +425,7 @@ ioaddr = (val & 0x000fff00) >> 8; irq = (val & 0x000000f0) >> 4; dma = (val & 0x0000000f); + dma2 = (val & 0xf0000000) >> 28; ptr = -1; for (j = 0; j < n && ptr == -1; j++) @@ -396,7 +443,7 @@ snd_installed_cards[ptr].config.io_base = ioaddr; snd_installed_cards[ptr].config.irq = irq; snd_installed_cards[ptr].config.dma = dma; - snd_installed_cards[ptr].config.dma2 = -1; + snd_installed_cards[ptr].config.dma2 = dma2; snd_installed_cards[ptr].config.name = NULL; snd_installed_cards[ptr].config.always_detect = 0; snd_installed_cards[ptr].config.driver_use_1 = 0; @@ -424,4 +471,131 @@ return (struct address_info *) NULL; return &snd_installed_cards[ptr].config; +} + + + +int +sound_install_audiodrv (int vers, + char *name, + struct audio_driver *driver, + int driver_size, + int flags, + unsigned int format_mask, + void *devc, + int dma1, + int dma2) +{ + struct audio_driver *d; + struct audio_operations *op; + int l, num; + + if (num_audiodevs >= MAX_AUDIO_DEV) + { + printk ("Sound: Too many audio drivers\n"); + return -(EIO); + } + + if (vers != AUDIO_DRIVER_VERSION || + driver_size > sizeof (struct audio_driver)) + { + printk ("Sound: Incompatible audio driver for %s\n", name); + return -(EIO); + } + + + d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_driver))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (d == NULL || op == NULL) + { + printk ("Sound: Can't allocate driver for (%s)\n", name); + return -(ENOSPC); + } + + memset ((char *) op, 0, sizeof (struct audio_operations)); + if (driver_size < sizeof (struct audio_driver)) + memset ((char *) d, 0, sizeof (struct audio_driver)); + + memcpy ((char *) d, (char *) driver, driver_size); + + op->d = d; + + l = strlen (name) + 1; + if (l > sizeof (op->name)) + l = sizeof (op->name); + strncpy (op->name, name, l); + op->name[l - 1] = 0; + op->flags = flags; + op->format_mask = format_mask; + op->devc = devc; + op->dmachan1 = dma1; + op->dmachan2 = dma2; + +/* + * Hardcoded defaults + */ + op->buffsize = DSP_BUFFSIZE; + + audio_devs[num_audiodevs] = op; + num = num_audiodevs++; + + DMAbuf_init (); + audio_init (); + return num; +} + +int +sound_install_mixer (int vers, + char *name, + struct mixer_operations *driver, + int driver_size, + void *devc) +{ + struct mixer_operations *op; + int l; + + if (num_mixers >= MAX_MIXER_DEV) + { + printk ("Sound: Too many mixer drivers\n"); + return -(EIO); + } + + if (vers != MIXER_DRIVER_VERSION || + driver_size > sizeof (struct mixer_operations)) + { + printk ("Sound: Incompatible mixer driver for %s\n", name); + return -(EIO); + } + + + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (op == NULL) + { + printk ("Sound: Can't allocate mixer driver for (%s)\n", name); + return -(ENOSPC); + } + + memset ((char *) op, 0, sizeof (struct mixer_operations)); + + memcpy ((char *) op, (char *) driver, driver_size); + + l = strlen (name) + 1; + if (l > sizeof (op->name)) + l = sizeof (op->name); + strncpy (op->name, name, l); + op->name[l - 1] = 0; + op->devc = devc; + + mixer_devs[num_mixers] = op; + return num_mixers++; } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.0.0/linux/drivers/sound/dev_table.h Fri Apr 12 15:52:02 1996 +++ linux/drivers/sound/dev_table.h Sun Jun 30 11:43:37 1996 @@ -4,33 +4,24 @@ * Global definitions for device call tables */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #ifndef _DEV_TABLE_H_ #define _DEV_TABLE_H_ + +/* + * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) + * Numbers 1000 to N are reserved for driver's internal use. + */ +#define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ + /* * NOTE! NOTE! NOTE! NOTE! * @@ -43,10 +34,10 @@ struct driver_info { char *driver_id; - int card_subtype; /* Driver specific. Usually 0 */ + int card_subtype; /* Driver spesific. Usually 0 */ int card_type; /* From soundcard.h */ char *name; - long (*attach) (long mem_start, struct address_info *hw_config); + void (*attach) (struct address_info *hw_config); int (*probe) (struct address_info *hw_config); void (*unload) (struct address_info *hw_config); }; @@ -143,16 +134,7 @@ void *devc; /* Driver specific info */ } coproc_operations; -struct audio_operations { - char name[32]; - int flags; -#define NOTHING_SPECIAL 0 -#define NEEDS_RESTART 1 -#define DMA_AUTOMODE 2 -#define DMA_DUPLEX 4 -#define DMA_PSEUDO_AUTOMODE 8 - int format_mask; /* Bitmask for supported audio formats */ - void *devc; /* Driver specific info */ +struct audio_driver { int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, @@ -170,6 +152,23 @@ void (*halt_input) (int dev); void (*halt_output) (int dev); void (*trigger) (int dev, int bits); + int (*set_speed)(int dev, int speed); + unsigned int (*set_bits)(int dev, unsigned int bits); + short (*set_channels)(int dev, short channels); +}; + +struct audio_operations { + char name[32]; + int flags; +#define NOTHING_SPECIAL 0x00 +#define NEEDS_RESTART 0x01 +#define DMA_AUTOMODE 0x02 +#define DMA_DUPLEX 0x04 +#define DMA_PSEUDO_AUTOMODE 0x08 +#define DMA_HARDSTOP 0x10 + int format_mask; /* Bitmask for supported audio formats */ + void *devc; /* Driver specific info */ + struct audio_driver *d; long buffsize; int dmachan1, dmachan2; struct dma_buffparms *dmap_in, *dmap_out; @@ -178,11 +177,15 @@ int enable_bits; int open_mode; int go; + int min_fragment; /* 0 == unlimited */ }; struct mixer_operations { + char id[16]; char name[32]; int (*ioctl) (int dev, unsigned int cmd, caddr_t arg); + + void *devc; }; struct synth_operations { @@ -246,6 +249,7 @@ int (*buffer_status) (int dev); int (*prefix_cmd) (int dev, unsigned char status); struct coproc_operations *coproc; + void *devc; }; struct sound_lowlev_timer { @@ -290,7 +294,7 @@ struct driver_info sound_drivers[] = { #ifdef CONFIG_PSS - {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, + {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif @@ -298,6 +302,8 @@ {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* MSS without IRQ/DMA config registers (for DEC Alphas) */ {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System (AXP)", attach_ms_sound, probe_ms_sound, unload_ms_sound}, + /* Compaq Deskpro XL */ + {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, #endif #ifdef CONFIG_MAD16 {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, @@ -324,11 +330,8 @@ #endif #ifdef CONFIG_SB {"SBLAST", 0, SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb, unload_sb}, -#ifdef CONFIG_AUDIO - {"SBX", 0, SNDCARD_SB16, "SoundBlaster 16bit", sb16_dsp_init, sb16_dsp_detect, unload_sb16}, -#endif #ifdef CONFIG_MIDI - {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU", attach_sb16midi, probe_sb16midi, unload_sb16midi}, + {"UART401", 0, SNDCARD_UART401,"MPU-401 UART", attach_uart401, probe_uart401, unload_uart401}, #endif #endif #ifdef CONFIG_GUS16 @@ -347,9 +350,6 @@ {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif -#ifdef CONFIG_SPNP - {"AD1848", 0, 500, "SoundPort", attach_pnp_ad1848, probe_pnp_ad1848, unload_pnp_ad1848}, -#endif {NULL, 0, 0, "*?*", NULL, NULL, NULL} }; @@ -390,7 +390,7 @@ #endif #ifdef CONFIG_SSCAPE {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, - {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_MAD16 #ifndef MAD16_DMA2 @@ -412,13 +412,19 @@ {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE}, #endif + #ifdef CONFIG_MSS +# ifdef DESKPROXL + {SNDCARD_DESKPROXL, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE}, +# else {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE}, +# endif # ifdef MSS2_BASE {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE}, # endif #endif + #ifdef CONFIG_PAS {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif @@ -431,6 +437,9 @@ # define SB_DMA2 -1 # endif {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE}, +# ifdef SB2_BASE + {SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE}, +# endif #endif #if defined(CONFIG_MAUI) {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -508,8 +517,9 @@ extern int max_sound_cards; extern int trace_init; +#endif /* _DEV_TABLE_C_ */ -long sndtable_init(long mem_start); +void sndtable_init(void); int sndtable_get_cardcount (void); struct address_info *sound_getconf(int card_type); void sound_chconf(int card_type, int ioaddr, int irq, int dma); @@ -521,15 +531,32 @@ int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan); void sound_free_dmap (int dev, struct dma_buffparms *dmap); -extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); +extern int soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); void install_pnp_sounddrv(struct pnp_sounddev *drv); 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); -#endif /* _DEV_TABLE_C_ */ +#define AUDIO_DRIVER_VERSION 1 +#define MIXER_DRIVER_VERSION 1 +int sound_install_audiodrv(int vers, + char *name, + struct audio_driver *driver, + int driver_size, + int flags, + unsigned int format_mask, + void *devc, + int dma1, + int dma2); +int sound_install_mixer(int vers, + char *name, + struct mixer_operations *driver, + int driver_size, + void *devc); + #endif /* _DEV_TABLE_H_ */ diff -u --recursive --new-file v2.0.0/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.0.0/linux/drivers/sound/dmabuf.c Fri Apr 19 10:08:01 1996 +++ linux/drivers/sound/dmabuf.c Sun Jun 30 11:43:55 1996 @@ -4,27 +4,11 @@ * The DMA buffer manager for digitized voice applications */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -59,6 +43,7 @@ static void dma_reset_output (int dev); static void dma_reset_input (int dev); +static int dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact); static void reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) @@ -75,9 +60,9 @@ if (dmap->fragment_size == 0) { /* Compute the fragment size using the default algorithm */ - sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1); - nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1); - sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1); + sr = dsp_dev->d->set_speed (dev, 0); + nc = dsp_dev->d->set_channels (dev, 0); + sz = dsp_dev->d->set_bits (dev, 0); if (sz == 8) dmap->neutral_byte = NEUTRAL8; @@ -98,7 +83,7 @@ sz /= 8; /* #bits -> #bytes */ /* - * Compute a buffer size for time not exceeding 1 second. + * Compute a buffer size for time not exeeding 1 second. * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds * of sound (using the current speed, sample size and #channels). */ @@ -135,8 +120,8 @@ else { /* - * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or - * the buffer size computation has already been done. + * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or + * the buffer sice computation has already been done. */ if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2)) dmap->fragment_size = (audio_devs[dev]->buffsize / 2); @@ -156,9 +141,10 @@ dmap->nbufs = n; dmap->bytes_in_use = n * bsz; - memset (dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); + if (dmap->raw_buf) + memset (dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); for (i = 0; i < dmap->nbufs; i++) { @@ -173,11 +159,11 @@ { if (dmap == audio_devs[dev]->dmap_out) { - out_sleep_flag[dev].mode = WK_NONE; + out_sleep_flag[dev].flags = WK_NONE; } else { - in_sleep_flag[dev].mode = WK_NONE; + in_sleep_flag[dev].flags = WK_NONE; } dmap->flags = DMA_BUSY; /* Other flags off */ @@ -196,7 +182,7 @@ open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) { if (dmap->flags & DMA_BUSY) - return -EBUSY; + return -(EBUSY); { int err; @@ -206,12 +192,12 @@ } if (dmap->raw_buf == NULL) - return -ENOSPC; /* Memory allocation failed during boot */ + return -(ENOSPC); /* Memory allocation failed during boot */ if (sound_open_dma (chan, audio_devs[dev]->name)) { printk ("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; + return -(EBUSY); } dmap->open_mode = mode; @@ -238,6 +224,37 @@ sound_free_dmap (dev, dmap); } +static unsigned int +default_set_bits (int dev, unsigned int bits) +{ + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1); +} + +static int +default_set_speed (int dev, int speed) +{ + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) speed, 1); +} + +static short +default_set_channels (int dev, short channels) +{ + int c = channels; + + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) c, 1); +} + +static void +check_driver (struct audio_driver *d) +{ + if (d->set_speed == NULL) + d->set_speed = default_set_speed; + if (d->set_bits == NULL) + d->set_bits = default_set_bits; + if (d->set_channels == NULL) + d->set_channels = default_set_channels; +} + int DMAbuf_open (int dev, int mode) { @@ -247,14 +264,14 @@ if (dev >= num_audiodevs) { - printk ("PCM device %d not installed.\n", dev); - return -ENXIO; + /* printk ("PCM device %d not installed.\n", dev); */ + return -(ENXIO); } if (!audio_devs[dev]) { - printk ("PCM device %d not initialized\n", dev); - return -ENXIO; + /* printk ("PCM device %d not initialized\n", dev); */ + return -(ENXIO); } if (!(audio_devs[dev]->flags & DMA_DUPLEX)) @@ -263,34 +280,37 @@ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1; } - if ((retval = audio_devs[dev]->open (dev, mode)) < 0) + if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) return retval; + check_driver (audio_devs[dev]->d); + dmap_out = audio_devs[dev]->dmap_out; dmap_in = audio_devs[dev]->dmap_in; if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) { - audio_devs[dev]->close (dev); + audio_devs[dev]->d->close (dev); return retval; } audio_devs[dev]->enable_bits = mode; - if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) + if (mode & OPEN_READ && + audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0) { - audio_devs[dev]->close (dev); + audio_devs[dev]->d->close (dev); close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1); return retval; } audio_devs[dev]->open_mode = mode; audio_devs[dev]->go = 1; - in_sleep_flag[dev].mode = WK_NONE; - out_sleep_flag[dev].mode = WK_NONE; + in_sleep_flag[dev].flags = WK_NONE; + out_sleep_flag[dev].flags = WK_NONE; - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, (caddr_t) 8, 1); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, (caddr_t) 1, 1); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, (caddr_t) DSP_DEFAULT_SPEED, 1); + 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); return 0; } @@ -302,12 +322,13 @@ save_flags (flags); cli (); - audio_devs[dev]->reset (dev); + audio_devs[dev]->d->reset (dev); restore_flags (flags); dma_reset_output (dev); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) dma_reset_input (dev); } @@ -319,10 +340,10 @@ save_flags (flags); cli (); if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->halt_output) - audio_devs[dev]->reset (dev); + !audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->reset (dev); else - audio_devs[dev]->halt_output (dev); + audio_devs[dev]->d->halt_output (dev); restore_flags (flags); dma_init_buffers (dev, audio_devs[dev]->dmap_out); @@ -337,10 +358,10 @@ save_flags (flags); cli (); if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->halt_input) - audio_devs[dev]->reset (dev); + !audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->reset (dev); else - audio_devs[dev]->halt_input (dev); + audio_devs[dev]->d->halt_input (dev); restore_flags (flags); dma_init_buffers (dev, audio_devs[dev]->dmap_in); @@ -360,7 +381,7 @@ save_flags (flags); cli (); - audio_devs[dev]->flags |= DMA_SYNCING; + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; audio_devs[dev]->dmap_out->underrun_count = 0; while (!current_got_fatal_signal () @@ -369,29 +390,29 @@ { { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - out_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - out_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + out_sleep_flag[dev].flags |= WK_TIMEOUT; } - out_sleep_flag[dev].mode &= ~WK_SLEEP; + out_sleep_flag[dev].flags &= ~WK_SLEEP; }; - if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) + if ((out_sleep_flag[dev].flags & WK_TIMEOUT)) { - audio_devs[dev]->flags &= ~DMA_SYNCING; + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; restore_flags (flags); return audio_devs[dev]->dmap_out->qlen; } } - audio_devs[dev]->flags &= ~DMA_SYNCING; + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; restore_flags (flags); /* @@ -401,27 +422,27 @@ save_flags (flags); cli (); - if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ { while (!(current_got_fatal_signal ()) - && audio_devs[dev]->local_qlen (dev)) + && audio_devs[dev]->d->local_qlen (dev)) { { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - out_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - out_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + out_sleep_flag[dev].flags |= WK_TIMEOUT; } - out_sleep_flag[dev].mode &= ~WK_SLEEP; + out_sleep_flag[dev].flags &= ~WK_SLEEP; }; } } @@ -442,20 +463,23 @@ && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) { dma_sync (dev); - - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); } + 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); + save_flags (flags); cli (); - audio_devs[dev]->close (dev); + audio_devs[dev]->d->halt_xfer (dev); + audio_devs[dev]->d->close (dev); close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->open_mode & OPEN_READ && + audio_devs[dev]->flags & DMA_DUPLEX) close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); audio_devs[dev]->open_mode = 0; @@ -467,6 +491,8 @@ static int activate_recording (int dev, struct dma_buffparms *dmap) { + int prepare = 0; + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) return 0; @@ -474,6 +500,7 @@ { dma_reset_input (dev); dmap->flags &= ~DMA_RESTART; + prepare = 1; } if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ @@ -486,11 +513,11 @@ if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap, 1); - if (!dmap->dma_mode) + if (prepare || !dmap->dma_mode) { int err; - if ((err = audio_devs[dev]->prepare_for_input (dev, + if ((err = audio_devs[dev]->d->prepare_for_input (dev, dmap->fragment_size, dmap->nbufs)) < 0) { return err; @@ -500,14 +527,14 @@ if (!(dmap->flags & DMA_ACTIVE)) { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0, + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 0, !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); + !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_ACTIVE | DMA_STARTED; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } return 0; @@ -525,7 +552,7 @@ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't read from mmapped device (1)\n"); - return -EINVAL; + return -(EINVAL); } else if (!dmap->qlen) { @@ -542,14 +569,14 @@ if (dontblock) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) & audio_devs[dev]->go) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } if (!audio_devs[dev]->go) @@ -559,26 +586,26 @@ { - unsigned long tl; + unsigned long tlimit; if (tmout) - current_set_timeout (tl = jiffies + (tmout)); + current_set_timeout (tlimit = jiffies + (tmout)); else - tl = (unsigned long) -1; - in_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + in_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(in_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - in_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + in_sleep_flag[dev].flags |= WK_TIMEOUT; } - in_sleep_flag[dev].mode &= ~WK_SLEEP; + in_sleep_flag[dev].flags &= ~WK_SLEEP; }; - if ((in_sleep_flag[dev].mode & WK_TIMEOUT)) + if ((in_sleep_flag[dev].flags & WK_TIMEOUT)) { printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); err = EIO; - audio_devs[dev]->reset (dev); + audio_devs[dev]->d->reset (dev); ; } else @@ -587,7 +614,7 @@ restore_flags (flags); if (!dmap->qlen) - return -err; + return -(err); *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; @@ -605,7 +632,7 @@ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; + return -(EINVAL); } else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ @@ -634,14 +661,14 @@ } if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; + dmap->fragment_size) /* Loo late to change */ + return -(EINVAL); if (fact > MAX_REALTIME_FACTOR) - return -EINVAL; + return -(EINVAL); if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return -EINVAL; + return -(EINVAL); dmap->subdivision = fact; return snd_ioctl_return ((int *) arg, fact); @@ -653,23 +680,27 @@ int bytes, count; if (fact == 0) - return -EIO; + return -(EIO); if (dmap->subdivision != 0 || - dmap->fragment_size) /* Too late to change */ - return -EINVAL; + dmap->fragment_size) /* Loo late to change */ + return -(EINVAL); bytes = fact & 0xffff; - count = (fact >> 16) & 0xffff; + count = (fact >> 16) & 0x7fff; if (count == 0) count = MAX_SUB_BUFFERS; - if (bytes < 4 || bytes > 17) /* <16 || > 128k */ - return -EINVAL; + if (bytes < 4 || bytes > 17) /* <16 || > 512k */ + return -(EINVAL); if (count < 2) - return -EINVAL; + return -(EINVAL); + + if (audio_devs[dev]->min_fragment > 0) + if (bytes < audio_devs[dev]->min_fragment) + bytes = audio_devs[dev]->min_fragment; #ifdef OS_DMA_MINBITS if (bytes < OS_DMA_MINBITS) @@ -687,7 +718,10 @@ dmap->fragment_size /= 2; /* Needs at least 2 buffers */ dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - return snd_ioctl_return ((int *) arg, bytes | (count << 16)); + if (arg) + return snd_ioctl_return ((int *) arg, bytes | (count << 16)); + else + return 0; } static int @@ -727,9 +761,45 @@ { struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; + int iarg = (int) arg; switch (cmd) { + case SOUND_PCM_WRITE_RATE: + if (local) + return audio_devs[dev]->d->set_speed (dev, (int) arg); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_fs_long ((long *) arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return audio_devs[dev]->d->set_speed (dev, 0); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0)); + + case SNDCTL_DSP_STEREO: + if (local) + return audio_devs[dev]->d->set_channels (dev, (int) arg + 1) - 1; + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_fs_long ((long *) arg) + 1) - 1); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return audio_devs[dev]->d->set_channels (dev, (short) iarg); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_fs_long ((long *) arg))); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return audio_devs[dev]->d->set_channels (dev, 0); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0)); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return audio_devs[dev]->d->set_bits (dev, (unsigned int) arg); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_fs_long ((long *) arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return audio_devs[dev]->d->set_bits (dev, 0); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0)); + case SNDCTL_DSP_RESET: dma_reset (dev); return 0; @@ -746,7 +816,8 @@ { reorganize_buffers (dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) reorganize_buffers (dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); } @@ -763,7 +834,8 @@ if (ret < 0) return ret; - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) ret = dma_subdivide (dev, dmap_in, arg, fact); return ret; @@ -772,9 +844,9 @@ case SNDCTL_DSP_SETDUPLEX: if (audio_devs[dev]->flags & DMA_DUPLEX) - return 0; + return 0; else - return -EIO; + return -(EIO); break; case SNDCTL_DSP_SETFRAGMENT: @@ -786,7 +858,8 @@ if (ret < 0) return ret; - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) ret = dma_set_fragment (dev, dmap_in, arg, fact); return ret; @@ -796,18 +869,22 @@ case SNDCTL_DSP_GETISPACE: case SNDCTL_DSP_GETOSPACE: if (!local) - return -EINVAL; + return -(EINVAL); else { struct dma_buffparms *dmap = dmap_out; audio_buf_info *info = (audio_buf_info *) arg; + if (cmd == SNDCTL_DSP_GETISPACE && + !(audio_devs[dev]->open_mode & OPEN_READ)) + return -(EINVAL); + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) dmap = dmap_in; if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -EINVAL; + return -(EINVAL); if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); @@ -823,9 +900,9 @@ else { info->fragments = dmap->nbufs - dmap->qlen; - if (audio_devs[dev]->local_qlen) + if (audio_devs[dev]->d->local_qlen) { - int tmp = audio_devs[dev]->local_qlen (dev); + int tmp = audio_devs[dev]->d->local_qlen (dev); if (tmp && info->fragments) tmp--; /* @@ -856,14 +933,14 @@ int bits = get_fs_long ((long *) arg) & audio_devs[dev]->open_mode; int changed; - if (audio_devs[dev]->trigger == NULL) - return -EINVAL; + if (audio_devs[dev]->d->trigger == NULL) + return -(EINVAL); if (!(audio_devs[dev]->flags & DMA_DUPLEX)) if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) { printk ("Sound: Device doesn't have full duplex capability\n"); - return -EINVAL; + return -(EINVAL); } save_flags (flags); @@ -879,10 +956,11 @@ reorganize_buffers (dev, dmap_in, 1); } - if ((err = audio_devs[dev]->prepare_for_input (dev, + if ((err = audio_devs[dev]->d->prepare_for_input (dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) - return -err; + return -(err); + audio_devs[dev]->enable_bits = bits; activate_recording (dev, dmap_in); } @@ -897,17 +975,19 @@ reorganize_buffers (dev, dmap_out, 0); } - if ((err = audio_devs[dev]->prepare_for_output (dev, + if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap_out->fragment_size, dmap_out->nbufs)) < 0) - return -err; + return -(err); dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; DMAbuf_start_output (dev, 0, dmap_out->fragment_size); } audio_devs[dev]->enable_bits = bits; - if (changed && audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, bits * audio_devs[dev]->go); + if (changed && audio_devs[dev]->d->trigger) + { + audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); + } restore_flags (flags); } case SNDCTL_DSP_GETTRIGGER: @@ -916,10 +996,10 @@ case SNDCTL_DSP_SETSYNCRO: - if (!audio_devs[dev]->trigger) - return -EINVAL; + if (!audio_devs[dev]->d->trigger) + return -(EINVAL); - audio_devs[dev]->trigger (dev, 0); + audio_devs[dev]->d->trigger (dev, 0); audio_devs[dev]->go = 0; return 0; break; @@ -929,13 +1009,16 @@ count_info info; unsigned long flags; + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -(EINVAL); + save_flags (flags); cli (); info.bytes = audio_devs[dev]->dmap_in->byte_counter; info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in); info.blocks = audio_devs[dev]->dmap_in->qlen; info.bytes += info.ptr; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */ @@ -949,13 +1032,16 @@ count_info info; unsigned long flags; + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -(EINVAL); + save_flags (flags); cli (); info.bytes = audio_devs[dev]->dmap_out->byte_counter; info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out); info.blocks = audio_devs[dev]->dmap_out->qlen; info.bytes += info.ptr; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */ @@ -966,7 +1052,7 @@ default: - return audio_devs[dev]->ioctl (dev, cmd, arg, local); + return audio_devs[dev]->d->ioctl (dev, cmd, arg, local); } } @@ -989,8 +1075,8 @@ /* OK to start the device */ audio_devs[dev]->go = 1; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } } @@ -1012,9 +1098,9 @@ max = dmap->max_fragments; len = dmap->qlen; - if (audio_devs[dev]->local_qlen) + if (audio_devs[dev]->d->local_qlen) { - tmp = audio_devs[dev]->local_qlen (dev); + tmp = audio_devs[dev]->d->local_qlen (dev); if (tmp && len) tmp--; /* * This buffer has been counted twice @@ -1039,7 +1125,7 @@ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; + return -(EINVAL); } if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ @@ -1063,7 +1149,7 @@ int err; dmap->dma_mode = DMODE_OUTPUT; - if ((err = audio_devs[dev]->prepare_for_output (dev, + if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; } @@ -1080,14 +1166,14 @@ if (dontblock) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) && audio_devs[dev]->go) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } /* @@ -1100,28 +1186,32 @@ { - unsigned long tl; + unsigned long tlimit; if (tmout) - current_set_timeout (tl = jiffies + (tmout)); + current_set_timeout (tlimit = jiffies + (tmout)); else - tl = (unsigned long) -1; - out_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - out_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + out_sleep_flag[dev].flags |= WK_TIMEOUT; } - out_sleep_flag[dev].mode &= ~WK_SLEEP; + out_sleep_flag[dev].flags &= ~WK_SLEEP; }; - if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) + if ((out_sleep_flag[dev].flags & WK_TIMEOUT)) { printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); err = EIO; abort = 1; ; - audio_devs[dev]->reset (dev); + if (audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; + audio_devs[dev]->d->reset (dev); } else if (current_got_fatal_signal ()) { @@ -1133,7 +1223,7 @@ if (!space_in_queue (dev)) { - return -err; /* Caught a signal ? */ + return -(err); /* Caught a signal ? */ } *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; @@ -1176,11 +1266,14 @@ DMAbuf_start_output (int dev, int buff_no, int l) { struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int restart = 0; dmap->cfrag = -1; + if (dmap->flags & DMA_RESTART) + restart = 1; /* - * Bypass buffering if using mmapped access + * Bypass buffering if using mmaped access */ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) @@ -1193,7 +1286,6 @@ else { - dmap->qlen++; if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n", @@ -1204,10 +1296,15 @@ { int p = dmap->fragment_size * dmap->qtail; + dmap->neutral_byte = dmap->raw_buf[p + l - 1]; + memset (dmap->raw_buf + p + l, dmap->neutral_byte, dmap->fragment_size - l); } + else + dmap->neutral_byte = + dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1]; if ((l != dmap->fragment_size) && ((audio_devs[dev]->flags & DMA_AUTOMODE) && @@ -1222,14 +1319,19 @@ if (!(dmap->flags & DMA_ACTIVE)) { dmap->flags |= DMA_ACTIVE; - audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 0, + + if (restart) + audio_devs[dev]->d->prepare_for_output (dev, + dmap->fragment_size, dmap->nbufs); + + audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 0, !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); + !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_STARTED; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } @@ -1254,6 +1356,12 @@ dmap = audio_devs[dev]->dmap_in; } + if (dmap->raw_buf_phys == 0) + { + printk ("sound: DMA buffer == NULL\n"); + return 0; + } + /* * The count must be one less than the actual size. This is handled by * set_dma_addr() @@ -1290,8 +1398,8 @@ return count; } -long -DMAbuf_init (long mem_start) +void +DMAbuf_init (void) { int dev; @@ -1311,7 +1419,6 @@ audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; } - return mem_start; } static void @@ -1343,12 +1450,12 @@ force_restart (int dev, struct dma_buffparms *dmap) { if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_output) - audio_devs[dev]->halt_output (dev); + audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->halt_output (dev); else - audio_devs[dev]->halt_xfer (dev); + audio_devs[dev]->d->halt_xfer (dev); - dmap->flags &= ~DMA_ACTIVE; + dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED); if (audio_devs[dev]->flags & DMA_AUTOMODE) dmap->flags |= DMA_RESTART; else @@ -1370,6 +1477,7 @@ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int this_fragment; dmap->byte_counter += dmap->counts[dmap->qhead]; @@ -1377,10 +1485,15 @@ sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); #endif + if (dmap->raw_buf == NULL) + { + printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->qlen++; /* Yes increment it (don't decrement) */ dmap->flags &= ~DMA_ACTIVE; @@ -1388,12 +1501,12 @@ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1, + audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; @@ -1408,6 +1521,7 @@ } dmap->qlen--; + this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->flags &= ~DMA_ACTIVE; @@ -1415,8 +1529,11 @@ { dmap->underrun_count++; - if (!(dmap->flags & DMA_CLEAN) && - (audio_devs[dev]->flags & DMA_SYNCING || dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) + if ((!(dmap->flags & DMA_CLEAN) && + (audio_devs[dev]->dmap_out->flags & DMA_SYNCING || + dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) || + audio_devs[dev]->flags & DMA_HARDSTOP) + { dmap->qlen = 0; force_restart (dev, dmap); @@ -1426,7 +1543,7 @@ if (dmap->closing) { polish_buffers (dmap); - audio_devs[dev]->halt_xfer (dev); + audio_devs[dev]->d->halt_xfer (dev); } else { @@ -1444,18 +1561,27 @@ if (dmap->qlen) { + if (dmap->flags & DMA_CLEAN) + { + int p = dmap->fragment_size * this_fragment; + + memset (dmap->raw_buf + p, + dmap->neutral_byte, + dmap->fragment_size); + } + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { if (dmap->counts[dmap->qhead] == 0) dmap->counts[dmap->qhead] = dmap->fragment_size; - audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + + audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1, + dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; @@ -1464,10 +1590,10 @@ save_flags (flags); cli (); - if ((out_sleep_flag[dev].mode & WK_SLEEP)) + if ((out_sleep_flag[dev].flags & WK_SLEEP)) { { - out_sleep_flag[dev].mode = WK_WAKEUP; + out_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&out_sleeper[dev]); }; } @@ -1486,6 +1612,12 @@ sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); #endif + if (dmap->raw_buf == NULL) + { + printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; @@ -1493,12 +1625,12 @@ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } @@ -1513,10 +1645,10 @@ { /* Force restart on next read */ if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_input) - audio_devs[dev]->halt_input (dev); + audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->halt_input (dev); else - audio_devs[dev]->halt_xfer (dev); + audio_devs[dev]->d->halt_xfer (dev); dmap->flags &= ~DMA_ACTIVE; if (audio_devs[dev]->flags & DMA_AUTOMODE) @@ -1536,12 +1668,12 @@ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } @@ -1549,10 +1681,10 @@ save_flags (flags); cli (); - if ((in_sleep_flag[dev].mode & WK_SLEEP)) + if ((in_sleep_flag[dev].flags & WK_SLEEP)) { { - in_sleep_flag[dev].mode = WK_WAKEUP; + in_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&in_sleeper[dev]); }; } @@ -1562,39 +1694,21 @@ int DMAbuf_open_dma (int dev) { +/* + * NOTE! This routine opens only the primary DMA channel (output). + */ + int chan = audio_devs[dev]->dmachan1; int err; unsigned long flags; if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0) { - return -EBUSY; + return -(EBUSY); } dma_init_buffers (dev, audio_devs[dev]->dmap_out); audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize; - /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */ - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0) - { - printk ("Unable to grab DMA%d for the audio driver\n", - audio_devs[dev]->dmachan2); - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - return -EBUSY; - } - dma_init_buffers (dev, audio_devs[dev]->dmap_in); - audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize; - /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */ - } - else - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1; - } - save_flags (flags); cli (); @@ -1610,10 +1724,6 @@ { DMAbuf_reset_dma (dev); close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); - } void @@ -1640,7 +1750,7 @@ save_flags (flags); cli (); - in_sleep_flag[dev].mode = WK_SLEEP; + in_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1667,7 +1777,7 @@ save_flags (flags); cli (); - in_sleep_flag[dev].mode = WK_SLEEP; + in_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1686,7 +1796,7 @@ save_flags (flags); cli (); - out_sleep_flag[dev].mode = WK_SLEEP; + out_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1707,7 +1817,7 @@ save_flags (flags); cli (); - out_sleep_flag[dev].mode = WK_SLEEP; + out_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1731,7 +1841,7 @@ int DMAbuf_open (int dev, int mode) { - return -ENXIO; + return -(ENXIO); } int @@ -1743,49 +1853,48 @@ int DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { - return -EIO; + return -(EIO); } int DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { - return -EIO; + return -(EIO); } int DMAbuf_rmchars (int dev, int buff_no, int c) { - return -EIO; + return -(EIO); } int DMAbuf_start_output (int dev, int buff_no, int l) { - return -EIO; + return -(EIO); } int DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - return -EIO; + return -(EIO); } -long -DMAbuf_init (long mem_start) +void +DMAbuf_init (void) { - return mem_start; } int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) { - return -EIO; + return -(EIO); } int DMAbuf_open_dma (int dev) { - return -ENXIO; + return -(ENXIO); } void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/finetune.h linux/drivers/sound/finetune.h --- v2.0.0/linux/drivers/sound/finetune.h Sun Mar 24 22:49:41 1996 +++ linux/drivers/sound/finetune.h Sun Jun 30 11:43:37 1996 @@ -1,26 +1,10 @@ #ifdef SEQUENCER_C /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.0.0/linux/drivers/sound/gus_card.c Sun Mar 24 22:49:59 1996 +++ linux/drivers/sound/gus_card.c Sun Jun 30 11:43:56 1996 @@ -4,27 +4,11 @@ * Detection routine for the Gravis Ultrasound. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -45,8 +29,8 @@ int *gus_osp; -long -attach_gus_card (long mem_start, struct address_info *hw_config) +void +attach_gus_card (struct address_info *hw_config) { int io_addr; @@ -57,7 +41,7 @@ * Try first the default */ { - mem_start = gus_wave_init (mem_start, hw_config); + gus_wave_init (hw_config); request_region (hw_config->io_base, 16, "GUS"); request_region (hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ @@ -68,9 +52,9 @@ if (sound_alloc_dma (hw_config->dma2, "GUS(2)")) printk ("gus_card.c: Can't allocate DMA channel2\n"); #ifdef CONFIG_MIDI - mem_start = gus_midi_init (mem_start); + gus_midi_init (); #endif - return mem_start; + return; } #ifndef EXCLUDE_GUS_IODETECT @@ -88,7 +72,7 @@ hw_config->io_base = io_addr; printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base); - mem_start = gus_wave_init (mem_start, hw_config); + gus_wave_init (hw_config); request_region (io_addr, 16, "GUS"); request_region (io_addr + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ if (sound_alloc_dma (hw_config->dma, "GUS")) @@ -97,16 +81,13 @@ if (sound_alloc_dma (hw_config->dma2, "GUS")) printk ("gus_card.c: Can't allocate DMA channel2\n"); #ifdef CONFIG_MIDI - mem_start = gus_midi_init (mem_start); + gus_midi_init (); #endif - return mem_start; + return; } #endif - return mem_start; /* - * Not detected - */ } int @@ -242,8 +223,8 @@ return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); } -long -attach_gus_db16 (long mem_start, struct address_info *hw_config) +void +attach_gus_db16 (struct address_info *hw_config) { #ifdef CONFIG_GUS gus_pcm_volume = 100; @@ -255,7 +236,6 @@ hw_config->dma, hw_config->dma, 0, hw_config->osp); - return mem_start; } void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.0.0/linux/drivers/sound/gus_midi.c Sun Mar 24 22:49:59 1996 +++ linux/drivers/sound/gus_midi.c Sun Jun 30 11:43:56 1996 @@ -4,27 +4,11 @@ * The low level driver for the GUS Midi Interface. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -64,7 +48,7 @@ if (midi_busy) { printk ("GUS: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } outb (MIDI_RESET, u_MidiControl); @@ -196,7 +180,7 @@ static int gus_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -(EINVAL); } static void @@ -249,20 +233,20 @@ NULL }; -long -gus_midi_init (long mem_start) +void +gus_midi_init (void) { if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); - return mem_start; + return; } outb (MIDI_RESET, u_MidiControl); std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &gus_midi_operations; - return mem_start; + return; } void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c --- v2.0.0/linux/drivers/sound/gus_vol.c Sun Mar 24 22:50:00 1996 +++ linux/drivers/sound/gus_vol.c Sun Jun 30 11:43:56 1996 @@ -2,27 +2,11 @@ * gus_vol.c - Compute volume for GUS. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.0.0/linux/drivers/sound/gus_wave.c Tue May 7 16:22:35 1996 +++ linux/drivers/sound/gus_wave.c Sun Jun 30 11:44:01 1996 @@ -4,31 +4,17 @@ * Driver for the Gravis UltraSound wave table synth. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include +#define GUSPNP_AUTODETECT + #include "sound_config.h" #include #include "gus_hw.h" @@ -113,9 +99,9 @@ #define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */ #define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer done ch. 1/2 */ -static int gus_sampling_speed; -static int gus_sampling_channels; -static int gus_sampling_bits; +static int gus_audio_speed; +static int gus_audio_channels; +static int gus_audio_bits; static wait_handle *dram_sleeper = NULL; static volatile struct snd_wait dram_sleep_flag = @@ -337,8 +323,27 @@ return ((hi << 8) & 0xff00) | lo; } +unsigned short +gus_look16 (int reg) +{ /* Reads from an indirect register (16 bit). No additional offset. */ + unsigned long flags; + unsigned char hi, lo; + + save_flags (flags); + cli (); + + outb (reg, u_Command); + + lo = inb (u_DataLo); + hi = inb (u_DataHi); + + restore_flags (flags); + + return ((hi << 8) & 0xff00) | lo; +} + void -gus_write_addr (int reg, unsigned long address, int is16bit) +gus_write_addr (int reg, unsigned long address, int frac, int is16bit) { /* Writes an 24 bit memory address */ unsigned long hold_address; unsigned long flags; @@ -358,11 +363,13 @@ } gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); - /* Could writing twice fix problems with GUS_VOICE_POS() ? Let's try... */ + gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); + /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ gus_delay (); gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); + gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); restore_flags (flags); } @@ -488,7 +495,7 @@ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) voices[voice].offset_pending = position; else - gus_write_addr (0x0a, sample_ptrs[sample_no] + position, + gus_write_addr (0x0a, sample_ptrs[sample_no] + position, 0, samples[sample_no].mode & WAVE_16_BITS); } @@ -502,7 +509,7 @@ gus_select_voice (voice); gus_voice_volume (0); gus_voice_off (); - gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ + gus_write_addr (0x0a, 0, 0, 0); /* Set current position to 0 */ gus_write8 (0x00, 0x03); /* Voice off */ gus_write8 (0x0d, 0x03); /* Ramping off */ voice_alloc->map[voice] = 0; @@ -687,14 +694,6 @@ gus_voice_init (i); /* Turn voice off */ gus_voice_init2 (i); } - - inb (u_Status); /* Touch the status register */ - - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - - gus_read8 (0x0f); /* Clear pending IRQs */ - } static void @@ -838,14 +837,194 @@ gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ - gusintr (0, NULL, NULL); /* Serve pending interrupts */ + gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + + inb (u_Status); /* Touch the status register */ + + gus_look8 (0x41); /* Clear any pending DMA IRQs */ + gus_look8 (0x49); /* Clear any pending sample IRQs */ + + gus_read8 (0x0f); /* Clear pending IRQs */ + restore_flags (flags); } +static void +pnp_mem_init (void) +{ +#include "iwmem.h" +#define CHUNK_SIZE (256*1024) +#define BANK_SIZE (4*1024*1024) +#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) + + int bank, chunk, addr, total = 0; + int bank_sizes[4]; + int i, j, bits = -1, nbanks = 0; + +/* + * This routine determines what kind of RAM is installed in each of the four + * SIMM banks and configures the DRAM address decode logic accordingly. + */ + +/* + * Place the chip into enhanced mode + */ + gus_write8 (0x19, gus_read8 (0x19) | 0x01); + gus_write8 (0x53, gus_look8 (0x53) & ~0x02); /* Select DRAM I/O access */ + +/* + * Set memory configuration to 4 DRAM banks of 4M in each (16M total). + */ + + gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | 0x000c); + +/* + * Perform the DRAM size detection for each bank individually. + */ + for (bank = 0; bank < 4; bank++) + { + int size = 0; + + addr = bank * BANK_SIZE; + + /* Clean check points of each chunk */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + /* Write a value to each chunk point and verify the result */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x55); + gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0xAA); + + if (gus_peek (addr + chunk * CHUNK_SIZE + 0L) == 0x55 && + gus_peek (addr + chunk * CHUNK_SIZE + 1L) == 0xAA) + { /* OK. There is RAM. Now check for possible shadows */ + int ok = 1, chunk2; + + for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) + if (gus_peek (addr + chunk2 * CHUNK_SIZE + 0L) || + gus_peek (addr + chunk2 * CHUNK_SIZE + 1L)) + ok = 0; /* Addressing wraps */ + + if (ok) + size = (chunk + 1) * CHUNK_SIZE; + } + gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + bank_sizes[bank] = size; + if (size) + nbanks = bank + 1; + DDB (printk ("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); + } + + if (nbanks == 0) /* No RAM - Give up */ + { + printk ("Sound: An Interwave audio chip detected but no DRAM\n"); + printk ("Sound: Unable to work with this card.\n"); + gus_write8 (0x19, gus_read8 (0x19) & ~0x01); + return; + } +/* + * Now we know how much DRAM there is in each bank. The next step is + * to find a DRAM size encoding (0 to 12) which is best for the combination + * we have. + * + * First try if any of the possible alternatives matches exactly the amount + * of memory we have. + */ + + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < 4; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + +/* + * If necessary, try to find a combination where other than the last + * bank matches our configuration and the last bank is left oversized. + * In this way we don't leave holes in the middle of memory. + */ + if (bits == -1) /* No luck yet */ + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) + bits = -1; /* The last bank is too small */ + } + +/* + * The last resort is to search for a combination where the last bank is + * smaller than the actual SIMM. This leaves some memory in the last bank + * unused but doesn't leave holes in the DRAM address space. + */ + if (bits == -1) /* No luck yet */ + { + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + + if (bits != -1) + { + printk ("Interwave: Can't use all installed RAM.\n"); + printk ("Interwave: Try reordering SIMMS.\n"); + } + } + + if (bits == -1) + { + printk ("Interwave: Can't find working DRAM encoding.\n"); + printk ("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); + bits = 0; + } + + DDB (printk ("Interwave: Selecting DRAM addressing mode %d\n", bits)); + + for (bank = 0; bank < 4; bank++) + { + DDB (printk (" Bank %d, mem=%dk (limit %dk)\n", + bank, bank_sizes[bank] / 1024, + mem_decode[bits][bank] / 1024)); + + if (bank_sizes[bank] > mem_decode[bits][bank]) + total += mem_decode[bits][bank]; + else + total += bank_sizes[bank]; + } + + DDB (printk ("Total %dk of DRAM (enhanced mode)\n", total / 1024)); +/* + * Set the memory addressing mode. + */ + gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits); + +/* + * Return the chip back to GUS compatible mode. + */ + gus_write8 (0x19, gus_read8 (0x19) & ~0x01); +} + int gus_wave_detect (int baseaddr) { - unsigned long i; + unsigned long i, max_mem = 1024L; unsigned long loc; gus_base = baseaddr; @@ -858,6 +1037,9 @@ gus_delay (); gus_delay (); + if (gus_pnp_flag) + pnp_mem_init (); + /* See if there is first block there.... */ gus_poke (0L, 0xaa); if (gus_peek (0L) != 0xaa) @@ -865,7 +1047,7 @@ /* Now zero it out so that I can check for mirroring .. */ gus_poke (0L, 0x00); - for (i = 1L; i < 1024L; i++) + for (i = 1L; i < max_mem; i++) { int n, failed; @@ -901,7 +1083,7 @@ { case SNDCTL_SYNTH_INFO: gus_info.nr_voices = nr_voices; - memcpy_tofs ((&((char *) arg)[0]), &gus_info, sizeof (gus_info)); + memcpy_tofs (&((char *) arg)[0], &gus_info, sizeof (gus_info)); return 0; break; @@ -918,7 +1100,7 @@ return gus_mem_size - free_mem_ptr - 32; default: - return -EINVAL; + return -(EINVAL); } } @@ -928,10 +1110,10 @@ int sample_no; if (instr_no < 0 || instr_no > MAX_PATCH) - return -EINVAL; + return -(EINVAL); if (voice < 0 || voice > 31) - return -EINVAL; + return -(EINVAL); if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { @@ -945,14 +1127,14 @@ if (sample_no == NOT_SAMPLE) { printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return -EINVAL; /* Patch not defined */ + return -(EINVAL); /* Patch not defined */ } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ { printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); - return -EINVAL; + return -(EINVAL); } sample_map[voice] = sample_no; @@ -1206,7 +1388,7 @@ if (voice < 0 || voice > 31) { printk ("GUS: Invalid voice\n"); - return -EINVAL; + return -(EINVAL); } if (note_num == 255) @@ -1224,12 +1406,12 @@ if ((patch = patch_map[voice]) == -1) { - return -EINVAL; + return -(EINVAL); } if ((samplep = patch_table[patch]) == NOT_SAMPLE) { - return -EINVAL; + return -(EINVAL); } note_freq = note_to_freq (note_num); @@ -1343,10 +1525,10 @@ if (samples[sample].mode & WAVE_LOOP_BACK) gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, is16bits); /* start=end */ + voices[voice].offset_pending, 0, is16bits); /* start=end */ else gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - is16bits); /* Sample start=begin */ + 0, is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) { @@ -1359,13 +1541,16 @@ { gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].loop_end - - voices[voice].offset_pending, is16bits); + voices[voice].offset_pending, + (samples[sample].fractions >> 4) & 0x0f, is16bits); mode |= 0x40; } gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, + samples[sample].fractions & 0x0f, is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ } else @@ -1374,8 +1559,9 @@ voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ voices[voice].loop_irq_parm = 1; gus_write_addr (0x02, sample_ptrs[sample], - is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, + 0, is16bits); /* Loop start location */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end - 1, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ } gus_voice_freq (freq); @@ -1435,7 +1621,7 @@ gus_select_voice (voice); /* Reselect the voice (just to be sure) */ } - if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065)) + if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < (unsigned) 2065)) { ret_val = guswave_start_note2 (dev, voice, note_num, volume); } @@ -1474,24 +1660,26 @@ int err; if (gus_busy) - return -EBUSY; + return -(EBUSY); - gus_initialize (); voice_alloc->timestamp = 0; if ((err = DMAbuf_open_dma (gus_devnum)) < 0) { - printk ("GUS: Loading samples without DMA\n"); + /* printk ("GUS: Loading saples without DMA\n"); */ gus_no_dma = 1; /* Upload samples using PIO */ } else gus_no_dma = 0; - dram_sleep_flag.mode = WK_NONE; + dram_sleep_flag.flags = WK_NONE; gus_busy = 1; active_device = GUS_DEV_WAVE; + gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + gus_initialize (); gus_reset (); + gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ return 0; } @@ -1522,13 +1710,13 @@ if (format != GUS_PATCH) { printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; + return -(EINVAL); } if (count < sizeof_patch) { printk ("GUS Error: Patch header too short\n"); - return -EINVAL; + return -(EINVAL); } count -= sizeof_patch; @@ -1536,7 +1724,7 @@ if (free_sample >= MAX_SAMPLE) { printk ("GUS: Sample table full\n"); - return -ENOSPC; + return -(ENOSPC); } /* @@ -1544,14 +1732,14 @@ * been transferred already. */ - memcpy_fromfs (&((char *) &patch)[offs], &((addr)[offs]), sizeof_patch - offs); + memcpy_fromfs (&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs); instr = patch.instr_no; if (instr < 0 || instr > MAX_PATCH) { printk ("GUS: Invalid patch number %d\n", instr); - return -EINVAL; + return -(EINVAL); } if (count < patch.len) @@ -1564,7 +1752,7 @@ if (patch.len <= 0 || patch.len > gus_mem_size) { printk ("GUS: Invalid sample length %d\n", (int) patch.len); - return -EINVAL; + return -(EINVAL); } if (patch.mode & WAVE_LOOPING) @@ -1572,13 +1760,13 @@ if (patch.loop_start < 0 || patch.loop_start >= patch.len) { printk ("GUS: Invalid loop start\n"); - return -EINVAL; + return -(EINVAL); } if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) { printk ("GUS: Invalid loop end\n"); - return -EINVAL; + return -(EINVAL); } } @@ -1594,7 +1782,7 @@ if (patch.len >= GUS_BANK_SIZE) { printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return -ENOSPC; + return -(ENOSPC); } if ((free_mem_ptr / GUS_BANK_SIZE) != @@ -1604,14 +1792,14 @@ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; + return -(ENOSPC); free_mem_ptr = tmp_mem; /* This leaves unusable memory */ } } if ((free_mem_ptr + patch.len) > gus_mem_size) - return -ENOSPC; + return -(ENOSPC); sample_ptrs[free_sample] = free_mem_ptr; @@ -1622,6 +1810,11 @@ if (patch.mode & WAVE_ENVELOPES) patch.mode &= ~WAVE_TREMOLO; + if (!(patch.mode & WAVE_FRACTIONS)) + { + patch.fractions = 0; + } + memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); /* @@ -1641,7 +1834,6 @@ while (left) /* Not completely transferred yet */ { - /* blk_sz = audio_devs[gus_devnum]->buffsize; */ blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; if (blk_sz > left) blk_sz = left; @@ -1658,7 +1850,7 @@ blk_sz = blk_end - target; } - if (gus_pnp_flag || gus_no_dma) + if (gus_no_dma) { /* * For some reason the DMA is not possible. We have to use PIO. @@ -1683,11 +1875,17 @@ unsigned char dma_command; unsigned long flags; + if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) + { + printk ("GUS: DMA buffer == NULL\n"); + return -(EINVAL); + } + /* * OK, move now. First in and then out. */ - memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &((addr)[sizeof_patch + src_offs]), blk_sz); + memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); save_flags (flags); cli (); @@ -1734,22 +1932,22 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - dram_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + dram_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&dram_sleeper); - if (!(dram_sleep_flag.mode & WK_WAKEUP)) + if (!(dram_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - dram_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + dram_sleep_flag.flags |= WK_TIMEOUT; } - dram_sleep_flag.mode &= ~WK_SLEEP; + dram_sleep_flag.flags &= ~WK_SLEEP; }; - if ((dram_sleep_flag.mode & WK_TIMEOUT)) + if ((dram_sleep_flag.flags & WK_TIMEOUT)) printk ("GUS: DMA Transfer timed out\n"); restore_flags (flags); } @@ -1935,11 +2133,11 @@ } static int -gus_sampling_set_speed (int speed) +gus_audio_set_speed (int speed) { if (speed <= 0) - speed = gus_sampling_speed; + speed = gus_audio_speed; if (speed < 4000) speed = 4000; @@ -1947,36 +2145,37 @@ if (speed > 44100) speed = 44100; - gus_sampling_speed = speed; + gus_audio_speed = speed; if (only_read_access) { /* Compute nearest valid recording speed and return it */ - speed = (9878400 / (gus_sampling_speed + 2)) / 16; + /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ + speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; speed = (9878400 / (speed * 16)) - 2; } return speed; } static int -gus_sampling_set_channels (int channels) +gus_audio_set_channels (int channels) { if (!channels) - return gus_sampling_channels; + return gus_audio_channels; if (channels > 2) channels = 2; if (channels < 1) channels = 1; - gus_sampling_channels = channels; + gus_audio_channels = channels; return channels; } static int -gus_sampling_set_bits (int bits) +gus_audio_set_bits (int bits) { if (!bits) - return gus_sampling_bits; + return gus_audio_bits; if (bits != 8 && bits != 16) bits = 8; @@ -1984,70 +2183,70 @@ if (only_8_bits) bits = 8; - gus_sampling_bits = bits; + gus_audio_bits = bits; return bits; } static int -gus_sampling_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +gus_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) - return gus_sampling_set_speed ((int) arg); - return snd_ioctl_return ((int *) arg, gus_sampling_set_speed (get_fs_long ((long *) arg))); + return gus_audio_set_speed ((int) arg); + return snd_ioctl_return ((int *) arg, gus_audio_set_speed (get_fs_long ((long *) arg))); break; case SOUND_PCM_READ_RATE: if (local) - return gus_sampling_speed; - return snd_ioctl_return ((int *) arg, gus_sampling_speed); + return gus_audio_speed; + return snd_ioctl_return ((int *) arg, gus_audio_speed); break; case SNDCTL_DSP_STEREO: if (local) - return gus_sampling_set_channels ((int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg) + 1) - 1); + return gus_audio_set_channels ((int) arg + 1) - 1; + return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_fs_long ((long *) arg) + 1) - 1); break; case SOUND_PCM_WRITE_CHANNELS: if (local) - return gus_sampling_set_channels ((int) arg); - return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg))); + return gus_audio_set_channels ((int) arg); + return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_fs_long ((long *) arg))); break; case SOUND_PCM_READ_CHANNELS: if (local) - return gus_sampling_channels; - return snd_ioctl_return ((int *) arg, gus_sampling_channels); + return gus_audio_channels; + return snd_ioctl_return ((int *) arg, gus_audio_channels); break; case SNDCTL_DSP_SETFMT: if (local) - return gus_sampling_set_bits ((int) arg); - return snd_ioctl_return ((int *) arg, gus_sampling_set_bits (get_fs_long ((long *) arg))); + return gus_audio_set_bits ((int) arg); + return snd_ioctl_return ((int *) arg, gus_audio_set_bits (get_fs_long ((long *) arg))); break; case SOUND_PCM_READ_BITS: if (local) - return gus_sampling_bits; - return snd_ioctl_return ((int *) arg, gus_sampling_bits); + return gus_audio_bits; + return snd_ioctl_return ((int *) arg, gus_audio_bits); case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - return snd_ioctl_return ((int *) arg, -EINVAL); + return snd_ioctl_return ((int *) arg, -(EINVAL)); break; case SOUND_PCM_READ_FILTER: - return snd_ioctl_return ((int *) arg, -EINVAL); + return snd_ioctl_return ((int *) arg, -(EINVAL)); break; } - return -EINVAL; + return -(EINVAL); } static void -gus_sampling_reset (int dev) +gus_audio_reset (int dev) { if (recording_active) { @@ -2057,11 +2256,16 @@ } static int -gus_sampling_open (int dev, int mode) +gus_audio_open (int dev, int mode) { if (gus_busy) - return -EBUSY; + return -(EBUSY); + if (gus_pnp_flag && mode & OPEN_READ) + { + printk ("Sound: This audio device doesn't have recording capability\n"); + return -(EIO); + } gus_initialize (); gus_busy = 1; @@ -2090,7 +2294,7 @@ } static void -gus_sampling_close (int dev) +gus_audio_close (int dev) { gus_reset (); gus_busy = 0; @@ -2107,13 +2311,13 @@ } static void -gus_sampling_update_volume (void) +gus_audio_update_volume (void) { unsigned long flags; int voice; if (pcm_active && pcm_opened) - for (voice = 0; voice < gus_sampling_channels; voice++) + for (voice = 0; voice < gus_audio_channels; voice++) { save_flags (flags); cli (); @@ -2129,7 +2333,7 @@ play_next_pcm_block (void) { unsigned long flags; - int speed = gus_sampling_speed; + int speed = gus_audio_speed; int this_one, is16bits, chn; unsigned long dram_loc; unsigned char mode[2], ramp_mode[2]; @@ -2139,7 +2343,7 @@ this_one = pcm_head; - for (chn = 0; chn < gus_sampling_channels; chn++) + for (chn = 0; chn < gus_audio_channels; chn++) { mode[chn] = 0x00; ramp_mode[chn] = 0x03; /* Ramping and rollover off */ @@ -2150,7 +2354,7 @@ voices[chn].loop_irq_mode = LMODE_PCM; } - if (gus_sampling_bits != 8) + if (gus_audio_bits != 8) { is16bits = 1; mode[chn] |= 0x04; /* 16 bit data */ @@ -2177,7 +2381,7 @@ gus_select_voice (chn); gus_voice_freq (speed); - if (gus_sampling_channels == 1) + if (gus_audio_channels == 1) gus_voice_balance (7); /* mono */ else if (chn == 0) gus_voice_balance (0); /* left */ @@ -2198,17 +2402,17 @@ gus_voice_volume (1530 + (25 * gus_pcm_volume)); gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - gus_write_addr (0x0a, dram_loc, is16bits); /* Starting position */ - gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */ + gus_write_addr (0x0a, dram_loc, 0, is16bits); /* Starting position */ + gus_write_addr (0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ if (chn != 0) gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - is16bits); /* Loop end location */ + 0, is16bits); /* Loop end location */ } if (chn == 0) gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, - is16bits); /* Loop end location */ + 0, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ @@ -2227,7 +2431,7 @@ else { gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], - is16bits); /* Loop end location */ + 0, is16bits); /* Loop end location */ mode[chn] &= ~0x08; /* Disable looping */ } } @@ -2235,7 +2439,7 @@ restore_flags (flags); } - for (chn = 0; chn < gus_sampling_channels; chn++) + for (chn = 0; chn < gus_audio_channels; chn++) { save_flags (flags); cli (); @@ -2269,7 +2473,7 @@ save_flags (flags); cli (); - count = total_count / gus_sampling_channels; + count = total_count / gus_audio_channels; if (chn == 0) { @@ -2302,7 +2506,7 @@ dma_command = 0x21; /* IRQ enable, DMA start */ - if (gus_sampling_bits != 8) + if (gus_audio_bits != 8) dma_command |= 0x40; /* 16 bit _DATA_ */ else dma_command |= 0x80; /* Invert MSB */ @@ -2312,7 +2516,7 @@ gus_write8 (0x41, dma_command); /* Kickstart */ - if (chn == (gus_sampling_channels - 1)) /* Last channel */ + if (chn == (gus_audio_channels - 1)) /* Last channel */ { /* * Last (right or mono) channel data @@ -2337,8 +2541,8 @@ } static void -gus_sampling_output_block (int dev, unsigned long buf, int total_count, - int intrflag, int restart_dma) +gus_audio_output_block (int dev, unsigned long buf, int total_count, + int intrflag, int restart_dma) { pcm_current_buf = buf; pcm_current_count = total_count; @@ -2348,8 +2552,8 @@ } static void -gus_sampling_start_input (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +gus_audio_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; unsigned char mode; @@ -2363,7 +2567,7 @@ if (audio_devs[dev]->dmachan2 > 3) mode |= 0x04; /* 16 bit DMA channel */ - if (gus_sampling_channels > 1) + if (gus_audio_channels > 1) mode |= 0x02; /* Stereo */ mode |= 0x01; /* DMA enable */ @@ -2373,37 +2577,37 @@ } static int -gus_sampling_prepare_for_input (int dev, int bsize, int bcount) +gus_audio_prepare_for_input (int dev, int bsize, int bcount) { unsigned int rate; - rate = (9878400 / (gus_sampling_speed + 2)) / 16; + rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ - if (gus_sampling_bits != 8) + if (gus_audio_bits != 8) { printk ("GUS Error: 16 bit recording not supported\n"); - return -EINVAL; + return -(EINVAL); } return 0; } static int -gus_sampling_prepare_for_output (int dev, int bsize, int bcount) +gus_audio_prepare_for_output (int dev, int bsize, int bcount) { int i; long mem_ptr, mem_size; mem_ptr = 0; - mem_size = gus_mem_size / gus_sampling_channels; + mem_size = gus_mem_size / gus_audio_channels; if (mem_size > (256 * 1024)) mem_size = 256 * 1024; - pcm_bsize = bsize / gus_sampling_channels; + pcm_bsize = bsize / gus_audio_channels; pcm_head = pcm_tail = pcm_qlen = 0; pcm_nblk = MAX_PCM_BUFFERS; @@ -2415,7 +2619,7 @@ pcm_banksize = pcm_nblk * pcm_bsize; - if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024)) + if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) pcm_nblk--; return 0; @@ -2431,11 +2635,11 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs, const char *userbuf, int useroffs, int len) { - if (gus_sampling_channels == 1) + if (gus_audio_channels == 1) { - memcpy_fromfs (&localbuf[localoffs], &((userbuf)[useroffs]), len); + memcpy_fromfs (&localbuf[localoffs], &(userbuf)[useroffs], len); } - else if (gus_sampling_bits == 8) + else if (gus_audio_bits == 8) { int in_left = useroffs; int in_right = useroffs + 1; @@ -2444,7 +2648,7 @@ len /= 2; localoffs /= 2; - out_left = &localbuf[localoffs]; + out_left = localbuf + localoffs; out_right = out_left + pcm_bsize; for (i = 0; i < len; i++) @@ -2465,7 +2669,7 @@ len /= 4; localoffs /= 4; - out_left = (short *) &localbuf[localoffs]; + out_left = ((short *) localbuf) + localoffs; out_right = out_left + (pcm_bsize / 2); for (i = 0; i < len; i++) @@ -2478,23 +2682,28 @@ } } -static struct audio_operations gus_sampling_operations = +static struct audio_driver gus_audio_driver = +{ + gus_audio_open, + gus_audio_close, + gus_audio_output_block, + gus_audio_start_input, + gus_audio_ioctl, + gus_audio_prepare_for_input, + gus_audio_prepare_for_output, + gus_audio_reset, + gus_audio_reset, + gus_local_qlen, + gus_copy_from_user +}; + +static struct audio_operations gus_audio_operations = { "Gravis UltraSound", NEEDS_RESTART, AFMT_U8 | AFMT_S16_LE, NULL, - gus_sampling_open, - gus_sampling_close, - gus_sampling_output_block, - gus_sampling_start_input, - gus_sampling_ioctl, - gus_sampling_prepare_for_input, - gus_sampling_prepare_for_output, - gus_sampling_reset, - gus_sampling_reset, - gus_local_qlen, - gus_copy_from_user + &gus_audio_driver }; static void @@ -2508,7 +2717,7 @@ voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just msb */ voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; + (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; voices[voice].bender = info->bender_value; @@ -2589,7 +2798,7 @@ struct patch_info *pat; if (ptr < 0 || ptr >= free_sample) - return -EINVAL; + return -(EINVAL); memcpy (rec->data.data8, (char *) &samples[ptr], sizeof (struct patch_info)); @@ -2609,12 +2818,12 @@ struct patch_info *pat; if (ptr < 0 || ptr >= free_sample) - return -EINVAL; + return -(EINVAL); pat = (struct patch_info *) rec->data.data8; if (pat->len > samples[ptr].len) /* Cannot expand sample */ - return -EINVAL; + return -(EINVAL); pat->key = samples[ptr].key; /* Ensure the link is correct */ @@ -2634,10 +2843,10 @@ int l = rec->parm3; if (sample < 0 || sample >= free_sample) - return -EINVAL; + return -(EINVAL); if (offs < 0 || offs >= samples[sample].len) - return -EINVAL; /* Invalid offset */ + return -(EINVAL); /* Invalid offset */ n = samples[sample].len - offs; /* Num of bytes left */ @@ -2648,12 +2857,12 @@ l = sizeof (rec->data.data8); if (l <= 0) - return -EINVAL; /* + return -(EINVAL); /* * Was there a bug? */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) @@ -2675,10 +2884,10 @@ int l = rec->parm3; if (sample < 0 || sample >= free_sample) - return -EINVAL; + return -(EINVAL); if (offs < 0 || offs >= samples[sample].len) - return -EINVAL; /* + return -(EINVAL); /* * Invalid offset */ @@ -2693,12 +2902,12 @@ l = sizeof (rec->data.data8); if (l <= 0) - return -EINVAL; /* + return -(EINVAL); /* * Was there a bug? */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) @@ -2711,7 +2920,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -2878,7 +3087,7 @@ gus_pcm_volume = 0; if (gus_pcm_volume > 100) gus_pcm_volume = 100; - gus_sampling_update_volume (); + gus_audio_update_volume (); return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8)); break; @@ -2902,7 +3111,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } else switch (cmd & 0xff) /* @@ -2947,21 +3156,22 @@ break; default: - return -EINVAL; + return -(EINVAL); } } else - return -EINVAL; + return -(EINVAL); } static struct mixer_operations gus_mixer_operations = { + "GUS", "Gravis Ultrasound", gus_default_mixer_ioctl }; -static long -gus_default_mixer_init (long mem_start) +static void +gus_default_mixer_init (void) { if (num_mixers < MAX_MIXER_DEV) /* * Don't install if there is another @@ -2979,11 +3189,10 @@ mix_image |= 0x04; /* All channels enabled */ outb (mix_image, u_Mixer); } - return mem_start; } -long -gus_wave_init (long mem_start, struct address_info *hw_config) +void +gus_wave_init (struct address_info *hw_config) { unsigned long flags; unsigned char val; @@ -2996,13 +3205,13 @@ if (irq < 0 || irq > 15) { printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return mem_start; + return; } if (dma < 0 || dma > 7 || dma == 4) { printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return mem_start; + return; } gus_irq = irq; @@ -3018,18 +3227,36 @@ * Versions < 3.6 don't have the digital ASIC. Try to probe it first. */ +#ifdef GUSPNP_AUTODETECT + val = gus_look8 (0x5b); /* Version number register */ + gus_write8 (0x5b, ~val); /* Invert all bits */ + + if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0)) /* No change */ + if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ + { + DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); + gus_pnp_flag = 1; + } + else + { + DDB (printk ("Not an Interwave chip\n")); + gus_pnp_flag = 0; + } + gus_write8 (0x5b, val); /* Restore all bits */ +#endif + save_flags (flags); cli (); outb (0x20, gus_base + 0x0f); val = inb (gus_base + 0x0f); restore_flags (flags); -#ifndef GUSPNP_NO_AUTODETECT - gus_pnp_flag = (val == 1); -#endif - if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ { + int ad_flags = 0; + + if (gus_pnp_flag) + ad_flags = 0x12345678; /* Interwave "magic" */ /* * It has the digital ASIC so the card is at least v3.4. * Next try to detect the true model. @@ -3082,13 +3309,17 @@ outb (max_config, gus_base + 0x106); /* UltraMax control */ } - if (ad1848_detect (gus_base + 0x10c, NULL, hw_config->osp)) + if (ad1848_detect (gus_base + 0x10c, &ad_flags, hw_config->osp)) { + char *name = "GUS MAX"; gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; gus_wave_volume = 90; have_gus_max = 1; - ad1848_init ("GUS MAX", gus_base + 0x10c, + if (hw_config->name) + name = hw_config->name; + + ad1848_init (name, gus_base + 0x10c, -irq, gus_dma2, /* Playback DMA */ gus_dma, /* Capture DMA */ @@ -3123,13 +3354,13 @@ sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); - samples = (struct patch_info *) (sound_mem_blocks[sound_num_blocks] = kmalloc ((MAX_SAMPLE + 1) * sizeof (*samples), GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc ((MAX_SAMPLE + 1) * sizeof (*samples))); + if (sound_nblocks < 1024) + sound_nblocks++;; if (samples == NULL) { - printk ("GUS Error: Can't allocate memory for instrument tables\n"); - return mem_start; + printk ("GUS Error: Cant allocate memory for instrument tables\n"); + return; } conf_printf (gus_info.name, hw_config); @@ -3151,10 +3382,13 @@ if (num_audiodevs < MAX_AUDIO_DEV) { - audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations; + audio_devs[gus_devnum = num_audiodevs++] = &gus_audio_operations; audio_devs[gus_devnum]->dmachan1 = dma; audio_devs[gus_devnum]->dmachan2 = dma2; audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE; + audio_devs[gus_devnum]->min_fragment = 9; + audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */ + audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; if (dma2 != dma && dma2 != -1) audio_devs[gus_devnum]->flags |= DMA_DUPLEX; } @@ -3171,12 +3405,14 @@ gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; gus_wave_volume = 90; request_region (u_MixSelect, 1, "GUS mixer"); - return ics2101_mixer_init (mem_start); + ics2101_mixer_init (); + return; case CS4231: /* Initialized elsewhere (ad1848.c) */ default: - return gus_default_mixer_init (mem_start); + gus_default_mixer_init (); + return; } } @@ -3412,9 +3648,9 @@ switch (active_device) { case GUS_DEV_WAVE: - if ((dram_sleep_flag.mode & WK_SLEEP)) + if ((dram_sleep_flag.flags & WK_SLEEP)) { - dram_sleep_flag.mode = WK_WAKEUP; + dram_sleep_flag.flags = WK_WAKEUP; module_wake_up (&dram_sleeper); }; break; diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.0.0/linux/drivers/sound/ics2101.c Sun Mar 24 22:50:04 1996 +++ linux/drivers/sound/ics2101.c Sun Jun 30 11:44:01 1996 @@ -4,27 +4,11 @@ * Driver for the ICS2101 mixer of GUS v3.7. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -164,7 +148,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } else switch (cmd & 0xff) /* @@ -213,21 +197,22 @@ break; default: - return -EINVAL; + return -(EINVAL); } } - return -EINVAL; + return -(EINVAL); } static struct mixer_operations ics2101_mixer_operations = { + "ICS2101", "ICS2101 Multimedia Mixer", ics2101_mixer_ioctl }; -long -ics2101_mixer_init (long mem_start) +void +ics2101_mixer_init (void) { int i; @@ -256,7 +241,6 @@ set_volumes (DEV_UNUSED, 0x0000); } - return mem_start; } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/iwmem.h linux/drivers/sound/iwmem.h --- v2.0.0/linux/drivers/sound/iwmem.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/iwmem.h Sun Jun 30 12:30:15 1996 @@ -0,0 +1,33 @@ +/* + * sound/iwmem.c + * + * DRAM size encoding table for AMD Interwave chip. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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. + */ + + +#define K 1024 +#define M (1024*K) +static int mem_decode[][4] = +{ +/* Bank0 Bank1 Bank2 Bank3 Encoding bits */ + {256*K, 0, 0, 0}, /* 0 */ + {256*K, 256*K, 0, 0}, /* 1 */ + {256*K, 256*K, 256*K, 256*K}, /* 2 */ + {256*K, 1*M, 0, 0}, /* 3 */ + {256*K, 1*M, 1*M, 1*M}, /* 4 */ + {256*K, 256*K, 1*M, 0}, /* 5 */ + {256*K, 256*K, 1*M, 1*M}, /* 6 */ + {1*M, 0, 0, 0}, /* 7 */ + {1*M, 1*M, 0, 0}, /* 8 */ + {1*M, 1*M, 1*M, 1*M}, /* 9 */ + {4*M, 0, 0, 0}, /* 10 */ + {4*M, 4*M, 0, 0}, /* 11 */ + {4*M, 4*M, 4*M, 4*M} /* 12 */ +}; diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/Config.tmpl linux/drivers/sound/lowlevel/Config.tmpl --- v2.0.0/linux/drivers/sound/lowlevel/Config.tmpl Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/lowlevel/Config.tmpl Thu May 16 11:05:56 1996 @@ -0,0 +1,5 @@ +bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND + +if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then + bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER +fi diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/Makefile linux/drivers/sound/lowlevel/Makefile --- v2.0.0/linux/drivers/sound/lowlevel/Makefile Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/lowlevel/Makefile Thu May 16 11:05:57 1996 @@ -0,0 +1,19 @@ +all: lowlevel.o + +OBJS = init.o + +ifdef CONFIG_LOWLEVEL_SOUND +ifdef CONFIG_ACI_MIXER +OBJS := $(OBJS) aci.o +endif +endif + +lowlevel.o: $(OBJS) + ld -r -o lowlevel.o $(OBJS) + +clean: + rm -f core x y z *~ *.o + +ifdef HOSTCC +include $(TOPDIR)/Rules.make +endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/README linux/drivers/sound/lowlevel/README --- v2.0.0/linux/drivers/sound/lowlevel/README Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/lowlevel/README Thu May 16 11:09:13 1996 @@ -0,0 +1,13 @@ +Additional low level sound drivers for Linux +-------------------------------------------- + +This directory contains additional low level sound drivers which +are not part of USS/Lite (UNIX Sound System). These drivers are +maintained by their authors. + +If you like to write a low level sound driver, please contact +Hannu Savolainen (hannu@voxware.pp.fi) for more info. + +The following low level drivers are included: + +- ACI MIXER for miroPCM12 by Markus Kuhn. See aci.readme for more info. diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c --- v2.0.0/linux/drivers/sound/lowlevel/aci.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/lowlevel/aci.c Tue May 28 21:48:45 1996 @@ -0,0 +1,590 @@ +/* + * Audio Command Interface (ACI) driver (sound/aci.c) + * + * ACI is a protocol used to communicate with the microcontroller on + * some sound cards produced by miro, e.g. the miroSOUND PCM12 and + * PCM20. The ACI has been developed for miro by Norberto Pellicci + * . Special thanks to both him and miro for + * providing the ACI specification. + * + * The main function of the ACI is to control the mixer and to get a + * product identification. On the PCM20, ACI also controls the radio + * tuner on this card, however this is not yet supported in this + * software. + * + * This Voxware ACI driver currently only supports the ACI functions + * on the miroSOUND PCM12 card. Support for miro soundcards with + * additional ACI functions can easily be added later. + * + * Revision history: + * + * 1995-11-10 Markus Kuhn + * First version written. + * 1995-12-31 Markus Kuhn + * Second revision, general code cleanup. + * 1996-05-16 Hannu Savolainen + * Integrated with other parts of the driver. + * 1996-05-28 Markus Kuhn + * Initialize CS4231A mixer, make ACI first mixer, + * use new private mixer API for solo mode. + */ + +/* + * Some driver specific information and features: + * + * This mixer driver identifies itself to applications as "ACI" in + * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info). + * + * Proprietary mixer features that go beyond the standard USS mixer + * interface are: + * + * Full duplex solo configuration: + * + * int solo_mode; + * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode); + * + * solo_mode = 0: deactivate solo mode (default) + * solo_mode > 0: activate solo mode + * With activated solo mode, the PCM input can not any + * longer hear the signals produced by the PCM output. + * Activating solo mode is important in duplex mode in order + * to avoid feedback distortions. + * solo_mode < 0: do not change solo mode (just retrieve the status) + * + * When the ioctl() returns 0, solo_mode contains the previous + * status (0 = deactivated, 1 = activated). If solo mode is not + * implemented on this card, ioctl() returns -1 and sets errno to + * EINVAL. + * + */ + +#include "../sound_config.h" +#ifdef CONFIG_ACI_MIXER + +#undef DEBUG /* if defined, produce a verbose report via syslog */ + +int aci_port = 0x354; /* as determined by bit 4 in the Opti 929 MC4 register */ +unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */ +unsigned char aci_version = 0; /* ACI firmware version */ +int aci_solo; /* status bit of the card that can't be * + * checked with ACI versions prior to 0xb0 */ + +static int aci_present = 0; + +#define COMMAND_REGISTER (aci_port) +#define STATUS_REGISTER (aci_port + 1) +#define BUSY_REGISTER (aci_port + 2) + +/* + * Wait until the ACI microcontroller has set the READYFLAG in the + * Busy/IRQ Source Register to 0. This is required to avoid + * overrunning the soundcard microcontroller. We do a busy wait here, + * because the microcontroller is not supposed to signal a busy + * condition for more than a few clock cycles. In case of a time-out, + * this function returns -1. + * + * This busy wait code normally requires less than 15 loops and + * practically always less than 100 loops on my i486/DX2 66 MHz. + * + * Warning: Waiting on the general status flag after reseting the MUTE + * function can take a VERY long time, because the PCM12 does some kind + * of fade-in effect. For this reason, access to the MUTE function has + * not been implemented at all. + */ + +static int busy_wait(void) +{ + long timeout; + + for (timeout = 0; timeout < 10000000L; timeout++) + if ((inb_p(BUSY_REGISTER) & 1) == 0) + return 0; + +#ifdef DEBUG + printk("ACI: READYFLAG timed out.\n"); +#endif + + return -1; +} + + +/* + * Read the GENERAL STATUS register. + */ + +static int read_general_status(void) +{ + unsigned long flags; + int status; + + save_flags(flags); + cli(); + if (busy_wait()) { restore_flags(flags); return -1; } + status = (unsigned) inb_p(STATUS_REGISTER); + restore_flags(flags); + return status; +} + + +/* + * The four ACI command types (implied, write, read and indexed) can + * be sent to the microcontroller using the following four functions. + * If a problem occured, they return -1. + */ + +static int implied_cmd(unsigned char opcode) +{ + unsigned long flags; + +#ifdef DEBUG + printk("ACI: implied_cmd(0x%02x)\n", opcode); +#endif + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + + restore_flags(flags); + return 0; +} + + +static int write_cmd(unsigned char opcode, unsigned char parameter) +{ + unsigned long flags; + int status; + +#ifdef DEBUG + printk("ACI: write_cmd(0x%02x, 0x%02x)\n", opcode, parameter); +#endif + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(parameter, COMMAND_REGISTER); + + if ((status = read_general_status()) < 0) { + restore_flags(flags); + return -1; + } + /* polarity of the INVALID flag depends on ACI version */ + if ((aci_version < 0xb0 && (status & 0x40) != 0) || + (aci_version >= 0xb0 && (status & 0x40) == 0)) { + restore_flags(flags); + printk("ACI: invalid write command 0x%02x, 0x%02x.\n", + opcode, parameter); + return -1; + } + + restore_flags(flags); + return 0; +} + + +static int read_cmd(unsigned char opcode, int length, unsigned char *parameter) +{ + unsigned long flags; + int i = 0; + + save_flags(flags); + cli(); + + if (read_general_status() < 0) { restore_flags(flags); return -1; } + while (i < length) { + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + parameter[i++] = inb_p(STATUS_REGISTER); +#ifdef DEBUG + if (i == 1) + printk("ACI: read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length, + parameter[i-1]); + else + printk("ACI: read_cmd cont.: 0x%02x\n", parameter[i-1]); +#endif + } + + restore_flags(flags); + return 0; +} + + +static int indexed_cmd(unsigned char opcode, unsigned char index, + unsigned char *parameter) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(index, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + *parameter = inb_p(STATUS_REGISTER); +#ifdef DEBUG + printk("ACI: indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index, + *parameter); +#endif + + restore_flags(flags); + return 0; +} + + +/* + * The following macro SCALE can be used to scale one integer volume + * value into another one using only integer arithmetic. If the input + * value x is in the range 0 <= x <= xmax, then the result will be in + * the range 0 <= SCALE(xmax,ymax,x) <= ymax. + * + * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the + * following nice properties: + * + * - SCALE(xmax,ymax,xmax) = ymax + * - SCALE(xmax,ymax,0) = 0 + * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) + * + * In addition, the rounding error is minimal and nicely distributed. + * The proofs are left as an exercise to the reader. + */ + +#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax)) + + +static int getvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) +{ + int vol; + unsigned char buf; + + /* left channel */ + if (indexed_cmd(0xf0, left_index, &buf)) return -EIO; + vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); + /* right channel */ + if (indexed_cmd(0xf0, right_index, &buf)) return -EIO; + vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; + + return snd_ioctl_return((int *) arg, vol); +} + + +static int setvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) +{ + int vol, ret; + unsigned param; + + param = get_user((int *) arg); + /* left channel */ + vol = param & 0xff; + if (vol > 100) vol = 100; + vol = SCALE(100, 0x20, vol); + if (write_cmd(left_index, 0x20 - vol)) return -EIO; + ret = SCALE(0x20, 100, vol); + /* right channel */ + vol = (param >> 8) & 0xff; + if (vol > 100) vol = 100; + vol = SCALE(100, 0x20, vol); + if (write_cmd(right_index, 0x20 - vol)) return -EIO; + ret |= SCALE(0x20, 100, vol) << 8; + + return snd_ioctl_return((int *) arg, ret); +} + + +static int +aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + int status, vol; + unsigned char buf; + + /* handle solo mode control */ + if (cmd == SOUND_MIXER_PRIVATE1) { + if (get_user((int *) arg) >= 0) { + aci_solo = !!get_user((int *) arg); + if (write_cmd(0xd2, aci_solo)) return -EIO; + } else if (aci_version >= 0xb0) { + if ((status = read_general_status()) < 0) return -EIO; + return snd_ioctl_return ((int *) arg, (status & 0x20) == 0); + } + return snd_ioctl_return((int *) arg, aci_solo); + } + + if (((cmd >> 8) & 0xff) == 'M') { + if (cmd & IOC_IN) + /* read and write */ + switch (cmd & 0xff) { + case SOUND_MIXER_VOLUME: + return setvolume(arg, 0x01, 0x00); + case SOUND_MIXER_CD: + return setvolume(arg, 0x3c, 0x34); + case SOUND_MIXER_MIC: + return setvolume(arg, 0x38, 0x30); + case SOUND_MIXER_LINE: + return setvolume(arg, 0x39, 0x31); + case SOUND_MIXER_SYNTH: + return setvolume(arg, 0x3b, 0x33); + case SOUND_MIXER_PCM: + return setvolume(arg, 0x3a, 0x32); + case SOUND_MIXER_LINE1: /* AUX1 */ + return setvolume(arg, 0x3d, 0x35); + case SOUND_MIXER_LINE2: /* AUX2 */ + return setvolume(arg, 0x3e, 0x36); + case SOUND_MIXER_IGAIN: /* MIC pre-amp */ + vol = get_user((int *) arg) & 0xff; + if (vol > 100) vol = 100; + vol = SCALE(100, 3, vol); + if (write_cmd(0x03, vol)) return -EIO; + vol = SCALE(3, 100, vol); + return snd_ioctl_return((int *) arg, vol | (vol << 8)); + case SOUND_MIXER_RECSRC: + return snd_ioctl_return ((int *) arg, 0); + break; + default: + return -EINVAL; + } + else + /* only read */ + switch (cmd & 0xff) { + case SOUND_MIXER_DEVMASK: + return snd_ioctl_return ((int *) arg, + SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | +#if 0 + SOUND_MASK_IGAIN | +#endif + SOUND_MASK_LINE1 | SOUND_MASK_LINE2); + break; + case SOUND_MIXER_STEREODEVS: + return snd_ioctl_return ((int *) arg, + SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | + SOUND_MASK_LINE1 | SOUND_MASK_LINE2); + break; + case SOUND_MIXER_RECMASK: + return snd_ioctl_return ((int *) arg, 0); + break; + case SOUND_MIXER_RECSRC: + return snd_ioctl_return ((int *) arg, 0); + break; + case SOUND_MIXER_CAPS: + return snd_ioctl_return ((int *) arg, 0); + break; + case SOUND_MIXER_VOLUME: + return getvolume(arg, 0x04, 0x03); + case SOUND_MIXER_CD: + return getvolume(arg, 0x0a, 0x09); + case SOUND_MIXER_MIC: + return getvolume(arg, 0x06, 0x05); + case SOUND_MIXER_LINE: + return getvolume(arg, 0x08, 0x07); + case SOUND_MIXER_SYNTH: + return getvolume(arg, 0x0c, 0x0b); + case SOUND_MIXER_PCM: + return getvolume(arg, 0x0e, 0x0d); + case SOUND_MIXER_LINE1: /* AUX1 */ + return getvolume(arg, 0x11, 0x10); + case SOUND_MIXER_LINE2: /* AUX2 */ + return getvolume(arg, 0x13, 0x12); + case SOUND_MIXER_IGAIN: /* MIC pre-amp */ + if (indexed_cmd(0xf0, 0x21, &buf)) return -EIO; + vol = SCALE(3, 100, buf <= 3 ? buf : 3); + vol |= vol << 8; + return snd_ioctl_return((int *) arg, vol); + default: + return -EINVAL; + } + } + + return -EINVAL; +} + + +static struct mixer_operations aci_mixer_operations = +{ + "ACI", + "ACI mixer", + aci_mixer_ioctl, + NULL +}; + +static unsigned char +mad_read (int port) +{ + outb (0xE3, 0xf8f); /* Write MAD16 password */ + return inb (port); /* Read from port */ +} + + +/* + * Check, whether there actually is any ACI port operational and if + * one was found, then initialize the ACI interface, reserve the I/O + * addresses and attach the new mixer to the relevant VoxWare data + * structures. + * + * Returns: 1 ACI mixer detected + * 0 nothing there + * + * There is also an internal mixer in the codec (CS4231A or AD1845), + * that deserves no purpose in an ACI based system which uses an + * external ACI controlled stereo mixer. Make sure that this codec + * mixer has the AUX1 input selected as the recording source, that the + * input gain is set near maximum and that the other channels going + * from the inputs to the codec output are muted. + */ + +int attach_aci(void) +{ + char *boardname = "unknown"; + int volume; + +#define MC4_PORT 0xf90 + + aci_port = + (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354; + + if (check_region(aci_port, 3)) { +#ifdef DEBUG + printk("ACI: I/O area 0x%03x-0x%03x already used.\n", + aci_port, aci_port+2); +#endif + return 0; + } + + if (read_cmd(0xf2, 2, aci_idcode)) { +#ifdef DEBUG + printk("ACI: Failed to read idcode.\n"); +#endif + return 0; + } + if (read_cmd(0xf1, 1, &aci_version)) { +#ifdef DEBUG + printk("ACI: Failed to read version.\n"); +#endif + return 0; + } + + if (aci_idcode[0] == 0x6d) { + /* it looks like a miro soundcard */ + switch (aci_idcode[1]) { + case 0x41: + boardname = "PCM1 pro / early PCM12"; + break; + case 0x42: + boardname = "PCM12"; + break; + case 0x43: + boardname = "PCM20"; + break; + default: + boardname = "unknown miro"; + } + } else +#ifndef DEBUG + return 0; +#endif + + printk(" at 0x%03x\n", + aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port); + + /* initialize ACI mixer */ + implied_cmd(0xff); + aci_solo = 0; + + /* attach the mixer */ + request_region(aci_port, 3, "sound mixer (ACI)"); + if (num_mixers < MAX_MIXER_DEV) { + if (num_mixers > 0 && + !strcmp("MAD16 WSS (CS4231A)", mixer_devs[num_mixers-1]->name)) { + /* + * The previously registered mixer device is the CS4231A which + * has no function on an ACI card. Make the ACI mixer the first + * of the two mixer devices. + */ + mixer_devs[num_mixers] = mixer_devs[num_mixers-1]; + mixer_devs[num_mixers-1] = &aci_mixer_operations; + /* + * Initialize the CS4231A mixer with reasonable values. It is + * unlikely that the user ever will want to change these as all + * channels can be mixed via ACI. + */ + volume = 0x6464; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); + volume = 0x6464; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume); + volume = SOUND_MASK_LINE1; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume); + num_mixers++; + } else + mixer_devs[num_mixers++] = &aci_mixer_operations; + } + + /* Initialize ACI mixer with reasonable power-up values */ + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); + + aci_present = 1; + + return 1; +} + +void unload_aci(void) +{ + if (aci_present) + release_region(aci_port, 3); +} + +#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/aci.readme linux/drivers/sound/lowlevel/aci.readme --- v2.0.0/linux/drivers/sound/lowlevel/aci.readme Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/lowlevel/aci.readme Thu May 16 11:08:03 1996 @@ -0,0 +1,40 @@ + +ACI mixer driver extension (miroSOUND PCM12) for Linux +------------------------------------------------------ + +Markus Kuhn -- 1995-12-31 + + +This is the ACI mixer driver for the miroSOUND PCM12 soundcard. It +works probably also for other ACI miroSOUND boards like the PCM1 pro +or the PCM20, however this has not been tested. + +Just copy the file aci.c into the /usr/src/linux/drivers/sound/ +subdirectory, then change to the subdirectory /usr/src/linux/drivers/ +and apply with "patch -p0 - Germany +WWW Home: diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/init.c linux/drivers/sound/lowlevel/init.c --- v2.0.0/linux/drivers/sound/lowlevel/init.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/lowlevel/init.c Tue May 28 17:45:17 1996 @@ -0,0 +1,26 @@ +/* + * lowlevel/init.c - Calls initialization code for configured drivers. + */ + +#include + +#ifdef CONFIG_LOWLEVEL_SOUND +extern int attach_aci(void); +extern void unload_aci(void); + +void +sound_init_lowlevel_drivers(void) +{ +#ifdef CONFIG_ACI_MIXER + attach_aci(); +#endif +} + +void +sound_unload_lowlevel_drivers(void) +{ +#ifdef CONFIG_ACI_MIXER + unload_aci(); +#endif +} +#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.0.0/linux/drivers/sound/mad16.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/mad16.c Sun Jun 30 11:44:02 1996 @@ -1,25 +1,9 @@ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -31,9 +15,9 @@ * OPTi 82C928 MAD16 (replaced by C929) * OAK OTI-601D Mozart * OPTi 82C929 MAD16 Pro - * OPTi 82C930 (Not supported yet) + * OPTi 82C930 * - * These audio interface chips don't produce sound themselves. They just + * These audio interface chips don't prduce sound themselves. They just * connect some other components (OPL-[234] and a WSS compatible codec) * to the PC bus and perform I/O, DMA and IRQ address decoding. There is * also a UART for the MPU-401 mode (not 82C928/Mozart). @@ -77,6 +61,8 @@ #if defined(CONFIG_MAD16) +#include "sb.h" + static int already_initialized = 0; #define C928 1 @@ -91,6 +77,9 @@ * All ports are inactive by default. They can be activated by * writing 0xE2 or 0xE3 to the password register. The password is valid * only until the next I/O read or write. + * + * 82C930 uses 0xE4 as the password and indirect addressing to access + * the config registers. */ #define MC0_PORT 0xf8c /* Dummy port */ @@ -136,9 +125,18 @@ outb (0xE3, PASSWD_REG); break; + case C930: + /* outb( 0xE4, PASSWD_REG); */ + break; } - tmp = inb (port); + if (board_type == C930) + { + outb (port - MC0_PORT, 0xe0e); /* Write to index reg */ + tmp = inb (0xe0f); /* Read from data reg */ + } + else + tmp = inb (port); restore_flags (flags); return tmp; @@ -163,13 +161,60 @@ outb (0xE3, PASSWD_REG); break; + case C930: + /* outb( 0xE4, PASSWD_REG); */ + break; } - outb ((unsigned char) (value & 0xff), port); + if (board_type == C930) + { + outb (port - MC0_PORT, 0xe0e); /* Write to index reg */ + outb ((unsigned char) (value & 0xff), 0xe0f); + } + else + outb ((unsigned char) (value & 0xff), port); restore_flags (flags); } static int +detect_c930 (void) +{ + unsigned char tmp = mad_read (MC1_PORT); + + if ((tmp & 0x06) != 0x06) + { + DDB (printk ("Wrong C930 signature (%x)\n", tmp)); + /* return 0; */ + } + + mad_write (MC1_PORT, 0); + + if (mad_read (MC1_PORT) != 0x06) + { + DDB (printk ("Wrong C930 signature2 (%x)\n", tmp)); + /* return 0; */ + } + + mad_write (MC1_PORT, tmp); /* Restore bits */ + + mad_write (MC7_PORT, 0); + if ((tmp = mad_read (MC7_PORT)) != 0) + { + DDB (printk ("MC7 not writeable (%x)\n", tmp)); + return 0; + } + + mad_write (MC7_PORT, 0xcb); + if ((tmp = mad_read (MC7_PORT)) != 0xcb) + { + DDB (printk ("MC7 not writeable2 (%x)\n", tmp)); + return 0; + } + + return 1; +} + +static int detect_mad16 (void) { unsigned char tmp, tmp2; @@ -190,6 +235,8 @@ for (i = 0xf8d; i <= 0xf98; i++) DDB (printk ("Port %0x (init value) = %0x\n", i, mad_read (i))); + if (board_type == C930) + return detect_c930 (); /* * Now check that the gate is closed on first I/O after writing * the password. (This is how a MAD16 compatible card works). @@ -201,7 +248,7 @@ return 0; } - mad_write (MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ + mad_write (MC1_PORT, tmp ^ 0x80); /* Togge a bit */ if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ { mad_write (MC1_PORT, tmp); /* Restore */ @@ -233,7 +280,7 @@ return 0; /* * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTriX Pro for example) + * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00. */ @@ -275,6 +322,57 @@ return 1; } +static int +init_c930 (struct address_info *hw_config) +{ + unsigned char cfg; + + cfg = (mad_read (MC1_PORT) & ~0x30); + /* mad_write(MC1_PORT, 0); */ + + switch (hw_config->io_base) + { + case 0x530: + cfg |= 0x00; + break; + case 0xe80: + cfg |= 0x10; + break; + case 0xf40: + cfg |= 0x20; + break; + case 0x604: + cfg |= 0x30; + break; + + default: + printk ("MAD16: Invalid codec port %x\n", hw_config->io_base); + return 0; + } + mad_write (MC1_PORT, cfg); + + /* MC2 is CD configuration. Don't touch it. */ + + mad_write (MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ + + mad_write (MC4_PORT, 0x52); /* ??? */ + mad_write (MC5_PORT, 0x3D); /* Init it into mode2 */ + mad_write (MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ + mad_write (MC7_PORT, 0xCB); + mad_write (MC10_PORT, 0x11); + + if (!wss_init (hw_config)) + return 0; + +/* + * A temporarary kludge which drops the device back to mode1. + * This removes problems with interrupts but disables full duplex. + * A better solution should be introduced later. + */ + mad_write (MC5_PORT, 0x1D); /* Disable mode2 */ + return wss_init (hw_config); +} + int probe_mad16 (struct address_info *hw_config) { @@ -313,7 +411,28 @@ if (!detect_mad16 ()) { - return 0; + if (inb (PASSWD_REG) != 0xff) + return 0; + +/* + * First relocate MC# registers to 0xe0e/0xe0f, disable password + */ + + outb (0xE4, PASSWD_REG); + outb (0x80, PASSWD_REG); + + board_type = C930; + + DDB (printk ("Detect using password = 0xE4\n")); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB (printk ("port %03x = %02x\n", i, mad_read (i))); + + if (!detect_mad16 ()) + return 0; + + DDB (printk ("mad16.c: 82C930 detected\n")); + return init_c930 (hw_config); } else { @@ -408,8 +527,8 @@ return 1; } -long -attach_mad16 (long mem_start, struct address_info *hw_config) +void +attach_mad16 (struct address_info *hw_config) { static char interrupt_bits[12] = @@ -430,7 +549,7 @@ already_initialized = 1; if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return mem_start; + return; /* * Set the IRQ and DMA addresses. @@ -438,7 +557,7 @@ bits = interrupt_bits[hw_config->irq]; if (bits == -1) - return mem_start; + return; outb (bits | 0x40, config_port); if ((inb (version_port) & 0x40) == 0) @@ -450,12 +569,21 @@ if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || (dma == 3 && dma2 == 0)) { dma2_bit = 0x04; /* Enable capture DMA */ - } else { @@ -474,12 +602,10 @@ dma2, 0, hw_config->osp); request_region (hw_config->io_base, 4, "MAD16 WSS config"); - - return mem_start; } -long -attach_mad16_mpu (long mem_start, struct address_info *hw_config) +void +attach_mad16_mpu (struct address_info *hw_config) { if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { @@ -490,19 +616,20 @@ else hw_config->io_base = 0x220; - return mad16_sb_dsp_init (mem_start, hw_config); -#else - return 0; + hw_config->name = "Mad16/Mozart"; + sb_dsp_init (hw_config); #endif + + return; } #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) if (!already_initialized) - return mem_start; + return; - return attach_mpu401 (mem_start, hw_config); -#else - return mem_start; + hw_config->driver_use_1 = SB_MIDI_ONLY; + hw_config->name = "Mad16/Mozart"; + attach_uart401 (hw_config); #endif } @@ -562,13 +689,15 @@ } mad_write (MC3_PORT, tmp | 0x04); - return mad16_sb_dsp_detect (hw_config); + hw_config->driver_use_1 = SB_MIDI_ONLY; + return sb_dsp_detect (hw_config); #else return 0; #endif } - tmp = 0x83; /* MPU-401 enable */ + tmp = mad_read (MC6_PORT) & 0x83; + tmp |= 0x80; /* MPU-401 enable */ /* * Set the MPU base bits @@ -609,7 +738,7 @@ } mad_write (MC6_PORT, tmp); /* Write MPU401 config */ - return probe_mpu401 (hw_config); + return probe_uart401 (hw_config); #else return 0; #endif @@ -632,13 +761,13 @@ #ifdef CONFIG_MIDI if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { - mad16_sb_dsp_unload (hw_config); + sb_dsp_unload (hw_config); return; } #endif -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); +#if (defined(CONFIG_UART401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + unload_uart401 (hw_config); #endif } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/mad16_sb_midi.c linux/drivers/sound/mad16_sb_midi.c --- v2.0.0/linux/drivers/sound/mad16_sb_midi.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/mad16_sb_midi.c Thu Jan 1 02:00:00 1970 @@ -1,357 +0,0 @@ -/* - * sound/mad16_sb_midi.c - * - * The low level driver for MAD16 SoundBlaster-DS-chip-based MIDI. - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - -/* - * Modifications by Aaron Ucko 1995 - */ - -#include "sound_config.h" - -#if defined(CONFIG_MAD16) && defined(CONFIG_MIDI) - -#define sbc_base mad16_sb_base -#include "sb.h" - -static int input_opened = 0; -static int my_dev; -static int mad16_sb_base = 0x220; -static int mad16_sb_irq = 0; -static int mad16_sb_dsp_ok = 0; -static int mad16_sb_dsp_attached = 0; -static int *midi_osp; - -int mad16_sb_midi_mode = NORMAL_MIDI; -int mad16_sb_midi_busy = 0; - -int mad16_sb_duplex_midi = 0; -volatile int mad16_sb_intr_active = 0; - -void (*midi_input_intr) (int dev, unsigned char data); - -static void mad16_sb_midi_init (int model); - -static int -mad16_sb_dsp_command (unsigned char val) -{ - int i; - unsigned long limit; - - limit = jiffies + HZ / 10; /* - * The timeout is 0.1 seconds - */ - - /* - * Note! the i<500000 is an emergency exit. The mad16_sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb (DSP_STATUS) & 0x80) == 0) - { - outb (val, DSP_COMMAND); - return 1; - } - } - - printk ("MAD16 (SBP mode): DSP Command(%x) Timeout.\n", val); - printk ("IRQ conflict???\n"); - return 0; -} - -void -mad16_sbintr (int irq, void *dev_id, struct pt_regs *dummy) -{ - int status; - - unsigned long flags; - unsigned char data; - - status = inb (DSP_DATA_AVAIL); /* - * Clear interrupt - */ - - save_flags (flags); - cli (); - - data = inb (DSP_READ); - if (input_opened) - midi_input_intr (my_dev, data); - - restore_flags (flags); -} - -static int -mad16_sb_reset_dsp (void) -{ - int loopc; - - outb (1, DSP_RESET); - tenmicrosec (midi_osp); - outb (0, DSP_RESET); - tenmicrosec (midi_osp); - tenmicrosec (midi_osp); - tenmicrosec (midi_osp); - - for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); /* - * Wait - * for - * data - * * - * available - * status - */ - - if (inb (DSP_READ) != 0xAA) - return 0; /* - * Sorry - */ - - return 1; -} - -int -mad16_sb_dsp_detect (struct address_info *hw_config) -{ - mad16_sb_base = hw_config->io_base; - mad16_sb_irq = hw_config->irq; - midi_osp = hw_config->osp; - - if (check_region (hw_config->io_base, 16)) - { - printk ("MAD16 SB MIDI: I/O base %x not free\n", hw_config->io_base); - return 0; - } - - if (mad16_sb_dsp_ok) - return 0; /* - * Already initialized - */ - if (!mad16_sb_reset_dsp ()) - return 0; - - return 1; /* - * Detected - */ -} - -long -mad16_sb_dsp_init (long mem_start, struct address_info *hw_config) -/* this function now just verifies the reported version and calls - * mad16_sb_midi_init -- everything else is done elsewhere */ -{ - - mad16_sb_dsp_attached = 1; - midi_osp = hw_config->osp; - if (snd_set_irq_handler (mad16_sb_irq, mad16_sbintr, "MAD16 SB MIDI", midi_osp) < 0) - { - printk ("MAD16 SB MIDI: IRQ not free\n"); - return mem_start; - } - - request_region (hw_config->io_base, 16, "mad16/Mozart MIDI"); - - conf_printf ("MAD16 MIDI (SB mode)", hw_config); - mad16_sb_midi_init (2); - - mad16_sb_dsp_ok = 1; - return mem_start; -} - -void -mad16_sb_dsp_unload (struct address_info *hw_config) -{ - if (!mad16_sb_dsp_attached) - return; - - release_region (hw_config->io_base, 16); - snd_release_irq (hw_config->irq); -} - -static int -mad16_sb_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - - if (!mad16_sb_dsp_ok) - { - printk ("MAD16_SB Error: MIDI hardware not installed\n"); - return -ENXIO; - } - - if (mad16_sb_midi_busy) - return -EBUSY; - - if (mode != OPEN_WRITE && !mad16_sb_duplex_midi) - { - if (num_midis == 1) - printk ("MAD16 (SBP mode): Midi input not currently supported\n"); - return -EPERM; - } - - mad16_sb_midi_mode = NORMAL_MIDI; - if (mode != OPEN_WRITE) - { - if (mad16_sb_intr_active) - return -EBUSY; - mad16_sb_midi_mode = UART_MIDI; - } - - if (mad16_sb_midi_mode == UART_MIDI) - { - mad16_sb_reset_dsp (); - - if (!mad16_sb_dsp_command (0x35)) - return -EIO; /* - * Enter the UART mode - */ - mad16_sb_intr_active = 1; - - input_opened = 1; - midi_input_intr = input; - } - - mad16_sb_midi_busy = 1; - - return 0; -} - -static void -mad16_sb_midi_close (int dev) -{ - if (mad16_sb_midi_mode == UART_MIDI) - { - mad16_sb_reset_dsp (); /* - * The only way to kill the UART mode - */ - } - mad16_sb_intr_active = 0; - mad16_sb_midi_busy = 0; - input_opened = 0; -} - -static int -mad16_sb_midi_out (int dev, unsigned char midi_byte) -{ - unsigned long flags; - - if (mad16_sb_midi_mode == NORMAL_MIDI) - { - save_flags (flags); - cli (); - if (mad16_sb_dsp_command (0x38)) - mad16_sb_dsp_command (midi_byte); - else - printk ("MAD16_SB Error: Unable to send a MIDI byte\n"); - restore_flags (flags); - } - else - mad16_sb_dsp_command (midi_byte); /* - * UART write - */ - - return 1; -} - -static int -mad16_sb_midi_start_read (int dev) -{ - if (mad16_sb_midi_mode != UART_MIDI) - { - printk ("MAD16 (SBP mode): MIDI input not implemented.\n"); - return -EPERM; - } - return 0; -} - -static int -mad16_sb_midi_end_read (int dev) -{ - if (mad16_sb_midi_mode == UART_MIDI) - { - mad16_sb_reset_dsp (); - mad16_sb_intr_active = 0; - } - return 0; -} - -static int -mad16_sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg) -{ - return -EPERM; -} - -#define MIDI_SYNTH_NAME "pseudo-SoundBlaster Midi" -#define MIDI_SYNTH_CAPS 0 -#include "midi_synth.h" - -static struct midi_operations mad16_sb_midi_operations = -{ - {"MAD16 (SBP mode)", 0, 0, SNDCARD_MAD16}, - &std_midi_synth, - {0}, - mad16_sb_midi_open, - mad16_sb_midi_close, - mad16_sb_midi_ioctl, - mad16_sb_midi_out, - mad16_sb_midi_start_read, - mad16_sb_midi_end_read, - NULL, /* - * Kick - */ - NULL, /* - * command - */ - NULL, /* - * buffer_status - */ - NULL -}; - -static void -mad16_sb_midi_init (int model) -{ - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - std_midi_synth.midi_dev = num_midis; - my_dev = num_midis; - midi_devs[num_midis++] = &mad16_sb_midi_operations; -} - -#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.0.0/linux/drivers/sound/maui.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/maui.c Sun Jun 30 11:44:02 1996 @@ -4,27 +4,11 @@ * The low level driver for Turtle Beach Maui and Tropez. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -57,6 +41,10 @@ #ifdef HAVE_MAUI_BOOT #include "maui_boot.h" +#else +static unsigned char *maui_os = NULL; +static int maui_osLen = 0; + #endif static wait_handle *maui_sleeper = NULL; @@ -93,20 +81,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - maui_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + maui_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&maui_sleeper); - if (!(maui_sleep_flag.mode & WK_WAKEUP)) + if (!(maui_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - maui_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + maui_sleep_flag.flags |= WK_TIMEOUT; } - maui_sleep_flag.mode &= ~WK_SLEEP; + maui_sleep_flag.flags &= ~WK_SLEEP; }; if (current_got_fatal_signal ()) return 0; @@ -193,7 +181,7 @@ if (c != 0x80) { - printk ("Download not acknowledged\n"); + printk ("Doanload not acknowledged\n"); return 0; } else if (!(lines++ % 10)) @@ -317,7 +305,7 @@ if (count < hdr_size) { printk ("Maui error: Patch header too short\n"); - return -EINVAL; + return -(EINVAL); } count -= hdr_size; @@ -327,7 +315,7 @@ * been transferred already. */ - memcpy_fromfs (&((char *) &header)[offs], &((addr)[offs]), hdr_size - offs); + memcpy_fromfs (&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); if (count < header.len) { @@ -345,10 +333,10 @@ data = get_fs_byte (&((addr)[hdr_size + i])); if (i == 0 && !(data & 0x80)) - return -EINVAL; + return -(EINVAL); if (maui_write (data) == -1) - return -EIO; + return -(EIO); } if ((i = maui_read ()) != 0x80) @@ -356,7 +344,7 @@ if (i != -1) printk ("Maui: Error status %02x\n", i); - return -EIO; + return -(EIO); } return 0; @@ -377,7 +365,7 @@ if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0) return 0; - maui_sleep_flag.mode = WK_NONE; + maui_sleep_flag.flags = WK_NONE; /* * Initialize the processor if necessary */ @@ -448,22 +436,23 @@ return ret; } -long -attach_maui (long mem_start, struct address_info *hw_config) +void +attach_maui (struct address_info *hw_config) { int this_dev = num_midis; conf_printf ("Maui", hw_config); hw_config->irq *= -1; - mem_start = attach_mpu401 (mem_start, hw_config); + hw_config->name = "Maui"; + attach_mpu401 (hw_config); if (num_midis > this_dev) /* The MPU401 driver installed itself */ { struct synth_operations *synth; /* - * Intercept patch loading calls so that they can be handled + * Intercept patch loading calls so that they canbe handled * by the Maui driver. */ @@ -477,7 +466,6 @@ else printk ("Maui: Can't install patch loader\n"); } - return mem_start; } void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v2.0.0/linux/drivers/sound/midi_synth.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/midi_synth.c Sun Jun 30 11:44:03 1996 @@ -4,27 +4,11 @@ * High level midi sequencer manager for dumb MIDI interfaces. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -291,7 +275,7 @@ { case SNDCTL_SYNTH_INFO: - memcpy_tofs ((&((char *) arg)[0]), synth_devs[dev]->info, sizeof (struct synth_info)); + memcpy_tofs (&((char *) arg)[0], synth_devs[dev]->info, sizeof (struct synth_info)); return 0; break; @@ -301,7 +285,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -453,7 +437,7 @@ struct midi_input_info *inc; if (orig_dev < 0 || orig_dev > num_midis) - return -ENXIO; + return -(ENXIO); midi2synth[orig_dev] = dev; sysex_state[dev] = 0; @@ -474,7 +458,7 @@ inc->m_prev_status = 0x00; restore_flags (flags); - sysex_sleep_flag.mode = WK_NONE; + sysex_sleep_flag.flags = WK_NONE; return 1; } @@ -519,13 +503,13 @@ if (format != SYSEX_PATCH) { printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; + return -(EINVAL); } if (count < hdr_size) { printk ("MIDI Error: Patch header too short\n"); - return -EINVAL; + return -(EINVAL); } count -= hdr_size; @@ -535,7 +519,7 @@ * been transferred already. */ - memcpy_fromfs (&((char *) &sysex)[offs], &((addr)[offs]), hdr_size - offs); + memcpy_fromfs (&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs); if (count < sysex.len) { @@ -547,7 +531,7 @@ left = sysex.len; src_offs = 0; - sysex_sleep_flag.mode = WK_NONE; + sysex_sleep_flag.flags = WK_NONE; for (i = 0; i < left && !current_got_fatal_signal (); i++) { @@ -565,7 +549,7 @@ if (data != 0xf0) { printk ("Error: Sysex start missing\n"); - return -EINVAL; + return -(EINVAL); } } @@ -573,20 +557,20 @@ !current_got_fatal_signal ()) { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sysex_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sysex_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sysex_sleeper); - if (!(sysex_sleep_flag.mode & WK_WAKEUP)) + if (!(sysex_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sysex_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sysex_sleep_flag.flags |= WK_TIMEOUT; } - sysex_sleep_flag.mode &= ~WK_SLEEP; + sysex_sleep_flag.flags &= ~WK_SLEEP; }; /* Wait for timeout */ if (!first_byte && data & 0x80) @@ -668,7 +652,7 @@ int midi_synth_patchmgr (int dev, struct patmgr_info *rec) { - return -EINVAL; + return -(EINVAL); } void @@ -744,7 +728,7 @@ if (!midi_devs[orig_dev]->putc (orig_dev, bytes[i])) { /* - * Hardware level buffer is full. Abort the sysex message. + * Hardware leve buffer is full. Abort the sysex message. */ int timeout = 0; diff -u --recursive --new-file v2.0.0/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.0.0/linux/drivers/sound/midibuf.c Sun Mar 24 22:50:08 1996 +++ linux/drivers/sound/midibuf.c Sun Jun 30 11:44:04 1996 @@ -4,27 +4,11 @@ * Device file manager for /dev/midi# */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -112,20 +96,20 @@ midi_devs[dev]->buffer_status (dev)) { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - midi_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(midi_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag[dev].flags |= WK_TIMEOUT; } - midi_sleep_flag[dev].mode &= ~WK_SLEEP; + midi_sleep_flag[dev].flags &= ~WK_SLEEP; }; } @@ -145,9 +129,9 @@ if (SPACE_AVAIL (midi_in_buf[dev])) { QUEUE_BYTE (midi_in_buf[dev], data); - if ((input_sleep_flag[dev].mode & WK_SLEEP)) + if ((input_sleep_flag[dev].flags & WK_SLEEP)) { - input_sleep_flag[dev].mode = WK_WAKEUP; + input_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&input_sleeper[dev]); }; } @@ -184,9 +168,9 @@ } if (DATA_AVAIL (midi_out_buf[dev]) < 100 && - (midi_sleep_flag[dev].mode & WK_SLEEP)) + (midi_sleep_flag[dev].flags & WK_SLEEP)) { - midi_sleep_flag[dev].mode = WK_WAKEUP; + midi_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&midi_sleeper[dev]); }; } @@ -218,7 +202,7 @@ if (dev < 0 || dev >= num_midis) { printk ("Sound: Nonexistent MIDI interface %d\n", dev); - return -ENXIO; + return -(ENXIO); } /* @@ -233,31 +217,31 @@ parms[dev].prech_timeout = 0; - midi_in_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL); + 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; + 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 *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL); + 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); - kfree (midi_in_buf[dev]); + vfree (midi_in_buf[dev]); midi_in_buf[dev] = NULL; - return -EIO; + return -(EIO); } midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; open_devs++; - midi_sleep_flag[dev].mode = WK_NONE; - input_sleep_flag[dev].mode = WK_NONE; + midi_sleep_flag[dev].flags = WK_NONE; + input_sleep_flag[dev].flags = WK_NONE; if (open_devs < 2) /* This was first open */ { @@ -302,20 +286,20 @@ DATA_AVAIL (midi_out_buf[dev])) { - unsigned long tl; + unsigned long tlimit; if (0) - current_set_timeout (tl = jiffies + (0)); + current_set_timeout (tlimit = jiffies + (0)); else - tl = (unsigned long) -1; - midi_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(midi_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag[dev].flags |= WK_TIMEOUT; } - midi_sleep_flag[dev].mode &= ~WK_SLEEP; + midi_sleep_flag[dev].flags &= ~WK_SLEEP; }; /* * Sync */ @@ -329,8 +313,8 @@ midi_devs[dev]->close (dev); - kfree (midi_in_buf[dev]); - kfree (midi_out_buf[dev]); + vfree (midi_in_buf[dev]); + vfree (midi_out_buf[dev]); midi_in_buf[dev] = NULL; midi_out_buf[dev] = NULL; if (open_devs < 2) @@ -365,25 +349,25 @@ { { - unsigned long tl; + unsigned long tlimit; if (0) - current_set_timeout (tl = jiffies + (0)); + current_set_timeout (tlimit = jiffies + (0)); else - tl = (unsigned long) -1; - midi_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(midi_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag[dev].flags |= WK_TIMEOUT; } - midi_sleep_flag[dev].mode &= ~WK_SLEEP; + midi_sleep_flag[dev].flags &= ~WK_SLEEP; }; if (current_got_fatal_signal ()) { restore_flags (flags); - return -EINTR; + return -(EINTR); } n = SPACE_AVAIL (midi_out_buf[dev]); @@ -394,7 +378,7 @@ for (i = 0; i < n; i++) { - memcpy_fromfs ((char *) &tmp_data, &((buf)[c]), 1); + memcpy_fromfs ((char *) &tmp_data, &(buf)[c], 1); QUEUE_BYTE (midi_out_buf[dev], tmp_data); c++; } @@ -424,23 +408,23 @@ { { - unsigned long tl; + unsigned long tlimit; if (parms[dev].prech_timeout) - current_set_timeout (tl = jiffies + (parms[dev].prech_timeout)); + current_set_timeout (tlimit = jiffies + (parms[dev].prech_timeout)); else - tl = (unsigned long) -1; - input_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + input_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&input_sleeper[dev]); - if (!(input_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(input_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - input_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + input_sleep_flag[dev].flags |= WK_TIMEOUT; } - input_sleep_flag[dev].mode &= ~WK_SLEEP; + input_sleep_flag[dev].flags &= ~WK_SLEEP; }; if (current_got_fatal_signal ()) - c = -EINTR; /* + c = -(EINTR); /* * The user is getting restless */ } @@ -457,7 +441,7 @@ while (c < n) { REMOVE_BYTE (midi_in_buf[dev], tmp_data); - memcpy_tofs (&((buf)[c]), (char *) &tmp_data, 1); + memcpy_tofs (&(buf)[c], (char *) &tmp_data, 1); c++; } } @@ -482,7 +466,7 @@ else printk ("/dev/midi%d: No coprocessor for this device\n", dev); - return -ENXIO; + return -(ENXIO); } else switch (cmd) @@ -514,7 +498,7 @@ if (!DATA_AVAIL (midi_in_buf[dev])) { - input_sleep_flag[dev].mode = WK_SLEEP; + input_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&input_sleeper[dev], wait); return 0; } @@ -525,7 +509,7 @@ if (SPACE_AVAIL (midi_out_buf[dev])) { - midi_sleep_flag[dev].mode = WK_SLEEP; + midi_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&midi_sleeper[dev], wait); return 0; } @@ -540,10 +524,9 @@ } -long -MIDIbuf_init (long mem_start) +void +MIDIbuf_init (void) { - return mem_start; } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.0.0/linux/drivers/sound/mpu401.c Tue May 7 16:22:35 1996 +++ linux/drivers/sound/mpu401.c Sun Jun 30 11:44:06 1996 @@ -4,27 +4,11 @@ * The low level driver for Roland MPU-401 compatible Midi cards. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -508,21 +492,21 @@ struct mpu_config *devc; if (dev < 0 || dev >= num_midis) - return -ENXIO; + return -(ENXIO); devc = &dev_conf[dev]; if (devc->opened) { printk ("MPU-401: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } /* * Verify that the device is really running. * Some devices (such as Ensoniq SoundScape don't * work before the on board processor (OBP) is initialized - * by downloading its microcode. + * by downloadin it's microcode. */ if (!devc->initialized) @@ -530,7 +514,7 @@ if (mpu401_status (devc) == 0xff) /* Bus float */ { printk ("MPU-401: Device not initialized properly\n"); - return -EIO; + return -(EIO); } reset_mpu401 (devc); } @@ -624,7 +608,7 @@ */ { printk ("MPU-401 commands not possible in the UART mode\n"); - return -EINVAL; + return -(EINVAL); } /* @@ -643,7 +627,7 @@ if (timeout-- <= 0) { printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; + return -(EIO); } save_flags (flags); @@ -667,7 +651,7 @@ ok = 1; } else - { /* Device is not currently open. Use simpler method */ + { /* Device is not currently open. Use simplier method */ if (read_data (devc) == MPU_ACK) ok = 1; } @@ -677,7 +661,7 @@ { restore_flags (flags); /* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ - return -EIO; + return -(EIO); } if (cmd->nr_args) @@ -689,7 +673,7 @@ { restore_flags (flags); printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; + return -(EIO); } } @@ -711,7 +695,7 @@ { restore_flags (flags); /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ - return -EIO; + return -(EIO); } } @@ -796,7 +780,7 @@ switch (cmd) { case 1: - memcpy_fromfs ((char *) init_sequence, &(((char *) arg)[0]), sizeof (init_sequence)); + memcpy_fromfs ((char *) init_sequence, &((char *) arg)[0], sizeof (init_sequence)); return 0; break; @@ -804,7 +788,7 @@ if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ { printk ("MPU-401: Intelligent mode not supported by the HW\n"); - return -EINVAL; + return -(EINVAL); } set_uart_mode (dev, devc, !get_fs_long ((long *) arg)); return 0; @@ -815,18 +799,18 @@ int ret; mpu_command_rec rec; - memcpy_fromfs ((char *) &rec, &(((char *) arg)[0]), sizeof (rec)); + memcpy_fromfs ((char *) &rec, &((char *) arg)[0], sizeof (rec)); if ((ret = mpu401_command (dev, &rec)) < 0) return ret; - memcpy_tofs ((&((char *) arg)[0]), (char *) &rec, sizeof (rec)); + memcpy_tofs (&((char *) arg)[0], (char *) &rec, sizeof (rec)); return 0; } break; default: - return -EINVAL; + return -(EINVAL); } } @@ -853,7 +837,7 @@ midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis) - return -ENXIO; + return -(ENXIO); devc = &dev_conf[midi_dev]; @@ -861,7 +845,7 @@ { case SNDCTL_SYNTH_INFO: - memcpy_tofs ((&((char *) arg)[0]), &mpu_synth_info[midi_dev], sizeof (struct synth_info)); + memcpy_tofs (&((char *) arg)[0], &mpu_synth_info[midi_dev], sizeof (struct synth_info)); return 0; break; @@ -871,7 +855,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -885,7 +869,7 @@ if (midi_dev < 0 || midi_dev > num_midis) { - return -ENXIO; + return -(ENXIO); } devc = &dev_conf[midi_dev]; @@ -894,7 +878,7 @@ * Verify that the device is really running. * Some devices (such as Ensoniq SoundScape don't * work before the on board processor (OBP) is initialized - * by downloading its microcode. + * by downloadin it's microcode. */ if (!devc->initialized) @@ -902,7 +886,7 @@ if (mpu401_status (devc) == 0xff) /* Bus float */ { printk ("MPU-401: Device not initialized properly\n"); - return -EIO; + return -(EIO); } reset_mpu401 (devc); } @@ -910,7 +894,7 @@ if (devc->opened) { printk ("MPU-401: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } devc->mode = MODE_SYNTH; @@ -1047,8 +1031,8 @@ restore_flags (flags); } -long -attach_mpu401 (long mem_start, struct address_info *hw_config) +void +attach_mpu401 (struct address_info *hw_config) { unsigned long flags; char revision_char; @@ -1058,7 +1042,7 @@ if (num_midis >= MAX_MIDI_DEV) { printk ("MPU-401: Too many midi devices detected\n"); - return mem_start; + return; } devc = &dev_conf[num_midis]; @@ -1091,14 +1075,14 @@ if (!reset_mpu401 (devc)) { printk ("MPU401: Device didn't respond\n"); - return mem_start; + return; } if (!devc->shared_irq) if (snd_set_irq_handler (devc->irq, mpuintr, "mpu401", devc->osp) < 0) { printk ("MPU401: Failed to allocate IRQ%d\n", devc->irq); - return mem_start; + return; } save_flags (flags); @@ -1117,15 +1101,15 @@ devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (struct synth_operations), GFP_KERNEL)); + mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + if (sound_nblocks < 1024) + sound_nblocks++;; if (mpu401_synth_operations[num_midis] == NULL) { printk ("mpu401: Can't allocate memory\n"); - return mem_start; + return; } if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ @@ -1177,12 +1161,15 @@ devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - sprintf (mpu_synth_info[num_midis].name, - "MPU-401 %d.%d%c Midi interface #%d", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char, - n_mpu_devs); + if (hw_config->name) + sprintf (mpu_synth_info[num_midis].name, "%s (MPU401)", hw_config->name); + else + sprintf (mpu_synth_info[num_midis].name, + "MPU-401 %d.%d%c Midi interface #%d", + (int) (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char, + n_mpu_devs); } strcpy (mpu401_midi_operations[num_midis].info.name, @@ -1199,7 +1186,6 @@ irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; - return mem_start; } static int @@ -1348,7 +1334,7 @@ /* * The MPU-401 supports just a limited set of possible timebase values. * Since the applications require more choices, the driver has to - * program the HW to do its best and to convert between the HW and + * program the HW to do it's best and to convert between the HW and * actual timebases. */ @@ -1478,7 +1464,7 @@ int midi_dev = sound_timer_devs[dev]->devlink; if (timer_open) - return -EBUSY; + return -(EBUSY); tmr_reset (); curr_tempo = 50; @@ -1677,7 +1663,7 @@ case SNDCTL_SEQ_CTRLRATE: if (get_fs_long ((long *) arg) != 0) /* Can't change */ - return -EINVAL; + return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; @@ -1691,7 +1677,7 @@ default:; } - return -EINVAL; + return -(EINVAL); } static void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.0.0/linux/drivers/sound/opl3.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/opl3.c Sun Jun 30 11:44:07 1996 @@ -4,27 +4,11 @@ * A low level driver for Yamaha YM3812 and OPL-3 -chips */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -58,6 +42,7 @@ typedef struct opl_devinfo { + int base; int left_io, right_io; int nr_voice; int lv_map[MAX_VOICE]; @@ -133,12 +118,12 @@ { struct sbi_instrument ins; - memcpy_fromfs ((char *) &ins, &(((char *) arg)[0]), sizeof (ins)); + memcpy_fromfs ((char *) &ins, &((char *) arg)[0], sizeof (ins)); if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; + return -(EINVAL); } pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0); @@ -149,7 +134,7 @@ case SNDCTL_SYNTH_INFO: devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - memcpy_tofs ((&((char *) arg)[0]), &devc->fm_info, sizeof (devc->fm_info)); + memcpy_tofs (&((char *) arg)[0], &devc->fm_info, sizeof (devc->fm_info)); return 0; break; @@ -164,7 +149,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -190,9 +175,9 @@ return 0; - devc = (struct opl_devinfo *) (sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (*devc), GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (*devc))); + if (sound_nblocks < 1024) + sound_nblocks++;; if (devc == NULL) { @@ -201,6 +186,7 @@ } devc->osp = osp; + devc->base = ioaddr; /* Reset timers 1 and 2 */ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); @@ -266,7 +252,7 @@ detected_model = 3; /* - * Detect availability of OPL4 (_experimental_). Works probably + * Detect availability of OPL4 (_experimental_). Works propably * only after a cold boot. In addition the OPL4 port * of the chip may not be connected to the PC bus at all. */ @@ -319,7 +305,7 @@ } static int -opl3_kill_note (int dev, int voice, int note, int velocity) +opl3_kill_note (int devno, int voice, int note, int velocity) { struct physical_voice_info *map; @@ -797,7 +783,7 @@ } static void -opl3_reset (int dev) +opl3_reset (int devno) { int i; @@ -821,7 +807,7 @@ KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); } - opl3_kill_note (dev, i, 0, 64); + opl3_kill_note (devno, i, 0, 64); } if (devc->model == 2) @@ -841,7 +827,7 @@ int i; if (devc->busy) - return -EBUSY; + return -(EBUSY); devc->busy = 1; devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; @@ -887,15 +873,15 @@ if (count < sizeof (ins)) { printk ("FM Error: Patch record too short\n"); - return -EINVAL; + return -(EINVAL); } - memcpy_fromfs (&((char *) &ins)[offs], &((addr)[offs]), sizeof (ins) - offs); + memcpy_fromfs (&((char *) &ins)[offs], &(addr)[offs], sizeof (ins) - offs); if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; + return -(EINVAL); } ins.key = format; @@ -1055,7 +1041,7 @@ static int opl3_patchmgr (int dev, struct patmgr_info *rec) { - return -EINVAL; + return -(EINVAL); } static void @@ -1173,25 +1159,26 @@ opl3_setup_voice }; -long -opl3_init (long mem_start, int ioaddr, int *osp) +void +opl3_init (int ioaddr, int *osp) { int i; if (num_synths >= MAX_SYNTH_DEV) { printk ("OPL3 Error: Too many synthesizers\n"); - return mem_start; + return; } if (devc == NULL) { printk ("OPL3: Device control structure not initialized.\n"); - return mem_start; + return; } memset ((char *) devc, 0x00, sizeof (*devc)); devc->osp = osp; + devc->base = ioaddr; devc->nr_voice = 9; strcpy (devc->fm_info.name, "OPL2"); @@ -1257,7 +1244,6 @@ for (i = 0; i < SBFM_MAXINSTR; i++) devc->i_map[i].channel = -1; - return mem_start; } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h --- v2.0.0/linux/drivers/sound/opl3.h Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/opl3.h Sun Jun 30 11:43:38 1996 @@ -2,27 +2,11 @@ * opl3.h - Definitions of the OPL-3 registers */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ /* @@ -34,7 +18,7 @@ * * The percussive mode is implemented in the left side only. * - * With the above exceptions the both sides can be operated independently. + * With the above exeptions the both sides can be operated independently. * * A 4 OP voice can be created by setting the corresponding * bit at offset 4 of the right side. diff -u --recursive --new-file v2.0.0/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v2.0.0/linux/drivers/sound/os.h Sun Mar 24 22:49:45 1996 +++ linux/drivers/sound/os.h Sun Jun 30 11:43:41 1996 @@ -18,14 +18,11 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -40,7 +37,7 @@ #define TRUE 1 struct snd_wait { - int mode; + int flags; }; extern int sound_alloc_dma(int chn, char *deviceID); @@ -51,7 +48,7 @@ #define RUNTIME_DMA_ALLOC extern caddr_t sound_mem_blocks[1024]; -extern int sound_num_blocks; +extern int sound_nblocks; #undef PSEUDO_DMA_AUTOINIT #define ALLOW_BUFFER_MAPPING diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas.h linux/drivers/sound/pas.h --- v2.0.0/linux/drivers/sound/pas.h Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/pas.h Thu Jan 1 02:00:00 1970 @@ -1,236 +0,0 @@ -/* */ -/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */ -/* */ -/* Feel free to use this header file in any application you create that has support for the Media Vision */ -/* Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission. */ -/* */ -/* - cmetz@thor.tjhsst.edu */ -/* */ -/* Notes: */ -/* */ -/* * All of these ports go into the MVD101 multimedia controller chip, which then signals the other chips to do */ -/* the actual work. Many ports like the FM ones functionally attach directly to the destination chip though */ -/* they don't actually have a direct connection. */ -/* */ -/* * The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original */ -/* PAS cards are pretty defunct now, so no attempt is made here to support them. */ -/* */ -/* * The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the */ -/* incompatibilities, there still are differences that need to be accounted for. */ -/* */ -/* Card CD-ROM interface PCM chip Mixer chip FM chip */ -/* PAS Plus Sony proprietary (Crystal?) 8-bit DAC National OPL3 */ -/* PAS 16 Zilog SCSI MVA416 16-bit Codec MVA508 OPL3 */ -/* CDPC Sony proprietary Sony 16-bit Codec National OPL3 */ -/* Fusion CD 16 Sony proprietary MVA416 16-bit Codec MVA508 OPL3 */ -/* Fusion CD Sony proprietary (Crystal?) 8-bit DAC National OPL3 */ -/* */ -#define PAS_DEFAULT_BASE 0x388 - -/* Symbolic Name Value R W Subsystem Description */ -#define SPEAKER_CONTROL 0x61 /* W PC speaker Control register */ -#define SPEAKER_CONTROL_GHOST 0x738B /* R W PC speaker Control ghost register */ -#define SPEAKER_TIMER_CONTROL 0x43 /* W PC speaker Timer control register */ -#define SPEAKER_TIMER_CONTROL_GHOST 0x778B /* R W PC speaker Timer control register ghost */ -#define SPEAKER_TIMER_DATA 0x42 /* W PC speaker Timer data register */ -#define SPEAKER_TIMER_DATA_GHOST 0x138A /* R W PC speaker Timer data register ghost */ - -#define WARM_BOOT 0x41 /* W Control Used to detect system warm boot */ -#define WARM_BOOT_GHOST 0x7789 /* ? W Control Use to get the card to fake warm boot */ -#define MASTER_DECODE 0x9A01 /* W Control Address >> 2 of card base address */ -#define PRESCALE_DIVIDER 0xBF8A /* R W PCM Ration between Codec clock and master clock */ -#define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */ -#define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */ - -#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */ - -#define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */ -# define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */ -# define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */ -# define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */ -# define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */ -# define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */ -# define S_C_1_FORCE_EXT_RESET 0x40 /* R W Control Force external reset */ -# define S_C_1_FORCE_INT_RESET 0x80 /* R W Control Force internal reset */ -#define SYSTEM_CONFIGURATION_2 0x8389 /* R W Control */ -# define S_C_2_PCM_OVERSAMPLING 0x03 /* R W PCM 00=0x, 01=2x, 10=4x, 11=reserved */ -# define S_C_2_PCM_16_BIT 0x04 /* R W PCM 1=16-bit, 0=8-bit samples */ -#define SYSTEM_CONFIGURATION_3 0x838A /* R W Control */ -# define S_C_3_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=use 1.008Mhz clock for PCM, 0=don't */ -#define SYSTEM_CONFIGURATION_4 0x838B /* R W Control CD-ROM interface controls */ - -#define IO_CONFIGURATION_1 0xF388 /* R W Control */ -# define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */ -# define I_C_1_JOYSTICK_ENABLE 0x40 /* R W Control 1=enable joystick port, 0=don't */ -#define IO_CONFIGURATION_2 0xF389 /* R W Control */ -# define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */ -#define IO_CONFIGURATION_3 0xF38A /* R W Control */ -# define I_C_3_PCM_IRQ_DISABLED 0x00 /* R W PCM PCM IRQ disabled */ - -#define COMPATIBILITY_ENABLE 0xF788 /* R W Control */ -# define C_E_MPU401_ENABLE 0x01 /* R W MIDI 1=enable, 0=disable MPU401 MIDI emulation */ -# define C_E_SB_ENABLE 0x02 /* R W PCM 1=enable, 0=disable Sound Blaster emulation */ -# define C_E_SB_ACTIVE 0x04 /* R PCM "Sound Blaster Interrupt active" */ -# define C_E_MPU401_ACTIVE 0x08 /* R MIDI "MPU UART mode active" */ -# define C_E_PCM_COMPRESSION 0x10 /* R W PCM 1=enable, 0=disabled compression */ -#define EMULATION_ADDRESS 0xF789 /* R W Control */ -# define E_A_SB_BASE 0x0f /* R W PCM bits A4-A7 for SB base port */ -# define E_A_MPU401_BASE 0xf0 /* R W MIDI bits A4-A7 for MPU401 base port */ -#define EMULATION_CONFIGURATION 0xFB8A /* R W ***** Only valid on newer PAS2 cards (?) ***** */ -# define E_C_MPU401_IRQ 0x07 /* R W MIDI MPU401 emulation IRQ */ -# define E_C_SB_IRQ 0x38 /* R W PCM SB emulation IRQ */ -# define E_C_SB_DMA 0xC0 /* R W PCM SB emulation DMA */ - -#define OPERATION_MODE_1 0xEF8B /* R Control */ -# define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */ -# define O_M_1_FM_TYPE 0x04 /* R FM 1=stereo, 0=mono FM chip */ -# define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */ -#define OPERATION_MODE_2 0xFF8B /* R Control */ -# define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */ -# define O_M_2_BUS_TIMING 0x10 /* R Control 1=AT bus timing, 0=XT bus timing */ -# define O_M_2_BOARD_REVISION 0xe0 /* R Control Board revision */ - -#define INTERRUPT_MASK 0x0B8B /* R W Control */ -# define I_M_FM_LEFT_IRQ_ENABLE 0x01 /* R W FM Enable FM left interrupt */ -# define I_M_FM_RIGHT_IRQ_ENABLE 0x02 /* R W FM Enable FM right interrupt */ -# define I_M_PCM_RATE_IRQ_ENABLE 0x04 /* R W PCM Enable Sample Rate interrupt */ -# define I_M_PCM_BUFFER_IRQ_ENABLE 0x08 /* R W PCM Enable Sample Buffer interrupt */ -# define I_M_MIDI_IRQ_ENABLE 0x10 /* R W MIDI Enable MIDI interrupt */ -# define I_M_BOARD_REV 0xE0 /* R Control Board revision */ - -#define INTERRUPT_STATUS 0x0B89 /* R W Control */ -# define I_S_FM_LEFT_IRQ 0x01 /* R W FM Left FM Interrupt Pending */ -# define I_S_FM_RIGHT_IRQ 0x02 /* R W FM Right FM Interrupt Pending */ -# define I_S_PCM_SAMPLE_RATE_IRQ 0x04 /* R W PCM Sample Rate Interrupt Pending */ -# define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08 /* R W PCM Sample Buffer Interrupt Pending */ -# define I_S_MIDI_IRQ 0x10 /* R W MIDI MIDI Interrupt Pending */ -# define I_S_PCM_CHANNEL 0x20 /* R W PCM 1=right, 0=left */ -# define I_S_RESET_ACTIVE 0x40 /* R W Control Reset is active (Timed pulse not finished) */ -# define I_S_PCM_CLIPPING 0x80 /* R W PCM Clipping has occurred */ - -#define FILTER_FREQUENCY 0x0B8A /* R W Control */ -# define F_F_FILTER_DISABLED 0x00 /* R W Mixer No filter */ -# define F_F_MIXER_UNMUTE 0x20 /* R W Mixer 1=disable, 0=enable board mute */ -# define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */ -# define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */ - -#define PAS_NONE 0 -#define PAS_PLUS 1 -#define PAS_CDPC 2 -#define PAS_16 3 -#define PAS_16D 4 - -#ifdef DEFINE_TRANSLATIONS - unsigned char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ - { 4, 1, 2, 3, 0, 5, 6, 7 }; - unsigned char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */ - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 }; - unsigned char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ - { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 }; - unsigned char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ - { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 }; - unsigned char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ - { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 }; - unsigned char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */ - { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; -#else - extern unsigned char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */ - extern unsigned char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */ - extern unsigned char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */ - extern unsigned char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */ - extern unsigned char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */ - extern unsigned char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */ -#endif - -#define PARALLEL_MIXER 0x078B /* W Mixer Documented for MVD101 as FM Mono Right decode?? */ -# define P_M_MV508_ADDRESS 0x80 /* W Mixer MVD508 Address/mixer select */ -# define P_M_MV508_DATA 0x00 -# define P_M_MV508_LEFT 0x20 /* W Mixer MVD508 Left channel select */ -# define P_M_MV508_RIGHT 0x40 /* W Mixer MVD508 Right channel select */ -# define P_M_MV508_BOTH 0x00 /* W Mixer MVD508 Both channel select */ -# define P_M_MV508_MIXER 0x10 /* W Mixer MVD508 Select a mixer (rather than a volume) */ -# define P_M_MV508_VOLUME 0x00 - -# define P_M_MV508_INPUTMIX 0x20 /* W Mixer MVD508 Select mixer A */ -# define P_M_MV508_OUTPUTMIX 0x00 /* W Mixer MVD508 Select mixer B */ - -# define P_M_MV508_MASTER_A 0x01 /* W Mixer MVD508 Master volume control A (output) */ -# define P_M_MV508_MASTER_B 0x02 /* W Mixer MVD508 Master volume control B (DSP input) */ -# define P_M_MV508_BASS 0x03 /* W Mixer MVD508 Bass control */ -# define P_M_MV508_TREBLE 0x04 /* W Mixer MVD508 Treble control */ -# define P_M_MV508_MODE 0x05 /* W Mixer MVD508 Master mode control */ - -# define P_M_MV508_LOUDNESS 0x04 /* W Mixer MVD508 Mode control - Loudness filter */ -# define P_M_MV508_ENHANCE_BITS 0x03 -# define P_M_MV508_ENHANCE_NONE 0x00 /* W Mixer MVD508 Mode control - No stereo enhancement */ -# define P_M_MV508_ENHANCE_40 0x01 /* W Mixer MVD508 Mode control - 40% stereo enhancement */ -# define P_M_MV508_ENHANCE_60 0x02 /* W Mixer MVD508 Mode control - 60% stereo enhancement */ -# define P_M_MV508_ENHANCE_80 0x03 /* W Mixer MVD508 Mode control - 80% stereo enhancement */ - -# define P_M_MV508_FM 0x00 /* W Mixer MVD508 Channel 0 - FM */ -# define P_M_MV508_IMIXER 0x01 /* W Mixer MVD508 Channel 1 - Input mixer (rec monitor) */ -# define P_M_MV508_LINE 0x02 /* W Mixer MVD508 Channel 2 - Line in */ -# define P_M_MV508_CDROM 0x03 /* W Mixer MVD508 Channel 3 - CD-ROM */ -# define P_M_MV508_MIC 0x04 /* W Mixer MVD508 Channel 4 - Microphone */ -# define P_M_MV508_PCM 0x05 /* W Mixer MVD508 Channel 5 - PCM */ -# define P_M_MV508_SPEAKER 0x06 /* W Mixer MVD508 Channel 6 - PC Speaker */ -# define P_M_MV508_SB 0x07 /* W Mixer MVD508 Channel 7 - SB DSP */ - -#define SERIAL_MIXER 0xB88 /* R W Control Serial mixer control (used other ways) */ -# define S_M_PCM_RESET 0x01 /* R W PCM Codec/DSP reset */ -# define S_M_FM_RESET 0x02 /* R W FM FM chip reset */ -# define S_M_SB_RESET 0x04 /* R W PCM SB emulation chip reset */ -# define S_M_MIXER_RESET 0x10 /* R W Mixer Mixer chip reset */ -# define S_M_INTEGRATOR_ENABLE 0x40 /* R W Speaker Enable PC speaker integrator (FORCE RealSound) */ -# define S_M_OPL3_DUAL_MONO 0x80 /* R W FM Set the OPL-3 to dual mono mode */ - -#define PCM_CONTROL 0xF8A /* R W PCM PCM Control Register */ -# define P_C_MIXER_CROSS_FIELD 0x0f -# define P_C_MIXER_CROSS_R_TO_R 0x01 /* R W Mixer Connect Right to Right */ -# define P_C_MIXER_CROSS_L_TO_R 0x02 /* R W Mixer Connect Left to Right */ -# define P_C_MIXER_CROSS_R_TO_L 0x04 /* R W Mixer Connect Right to Left */ -# define P_C_MIXER_CROSS_L_TO_L 0x08 /* R W Mixer Connect Left to Left */ -# define P_C_PCM_DAC_MODE 0x10 /* R W PCM Playback (DAC) mode */ -# define P_C_PCM_ADC_MODE 0x00 /* R W PCM Record (ADC) mode */ -# define P_C_PCM_MONO 0x20 /* R W PCM Mono mode */ -# define P_C_PCM_STEREO 0x00 /* R W PCM Stereo mode */ -# define P_C_PCM_ENABLE 0x40 /* R W PCM Enable PCM engine */ -# define P_C_PCM_DMA_ENABLE 0x80 /* R W PCM Enable DRQ */ - -#define SAMPLE_COUNTER_CONTROL 0x138B /* R W PCM Sample counter control register */ -# define S_C_C_SQUARE_WAVE 0x04 /* R W PCM Square wave generator (use for sample rate) */ -# define S_C_C_RATE 0x06 /* R W PCM Rate generator (use for sample buffer count) */ -# define S_C_C_LSB_THEN_MSB 0x30 /* R W PCM Change all 16 bits, LSB first, then MSB */ - - /* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */ -# define S_C_C_SAMPLE_RATE 0x00 /* R W PCM Select sample rate timer */ -# define S_C_C_SAMPLE_BUFFER 0x40 /* R W PCM Select sample buffer counter */ - -# define S_C_C_PC_SPEAKER 0x80 /* R W PCM Select PC speaker counter */ - -#define SAMPLE_RATE_TIMER 0x1388 /* W PCM Sample rate timer register (PCM wait interval) */ -#define SAMPLE_BUFFER_COUNTER 0x1389 /* R W PCM Sample buffer counter (DMA buffer size) */ - -#define MIDI_CONTROL 0x178b /* R W MIDI Midi control register */ -# define M_C_ENA_TSTAMP_IRQ 0x01 /* R W MIDI Enable Time Stamp Interrupts */ -# define M_C_ENA_TME_COMP_IRQ 0x02 /* R W MIDI Enable time compare interrupts */ -# define M_C_ENA_INPUT_IRQ 0x04 /* R W MIDI Enable input FIFO interrupts */ -# define M_C_ENA_OUTPUT_IRQ 0x08 /* R W MIDI Enable output FIFO interrupts */ -# define M_C_ENA_OUTPUT_HALF_IRQ 0x10 /* R W MIDI Enable output FIFO half full interrupts */ -# define M_C_RESET_INPUT_FIFO 0x20 /* R W MIDI Reset input FIFO pointer */ -# define M_C_RESET_OUTPUT_FIFO 0x40 /* R W MIDI Reset output FIFO pointer */ -# define M_C_ENA_THRU_MODE 0x80 /* R W MIDI Echo input to output (THRU) */ - -#define MIDI_STATUS 0x1B88 /* R W MIDI Midi (interrupt) status register */ -# define M_S_TIMESTAMP 0x01 /* R W MIDI Midi time stamp interrupt occurred */ -# define M_S_COMPARE 0x02 /* R W MIDI Midi compare time interrupt occurred */ -# define M_S_INPUT_AVAIL 0x04 /* R W MIDI Midi input data available interrupt occurred */ -# define M_S_OUTPUT_EMPTY 0x08 /* R W MIDI Midi output FIFO empty interrupt occurred */ -# define M_S_OUTPUT_HALF_EMPTY 0x10 /* R W MIDI Midi output FIFO half empty interrupt occurred */ -# define M_S_INPUT_OVERRUN 0x20 /* R W MIDI Midi input overrun error occurred */ -# define M_S_OUTPUT_OVERRUN 0x40 /* R W MIDI Midi output overrun error occurred */ -# define M_S_FRAMING_ERROR 0x80 /* R W MIDI Midi input framing error occurred */ - -#define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */ -#define MIDI_DATA 0x178A /* R W MIDI Midi data register */ -#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */ diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.0.0/linux/drivers/sound/pas2_card.c Sun Mar 24 22:50:12 1996 +++ linux/drivers/sound/pas2_card.c Sun Jun 30 12:31:09 1996 @@ -4,38 +4,21 @@ * * Detection routine for the Pro Audio Spectrum cards. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include +#include #include "sound_config.h" #if defined(CONFIG_PAS) -#define DEFINE_TRANSLATIONS -#include "pas.h" +static unsigned char dma_bits[] = +{4, 1, 2, 3, 0, 5, 6, 7}; +static unsigned char irq_bits[] = +{0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11}; +static unsigned char sb_irq_bits[] = +{0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0}; +static unsigned char sb_dma_bits[] = +{0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0}; /* * The Address Translation code is used to convert I/O register addresses to @@ -45,6 +28,7 @@ int translat_code; static int pas_intr_mask = 0; static int pas_irq = 0; +static int pas_sb_base = 0; int *pas_osp; @@ -54,11 +38,7 @@ /* * pas_read() and pas_write() are equivalents of inb and outb - */ -/* * These routines perform the I/O address translation required - */ -/* * to support other than the default base address */ extern void mix_write (unsigned char data, int ioaddr); @@ -75,12 +55,6 @@ outb (data, ioaddr ^ translat_code); } -void -pas2_msg (char *foo) -{ - printk (" PAS2: %s.\n", foo); -} - /******************* Begin of the Interrupt Handler ********************/ void @@ -88,26 +62,23 @@ { int status; - status = pas_read (INTERRUPT_STATUS); - pas_write (status, INTERRUPT_STATUS); /* - * Clear interrupt - */ + status = pas_read (0x0B89); + pas_write (status, 0x0B89); /* Clear interrupt */ - if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) + if (status & 0x08) { #ifdef CONFIG_AUDIO pas_pcm_interrupt (status, 1); #endif - status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ; + status &= ~0x08; } - if (status & I_S_MIDI_IRQ) + if (status & 0x10) { #ifdef CONFIG_MIDI pas_midi_interrupt (); #endif - status &= ~I_S_MIDI_IRQ; + status &= ~0x10; } - } int @@ -118,7 +89,7 @@ pas_intr_mask |= mask; - pas_write (pas_intr_mask, INTERRUPT_MASK); + pas_write (pas_intr_mask, 0x0B8B); return 0; } @@ -129,7 +100,7 @@ return 0; pas_intr_mask &= ~mask; - pas_write (pas_intr_mask, INTERRUPT_MASK); + pas_write (pas_intr_mask, 0x0B8B); return 0; } @@ -146,41 +117,41 @@ pas_irq = hw_config->irq; - pas_write (0x00, INTERRUPT_MASK); + pas_write (0x00, 0x0B8B); + + pas_write (0x36, 0x138B); /* + * Local timer control * + * register + */ + + pas_write (0x36, 0x1388); /* + * Sample rate timer (16 bit) + */ + pas_write (0, 0x1388); + + pas_write (0x74, 0x138B); /* + * Local timer control * + * register + */ + + pas_write (0x74, 0x1389); /* + * Sample count register (16 + * * bit) + */ + pas_write (0, 0x1389); - pas_write (0x36, SAMPLE_COUNTER_CONTROL); /* - * Local timer control * - * register - */ - - pas_write (0x36, SAMPLE_RATE_TIMER); /* - * Sample rate timer (16 bit) - */ - pas_write (0, SAMPLE_RATE_TIMER); - - pas_write (0x74, SAMPLE_COUNTER_CONTROL); /* - * Local timer control * - * register - */ - - pas_write (0x74, SAMPLE_BUFFER_COUNTER); /* - * Sample count register (16 - * * bit) - */ - pas_write (0, SAMPLE_BUFFER_COUNTER); - - pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY); - pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL); - pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* - * | - * S_M_OPL3_DUAL_MONO - */ , SERIAL_MIXER); + pas_write (0x80 | 0x40 | 0x20 | 1, 0x0B8A); + pas_write (0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); + pas_write (0x01 | 0x02 | 0x04 | 0x10 /* + * | + * 0x80 + */ , 0xB88); - pas_write (I_C_1_BOOT_RESET_ENABLE + pas_write (0x80 #ifdef PAS_JOYSTICK_ENABLE - | I_C_1_JOYSTICK_ENABLE + | 0x40 #endif - ,IO_CONFIGURATION_1); + ,0xF388); if (pas_irq < 0 || pas_irq > 15) { @@ -189,10 +160,10 @@ } else { - int_ptrs = pas_read (IO_CONFIGURATION_3); - int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf; - pas_write (int_ptrs, IO_CONFIGURATION_3); - if (!I_C_3_PCM_IRQ_translate[pas_irq]) + int_ptrs = pas_read (0xF38A); + int_ptrs |= irq_bits[pas_irq] & 0xf; + pas_write (int_ptrs, 0xF38A); + if (!irq_bits[pas_irq]) { printk ("PAS2: Invalid IRQ %d", pas_irq); ok = 0; @@ -211,8 +182,8 @@ } else { - pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2); - if (!I_C_2_PCM_DMA_translate[hw_config->dma]) + pas_write (dma_bits[hw_config->dma], 0xF389); + if (!dma_bits[hw_config->dma]) { printk ("PAS2: Invalid DMA selection %d", hw_config->dma); ok = 0; @@ -237,29 +208,19 @@ #endif #ifdef BROKEN_BUS_CLOCK - pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1); + pas_write (0x01 | 0x10 | 0x20 | 0x04, 0x8388); #else /* - * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); + * pas_write(0x01, 0x8388); */ - pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1); + pas_write (0x01 | 0x10 | 0x20, 0x8388); #endif - pas_write (0x18, SYSTEM_CONFIGURATION_3); /* - * ??? - */ - - pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* - * Sets mute - * off and * - * selects - * filter - * rate * of - * 17.897 kHz - */ - pas_write (8, PRESCALE_DIVIDER); + pas_write (0x18, 0x838A); /* ??? */ + pas_write (0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ + pas_write (8, 0xBF8A); - mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); - mix_write (5, PARALLEL_MIXER); + mix_write (0x80 | 5, 0x078B); + mix_write (5, 0x078B); #if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) @@ -272,42 +233,39 @@ /* * Turn on Sound Blaster compatibility - */ - /* * bit 1 = SB emulation - */ - /* * bit 0 = MPU401 emulation (CDPC only :-( ) */ - pas_write (0x02, COMPATIBILITY_ENABLE); + pas_write (0x02, 0xF788); /* * "Emulation address" */ - pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS); + pas_write ((sb_config->io_base >> 4) & 0x0f, 0xF789); + pas_sb_base = sb_config->io_base; - if (!E_C_SB_DMA_translate[sb_config->dma]) + if (!sb_dma_bits[sb_config->dma]) printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); - if (!E_C_SB_IRQ_translate[sb_config->irq]) + if (!sb_irq_bits[sb_config->irq]) printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); - irq_dma = E_C_SB_DMA_translate[sb_config->dma] | - E_C_SB_IRQ_translate[sb_config->irq]; + irq_dma = sb_dma_bits[sb_config->dma] | + sb_irq_bits[sb_config->irq]; - pas_write (irq_dma, EMULATION_CONFIGURATION); + pas_write (irq_dma, 0xFB8A); } else - pas_write (0x00, COMPATIBILITY_ENABLE); + pas_write (0x00, 0xF788); } #else - pas_write (0x00, COMPATIBILITY_ENABLE); + pas_write (0x00, 0xF788); #endif if (!ok) - pas2_msg ("Driver not enabled"); + printk ("PAS16: Driver not enabled\n"); return ok; } @@ -324,18 +282,12 @@ * you have something on base port 0x388. SO be forewarned. */ - outb (0xBC, MASTER_DECODE); /* - * Talk to first board - */ - outb (hw_config->io_base >> 2, MASTER_DECODE); /* - * Set base address - */ - translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base; - pas_write (1, WAIT_STATE); /* - * One wait-state - */ + outb (0xBC, 0x9A01); /* Activate first board */ + outb (hw_config->io_base >> 2, 0x9A01); /* Set base address */ + translat_code = 0x388 ^ hw_config->io_base; + pas_write (1, 0xBF88); /* Select one wait states */ - board_id = pas_read (INTERRUPT_MASK); + board_id = pas_read (0x0B8B); if (board_id == 0xff) return 0; @@ -348,22 +300,22 @@ foo = board_id ^ 0xe0; - pas_write (foo, INTERRUPT_MASK); - foo = inb (INTERRUPT_MASK); - pas_write (board_id, INTERRUPT_MASK); + pas_write (foo, 0x0B8B); + foo = inb (0x0B8B); + pas_write (board_id, 0x0B8B); if (board_id != foo) /* * Not a PAS2 */ return 0; - pas_model = pas_read (CHIP_REV); + pas_model = pas_read (0xFF88); return pas_model; } -long -attach_pas_card (long mem_start, struct address_info *hw_config) +void +attach_pas_card (struct address_info *hw_config) { pas_irq = hw_config->irq; pas_osp = hw_config->osp; @@ -371,13 +323,13 @@ if (detect_pas_hw (hw_config)) { - if ((pas_model = pas_read (CHIP_REV))) + if ((pas_model = pas_read (0xFF88))) { char temp[100]; sprintf (temp, "%s rev %d", pas_model_names[(int) pas_model], - pas_read (BOARD_REV_ID)); + pas_read (0x2789)); conf_printf (temp, hw_config); } @@ -385,27 +337,23 @@ { #ifdef CONFIG_AUDIO - mem_start = pas_pcm_init (mem_start, hw_config); + pas_pcm_init (hw_config); #endif #if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) - sb_dsp_disable_midi (); /* - * The SB emulation don't support * - * midi - */ + sb_dsp_disable_midi (pas_sb_base); /* No MIDI capability */ #endif #ifdef CONFIG_MIDI - mem_start = pas_midi_init (mem_start); + pas_midi_init (); #endif pas_init_mixer (); } } - return mem_start; } int diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v2.0.0/linux/drivers/sound/pas2_midi.c Sun Mar 24 22:50:12 1996 +++ linux/drivers/sound/pas2_midi.c Sun Jun 30 12:31:09 1996 @@ -3,36 +3,11 @@ * * The low level driver for the PAS Midi Interface. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include +#include #include "sound_config.h" -#include "pas.h" - #if defined(CONFIG_PAS) && defined(CONFIG_MIDI) static int midi_busy = 0, input_opened = 0; @@ -59,19 +34,19 @@ if (midi_busy) { printk ("PAS2: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } /* * Reset input and output FIFO pointers */ - pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, - MIDI_CONTROL); + pas_write (0x20 | 0x40, + 0x178b); save_flags (flags); cli (); - if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0) + if ((err = pas_set_intr (0x10)) < 0) return err; /* @@ -84,28 +59,28 @@ if (mode == OPEN_READ || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_INPUT_IRQ; /* - * Enable input - */ + ctrl |= 0x04; /* + * Enable input + */ input_opened = 1; } if (mode == OPEN_WRITE || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_OUTPUT_IRQ | /* - * Enable output - */ - M_C_ENA_OUTPUT_HALF_IRQ; + ctrl |= 0x08 | /* + * Enable output + */ + 0x10; } pas_write (ctrl, - MIDI_CONTROL); + 0x178b); /* * Acknowledge any pending interrupts */ - pas_write (0xff, MIDI_STATUS); + pas_write (0xff, 0x1B88); ofifo_bytes = 0; restore_flags (flags); @@ -122,9 +97,9 @@ /* * Reset FIFO pointers, disable intrs */ - pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL); + pas_write (0x20 | 0x40, 0x178b); - pas_remove_intr (I_M_MIDI_IRQ_ENABLE); + pas_remove_intr (0x10); midi_busy = 0; } @@ -133,7 +108,7 @@ { int fifo_space, x; - fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f; + fifo_space = ((x = pas_read (0x1B89)) >> 4) & 0x0f; if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* * Fifo @@ -147,7 +122,7 @@ ofifo_bytes++; - pas_write (midi_byte, MIDI_DATA); + pas_write (midi_byte, 0x178A); return 1; } @@ -219,7 +194,7 @@ static int pas_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -(EINVAL); } static void @@ -257,18 +232,17 @@ NULL }; -long -pas_midi_init (long mem_start) +void +pas_midi_init (void) { if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); - return mem_start; + return; } std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &pas_midi_operations; - return mem_start; } void @@ -278,32 +252,32 @@ int i, incount; unsigned long flags; - stat = pas_read (MIDI_STATUS); + stat = pas_read (0x1B88); - if (stat & M_S_INPUT_AVAIL) /* - * Input byte available + if (stat & 0x04) /* + * Input byte available */ { - incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* - * Input FIFO count - */ + incount = pas_read (0x1B89) & 0x0f; /* + * Input FIFO count + */ if (!incount) incount = 16; for (i = 0; i < incount; i++) if (input_opened) { - midi_input_intr (my_dev, pas_read (MIDI_DATA)); + midi_input_intr (my_dev, pas_read (0x178A)); } else - pas_read (MIDI_DATA); /* + pas_read (0x178A); /* * Flush */ } - if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY)) + if (stat & (0x08 | 0x10)) { - if (!(stat & M_S_OUTPUT_EMPTY)) + if (!(stat & 0x08)) { ofifo_bytes = 8; } @@ -325,15 +299,15 @@ } - if (stat & M_S_OUTPUT_OVERRUN) + if (stat & 0x40) { - printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes); + printk ("MIDI output overrun %x,%x,%d \n", pas_read (0x1B89), stat, ofifo_bytes); ofifo_bytes = 100; } - pas_write (stat, MIDI_STATUS); /* - * Acknowledge interrupts - */ + pas_write (stat, 0x1B88); /* + * Acknowledge interrupts + */ } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.0.0/linux/drivers/sound/pas2_mixer.c Sun Mar 24 22:50:13 1996 +++ linux/drivers/sound/pas2_mixer.c Sun Jun 30 12:31:09 1996 @@ -5,43 +5,21 @@ * * Mixer routines for the Pro Audio Spectrum cards. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + #include - #include "sound_config.h" #if defined(CONFIG_PAS) -#include "pas.h" - -#define TRACE(what) /* (what) */ +#ifndef DEB +#define DEB(what) /* (what) */ +#endif extern int translat_code; extern char pas_model; extern int *pas_osp; +extern int pas_audiodev; static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ static int mode_control = 0; @@ -51,8 +29,8 @@ #define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \ - SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD) + SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV) + static unsigned short levels[SOUND_MIXER_NRDEVICES] = { @@ -81,7 +59,7 @@ * sequence problem. */ - if (pas_model == PAS_16D) + if (pas_model == 4) { outw (data | (data << 8), (ioaddr ^ translat_code) - 1); outb (0x80, 0); @@ -98,7 +76,7 @@ int right = right_vol * div / 100; - if (bits & P_M_MV508_MIXER) + if (bits & 0x10) { /* * Select input or output mixer */ @@ -106,20 +84,20 @@ right |= mixer; } - if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE) + if (bits == 0x03 || bits == 0x04) { /* * Bass and treble are mono devices */ - mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER); - mix_write (left, PARALLEL_MIXER); + mix_write (0x80 | bits, 0x078B); + mix_write (left, 0x078B); right_vol = left_vol; } else { - mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER); - mix_write (left, PARALLEL_MIXER); - mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER); - mix_write (right, PARALLEL_MIXER); + mix_write (0x80 | 0x20 | bits, 0x078B); + mix_write (left, 0x078B); + mix_write (0x80 | 0x40 | bits, 0x078B); + mix_write (right, 0x078B); } return (left_vol | (right_vol << 8)); @@ -128,8 +106,8 @@ void set_mode (int new_mode) { - mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); - mix_write (new_mode, PARALLEL_MIXER); + mix_write (0x80 | 0x05, 0x078B); + mix_write (new_mode, 0x078B); mode_control = new_mode; } @@ -139,21 +117,21 @@ { int left, right, devmask, changed, i, mixer = 0; - TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); + DEB (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); left = level & 0x7f; right = (level & 0x7f00) >> 8; if (whichDev < SOUND_MIXER_NRDEVICES) if ((1 << whichDev) & rec_devices) - mixer = P_M_MV508_INPUTMIX; + mixer = 0x20; else - mixer = P_M_MV508_OUTPUTMIX; + mixer = 0x00; switch (whichDev) { case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ - levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0); + levels[whichDev] = mixer_output (right, left, 63, 0x01, 0); break; /* @@ -161,67 +139,41 @@ * channel. */ case SOUND_MIXER_BASS: /* Bass (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0); + levels[whichDev] = mixer_output (right, left, 12, 0x03, 0); break; case SOUND_MIXER_TREBLE: /* Treble (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0); + levels[whichDev] = mixer_output (right, left, 12, 0x04, 0); break; case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x00, mixer); break; case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x05, mixer); break; case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x07, mixer); break; case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x06, mixer); break; case SOUND_MIXER_LINE: /* External line (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x02, mixer); break; case SOUND_MIXER_CD: /* CD (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x03, mixer); break; case SOUND_MIXER_MIC: /* External microphone (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x04, mixer); break; case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER, - P_M_MV508_OUTPUTMIX); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x01, + 0x00); break; case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ - levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0); + levels[whichDev] = mixer_output (right, left, 15, 0x02, 0); break; - case SOUND_MIXER_MUTE: - return 0; - break; - - case SOUND_MIXER_ENHANCE: - i = 0; - level &= 0x7f; - if (level) - i = (level / 20) - 1; - - mode_control &= ~P_M_MV508_ENHANCE_BITS; - mode_control |= P_M_MV508_ENHANCE_BITS; - set_mode (mode_control); - - if (i) - i = (i + 1) * 20; - return i; - break; - - case SOUND_MIXER_LOUD: - mode_control &= ~P_M_MV508_LOUDNESS; - if (level) - mode_control |= P_M_MV508_LOUDNESS; - set_mode (mode_control); - return !!level; /* 0 or 1 */ - break; case SOUND_MIXER_RECSRC: devmask = level & POSSIBLE_RECORDING_DEVICES; @@ -238,7 +190,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } return (levels[whichDev]); @@ -251,18 +203,92 @@ { int foo; - TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); + DEB (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) pas_mixer_set (foo, levels[foo]); - set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40); + set_mode (0x04 | 0x01); } int pas_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { - TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + + if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */ + { + int level = get_fs_long ((long *) arg); + + if (level == -1) /* Return current settings */ + { + if (mode_control & 0x04) + return snd_ioctl_return ((int *) arg, 1); + else + return snd_ioctl_return ((int *) arg, 0); + } + else + { + mode_control &= ~0x04; + if (level) + mode_control |= 0x04; + set_mode (mode_control); + return snd_ioctl_return ((int *) arg, !!level); /* 0 or 1 */ + } + } + + + if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */ + { + int level = get_fs_long ((long *) arg); + + if (level == -1) /* Return current settings */ + { + if (!(mode_control & 0x03)) + return snd_ioctl_return ((int *) arg, 0); + return snd_ioctl_return ((int *) arg, ((mode_control & 0x03) + 1) * 20); + } + else + { + int i = 0; + + level &= 0x7f; + if (level) + i = (level / 20) - 1; + + mode_control &= ~0x03; + mode_control |= i & 0x03; + set_mode (mode_control); + + if (i) + i = (i + 1) * 20; + + return i; + } + } + + if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */ + { + int level = get_fs_long ((long *) arg); + + if (level == -1) /* Return current settings */ + { + return snd_ioctl_return ((int *) arg, + !(pas_read (0x0B8A) & + 0x20)); + } + else + { + if (level) + pas_write (pas_read (0x0B8A) & (~0x20), + 0x0B8A); + else + pas_write (pas_read (0x0B8A) | 0x20, + 0x0B8A); + + return !(pas_read (0x0B8A) & 0x20); + } + } if (((cmd >> 8) & 0xff) == 'M') { @@ -270,7 +296,7 @@ return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_fs_long ((long *) arg))); else { /* - * Read parameters + * Read parameters */ switch (cmd & 0xff) @@ -296,32 +322,18 @@ return snd_ioctl_return ((int *) arg, 0); /* No special capabilities */ break; - case SOUND_MIXER_MUTE: - return snd_ioctl_return ((int *) arg, 0); /* No mute yet */ - break; - - case SOUND_MIXER_ENHANCE: - if (!(mode_control & P_M_MV508_ENHANCE_BITS)) - return snd_ioctl_return ((int *) arg, 0); - return snd_ioctl_return ((int *) arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20); - break; - - case SOUND_MIXER_LOUD: - if (mode_control & P_M_MV508_LOUDNESS) - return snd_ioctl_return ((int *) arg, 1); - return snd_ioctl_return ((int *) arg, 0); - break; default: return snd_ioctl_return ((int *) arg, levels[cmd & 0xff]); } } } - return -EINVAL; + return -(EINVAL); } static struct mixer_operations pas_mixer_operations = { + "PAS16", "Pro Audio Spectrum 16", pas_mixer_ioctl }; @@ -332,7 +344,10 @@ pas_mixer_reset (); if (num_mixers < MAX_MIXER_DEV) - mixer_devs[num_mixers++] = &pas_mixer_operations; + { + audio_devs[pas_audiodev]->mixer_dev = num_mixers; + mixer_devs[num_mixers++] = &pas_mixer_operations; + } return 1; } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v2.0.0/linux/drivers/sound/pas2_pcm.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/pas2_pcm.c Sun Jun 30 12:31:09 1996 @@ -4,40 +4,16 @@ * * The low level driver for the Pro Audio Spectrum ADC/DAC. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + #include - #include "sound_config.h" -#include "pas.h" - #if defined(CONFIG_PAS) && defined(CONFIG_AUDIO) -#define TRACE(WHAT) /* - * * * (WHAT) */ +#ifndef DEB +#define DEB(WHAT) +#endif #define PAS_PCM_INTRBITS (0x08) /* @@ -56,7 +32,7 @@ static unsigned long pcm_count = 0; static unsigned short pcm_bitsok = 8; /* mask of OK bits */ static int pcm_busy = 0; -static int my_devnum = 0; +int pas_audiodev = 0; static int open_mode = 0; int @@ -83,41 +59,45 @@ pcm_speed = arg; - tmp = pas_read (FILTER_FREQUENCY); + tmp = pas_read (0x0B8A); /* - * Set anti-aliasing filters according to sample rate. You really *NEED* + * Set anti-aliasing filters according to sample rate. You reall *NEED* * to enable this feature for all normal recording unless you want to * experiment with aliasing effects. * These filters apply to the selected "recording" source. * I (pfw) don't know the encoding of these 5 bits. The values shown * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + * + * I cleared bit 5 of these values, since that bit controls the master + * mute flag. (Olav Wölfelschneider) + * */ #if !defined NO_AUTO_FILTER_SET tmp &= 0xe0; if (pcm_speed >= 2 * 17897) - tmp |= 0x21; + tmp |= 0x01; else if (pcm_speed >= 2 * 15909) - tmp |= 0x22; + tmp |= 0x02; else if (pcm_speed >= 2 * 11931) - tmp |= 0x29; + tmp |= 0x09; else if (pcm_speed >= 2 * 8948) - tmp |= 0x31; + tmp |= 0x11; else if (pcm_speed >= 2 * 5965) - tmp |= 0x39; + tmp |= 0x19; else if (pcm_speed >= 2 * 2982) - tmp |= 0x24; + tmp |= 0x04; pcm_filter = tmp; #endif save_flags (flags); cli (); - pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (foo & 0xff, SAMPLE_RATE_TIMER); - pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER); - pas_write (tmp, FILTER_FREQUENCY); + pas_write (tmp & ~(0x40 | 0x80), 0x0B8A); + pas_write (0x00 | 0x30 | 0x04, 0x138B); + pas_write (foo & 0xff, 0x1388); + pas_write ((foo >> 8) & 0xff, 0x1388); + pas_write (tmp, 0x0B8A); restore_flags (flags); @@ -133,7 +113,7 @@ if (arg != pcm_channels) { - pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL); + pas_write (pas_read (0xF8A) ^ 0x20, 0xF8A); pcm_channels = arg; pcm_set_speed (pcm_speed); /* @@ -152,7 +132,7 @@ if (arg != pcm_bits) { - pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); + pas_write (pas_read (0x8389) ^ 0x04, 0x8389); pcm_bits = arg; } @@ -161,9 +141,9 @@ } static int -pas_pcm_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +pas_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB (printk ("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); switch (cmd) { @@ -212,7 +192,7 @@ * NOT YET IMPLEMENTED */ if (get_fs_long ((long *) arg) > 1) - return -EINVAL; + return -(EINVAL); pcm_filter = get_fs_long ((long *) arg); break; @@ -221,34 +201,34 @@ break; default: - return -EINVAL; + return -(EINVAL); } - return -EINVAL; + return -(EINVAL); } static void -pas_pcm_reset (int dev) +pas_audio_reset (int dev) { - TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n")); + DEB (printk ("pas2_pcm.c: static void pas_audio_reset(void)\n")); - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); } static int -pas_pcm_open (int dev, int mode) +pas_audio_open (int dev, int mode) { int err; unsigned long flags; - TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode)); + DEB (printk ("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); save_flags (flags); cli (); if (pcm_busy) { restore_flags (flags); - return -EBUSY; + return -(EBUSY); } pcm_busy = 1; @@ -265,16 +245,16 @@ } static void -pas_pcm_close (int dev) +pas_audio_close (int dev) { unsigned long flags; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n")); + DEB (printk ("pas2_pcm.c: static void pas_audio_close(void)\n")); save_flags (flags); cli (); - pas_pcm_reset (dev); + pas_audio_reset (dev); pas_remove_intr (PAS_PCM_INTRBITS); pcm_mode = PCM_NON; @@ -283,12 +263,12 @@ } static void -pas_pcm_output_block (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +pas_audio_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags, cnt; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count)); + DEB (printk ("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; if (audio_devs[dev]->dmachan1 > 3) @@ -304,8 +284,8 @@ save_flags (flags); cli (); - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, - PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, + 0xF8A); if (restart_dma) DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); @@ -315,17 +295,17 @@ if (count != pcm_count) { - pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); + pas_write (0x40 | 0x30 | 0x04, 0x138B); + pas_write (count & 0xff, 0x1389); + pas_write ((count >> 8) & 0xff, 0x1389); + pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); #endif pcm_mode = PCM_DAC; @@ -334,19 +314,19 @@ } static void -pas_pcm_start_input (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +pas_audio_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; int cnt; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count)); + DEB (printk ("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; if (audio_devs[dev]->dmachan1 > 3) cnt >>= 1; - if (audio_devs[my_devnum]->flags & DMA_AUTOMODE && + if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) return; /* @@ -364,17 +344,17 @@ if (count != pcm_count) { - pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); + pas_write (0x40 | 0x30 | 0x04, 0x138B); + pas_write (count & 0xff, 0x1389); + pas_write ((count >> 8) & 0xff, 0x1389); + pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); #endif pcm_mode = PCM_ADC; @@ -384,7 +364,7 @@ #ifndef NO_TRIGGER static void -pas_pcm_trigger (int dev, int state) +pas_audio_trigger (int dev, int state) { unsigned long flags; @@ -393,75 +373,74 @@ state &= open_mode; if (state & PCM_ENABLE_OUTPUT) - pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); else if (state & PCM_ENABLE_INPUT) - pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); else - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); restore_flags (flags); } #endif static int -pas_pcm_prepare_for_input (int dev, int bsize, int bcount) +pas_audio_prepare_for_input (int dev, int bsize, int bcount) { return 0; } static int -pas_pcm_prepare_for_output (int dev, int bsize, int bcount) +pas_audio_prepare_for_output (int dev, int bsize, int bcount) { return 0; } -static struct audio_operations pas_pcm_operations = +static struct audio_driver pas_audio_driver = { - "Pro Audio Spectrum", - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, + pas_audio_open, + pas_audio_close, + pas_audio_output_block, + pas_audio_start_input, + pas_audio_ioctl, + pas_audio_prepare_for_input, + pas_audio_prepare_for_output, + pas_audio_reset, + pas_audio_reset, NULL, - pas_pcm_open, - pas_pcm_close, - pas_pcm_output_block, - pas_pcm_start_input, - pas_pcm_ioctl, - pas_pcm_prepare_for_input, - pas_pcm_prepare_for_output, - pas_pcm_reset, - pas_pcm_reset, NULL, NULL, NULL, + pas_audio_trigger +}; + +static struct audio_operations pas_audio_operations = +{ + "Pro Audio Spectrum", + DMA_AUTOMODE, + AFMT_U8 | AFMT_S16_LE, NULL, -#ifndef NO_TRIGGER - pas_pcm_trigger -#else - NULL -#endif + &pas_audio_driver }; -long -pas_pcm_init (long mem_start, struct address_info *hw_config) +void +pas_pcm_init (struct address_info *hw_config) { - TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start)); + DEB (printk ("pas2_pcm.c: long pas_pcm_init()\n")); pcm_bitsok = 8; - if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE) + if (pas_read (0xEF8B) & 0x08) pcm_bitsok |= 16; pcm_set_speed (DSP_DEFAULT_SPEED); if (num_audiodevs < MAX_AUDIO_DEV) { - audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations; - audio_devs[my_devnum]->dmachan1 = hw_config->dma; - audio_devs[my_devnum]->buffsize = DSP_BUFFSIZE; + audio_devs[pas_audiodev = num_audiodevs++] = &pas_audio_operations; + audio_devs[pas_audiodev]->dmachan1 = hw_config->dma; + audio_devs[pas_audiodev]->buffsize = DSP_BUFFSIZE; } else printk ("PAS2: Too many PCM devices available\n"); - - return mem_start; } void @@ -476,21 +455,21 @@ * block before the PCM chip proceeds to the next sample */ - if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE)) + if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) { - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, - PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, + 0xF8A); } switch (pcm_mode) { case PCM_DAC: - DMAbuf_outputintr (my_devnum, 1); + DMAbuf_outputintr (pas_audiodev, 1); break; case PCM_ADC: - DMAbuf_inputintr (my_devnum); + DMAbuf_inputintr (pas_audiodev); break; default: diff -u --recursive --new-file v2.0.0/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c --- v2.0.0/linux/drivers/sound/patmgr.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/patmgr.c Sun Jun 30 11:44:10 1996 @@ -1,30 +1,14 @@ /* * sound/patmgr.c * - * The patch manager interface for the /dev/sequencer + * The patch maneger interface for the /dev/sequencer */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -59,13 +43,13 @@ pmgr_open (int dev) { if (dev < 0 || dev >= num_synths) - return -ENXIO; + return -(ENXIO); if (pmgr_opened[dev]) - return -EBUSY; + return -(EBUSY); pmgr_opened[dev] = 1; - server_wait_flag[dev].mode = WK_NONE; + server_wait_flag[dev].flags = WK_NONE; return 0; } @@ -80,11 +64,11 @@ { mbox[dev]->key = PM_ERROR; - mbox[dev]->parm1 = -EIO; + mbox[dev]->parm1 = -(EIO); - if ((appl_wait_flag.mode & WK_SLEEP)) + if ((appl_wait_flag.flags & WK_SLEEP)) { - appl_wait_flag.mode = WK_WAKEUP; + appl_wait_flag.flags = WK_WAKEUP; module_wake_up (&appl_proc); }; } @@ -101,7 +85,7 @@ if (count != sizeof (struct patmgr_info)) { printk ("PATMGR%d: Invalid read count\n", dev); - return -EIO; + return -(EIO); } while (!ok && !current_got_fatal_signal ()) @@ -113,14 +97,14 @@ !current_got_fatal_signal ()) { - server_wait_flag[dev].mode = WK_SLEEP; + server_wait_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&server_procs[dev]); - server_wait_flag[dev].mode &= ~WK_SLEEP;; + server_wait_flag[dev].flags &= ~WK_SLEEP;; } if (mbox[dev] && msg_direction[dev] == A_TO_S) { - memcpy_tofs (&((buf)[0]), (char *) mbox[dev], count); + memcpy_tofs (&(buf)[0], (char *) mbox[dev], count); msg_direction[dev] = 0; ok = 1; } @@ -130,7 +114,7 @@ } if (!ok) - return -EINTR; + return -(EINTR); return count; } @@ -142,10 +126,10 @@ if (count < 4) { printk ("PATMGR%d: Write count < 4\n", dev); - return -EIO; + return -(EIO); } - memcpy_fromfs ((char *) mbox[dev], &((buf)[0]), 4); + memcpy_fromfs ((char *) mbox[dev], &(buf)[0], 4); if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE) { @@ -153,7 +137,7 @@ tmp_dev = ((unsigned short *) mbox[dev])[2]; if (tmp_dev != dev) - return -ENXIO; + return -(ENXIO); return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev], buf, 4, count, 1); @@ -162,7 +146,7 @@ if (count != sizeof (struct patmgr_info)) { printk ("PATMGR%d: Invalid write count\n", dev); - return -EIO; + return -(EIO); } /* @@ -175,13 +159,13 @@ if (mbox[dev] && !msg_direction[dev]) { - memcpy_fromfs (&((char *) mbox[dev])[4], &((buf)[4]), count - 4); + memcpy_fromfs (&((char *) mbox[dev])[4], &(buf)[4], count - 4); msg_direction[dev] = S_TO_A; - if ((appl_wait_flag.mode & WK_SLEEP)) + if ((appl_wait_flag.flags & WK_SLEEP)) { { - appl_wait_flag.mode = WK_WAKEUP; + appl_wait_flag.flags = WK_WAKEUP; module_wake_up (&appl_proc); }; } @@ -209,23 +193,23 @@ mbox[dev] = rec; msg_direction[dev] = A_TO_S; - if ((server_wait_flag[dev].mode & WK_SLEEP)) + if ((server_wait_flag[dev].flags & WK_SLEEP)) { { - server_wait_flag[dev].mode = WK_WAKEUP; + server_wait_flag[dev].flags = WK_WAKEUP; module_wake_up (&server_procs[dev]); }; } - appl_wait_flag.mode = WK_SLEEP; + appl_wait_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&appl_proc); - appl_wait_flag.mode &= ~WK_SLEEP;; + appl_wait_flag.flags &= ~WK_SLEEP;; if (msg_direction[dev] != S_TO_A) { rec->key = PM_ERROR; - rec->parm1 = -EIO; + rec->parm1 = -(EIO); } else if (rec->key == PM_ERROR) { @@ -255,7 +239,7 @@ if (!pmgr_opened[dev]) return 0; - tmp_mbox = (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL); + tmp_mbox = (struct patmgr_info *) vmalloc (sizeof (struct patmgr_info)); if (tmp_mbox == NULL) { @@ -279,24 +263,24 @@ mbox[dev]->parm3 = p3; msg_direction[dev] = A_TO_S; - if ((server_wait_flag[dev].mode & WK_SLEEP)) + if ((server_wait_flag[dev].flags & WK_SLEEP)) { { - server_wait_flag[dev].mode = WK_WAKEUP; + server_wait_flag[dev].flags = WK_WAKEUP; module_wake_up (&server_procs[dev]); }; } - appl_wait_flag.mode = WK_SLEEP; + appl_wait_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&appl_proc); - appl_wait_flag.mode &= ~WK_SLEEP;; + appl_wait_flag.flags &= ~WK_SLEEP;; mbox[dev] = NULL; msg_direction[dev] = 0; } restore_flags (flags); - kfree (tmp_mbox); + vfree (tmp_mbox); return err; } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.0.0/linux/drivers/sound/pss.c Sat Jun 1 20:11:32 1996 +++ linux/drivers/sound/pss.c Sun Jun 30 11:44:11 1996 @@ -4,27 +4,11 @@ * The low level driver for the Personal Sound System (ECHO ESC614). */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -69,12 +53,12 @@ #include "synth-ld.h" #else static int pss_synthLen = 0; -static unsigned char pss_synth[1] = -{0}; +static unsigned char *pss_synth = +NULL; #endif -typedef struct pss_config +typedef struct pss_confdata { int base; int irq; @@ -82,10 +66,10 @@ int *osp; } -pss_config; +pss_confdata; -static pss_config pss_data; -static pss_config *devc = &pss_data; +static pss_confdata pss_data; +static pss_confdata *devc = &pss_data; static int pss_initialized = 0; static int nonstandard_microcode = 0; @@ -122,7 +106,7 @@ } static int -set_irq (pss_config * devc, int dev, int irq) +set_irq (pss_confdata * devc, int dev, int irq) { static unsigned short irq_bits[16] = { @@ -150,7 +134,7 @@ } static int -set_io_base (pss_config * devc, int dev, int base) +set_io_base (pss_confdata * devc, int dev, int base) { unsigned short tmp = inw (REG (dev)) & 0x003f; unsigned short bits = (base & 0x0ffc) << 4; @@ -161,7 +145,7 @@ } static int -set_dma (pss_config * devc, int dev, int dma) +set_dma (pss_confdata * devc, int dev, int dma) { static unsigned short dma_bits[8] = { @@ -187,7 +171,7 @@ } static int -pss_reset_dsp (pss_config * devc) +pss_reset_dsp (pss_confdata * devc) { unsigned long i, limit = jiffies + 10; @@ -202,7 +186,7 @@ } static int -pss_put_dspword (pss_config * devc, unsigned short word) +pss_put_dspword (pss_confdata * devc, unsigned short word) { int i, val; @@ -219,7 +203,7 @@ } static int -pss_get_dspword (pss_config * devc, unsigned short *word) +pss_get_dspword (pss_confdata * devc, unsigned short *word) { int i, val; @@ -237,7 +221,7 @@ } static int -pss_download_boot (pss_config * devc, unsigned char *block, int size, int flags) +pss_download_boot (pss_confdata * devc, unsigned char *block, int size, int flags) { int i, limit, val, count; @@ -320,8 +304,8 @@ return 1; } -long -attach_pss (long mem_start, struct address_info *hw_config) +void +attach_pss (struct address_info *hw_config) { unsigned short id; char tmp[100]; @@ -332,7 +316,7 @@ devc->osp = hw_config->osp; if (!probe_pss (hw_config)) - return mem_start; + return; id = inw (REG (PSS_ID)) & 0x00ff; @@ -349,27 +333,25 @@ if (sound_alloc_dma (hw_config->dma, "PSS")) { printk ("pss.c: Can't allocate DMA channel\n"); - return mem_start; + return; } if (!set_irq (devc, CONF_PSS, devc->irq)) { printk ("PSS: IRQ error\n"); - return mem_start; + return; } if (!set_dma (devc, CONF_PSS, devc->dma)) { printk ("PSS: DRQ error\n"); - return mem_start; + return; } #endif pss_initialized = 1; sprintf (tmp, "ECHO-PSS Rev. %d", id); conf_printf (tmp, hw_config); - - return mem_start; } int @@ -440,14 +422,14 @@ if (pss_synthLen == 0) { printk ("PSS: MIDI synth microcode not available.\n"); - return -EIO; + return -(EIO); } if (nonstandard_microcode) if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) { printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; + return -(EIO); } nonstandard_microcode = 0; break; @@ -478,12 +460,12 @@ download_boot_block (void *dev_info, copr_buffer * buf) { if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; + return -(EINVAL); if (!pss_download_boot (devc, buf->data, buf->len, buf->flags)) { printk ("PSS: Unable to load microcode block to DSP.\n"); - return -EIO; + return -(EIO); } nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ @@ -507,31 +489,29 @@ copr_buffer *buf; int err; - buf = (copr_buffer *) kmalloc (sizeof (copr_buffer), GFP_KERNEL); + buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); if (buf == NULL) - return -ENOSPC; + return -(ENOSPC); - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); + memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf)); err = download_boot_block (dev_info, buf); - kfree (buf); + vfree (buf); return err; } break; case SNDCTL_COPR_SENDMSG: { - /* send buf->len words from buf->data to DSP */ - copr_msg *buf; unsigned long flags; unsigned short *data; int i; - buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL); + buf = (copr_msg *) vmalloc (sizeof (copr_msg)); if (buf == NULL) - return -ENOSPC; + return -(ENOSPC); - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); + memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf)); data = (unsigned short *) (buf->data); @@ -543,16 +523,15 @@ if (!pss_put_dspword (devc, *data++)) { restore_flags (flags); - /* feed back number of WORDs sent */ - memcpy_tofs( (char *)(&(((copr_msg *)arg)->len)), - (char *)(&i), sizeof(buf->len)); - kfree (buf); - return -EIO; + buf->len = i; /* feed back number of WORDs sent */ + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); + vfree (buf); + return -(EIO); } } restore_flags (flags); - kfree (buf); + vfree (buf); return 0; } @@ -561,42 +540,37 @@ case SNDCTL_COPR_RCVMSG: { - /* try to read as much words as possible from DSP into buf */ copr_msg *buf; unsigned long flags; unsigned short *data; unsigned int i; int err = 0; - buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL); + buf = (copr_msg *) vmalloc (sizeof (copr_msg)); if (buf == NULL) - return -ENOSPC; -#if 0 - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); -#endif + return -(ENOSPC); + data = (unsigned short *) buf->data; save_flags (flags); cli (); - for (i = 0; i < sizeof(buf->data); i++) + for (i = 0; i < buf->len; i++) { + buf->len = i; /* feed back number of WORDs read */ if (!pss_get_dspword (devc, data++)) { - buf->len = i; /* feed back number of WORDs read */ - err = (i==0)? -EIO : 0; /* EIO only if no word read */ + if (i == 0) + err = -(EIO); break; } } - if( i==sizeof(buf->data) ) - buf->len = i; - restore_flags (flags); - memcpy_tofs ((&((char *) arg)[0]), buf, sizeof (*buf)); - kfree (buf); + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); + vfree (buf); return err; } @@ -609,32 +583,32 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d0)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_get_dspword (devc, &tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } buf.parm1 = tmp; restore_flags (flags); - memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf)); + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); return 0; } break; @@ -645,27 +619,27 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d1)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } tmp = (unsigned int) buf.parm2 & 0xffff; if (!pss_put_dspword (devc, tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } restore_flags (flags); @@ -679,34 +653,34 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d3)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } tmp = (unsigned int) buf.parm2 & 0x00ff; if (!pss_put_dspword (devc, tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; if (!pss_put_dspword (devc, tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } restore_flags (flags); @@ -720,26 +694,26 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d2)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_get_dspword (devc, &tmp)) /* Read msb */ { restore_flags (flags); - return -EIO; + return -(EIO); } buf.parm1 = tmp << 8; @@ -747,23 +721,23 @@ if (!pss_get_dspword (devc, &tmp)) /* Read lsb */ { restore_flags (flags); - return -EIO; + return -(EIO); } buf.parm1 |= tmp & 0x00ff; restore_flags (flags); - memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf)); + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); return 0; } break; default: - return -EINVAL; + return -(EINVAL); } - return -EINVAL; + return -(EINVAL); } static coproc_operations pss_coproc_operations = @@ -776,23 +750,19 @@ &pss_data }; -long -attach_pss_mpu (long mem_start, struct address_info *hw_config) +void +attach_pss_mpu (struct address_info *hw_config) { #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - long ret; - { int prev_devs; + prev_devs = num_midis; - ret = attach_mpu401 (mem_start, hw_config); + attach_mpu401 (hw_config); if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ midi_devs[prev_devs]->coproc = &pss_coproc_operations; } - return ret; -#else - return mem_start; #endif } @@ -830,7 +800,7 @@ /* * For some reason the card returns 0xff in the WSS status register - * immediately after boot. Probably MIDI+SB emulation algorithm + * immediately after boot. Propably MIDI+SB emulation algorithm * downloaded to the ADSP2115 spends some time initializing the card. * Let's try to wait until it finishes this task. */ @@ -842,19 +812,16 @@ return probe_ms_sound (hw_config); } -long -attach_pss_mss (long mem_start, struct address_info *hw_config) +void +attach_pss_mss (struct address_info *hw_config) { int prev_devs; - long ret; prev_devs = num_audiodevs; - ret = attach_ms_sound (mem_start, hw_config); + attach_ms_sound (hw_config); if (num_audiodevs == (prev_devs + 1)) /* The MSS driver installed itself */ audio_devs[prev_devs]->coproc = &pss_coproc_operations; - - return ret; } void @@ -865,9 +832,7 @@ void unload_pss_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) unload_mpu401 (hw_config); -#endif } void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.0.0/linux/drivers/sound/sb.h Sun Mar 24 22:49:43 1996 +++ linux/drivers/sound/sb.h Sun Jun 30 11:43:38 1996 @@ -1,15 +1,15 @@ -#define DSP_RESET (sbc_base + 0x6) -#define DSP_READ (sbc_base + 0xA) -#define DSP_WRITE (sbc_base + 0xC) -#define DSP_COMMAND (sbc_base + 0xC) -#define DSP_STATUS (sbc_base + 0xC) -#define DSP_DATA_AVAIL (sbc_base + 0xE) -#define DSP_DATA_AVL16 (sbc_base + 0xF) -#define MIXER_ADDR (sbc_base + 0x4) -#define MIXER_DATA (sbc_base + 0x5) -#define OPL3_LEFT (sbc_base + 0x0) -#define OPL3_RIGHT (sbc_base + 0x2) -#define OPL3_BOTH (sbc_base + 0x8) +#define DSP_RESET (devc->base + 0x6) +#define DSP_READ (devc->base + 0xA) +#define DSP_WRITE (devc->base + 0xC) +#define DSP_COMMAND (devc->base + 0xC) +#define DSP_STATUS (devc->base + 0xC) +#define DSP_DATA_AVAIL (devc->base + 0xE) +#define DSP_DATA_AVL16 (devc->base + 0xF) +#define MIXER_ADDR (devc->base + 0x4) +#define MIXER_DATA (devc->base + 0x5) +#define OPL3_LEFT (devc->base + 0x0) +#define OPL3_RIGHT (devc->base + 0x2) +#define OPL3_BOTH (devc->base + 0x8) /* DSP Commands */ #define DSP_CMD_SPKON 0xD1 @@ -26,3 +26,96 @@ #define NORMAL_MIDI 0 #define UART_MIDI 1 + +/* + * Device models + */ +#define MDL_NONE 0 +#define MDL_SB1 1 /* SB1.0 or 1.5 */ +#define MDL_SB2 2 /* SB2.0 */ +#define MDL_SB201 3 /* SB2.01 */ +#define MDL_SBPRO 4 /* SB Pro */ +#define MDL_SB16 5 /* SB16/32/AWE */ +#define MDL_JAZZ 10 /* Media Vision Jazz16 */ +#define MDL_SMW 11 /* Logitech Soundman Wave (Jazz16) */ +#define MDL_ESS 12 /* ESS ES688 and ES1688 */ +#define MDL_AZTECH 13 /* Aztech Sound Galaxy family */ + +/* + * Config flags + */ +#define SB_NO_MIDI 0x00000001 +#define SB_NO_MIXER 0x00000002 +#define SB_NO_AUDIO 0x00000004 +#define SB_NO_RECORDING 0x00000008 /* No audio recording */ +#define SB_MIDI_ONLY (SB_NO_AUDIO|SB_NO_MIXER) + +struct mixer_def { + unsigned int regno: 8; + unsigned int bitoffs:4; + unsigned int nbits:4; +}; + +typedef struct mixer_def mixer_tab[32][2]; +typedef struct mixer_def mixer_ent; + +typedef struct sb_devc { + int dev; + + /* Hardware parameters */ + int *osp; + int minor, major; + int type; + int model, submodel; + int caps; +# define SBCAP_STEREO 0x00000001 +# define SBCAP_16BITS 0x00000002 + + /* Hardware resources */ + int base; + int irq; + int dma8, dma16; + + /* State variables */ + int opened; + int speed, bits, channels; + volatile int irq_ok; + volatile int intr_active, irq_mode; + + /* Mixer fields */ + int levels[SOUND_MIXER_NRDEVICES]; + mixer_tab *iomap; + int mixer_caps, recmask, supported_devices; + int supported_rec_devices; + int my_mixerdev; + + /* Audio fields */ + unsigned long trg_buf; + int trigger_bits; + int trg_bytes; + int trg_intrflag; + int trg_restart; + unsigned char tconst; + int my_dev; + + /* MIDI fields */ + int my_mididev; + int input_opened; + void (*midi_input_intr) (int dev, unsigned char data); + } sb_devc; + +int sb_dsp_command (sb_devc *devc, unsigned char val); +int sb_dsp_get_byte (sb_devc *devc); +int sb_dsp_reset (sb_devc *devc); +void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); +unsigned int sb_getmixer (sb_devc *devc, unsigned int port); +int sb_dsp_detect (struct address_info *hw_config); +void sb_dsp_init (struct address_info *hw_config); +void sb_dsp_unload(struct address_info *hw_config); +int sb_mixer_init(sb_devc *devc); +void smw_mixer_init(sb_devc *devc); +void sb_dsp_midi_init (sb_devc *devc); +void sb_audio_init (sb_devc *devc, char *name); +void sb_midi_interrupt (sb_devc *devc); +int ess_write (sb_devc *devc, unsigned char reg, unsigned char data); +int ess_read (sb_devc *devc, unsigned char reg); diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c --- v2.0.0/linux/drivers/sound/sb16_dsp.c Mon Mar 25 09:25:26 1996 +++ linux/drivers/sound/sb16_dsp.c Thu Jan 1 02:00:00 1970 @@ -1,643 +0,0 @@ -/* - * sound/sb16_dsp.c - * - * The low level driver for the SoundBlaster DSP chip. - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - - -#define DEB(x) -#define DEB1(x) -/* - * #define DEB_DMARES - */ -#include "sound_config.h" -#include "sb.h" -#include "sb_mixer.h" - -#if defined(CONFIG_SB) && defined(CONFIG_AUDIO) - -extern int sbc_base; -extern int *sb_osp; - -static int sb16_dsp_ok = 0; -static int dsp_16bit = 0; -static int dsp_stereo = 0; -static int dsp_current_speed = 8000; -static int dsp_busy = 0; -static int dma16 = -1, dma8 = -1; -static int trigger_bits = 0; -static unsigned long dsp_count = 0; - -static int irq_mode = IMODE_NONE; -static int my_dev = 0; - -static volatile int intr_active = 0; - -static int sb16_dsp_open (int dev, int mode); -static void sb16_dsp_close (int dev); -static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart); -static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart); -static int sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local); -static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount); -static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount); -static void sb16_dsp_reset (int dev); -static void sb16_dsp_halt (int dev); -static void sb16_dsp_trigger (int dev, int bits); -static int dsp_set_speed (int); -static int dsp_set_stereo (int); -static void dsp_cleanup (void); -int sb_reset_dsp (void); - -static struct audio_operations sb16_dsp_operations = -{ - "SoundBlaster 16", - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, - NULL, - sb16_dsp_open, - sb16_dsp_close, - sb16_dsp_output_block, - sb16_dsp_start_input, - sb16_dsp_ioctl, - sb16_dsp_prepare_for_input, - sb16_dsp_prepare_for_output, - sb16_dsp_reset, - sb16_dsp_halt, - NULL, - NULL, - NULL, - NULL, - sb16_dsp_trigger -}; - -static int -sb_dsp_command01 (unsigned char val) -{ - int i = 1 << 16; - - while (--i & (!inb (DSP_STATUS) & 0x80)); - if (!i) - printk ("SB16 sb_dsp_command01 Timeout\n"); - return sb_dsp_command (val); -} - -static int -dsp_set_speed (int mode) -{ - DEB (printk ("dsp_set_speed(%d)\n", mode)); - if (mode) - { - if (mode < 5000) - mode = 5000; - if (mode > 44100) - mode = 44100; - dsp_current_speed = mode; - } - return mode; -} - -static int -dsp_set_stereo (int mode) -{ - DEB (printk ("dsp_set_stereo(%d)\n", mode)); - - dsp_stereo = mode; - - return mode; -} - -static int -dsp_set_bits (int arg) -{ - DEB (printk ("dsp_set_bits(%d)\n", arg)); - - if (arg) - switch (arg) - { - case 8: - dsp_16bit = 0; - break; - case 16: - dsp_16bit = 1; - break; - default: - dsp_16bit = 0; - } - return dsp_16bit ? 16 : 8; -} - -static int -sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) -{ - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return dsp_set_speed ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_RATE: - if (local) - return dsp_current_speed; - return snd_ioctl_return ((int *) arg, dsp_current_speed); - - case SNDCTL_DSP_STEREO: - if (local) - return dsp_set_stereo ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg))); - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return dsp_set_stereo ((long) arg - 1) + 1; - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1); - - case SOUND_PCM_READ_CHANNELS: - if (local) - return dsp_stereo + 1; - return snd_ioctl_return ((int *) arg, dsp_stereo + 1); - - case SNDCTL_DSP_SETFMT: - if (local) - return dsp_set_bits ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_BITS: - if (local) - return dsp_16bit ? 16 : 8; - return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8); - - case SOUND_PCM_WRITE_FILTER: /* - * NOT YET IMPLEMENTED - */ - if (get_fs_long ((long *) arg) > 1) - return snd_ioctl_return ((int *) arg, -EINVAL); - default: - return -EINVAL; - } - - return -EINVAL; -} - -static int -sb16_dsp_open (int dev, int mode) -{ - int retval; - - DEB (printk ("sb16_dsp_open()\n")); - if (!sb16_dsp_ok) - { - printk ("SB16 Error: SoundBlaster board not installed\n"); - return -ENXIO; - } - - if (intr_active) - return -EBUSY; - - retval = sb_get_irq (); - if (retval < 0) - return retval; - - sb_reset_dsp (); - - if (dma16 != dma8) - if (sound_open_dma (dma16, "SB16 (16bit)")) - { - printk ("SB16: Unable to grab DMA%d\n", dma16); - sb_free_irq (); - return -EBUSY; - } - - irq_mode = IMODE_NONE; - dsp_busy = 1; - trigger_bits = 0; - - return 0; -} - -static void -sb16_dsp_close (int dev) -{ - unsigned long flags; - - DEB (printk ("sb16_dsp_close()\n")); - sb_dsp_command01 (0xd9); - sb_dsp_command01 (0xd5); - sb_reset_dsp (); - - save_flags (flags); - cli (); - - audio_devs[dev]->dmachan1 = audio_devs[dev]->dmachan2 = dma8; - - if (dma16 != dma8) - sound_close_dma (dma16); - sb_free_irq (); - dsp_cleanup (); - dsp_busy = 0; - restore_flags (flags); -} - -static unsigned long trg_buf; -static int trg_bytes; -static int trg_intrflag; -static int trg_restart; - -static void -sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - trg_buf = buf; - trg_bytes = count; - trg_intrflag = intrflag; - trg_restart = dma_restart; - irq_mode = IMODE_OUTPUT; -} - -static void -actually_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - unsigned long flags, cnt; - - cnt = count; - if (dsp_16bit) - cnt >>= 1; - cnt--; - - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == dsp_count) - { - irq_mode = IMODE_OUTPUT; - intr_active = 1; - return; /* - * Auto mode on. No need to react - */ - } - save_flags (flags); - cli (); - - if (dma_restart) - { - sb16_dsp_halt (dev); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - } - sb_dsp_command (0x41); - sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff)); - sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff)); - sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6)); - dsp_count = cnt; - sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) + - (dsp_16bit ? 0x10 : 0))); - sb_dsp_command01 ((unsigned char) (cnt & 0xff)); - sb_dsp_command ((unsigned char) (cnt >> 8)); - - irq_mode = IMODE_OUTPUT; - intr_active = 1; - restore_flags (flags); -} - -static void -sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - trg_buf = buf; - trg_bytes = count; - trg_intrflag = intrflag; - trg_restart = dma_restart; - irq_mode = IMODE_INPUT; -} - -static void -actually_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - unsigned long flags, cnt; - - cnt = count; - if (dsp_16bit) - cnt >>= 1; - cnt--; - - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == dsp_count) - { - irq_mode = IMODE_INPUT; - intr_active = 1; - return; /* - * Auto mode on. No need to react - */ - } - save_flags (flags); - cli (); - - if (dma_restart) - { - sb16_dsp_halt (dev); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - } - - sb_dsp_command (0x42); - sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff)); - sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff)); - - sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce)); - dsp_count = cnt; - sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) + - (dsp_16bit ? 0x10 : 0))); - sb_dsp_command01 ((unsigned char) (cnt & 0xff)); - sb_dsp_command ((unsigned char) (cnt >> 8)); - - irq_mode = IMODE_INPUT; - intr_active = 1; - restore_flags (flags); -} - -static int -sb16_dsp_prepare_for_input (int dev, int bsize, int bcount) -{ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - dsp_count = 0; - dsp_cleanup (); - trigger_bits = 0; - return 0; -} - -static int -sb16_dsp_prepare_for_output (int dev, int bsize, int bcount) -{ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - dsp_count = 0; - dsp_cleanup (); - trigger_bits = 0; - return 0; -} - -static void -sb16_dsp_trigger (int dev, int bits) -{ - trigger_bits = bits; - - if (!bits) - { - sb_dsp_command (0xd0); /* Halt DMA */ - } - else if (bits & irq_mode) - switch (irq_mode) - { - case IMODE_INPUT: - actually_start_input (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - - break; - - case IMODE_OUTPUT: - actually_output_block (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - break; - - } -} - -static void -dsp_cleanup (void) -{ - irq_mode = IMODE_NONE; - intr_active = 0; -} - -static void -sb16_dsp_reset (int dev) -{ - unsigned long flags; - - save_flags (flags); - cli (); - - sb_reset_dsp (); - dsp_cleanup (); - - restore_flags (flags); -} - -static void -sb16_dsp_halt (int dev) -{ - if (dsp_16bit) - { - sb_dsp_command01 (0xd9); - sb_dsp_command01 (0xd5); - } - else - { - sb_dsp_command01 (0xda); - sb_dsp_command01 (0xd0); - } - /* DMAbuf_reset_dma (dev); */ -} - -static void -set_irq_hw (int level) -{ - 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_LEVEL %d does not exist\n", level); - return; - } - sb_setmixer (IRQ_NR, ival); -} - -long -sb16_dsp_init (long mem_start, struct address_info *hw_config) -{ - extern int sbc_major, sbc_minor; - - if (sbc_major < 4) - return mem_start; /* Not a SB16 */ - - sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); - - conf_printf (sb16_dsp_operations.name, hw_config); - - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations; - audio_devs[my_dev]->dmachan1 = audio_devs[my_dev]->dmachan2 = dma8; - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - - if (sound_alloc_dma (dma8, "SB16 (8bit)")) - { - printk ("SB16: Unable to grab DMA%d\n", dma8); - } - - if (dma16 != dma8) - if (sound_alloc_dma (dma16, "SB16 (16bit)")) - { - printk ("SB16: Unable to grab DMA%d\n", dma16); - } - } - else - printk ("SB: Too many DSP devices available\n"); - sb16_dsp_ok = 1; - return mem_start; -} - -static void -set_dma (int dma) -{ - if (dma >= 0 && dma < 4) - dma8 = dma; - if (dma >= 5 && dma <= 7) - dma16 = dma; -} - -int -sb16_dsp_detect (struct address_info *hw_config) -{ - struct address_info *sb_config; - extern int sbc_major, Jazz16_detected; - - extern void Jazz16_set_dma16 (int dma); - int irq; - - if (sb16_dsp_ok) - { - return 1; /* Can't drive two cards */ - } - - irq = hw_config->irq; - set_dma (hw_config->dma); - set_dma (hw_config->dma2); - - if (Jazz16_detected) - { - Jazz16_set_dma16 (dma16); - sb16_dsp_ok = 1; - return 1; - } - - if (dma8 == -1) - if (!(sb_config = sound_getconf (SNDCARD_SB))) - { - printk ("SB16 Error: Plain SB not configured\n"); - return 0; - } - else - { - dma8 = sb_config->dma; - irq = sb_config->irq; - } - - if (dma16 == -1) - dma16 = dma8; - - /* - * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0; - */ - - if (!sb_reset_dsp ()) - return 0; - - if (sbc_major < 4) /* Set by the plain SB driver */ - return 0; /* Not a SB16 */ - - if (dma16 < 4) - if (dma16 != dma8) - { - printk ("SB16 Error: Invalid DMA channel %d/%d\n", - dma8, dma16); - return 0; - } - - set_irq_hw (irq); - sb_setmixer (DMA_NR, (1 << dma16) | (1 << dma8)); - - DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, dma16)); - - /* - * dsp_showmessage(0xe3,99); - */ - sb16_dsp_ok = 1; - return 1; -} - -void -unload_sb16 (struct address_info *hw_config) -{ - extern int Jazz16_detected; - - if (Jazz16_detected) - return; - - sound_free_dma (dma8); - - if (dma16 != dma8) - sound_free_dma (dma16); -} - -void -sb16_dsp_interrupt (int unused) -{ - int data; - - data = inb (DSP_DATA_AVL16); /* - * Interrupt acknowledge - */ - - if (intr_active) - switch (irq_mode) - { - case IMODE_OUTPUT: - DMAbuf_outputintr (my_dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr (my_dev); - break; - - default: - printk ("SoundBlaster: Unexpected interrupt\n"); - } -} - -#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c --- v2.0.0/linux/drivers/sound/sb16_midi.c Sun Mar 24 22:50:18 1996 +++ linux/drivers/sound/sb16_midi.c Thu Jan 1 02:00:00 1970 @@ -1,364 +0,0 @@ -/* - * sound/sb16_midi.c - * - * The low level driver for the MPU-401 UART emulation of the SB16. - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - - -#include "sound_config.h" - -#if defined(CONFIG_SB) && defined(CONFIG_MIDI) - -#include "sb.h" - -#define DATAPORT (sb16midi_base) -#define COMDPORT (sb16midi_base+1) -#define STATPORT (sb16midi_base+1) - -extern int *sb_osp; -static int sb16midi_base = 0; - -static int -sb16midi_status (void) -{ - return inb (STATPORT); -} -#define input_avail() (!(sb16midi_status()&INPUT_AVAIL)) -#define output_ready() (!(sb16midi_status()&OUTPUT_READY)) -static void -sb16midi_cmd (unsigned char cmd) -{ - outb (cmd, COMDPORT); -} -static int -sb16midi_read (void) -{ - return inb (DATAPORT); -} -static void -sb16midi_write (unsigned char byte) -{ - outb (byte, DATAPORT); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static int sb16midi_opened = 0; -static int sb16midi_detected = 0; -static int my_dev; -extern int sbc_base; - -extern int Jazz16_detected; -extern int AudioDrive; - -static int reset_sb16midi (void); -static void (*midi_input_intr) (int dev, unsigned char data); -static volatile unsigned char input_byte; - -static void -sb16midi_input_loop (void) -{ - while (input_avail ()) - { - unsigned char c = sb16midi_read (); - - if (c == MPU_ACK) - input_byte = c; - else if (sb16midi_opened & OPEN_READ && midi_input_intr) - midi_input_intr (my_dev, c); - } -} - -void -sb16midiintr (int unit) -{ - if (sb16midi_base == 0) - return; - - if (input_avail ()) - sb16midi_input_loop (); -} - -void -sbmidiintr (int irq, void *dev_id, struct pt_regs *dummy) -{ - if (input_avail ()) - sb16midi_input_loop (); -} - -static int -sb16midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - if (sb16midi_opened) - { - return -EBUSY; - } - - while (input_avail ()) - sb16midi_read (); - - midi_input_intr = input; - sb16midi_opened = mode; - - return 0; -} - -static void -sb16midi_close (int dev) -{ - sb16midi_opened = 0; -} - -static int -sb16midi_out (int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - - /* - * Test for input since pending input seems to block the output. - */ - - save_flags (flags); - cli (); - - if (input_avail ()) - sb16midi_input_loop (); - - restore_flags (flags); - - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* - * Wait - */ - - if (!output_ready ()) - { - printk ("MPU-401: Timeout\n"); - return 0; - } - - sb16midi_write (midi_byte); - return 1; -} - -static int -sb16midi_start_read (int dev) -{ - return 0; -} - -static int -sb16midi_end_read (int dev) -{ - return 0; -} - -static int -sb16midi_ioctl (int dev, unsigned cmd, caddr_t arg) -{ - return -EINVAL; -} - -static void -sb16midi_kick (int dev) -{ -} - -static int -sb16midi_buffer_status (int dev) -{ - return 0; /* - * No data in buffers - */ -} - -#define MIDI_SYNTH_NAME "SoundBlaster MPU" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations sb16midi_operations = -{ - {"SoundBlaster MPU", 0, 0, SNDCARD_SB16MIDI}, - &std_midi_synth, - {0}, - sb16midi_open, - sb16midi_close, - sb16midi_ioctl, - sb16midi_out, - sb16midi_start_read, - sb16midi_end_read, - sb16midi_kick, - NULL, - sb16midi_buffer_status, - NULL -}; - -static void -enter_uart_mode (void) -{ - int ok, timeout; - unsigned long flags; - - save_flags (flags); - cli (); - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); - - input_byte = 0; - sb16midi_cmd (UART_MODE_ON); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_byte == MPU_ACK) - ok = 1; - else if (input_avail ()) - if (sb16midi_read () == MPU_ACK) - ok = 1; - - restore_flags (flags); -} - -long -attach_sb16midi (long mem_start, struct address_info *hw_config) -{ - sb16midi_base = hw_config->io_base; - - if (!sb16midi_detected) - return mem_start; - - request_region (hw_config->io_base, 4, "SB MIDI"); - enter_uart_mode (); - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return mem_start; - } - - conf_printf ("SoundBlaster MPU-401", hw_config); - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &sb16midi_operations; - return mem_start; -} - -static int -reset_sb16midi (void) -{ - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; - - /*save_flags(flags);cli(); */ - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* - * Wait - */ - input_byte = 0; - sb16midi_cmd (MPU_RESET); /* - * Send MPU-401 RESET Command - */ - - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ - - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail ()) - if (sb16midi_read () == MPU_ACK) - ok = 1; - - } - - sb16midi_opened = 0; - if (ok) - sb16midi_input_loop (); /* - * Flush input before enabling interrupts - */ - - /* restore_flags(flags); */ - - return ok; -} - -int -probe_sb16midi (struct address_info *hw_config) -{ - int ok = 0; - extern int sbc_major; - - extern void ess_midi_init (struct address_info *hw_config); - extern void Jazz16_midi_init (struct address_info *hw_config); - - if (check_region (hw_config->io_base, 4)) - return 0; - - if (AudioDrive) - ess_midi_init (hw_config); - else if (Jazz16_detected) - Jazz16_midi_init (hw_config); - else if (sbc_major < 4) - return 0; /* Not a SB16 */ - - sb16midi_base = hw_config->io_base; - - if (sb_get_irq () < 0) - return 0; - - ok = reset_sb16midi (); - - sb16midi_detected = ok; - return ok; -} - -void -unload_sb16midi (struct address_info *hw_config) -{ - release_region (hw_config->io_base, 4); -} - -#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.0.0/linux/drivers/sound/sb_audio.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/sb_audio.c Sun Jun 30 11:44:12 1996 @@ -0,0 +1,1202 @@ +/* + * sound/sb_audio.c + * + * Audio routines for SoundBlaster compatible cards. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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. + */ +#include + + +#include "sound_config.h" + +#if defined(CONFIG_SBDSP) + +#include "sb_mixer.h" +#include "sb.h" + +static int +sb_audio_open (int dev, int mode) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + { + printk ("SB: Incomplete initialization\n"); + return -(ENXIO); + } + + if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) + { + printk ("SB: Recording is not possible with this device\n"); + return -(EPERM); + } + + save_flags (flags); + cli (); + if (devc->opened) + { + restore_flags (flags); + return -(EBUSY); + } + + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + { + if (sound_open_dma (devc->dma16, "Sound Blaster 16 bit")) + { + return -(EBUSY); + } + } + devc->opened = mode; + restore_flags (flags); + + devc->irq_mode = IMODE_NONE; + sb_dsp_reset (devc); + + return 0; +} + +static void +sb_audio_close (int dev) +{ + sb_devc *devc = audio_devs[dev]->devc; + + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->dma8; + + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + sound_close_dma (devc->dma16); + + devc->opened = 0; +} + +static void +sb_set_output_parms (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + sb_devc *devc = audio_devs[dev]->devc; + + devc->trg_buf = buf; + devc->trg_bytes = nr_bytes; + devc->trg_intrflag = intrflag; + devc->trg_restart = restart_dma; + devc->irq_mode = IMODE_OUTPUT; +} + +static void +sb_set_input_parms (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) +{ + sb_devc *devc = audio_devs[dev]->devc; + + devc->trg_buf = buf; + devc->trg_bytes = count; + devc->trg_intrflag = intrflag; + devc->trg_restart = restart_dma; + devc->irq_mode = IMODE_INPUT; +} + +/* + * SB1.x compatible routines + */ + +static void +sb1_audio_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x14)) /* 8 bit DAC using DMA */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + } + else + printk ("SB: Unable to start DAC\n"); + restore_flags (flags); + devc->intr_active = 1; +} + +static void +sb1_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, + int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x24)) /* 8 bit ADC using DMA */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + } + else + printk ("SB Error: Unable to start ADC\n"); + restore_flags (flags); + + devc->intr_active = 1; +} + +static void +sb1_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb1_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + sb1_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +static int +sb1_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKOFF); + restore_flags (flags); + + devc->trigger_bits = 0; + return 0; +} + +static int +sb1_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKON); + restore_flags (flags); + devc->trigger_bits = 0; + return 0; +} + +static int +sb1_audio_set_speed (int dev, int speed) +{ + int max_speed = 23000; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + + if (devc->opened & OPEN_READ) + max_speed = 13000; + + if (speed > 0) + { + if (speed < 4000) + speed = 4000; + + if (speed > max_speed) + speed = max_speed; + + devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; + + tmp = 256 - devc->tconst; + speed = (1000000 + tmp / 2) / tmp; + + devc->speed = speed; + } + + return devc->speed; +} + +static short +sb1_audio_set_channels (int dev, short channels) +{ + sb_devc *devc = audio_devs[dev]->devc; + + return devc->channels = 1; +} + +static unsigned int +sb1_audio_set_bits (int dev, unsigned int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + return devc->bits = 8; +} + +static void +sb1_audio_halt_xfer (int dev) +{ + sb_devc *devc = audio_devs[dev]->devc; + + sb_dsp_reset (devc); +} + +/* + * SB 2.0 and SB 2.01 compatible routines + */ + +static void +sb20_audio_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= 23000) + cmd = 0x1c; /* 8 bit PCM output */ + else + cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ + + if (!sb_dsp_command (devc, cmd)) + printk ("SB: Unable to start DAC\n"); + + } + else + printk ("SB: Unable to start DAC\n"); + restore_flags (flags); + devc->intr_active = 1; +} + +static void +sb20_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, + int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) + cmd = 0x2c; /* 8 bit PCM input */ + else + cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ + + if (!sb_dsp_command (devc, cmd)) + printk ("SB: Unable to start ADC\n"); + } + else + printk ("SB Error: Unable to start ADC\n"); + restore_flags (flags); + + devc->intr_active = 1; +} + +static void +sb20_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb20_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + sb20_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +/* + * SB2.01 spesific speed setup + */ + +static int +sb201_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + int s = speed * devc->channels; + + if (speed > 0) + { + if (speed < 4000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + if (devc->opened & OPEN_READ && speed > 15000) + speed = 15000; + + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; + + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + + devc->speed = speed; + } + + return devc->speed; +} + +/* + * SB Pro spesific routines + */ + +static int +sbpro_audio_prepare_for_input (int dev, int bsize, int bcount) +{ /* For SB Pro and Jazz16 */ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == 16 ? devc->dma16 : devc->dma8; + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKOFF); + if (devc->channels == 1) + sb_dsp_command (devc, 0xa0 | bits); /* Mono input */ + else + sb_dsp_command (devc, 0xa8 | bits); /* Stereo input */ + restore_flags (flags); + + devc->trigger_bits = 0; + return 0; +} + +static int +sbpro_audio_prepare_for_output (int dev, int bsize, int bcount) +{ /* For SB Pro and Jazz16 */ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char tmp; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == 16 ? devc->dma16 : devc->dma8; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKON); + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + { + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + if (devc->channels == 1) + sb_dsp_command (devc, 0xa0 | bits); /* Mono output */ + else + sb_dsp_command (devc, 0xa8 | bits); /* Stereo output */ + } + else + { + tmp = sb_getmixer (devc, 0x0e); + if (devc->channels == 1) + tmp &= ~0x20; + else + tmp |= 0x20; + sb_setmixer (devc, 0x0e, tmp); + } + restore_flags (flags); + devc->trigger_bits = 0; + return 0; +} + +static int +sbpro_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (speed > 0) + { + if (speed < 4000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + if (devc->channels > 1 && speed > 22050) + speed = 22050; + + sb201_audio_set_speed (dev, speed); + } + + return devc->speed; +} + +static short +sbpro_audio_set_channels (int dev, short channels) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (channels == 1 || channels == 2) + if (channels != devc->channels) + { + devc->channels = channels; + sbpro_audio_set_speed (dev, devc->speed); + } + return devc->channels; +} + +static int +jazz16_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (speed > 0) + { + int tmp; + int s = speed * devc->channels; + + if (speed < 5000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; + + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + + devc->speed = speed; + } + + return devc->speed; +} + +/* + * ESS spesific routines + */ + +static void +ess_speed (sb_devc * devc) +{ + int divider; + unsigned char bits = 0; + int speed = devc->speed; + + if (speed < 4000) + speed = 4000; + else if (speed > 48000) + speed = 48000; + + if (speed > 22000) + { + bits = 0x80; + divider = 256 - (795500 + speed / 2) / speed; + } + else + { + divider = 128 - (397700 + speed / 2) / speed; + } + + bits |= (unsigned char) divider; + ess_write (devc, 0xa1, bits); + +/* + * Set filter divider register + */ + + speed = (speed * 9) / 20; /* Set filter rolloff to 90% of speed/2 */ + divider = 256 - 7160000 / (speed * 82); + ess_write (devc, 0xa2, divider); + + return; +} + +static int +ess_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + ess_speed (devc); + sb_dsp_command (devc, DSP_CMD_SPKOFF); + + ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ + ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8 == 0) + { /* 8 bit mono */ + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0xd0); + } + else + { /* 16 bit mono */ + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xf4); + } + } + else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xbc); + } + } + + ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); + ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); + + devc->trigger_bits = 0; + return 0; +} + +static int +ess_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + sb_dsp_reset (devc); + ess_speed (devc); + + ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ + ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write (devc, 0xb6, 0x80); + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0xd0); + } + else + { /* 16 bit mono */ + ess_write (devc, 0xb6, 0x00); + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xf4); + } + } + else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write (devc, 0xb6, 0x80); + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write (devc, 0xb6, 0x00); + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xbc); + } + } + + ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); + ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); + sb_dsp_command (devc, DSP_CMD_SPKON); + + devc->trigger_bits = 0; + return 0; +} + +static void +ess_audio_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; + + if (!restart_dma) + return; + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + + ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x05); /* Go */ + devc->intr_active = 1; +} + +static void +ess_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, + int restart_dma) +{ + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; + + if (!restart_dma) + return; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + + ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x0f); /* Go */ + devc->intr_active = 1; +} + +static void +ess_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + ess_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + ess_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +/* + * SB16 spesific routines + */ + +static int +sb16_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (speed > 0) + { + if (speed < 5000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + devc->speed = speed; + } + + return devc->speed; +} + +static unsigned int +sb16_audio_set_bits (int dev, unsigned int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (bits != 0) + if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE) + devc->bits = bits; + else + devc->bits = AFMT_U8; + + return devc->bits; +} + +static int +sb16_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + + devc->trigger_bits = 0; + return 0; +} + +static int +sb16_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + + devc->trigger_bits = 0; + return 0; +} + +static void +sb16_audio_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) +{ + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; + + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; + + if (!restart_dma) + return; + + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; + + save_flags (flags); + cli (); + + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + sb_dsp_command (devc, 0x41); + sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + + sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); + sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + + restore_flags (flags); +} + +static void +sb16_audio_start_input (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) +{ + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; + + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; + + if (!restart_dma) + return; + + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; + + save_flags (flags); + cli (); + + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + sb_dsp_command (devc, 0x42); + sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + + sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); + sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + + restore_flags (flags); +} + +static void +sb16_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb16_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + sb16_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +static int +sb_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +{ + return -(EINVAL); +} + +static void +sb_audio_reset (int dev) +{ + unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + + save_flags (flags); + cli (); + sb_dsp_reset (devc); + restore_flags (flags); +} + +static struct audio_driver sb1_audio_driver = /* SB1.x */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb1_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels +}; + +static struct audio_driver sb20_audio_driver = /* SB2.0 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels +}; + +static struct audio_driver sb201_audio_driver = /* SB2.01 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb201_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels +}; + +static struct audio_driver sbpro_audio_driver = /* SB Pro */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sbpro_audio_set_speed, + sb1_audio_set_bits, + sbpro_audio_set_channels +}; + +static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + jazz16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels +}; + +static struct audio_driver sb16_audio_driver = /* SB16 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb16_audio_prepare_for_input, + sb16_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb16_audio_trigger, + sb16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels +}; + +static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + ess_audio_prepare_for_input, + ess_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + ess_audio_trigger, + sb16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels +}; + +void +sb_audio_init (sb_devc * devc, char *name) +{ + int audio_flags = 0; + int format_mask = AFMT_U8; + + struct audio_driver *driver = &sb1_audio_driver; + + switch (devc->model) + { + case MDL_SB1: /* SB1.0 or SB 1.5 */ + DDB (printk ("Will use standard SB1.x driver\n")); + audio_flags = DMA_HARDSTOP; + break; + + case MDL_SB2: + DDB (printk ("Will use SB2.0 driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb20_audio_driver; + break; + + case MDL_SB201: + DDB (printk ("Will use SB2.01 (high speed) driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb201_audio_driver; + break; + + case MDL_JAZZ: + case MDL_SMW: + DDB (printk ("Will use Jazz16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &jazz16_audio_driver; + break; + + case MDL_ESS: + DDB (printk ("Will use ESS ES688/1688 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &ess_audio_driver; + break; + + case MDL_SB16: + DDB (printk ("Will use SB16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &sb16_audio_driver; + break; + + default: + DDB (printk ("Will use SB Pro driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sbpro_audio_driver; + } + + if ((devc->my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, + name, + driver, + sizeof (struct audio_driver), + audio_flags, + format_mask, + devc, + devc->dma8, + devc->dma8)) < 0) + { + return; + } + + audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev; + audio_devs[devc->my_dev]->min_fragment = 5; +} + +#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.0.0/linux/drivers/sound/sb_card.c Sun Mar 24 22:50:18 1996 +++ linux/drivers/sound/sb_card.c Sun Jun 30 11:44:12 1996 @@ -4,27 +4,11 @@ * Detection routine for the SoundBlaster cards. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -33,19 +17,15 @@ #if defined(CONFIG_SB) +#include "sb_mixer.h" #include "sb.h" -long -attach_sb_card (long mem_start, struct address_info *hw_config) +void +attach_sb_card (struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) - if (!sb_dsp_detect (hw_config)) - return mem_start; - mem_start = sb_dsp_init (mem_start, hw_config); - request_region (hw_config->io_base, 16, "SoundBlaster"); + sb_dsp_init (hw_config); #endif - - return mem_start; } int @@ -64,7 +44,6 @@ void unload_sb (struct address_info *hw_config) { - release_region (hw_config->io_base, 16); sb_dsp_unload (hw_config); } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.0.0/linux/drivers/sound/sb_common.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/sb_common.c Sun Jun 30 11:44:13 1996 @@ -0,0 +1,1207 @@ +/* + * sound/sb_common.c + * + * Common routines for SoundBlaster compatible cards. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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. + */ +#include + + +#include "sound_config.h" + +#if defined(CONFIG_SBDSP) + +#ifndef CONFIG_AUDIO +#error You will need to configure the sound driver with CONFIG_AUDIO option. +#endif + +#include "sb_mixer.h" +#include "sb.h" + +static sb_devc *detected_devc = NULL; /* For communication from probe to init */ +static sb_devc *last_devc = NULL; /* For MPU401 initalization */ +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 spesific control variables + */ + +static int jazz16_base = 0; /* Not detected */ +static unsigned char jazz16_bits = 0; /* I/O relocation bits */ + +/* + * Logitech Soundman Wave spesific initialization code + */ + +#ifdef SMW_MIDI0001_INCLUDED +#include "smw-midi0001.h" +#else +unsigned char *smw_ucode = NULL; +int smw_ucodeLen = 0; + +#endif + +int +sb_dsp_command (sb_devc * devc, unsigned char val) +{ + int i; + unsigned long limit; + + limit = jiffies + HZ / 10; /* + * The timeout is 0.1 secods + */ + + /* + * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 500000 && jiffies < limit; i++) + { + if ((inb (DSP_STATUS) & 0x80) == 0) + { + outb (val, DSP_COMMAND); + return 1; + } + } + + printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val); + return 0; +} + +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 0xffff; +} + +int +ess_write (sb_devc * devc, unsigned char reg, unsigned char data) +{ + /* Write a byte to an extended mode register of ES1688 */ + + if (!sb_dsp_command (devc, reg)) + return 0; + + return sb_dsp_command (devc, data); +} + +int +ess_read (sb_devc * devc, unsigned char reg) +{ +/* Read a byte from an extended mode register of ES1688 */ + + if (!sb_dsp_command (devc, 0xc0)) /* Read register command */ + return -1; + + if (!sb_dsp_command (devc, reg)) + return -1; + + return sb_dsp_get_byte (devc); +} + +void +sbintr (int irq, void *dev_id, struct pt_regs *dummy) +{ + int status; + unsigned char src = 0xff; + + sb_devc *devc = irq2devc[irq]; + + devc->irq_ok = 1; + + if (devc == NULL || devc->irq != irq) + { + DEB (printk ("sbintr: Bogus interrupt IRQ%d\n", irq)); + return; + } + + if (devc->model == MDL_SB16) + { + + src = sb_getmixer (devc, IRQ_STAT); /* Interrupt source register */ + +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + if (src & 4) + uart401intr (devc->irq, NULL, NULL); /* MPU401 interrupt */ +#endif + + 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_INIT: + break; + + case IMODE_MIDI: +#ifdef CONFIG_MIDI + sb_midi_interrupt (devc); +#endif + break; + + default: + printk ("SoundBlaster: Unexpected interrupt\n"); + } +/* + * Acknowledge interrupts + */ + + if (src & 0x01) + status = inb (DSP_DATA_AVAIL); + + if (devc->model == MDL_SB16 && src & 0x02) + status = inb (DSP_DATA_AVL16); +} + +int +sb_dsp_reset (sb_devc * devc) +{ + int loopc; + + if (devc->model == MDL_ESS) + outb (3, DSP_RESET); /* Reset FIFO too */ + else + outb (1, DSP_RESET); + + tenmicrosec (devc->osp); + outb (0, DSP_RESET); + tenmicrosec (devc->osp); + tenmicrosec (devc->osp); + tenmicrosec (devc->osp); + + for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); + + if (inb (DSP_READ) != 0xAA) + return 0; /* Sorry */ + + if (devc->model == MDL_ESS) + sb_dsp_command (devc, 0xc6); /* Enable extended mode */ + + return 1; +} + +static void +dsp_get_vers (sb_devc * devc) +{ + int i; + + unsigned long flags; + + save_flags (flags); + cli (); + devc->major = devc->minor = 0; + 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; + } + } + } + restore_flags (flags); +} + +static int +sb16_set_dma_hw (sb_devc * devc) +{ + int bits; + + if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) + { + printk ("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); + return 0; + } + + bits = (1 << devc->dma8); + + if (devc->dma16 >= 5 && devc->dma16 <= 7) + bits |= (1 << devc->dma16); + + sb_setmixer (devc, DMA_NR, bits); + return 1; +} + +static int +sb16_set_irq_hw (sb_devc * devc, int level) +{ + 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; + } + sb_setmixer (devc, IRQ_NR, ival); + return 1; +} + +static void +relocate_Jazz16 (sb_devc * devc, struct address_info *hw_config) +{ + 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; + } + + bits = jazz16_bits = bits << 5; + + jazz16_base = hw_config->io_base; + +/* + * Magic wake up sequence by writing to 0x201 (aka Joystick port) + */ + save_flags (flags); + cli (); + outb (0xAF, 0x201); + outb (0x50, 0x201); + outb (bits, 0x201); + restore_flags (flags); +} + +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. + */ + + if (!sb_dsp_command (devc, 0xfa)) + return 0; + + if (sb_dsp_get_byte (devc) != 0x12) + return 0; + +/* + * OK so far. Now configure the IRQ and DMA channel used by the acrd. + */ + 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; + } + + 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); + return 0; + } + + if (hw_config->dma2 < 0) + { + printk ("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; + } + + devc->dma16 = hw_config->dma2; + + if (!sb_dsp_command (devc, 0xfb)) + return 0; + + if (!sb_dsp_command (devc, jazz_dma_bits[hw_config->dma] | + (jazz_dma_bits[hw_config->dma2] << 4))) + return 0; + + if (!sb_dsp_command (devc, jazz_irq_bits[hw_config->irq])) + return 0; + +/* + * 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))); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy (hw_config->name, name); + devc->caps |= SB_NO_MIDI; + return 1; +} + +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]; + +/* + * 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 (ess_major == 0) + return 0; + + if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) + { + 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) + { + sprintf (name, + "ESS ES1688 AudioDrive (rev %d)", + 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))); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy (hw_config->name, name); + + + sb_dsp_reset (devc); /* Turn on extended mode */ + +/* + * 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; + } + + if (!ess_write (devc, 0xb1, cfg | (irq_bits << 2))) + printk ("\nESS1688: Failed to write to IRQ config register\n"); + +/* + * Set DMA configuration register + */ + + cfg = 0x50; /* Extended mode DMA ebable */ + + 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; + } + + if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) + printk ("\nESS1688: Failed to write to DMA config register\n"); + +/* + * Enable joystick and OPL3 + */ + + cfg = sb_getmixer (devc, 0x40); + sb_setmixer (devc, 0x40, cfg | 0x03); + if (devc->submodel >= 8) /* ES1688 */ + devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ + sb_dsp_reset (devc); + return 1; +} + +int +sb_dsp_detect (struct address_info *hw_config) +{ + sb_devc sb_info; + sb_devc *devc = &sb_info; + +/* + * Initialize variables + */ + DDB (printk ("sb_dsp_detect(%x) entered\n", hw_config->io_base)); + if (check_region (hw_config->io_base, 16)) + return 0; + + memset ((char *) &sb_info, 0, sizeof (sb_info)); /* Zero everything */ + + devc->osp = hw_config->osp; + devc->type = hw_config->card_subtype; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma8 = hw_config->dma; + + devc->dma16 = -1; + +/* + * Detect the device + */ + + if (sb_dsp_reset (devc)) + dsp_get_vers (devc); + else + devc->major = 0; + + if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) + if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) + relocate_Jazz16 (devc, hw_config); + + if (!sb_dsp_reset (devc)) + { + DDB (printk ("SB reset failed\n")); + 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 */ + } + } + +/* + * Save device information for sb_dsp_init() + */ + + + detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (sb_devc))); + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (detected_devc == NULL) + { + printk ("sb: Can't allocate memory for device information\n"); + return 0; + } + + memcpy ((char *) detected_devc, (char *) devc, sizeof (sb_devc)); + + DDB (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) +{ + sb_devc *devc; + int n; + char name[100]; + +/* + * Check if we had detected a SB device earlier + */ + DDB (printk ("sb_dsp_init(%x) entered\n", hw_config->io_base)); + + if (detected_devc == NULL) + { + DDB (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 + */ + devc->dev = num_audiodevs; + devc->caps = hw_config->driver_use_1; + + if (snd_set_irq_handler (hw_config->irq, + sbintr, "soundblaster", devc->osp) < 0) + { + printk ("SB: Can't allocate IRQ%d\n", hw_config->irq); + return; + } + + if (devc->major == 4) + if (!sb16_set_irq_hw (devc, devc->irq)) /* Unsupported IRQ */ + { + snd_release_irq (devc->irq); + 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 && + devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config)) + { + DDB (printk ("This is a genuine SB Pro\n")); + } + } + + irq2devc[hw_config->irq] = devc; + devc->irq_ok = 0; + + 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 < 10000000; i++); + } + + if (!devc->irq_ok) + { + printk ("sb: Interrupt test on IRQ%d failed - device disabled\n", devc->irq); + snd_release_irq (devc->irq); + return; + } + else + { + DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq)); + } + + 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"; + } + 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; + } + + if (!(devc->caps & SB_NO_MIXER)) + if (devc->major == 3 || devc->major == 4) + sb_mixer_init (devc); + +#ifdef CONFIG_MIDI + if (!(devc->caps & SB_NO_MIDI)) + sb_dsp_midi_init (devc); +#endif + + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster"; + + sprintf (name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); + conf_printf (name, hw_config); + hw_config->card_subtype = devc->model; + last_devc = devc; /* For SB MPU detection */ + + if (!(devc->caps & SB_NO_AUDIO)) + { + 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); + } +} + +void +sb_dsp_disable_midi (int io_base) +{ +} + +void +sb_dsp_disable_recording (int io_base) +{ +} + +void +sb_dsp_unload (struct address_info *hw_config) +{ + sb_devc *devc; + int irq = hw_config->irq; + + if (irq < 0) + irq *= -1; + + devc = irq2devc[irq]; + + if (devc && devc->base == hw_config->io_base) + { + 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); + } + + snd_release_irq (devc->irq); + irq2devc[devc->irq] = NULL; + } +} + +/* + * Mixer access routines + */ + +void +sb_setmixer (sb_devc * devc, unsigned int port, unsigned int value) +{ + unsigned long flags; + + save_flags (flags); + cli (); + outb ((unsigned char) (port & 0xff), MIXER_ADDR); + + tenmicrosec (devc->osp); + outb ((unsigned char) (value & 0xff), MIXER_DATA); + tenmicrosec (devc->osp); + restore_flags (flags); +} + +unsigned int +sb_getmixer (sb_devc * devc, unsigned int port) +{ + unsigned int val; + unsigned long flags; + + save_flags (flags); + cli (); + outb ((unsigned char) (port & 0xff), MIXER_ADDR); + + tenmicrosec (devc->osp); + val = inb (MIXER_DATA); + tenmicrosec (devc->osp); + restore_flags (flags); + + return val; +} + +#ifdef CONFIG_MIDI +/* + * MPU401 MIDI initialization. + */ + +static void +smw_putmem (sb_devc * devc, int base, int addr, unsigned char val) +{ + unsigned long flags; + + save_flags (flags); + cli (); + + outb (addr & 0xff, base + 1); /* Low address bits */ + outb (addr >> 8, base + 2); /* High address bits */ + outb (val, base); /* Data */ + + restore_flags (flags); +} + +static unsigned char +smw_getmem (sb_devc * devc, int base, int addr) +{ + unsigned long flags; + unsigned char val; + + save_flags (flags); + cli (); + + outb (addr & 0xff, base + 1); /* Low address bits */ + outb (addr >> 8, base + 2); /* High address bits */ + val = inb (base); /* Data */ + + restore_flags (flags); + return val; +} + +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; + + + /* + * 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); + + outb (control & 0xfc, mpu_base + 7); /* xxxxxx00 enables RAM */ + + /* + * 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); + + 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 */ + } + + /* + * There is RAM so assume it's really a SM Wave + */ + + devc->model = MDL_SMW; + smw_mixer_init (devc); + + 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; + } + } + + 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. + */ + { + 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. + */ + 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) +{ + 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 */ + } + + tmp = (hw_config->io_base & 0x0f0) >> 4; + + if (tmp > 3) + { + 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; + } + + cfg |= tmp << 5; + + sb_setmixer (devc, 0x40, cfg | 0x03); + return 1; +} + +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; + + 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; + } + + switch (sb_base) + { + 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) + */ + save_flags (flags); + cli (); + outb (0xAF, 0x201); + outb (0x50, 0x201); + outb (bits, 0x201); + restore_flags (flags); + + hw_config->name = "Jazz16"; + smw_midi_init (devc, hw_config); + + if (!sb_dsp_command (devc, 0xfb)) + return 0; + + if (!sb_dsp_command (devc, jazz_dma_bits[devc->dma8] | + (jazz_dma_bits[devc->dma16] << 4))) + return 0; + + if (!sb_dsp_command (devc, jazz_irq_bits[devc->irq] | + (jazz_irq_bits[irq] << 4))) + return 0; + + return 1; +} + +void +attach_sbmpu (struct address_info *hw_config) +{ +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + attach_uart401 (hw_config); +#endif +} + +int +probe_sbmpu (struct address_info *hw_config) +{ +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + sb_devc *devc = last_devc; + + if (last_devc == NULL) + return 0; + + last_devc = 0; + + if (check_region (hw_config->io_base, 4)) + { + printk ("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; + 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; + } + + return probe_uart401 (hw_config); +#else + return 0; +#endif +} + +void +unload_sbmpu (struct address_info *hw_config) +{ +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + unload_uart401 (hw_config); +#endif +} +#else /* !CONFIG_MIDI */ + +void +unload_sbmpu (struct address_info *hw_config) +{ +} + +int +probe_sbmpu (struct address_info *hw_config) +{ + return 0; +} + +void +attach_sbmpu (struct address_info *hw_config) +{ +} +#endif + + +#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c --- v2.0.0/linux/drivers/sound/sb_dsp.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/sb_dsp.c Thu Jan 1 02:00:00 1970 @@ -1,1661 +0,0 @@ -/* - * sound/sb_dsp.c - * - * The low level driver for the SoundBlaster DSP chip (SB1.0 to 2.1, SB Pro). - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - -/* - * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support Sound Galaxy NX Pro - * - * JRA Gibson April 1995 - * Code added for MV ProSonic/Jazz 16 in 16 bit mode - */ - -#include "sound_config.h" - -#if defined(CONFIG_SB) - -#include "sb.h" -#include "sb_mixer.h" -#undef SB_TEST_IRQ - -int sbc_base = 0; -static int sbc_irq = 0, sbc_dma; -static int open_mode = 0; /* Read, write or both */ -int Jazz16_detected = 0; -int AudioDrive = 0; /* 1=ES1688 detected */ -static int ess_mpu_irq = 0; -int sb_no_recording = 0; -static int dsp_count = 0; -static int trigger_bits; -static int mpu_base = 0, mpu_irq = 0; -static int sb16_inited = 0; - -/* - * The DSP channel can be used either for input or output. Variable - * 'sb_irq_mode' will be set when the program calls read or write first time - * after open. Current version doesn't support mode changes without closing - * and reopening the device. Support for this feature may be implemented in a - * future version of this driver. - */ - -int sb_dsp_ok = 0; /* - - - * * * * Set to 1 after successful - * initialization * */ -static int midi_disabled = 0; -int sb_dsp_highspeed = 0; -int sbc_major = 0, sbc_minor = 0; -static int dsp_stereo = 0; -static int dsp_current_speed = DSP_DEFAULT_SPEED; -static int dsp_requested_speed = DSP_DEFAULT_SPEED; -static int sb16 = 0; -static int irq_verified = 0; - -int sb_midi_mode = NORMAL_MIDI; -int sb_midi_busy = 0; -int sb_dsp_busy = 0; - -volatile int sb_irq_mode = IMODE_NONE; -static volatile int irq_ok = 0; - -static int dma8 = 1; -static int dsp_16bit = 0; - -/* 16 bit support - */ - -static int dma16 = 1; - -static int dsp_set_bits (int arg); -static int initialize_ProSonic16 (void); - -/* end of 16 bit support - */ - -int sb_duplex_midi = 0; -static int my_dev = 0; - -volatile int sb_intr_active = 0; - -static int dsp_speed (int); -static int dsp_set_stereo (int mode); -static void sb_dsp_reset (int dev); -static void dsp_get_vers (struct address_info *hw_config); -int *sb_osp = NULL; - -#if defined(CONFIG_MIDI) || defined(CONFIG_AUDIO) - -/* - * Common code for the midi and pcm functions - */ - -int -sb_dsp_command (unsigned char val) -{ - int i; - unsigned long limit; - - limit = jiffies + HZ / 10; /* - * The timeout is 0.1 seconds - */ - - /* - * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb (DSP_STATUS) & 0x80) == 0) - { - outb (val, DSP_COMMAND); - return 1; - } - } - - printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val); - return 0; -} - -static int -ess_write (unsigned char reg, unsigned char data) -{ - /* Write a byte to an extended mode register of ES1688 */ - - if (!sb_dsp_command (reg)) - return 0; - - return sb_dsp_command (data); -} - -static int -ess_read (unsigned char reg) -{ -/* Read a byte from an extended mode register of ES1688 */ - - int i; - - if (!sb_dsp_command (0xc0)) /* Read register command */ - return -1; - - if (!sb_dsp_command (reg)) - return -1; - - for (i = 1000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - return inb (DSP_READ); - } - - return -1; -} - -void -sbintr (int irq, void *dev_id, struct pt_regs *dummy) -{ - int status; - - if (sb16 && !AudioDrive) - { - unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ - - if (src & 3) - sb16_dsp_interrupt (irq); - -#ifdef CONFIG_MIDI - if (src & 4) - sb16midiintr (irq); /* - * SB MPU401 interrupt - */ -#endif - - if (!(src & 1)) - return; /* - * Not a DSP interrupt - */ - } - - status = inb (DSP_DATA_AVAIL); /* - * Clear interrupt - */ - if (sb_intr_active) - switch (sb_irq_mode) - { - case IMODE_OUTPUT: - if (!AudioDrive) - sb_intr_active = 0; - DMAbuf_outputintr (my_dev, 1); - break; - - case IMODE_INPUT: - if (!AudioDrive) - sb_intr_active = 0; - DMAbuf_inputintr (my_dev); - break; - - case IMODE_INIT: - sb_intr_active = 0; - irq_ok = 1; - break; - - case IMODE_MIDI: -#ifdef CONFIG_MIDI - sb_midi_interrupt (irq); -#endif - break; - - default: - printk ("SoundBlaster: Unexpected interrupt\n"); - } -} - -int -sb_get_irq (void) -{ - return 0; -} - -void -sb_free_irq (void) -{ -} - -int -sb_reset_dsp (void) -{ - int loopc; - - if (AudioDrive) - outb (3, DSP_RESET); /* Reset FIFO too */ - else - outb (1, DSP_RESET); - - tenmicrosec (sb_osp); - outb (0, DSP_RESET); - tenmicrosec (sb_osp); - tenmicrosec (sb_osp); - tenmicrosec (sb_osp); - - for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); - - if (inb (DSP_READ) != 0xAA) - return 0; /* Sorry */ - - if (AudioDrive) - sb_dsp_command (0xc6); /* Enable extended mode */ - - return 1; -} - -#endif - -#ifdef CONFIG_AUDIO - -static void -dsp_speaker (char state) -{ - if (state) - sb_dsp_command (DSP_CMD_SPKON); - else - sb_dsp_command (DSP_CMD_SPKOFF); -} - -static int -ess_speed (int speed) -{ - int divider; - unsigned char bits = 0; - - if (speed < 4000) - speed = 4000; - else if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - dsp_current_speed = 795500 / (256 - divider); - } - else - { - divider = 128 - (397700 + speed / 2) / speed; - dsp_current_speed = 397700 / (128 - divider); - } - - bits |= (unsigned char) divider; - ess_write (0xa1, bits); - -/* - * Set filter divider register - */ - - speed = (speed * 9) / 20; /* Set filter rolloff to 90% of speed/2 */ - divider = 256 - 7160000 / (speed * 82); - ess_write (0xa2, divider); - - return dsp_current_speed; -} - -static int -dsp_speed (int speed) -{ - unsigned char tconst; - unsigned long flags; - int max_speed = 44100; - - dsp_requested_speed = speed; - - if (AudioDrive) - return ess_speed (speed); - - if (speed < 4000) - speed = 4000; - - /* - * Older SB models don't support higher speeds than 22050. - */ - - if (sbc_major < 2 || - (sbc_major == 2 && sbc_minor == 0)) - max_speed = 22050; - - /* - * SB models earlier than SB Pro have low limit for the input speed. - */ - if (open_mode != OPEN_WRITE) /* Recording is possible */ - if (sbc_major < 3) /* Limited input speed with these cards */ - if (sbc_major == 2 && sbc_minor > 0) - max_speed = 15000; - else - max_speed = 13000; - - if (speed > max_speed) - speed = max_speed; /* - * Invalid speed - */ - - /* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */ -#if !defined (SM_GAMES) - /* - * Max. stereo speed is 22050 - */ - if (dsp_stereo && speed > 22050 && Jazz16_detected == 0 && AudioDrive == 0) - speed = 22050; -#endif - - if ((speed > 22050) && sb_midi_busy) - { - printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n"); - speed = 22050; - } - - if (dsp_stereo) - speed *= 2; - - /* - * Now the speed should be valid - */ - - if (speed > 22050) - { /* - * High speed mode - */ - int tmp; - - tconst = (unsigned char) ((65536 - - ((256000000 + speed / 2) / speed)) >> 8); - sb_dsp_highspeed = 1; - - save_flags (flags); - cli (); - if (sb_dsp_command (0x40)) - sb_dsp_command (tconst); - restore_flags (flags); - - tmp = 65536 - (tconst << 8); - speed = (256000000 + tmp / 2) / tmp; - } - else - { - int tmp; - - sb_dsp_highspeed = 0; - tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - - save_flags (flags); - cli (); - if (sb_dsp_command (0x40)) /* - * Set time constant - */ - sb_dsp_command (tconst); - restore_flags (flags); - - tmp = 256 - tconst; - speed = (1000000 + tmp / 2) / tmp; - } - - if (dsp_stereo) - speed /= 2; - - dsp_current_speed = speed; - return speed; -} - -static int -dsp_set_stereo (int mode) -{ - dsp_stereo = 0; - - if (sbc_major < 3 || sb16) - return 0; /* - * Sorry no stereo - */ - - if (mode && sb_midi_busy) - { - printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n"); - return 0; - } - - dsp_stereo = !!mode; - dsp_speed (dsp_requested_speed); - return dsp_stereo; -} - -static unsigned long trg_buf; -static int trg_bytes; -static int trg_intrflag; -static int trg_restart; - -static void -sb_dsp_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag, int restart_dma) -{ - trg_buf = buf; - trg_bytes = nr_bytes; - trg_intrflag = intrflag; - trg_restart = restart_dma; - sb_irq_mode = IMODE_OUTPUT; -} - -static void -actually_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag, int restart_dma) -{ - unsigned long flags; - int count = nr_bytes; - - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - - sb_irq_mode = 0; - - if (audio_devs[dev]->dmachan1 > 3) - count >>= 1; - count--; - dsp_count = count; - - sb_irq_mode = IMODE_OUTPUT; - - if (AudioDrive) - { - short c = -nr_bytes; - - ess_write (0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_write (0xb8, ess_read (0xb8) | 0x01); /* Go */ - } - else if (sb_dsp_highspeed) - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x48)) /* - * High speed size - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - sb_dsp_command (0x91); /* - * High speed 8 bit DAC - */ - } - else - printk ("SB Error: Unable to start (high speed) DAC\n"); - restore_flags (flags); - } - else - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x14)) /* - * 8-bit DAC (DMA) - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - } - else - printk ("SB Error: Unable to start DAC\n"); - restore_flags (flags); - } - sb_intr_active = 1; -} - -static void -sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, - int restart_dma) -{ - if (sb_no_recording) - { - return; - } - - trg_buf = buf; - trg_bytes = count; - trg_intrflag = intrflag; - trg_restart = restart_dma; - sb_irq_mode = IMODE_INPUT; -} - -static void -actually_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, - int restart_dma) -{ - unsigned long flags; - int count = nr_bytes; - - if (sb_no_recording) - { - return; - } - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - sb_irq_mode = 0; - - if (audio_devs[dev]->dmachan1 > 3) - count >>= 1; - count--; - dsp_count = count; - - sb_irq_mode = IMODE_INPUT; - - if (AudioDrive) - { - short c = -nr_bytes; - - ess_write (0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_write (0xb8, ess_read (0xb8) | 0x01); /* Go */ - } - else if (sb_dsp_highspeed) - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x48)) /* - * High speed size - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - sb_dsp_command (0x99); /* - * High speed 8 bit ADC - */ - } - else - printk ("SB Error: Unable to start (high speed) ADC\n"); - restore_flags (flags); - } - else - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x24)) /* - * 8-bit ADC (DMA) - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - } - else - printk ("SB Error: Unable to start ADC\n"); - restore_flags (flags); - } - - sb_intr_active = 1; -} - -static void -sb_dsp_trigger (int dev, int bits) -{ - - if (!bits) - sb_dsp_command (0xd0); /* Halt DMA */ - else if (bits & sb_irq_mode) - { - switch (sb_irq_mode) - { - case IMODE_INPUT: - actually_start_input (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - break; - - case IMODE_OUTPUT: - actually_output_block (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - break; - } - } - - trigger_bits = bits; -} - -static void -dsp_cleanup (void) -{ - sb_intr_active = 0; -} - -static int -sb_dsp_prepare_for_input (int dev, int bsize, int bcount) -{ - if (sb_no_recording) - { - printk ("SB Error: This device doesn't support recording\n"); - return 0; - } - - dsp_cleanup (); - dsp_speaker (OFF); - dsp_speed (dsp_requested_speed); - - if (sbc_major == 3) /* - * SB Pro - */ - { - if (AudioDrive) - { - - ess_write (0xb8, 0x0e); /* Auto init DMA mode */ - ess_write (0xa8, (ess_read (0xa8) & ~0x04) | - (2 - dsp_stereo)); /* Mono/stereo */ - ess_write (0xb9, 2); /* Demand mode (2 bytes/xfer) */ - - if (!dsp_stereo) - { - if (dsp_16bit == 0) - { /* 8 bit mono */ - ess_write (0xb7, 0x51); - ess_write (0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (!dsp_16bit) - { /* 8 bit stereo */ - ess_write (0xb7, 0x51); - ess_write (0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xbc); - } - } - - ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50); - ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50); - } - else - { /* !AudioDrive */ - - /* Select correct dma channel - * for 16/8 bit access - */ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - if (dsp_stereo) - sb_dsp_command (dsp_16bit ? 0xac : 0xa8); - else - sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); - - } /* !AudioDrive */ - } - trigger_bits = 0; - return 0; -} - -static int -sb_dsp_prepare_for_output (int dev, int bsize, int bcount) -{ - dsp_cleanup (); - dsp_speaker (OFF); - dsp_speed (dsp_requested_speed); - - if (sbc_major == 3) /* SB Pro (at least ) */ - { - - if (AudioDrive) - { - - ess_write (0xb8, 4); /* Auto init DMA mode */ - ess_write (0xa8, ess_read (0xa8) | - (2 - dsp_stereo)); /* Mono/stereo */ - ess_write (0xb9, 2); /* Demand mode (2 bytes/xfer) */ - - if (!dsp_stereo) - { - if (dsp_16bit == 0) - { /* 8 bit mono */ - ess_write (0xb6, 0x80); - ess_write (0xb7, 0x51); - ess_write (0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (0xb6, 0x00); - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (!dsp_16bit) - { /* 8 bit stereo */ - ess_write (0xb6, 0x80); - ess_write (0xb7, 0x51); - ess_write (0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write (0xb6, 0x00); - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xbc); - } - } - - ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50); - ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50); - } - else - { /* !AudioDrive */ - - /* 16 bit specific instructions (Jazz16) - */ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - if (Jazz16_detected != 2) /* SM Wave */ - sb_mixer_set_stereo (dsp_stereo); - if (dsp_stereo) - sb_dsp_command (dsp_16bit ? 0xac : 0xa8); - else - sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); - } /* !AudioDrive */ - - } - - trigger_bits = 0; - dsp_speaker (ON); - return 0; -} - -static void -sb_dsp_halt_xfer (int dev) -{ - if (AudioDrive) - sb_reset_dsp (); -} - -static int -verify_irq (void) -{ - irq_ok = 1; - return irq_ok; -} - -static int -sb_dsp_open (int dev, int mode) -{ - int retval; - - if (!sb_dsp_ok) - { - printk ("SB Error: SoundBlaster board not installed\n"); - return -ENXIO; - } - - if (sb_no_recording && mode & OPEN_READ) - { - printk ("SB Warning: Recording not supported by this device\n"); - } - - if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) - { - printk ("SB: Audio device or MIDI already in use.\n"); - return -EBUSY; - } - - if (!sb_midi_busy) - sb_reset_dsp (); - - if (!irq_verified) - { - verify_irq (); - irq_verified = 1; - } - else if (!irq_ok) - printk ("SB Warning: Incorrect IRQ setting %d\n", - sbc_irq); - - retval = sb_get_irq (); - if (retval) - return retval; - - /* Allocate 8 bit dma - */ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dma8; - - /* Allocate 16 bit dma (jazz16) - */ - if (Jazz16_detected != 0) - if (dma16 != dma8) - { - if (sound_open_dma (dma16, "Jazz16 16 bit")) - { - sb_free_irq (); - /* DMAbuf_close_dma (dev); */ - return -EBUSY; - } - } - - sb_irq_mode = IMODE_NONE; - - sb_dsp_busy = 1; - open_mode = mode; - - return 0; -} - -static void -sb_dsp_close (int dev) -{ - /* Release 16 bit dma channel - */ - if (Jazz16_detected) - { - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dma8; - - if (dma16 != dma8) - sound_close_dma (dma16); - } - - if (AudioDrive) - sb_reset_dsp (); - - /* DMAbuf_close_dma (dev); */ - sb_free_irq (); - /* sb_dsp_command (0xd4); */ - dsp_cleanup (); - dsp_speaker (OFF); - sb_dsp_busy = 0; - sb_dsp_highspeed = 0; - open_mode = 0; -} - -static int -dsp_set_bits (int arg) -{ - if (arg) - if (Jazz16_detected == 0 && AudioDrive == 0) - dsp_16bit = 0; - else - switch (arg) - { - case 8: - dsp_16bit = 0; - break; - case 16: - dsp_16bit = 1; - break; - default: - dsp_16bit = 0; - } - - return dsp_16bit ? 16 : 8; -} - -static int -sb_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) -{ - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return dsp_speed ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_speed (get_fs_long ((long *) arg))); - break; - - case SOUND_PCM_READ_RATE: - if (local) - return dsp_current_speed; - return snd_ioctl_return ((int *) arg, dsp_current_speed); - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return dsp_set_stereo ((long) arg - 1) + 1; - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1); - break; - - case SOUND_PCM_READ_CHANNELS: - if (local) - return dsp_stereo + 1; - return snd_ioctl_return ((int *) arg, dsp_stereo + 1); - break; - - case SNDCTL_DSP_STEREO: - if (local) - return dsp_set_stereo ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg))); - break; - - /* Word size specific cases here. - * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS - */ - case SNDCTL_DSP_SETFMT: - if (local) - return dsp_set_bits ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg))); - break; - - case SOUND_PCM_READ_BITS: - if (local) - return dsp_16bit ? 16 : 8; - return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8); - break; - - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - break; - - default:; - } - - return -EINVAL; -} - -static void -sb_dsp_reset (int dev) -{ - unsigned long flags; - - save_flags (flags); - cli (); - - sb_reset_dsp (); - dsp_speed (dsp_current_speed); - dsp_cleanup (); - - restore_flags (flags); -} - -#endif - - -/* - * Initialization of a Media Vision ProSonic 16 Soundcard. - * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets - * the base address, the DMA-channels, interrupts and enables the joystickport. - * - * Also used by Jazz 16 (same card, different name) - * - * written 1994 by Rainer Vranken - * E-Mail: rvranken@polaris.informatik.uni-essen.de - */ - -unsigned int -get_sb_byte (void) -{ - int i; - - for (i = 1000; i; i--) - if (inb (DSP_DATA_AVAIL) & 0x80) - { - return inb (DSP_READ); - } - - return 0xffff; -} - -/* - * Logitech Soundman Wave detection and initialization by Hannu Savolainen. - * - * There is a microcontroller (8031) in the SM Wave card for MIDI emulation. - * it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific - * control register for MC reset, SCSI, OPL4 and DSP (future expansion) - * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16 - * based soundcard. - */ - -static void -smw_putmem (int base, int addr, unsigned char val) -{ - unsigned long flags; - - save_flags (flags); - cli (); - - outb (addr & 0xff, base + 1); /* Low address bits */ - outb (addr >> 8, base + 2); /* High address bits */ - outb (val, base); /* Data */ - - restore_flags (flags); -} - -static unsigned char -smw_getmem (int base, int addr) -{ - unsigned long flags; - unsigned char val; - - save_flags (flags); - cli (); - - outb (addr & 0xff, base + 1); /* Low address bits */ - outb (addr >> 8, base + 2); /* High address bits */ - val = inb (base); /* Data */ - - restore_flags (flags); - return val; -} - -#ifdef SMW_MIDI0001_INCLUDED -#include "smw-midi0001.h" -#else -unsigned char *smw_ucode = NULL; -int smw_ucodeLen = 0; - -#endif - -static int -initialize_smw (int mpu_base) -{ - - int mp_base = mpu_base + 4; /* Microcontroller base */ - int i; - unsigned char control; - - - /* - * 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 (sb_osp); - - outb (control & 0xfc, mpu_base + 7); /* xxxxxx00 enables RAM */ - - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem (mp_base, 0, 0x00); - smw_putmem (mp_base, 1, 0xff); - tenmicrosec (sb_osp); - - if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff) - { - printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", - smw_getmem (mp_base, 0), smw_getmem (mp_base, 1)); - return 0; /* No RAM */ - } - - /* - * There is RAM so assume it's really a SM Wave - */ - - 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 (mp_base, i, smw_ucode[i]); - - /* - * Verify microcode - */ - - for (i = 0; i < 8192; i++) - if (smw_getmem (mp_base, i) != smw_ucode[i]) - { - printk ("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. - */ - { - 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. - */ - 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 */ - return 1; -} - -static int -initialize_ProSonic16 (void) -{ - int x; - static unsigned char int_translat[16] = - {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] = - {0, 1, 0, 2, 0, 3, 0, 4}; - - outb (0xAF, 0x201); /* ProSonic/Jazz16 wakeup */ - for (x = 0; x < 1000; ++x) /* wait 10 milliseconds */ - tenmicrosec (sb_osp); - outb (0x50, 0x201); - outb ((sbc_base & 0x70) | ((mpu_base & 0x30) >> 4), 0x201); - - if (sb_reset_dsp ()) - { /* OK. We have at least a SB */ - - /* Check the version number of ProSonic (I guess) */ - - if (!sb_dsp_command (0xFA)) - return 1; - if (get_sb_byte () != 0x12) - return 1; - - if (sb_dsp_command (0xFB) && /* set DMA-channels and Interrupts */ - sb_dsp_command ((dma_translat[dma16] << 4) | dma_translat[dma8]) && - sb_dsp_command ((int_translat[mpu_irq] << 4) | int_translat[sbc_irq])) - { - Jazz16_detected = 1; - - if (mpu_base != 0) - if (initialize_smw (mpu_base)) - Jazz16_detected = 2; - - sb_dsp_disable_midi (); - } - - return 1; /* There was at least a SB */ - } - return 0; /* No SB or ProSonic16 detected */ -} - -int -sb_dsp_detect (struct address_info *hw_config) -{ - if (sb_dsp_ok) - return 0; /* - * Already initialized - */ - - sbc_base = hw_config->io_base; - sbc_irq = hw_config->irq; - sbc_dma = hw_config->dma; - sb_osp = hw_config->osp; - dma8 = dma16 = hw_config->dma; - - if (sb_reset_dsp ()) - dsp_get_vers (hw_config); - else - sbc_major = 0; - - if (sbc_major == 3 || sbc_major == 0) - if (initialize_ProSonic16 ()) - return 1; - - if (!sb_reset_dsp ()) - return 0; - - return 1; /* - * Detected - */ -} - -#ifdef CONFIG_AUDIO -static struct audio_operations sb_dsp_operations = -{ - "SoundBlaster", - NOTHING_SPECIAL, - AFMT_U8, /* Just 8 bits. Poor old SB */ - NULL, - sb_dsp_open, - sb_dsp_close, - sb_dsp_output_block, - sb_dsp_start_input, - sb_dsp_ioctl, - sb_dsp_prepare_for_input, - sb_dsp_prepare_for_output, - sb_dsp_reset, - sb_dsp_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb_dsp_trigger -}; - -#endif - -static void -ess_init (int ess_minor) /* ESS1688 Initialization */ -{ - unsigned char cfg, irq_bits = 0, dma_bits = 0; - - AudioDrive = 1; - - if (ess_minor >= 8) /* ESS1688 doesn't support SB MIDI */ - midi_disabled = 1; - - sb_reset_dsp (); /* Turn on extended mode */ - -/* - * Set IRQ configuration register - */ - - cfg = 0x50; /* Enable only DMA counter interrupt */ - - switch (sbc_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", sbc_irq); - } - - if (!ess_write (0xb1, cfg | (irq_bits << 2))) - printk ("\nESS1688: Failed to write to IRQ config register\n"); - -/* - * Set DMA configuration register - */ - - cfg = 0x50; /* Extended mode DMA enable */ - - if (sbc_dma > 3 || sbc_dma < 0 || sbc_dma == 2) - { - dma_bits = 0; - cfg = 0x00; /* Disable all DMA */ - printk ("\nESS1688: Invalid DMA %d\n", sbc_dma); - } - else - { - if (sbc_dma == 3) - dma_bits = 3; - else - dma_bits = sbc_dma + 1; - } - - if (!ess_write (0xb2, cfg | (dma_bits << 2))) - printk ("\nESS1688: Failed to write to DMA config register\n"); - -/* - * Enable joystick and OPL3 - */ - - cfg = sb_getmixer (0x40); - sb_setmixer (0x40, cfg | 0x03); -} - -#ifdef CONFIG_MIDI -void -ess_midi_init (struct address_info *hw_config) /* called from sb16_midi.c */ -{ - unsigned char cfg, tmp; - - cfg = sb_getmixer (0x40) & 0x03; - - tmp = (hw_config->io_base & 0x0f0) >> 4; - - if (tmp > 3) - { - sb_setmixer (0x40, cfg); - return; - } - - 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; - } - - cfg |= tmp << 5; - - if (tmp != 1) - { - ess_mpu_irq = hw_config->irq; - - if (snd_set_irq_handler (ess_mpu_irq, sbmidiintr, "ES1688 MIDI", sb_osp) < 0) - printk ("ES1688: Can't allocate IRQ%d\n", ess_mpu_irq); - } - - sb_setmixer (0x40, cfg); -} -#endif - -void -Jazz16_midi_init (struct address_info *hw_config) -{ - extern void smw_mixer_init (void); - extern void sb_mixer_reset (void); - - mpu_base = hw_config->io_base; - mpu_irq = hw_config->irq; - - initialize_ProSonic16 (); - - smw_mixer_init (); - sb_mixer_reset (); -} - -void -Jazz16_set_dma16 (int dma) -{ - dma16 = dma; - -/* Allocate 16 bit dma (Jazz16) - */ - if (dma16 != dma8) - { - if (sound_alloc_dma (dma16, "Jazz16 16 bit")) - { - printk ("Jazz16: Can't allocate 16 bit DMA channel\n"); - Jazz16_detected = 0; - return; - } - } - initialize_ProSonic16 (); -} - -static void -dsp_get_vers (struct address_info *hw_config) -{ - int i; - - unsigned long flags; - - save_flags (flags); - cli (); - sb_osp = hw_config->osp; - sbc_major = sbc_minor = 0; - sb_dsp_command (0xe1); /* Get version */ - - for (i = 100000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { - if (sbc_major == 0) - sbc_major = inb (DSP_READ); - else - { - sbc_minor = inb (DSP_READ); - break; - } - } - } - restore_flags (flags); -} - -long -sb_dsp_init (long mem_start, struct address_info *hw_config) -{ - int i; - int ess_major = 0, ess_minor = 0; - - int mixer_type = 0; - - if (sbc_major == 0) - dsp_get_vers (hw_config); - - if (sbc_major == 0) - { - sb_reset_dsp (); - dsp_get_vers (hw_config); - } - - if (sbc_major == 0) - { - printk ("\n\nFailed to get SB version (%x) - possible I/O conflict?\n\n", - inb (DSP_DATA_AVAIL)); - sbc_major = 1; - } - - if (sbc_major == 2 || sbc_major == 3) - sb_duplex_midi = 1; - - if (sbc_major == 4) - sb16 = 1; - - if (sbc_major == 3 && sbc_minor == 1) - { - -/* - * Try to detect ESS chips. - */ - - sb_dsp_command (0xe7); /* - * Return identification bytes. - */ - - for (i = 1000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { /* - * wait for Data Ready - */ - if (ess_major == 0) - ess_major = inb (DSP_READ); - else - { - ess_minor = inb (DSP_READ); - break; - } - } - } - } - - if (snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster", sb_osp) < 0) - printk ("sb_dsp: Can't allocate IRQ\n");; - -#ifdef CONFIG_AUDIO - if (sbc_major >= 3) - { - if (Jazz16_detected) - { - if (Jazz16_detected == 2) - sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor); - else - sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor); - sb_dsp_operations.format_mask |= AFMT_S16_LE; /* Hurrah, 16 bits */ - } - else -#ifdef __SGNXPRO__ - if (mixer_type == 2) - { - sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor); - } - else -#endif - - if (sbc_major == 4) - { - sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); - } - else if (ess_major != 0) - { - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) - sprintf (sb_dsp_operations.name, "ESS ES488 AudioDrive (rev %d)", - ess_minor & 0x0f); - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) - { - sprintf (sb_dsp_operations.name, - "ESS ES1688 AudioDrive (rev %d)", - ess_minor & 0x0f); - sb_dsp_operations.format_mask |= AFMT_S16_LE; - ess_init (ess_minor); - } - } - else - { - sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor); - } - } - else - { - sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor); - } - - conf_printf (sb_dsp_operations.name, hw_config); - - if (sbc_major >= 3) - mixer_type = sb_mixer_init (sbc_major); - - if (!sb16) - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations; - - if (AudioDrive) - audio_devs[my_dev]->flags |= DMA_AUTOMODE; - - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - dma8 = audio_devs[my_dev]->dmachan1 = hw_config->dma; - dma16 = audio_devs[my_dev]->dmachan2 = hw_config->dma; - if (sound_alloc_dma (hw_config->dma, "SoundBlaster")) - printk ("sb_dsp.c: Can't allocate DMA channel\n"); - } - else - printk ("SB: Too many DSP devices available\n"); -#else - conf_printf ("SoundBlaster (configured without audio support)", hw_config); -#endif - -#ifdef CONFIG_MIDI - if (!midi_disabled && !sb16) /* - * Midi don't work in the SB emulation mode * - * of PAS, SB16 has better midi interface - */ - sb_midi_init (sbc_major); -#endif - - sb_dsp_ok = 1; - sb_reset_dsp (); - - if (sb16 || hw_config->dma2 >= 0) - { - if (sb16_dsp_detect (hw_config)) - { - sb16_inited = 1; - return sb16_dsp_init (mem_start, hw_config); - } - } - return mem_start; -} - -void -sb_dsp_unload (struct address_info *hw_config) -{ - sound_free_dma (dma8); - - /* Free 16 bit dma (Jazz16) - */ - if (Jazz16_detected != 0) - if (dma16 != dma8) - { - sound_free_dma (dma16); - } - snd_release_irq (sbc_irq); - - if (AudioDrive && ess_mpu_irq) - { - snd_release_irq (ess_mpu_irq); - } - - if (sb16_inited) - unload_sb16 (hw_config); -} - -void -sb_dsp_disable_midi (void) -{ - midi_disabled = 1; -} - - -#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v2.0.0/linux/drivers/sound/sb_midi.c Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/sb_midi.c Sun Jun 30 11:44:14 1996 @@ -4,34 +4,18 @@ * The low level driver for the SoundBlaster DS chips. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include #include "sound_config.h" -#if defined(CONFIG_SB) && defined(CONFIG_MIDI) +#if defined(CONFIG_SBDSP) && defined(CONFIG_MIDI) #include "sb.h" #undef SB_TEST_IRQ @@ -44,27 +28,6 @@ * future version of this driver. */ -extern int sb_dsp_ok; /* Set to 1 after successful initialization */ -extern int sbc_base; - -extern int sb_midi_mode; -extern int sb_midi_busy; /* - - - * * * * 1 if the process has output to MIDI - * - */ -extern int sb_dsp_busy; -extern int sb_dsp_highspeed; - -extern volatile int sb_irq_mode; -extern int sb_duplex_midi; -extern int sb_intr_active; -int input_opened = 0; -static int my_dev; - -extern int *sb_osp; - void (*midi_input_intr) (int dev, unsigned char data); static int @@ -73,100 +36,69 @@ void (*output) (int dev) ) { - int ret; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + return -(ENXIO); - if (!sb_dsp_ok) + save_flags (flags); + cli (); + if (devc->opened) { - printk ("SB Error: MIDI hardware not installed\n"); - return -ENXIO; + restore_flags (flags); + return -(EBUSY); } + devc->opened = 1; + restore_flags (flags); - if (sb_midi_busy) - return -EBUSY; + devc->irq_mode = IMODE_MIDI; - if (mode != OPEN_WRITE && !sb_duplex_midi) - { - if (num_midis == 1) - printk ("SoundBlaster: Midi input not currently supported\n"); - return -EPERM; - } + sb_dsp_reset (devc); - sb_midi_mode = NORMAL_MIDI; - if (mode != OPEN_WRITE) + if (!sb_dsp_command (devc, 0x35)) /* Start MIDI UART mode */ { - if (sb_dsp_busy || sb_intr_active) - return -EBUSY; - sb_midi_mode = UART_MIDI; + devc->opened = 0; + return -(EIO); } - if (sb_dsp_highspeed) - { - printk ("SB Error: Midi output not possible during stereo or high speed audio\n"); - return -EBUSY; - } + devc->intr_active = 1; - if (sb_midi_mode == UART_MIDI) + if (mode & OPEN_READ) { - sb_irq_mode = IMODE_MIDI; - - sb_reset_dsp (); - - if (!sb_dsp_command (0x35)) - return -EIO; /* - * Enter the UART mode - */ - sb_intr_active = 1; - - if ((ret = sb_get_irq ()) < 0) - { - sb_reset_dsp (); - return 0; /* - * IRQ not free - */ - } - input_opened = 1; - midi_input_intr = input; + devc->input_opened = 1; + devc->midi_input_intr = input; } - sb_midi_busy = 1; - return 0; } static void sb_midi_close (int dev) { - if (sb_midi_mode == UART_MIDI) - { - sb_reset_dsp (); /* - * The only way to kill the UART mode - */ - sb_free_irq (); - } - sb_intr_active = 0; - sb_midi_busy = 0; - input_opened = 0; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + return; + + save_flags (flags); + cli (); + sb_dsp_reset (devc); + devc->intr_active = 0; + devc->input_opened = 0; + restore_flags (flags); } static int sb_midi_out (int dev, unsigned char midi_byte) { - unsigned long flags; + sb_devc *devc = midi_devs[dev]->devc; - if (sb_midi_mode == NORMAL_MIDI) - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x38)) - sb_dsp_command (midi_byte); - else - printk ("SB Error: Unable to send a MIDI byte\n"); - restore_flags (flags); - } - else - sb_dsp_command (midi_byte); /* - * UART write - */ + if (devc == NULL) + return -(ENXIO); + + sb_dsp_command (devc, midi_byte); return 1; } @@ -174,43 +106,43 @@ static int sb_midi_start_read (int dev) { - if (sb_midi_mode != UART_MIDI) - { - printk ("SoundBlaster: MIDI input not implemented.\n"); - return -EPERM; - } return 0; } static int sb_midi_end_read (int dev) { - if (sb_midi_mode == UART_MIDI) - { - sb_reset_dsp (); - sb_intr_active = 0; - } + sb_devc *devc = midi_devs[dev]->devc; + + if (devc == NULL) + return -(ENXIO); + + sb_dsp_reset (devc); + devc->intr_active = 0; return 0; } static int sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EPERM; + return -(EPERM); } void -sb_midi_interrupt (int dummy) +sb_midi_interrupt (sb_devc * devc) { unsigned long flags; unsigned char data; + if (devc == NULL) + return; + save_flags (flags); cli (); data = inb (DSP_READ); - if (input_opened) - midi_input_intr (my_dev, data); + if (devc->input_opened) + devc->midi_input_intr (devc->my_mididev, data); restore_flags (flags); } @@ -230,21 +162,18 @@ sb_midi_out, sb_midi_start_read, sb_midi_end_read, - NULL, /* - * Kick - */ - NULL, /* - * command - */ - NULL, /* - * buffer_status - */ + NULL, + NULL, + NULL, NULL }; void -sb_midi_init (int model) +sb_dsp_midi_init (sb_devc * devc) { + if (devc->model < 2) /* No MIDI support for SB 1.x */ + return; + if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); @@ -252,8 +181,42 @@ } std_midi_synth.midi_dev = num_midis; - my_dev = num_midis; - midi_devs[num_midis++] = &sb_midi_operations; + devc->my_mididev = num_midis; + + std_midi_synth.midi_dev = devc->my_mididev = num_midis; + + + midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[num_midis] == NULL) + { + printk ("sb MIDI: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis], (char *) &sb_midi_operations, + sizeof (struct midi_operations)); + + midi_devs[num_midis]->devc = devc; + + + midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (midi_devs[num_midis]->converter == NULL) + { + printk ("sb MIDI: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, + sizeof (struct synth_operations)); + + num_midis++; } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.0.0/linux/drivers/sound/sb_mixer.c Sun Mar 24 22:50:21 1996 +++ linux/drivers/sound/sb_mixer.c Sun Jun 30 11:44:14 1996 @@ -2,251 +2,100 @@ /* * sound/sb_mixer.c * - * The low level mixer driver for the SoundBlaster Pro and SB16 cards. + * The low level mixer driver for the SoundBlaster compatible cards. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include -/* - * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support the Sound Galaxy NX Pro mixer. - * - */ #include "sound_config.h" -#if defined(CONFIG_SB) +#if defined(CONFIG_SBDSP) #define __SB_MIXER_C__ #include "sb.h" #include "sb_mixer.h" -#undef SB_TEST_IRQ - -extern int sbc_base; -extern int Jazz16_detected; -extern int *sb_osp; -extern int AudioDrive; - -static int mixer_initialized = 0; - -static int supported_rec_devices; -static int supported_devices; -static int recmask = 0; -static int mixer_model; -static int mixer_caps; -static mixer_tab *iomap; - -void -sb_setmixer (unsigned int port, unsigned int value) -{ - unsigned long flags; - - save_flags (flags); - cli (); - outb ((unsigned char) (port & 0xff), MIXER_ADDR); /* - * Select register - */ - tenmicrosec (sb_osp); - outb ((unsigned char) (value & 0xff), MIXER_DATA); - tenmicrosec (sb_osp); - restore_flags (flags); -} - -int -sb_getmixer (unsigned int port) -{ - int val; - unsigned long flags; - - save_flags (flags); - cli (); - outb ((unsigned char) (port & 0xff), MIXER_ADDR); /* - * Select register - */ - tenmicrosec (sb_osp); - val = inb (MIXER_DATA); - tenmicrosec (sb_osp); - restore_flags (flags); - return val; -} +void sb_mixer_reset (sb_devc * devc); void -sb_mixer_set_stereo (int mode) +sb_mixer_set_stereo (sb_devc * devc, int mode) { - if (!mixer_initialized) - return; - - sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC) - | (mode ? STEREO_DAC : MONO_DAC))); + sb_setmixer (devc, OUT_FILTER, ((sb_getmixer (devc, OUT_FILTER) & ~STEREO_DAC) + | (mode ? STEREO_DAC : MONO_DAC))); } -/* - * Returns: - * 0 No mixer detected. - * 1 Only a plain Sound Blaster Pro style mixer detected. - * 2 The Sound Galaxy NX Pro mixer detected. - */ static int -detect_mixer (void) +detect_mixer (sb_devc * devc) { -#ifdef __SGNXPRO__ - int oldbass, oldtreble; - extern int sbc_major; - -#endif - int retcode = 1; - /* * Detect the mixer by changing parameters of two volume channels. If the * values read back match with the values written, the mixer is there (is * it?) */ - sb_setmixer (FM_VOL, 0xff); - sb_setmixer (VOC_VOL, 0x33); + sb_setmixer (devc, FM_VOL, 0xff); + sb_setmixer (devc, VOC_VOL, 0x33); - if (sb_getmixer (FM_VOL) != 0xff) - return 0; /* - * No match - */ - if (sb_getmixer (VOC_VOL) != 0x33) + if (sb_getmixer (devc, FM_VOL) != 0xff) + return 0; + if (sb_getmixer (devc, VOC_VOL) != 0x33) return 0; -#ifdef __SGNXPRO__ - /* Attempt to detect the SG NX Pro by check for valid bass/treble - * registers. - */ - oldbass = sb_getmixer (BASS_LVL); - oldtreble = sb_getmixer (TREBLE_LVL); - - sb_setmixer (BASS_LVL, 0xaa); - sb_setmixer (TREBLE_LVL, 0x55); - - if ((sb_getmixer (BASS_LVL) != 0xaa) || - (sb_getmixer (TREBLE_LVL) != 0x55)) - { - retcode = 1; /* 1 == Only SB Pro detected */ - } - else - retcode = 2; /* 2 == SG NX Pro detected */ - /* Restore register in either case since SG NX Pro has EEPROM with - * 'preferred' values stored. - */ - sb_setmixer (BASS_LVL, oldbass); - sb_setmixer (TREBLE_LVL, oldtreble); - - /* - * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16. - * In this case it's good idea to disable the Disney Sound Source - * compatibility mode. It's useless and just causes noise every time the - * LPT-port is accessed. - * - * Also place the card into WSS mode. - */ - if (sbc_major == 3) - { - outb (0x01, sbc_base + 0x1c); - outb (0x00, sbc_base + 0x1a); - } - -#endif - return retcode; + return 1; } static void -change_bits (unsigned char *regval, int dev, int chn, int newval) +change_bits (sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) { unsigned char mask; int shift; - mask = (1 << (*iomap)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* - * Scale it - */ + mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; + newval = (int) ((newval * mask) + 50) / 100; /* Scale */ - shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1; + shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; - *regval &= ~(mask << shift); /* - * Filter out the previous value - */ - *regval |= (newval & mask) << shift; /* - * Set the new value - */ + *regval &= ~(mask << shift); /* Mask out previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ } static int -sb_mixer_get (int dev) +sb_mixer_get (sb_devc * devc, int dev) { - if (!((1 << dev) & supported_devices)) - return -EINVAL; + if (!((1 << dev) & devc->supported_devices)) + return -(EINVAL); - return levels[dev]; + return devc->levels[dev]; } -static char smw_mix_regs[] = /* Left mixer registers */ -{ - 0x0b, /* SOUND_MIXER_VOLUME */ - 0x0d, /* SOUND_MIXER_BASS */ - 0x0d, /* SOUND_MIXER_TREBLE */ - 0x05, /* SOUND_MIXER_SYNTH */ - 0x09, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x03, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x07, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00, /* SOUND_MIXER_OGAIN */ - 0x00, /* SOUND_MIXER_LINE1 */ - 0x00, /* SOUND_MIXER_LINE2 */ - 0x00 /* SOUND_MIXER_LINE3 */ -}; - void -smw_mixer_init (void) +smw_mixer_init (sb_devc * devc) { int i; - sb_setmixer (0x00, 0x18); /* Mute unused (Telephone) line */ - sb_setmixer (0x10, 0x38); /* Config register 2 */ + sb_setmixer (devc, 0x00, 0x18); /* Mute unused (Telephone) line */ + sb_setmixer (devc, 0x10, 0x38); /* Config register 2 */ - supported_devices = 0; + devc->supported_devices = 0; for (i = 0; i < sizeof (smw_mix_regs); i++) if (smw_mix_regs[i] != 0) - supported_devices |= (1 << i); + devc->supported_devices |= (1 << i); - supported_rec_devices = supported_devices & + devc->supported_rec_devices = devc->supported_devices & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); + + sb_mixer_reset (devc); } static int -smw_mixer_set (int dev, int value) +smw_mixer_set (sb_devc * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; @@ -258,47 +107,47 @@ right = 100; if (dev > 31) - return -EINVAL; + return -(EINVAL); - if (!(supported_devices & (1 << dev))) /* Not supported */ - return -EINVAL; + if (!(devc->supported_devices & (1 << dev))) /* Not supported */ + return -(EINVAL); switch (dev) { case SOUND_MIXER_VOLUME: - sb_setmixer (0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ - sb_setmixer (0x0c, 96 - (96 * right / 100)); + sb_setmixer (devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer (devc, 0x0c, 96 - (96 * right / 100)); break; case SOUND_MIXER_BASS: case SOUND_MIXER_TREBLE: - levels[dev] = left | (right << 8); + devc->levels[dev] = left | (right << 8); /* Set left bass and treble values */ - val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; - val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (0x0d, val); + val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; + val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer (devc, 0x0d, val); /* Set right bass and treble values */ - val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; - val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (0x0e, val); + val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; + val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer (devc, 0x0e, val); break; default: reg = smw_mix_regs[dev]; if (reg == 0) - return -EINVAL; - sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ - sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40); + return -(EINVAL); + sb_setmixer (devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer (devc, reg + 1, (24 - (24 * right / 100)) | 0x40); } - levels[dev] = left | (right << 8); + devc->levels[dev] = left | (right << 8); return left | (right << 8); } static int -sb_mixer_set (int dev, int value) +sb_mixer_set (sb_devc * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; @@ -306,8 +155,8 @@ int regoffs; unsigned char val; - if (Jazz16_detected == 2) - return smw_mixer_set (dev, value); + if (devc->model == MDL_SMW) + return smw_mixer_set (devc, dev, value); if (left > 100) left = 100; @@ -315,67 +164,70 @@ right = 100; if (dev > 31) - return -EINVAL; + return -(EINVAL); - if (!(supported_devices & (1 << dev))) /* + if (!(devc->supported_devices & (1 << dev))) /* * Not supported */ - return -EINVAL; + return -(EINVAL); - regoffs = (*iomap)[dev][LEFT_CHN].regno; + regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; if (regoffs == 0) - return -EINVAL; + return -(EINVAL); - val = sb_getmixer (regoffs); - change_bits (&val, dev, LEFT_CHN, left); + val = sb_getmixer (devc, regoffs); + change_bits (devc, &val, dev, LEFT_CHN, left); - levels[dev] = left | (left << 8); + devc->levels[dev] = left | (left << 8); - if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* + if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* * Change register */ { - sb_setmixer (regoffs, val); /* - * Save the old one - */ - regoffs = (*iomap)[dev][RIGHT_CHN].regno; + sb_setmixer (devc, regoffs, val); /* + * Save the old one + */ + regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; if (regoffs == 0) return left | (left << 8); /* * Just left channel present */ - val = sb_getmixer (regoffs); /* - * Read the new one - */ + val = sb_getmixer (devc, regoffs); /* + * Read the new one + */ } - change_bits (&val, dev, RIGHT_CHN, right); + change_bits (devc, &val, dev, RIGHT_CHN, right); - sb_setmixer (regoffs, val); + sb_setmixer (devc, regoffs, val); - levels[dev] = left | (right << 8); + devc->levels[dev] = left | (right << 8); return left | (right << 8); } static void -set_recsrc (int src) +set_recsrc (sb_devc * devc, int src) { - sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7)); + sb_setmixer (devc, RECORD_SRC, (sb_getmixer (devc, RECORD_SRC) & ~7) | (src & 0x7)); } static int -set_recmask (int mask) +set_recmask (sb_devc * devc, int mask) { int devmask, i; unsigned char regimageL, regimageR; - devmask = mask & supported_rec_devices; + devmask = mask & devc->supported_rec_devices; - switch (mixer_model) + switch (devc->model) { - case 3: + case MDL_SBPRO: + case MDL_ESS: + case MDL_JAZZ: + case MDL_SMW: if (devmask != SOUND_MASK_MIC && devmask != SOUND_MASK_LINE && @@ -384,7 +236,7 @@ * More than one devices selected. Drop the * * previous selection */ - devmask &= ~recmask; + devmask &= ~devc->recmask; } if (devmask != SOUND_MASK_MIC && @@ -398,33 +250,33 @@ } - if (devmask ^ recmask) /* - * Input source changed - */ + if (devmask ^ devc->recmask) /* + * Input source changed + */ { switch (devmask) { case SOUND_MASK_MIC: - set_recsrc (SRC_MIC); + set_recsrc (devc, SRC__MIC); break; case SOUND_MASK_LINE: - set_recsrc (SRC_LINE); + set_recsrc (devc, SRC__LINE); break; case SOUND_MASK_CD: - set_recsrc (SRC_CD); + set_recsrc (devc, SRC__CD); break; default: - set_recsrc (SRC_MIC); + set_recsrc (devc, SRC__MIC); } } break; - case 4: + case MDL_SB16: if (!devmask) devmask = SOUND_MASK_MIC; @@ -435,159 +287,155 @@ regimageL |= sb16_recmasks_L[i]; regimageR |= sb16_recmasks_R[i]; } - sb_setmixer (SB16_IMASK_L, regimageL); - sb_setmixer (SB16_IMASK_R, regimageR); + sb_setmixer (devc, SB16_IMASK_L, regimageL); + sb_setmixer (devc, SB16_IMASK_R, regimageR); break; } - recmask = devmask; - return recmask; + devc->recmask = devmask; + return devc->recmask; } static int sb_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { + sb_devc *devc = mixer_devs[dev]->devc; + if (((cmd >> 8) & 0xff) == 'M') { if (_IOC_DIR (cmd) & _IOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - return snd_ioctl_return ((int *) arg, set_recmask (get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_recmask (devc, get_fs_long ((long *) arg))); break; default: - return snd_ioctl_return ((int *) arg, sb_mixer_set (cmd & 0xff, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, sb_mixer_set (devc, cmd & 0xff, get_fs_long ((long *) arg))); } else - switch (cmd & 0xff) /* - * Return parameters - */ + switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - return snd_ioctl_return ((int *) arg, recmask); + return snd_ioctl_return ((int *) arg, devc->recmask); break; case SOUND_MIXER_DEVMASK: - return snd_ioctl_return ((int *) arg, supported_devices); + return snd_ioctl_return ((int *) arg, devc->supported_devices); break; case SOUND_MIXER_STEREODEVS: - if (Jazz16_detected) - return snd_ioctl_return ((int *) arg, supported_devices); + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + return snd_ioctl_return ((int *) arg, devc->supported_devices); else - return snd_ioctl_return ((int *) arg, supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + return snd_ioctl_return ((int *) arg, devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); break; case SOUND_MIXER_RECMASK: - return snd_ioctl_return ((int *) arg, supported_rec_devices); + return snd_ioctl_return ((int *) arg, devc->supported_rec_devices); break; case SOUND_MIXER_CAPS: - return snd_ioctl_return ((int *) arg, mixer_caps); + return snd_ioctl_return ((int *) arg, devc->mixer_caps); break; default: - return snd_ioctl_return ((int *) arg, sb_mixer_get (cmd & 0xff)); + return snd_ioctl_return ((int *) arg, sb_mixer_get (devc, cmd & 0xff)); } } else - return -EINVAL; + return -(EINVAL); } static struct mixer_operations sb_mixer_operations = { + "SB", "SoundBlaster", sb_mixer_ioctl }; void -sb_mixer_reset (void) +sb_mixer_reset (sb_devc * devc) { int i; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - sb_mixer_set (i, levels[i]); - set_recmask (SOUND_MASK_MIC); + sb_mixer_set (devc, i, devc->levels[i]); + set_recmask (devc, SOUND_MASK_MIC); } -/* - * Returns a code depending on whether a SG NX Pro was detected. - * 1 == Plain SB Pro - * 2 == SG NX Pro detected. - * 3 == SB16 - * - * Used to update message. - */ int -sb_mixer_init (int major_model) +sb_mixer_init (sb_devc * devc) { int mixer_type = 0; - sb_setmixer (0x00, 0); /* Reset mixer */ + sb_setmixer (devc, 0x00, 0); /* Reset mixer */ - if (!(mixer_type = detect_mixer ())) + if (!(mixer_type = detect_mixer (devc))) return 0; /* No mixer. Why? */ - mixer_initialized = 1; - mixer_model = major_model; - - switch (major_model) + switch (devc->model) { - case 3: - mixer_caps = SOUND_CAP_EXCL_INPUT; + case MDL_SBPRO: + case MDL_JAZZ: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = SBPRO_MIXER_DEVICES; + devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; + devc->iomap = &sbpro_mix; + break; - if (AudioDrive) - { - supported_devices = ES688_MIXER_DEVICES; - supported_rec_devices = ES688_RECORDING_DEVICES; - iomap = &es688_mix; - } - else if (Jazz16_detected == 2) /* SM Wave */ - { - supported_devices = 0; - supported_rec_devices = 0; - iomap = &sbpro_mix; - smw_mixer_init (); - mixer_type = 1; - } - else -#ifdef __SGNXPRO__ - if (mixer_type == 2) /* A SGNXPRO was detected */ - { - supported_devices = SGNXPRO_MIXER_DEVICES; - supported_rec_devices = SGNXPRO_RECORDING_DEVICES; - iomap = &sgnxpro_mix; - } - else -#endif - { - supported_devices = SBPRO_MIXER_DEVICES; - supported_rec_devices = SBPRO_RECORDING_DEVICES; - iomap = &sbpro_mix; - mixer_type = 1; - } + case MDL_ESS: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = ES688_MIXER_DEVICES; + devc->supported_rec_devices = ES688_RECORDING_DEVICES; + devc->iomap = &es688_mix; break; - case 4: - mixer_caps = 0; - supported_devices = SB16_MIXER_DEVICES; - supported_rec_devices = SB16_RECORDING_DEVICES; - iomap = &sb16_mix; - mixer_type = 3; + case MDL_SMW: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = 0; + devc->supported_rec_devices = 0; + devc->iomap = &sbpro_mix; + smw_mixer_init (devc); + break; + + case MDL_SB16: + devc->mixer_caps = 0; + devc->supported_devices = SB16_MIXER_DEVICES; + devc->supported_rec_devices = SB16_RECORDING_DEVICES; + devc->iomap = &sb16_mix; break; default: - printk ("SB Warning: Unsupported mixer type\n"); + printk ("SB Warning: Unsupported mixer type %d\n", devc->model); return 0; } - if (num_mixers < MAX_MIXER_DEV) - mixer_devs[num_mixers++] = &sb_mixer_operations; - sb_mixer_reset (); - return mixer_type; + if (num_mixers >= MAX_MIXER_DEV) + return 0; + + + mixer_devs[num_mixers] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (mixer_devs[num_mixers] == NULL) + { + printk ("sb_mixer: Can't allocate memory\n"); + return 0; + } + + memcpy ((char *) mixer_devs[num_mixers], (char *) &sb_mixer_operations, + sizeof (struct mixer_operations)); + + mixer_devs[num_mixers]->devc = devc; + memcpy ((char *) devc->levels, (char *) &default_levels, sizeof (default_levels)); + + sb_mixer_reset (devc); + devc->my_mixerdev = num_mixers++; + return 1; } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v2.0.0/linux/drivers/sound/sb_mixer.h Sun Mar 24 22:49:43 1996 +++ linux/drivers/sound/sb_mixer.h Sun Jun 30 11:43:39 1996 @@ -4,27 +4,11 @@ * Definitions for the SB Pro and SB16 mixers */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ /* @@ -109,16 +93,6 @@ #define LEFT_CHN 0 #define RIGHT_CHN 1 -struct mixer_def { - unsigned int regno: 8; - unsigned int bitoffs:4; - unsigned int nbits:4; -}; - - -typedef struct mixer_def mixer_tab[32][2]; -typedef struct mixer_def mixer_ent; - #define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} @@ -197,7 +171,7 @@ higher than with SB Pro. This improves the sound quality */ -static unsigned short levels[SOUND_MIXER_NRDEVICES] = +static unsigned short default_levels[SOUND_MIXER_NRDEVICES] = { 0x2020, /* Master Volume */ 0x4b4b, /* Bass */ @@ -220,7 +194,7 @@ #else /* If the user selected just plain SB Pro */ -static unsigned short levels[SOUND_MIXER_NRDEVICES] = +static unsigned short default_levels[SOUND_MIXER_NRDEVICES] = { 0x5a5a, /* Master Volume */ 0x4b4b, /* Bass */ @@ -278,12 +252,33 @@ 0x00 /* SOUND_MIXER_OGAIN */ }; +static char smw_mix_regs[] = /* Left mixer registers */ +{ + 0x0b, /* SOUND_MIXER_VOLUME */ + 0x0d, /* SOUND_MIXER_BASS */ + 0x0d, /* SOUND_MIXER_TREBLE */ + 0x05, /* SOUND_MIXER_SYNTH */ + 0x09, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x03, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x07, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00, /* SOUND_MIXER_OGAIN */ + 0x00, /* SOUND_MIXER_LINE1 */ + 0x00, /* SOUND_MIXER_LINE2 */ + 0x00 /* SOUND_MIXER_LINE3 */ +}; + /* * Recording sources (SB Pro) */ -#define SRC_MIC 1 /* Select Microphone recording source */ -#define SRC_CD 3 /* Select CD recording source */ -#define SRC_LINE 7 /* Use Line-in for recording source */ +#define SRC__MIC 1 /* Select Microphone recording source */ +#define SRC__CD 3 /* Select CD recording source */ +#define SRC__LINE 7 /* Use Line-in for recording source */ #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.0.0/linux/drivers/sound/sequencer.c Mon Jun 3 16:46:56 1996 +++ linux/drivers/sound/sequencer.c Sun Jun 30 11:44:16 1996 @@ -4,27 +4,11 @@ * The sequencer personality manager. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -51,7 +35,7 @@ /* * The seq_mode gives the operating mode of the sequencer: * 1 = level1 (the default) - * 2 = level2 (extended capabilities) + * 2 = level2 (extended capabilites) */ #define SEQ_1 1 @@ -124,25 +108,25 @@ 1 : 0)) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } { - unsigned long tl; + unsigned long tlimit; if (pre_event_timeout) - current_set_timeout (tl = jiffies + (pre_event_timeout)); + current_set_timeout (tlimit = jiffies + (pre_event_timeout)); else - tl = (unsigned long) -1; - midi_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper); - if (!(midi_sleep_flag.mode & WK_WAKEUP)) + if (!(midi_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag.flags |= WK_TIMEOUT; } - midi_sleep_flag.mode &= ~WK_SLEEP; + midi_sleep_flag.flags &= ~WK_SLEEP; }; if (!iqlen) @@ -155,7 +139,7 @@ while (iqlen && c >= ev_len) { - memcpy_tofs (&((buf)[p]), (char *) &iqueue[iqhead * IEV_SZ], ev_len); + memcpy_tofs (&(buf)[p], (char *) &iqueue[iqhead * IEV_SZ], ev_len); p += ev_len; c -= ev_len; @@ -198,10 +182,10 @@ iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - if ((midi_sleep_flag.mode & WK_SLEEP)) + if ((midi_sleep_flag.flags & WK_SLEEP)) { { - midi_sleep_flag.mode = WK_WAKEUP; + midi_sleep_flag.flags = WK_WAKEUP; module_wake_up (&midi_sleeper); }; } @@ -274,7 +258,7 @@ DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); if (mode == OPEN_READ) - return -EIO; + return -(EIO); if (dev) return pmgr_write (dev - 1, file, buf, count); @@ -283,7 +267,7 @@ while (c >= 4) { - memcpy_fromfs ((char *) event_rec, &((buf)[p]), 4); + memcpy_fromfs ((char *) event_rec, &(buf)[p], 4); ev_code = event_rec[0]; if (ev_code == SEQ_FULLSIZE) @@ -292,10 +276,10 @@ dev = *(unsigned short *) &event_rec[2]; if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + return -(ENXIO); err = synth_devs[dev]->load_patch (dev, *(short *) &event_rec[0], buf, p + 4, c, 0); if (err < 0) @@ -309,7 +293,7 @@ if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) { printk ("Sequencer: Invalid level 2 event %x\n", ev_code); - return -EINVAL; + return -(EINVAL); } ev_size = 8; @@ -321,7 +305,7 @@ return count - c; } - memcpy_fromfs ((char *) &event_rec[4], &((buf)[p + 4]), 4); + memcpy_fromfs ((char *) &event_rec[4], &(buf)[p + 4], 4); } else @@ -329,7 +313,7 @@ if (seq_mode == SEQ_2) { printk ("Sequencer: 4 byte event in level 2 mode\n"); - return -EINVAL; + return -(EINVAL); } ev_size = 4; } @@ -345,7 +329,7 @@ if (dev >= max_mididev) { printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); - return -ENXIO; + return -(ENXIO); } mode = file->mode & O_ACCMODE; @@ -373,7 +357,7 @@ if (!processed && (file->flags & (O_NONBLOCK) ? 1 : 0)) - return -EAGAIN; + return -(EAGAIN); else return processed; } @@ -404,15 +388,15 @@ * Give chance to drain the queue */ - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.mode & WK_SLEEP)) + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.flags & WK_SLEEP)) { /* * Sleep until there is enough space on the queue */ - seq_sleep_flag.mode = WK_SLEEP; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - seq_sleep_flag.mode &= ~WK_SLEEP;; + seq_sleep_flag.flags &= ~WK_SLEEP;; } if (qlen >= SEQ_MAX_QUEUE) @@ -435,10 +419,10 @@ int dev = q[2]; if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + return -(ENXIO); switch (q[1]) { @@ -475,7 +459,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } return 0; @@ -710,10 +694,10 @@ save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -750,10 +734,10 @@ save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -886,10 +870,10 @@ save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -927,7 +911,7 @@ dev = q[2]; if (dev < 0 || dev >= num_midis) - break; + break; if (!midi_devs[dev]->putc (dev, q[1])) { @@ -946,7 +930,7 @@ case SEQ_ECHO: seq_copy_to_input (q, 4); /* - * Echo back to the process + * Echo back to the process */ break; @@ -1025,10 +1009,10 @@ save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -1095,13 +1079,13 @@ if (!sequencer_ok) { printk ("Soundcard: Sequencer not initialized\n"); - return -ENXIO; + return -(ENXIO); } if (dev) /* Patch manager device */ { printk ("Patch manager interface is currently broken. Sorry\n"); - return -ENXIO; + return -(ENXIO); } save_flags (flags); @@ -1110,7 +1094,7 @@ { printk ("Sequencer busy\n"); restore_flags (flags); - return -EBUSY; + return -(EBUSY); } sequencer_busy = 1; restore_flags (flags); @@ -1150,7 +1134,7 @@ { printk ("sequencer: No timer for level 2\n"); sequencer_busy = 0; - return -ENXIO; + return -(ENXIO); } setup_mode2 (); } @@ -1160,11 +1144,11 @@ { printk ("Sequencer: No Midi devices. Input not possible\n"); sequencer_busy = 0; - return -ENXIO; + return -(ENXIO); } if (!max_synthdev && !max_mididev) - return -ENXIO; + return -(ENXIO); synth_open_mask = 0; @@ -1217,8 +1201,8 @@ tmr->open (tmr_no, seq_mode); } - seq_sleep_flag.mode = WK_NONE; - midi_sleep_flag.mode = WK_NONE; + seq_sleep_flag.flags = WK_NONE; + midi_sleep_flag.flags = WK_NONE; output_treshold = SEQ_MAX_QUEUE / 2; for (i = 0; i < num_synths; i++) @@ -1256,20 +1240,20 @@ { { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - seq_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) + if (!(seq_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + seq_sleep_flag.flags |= WK_TIMEOUT; } - seq_sleep_flag.mode &= ~WK_SLEEP; + seq_sleep_flag.flags &= ~WK_SLEEP; }; } } @@ -1352,24 +1336,24 @@ save_flags (flags); cli (); - if (qlen && !(seq_sleep_flag.mode & WK_SLEEP)) + if (qlen && !(seq_sleep_flag.flags & WK_SLEEP)) { { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - seq_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) + if (!(seq_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + seq_sleep_flag.flags |= WK_TIMEOUT; } - seq_sleep_flag.mode &= ~WK_SLEEP; + seq_sleep_flag.flags &= ~WK_SLEEP; }; } restore_flags (flags); @@ -1401,20 +1385,20 @@ { { - unsigned long tl; + unsigned long tlimit; if (4) - current_set_timeout (tl = jiffies + (4)); + current_set_timeout (tlimit = jiffies + (4)); else - tl = (unsigned long) -1; - seq_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) + if (!(seq_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + seq_sleep_flag.flags |= WK_TIMEOUT; } - seq_sleep_flag.mode &= ~WK_SLEEP; + seq_sleep_flag.flags &= ~WK_SLEEP; }; n--; } @@ -1493,11 +1477,11 @@ save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { /* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -1546,25 +1530,25 @@ case SNDCTL_TMR_METRONOME: case SNDCTL_TMR_SOURCE: if (dev) /* Patch manager */ - return -EIO; + return -(EIO); if (seq_mode != SEQ_2) - return -EINVAL; + return -(EINVAL); return tmr->ioctl (tmr_no, cmd, arg); break; case SNDCTL_TMR_SELECT: if (dev) /* Patch manager */ - return -EIO; + return -(EIO); if (seq_mode != SEQ_2) - return -EINVAL; + return -(EINVAL); pending_timer = get_fs_long ((long *) arg); if (pending_timer < 0 || pending_timer >= num_sound_timers) { pending_timer = -1; - return -EINVAL; + return -(EINVAL); } return snd_ioctl_return ((int *) arg, pending_timer); @@ -1578,14 +1562,14 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (mode == OPEN_READ) return 0; while (qlen && !current_got_fatal_signal ()) seq_sync (); if (qlen) - return -EINTR; + return -(EINTR); else return 0; break; @@ -1594,7 +1578,7 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); seq_reset (); return 0; @@ -1604,11 +1588,11 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); midi_dev = get_fs_long ((long *) arg); if (midi_dev >= max_mididev) - return -ENXIO; + return -(ENXIO); if (!midi_opened[midi_dev]) { @@ -1630,7 +1614,7 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (mode == OPEN_WRITE) return 0; @@ -1646,7 +1630,7 @@ case SNDCTL_SEQ_CTRLRATE: if (dev) /* Patch manager */ - return -EIO; + return -(EIO); /* * If *arg == 0, just return the current rate @@ -1655,7 +1639,7 @@ return tmr->ioctl (tmr_no, cmd, arg); if (get_fs_long ((long *) arg) != 0) - return -EINVAL; + return -(EINVAL); return snd_ioctl_return ((int *) arg, HZ); break; @@ -1667,12 +1651,12 @@ dev = get_fs_long ((long *) arg); if (dev < 0 || dev >= num_synths) { - return -ENXIO; + return -(ENXIO); } if (!(synth_open_mask & (1 << dev)) && !orig_dev) { - return -EBUSY; + return -(EBUSY); } if (!orig_dev && pmgr_present[dev]) @@ -1696,10 +1680,10 @@ int dev = get_fs_long ((long *) arg); if (dev < 0 || dev >= num_synths) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + return -(EBUSY); return snd_ioctl_return ((int *) arg, synth_devs[dev]->ioctl (dev, cmd, arg)); } @@ -1710,10 +1694,10 @@ int dev = get_fs_long ((long *) arg); if (dev < 0 || dev >= num_synths) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + return -(ENXIO); synth_devs[dev]->ioctl (dev, cmd, arg); return 0; @@ -1725,14 +1709,14 @@ struct synth_info inf; int dev; - memcpy_fromfs ((char *) &inf, &(((char *) arg)[0]), sizeof (inf)); + memcpy_fromfs ((char *) &inf, &((char *) arg)[0], sizeof (inf)); dev = inf.device; if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + return -(EBUSY); return synth_devs[dev]->ioctl (dev, cmd, arg); } @@ -1743,7 +1727,7 @@ struct seq_event_rec event_rec; unsigned long flags; - memcpy_fromfs ((char *) &event_rec, &(((char *) arg)[0]), sizeof (event_rec)); + memcpy_fromfs ((char *) &event_rec, &((char *) arg)[0], sizeof (event_rec)); save_flags (flags); cli (); @@ -1759,13 +1743,13 @@ struct midi_info inf; int dev; - memcpy_fromfs ((char *) &inf, &(((char *) arg)[0]), sizeof (inf)); + memcpy_fromfs ((char *) &inf, &((char *) arg)[0], sizeof (inf)); dev = inf.device; if (dev < 0 || dev >= max_mididev) - return -ENXIO; + return -(ENXIO); - memcpy_tofs ((&((char *) arg)[0]), (char *) &(midi_devs[dev]->info), sizeof (inf)); + memcpy_tofs (&((char *) arg)[0], (char *) &(midi_devs[dev]->info), sizeof (inf)); return 0; } break; @@ -1775,35 +1759,35 @@ struct patmgr_info *inf; int dev, err; - if ((inf = (struct patmgr_info *) kmalloc (sizeof (*inf), GFP_KERNEL)) == NULL) + if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL) { printk ("patmgr: Can't allocate memory for a message\n"); - return -EIO; + return -(EIO); } - memcpy_fromfs ((char *) inf, &(((char *) arg)[0]), sizeof (*inf)); + memcpy_fromfs ((char *) inf, &((char *) arg)[0], sizeof (*inf)); dev = inf->device; if (dev < 0 || dev >= num_synths) { - kfree (inf); - return -ENXIO; + vfree (inf); + return -(ENXIO); } if (!synth_devs[dev]->pmgr_interface) { - kfree (inf); - return -ENXIO; + vfree (inf); + return -(ENXIO); } if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1) { - kfree (inf); + vfree (inf); return err; } - memcpy_tofs ((&((char *) arg)[0]), (char *) inf, sizeof (*inf)); - kfree (inf); + memcpy_tofs (&((char *) arg)[0], (char *) inf, sizeof (*inf)); + vfree (inf); return 0; } break; @@ -1813,35 +1797,35 @@ struct patmgr_info *inf; int dev, err; - if ((inf = (struct patmgr_info *) kmalloc (sizeof (*inf), GFP_KERNEL)) == NULL) + if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL) { printk ("patmgr: Can't allocate memory for a message\n"); - return -EIO; + return -(EIO); } - memcpy_fromfs ((char *) inf, &(((char *) arg)[0]), sizeof (*inf)); + memcpy_fromfs ((char *) inf, &((char *) arg)[0], sizeof (*inf)); dev = inf->device; if (dev < 0 || dev >= num_synths) { - kfree (inf); - return -ENXIO; + vfree (inf); + return -(ENXIO); } if (!pmgr_present[dev]) { - kfree (inf); - return -ESRCH; + vfree (inf); + return -(ESRCH); } if ((err = pmgr_access (dev, inf)) < 0) { - kfree (inf); + vfree (inf); return err; } - memcpy_tofs ((&((char *) arg)[0]), (char *) inf, sizeof (*inf)); - kfree (inf); + memcpy_tofs (&((char *) arg)[0], (char *) inf, sizeof (*inf)); + vfree (inf); return 0; } break; @@ -1853,7 +1837,7 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (tmp < 1) tmp = 1; @@ -1881,20 +1865,20 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (mode == OPEN_READ) - return -EIO; + return -(EIO); if (!synth_devs[0]) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << 0))) - return -ENXIO; + return -(ENXIO); return synth_devs[0]->ioctl (0, cmd, arg); break; } - return -EINVAL; + return -(EINVAL); } int @@ -1912,7 +1896,7 @@ if (!iqlen) { - midi_sleep_flag.mode = WK_SLEEP; + midi_sleep_flag.flags = WK_SLEEP; module_select_wait (&midi_sleeper, wait); restore_flags (flags); return 0; @@ -1927,7 +1911,7 @@ if ((SEQ_MAX_QUEUE - qlen) < output_treshold) { - seq_sleep_flag.mode = WK_SLEEP; + seq_sleep_flag.flags = WK_SLEEP; module_select_wait (&seq_sleeper, wait); restore_flags (flags); return 0; @@ -2035,33 +2019,31 @@ } -long -sequencer_init (long mem_start) +void +sequencer_init (void) { - queue = (unsigned char *) (sound_mem_blocks[sound_num_blocks] = kmalloc (SEQ_MAX_QUEUE * EV_SZ, GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * EV_SZ)); + if (sound_nblocks < 1024) + sound_nblocks++;; if (queue == NULL) { printk ("Sound: Can't allocate memory for sequencer output queue\n"); - return mem_start; + return; } - iqueue = (unsigned char *) (sound_mem_blocks[sound_num_blocks] = kmalloc (SEQ_MAX_QUEUE * IEV_SZ, GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * IEV_SZ)); + if (sound_nblocks < 1024) + sound_nblocks++;; if (queue == NULL) { printk ("Sound: Can't allocate memory for sequencer input queue\n"); - return mem_start; + return; } sequencer_ok = 1; - - return mem_start; } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.0.0/linux/drivers/sound/sound_calls.h Sun Mar 24 22:49:43 1996 +++ linux/drivers/sound/sound_calls.h Sun Jun 30 11:43:39 1996 @@ -11,7 +11,7 @@ int DMAbuf_start_output(int dev, int buff_no, int l); int DMAbuf_set_count(int dev, int buff_no, int l); int DMAbuf_ioctl(int dev, unsigned int cmd, caddr_t arg, int local); -long DMAbuf_init(long mem_start); +void DMAbuf_init(void); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); int DMAbuf_open_dma (int dev); void DMAbuf_close_dma (int dev); @@ -32,7 +32,7 @@ int audio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long audio_init (long mem_start); +void audio_init (void); int audio_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); @@ -47,7 +47,7 @@ int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long sequencer_init (long mem_start); +void sequencer_init (void); void sequencer_timer(unsigned long dummy); int note_to_freq(int note_num); unsigned long compute_finetune(unsigned long base_freq, int bend, int range); @@ -68,7 +68,7 @@ unsigned int cmd, caddr_t arg); int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig); void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); -long MIDIbuf_init(long mem_start); +void MIDIbuf_init(void); int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); @@ -83,7 +83,7 @@ void request_sound_timer (int count); void sound_stop_timer(void); int snd_ioctl_return(int *addr, int value); -int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void*, struct pt_regs *), char *name, int *osp); +int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp); void snd_release_irq(int vect); void sound_dma_malloc(int dev); void sound_dma_free(int dev); @@ -98,51 +98,33 @@ int sound_ioctl_sw (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); -/* From sb_dsp.c */ -int sb_dsp_detect (struct address_info *hw_config); -long sb_dsp_init (long mem_start, struct address_info *hw_config); -void sb_dsp_disable_midi(void); -int sb_get_irq(void); -void sb_free_irq(void); -int sb_dsp_command (unsigned char val); -int sb_reset_dsp (void); -void sb_dsp_unload(struct address_info *); - -/* From sb16_dsp.c */ -void sb16_dsp_interrupt (int irq); -long sb16_dsp_init(long mem_start, struct address_info *hw_config); -int sb16_dsp_detect(struct address_info *hw_config); - -/* From sb16_midi.c */ -void sb16midiintr (int unit); -long attach_sb16midi(long mem_start, struct address_info * hw_config); -int probe_sb16midi(struct address_info *hw_config); -void sb_midi_interrupt(int dummy); -void sbmidiintr(int irq, void *dev_id, struct pt_regs * dummy); - -/* From sb_midi.c */ -void sb_midi_init(int model); - -/* From sb_mixer.c */ -void sb_setmixer (unsigned int port, unsigned int value); -int sb_getmixer (unsigned int port); -void sb_mixer_set_stereo(int mode); -int sb_mixer_init(int major_model); - /* From opl3.c */ int opl3_detect (int ioaddr, int *osp); -long opl3_init(long mem_start, int ioaddr, int *osp); +void opl3_init(int ioaddr, int *osp); /* From sb_card.c */ -long attach_sb_card(long mem_start, struct address_info *hw_config); +void attach_sb_card(struct address_info *hw_config); int probe_sb(struct address_info *hw_config); +/* From sb_common.c */ +void sb_dsp_disable_midi(int port); +void sb_dsp_disable_recording(int port); +void attach_sbmpu (struct address_info *hw_config); +int probe_sbmpu (struct address_info *hw_config); +void unload_sbmpu (struct address_info *hw_config); + +/* From uart401.c */ +void attach_uart401 (struct address_info *hw_config); +int probe_uart401 (struct address_info *hw_config); +void unload_uart401 (struct address_info *hw_config); +void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); + /* From adlib_card.c */ -long attach_adlib_card(long mem_start, struct address_info *hw_config); +void attach_adlib_card(struct address_info *hw_config); int probe_adlib(struct address_info *hw_config); /* From pas_card.c */ -long attach_pas_card(long mem_start, struct address_info *hw_config); +void attach_pas_card(struct address_info *hw_config); int probe_pas(struct address_info *hw_config); int pas_set_intr(int mask); int pas_remove_intr(int mask); @@ -151,26 +133,26 @@ /* From pas_audio.c */ void pas_pcm_interrupt(unsigned char status, int cause); -long pas_pcm_init(long mem_start, struct address_info *hw_config); +void pas_pcm_init(struct address_info *hw_config); /* From pas_mixer.c */ int pas_init_mixer(void); /* From pas_midi.c */ -long pas_midi_init(long mem_start); +void pas_midi_init(void); void pas_midi_interrupt(void); /* From gus_card.c */ -long attach_gus_card(long mem_start, struct address_info * hw_config); +void attach_gus_card(struct address_info * hw_config); int probe_gus(struct address_info *hw_config); int gus_set_midi_irq(int num); void gusintr(int irq, void *dev_id, struct pt_regs * dummy); -long attach_gus_db16(long mem_start, struct address_info * hw_config); +void attach_gus_db16(struct address_info * hw_config); int probe_gus_db16(struct address_info *hw_config); /* From gus_wave.c */ int gus_wave_detect(int baseaddr); -long gus_wave_init(long mem_start, struct address_info *hw_config); +void gus_wave_init(struct address_info *hw_config); void gus_wave_unload (void); void gus_voice_irq(void); unsigned char gus_read8 (int reg); @@ -181,16 +163,16 @@ void gus_timer_command (unsigned int addr, unsigned int val); /* From gus_midi.c */ -long gus_midi_init(long mem_start); +void gus_midi_init(void); void gus_midi_interrupt(int dummy); /* From mpu401.c */ -long attach_mpu401(long mem_start, struct address_info * hw_config); +void attach_mpu401(struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); /* From uart6850.c */ -long attach_uart6850(long mem_start, struct address_info * hw_config); +void attach_uart6850(struct address_info * hw_config); int probe_uart6850(struct address_info *hw_config); /* From opl3.c */ @@ -206,7 +188,7 @@ unsigned long parm3, unsigned long parm4); /* From ics2101.c */ -long ics2101_mixer_init(long mem_start); +void ics2101_mixer_init(void); /* From sound_timer.c */ void sound_timer_interrupt(void); @@ -221,25 +203,25 @@ #define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ void ad1848_interrupt (int irq, void *dev_id, struct pt_regs * dummy); -long attach_ms_sound(long mem_start, struct address_info * hw_config); +void attach_ms_sound(struct address_info * hw_config); int probe_ms_sound(struct address_info *hw_config); -long attach_pnp_ad1848(long mem_start, struct address_info * hw_config); +void attach_pnp_ad1848(struct address_info * hw_config); int probe_pnp_ad1848(struct address_info *hw_config); void unload_pnp_ad1848(struct address_info *hw_info); /* From pss.c */ int probe_pss (struct address_info *hw_config); -long attach_pss (long mem_start, struct address_info *hw_config); +void attach_pss (struct address_info *hw_config); int probe_pss_mpu (struct address_info *hw_config); -long attach_pss_mpu (long mem_start, struct address_info *hw_config); +void attach_pss_mpu (struct address_info *hw_config); int probe_pss_mss (struct address_info *hw_config); -long attach_pss_mss (long mem_start, struct address_info *hw_config); +void attach_pss_mss (struct address_info *hw_config); /* From sscape.c */ int probe_sscape (struct address_info *hw_config); -long attach_sscape (long mem_start, struct address_info *hw_config); +void attach_sscape (struct address_info *hw_config); int probe_ss_ms_sound (struct address_info *hw_config); -long attach_ss_ms_sound(long mem_start, struct address_info * hw_config); +void attach_ss_ms_sound(struct address_info * hw_config); int pss_read (int dev, struct fileinfo *file, char *buf, int count); int pss_write (int dev, struct fileinfo *file, char *buf, int count); @@ -248,7 +230,7 @@ int pss_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long pss_init(long mem_start); +void pss_init(void); /* From aedsp16.c */ int InitAEDSP16_SBPRO(struct address_info *hw_config); @@ -259,21 +241,19 @@ void do_midi_msg (int synthno, unsigned char *msg, int mlen); /* From trix.c */ -long attach_trix_wss (long mem_start, struct address_info *hw_config); +void attach_trix_wss (struct address_info *hw_config); int probe_trix_wss (struct address_info *hw_config); -long attach_trix_sb (long mem_start, struct address_info *hw_config); +void attach_trix_sb (struct address_info *hw_config); int probe_trix_sb (struct address_info *hw_config); -long attach_trix_mpu (long mem_start, struct address_info *hw_config); +void attach_trix_mpu (struct address_info *hw_config); int probe_trix_mpu (struct address_info *hw_config); /* From mad16.c */ -long attach_mad16 (long mem_start, struct address_info *hw_config); +void attach_mad16 (struct address_info *hw_config); int probe_mad16 (struct address_info *hw_config); -long attach_mad16_mpu (long mem_start, struct address_info *hw_config); +void attach_mad16_mpu (struct address_info *hw_config); int probe_mad16_mpu (struct address_info *hw_config); int mad16_sb_dsp_detect (struct address_info *hw_config); -long mad16_sb_dsp_init (long mem_start, struct address_info *hw_config); -void mad16_sb_dsp_unload(struct address_info *hw_config); /* Unload routines from various source files*/ void unload_pss(struct address_info *hw_info); @@ -303,14 +283,14 @@ /* From cs4232.c */ int probe_cs4232 (struct address_info *hw_config); -long attach_cs4232 (long mem_start, struct address_info *hw_config); +void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); -long attach_cs4232_mpu (long mem_start, struct address_info *hw_config); +void attach_cs4232_mpu (struct address_info *hw_config); /* From maui.c */ -long attach_maui(long mem_start, struct address_info * hw_config); +void attach_maui(struct address_info * hw_config); int probe_maui(struct address_info *hw_config); /* From sound_pnp.c */ -void sound_pnp_init(void); +void sound_pnp_init(int *osp); void sound_pnp_disconnect(void); diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v2.0.0/linux/drivers/sound/sound_config.h Fri Apr 12 15:52:03 1996 +++ linux/drivers/sound/sound_config.h Sun Jun 30 11:43:39 1996 @@ -3,27 +3,11 @@ * A driver for Soundcards, misc configuration parameters. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ @@ -112,8 +96,8 @@ #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ #define SND_DEV_STATUS 6 /* /dev/sndstat */ -/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_AWFM 7 /* Reserved */ +#define SND_DEV_SEQ2 8 /* /dev/sequecer, level 2 interface */ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC @@ -143,8 +127,8 @@ char *name; int driver_use_1; /* Driver defined field 1 */ int driver_use_2; /* Driver defined field 2 */ - int *osp; /* OS specific info */ - int card_subtype; /* Driver specific. Usually 0 */ + int *osp; /* OS spesific info */ + int card_subtype; /* Driver spesific. Usually 0 */ }; #define SYNTH_MAX_VOICES 32 diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c --- v2.0.0/linux/drivers/sound/sound_switch.c Tue May 7 16:22:35 1996 +++ linux/drivers/sound/sound_switch.c Sun Jun 30 11:44:18 1996 @@ -4,27 +4,11 @@ * The system call switch handler */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -48,7 +32,7 @@ static int put_status (char *s) { - int l = strnlen (s, 256); + int l = strlen (s); if (status_len + l >= 4000) return 0; @@ -172,18 +156,24 @@ if (!put_status (sound_drivers[drv].name)) return; - if (!put_status (" at 0x")) - return; - if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) - return; + if (snd_installed_cards[i].config.io_base) + { + if (!put_status (" at 0x")) + return; + if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) + return; + } - if (!put_status (" irq ")) - return; tmp = snd_installed_cards[i].config.irq; - if (tmp < 0) - tmp = -tmp; - if (!put_status_int (tmp, 10)) - return; + if (tmp != 0) + { + if (!put_status (" irq ")) + return; + if (tmp < 0) + tmp = -tmp; + if (!put_status_int (tmp, 10)) + return; + } if (snd_installed_cards[i].config.dma != -1) { @@ -326,7 +316,7 @@ if (l <= 0) return 0; - memcpy_tofs (&((buf)[0]), &status_buf[status_ptr], l); + memcpy_tofs (&(buf)[0], &status_buf[status_ptr], l); status_ptr += l; return l; @@ -367,7 +357,7 @@ printk ("Sound: Undefined minor device %d\n", dev); } - return -EPERM; + return -(EPERM); } int @@ -401,77 +391,67 @@ } - return -EPERM; + return -(EPERM); } int sound_open_sw (int dev, struct fileinfo *file) { + int retval; + DEB (printk ("sound_open_sw(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) { printk ("Invalid minor device %d\n", dev); - return -ENXIO; + return -(ENXIO); } switch (dev & 0x0f) { case SND_DEV_STATUS: if (status_busy) - return -EBUSY; + return -(EBUSY); status_busy = 1; - if ((status_buf = (char *) kmalloc (4000, GFP_KERNEL)) == NULL) - return -EIO; + if ((status_buf = (char *) vmalloc (4000)) == NULL) + return -(EIO); status_len = status_ptr = 0; init_status (); break; case SND_DEV_CTL: if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) - return -ENXIO; + return -(ENXIO); return 0; break; #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - { - int retval; - if ((retval = sequencer_open (dev, file)) < 0) return retval; break; - } #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - { - int retval; - if ((retval = MIDIbuf_open (dev, file)) < 0) return retval; break; - } #endif #ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - { - int retval; - if ((retval = audio_open (dev, file)) < 0) return retval; break; - } #endif default: printk ("Invalid minor device %d\n", dev); - return -ENXIO; + return -(ENXIO); } in_use++; @@ -489,7 +469,7 @@ { case SND_DEV_STATUS: if (status_buf) - kfree (status_buf); + vfree (status_buf); status_buf = NULL; status_busy = 0; break; @@ -524,6 +504,21 @@ in_use--; } +static int +get_mixer_info (int dev, caddr_t arg) +{ + mixer_info info; + + if (dev < 0 || dev >= num_mixers) + return -(ENXIO); + + strcpy (info.id, mixer_devs[dev]->id); + strcpy (info.name, mixer_devs[dev]->name); + + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); + return 0; +} + int sound_ioctl_sw (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg) @@ -533,22 +528,29 @@ if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ if ((dev & 0x0f) != SND_DEV_CTL) { -#ifdef CONFIG_AUDIO int dtype = dev & 0x0f; int mixdev; 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 -(ENXIO); + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info (mixdev, arg); return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); - } + break; #endif - return mixer_devs[0]->ioctl (0, cmd, arg); + + default: + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info (0, arg); + return mixer_devs[0]->ioctl (0, cmd, arg); + } } switch (dev & 0x0f) @@ -557,13 +559,15 @@ case SND_DEV_CTL: if (!num_mixers) - return -ENXIO; + return -(ENXIO); dev = dev >> 4; if (dev >= num_mixers) - return -ENXIO; + return -(ENXIO); + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info (dev, arg); return mixer_devs[dev]->ioctl (dev, cmd, arg); break; @@ -590,5 +594,5 @@ } - return -EPERM; + return -(EPERM); } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.0.0/linux/drivers/sound/sound_timer.c Sun Mar 24 22:50:24 1996 +++ linux/drivers/sound/sound_timer.c Sun Jun 30 11:44:18 1996 @@ -2,27 +2,11 @@ * sound/sound_timer.c */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -110,7 +94,7 @@ timer_open (int dev, int mode) { if (opened) - return -EBUSY; + return -(EBUSY); tmr_reset (); curr_tempo = 60; @@ -268,7 +252,7 @@ case SNDCTL_SEQ_CTRLRATE: if (get_fs_long ((long *) arg) != 0) /* Can't change */ - return -EINVAL; + return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; @@ -280,7 +264,7 @@ default:; } - return -EINVAL; + return -(EINVAL); } static void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.0.0/linux/drivers/sound/soundcard.c Fri May 17 15:32:17 1996 +++ linux/drivers/sound/soundcard.c Sun Jun 30 11:44:19 1996 @@ -4,27 +4,11 @@ * Soundcard driver for Linux */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -33,6 +17,8 @@ #include + +int *sound_global_osp = NULL; static int chrdev_registered = 0; static int sound_major = SOUND_MAJOR; @@ -42,7 +28,7 @@ * Table for permanently allocated memory (used when unloading the module) */ caddr_t sound_mem_blocks[1024]; -int sound_num_blocks = 0; +int sound_nblocks = 0; static int soundcard_configured = 0; @@ -55,6 +41,7 @@ #define DMA_MAP_FREE 1 #define DMA_MAP_BUSY 2 + int snd_ioctl_return (int *addr, int value) { @@ -92,7 +79,7 @@ static int sound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig) { - return -EPERM; + return -(EPERM); } static int @@ -104,7 +91,7 @@ if (is_unloading) { printk ("Sound: Driver partially removed. Can't open device\n"); - return -EBUSY; + return -(EBUSY); } dev = MINOR (inode_get_rdev (inode)); @@ -112,7 +99,7 @@ if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) { printk ("SoundCard Error: The soundcard system has not been configured\n"); - return -ENXIO; + return -(ENXIO); } tmp_file.mode = 0; @@ -302,7 +289,6 @@ size, dmap->bytes_in_use); } - if (remap_page_range (vma_get_start (vma), dmap->raw_buf_phys, vma_get_end (vma) - vma_get_start (vma), vma_get_page_prot (vma))) @@ -342,8 +328,17 @@ soundcard_configured = 1; - sndtable_init (0); /* Initialize call tables and - * detect cards */ + sndtable_init (); /* Initialize call tables and detect cards */ + + + +#ifdef CONFIG_LOWLEVEL_SOUND + { + extern void sound_init_lowlevel_drivers (void); + + sound_init_lowlevel_drivers (); + } +#endif if (sndtable_get_cardcount () == 0) return; /* No cards detected */ @@ -351,19 +346,19 @@ #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { - DMAbuf_init (0); - audio_init (0); + DMAbuf_init (); + audio_init (); } #endif #ifdef CONFIG_MIDI if (num_midis) - MIDIbuf_init (0); + MIDIbuf_init (); #endif #ifdef CONFIG_SEQUENCER if (num_midis + num_synths) - sequencer_init (0); + sequencer_init (); #endif } @@ -389,6 +384,8 @@ #endif +static int debugmem = 0; /* switched off by default */ + static int sound[20] = {0}; @@ -426,7 +423,7 @@ chrdev_registered = 1; soundcard_init (); - if (sound_num_blocks >= 1024) + if (sound_nblocks >= 1024) printk ("Sound warning: Deallocation table was too small.\n"); return 0; @@ -440,16 +437,29 @@ { int i; + if (MOD_IN_USE) + { + return; + } + if (chrdev_registered) module_unregister_chrdev (sound_major, "sound"); #ifdef CONFIG_SEQUENCER sound_stop_timer (); #endif + +#ifdef CONFIG_LOWLEVEL_SOUND + { + extern void sound_unload_lowlevel_drivers (void); + + sound_unload_lowlevel_drivers (); + } +#endif sound_unload_drivers (); - for (i = 0; i < sound_num_blocks; i++) - kfree (sound_mem_blocks[i]); + for (i = 0; i < sound_nblocks; i++) + vfree (sound_mem_blocks[i]); free_all_irqs (); /* If something was left allocated by accident */ @@ -460,6 +470,7 @@ sound_free_dma (i); } + } #endif @@ -473,11 +484,11 @@ } int -snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, void *, struct pt_regs *), char *name, int *osp) +snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) { int retcode; - retcode = request_irq (interrupt_level, hndlr, 0 /* SA_INTERRUPT */ , name, NULL); + retcode = request_irq (interrupt_level, iproc, 0 /* SA_INTERRUPT */ , name, NULL); if (retcode < 0) { printk ("Sound: IRQ%d already in use\n", interrupt_level); @@ -516,6 +527,12 @@ { unsigned long flags; + if (chn < 0 || chn > 7 || chn == 4) + { + printk ("sound_open_dma: Invalid DMA channel %d\n", chn); + return 1; + } + save_flags (flags); cli (); @@ -598,8 +615,6 @@ fatal_error__This_version_is_not_compatible_with_this_kernel; #endif -static int debugmem = 0; /* switched off by default */ - static int dma_buffsize = DSP_BUFFSIZE; int @@ -655,7 +670,7 @@ if (start_addr == NULL) { printk ("Sound error: Couldn't allocate DMA buffer\n"); - return -ENOMEM; + return -(ENOMEM); } else { @@ -673,10 +688,10 @@ || end_addr >= (char *) (MAX_DMA_ADDRESS)) { printk ( - "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n", + "sound: Got invalid address 0x%lx for %ldb DMA-buffer\n", (long) start_addr, audio_devs[dev]->buffsize); - return -EFAULT; + return -(EFAULT); } } dmap->raw_buf = start_addr; @@ -693,39 +708,37 @@ void sound_free_dmap (int dev, 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 */ - { - int sz, size, i; - unsigned long start_addr, end_addr; - - for (sz = 0, size = PAGE_SIZE; - size < audio_devs[dev]->buffsize; - sz++, size <<= 1); + for (sz = 0, size = PAGE_SIZE; + size < audio_devs[dev]->buffsize; + sz++, size <<= 1); - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + audio_devs[dev]->buffsize; + start_addr = (unsigned long) dmap->raw_buf; + end_addr = start_addr + audio_devs[dev]->buffsize; - for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) - { - mem_map_unreserve (i); - } + for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) + { + mem_map_unreserve (i); + } - free_pages ((unsigned long) dmap->raw_buf, sz); - } + free_pages ((unsigned long) dmap->raw_buf, sz); dmap->raw_buf = NULL; } int -sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info) +soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info) { printk ("Entered sound_map_buffer()\n"); printk ("Exited sound_map_buffer()\n"); - return -EINVAL; + return -(EINVAL); } #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h --- v2.0.0/linux/drivers/sound/soundvers.h Sun Mar 31 00:13:18 1996 +++ linux/drivers/sound/soundvers.h Mon Jul 1 06:30:35 1996 @@ -1,2 +1,2 @@ -#define SOUND_VERSION_STRING "3.5.2-960330" -#define SOUND_INTERNAL_VERSION 0x030500 +#define SOUND_VERSION_STRING "3.5.4-960630" +#define SOUND_INTERNAL_VERSION 0x030504 diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.0.0/linux/drivers/sound/sscape.c Sat Apr 13 18:22:07 1996 +++ linux/drivers/sound/sscape.c Sun Jun 30 11:44:20 1996 @@ -4,27 +4,11 @@ * Low level driver for Ensoniq Soundscape */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -281,7 +265,7 @@ host_command3 (devc, CMD_SET_CONTROL, ctrl, value); if (host_read (devc) != CMD_ACK) { - printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl); + /* printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl); */ } host_close (devc); } @@ -307,10 +291,10 @@ static int debug = 0; bits = sscape_read (devc, GA_INTSTAT_REG); - if ((sscape_sleep_flag.mode & WK_SLEEP)) + if ((sscape_sleep_flag.flags & WK_SLEEP)) { { - sscape_sleep_flag.mode = WK_WAKEUP; + sscape_sleep_flag.flags = WK_WAKEUP; module_wake_up (&sscape_sleeper); }; } @@ -320,10 +304,10 @@ printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); } -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (bits & 0x01) { - mpuintr (irq, NULL, NULL); + uart401intr (irq, NULL, NULL); if (debug++ > 10) /* Temporary debugging hack */ { sscape_write (devc, GA_INTENA_REG, 0x00); /* Disable all interrupts */ @@ -352,9 +336,11 @@ return; } + audio_devs[devc->my_audiodev]->flags &= ~DMA_AUTOMODE; DMAbuf_start_dma (devc->my_audiodev, buf, blk_size, mode); + audio_devs[devc->my_audiodev]->flags |= DMA_AUTOMODE; temp = devc->dma << 4; /* Setup DMA channel select bits */ if (devc->dma <= 3) @@ -401,10 +387,10 @@ { set_mt32 (devc, 0); if (!verify_mpu (devc)) - return -EIO; + return -(EIO); } - sscape_sleep_flag.mode = WK_NONE; + sscape_sleep_flag.flags = WK_NONE; return 0; } @@ -419,11 +405,9 @@ if (devc->dma_allocated) { sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ -#ifdef CONFIG_NATIVE_PCM -#endif devc->dma_allocated = 0; } - sscape_sleep_flag.mode = WK_NONE; + sscape_sleep_flag.flags = WK_NONE; restore_flags (flags); return; @@ -440,7 +424,7 @@ unsigned long flags; unsigned char temp; int done, timeout_val; - static int already_done = 0; + static unsigned char codec_dma_bits = 0; if (flag & CPF_FIRST) { @@ -449,20 +433,14 @@ * before continuing. */ - if (already_done) - { - printk ("Can't run 'ssinit' twice\n"); - return 0; - } - already_done = 1; - save_flags (flags); cli (); + codec_dma_bits = sscape_read (devc, GA_CDCFG_REG); + sscape_write (devc, GA_CDCFG_REG, + codec_dma_bits & ~0x08); /* Disable codec DMA */ + if (devc->dma_allocated == 0) { -#ifdef CONFIG_NATIVE_PCM -#endif - devc->dma_allocated = 1; } restore_flags (flags); @@ -479,7 +457,7 @@ } /* - * Transfer one code block using DMA + * Transfer one code block using DMA */ memcpy (audio_devs[devc->my_audiodev]->dmap_out->raw_buf, block, size); @@ -493,7 +471,7 @@ /* * Wait until transfer completes. */ - sscape_sleep_flag.mode = WK_NONE; + sscape_sleep_flag.flags = WK_NONE; done = 0; timeout_val = 100; while (!done && timeout_val-- > 0) @@ -502,24 +480,26 @@ { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sscape_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.mode & WK_WAKEUP)) + if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sscape_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sscape_sleep_flag.flags |= WK_TIMEOUT; } - sscape_sleep_flag.mode &= ~WK_SLEEP; + sscape_sleep_flag.flags &= ~WK_SLEEP; }; clear_dma_ff (devc->dma); if ((resid = get_dma_residue (devc->dma)) == 0) - done = 1; + { + done = 1; + } } restore_flags (flags); @@ -550,24 +530,26 @@ { { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sscape_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.mode & WK_WAKEUP)) + if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sscape_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sscape_sleep_flag.flags |= WK_TIMEOUT; } - sscape_sleep_flag.mode &= ~WK_SLEEP; + sscape_sleep_flag.flags &= ~WK_SLEEP; }; if (inb (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */ done = 1; } + sscape_write (devc, GA_CDCFG_REG, codec_dma_bits); + restore_flags (flags); if (!done) { @@ -583,20 +565,20 @@ { { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sscape_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.mode & WK_WAKEUP)) + if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sscape_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sscape_sleep_flag.flags |= WK_TIMEOUT; } - sscape_sleep_flag.mode &= ~WK_SLEEP; + sscape_sleep_flag.flags &= ~WK_SLEEP; }; if (inb (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ done = 1; @@ -636,12 +618,12 @@ download_boot_block (void *dev_info, copr_buffer * buf) { if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; + return -(EINVAL); if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) { printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); - return -EIO; + return -(EIO); } return 0; @@ -663,18 +645,18 @@ copr_buffer *buf; int err; - buf = (copr_buffer *) kmalloc (sizeof (copr_buffer), GFP_KERNEL); + buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); if (buf == NULL) - return -ENOSPC; - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); + return -(ENOSPC); + memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf)); err = download_boot_block (dev_info, buf); - kfree (buf); + vfree (buf); return err; } break; default: - return -EINVAL; + return -(EINVAL); } } @@ -689,176 +671,11 @@ &dev_info }; -static int -sscape_audio_open (int dev, int mode) -{ - unsigned long flags; - sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - return -EBUSY; - } - devc->opened = 1; - restore_flags (flags); -#ifdef SSCAPE_DEBUG4 - /* - * Temporary debugging aid. Print contents of the registers - * when the device is opened. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x\n", i, sscape_read (devc, i)); - } -#endif - - return 0; -} - -static void -sscape_audio_close (int dev) -{ - unsigned long flags; - sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; - - DEB (printk ("sscape_audio_close(void)\n")); - - save_flags (flags); - cli (); - - devc->opened = 0; - - restore_flags (flags); -} - -static int -set_speed (sscape_info * devc, int arg) -{ - return 8000; -} - -static int -set_channels (sscape_info * devc, int arg) -{ - return 1; -} - -static int -set_format (sscape_info * devc, int arg) -{ - return AFMT_U8; -} - -static int -sscape_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) -{ - sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return set_speed (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_RATE: - if (local) - return 8000; - return snd_ioctl_return ((int *) arg, 8000); - - case SNDCTL_DSP_STEREO: - if (local) - return set_channels (devc, (int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1); - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return set_channels (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_CHANNELS: - if (local) - return 1; - return snd_ioctl_return ((int *) arg, 1); - - case SNDCTL_DSP_SAMPLESIZE: - if (local) - return set_format (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_BITS: - if (local) - return 8; - return snd_ioctl_return ((int *) arg, 8); - - default:; - } - return -EINVAL; -} - -static void -sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ -} - -static void -sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ -} - -static int -sscape_audio_prepare_for_input (int dev, int bsize, int bcount) -{ - return 0; -} - -static int -sscape_audio_prepare_for_output (int dev, int bsize, int bcount) -{ - return 0; -} - -static void -sscape_audio_halt (int dev) -{ -} - -static void -sscape_audio_reset (int dev) -{ - sscape_audio_halt (dev); -} - -static struct audio_operations sscape_audio_operations = -{ - "Not functional", - 0, - AFMT_U8 | AFMT_S16_LE, - NULL, - sscape_audio_open, - sscape_audio_close, - sscape_audio_output_block, - sscape_audio_start_input, - sscape_audio_ioctl, - sscape_audio_prepare_for_input, - sscape_audio_prepare_for_output, - sscape_audio_reset, - sscape_audio_halt, - NULL, - NULL -}; - static int sscape_detected = 0; -long -attach_sscape (long mem_start, struct address_info *hw_config) +void +attach_sscape (struct address_info *hw_config) { - int my_dev; #ifndef SSCAPE_REGS /* @@ -894,7 +711,7 @@ int i, irq_bits = 0xff; if (sscape_detected != hw_config->io_base) - return mem_start; + return; if (old_hardware) { @@ -914,7 +731,7 @@ if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) { printk ("Invalid IRQ%d\n", hw_config->irq); - return mem_start; + return; } save_flags (flags); @@ -968,45 +785,27 @@ } #endif -#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) - if (probe_mpu401 (hw_config)) +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + if (probe_uart401 (hw_config)) hw_config->always_detect = 1; { int prev_devs; prev_devs = num_midis; - mem_start = attach_mpu401 (mem_start, hw_config); + hw_config->name = "Soundscape"; + + hw_config->irq *= -1; /* Negative value signals IRQ sharing */ + attach_uart401 (hw_config); + hw_config->irq *= -1; /* Restore it */ if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ midi_devs[prev_devs]->coproc = &sscape_coproc_operations; } #endif -#ifndef EXCLUDE_NATIVE_PCM - /* Not supported yet */ - -#ifdef CONFIG_AUDIO - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; - audio_devs[my_dev]->dmachan1 = hw_config->dma; - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - audio_devs[my_dev]->devc = devc; - devc->my_audiodev = my_dev; - devc->opened = 0; - audio_devs[my_dev]->coproc = &sscape_coproc_operations; - if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape", devc->osp) < 0) - printk ("Error: Can't allocate IRQ for SoundScape\n"); - - sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - } - else - printk ("SoundScape: More than enough audio devices detected\n"); -#endif -#endif + sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0; - return mem_start; } int @@ -1083,11 +882,6 @@ old_hardware = 0; } - if (sound_alloc_dma (hw_config->dma, "soundscape")) - { - printk ("sscape.c: Can't allocate DMA channel\n"); - return 0; - } sscape_detected = hw_config->io_base; @@ -1123,8 +917,8 @@ return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); } -long -attach_ss_ms_sound (long mem_start, struct address_info *hw_config) +void +attach_ss_ms_sound (struct address_info *hw_config) { /* * This routine configures the SoundScape card for use with the @@ -1134,18 +928,17 @@ int i, irq_bits = 0xff; -#ifndef CONFIG_NATIVE_PCM int prev_devs = num_audiodevs; -#endif + hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ /* - * Setup the DMA polarity. + * Setup the DMA polarity. */ sscape_write (devc, GA_DMACFG_REG, 0x50); /* - * Take the gate-array off of the DMA channel. + * Take the gate-arry off of the DMA channel. */ sscape_write (devc, GA_DMAB_REG, 0x20); @@ -1173,10 +966,10 @@ 0, devc->osp); -#ifndef CONFIG_NATIVE_PCM if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ audio_devs[prev_devs]->coproc = &sscape_coproc_operations; -#endif + devc->my_audiodev = prev_devs; + #ifdef SSCAPE_DEBUG5 /* * Temporary debugging aid. Print contents of the registers @@ -1190,17 +983,15 @@ } #endif - return mem_start; } void unload_sscape (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + unload_uart401 (hw_config); #endif snd_release_irq (hw_config->irq); - sound_free_dma (hw_config->dma); } void @@ -1208,9 +999,10 @@ { ad1848_unload (hw_config->io_base, hw_config->irq, - hw_config->dma, - hw_config->dma, + devc->dma, + devc->dma, 0); } + #endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c --- v2.0.0/linux/drivers/sound/sys_timer.c Sun Mar 24 22:50:27 1996 +++ linux/drivers/sound/sys_timer.c Sun Jun 30 11:44:21 1996 @@ -5,27 +5,11 @@ * Uses the (1/HZ sec) timer of kernel. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -106,7 +90,7 @@ def_tmr_open (int dev, int mode) { if (opened) - return -EBUSY; + return -(EBUSY); tmr_reset (); curr_tempo = 60; @@ -266,7 +250,7 @@ case SNDCTL_SEQ_CTRLRATE: if (get_fs_long ((long *) arg) != 0) /* Can't change */ - return -EINVAL; + return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; @@ -278,7 +262,7 @@ default:; } - return -EINVAL; + return -(EINVAL); } static void diff -u --recursive --new-file v2.0.0/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.0.0/linux/drivers/sound/trix.c Sun Mar 24 22:50:28 1996 +++ linux/drivers/sound/trix.c Sun Jun 30 11:44:21 1996 @@ -1,36 +1,21 @@ /* * sound/trix.c * - * Low level driver for the MediaTriX AudioTriX Pro + * Low level driver for the MediaTrix AudioTrix Pro * (MT-0002-PC Control Chip) */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include #include "sound_config.h" +#include "sb.h" #if defined(CONFIG_TRIX) @@ -98,7 +83,7 @@ if (check_region (0x390, 2)) { - printk ("AudioTriX: Config port I/O conflict\n"); + printk ("AudioTrix: Config port I/O conflict\n"); return 0; } @@ -107,7 +92,7 @@ if (trix_read (0x15) != 0x71) /* No asic signature */ { - DDB (printk ("No AudioTriX ASIC signature found\n")); + DDB (printk ("No AudioTrix ASIC signature found\n")); return 0; } @@ -148,7 +133,7 @@ /* * Probe and attach routines for the Windows Sound System mode of - * AudioTriX Pro + * AudioTrix Pro */ int @@ -158,12 +143,12 @@ /* * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTriX Pro for example) + * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00. */ if (check_region (hw_config->io_base, 8)) { - printk ("AudioTriX: MSS I/O port conflict (%x)\n", hw_config->io_base); + printk ("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); return 0; } @@ -180,20 +165,20 @@ if (hw_config->irq > 11) { - printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq); + printk ("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) { - printk ("AudioTriX: Bad WSS DMA %d\n", hw_config->dma); + printk ("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); return 0; } if (hw_config->dma2 != -1) if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) { - printk ("AudioTriX: Bad capture DMA %d\n", hw_config->dma2); + printk ("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); return 0; } @@ -203,43 +188,43 @@ if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) { - printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n"); + printk ("AudioTrix: Can't use DMA0 with a 8 bit card\n"); return 0; } if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) { - printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); + printk ("AudioTrix: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); return 0; } ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); if (ret) - request_region (0x390, 2, "AudioTriX"); + request_region (0x390, 2, "AudioTrix"); return ret; } -long -attach_trix_wss (long mem_start, struct address_info *hw_config) +void +attach_trix_wss (struct address_info *hw_config) { static unsigned char interrupt_bits[12] = - {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; char bits; static unsigned char dma_bits[4] = {1, 2, 0, 3}; - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + int config_port = hw_config->io_base + 0; int dma1 = hw_config->dma, dma2 = hw_config->dma2; trix_osp = hw_config->osp; if (!kilroy_was_here) { - DDB (printk ("AudioTriX: Attach called but not probed yet???\n")); - return mem_start; + DDB (printk ("AudioTrix: Attach called but not probed yet???\n")); + return; } /* @@ -247,17 +232,15 @@ */ bits = interrupt_bits[hw_config->irq]; - if (bits == -1) + if (bits == 0) { - printk ("AudioTriX: Bad IRQ (%d)\n", hw_config->irq); - return mem_start; + printk ("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); + return; } outb (bits | 0x40, config_port); - if ((inb (version_port) & 0x40) == 0) - printk ("[IRQ Conflict?]"); - if (hw_config->dma2 == -1) /* Single DMA mode */ + if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) { bits |= dma_bits[dma1]; dma2 = dma1; @@ -275,14 +258,13 @@ outb (bits, config_port); /* Write IRQ+DMA setup */ - ad1848_init ("AudioTriX Pro", hw_config->io_base + 4, + ad1848_init ("AudioTrix Pro", hw_config->io_base + 4, hw_config->irq, dma1, dma2, 0, hw_config->osp); request_region (hw_config->io_base, 4, "MSS config"); - return mem_start; } int @@ -298,18 +280,18 @@ return 0; /* No boot code -> no fun */ if (!kilroy_was_here) - return 0; /* AudioTriX Pro has not been detected earlier */ + return 0; /* AudioTrix Pro has not been detected earlier */ if (sb_initialized) return 0; if (check_region (hw_config->io_base, 16)) { - printk ("AudioTriX: SB I/O port conflict (%x)\n", hw_config->io_base); + printk ("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); return 0; } - if (hw_config->io_base & 0xffffff8f != 0x200) + if ((hw_config->io_base & 0xffffff8f) != 0x200) return 0; tmp = hw_config->irq; @@ -332,36 +314,36 @@ download_boot (hw_config->io_base); sb_initialized = 1; - return 1; + hw_config->name = "AudioTrix SB"; +#ifdef CONFIG_SBDSP + return probe_sb (hw_config); +#else + return 0; +#endif } -long -attach_trix_sb (long mem_start, struct address_info *hw_config) +void +attach_trix_sb (struct address_info *hw_config) { -#ifdef CONFIG_SB - extern int sb_no_recording; - - sb_dsp_disable_midi (); - sb_no_recording = 1; +#ifdef CONFIG_SBDSP + hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; + attach_sb_card (hw_config); #endif - conf_printf ("AudioTriX (SB)", hw_config); - return mem_start; } -long -attach_trix_mpu (long mem_start, struct address_info *hw_config) +void +attach_trix_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - return attach_mpu401 (mem_start, hw_config); -#else - return mem_start; +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + hw_config->name = "AudioTrix Pro"; + attach_uart401 (hw_config); #endif } int probe_trix_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static char irq_bits[] = {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; @@ -369,7 +351,7 @@ if (!kilroy_was_here) { DDB (printk ("Trix: WSS and SB modes must be initialized before MPU\n")); - return 0; /* AudioTriX Pro has not been detected earlier */ + return 0; /* AudioTrix Pro has not been detected earlier */ } if (!sb_initialized) @@ -386,19 +368,19 @@ if (check_region (hw_config->io_base, 4)) { - printk ("AudioTriX: MPU I/O port conflict (%x)\n", hw_config->io_base); + printk ("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); return 0; } if (hw_config->irq > 9) { - printk ("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq); + printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); return 0; } if (irq_bits[hw_config->irq] == -1) { - printk ("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq); + printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); return 0; } @@ -426,7 +408,7 @@ mpu_initialized = 1; - return probe_mpu401 (hw_config); + return probe_uart401 (hw_config); #else return 0; #endif @@ -453,13 +435,14 @@ void unload_trix_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + unload_uart401 (hw_config); #endif } void unload_trix_sb (struct address_info *hw_config) { + unload_sb (hw_config); } diff -u --recursive --new-file v2.0.0/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.0.0/linux/drivers/sound/uart401.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/uart401.c Sun Jun 30 11:44:22 1996 @@ -0,0 +1,437 @@ +/* + * sound/uart401.c + * + * MPU-401 UART driver (formerly uart401_midi.c) + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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. + */ +#include + + +#include "sound_config.h" + +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + +typedef struct uart401_devc + { + int base; + int irq; + int *osp; + void (*midi_input_intr) (int dev, unsigned char data); + int opened; + volatile unsigned char input_byte; + int my_dev; + int share_irq; + } +uart401_devc; + +static uart401_devc *detected_devc = NULL; +static uart401_devc *irq2devc[16] = +{NULL}; + +#define DATAPORT (devc->base) +#define COMDPORT (devc->base+1) +#define STATPORT (devc->base+1) + +static int +uart401_status (uart401_devc * devc) +{ + return inb (STATPORT); +} +#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) +#define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) +static void +uart401_cmd (uart401_devc * devc, unsigned char cmd) +{ + outb (cmd, COMDPORT); +} +static int +uart401_read (uart401_devc * devc) +{ + return inb (DATAPORT); +} +static void +uart401_write (uart401_devc * devc, unsigned char byte) +{ + outb (byte, DATAPORT); +} + +#define OUTPUT_READY 0x40 +#define INPUT_AVAIL 0x80 +#define MPU_ACK 0xFE +#define MPU_RESET 0xFF +#define UART_MODE_ON 0x3F + +static int reset_uart401 (uart401_devc * devc); + +static void +uart401_input_loop (uart401_devc * devc) +{ + while (input_avail (devc)) + { + unsigned char c = uart401_read (devc); + + if (c == MPU_ACK) + devc->input_byte = c; + else if (devc->opened & OPEN_READ && devc->midi_input_intr) + devc->midi_input_intr (devc->my_dev, c); + } +} + +void +uart401intr (int irq, void *dev_id, struct pt_regs *dummy) +{ + uart401_devc *devc; + + if (irq < 1 || irq > 15) + return; + + devc = irq2devc[irq]; + + if (devc == NULL) + return; + + if (input_avail (devc)) + uart401_input_loop (devc); +} + +static int +uart401_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + if (devc->opened) + { + return -(EBUSY); + } + + while (input_avail (devc)) + uart401_read (devc); + + devc->midi_input_intr = input; + devc->opened = mode; + + return 0; +} + +static void +uart401_close (int dev) +{ + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + devc->opened = 0; +} + +static int +uart401_out (int dev, unsigned char midi_byte) +{ + int timeout; + unsigned long flags; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + /* + * Test for input since pending input seems to block the output. + */ + + save_flags (flags); + cli (); + + if (input_avail (devc)) + uart401_input_loop (devc); + + restore_flags (flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); + + if (!output_ready (devc)) + { + printk ("MPU-401: Timeout\n"); + return 0; + } + + uart401_write (devc, midi_byte); + return 1; +} + +static int +uart401_start_read (int dev) +{ + return 0; +} + +static int +uart401_end_read (int dev) +{ + return 0; +} + +static int +uart401_ioctl (int dev, unsigned cmd, caddr_t arg) +{ + return -(EINVAL); +} + +static void +uart401_kick (int dev) +{ +} + +static int +uart401_buffer_status (int dev) +{ + return 0; +} + +#define MIDI_SYNTH_NAME "MPU-401 UART" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + +static struct midi_operations uart401_operations = +{ + {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + &std_midi_synth, + {0}, + uart401_open, + uart401_close, + uart401_ioctl, + uart401_out, + uart401_start_read, + uart401_end_read, + uart401_kick, + NULL, + uart401_buffer_status, + NULL +}; + +static void +enter_uart_mode (uart401_devc * devc) +{ + int ok, timeout; + unsigned long flags; + + save_flags (flags); + cli (); + for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--); + + devc->input_byte = 0; + uart401_cmd (devc, UART_MODE_ON); + + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) + ok = 1; + else if (input_avail (devc)) + if (uart401_read (devc) == MPU_ACK) + ok = 1; + + restore_flags (flags); +} + +void +attach_uart401 (struct address_info *hw_config) +{ + uart401_devc *devc; + char *name = "MPU-401 (UART) MIDI"; + + if (hw_config->name) + name = hw_config->name; + + if (detected_devc == NULL) + return; + + + devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (uart401_devc))); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (devc == NULL) + { + printk ("uart401: Can't allocate memory\n"); + return; + } + + memcpy ((char *) devc, (char *) detected_devc, sizeof (uart401_devc)); + detected_devc = NULL; + + devc->irq = hw_config->irq; + if (devc->irq < 0) + { + devc->share_irq = 1; + devc->irq *= -1; + } + else + devc->share_irq = 0; + + if (devc->irq < 1 || devc->irq > 15) + return; + + if (!devc->share_irq) + if (snd_set_irq_handler (devc->irq, uart401intr, "uart401", devc->osp) < 0) + { + printk ("uart401: Failed to allocate IRQ%d\n", devc->irq); + return; + } + + irq2devc[devc->irq] = devc; + devc->my_dev = num_midis; + + request_region (hw_config->io_base, 4, "SB MIDI"); + enter_uart_mode (devc); + + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return; + } + + conf_printf (name, hw_config); + + std_midi_synth.midi_dev = devc->my_dev = num_midis; + + + midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[num_midis] == NULL) + { + printk ("uart401: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis], (char *) &uart401_operations, + sizeof (struct midi_operations)); + + midi_devs[num_midis]->devc = devc; + + + midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (midi_devs[num_midis]->converter == NULL) + { + printk ("uart401: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, + sizeof (struct synth_operations)); + + strcpy (midi_devs[num_midis]->info.name, name); + num_midis++; + devc->opened = 0; +} + +static int +reset_uart401 (uart401_devc * devc) +{ + int ok, timeout, n; + + /* + * Send the RESET command. Try again if no success at the first time. + */ + + ok = 0; + + /* save_flags(flags);cli(); */ + + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--); + + devc->input_byte = 0; + uart401_cmd (devc, MPU_RESET); + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) /* Interrupt */ + ok = 1; + else if (input_avail (devc)) + if (uart401_read (devc) == MPU_ACK) + ok = 1; + + } + + if (ok) + uart401_input_loop (devc); /* + * Flush input before enabling interrupts + */ + + /* restore_flags(flags); */ + + return ok; +} + +int +probe_uart401 (struct address_info *hw_config) +{ + int ok = 0; + + static uart401_devc hw_info; + uart401_devc *devc = &hw_info; + + detected_devc = NULL; + + if (check_region (hw_config->io_base, 4)) + return 0; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->osp = hw_config->osp; + devc->midi_input_intr = NULL; + devc->opened = 0; + devc->input_byte = 0; + devc->my_dev = 0; + devc->share_irq = 0; + + ok = reset_uart401 (devc); + + if (ok) + detected_devc = devc; + + return ok; +} + +void +unload_uart401 (struct address_info *hw_config) +{ + uart401_devc *devc; + + int irq = hw_config->irq; + + if (irq < 0) + irq *= -1; + + if (irq < 1 || irq > 15) + return; + + devc = irq2devc[irq]; + if (devc == NULL) + return; + + release_region (hw_config->io_base, 4); + + if (!devc->share_irq) + snd_release_irq (devc->irq); +} + + +#endif diff -u --recursive --new-file v2.0.0/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.0.0/linux/drivers/sound/uart6850.c Sun Mar 24 22:50:28 1996 +++ linux/drivers/sound/uart6850.c Sun Jun 30 11:44:22 1996 @@ -2,27 +2,11 @@ * sound/uart6850.c */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #include @@ -154,7 +138,7 @@ if (uart6850_opened) { printk ("Midi6850: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } ; @@ -238,7 +222,7 @@ static int uart6850_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -(EINVAL); } static void @@ -275,8 +259,8 @@ }; -long -attach_uart6850 (long mem_start, struct address_info *hw_config) +void +attach_uart6850 (struct address_info *hw_config) { int ok, timeout; unsigned long flags; @@ -284,7 +268,7 @@ if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); - return mem_start; + return; } uart6850_base = hw_config->io_base; @@ -292,7 +276,7 @@ uart6850_irq = hw_config->irq; if (!uart6850_detected) - return -EIO; + return; save_flags (flags); cli (); @@ -310,7 +294,6 @@ std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &uart6850_operations; - return mem_start; } static int diff -u --recursive --new-file v2.0.0/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.0.0/linux/fs/affs/namei.c Mon May 20 08:21:04 1996 +++ linux/fs/affs/namei.c Wed Jul 3 12:03:47 1996 @@ -535,7 +535,8 @@ int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { struct inode *old_inode; struct inode *new_inode; @@ -568,6 +569,8 @@ goto end_rename; old_inode = __iget(old_dir->i_sb,old_ino,0); if (!old_inode) + goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) goto end_rename; new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); if (new_bh) { diff -u --recursive --new-file v2.0.0/linux/fs/exec.c linux/fs/exec.c --- v2.0.0/linux/fs/exec.c Sat May 11 10:42:06 1996 +++ linux/fs/exec.c Tue Jul 2 19:08:42 1996 @@ -429,7 +429,6 @@ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->inode,MAY_READ)) current->dumpable = 0; - current->signal = 0; for (i=0 ; i<32 ; i++) { current->sig->action[i].sa_mask = 0; current->sig->action[i].sa_flags = 0; diff -u --recursive --new-file v2.0.0/linux/fs/ext/namei.c linux/fs/ext/namei.c --- v2.0.0/linux/fs/ext/namei.c Mon Sep 18 08:54:10 1995 +++ linux/fs/ext/namei.c Wed Jul 3 16:19:00 1996 @@ -885,7 +885,8 @@ * as they are on different partitions. */ int ext_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; diff -u --recursive --new-file v2.0.0/linux/fs/ext2/acl.c linux/fs/ext2/acl.c --- v2.0.0/linux/fs/ext2/acl.c Wed Mar 22 10:33:59 1995 +++ linux/fs/ext2/acl.c Tue Jul 2 19:08:42 1996 @@ -28,6 +28,13 @@ unsigned short mode = inode->i_mode; /* + * Nobody gets write access to a file on a readonly-fs + */ + if ((mask & S_IWOTH) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) && + IS_RDONLY(inode)) + return -EROFS; + /* * Nobody gets write access to an immutable file */ if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) diff -u --recursive --new-file v2.0.0/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c --- v2.0.0/linux/fs/ext2/ioctl.c Mon Jun 3 16:46:56 1996 +++ linux/fs/ext2/ioctl.c Tue Jul 2 19:08:42 1996 @@ -82,6 +82,6 @@ inode->i_dirt = 1; return 0; default: - return -EINVAL; + return -ENOTTY; } } diff -u --recursive --new-file v2.0.0/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.0.0/linux/fs/ext2/namei.c Mon Dec 11 06:56:35 1995 +++ linux/fs/ext2/namei.c Wed Jul 3 11:46:41 1996 @@ -25,12 +25,6 @@ #include /* - * comment out this line if you want names > EXT2_NAME_LEN chars to be - * truncated. Else they will be disallowed. - */ -/* #define NO_TRUNCATE */ - -/* * define how far ahead to read directories while searching them. */ #define NAMEI_RA_CHUNKS 2 @@ -80,13 +74,8 @@ return NULL; sb = dir->i_sb; -#ifdef NO_TRUNCATE if (namelen > EXT2_NAME_LEN) return NULL; -#else - if (namelen > EXT2_NAME_LEN) - namelen = EXT2_NAME_LEN; -#endif memset (bh_use, 0, sizeof (bh_use)); toread = 0; @@ -176,6 +165,8 @@ iput (dir); return -ENOENT; } + if (len > EXT2_NAME_LEN) + return -ENAMETOOLONG; if (dcache_lookup(dir, name, len, &ino)) { if (!ino) { iput(dir); @@ -232,13 +223,13 @@ if (!dir) return NULL; sb = dir->i_sb; -#ifdef NO_TRUNCATE + if (namelen > EXT2_NAME_LEN) + { + *err = -ENAMETOOLONG; return NULL; -#else - if (namelen > EXT2_NAME_LEN) - namelen = EXT2_NAME_LEN; -#endif + } + if (!namelen) return NULL; /* @@ -415,6 +406,9 @@ if (!dir) return -ENOENT; + + if (len > EXT2_NAME_LEN) + return -ENAMETOOLONG; bh = ext2_find_entry (dir, name, len, &de); if (bh) { brelse (bh); @@ -478,6 +472,8 @@ if (!dir) return -ENOENT; + if (len > EXT2_NAME_LEN) + return -ENAMETOOLONG; bh = ext2_find_entry (dir, name, len, &de); if (bh) { brelse (bh); @@ -615,6 +611,8 @@ if (!dir) return -ENOENT; inode = NULL; + if (len > EXT2_NAME_LEN) + return -ENAMETOOLONG; bh = ext2_find_entry (dir, name, len, &de); retval = -ENOENT; if (!bh) @@ -624,8 +622,10 @@ goto end_rmdir; if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); - if (inode->i_dev != dir->i_dev) + if (inode->i_dev != dir->i_dev) { + retval = -EBUSY; goto end_rmdir; + } if (de->inode != inode->i_ino) { iput(inode); brelse(bh); @@ -699,6 +699,8 @@ return -ENOENT; retval = -ENOENT; inode = NULL; + if (len > EXT2_NAME_LEN) + return -ENAMETOOLONG; bh = ext2_find_entry (dir, name, len, &de); if (!bh) goto end_unlink; @@ -928,7 +930,8 @@ */ static int do_ext2_rename (struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len) + const char * new_name, int new_len, + int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -952,6 +955,10 @@ old_inode = new_inode = NULL; old_bh = new_bh = dir_bh = NULL; new_de = NULL; + retval = -ENAMETOOLONG; + if (old_len > EXT2_NAME_LEN) + goto end_rename; + old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de); retval = -ENOENT; if (!old_bh) @@ -959,6 +966,8 @@ old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -1099,7 +1108,8 @@ * on the same file system */ int ext2_rename (struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { int result; @@ -1107,7 +1117,7 @@ sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait); old_dir->i_sb->u.ext2_sb.s_rename_lock = 1; result = do_ext2_rename (old_dir, old_name, old_len, new_dir, - new_name, new_len); + new_name, new_len, must_be_dir); old_dir->i_sb->u.ext2_sb.s_rename_lock = 0; wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait); return result; diff -u --recursive --new-file v2.0.0/linux/fs/ioctl.c linux/fs/ioctl.c --- v2.0.0/linux/fs/ioctl.c Sun Mar 10 09:28:56 1996 +++ linux/fs/ioctl.c Tue Jul 2 19:08:42 1996 @@ -51,7 +51,7 @@ } if (filp->f_op && filp->f_op->ioctl) return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg); - return -EINVAL; + return -ENOTTY; } @@ -103,6 +103,6 @@ if (filp->f_op && filp->f_op->ioctl) return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg); - return -EINVAL; + return -ENOTTY; } } diff -u --recursive --new-file v2.0.0/linux/fs/locks.c linux/fs/locks.c --- v2.0.0/linux/fs/locks.c Sun Jun 9 13:28:46 1996 +++ linux/fs/locks.c Tue Jul 2 19:08:42 1996 @@ -317,6 +317,8 @@ break; case F_UNLCK : break; + default: + return -EINVAL; } return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); @@ -448,7 +450,7 @@ if (current->signal & ~current->blocked) return (-ERESTARTSYS); if (posix_locks_deadlock(current, fl->fl_owner)) - return (-EDEADLOCK); + return (-EDEADLK); interruptible_sleep_on(&fl->fl_wait); if (current->signal & ~current->blocked) return (-ERESTARTSYS); @@ -762,7 +764,7 @@ if (current->signal & ~current->blocked) return (-ERESTARTSYS); if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner)) - return (-EDEADLOCK); + return (-EDEADLK); interruptible_sleep_on(&fl->fl_wait); if (current->signal & ~current->blocked) return (-ERESTARTSYS); diff -u --recursive --new-file v2.0.0/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.0.0/linux/fs/minix/namei.c Wed Nov 8 12:22:48 1995 +++ linux/fs/minix/namei.c Wed Jul 3 13:13:21 1996 @@ -672,7 +672,7 @@ * higher-level routines. */ static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -700,6 +700,8 @@ old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -816,7 +818,8 @@ * as they are on different partitions. */ int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -826,7 +829,7 @@ sleep_on(&wait); lock = 1; result = do_minix_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + new_dir, new_name, new_len, must_be_dir); lock = 0; wake_up(&wait); return result; diff -u --recursive --new-file v2.0.0/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v2.0.0/linux/fs/msdos/namei.c Sat May 11 10:42:06 1996 +++ linux/fs/msdos/namei.c Wed Jul 3 12:08:03 1996 @@ -738,7 +738,8 @@ /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */ int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len) + struct inode *new_dir,const char *new_name,int new_len, + int must_be_dir) { struct super_block *sb = old_dir->i_sb; char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME]; diff -u --recursive --new-file v2.0.0/linux/fs/namei.c linux/fs/namei.c --- v2.0.0/linux/fs/namei.c Wed Apr 17 09:06:32 1996 +++ linux/fs/namei.c Wed Jul 3 11:38:01 1996 @@ -515,6 +515,43 @@ return error; } +/* + * Some operations need to remove trailing slashes for POSIX.1 + * conformance. For rename we also need to change the behaviour + * depending on whether we had a trailing slash or not.. (we + * cannot rename normal files with trailing slashes, only dirs) + * + * "dummy" is used to make sure we don't do "/" -> "". + */ +static int remove_trailing_slashes(char * name) +{ + int result; + char dummy[1]; + char *remove = dummy+1; + + for (;;) { + char c = *name; + name++; + if (!c) + break; + if (c != '/') { + remove = NULL; + continue; + } + if (remove) + continue; + remove = name; + } + + result = 0; + if (remove) { + remove[-1] = 0; + result = 1; + } + + return result; +} + static int do_mkdir(const char * pathname, int mode) { const char * basename; @@ -557,6 +594,7 @@ error = getname(pathname,&tmp); if (!error) { + remove_trailing_slashes(tmp); error = do_mkdir(tmp,mode); putname(tmp); } @@ -607,6 +645,7 @@ error = getname(pathname,&tmp); if (!error) { + remove_trailing_slashes(tmp); error = do_rmdir(tmp); putname(tmp); } @@ -788,7 +827,7 @@ return error; } -static int do_rename(const char * oldname, const char * newname) +static int do_rename(const char * oldname, const char * newname, int must_be_dir) { struct inode * old_dir, * new_dir; const char * old_base, * new_base; @@ -852,7 +891,7 @@ new_dir->i_sb->dq_op->initialize(new_dir, -1); down(&new_dir->i_sem); error = old_dir->i_op->rename(old_dir, old_base, old_len, - new_dir, new_base, new_len); + new_dir, new_base, new_len, must_be_dir); up(&new_dir->i_sem); iput(new_dir); return error; @@ -867,7 +906,9 @@ if (!error) { error = getname(newname,&to); if (!error) { - error = do_rename(from,to); + error = do_rename(from,to, + remove_trailing_slashes(from) | + remove_trailing_slashes(to)); putname(to); } putname(from); diff -u --recursive --new-file v2.0.0/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c --- v2.0.0/linux/fs/ncpfs/dir.c Mon Jun 3 16:46:57 1996 +++ linux/fs/ncpfs/dir.c Wed Jul 3 12:10:59 1996 @@ -63,7 +63,8 @@ static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir); static inline void str_upper(char *name) @@ -1099,7 +1100,8 @@ static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { int res; char _old_name[old_len+1]; diff -u --recursive --new-file v2.0.0/linux/fs/nfs/bio.c linux/fs/nfs/bio.c --- v2.0.0/linux/fs/nfs/bio.c Sun Jun 9 13:28:46 1996 +++ linux/fs/nfs/bio.c Sat Jun 29 12:00:46 1996 @@ -16,6 +16,9 @@ * Another possible solution to this problem may be to have a cache of recent * RPC call results indexed by page pointer, or even a result code field * in struct page. + * + * June 96: Added retries of RPCs that seem to have failed for a transient + * reason. */ #include @@ -90,64 +93,114 @@ } /* + * This is the function to (re-) transmit an NFS readahead request + */ +static int +nfsiod_read_setup(struct nfsiod_req *req) +{ + struct inode *inode = req->rq_inode; + struct page *page = req->rq_page; + + return nfs_proc_read_request(&req->rq_rpcreq, + NFS_SERVER(inode), NFS_FH(inode), + page->offset, PAGE_SIZE, + (__u32 *) page_address(page)); +} + +/* * This is the callback from nfsiod telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ -static void -nfs_read_cb(int result, struct nfsiod_req *req) +static int +nfsiod_read_result(int result, struct nfsiod_req *req) { - struct page *page = (struct page *) req->rq_cdata; + struct nfs_server *server = NFS_SERVER(req->rq_inode); + struct page *page = req->rq_page; static int succ = 0, fail = 0; + int i; dprintk("BIO: received callback for page %p, result %d\n", page, result); - if (result >= 0 - && (result = nfs_proc_read_reply(&req->rq_rpcreq)) >= 0) { - succ++; + if (result >= 0) { + struct nfs_fattr fattr; + + result = nfs_proc_read_reply(&req->rq_rpcreq, &fattr); + if (result >= 0) { + nfs_refresh_inode(req->rq_inode, &fattr); + if (result < PAGE_SIZE) + memset((u8 *) page_address(page)+result, + 0, PAGE_SIZE-result); + } + } else + if (result == -ETIMEDOUT && !(server->flags & NFS_MOUNT_SOFT)) { + /* XXX: Theoretically, we'd have to increment the initial + * timeo here; but I'm not going to bother with this now + * because this old nfsiod stuff will soon die anyway. + */ + result = -EAGAIN; + } + + if (result == -EAGAIN && req->rq_retries--) { + dprintk("BIO: retransmitting request.\n"); + memset(&req->rq_rpcreq, 0, sizeof(struct rpc_ioreq)); + while (rpc_reserve(server->rsock, &req->rq_rpcreq, 1) < 0) + schedule(); + current->fsuid = req->rq_fsuid; + current->fsgid = req->rq_fsgid; + for (i = 0; i < NGROUPS; i++) + current->groups[i] = req->rq_groups[i]; + nfsiod_read_setup(req); + return 0; + } + if (result >= 0) { set_bit(PG_uptodate, &page->flags); + succ++; } else { - fail++; dprintk("BIO: %d successful reads, %d failures\n", succ, fail); set_bit(PG_error, &page->flags); + fail++; } clear_bit(PG_locked, &page->flags); wake_up(&page->wait); free_page(page_address(page)); + return 1; } static inline int do_read_nfs_async(struct inode *inode, struct page *page) { struct nfsiod_req *req; - int result = -1; /* totally arbitrary */ + int result, i; dprintk("NFS: do_read_nfs_async(%p)\n", page); set_bit(PG_locked, &page->flags); clear_bit(PG_error, &page->flags); - if (!(req = nfsiod_reserve(NFS_SERVER(inode), nfs_read_cb))) - goto done; - result = nfs_proc_read_request(&req->rq_rpcreq, - NFS_SERVER(inode), NFS_FH(inode), - page->offset, PAGE_SIZE, - (__u32 *) page_address(page)); - if (result >= 0) { - req->rq_cdata = page; + if (!(req = nfsiod_reserve(NFS_SERVER(inode)))) + return -EAGAIN; + + req->rq_retries = 5; + req->rq_callback = nfsiod_read_result; + req->rq_inode = inode; + req->rq_page = page; + + req->rq_fsuid = current->fsuid; + req->rq_fsgid = current->fsgid; + for (i = 0; i < NGROUPS; i++) + req->rq_groups[i] = current->groups[i]; + + if ((result = nfsiod_read_setup(req)) >= 0) { page->count++; - result = nfsiod_enqueue(req); - if (result >= 0) - dprintk("NFS: enqueued async READ request.\n"); - } - if (result < 0) { + nfsiod_enqueue(req); + } else { dprintk("NFS: deferring async READ request.\n"); nfsiod_release(req); clear_bit(PG_locked, &page->flags); wake_up(&page->wait); } -done: return result < 0? result : 0; } diff -u --recursive --new-file v2.0.0/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.0.0/linux/fs/nfs/dir.c Sat Jun 1 20:11:34 1996 +++ linux/fs/nfs/dir.c Wed Jul 3 13:54:26 1996 @@ -32,7 +32,7 @@ static int nfs_link(struct inode *, struct inode *, const char *, int); static int nfs_mknod(struct inode *, const char *, int, int, int); static int nfs_rename(struct inode *, const char *, int, - struct inode *, const char *, int); + struct inode *, const char *, int, int); static struct file_operations nfs_dir_operations = { NULL, /* lseek - default */ @@ -505,8 +505,7 @@ return -ENAMETOOLONG; } error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name); - if (!error) - nfs_lookup_cache_remove(dir, NULL, name); + nfs_lookup_cache_remove(dir, NULL, name); iput(dir); return error; } @@ -531,7 +530,7 @@ return -EIO; /* DWIM */ } ret = nfs_proc_rename(NFS_SERVER(dir), NFS_FH(dir), name, - NFS_FH(dir), silly); + NFS_FH(dir), silly, 0); if (ret >= 0) { nfs_lookup_cache_remove(dir, NULL, name); nfs_lookup_cache_remove(dir, NULL, silly); @@ -571,8 +570,7 @@ } if ((error = nfs_sillyrename(dir, name, len)) < 0) { error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name); - if (!error) - nfs_lookup_cache_remove(dir, NULL, name); + nfs_lookup_cache_remove(dir, NULL, name); } iput(dir); return error; @@ -630,15 +628,16 @@ } error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode), NFS_FH(dir), name); - if (!error) - nfs_lookup_cache_remove(dir, oldinode, NULL); + + nfs_lookup_cache_remove(dir, oldinode, NULL); iput(oldinode); iput(dir); return error; } static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { int error; @@ -661,11 +660,11 @@ } error = nfs_proc_rename(NFS_SERVER(old_dir), NFS_FH(old_dir), old_name, - NFS_FH(new_dir), new_name); - if (!error) { - nfs_lookup_cache_remove(old_dir, NULL, old_name); - nfs_lookup_cache_remove(new_dir, NULL, new_name); - } + NFS_FH(new_dir), new_name, + must_be_dir); + + nfs_lookup_cache_remove(old_dir, NULL, old_name); + nfs_lookup_cache_remove(new_dir, NULL, new_name); iput(old_dir); iput(new_dir); return error; diff -u --recursive --new-file v2.0.0/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v2.0.0/linux/fs/nfs/file.c Tue Apr 2 13:32:22 1996 +++ linux/fs/nfs/file.c Sat Jun 29 12:00:46 1996 @@ -146,7 +146,9 @@ file->f_pos = pos; if (pos > inode->i_size) inode->i_size = pos; - nfs_refresh_inode(inode, &fattr); + /* Avoid possible Solaris 2.5 nfsd bug */ + if (inode->i_ino == fattr.fileid) + nfs_refresh_inode(inode, &fattr); return written; } diff -u --recursive --new-file v2.0.0/linux/fs/nfs/nfsiod.c linux/fs/nfs/nfsiod.c --- v2.0.0/linux/fs/nfs/nfsiod.c Mon Apr 8 19:01:45 1996 +++ linux/fs/nfs/nfsiod.c Sat Jun 29 12:00:46 1996 @@ -37,7 +37,7 @@ * Reserve an nfsiod slot and initialize the request struct */ struct nfsiod_req * -nfsiod_reserve(struct nfs_server *server, nfsiod_done_fn_t callback) +nfsiod_reserve(struct nfs_server *server) { struct nfsiod_req *req; @@ -56,8 +56,6 @@ } req->rq_server = server; - req->rq_callback = callback; - return req; } @@ -74,21 +72,12 @@ /* * Transmit a request and put it on nfsiod's list of pending requests. */ -int +void nfsiod_enqueue(struct nfsiod_req *req) { - int result; - dprintk("BIO: enqueuing request %p\n", &req->rq_rpcreq); - result = rpc_transmit(req->rq_server->rsock, &req->rq_rpcreq); - if (result < 0) { - dprintk("BIO: rpc_transmit returned %d\n", result); - } else { - dprintk("BIO: waking up nfsiod (%p)\n", req->rq_wait); - wake_up(&req->rq_wait); - schedule(); - } - return result; + wake_up(&req->rq_wait); + schedule(); } /* @@ -120,8 +109,10 @@ current->pid); active++; dprintk("BIO: before: now %d nfsiod's active\n", active); - result = nfs_rpc_doio(req->rq_server, &req->rq_rpcreq, 1); - req->rq_callback(result, req); + do { + result = nfs_rpc_doio(req->rq_server, + &req->rq_rpcreq, 1); + } while (!req->rq_callback(result, req)); active--; } diff -u --recursive --new-file v2.0.0/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.0.0/linux/fs/nfs/proc.c Sun Apr 21 19:22:11 1996 +++ linux/fs/nfs/proc.c Wed Jul 3 13:52:09 1996 @@ -451,13 +451,12 @@ req->rq_addr = &server->toaddr; req->rq_alen = sizeof(server->toaddr); - return 0; + return rpc_transmit(server->rsock, req); } int -nfs_proc_read_reply(struct rpc_ioreq *req) +nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr) { - struct nfs_fattr fattr; int status; __u32 *p0, *p; int count; @@ -465,9 +464,11 @@ p0 = (__u32 *) req->rq_rvec[0].iov_base; if (!(p = nfs_rpc_verify(p0))) { - status = -errno_NFSERR_IO; + /* Tell the upper layers to retry */ + status = -EAGAIN; + /* status = -errno_NFSERR_IO; */ } else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fattr(p, &fattr); + p = xdr_decode_fattr(p, fattr); count = ntohl(*p++); if (p != req->rq_rvec[2].iov_base) { /* unexpected RPC reply header size. punt. @@ -612,12 +613,19 @@ int nfs_proc_rename(struct nfs_server *server, struct nfs_fh *old_dir, const char *old_name, - struct nfs_fh *new_dir, const char *new_name) + struct nfs_fh *new_dir, const char *new_name, + int must_be_dir) { int *p, *p0; int status; int ruid = 0; + /* + * Disallow "rename()" with trailing slashes over NFS: getting + * POSIX.1 behaviour is just too unlikely. + */ + if (must_be_dir) + return -EINVAL; PRINTK("NFS call rename %s -> %s\n", old_name, new_name); if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; diff -u --recursive --new-file v2.0.0/linux/fs/open.c linux/fs/open.c --- v2.0.0/linux/fs/open.c Tue May 28 08:09:56 1996 +++ linux/fs/open.c Tue Jul 2 19:08:42 1996 @@ -53,6 +53,8 @@ return -EBADF; if (!(inode = file->f_inode)) return -ENOENT; + if (!inode->i_sb) + return -ENODEV; if (!inode->i_sb->s_op->statfs) return -ENOSYS; inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); @@ -397,7 +399,7 @@ /* * If the owner has been changed, remove the setuid bit */ - if (user != inode->i_uid && (inode->i_mode & S_ISUID)) { + if (inode->i_mode & S_ISUID) { newattrs.ia_mode &= ~S_ISUID; newattrs.ia_valid |= ATTR_MODE; } @@ -407,8 +409,7 @@ * Don't remove the setgid bit if no group execute bit. * This is a file marked for mandatory locking. */ - if (group != inode->i_gid && - ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } @@ -453,7 +454,7 @@ /* * If the owner has been changed, remove the setuid bit */ - if (user != inode->i_uid && (inode->i_mode & S_ISUID)) { + if (inode->i_mode & S_ISUID) { newattrs.ia_mode &= ~S_ISUID; newattrs.ia_valid |= ATTR_MODE; } @@ -463,8 +464,7 @@ * Don't remove the setgid bit if no group execute bit. * This is a file marked for mandatory locking. */ - if (group != inode->i_gid && - ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } @@ -509,7 +509,7 @@ f->f_mode = (flag+1) & O_ACCMODE; if (f->f_mode) flag++; - if (flag & (O_TRUNC | O_CREAT)) + if (flag & O_TRUNC) flag |= 2; error = open_namei(filename,flag,mode,&inode,NULL); if (error) diff -u --recursive --new-file v2.0.0/linux/fs/pipe.c linux/fs/pipe.c --- v2.0.0/linux/fs/pipe.c Sun May 5 08:52:03 1996 +++ linux/fs/pipe.c Tue Jul 2 19:08:42 1996 @@ -67,8 +67,10 @@ } PIPE_LOCK(*inode)--; wake_up_interruptible(&PIPE_WAIT(*inode)); - if (read) + if (read) { + inode->i_atime = CURRENT_TIME; return read; + } if (PIPE_WRITERS(*inode)) return -EAGAIN; return 0; @@ -118,6 +120,7 @@ wake_up_interruptible(&PIPE_WAIT(*inode)); free = 1; } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; return written; } diff -u --recursive --new-file v2.0.0/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.0.0/linux/fs/proc/array.c Sun May 5 08:52:03 1996 +++ linux/fs/proc/array.c Mon Jun 10 08:14:28 1996 @@ -861,8 +861,13 @@ * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH * + (index into the line) */ +#ifdef __alpha__ +#define MAPS_LINE_FORMAT "%016lx-%016lx %s %016lx %s %lu\n" +#define MAPS_LINE_MAX 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ +#else #define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu\n" #define MAPS_LINE_MAX 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ +#endif static int read_maps (int pid, struct file * file, char * buf, int count) { diff -u --recursive --new-file v2.0.0/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v2.0.0/linux/fs/smbfs/dir.c Thu Jun 6 17:42:36 1996 +++ linux/fs/smbfs/dir.c Wed Jul 3 12:09:32 1996 @@ -61,7 +61,8 @@ static int smb_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir); static inline void str_upper(char *name) { @@ -882,7 +883,8 @@ static int smb_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { int res; char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN]; diff -u --recursive --new-file v2.0.0/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.0.0/linux/fs/smbfs/proc.c Thu Jun 6 17:42:37 1996 +++ linux/fs/smbfs/proc.c Tue Jul 2 19:08:43 1996 @@ -305,7 +305,7 @@ case ERRdiffdevice: return EXDEV; case ERRnofiles: return 0; case ERRbadshare: return ETXTBSY; - case ERRlock: return EDEADLOCK; + case ERRlock: return EDEADLK; case ERRfilexists: return EEXIST; case 87: return 0; /* Unknown error!! */ /* This next error seems to occur on an mv when @@ -330,7 +330,7 @@ case ERRdata: return EIO; case ERRbadreq: return ERANGE; case ERRbadshare: return ETXTBSY; - case ERRlock: return EDEADLOCK; + case ERRlock: return EDEADLK; default: return EIO; } else if (errcls == ERRCMD) diff -u --recursive --new-file v2.0.0/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.0.0/linux/fs/sysv/namei.c Wed Nov 8 12:36:10 1995 +++ linux/fs/sysv/namei.c Wed Jul 3 12:06:03 1996 @@ -668,7 +668,7 @@ * higher-level routines. */ static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -694,6 +694,8 @@ old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -808,7 +810,8 @@ * as they are on different partitions. */ int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -818,7 +821,7 @@ sleep_on(&wait); lock = 1; result = do_sysv_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + new_dir, new_name, new_len, must_be_dir); lock = 0; wake_up(&wait); return result; diff -u --recursive --new-file v2.0.0/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v2.0.0/linux/fs/umsdos/ioctl.c Sun Mar 24 20:07:00 1996 +++ linux/fs/umsdos/ioctl.c Wed Jul 3 16:39:48 1996 @@ -219,7 +219,7 @@ ret = msdos_rename (dir ,data.dos_dirent.d_name,data.dos_dirent.d_reclen ,dir - ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); + ,data.umsdos_dirent.name,data.umsdos_dirent.name_len,0); }else if (cmd == UMSDOS_UNLINK_EMD){ /* #Specification: ioctl / UMSDOS_UNLINK_EMD The umsdos_dirent field of the struct umsdos_ioctl is used diff -u --recursive --new-file v2.0.0/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v2.0.0/linux/fs/umsdos/namei.c Tue May 7 16:22:37 1996 +++ linux/fs/umsdos/namei.c Wed Jul 3 16:41:31 1996 @@ -353,7 +353,8 @@ ret = msdos_rename (old_dir ,old_info.fake.fname,old_info.fake.len ,new_dir - ,new_info.fake.fname,new_info.fake.len); + ,new_info.fake.fname,new_info.fake.len + ,0); chkstk(); PRINTK (("after m_rename ret %d ",ret)); if (ret != 0){ @@ -1014,7 +1015,8 @@ int old_len, struct inode * new_dir, const char * new_name, - int new_len) + int new_len, + int must_be_dir) { /* #Specification: weakness / rename There is a case where UMSDOS rename has a different behavior diff -u --recursive --new-file v2.0.0/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.0.0/linux/fs/vfat/namei.c Sat May 11 10:42:06 1996 +++ linux/fs/vfat/namei.c Wed Jul 3 11:58:01 1996 @@ -1352,7 +1352,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len) + struct inode *new_dir,const char *new_name,int new_len,int must_be_dir) { struct super_block *sb = old_dir->i_sb; struct buffer_head *old_bh,*new_bh,*dotdot_bh; @@ -1383,8 +1383,12 @@ PRINTK(("vfat_rename 3\n")); if (res < 0) goto rename_done; - if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done; + res = -ENOENT; + if (!(old_inode = iget(old_dir->i_sb,old_ino))) + goto rename_done; is_dir = S_ISDIR(old_inode->i_mode); + if (must_be_dir && !is_dir) + goto rename_done; if (is_dir) { if ((old_dir->i_dev != new_dir->i_dev) || (old_ino == new_dir->i_ino)) { diff -u --recursive --new-file v2.0.0/linux/fs/xiafs/namei.c linux/fs/xiafs/namei.c --- v2.0.0/linux/fs/xiafs/namei.c Wed Nov 8 12:32:32 1995 +++ linux/fs/xiafs/namei.c Wed Jul 3 16:28:55 1996 @@ -713,7 +713,8 @@ */ static int do_xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len) + const char * new_name, int new_len, + int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -730,6 +731,8 @@ old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -832,7 +835,8 @@ * as they are on different partitions. */ int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -842,7 +846,8 @@ sleep_on(&wait); lock = 1; result = do_xiafs_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + new_dir, new_name, new_len, + must_be_dir); lock = 0; wake_up(&wait); return result; diff -u --recursive --new-file v2.0.0/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h --- v2.0.0/linux/include/asm-alpha/byteorder.h Thu Feb 15 09:20:41 1996 +++ linux/include/asm-alpha/byteorder.h Mon Jul 1 20:06:05 1996 @@ -21,6 +21,9 @@ extern unsigned long int __ntohl(unsigned long int); extern unsigned short int __ntohs(unsigned short int); + +#ifdef __GNUC__ + extern unsigned long int __constant_ntohl(unsigned long int); extern unsigned short int __constant_ntohs(unsigned short int); @@ -100,6 +103,8 @@ (__builtin_constant_p((short)(x)) ? \ __constant_htons((x)) : \ __htons((x))) -#endif +#endif /* __OPTIMIZE__ */ + +#endif /* __GNUC__ */ -#endif +#endif /* _ALPHA_BYTEORDER_H */ diff -u --recursive --new-file v2.0.0/linux/include/asm-alpha/errno.h linux/include/asm-alpha/errno.h --- v2.0.0/linux/include/asm-alpha/errno.h Tue Nov 7 09:18:35 1995 +++ linux/include/asm-alpha/errno.h Tue Jul 2 19:08:43 1996 @@ -106,7 +106,9 @@ #define ENOANO 100 /* No anode */ #define EBADRQC 101 /* Invalid request code */ #define EBADSLT 102 /* Invalid slot */ +#if 0 #define EDEADLOCK 103 /* File locking deadlock error */ +#endif #define EBFONT 104 /* Bad font file format */ #define ENONET 105 /* Machine is not on the network */ #define ENOLINK 106 /* Link has been severed */ diff -u --recursive --new-file v2.0.0/linux/include/asm-i386/errno.h linux/include/asm-i386/errno.h --- v2.0.0/linux/include/asm-i386/errno.h Sat Jun 10 18:36:48 1995 +++ linux/include/asm-i386/errno.h Tue Jul 2 19:08:43 1996 @@ -58,7 +58,9 @@ #define ENOANO 55 /* No anode */ #define EBADRQC 56 /* Invalid request code */ #define EBADSLT 57 /* Invalid slot */ +#if 0 #define EDEADLOCK 58 /* File locking deadlock error */ +#endif #define EBFONT 59 /* Bad font file format */ #define ENOSTR 60 /* Device not a stream */ #define ENODATA 61 /* No data available */ diff -u --recursive --new-file v2.0.0/linux/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h --- v2.0.0/linux/include/asm-i386/posix_types.h Mon Jun 3 16:46:58 1996 +++ linux/include/asm-i386/posix_types.h Tue Jul 2 19:08:43 1996 @@ -28,32 +28,36 @@ #endif typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ } __kernel_fsid_t; #undef __FD_SET #define __FD_SET(fd,fdsetp) \ __asm__ __volatile__("btsl %1,%0": \ - "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_CLR #define __FD_CLR(fd,fdsetp) \ __asm__ __volatile__("btrl %1,%0": \ - "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_ISSET #define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ unsigned char __result; \ __asm__ __volatile__("btl %1,%2 ; setb %0" \ :"=q" (__result) :"r" ((int) (fd)), \ - "m" (*(fd_set *) (fdsetp))); \ + "m" (*(__kernel_fd_set *) (fdsetp))); \ __result; })) #undef __FD_ZERO #define __FD_ZERO(fdsetp) \ __asm__ __volatile__("cld ; rep ; stosl" \ - :"=m" (*(fd_set *) (fdsetp)) \ + :"=m" (*(__kernel_fd_set *) (fdsetp)) \ :"a" (0), "c" (__FDSET_INTS), \ - "D" ((fd_set *) (fdsetp)) :"cx","di") + "D" ((__kernel_fd_set *) (fdsetp)) :"cx","di") #endif diff -u --recursive --new-file v2.0.0/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h --- v2.0.0/linux/include/linux/affs_fs.h Mon May 20 08:21:04 1996 +++ linux/include/linux/affs_fs.h Wed Jul 3 11:53:06 1996 @@ -69,7 +69,8 @@ const char *symname); extern int affs_fixup(struct buffer_head *bh, struct inode *inode); extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir); /* inode.c */ diff -u --recursive --new-file v2.0.0/linux/include/linux/dirent.h linux/include/linux/dirent.h --- v2.0.0/linux/include/linux/dirent.h Tue Aug 15 18:31:52 1995 +++ linux/include/linux/dirent.h Tue Jul 2 19:08:43 1996 @@ -1,13 +1,11 @@ #ifndef _LINUX_DIRENT_H #define _LINUX_DIRENT_H -#include - struct dirent { long d_ino; off_t d_off; unsigned short d_reclen; - char d_name[NAME_MAX+1]; + char d_name[256]; /* We must not include limits.h! */ }; #endif diff -u --recursive --new-file v2.0.0/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v2.0.0/linux/include/linux/ext2_fs.h Sun Jun 9 13:28:47 1996 +++ linux/include/linux/ext2_fs.h Wed Jul 3 11:48:37 1996 @@ -495,7 +495,7 @@ extern int ext2_link (struct inode *, struct inode *, const char *, int); extern int ext2_mknod (struct inode *, const char *, int, int, int); extern int ext2_rename (struct inode *, const char *, int, - struct inode *, const char *, int); + struct inode *, const char *, int, int); /* super.c */ extern void ext2_error (struct super_block *, const char *, const char *, ...) diff -u --recursive --new-file v2.0.0/linux/include/linux/ext_fs.h linux/include/linux/ext_fs.h --- v2.0.0/linux/include/linux/ext_fs.h Mon Jan 15 07:59:13 1996 +++ linux/include/linux/ext_fs.h Wed Jul 3 11:53:06 1996 @@ -74,7 +74,7 @@ extern int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len); + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); extern struct inode * ext_new_inode(const struct inode * dir); extern void ext_free_inode(struct inode * inode); extern unsigned long ext_count_free_inodes(struct super_block *sb); diff -u --recursive --new-file v2.0.0/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.0.0/linux/include/linux/fs.h Tue May 28 08:10:01 1996 +++ linux/include/linux/fs.h Wed Jul 3 17:53:14 1996 @@ -478,7 +478,7 @@ int (*mkdir) (struct inode *,const char *,int,int); int (*rmdir) (struct inode *,const char *,int); int (*mknod) (struct inode *,const char *,int,int,int); - int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int); + int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int); int (*readlink) (struct inode *,char *,int); int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **); int (*readpage) (struct inode *, struct page *); diff -u --recursive --new-file v2.0.0/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.0.0/linux/include/linux/if_arp.h Sat Jun 1 20:11:35 1996 +++ linux/include/linux/if_arp.h Wed Jul 3 17:55:18 1996 @@ -22,6 +22,7 @@ #ifndef _LINUX_IF_ARP_H #define _LINUX_IF_ARP_H +#include /* ARP protocol HARDWARE identifiers. */ #define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ diff -u --recursive --new-file v2.0.0/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v2.0.0/linux/include/linux/isdn.h Sun Jun 9 13:28:47 1996 +++ linux/include/linux/isdn.h Sat Jun 29 20:36:23 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.14 1996/06/06 21:24:23 fritz Exp $ +/* $Id: isdn.h,v 1.15 1996/06/15 14:56:57 fritz Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.15 1996/06/15 14:56:57 fritz + * Added version signatures for data structures used + * by userlevel programs. + * * Revision 1.14 1996/06/06 21:24:23 fritz * Started adding support for suspend/resume. * @@ -118,6 +122,7 @@ #define IIOCNETASL _IO('I',19) #define IIOCNETDIL _IO('I',20) #define IIOCGETCPS _IO('I',21) +#define IIOCGETDVR _IO('I',22) #define IIOCNETALN _IO('I',32) #define IIOCNETDLN _IO('I',33) @@ -164,6 +169,9 @@ char phone[20]; int outgoing; } isdn_net_ioctl_phone; + +#define NET_DV 0x01 /* Data version for net_cfg */ +#define TTY_DV 0x01 /* Data version for iprofd etc. */ typedef struct { char name[10]; /* Name of interface */ diff -u --recursive --new-file v2.0.0/linux/include/linux/loop.h linux/include/linux/loop.h --- v2.0.0/linux/include/linux/loop.h Sun Mar 24 20:07:01 1996 +++ linux/include/linux/loop.h Mon Jul 1 20:06:05 1996 @@ -32,6 +32,10 @@ des_key_schedule lo_des_key; unsigned long lo_des_init[2]; #endif +#ifdef IDEA_AVAILABLE + idea_key lo_idea_en_key; + idea_key lo_idea_de_key; +#endif }; typedef int (* transfer_proc_t)(struct loop_device *, int cmd, diff -u --recursive --new-file v2.0.0/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h --- v2.0.0/linux/include/linux/minix_fs.h Mon Jan 15 07:59:14 1996 +++ linux/include/linux/minix_fs.h Wed Jul 3 11:53:06 1996 @@ -100,7 +100,7 @@ extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len); + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); extern struct inode * minix_new_inode(const struct inode * dir); extern void minix_free_inode(struct inode * inode); extern unsigned long minix_count_free_inodes(struct super_block *sb); diff -u --recursive --new-file v2.0.0/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.0.0/linux/include/linux/mm.h Sat Apr 27 15:20:07 1996 +++ linux/include/linux/mm.h Wed Jul 3 17:53:14 1996 @@ -318,7 +318,8 @@ unsigned long grow; address &= PAGE_MASK; - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) + if (vma->vm_end - address + > (unsigned long) current->rlim[RLIMIT_STACK].rlim_cur) return -ENOMEM; grow = vma->vm_start - address; vma->vm_start = address; diff -u --recursive --new-file v2.0.0/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v2.0.0/linux/include/linux/msdos_fs.h Tue May 7 16:22:38 1996 +++ linux/include/linux/msdos_fs.h Wed Jul 3 17:56:37 1996 @@ -251,7 +251,8 @@ extern int msdos_unlink(struct inode *dir,const char *name,int len); extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len); extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len); + struct inode *new_dir,const char *new_name,int new_len, + int must_be_dir); /* fatfs_syms.c */ extern int init_fat_fs(void); @@ -263,7 +264,8 @@ extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode); extern int vfat_rmdir(struct inode *dir,const char *name,int len); extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len); + struct inode *new_dir,const char *new_name,int new_len, + int must_be_dir); extern void vfat_put_super(struct super_block *sb); extern struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent); diff -u --recursive --new-file v2.0.0/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.0.0/linux/include/linux/nfs_fs.h Fri Apr 12 15:52:08 1996 +++ linux/include/linux/nfs_fs.h Wed Jul 3 11:53:06 1996 @@ -79,7 +79,8 @@ const char *name); extern int nfs_proc_rename(struct nfs_server *server, struct nfs_fh *old_dir, const char *old_name, - struct nfs_fh *new_dir, const char *new_name); + struct nfs_fh *new_dir, const char *new_name, + int must_be_dir); extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fh *dir, const char *name); extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, @@ -96,7 +97,7 @@ extern int nfs_proc_read_request(struct rpc_ioreq *, struct nfs_server *, struct nfs_fh *, unsigned long offset, unsigned long count, __u32 *buf); -extern int nfs_proc_read_reply(struct rpc_ioreq *); +extern int nfs_proc_read_reply(struct rpc_ioreq *, struct nfs_fattr *); extern int *rpc_header(int *p, int procedure, int program, int version, int uid, int gid, int *groups); extern int *rpc_verify(int *p); diff -u --recursive --new-file v2.0.0/linux/include/linux/nfsiod.h linux/include/linux/nfsiod.h --- v2.0.0/linux/include/linux/nfsiod.h Tue Apr 2 13:32:22 1996 +++ linux/include/linux/nfsiod.h Wed Jul 3 13:52:36 1996 @@ -9,6 +9,7 @@ #define _LINUX_NFSIOD_H #include +#include #ifdef __KERNEL__ @@ -17,7 +18,7 @@ * Note that the callback procedure must NOT sleep. */ struct nfsiod_req; -typedef void (*nfsiod_done_fn_t)(int result, struct nfsiod_req *); +typedef int (*nfsiod_callback_t)(int result, struct nfsiod_req *); /* * This is the nfsiod request struct. @@ -25,16 +26,25 @@ struct nfsiod_req { struct nfsiod_req * rq_next; struct nfsiod_req * rq_prev; - struct nfs_server * rq_server; struct wait_queue * rq_wait; struct rpc_ioreq rq_rpcreq; - nfsiod_done_fn_t rq_callback; - void * rq_cdata; + nfsiod_callback_t rq_callback; + struct nfs_server * rq_server; + struct inode * rq_inode; + struct page * rq_page; + + /* user creds */ + uid_t rq_fsuid; + gid_t rq_fsgid; + int rq_groups[NGROUPS]; + + /* retry handling */ + int rq_retries; }; -struct nfsiod_req * nfsiod_reserve(struct nfs_server *, nfsiod_done_fn_t); +struct nfsiod_req * nfsiod_reserve(struct nfs_server *); void nfsiod_release(struct nfsiod_req *); -int nfsiod_enqueue(struct nfsiod_req *); +void nfsiod_enqueue(struct nfsiod_req *); int nfsiod(void); diff -u --recursive --new-file v2.0.0/linux/include/linux/posix_types.h linux/include/linux/posix_types.h --- v2.0.0/linux/include/linux/posix_types.h Wed Mar 27 08:19:29 1996 +++ linux/include/linux/posix_types.h Tue Jul 2 19:08:43 1996 @@ -12,10 +12,10 @@ #endif /* - * This allows for 256 file descriptors: if NR_OPEN is ever grown - * beyond that you'll have to change this too. But 256 fd's seem to be - * enough even for such "real" unices like SunOS, so hopefully this is - * one limit that doesn't have to be changed. + * This allows for 1024 file descriptors: if NR_OPEN is ever grown + * beyond that you'll have to change this too. But 1024 fd's seem to be + * enough even for such "real" unices like OSF/1, so hopefully this is + * one limit that doesn't have to be changed [again]. * * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in * (and thus ) - but this is a more logical @@ -30,7 +30,7 @@ #define __NFDBITS (8 * sizeof(unsigned int)) #undef __FD_SETSIZE -#define __FD_SETSIZE 256 +#define __FD_SETSIZE 1024 #undef __FDSET_INTS #define __FDSET_INTS (__FD_SETSIZE/__NFDBITS) @@ -41,7 +41,7 @@ #undef __FDMASK #define __FDMASK(d) (1 << ((d) % __NFDBITS)) -typedef struct fd_set { +typedef struct { unsigned int fds_bits [__FDSET_INTS]; } __kernel_fd_set; diff -u --recursive --new-file v2.0.0/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v2.0.0/linux/include/linux/soundcard.h Sun Apr 21 12:39:03 1996 +++ linux/include/linux/soundcard.h Sun Jun 30 12:25:28 1996 @@ -58,6 +58,8 @@ #define SNDCARD_MAUI 23 #define SNDCARD_PSEUDO_MSS 24 #define SNDCARD_GUSPNP 25 +#define SNDCARD_UART401 26 +/* Soundcard numbers 27 to N are reserved. Don't add more numbers here */ /*********************************** * IOCTL Commands for /dev/sequencer @@ -140,7 +142,7 @@ * Sample loading mechanism for internal synthesizers (/dev/sequencer) * The following patch_info structure has been designed to support * Gravis UltraSound. It tries to be universal format for uploading - * sample based patches but is probably too limited. + * sample based patches but is propably too limited. */ struct patch_info { @@ -168,6 +170,7 @@ #define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ #define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ #define WAVE_SCALE 0x00040000 /* The scaling info is valid */ +#define WAVE_FRACTIONS 0x00080000 /* Fraction information is valid */ /* Other bits must be zeroed */ int len; /* Size of the wave data in bytes */ @@ -220,7 +223,8 @@ unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */ int volume; - int spare[4]; + int fractions; + int spare[3]; char data[1]; /* The waveform data starts here */ }; @@ -259,7 +263,7 @@ * may confuse the patch manager daemon. */ -struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */ +struct patmgr_info { unsigned int key; /* Don't worry. Reserved for communication between the patch manager and the driver. */ #define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */ @@ -550,7 +554,8 @@ #define SNDCTL_DSP_STEREO _IOWR('P', 3, int) #define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) #define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT -#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int) +#define SNDCTL_DSP_CHANNELS _IOWR('P', 6, int) +#define SOUND_PCM_WRITE_CHANNELS SNDCTL_DSP_CHANNELS #define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int) #define SNDCTL_DSP_POST _IO ('P', 8) #define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int) @@ -575,7 +580,7 @@ * Buffer status queries. */ typedef struct audio_buf_info { - int fragments; /* # of available fragments (partially used ones not counted) */ + int fragments; /* # of available fragments (partially usend ones not counted) */ int fragstotal; /* Total # of fragments allocated */ int fragsize; /* Size of a fragment in bytes */ @@ -688,7 +693,7 @@ #define SNDCTL_COPR_WCODE _IOW ('C', 5, copr_debug_buf) #define SNDCTL_COPR_RUN _IOWR('C', 6, copr_debug_buf) #define SNDCTL_COPR_HALT _IOWR('C', 7, copr_debug_buf) -#define SNDCTL_COPR_SENDMSG _IOW ('C', 8, copr_msg) +#define SNDCTL_COPR_SENDMSG _IOWR('C', 8, copr_msg) #define SNDCTL_COPR_RCVMSG _IOR ('C', 9, copr_msg) /********************************************* @@ -722,7 +727,7 @@ /* * The AD1848 codec and compatibles have three line level inputs * (line, aux1 and aux2). Since each card manufacturer have assigned - * different meanings to these inputs, it's impractical to assign + * different meanings to these inputs, it's inpractical to assign * specific meanings (line, cd, synth etc.) to them. */ #define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ @@ -737,6 +742,7 @@ /* Note! Number 31 cannot be used since the sign bit is reserved */ +#ifdef NO_LONGER_AVAILABLE /* * The following unsupported macros will be removed from the API in near * future. @@ -744,7 +750,7 @@ #define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ #define SOUND_MIXER_MUTE 28 /* 0 or 1 */ #define SOUND_MIXER_LOUD 30 /* 0 or 1 */ - +#endif #define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ @@ -784,9 +790,11 @@ #define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) #define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) +#ifdef NO_LONGER_AVAILABLE #define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) #define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) #define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) +#endif #define MIXER_READ(dev) _IOR('M', dev, int) #define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) @@ -806,9 +814,11 @@ #define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) #define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) #define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) +#ifdef NO_LONGER_AVAILABLE #define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) #define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) +#endif #define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) #define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) @@ -834,12 +844,42 @@ #define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) #define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) #define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) +#ifdef NO_LONGER_AVAILABLE #define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) #define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) +#endif #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) +typedef struct mixer_info +{ + char id[16]; + char name[32]; +} mixer_info; + +#define SOUND_MIXER_INFO _IOR ('M', 101, mixer_info) + +/* + * A mechanism for accessing "proprietary" mixer features. This method + * permits passing 128 bytes of arbitrary data between a mixer application + * and the mixer driver. Interpretation of the record is defined by + * the particular mixer driver. + */ +typedef unsigned char mixer_record[128]; + +#define SOUND_MIXER_ACCESS _IOWR('M', 102, mixer_record) + +/* + * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers. + * These features can be used when accessing device specific features. + */ +#define SOUND_MIXER_PRIVATE1 _IOWR('M', 111, int) +#define SOUND_MIXER_PRIVATE2 _IOWR('M', 112, int) +#define SOUND_MIXER_PRIVATE3 _IOWR('M', 113, int) +#define SOUND_MIXER_PRIVATE4 _IOWR('M', 114, int) +#define SOUND_MIXER_PRIVATE5 _IOWR('M', 115, int) + /* * Level 2 event types for /dev/sequencer */ @@ -1077,7 +1117,7 @@ #define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2) /* - * Timing and synchronization macros + * Timing and syncronization macros */ #define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ diff -u --recursive --new-file v2.0.0/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v2.0.0/linux/include/linux/sysv_fs.h Mon Mar 25 10:26:15 1996 +++ linux/include/linux/sysv_fs.h Wed Jul 3 17:58:15 1996 @@ -373,7 +373,7 @@ extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len); + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); extern struct inode * sysv_new_inode(const struct inode * dir); extern void sysv_free_inode(struct inode * inode); extern unsigned long sysv_count_free_inodes(struct super_block *sb); diff -u --recursive --new-file v2.0.0/linux/include/linux/time.h linux/include/linux/time.h --- v2.0.0/linux/include/linux/time.h Tue Feb 13 19:55:59 1996 +++ linux/include/linux/time.h Tue Jul 2 19:08:43 1996 @@ -1,10 +1,13 @@ #ifndef _LINUX_TIME_H #define _LINUX_TIME_H +#ifndef _STRUCT_TIMESPEC +#define _STRUCT_TIMESPEC struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; +#endif /* _STRUCT_TIMESPEC */ struct timeval { int tv_sec; /* seconds */ diff -u --recursive --new-file v2.0.0/linux/include/linux/ultrasound.h linux/include/linux/ultrasound.h --- v2.0.0/linux/include/linux/ultrasound.h Fri Apr 12 15:52:08 1996 +++ linux/include/linux/ultrasound.h Sun Jun 30 11:43:41 1996 @@ -6,27 +6,11 @@ * and not portable. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ @@ -50,7 +34,7 @@ * _GUS_VOICEOFF - Stops voice (no parameters) * _GUS_VOICEFADE - Stops the voice smoothly. * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode) - * _GUS_VOICEBALA - Sets voice balance (P1, 0=left, 7=middle and 15=right, default 7) + * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7) * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz) * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) diff -u --recursive --new-file v2.0.0/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p --- v2.0.0/linux/include/linux/umsdos_fs.p Tue Aug 1 10:02:47 1995 +++ linux/include/linux/umsdos_fs.p Wed Jul 3 16:39:14 1996 @@ -122,7 +122,8 @@ int old_len, struct inode *new_dir, const char *new_name, - int new_len); + int new_len, + int must_be_dir); /* rdir.c 22/03/95 03.31.42 */ int umsdos_rlookup_x (struct inode *dir, const char *name, diff -u --recursive --new-file v2.0.0/linux/include/linux/xia_fs.h linux/include/linux/xia_fs.h --- v2.0.0/linux/include/linux/xia_fs.h Mon Jan 15 07:59:14 1996 +++ linux/include/linux/xia_fs.h Wed Jul 3 11:53:06 1996 @@ -79,7 +79,8 @@ int mode, int rdev); extern int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len); + const char * new_name, int new_len, + int must_be_dir); extern struct inode * xiafs_new_inode(struct inode * dir); extern void xiafs_free_inode(struct inode * inode); extern unsigned long xiafs_count_free_inodes(struct super_block *sb); diff -u --recursive --new-file v2.0.0/linux/include/scsi/scsi.h linux/include/scsi/scsi.h --- v2.0.0/linux/include/scsi/scsi.h Wed Jun 5 10:41:29 1996 +++ linux/include/scsi/scsi.h Wed Jun 26 11:05:26 1996 @@ -96,7 +96,7 @@ #define RESERVATION_CONFLICT 0x0c #define QUEUE_FULL 0x1a -#define STATUS_MASK 0x1e +#define STATUS_MASK 0x3e /* * SENSE KEYS diff -u --recursive --new-file v2.0.0/linux/kernel/exit.c linux/kernel/exit.c --- v2.0.0/linux/kernel/exit.c Mon Jun 3 16:46:59 1996 +++ linux/kernel/exit.c Tue Jul 2 19:08:43 1996 @@ -75,8 +75,8 @@ if (!p || sig > 32) return -EINVAL; if (!priv && ((sig != SIGCONT) || (current->session != p->session)) && - (current->euid ^ p->euid) && (current->euid ^ p->uid) && - (current->uid ^ p->euid) && (current->uid ^ p->uid) && + (current->euid ^ p->suid) && (current->euid ^ p->uid) && + (current->uid ^ p->suid) && (current->uid ^ p->uid) && !suser()) return -EPERM; if (!sig) @@ -346,12 +346,12 @@ * * "I ask you, have you ever known what it is to be an orphan?" */ -int is_orphaned_pgrp(int pgrp) +static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task) { struct task_struct *p; for_each_task(p) { - if ((p->pgrp != pgrp) || + if ((p == ignored_task) || (p->pgrp != pgrp) || (p->state == TASK_ZOMBIE) || (p->p_pptr->pid == 1)) continue; @@ -362,6 +362,11 @@ return(1); /* (sighing) "Often!" */ } +int is_orphaned_pgrp(int pgrp) +{ + return will_become_orphaned_pgrp(pgrp, 0); +} + static inline int has_stopped_jobs(int pgrp) { struct task_struct * p; @@ -495,7 +500,7 @@ */ if ((current->p_pptr->pgrp != current->pgrp) && (current->p_pptr->session == current->session) && - is_orphaned_pgrp(current->pgrp) && + will_become_orphaned_pgrp(current->pgrp, current) && has_stopped_jobs(current->pgrp)) { kill_pg(current->pgrp,SIGHUP,1); kill_pg(current->pgrp,SIGCONT,1); @@ -607,6 +612,9 @@ if (flag) return flag; } + if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) + return -EINVAL; + add_wait_queue(¤t->wait_chldexit,&wait); repeat: flag=0; @@ -666,12 +674,11 @@ retval = 0; if (options & WNOHANG) goto end_wait4; - current->state=TASK_INTERRUPTIBLE; - schedule(); - current->signal &= ~(1<<(SIGCHLD-1)); retval = -ERESTARTSYS; if (current->signal & ~current->blocked) goto end_wait4; + current->state=TASK_INTERRUPTIBLE; + schedule(); goto repeat; } retval = -ECHILD; diff -u --recursive --new-file v2.0.0/linux/kernel/fork.c linux/kernel/fork.c --- v2.0.0/linux/kernel/fork.c Tue Apr 23 13:57:14 1996 +++ linux/kernel/fork.c Tue Jul 2 19:08:43 1996 @@ -34,7 +34,6 @@ static inline int find_empty_process(void) { int i; - struct task_struct *p; if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) { if (current->uid) @@ -43,7 +42,9 @@ if (current->uid) { long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur; + max_tasks--; /* count the new process.. */ if (max_tasks < nr_tasks) { + struct task_struct *p; for_each_task (p) { if (p->uid == current->uid) if (--max_tasks < 0) diff -u --recursive --new-file v2.0.0/linux/kernel/sched.c linux/kernel/sched.c --- v2.0.0/linux/kernel/sched.c Tue May 7 16:22:40 1996 +++ linux/kernel/sched.c Sat Jun 29 12:00:48 1996 @@ -573,6 +573,7 @@ { struct timer_list * timer; + cli(); while ((timer = timer_head.next) != &timer_head && timer->expires <= jiffies) { void (*fn)(unsigned long) = timer->function; unsigned long data = timer->data; @@ -583,6 +584,7 @@ fn(data); cli(); } + sti(); } static inline void run_old_timers(void) @@ -942,6 +944,12 @@ } update_one_process(p, ticks, utime, stime); + if (p->priority < DEF_PRIORITY) + kstat.cpu_nice += utime; + else + kstat.cpu_user += utime; + kstat.cpu_system += stime; + p->counter -= ticks; if (p->counter >= 0) continue; @@ -966,25 +974,27 @@ static unsigned long lost_ticks = 0; static unsigned long lost_ticks_system = 0; -static void timer_bh(void) +static inline void update_times(void) { - unsigned long ticks, system; + unsigned long ticks; - run_old_timers(); - - cli(); - run_timer_list(); - ticks = lost_ticks; - lost_ticks = 0; - system = lost_ticks_system; - lost_ticks_system = 0; - sti(); + ticks = xchg(&lost_ticks, 0); if (ticks) { + unsigned long system; + + system = xchg(&lost_ticks_system, 0); calc_load(ticks); update_wall_time(ticks); update_process_times(ticks, system); } +} + +static void timer_bh(void) +{ + update_times(); + run_old_timers(); + run_timer_list(); } /* diff -u --recursive --new-file v2.0.0/linux/kernel/signal.c linux/kernel/signal.c --- v2.0.0/linux/kernel/signal.c Sat Feb 17 09:19:43 1996 +++ linux/kernel/signal.c Tue Jul 2 19:08:43 1996 @@ -91,7 +91,7 @@ * POSIX 3.3.1.3: * "Setting a signal action to SIG_IGN for a signal that is pending * shall cause the pending signal to be discarded, whether or not - * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone). + * it is blocked." * * "Setting a signal action to SIG_DFL for a signal that is pending * and whose default action is to ignore the signal (for example, @@ -108,8 +108,6 @@ p = signum - 1 + current->sig->action; if (p->sa_handler == SIG_IGN) { - if (signum == SIGCHLD) - return; current->signal &= ~_S(signum); return; } @@ -156,18 +154,14 @@ if (signum<1 || signum>32) return -EINVAL; - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; p = signum - 1 + current->sig->action; if (action) { int err = verify_area(VERIFY_READ, action, sizeof(*action)); if (err) return err; + if (signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); - new_sa.sa_mask |= _S(signum); - if (new_sa.sa_flags & SA_NOMASK) - new_sa.sa_mask &= ~_S(signum); - new_sa.sa_mask &= _BLOCKABLE; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) diff -u --recursive --new-file v2.0.0/linux/kernel/sys.c linux/kernel/sys.c --- v2.0.0/linux/kernel/sys.c Thu Jun 6 17:42:38 1996 +++ linux/kernel/sys.c Tue Jul 2 19:08:43 1996 @@ -634,8 +634,13 @@ asmlinkage int sys_setsid(void) { - if (current->leader) - return -EPERM; + struct task_struct * p; + + for_each_task(p) { + if (p->pgrp == current->pid) + return -EPERM; + } + current->leader = 1; current->session = current->pgrp = current->pid; current->tty = NULL; @@ -651,21 +656,29 @@ int i; int * groups; - if (gidsetsize) { - i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize); - if (i) - return i; - } + if (gidsetsize < 0) + return -EINVAL; groups = current->groups; - for (i = 0 ; (i < NGROUPS) && (*groups != NOGROUP) ; i++, groups++) { - if (!gidsetsize) - continue; - if (i >= gidsetsize) + for (i = 0 ; i < NGROUPS ; i++) { + if (groups[i] == NOGROUP) break; - put_user(*groups, grouplist); - grouplist++; } - return(i); + if (gidsetsize) { + int error; + error = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize); + if (error) + return error; + if (i > gidsetsize) + return -EINVAL; + + for (i = 0 ; i < NGROUPS ; i++) { + if (groups[i] == NOGROUP) + break; + put_user(groups[i], grouplist); + grouplist++; + } + } + return i; } asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) diff -u --recursive --new-file v2.0.0/linux/lib/ctype.c linux/lib/ctype.c --- v2.0.0/linux/lib/ctype.c Mon Nov 27 15:53:48 1995 +++ linux/lib/ctype.c Tue Jul 2 19:08:43 1996 @@ -26,10 +26,11 @@ _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + diff -u --recursive --new-file v2.0.0/linux/mm/mremap.c linux/mm/mremap.c --- v2.0.0/linux/mm/mremap.c Fri Apr 12 15:52:10 1996 +++ linux/mm/mremap.c Wed Jun 26 09:44:52 1996 @@ -167,8 +167,6 @@ return -EINVAL; old_len = PAGE_ALIGN(old_len); new_len = PAGE_ALIGN(new_len); - if (old_len == new_len) - return addr; /* * Always allow a shrinking remap: that just unmaps @@ -196,7 +194,8 @@ } /* old_len exactly to the end of the area.. */ - if (old_len == vma->vm_end - addr) { + if (old_len == vma->vm_end - addr && + (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { unsigned long max_addr = TASK_SIZE; if (vma->vm_next) max_addr = vma->vm_next->vm_start; diff -u --recursive --new-file v2.0.0/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.0.0/linux/mm/swapfile.c Fri May 31 08:02:20 1996 +++ linux/mm/swapfile.c Tue Jun 11 13:00:11 1996 @@ -16,6 +16,7 @@ #include #include #include +#include /* for blk_size */ #include #include /* for cli()/sti() */ @@ -457,7 +458,9 @@ if(error) goto bad_swap_2; error = -ENODEV; - if (!p->swap_device) + if (!p->swap_device || + (blk_size[MAJOR(p->swap_device)] && + !blk_size[MAJOR(p->swap_device)][MINOR(p->swap_device)])) goto bad_swap; error = -EBUSY; for (i = 0 ; i < nr_swapfiles ; i++) { diff -u --recursive --new-file v2.0.0/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.0.0/linux/mm/vmscan.c Thu Jun 6 17:42:38 1996 +++ linux/mm/vmscan.c Fri Jun 28 18:49:55 1996 @@ -404,6 +404,7 @@ while (1) { kswapd_awake = 0; current->signal = 0; + run_task_queue(&tq_disk); interruptible_sleep_on(&kswapd_wait); kswapd_awake = 1; swapstats.wakeups++; diff -u --recursive --new-file v2.0.0/linux/net/core/sock.c linux/net/core/sock.c --- v2.0.0/linux/net/core/sock.c Sun Jun 9 13:28:47 1996 +++ linux/net/core/sock.c Wed Jun 26 11:05:26 1996 @@ -185,6 +185,8 @@ val = SK_RMEM_MAX*2; if(val < 256) val = 256; + if(val > 65535) + val = 65535; sk->rcvbuf = val; return(0); diff -u --recursive --new-file v2.0.0/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.0.0/linux/net/ipv4/af_inet.c Sun Jun 9 13:28:47 1996 +++ linux/net/ipv4/af_inet.c Tue Jul 2 19:08:43 1996 @@ -926,7 +926,7 @@ * Reuse ? */ - if (!sk2->reuse || sk2->state==TCP_LISTEN) + if (!sk2->dead) { sti(); return(-EADDRINUSE); diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c --- v2.0.0/linux/net/ipv4/ip_forward.c Thu Jun 6 17:42:39 1996 +++ linux/net/ipv4/ip_forward.c Tue Jul 2 12:14:08 1996 @@ -326,7 +326,7 @@ #ifdef CONFIG_IP_MROUTE if(is_frag&IPFWD_MULTITUNNEL) { - skb_reserve(skb,(encap+dev->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ + skb_reserve(skb2,(encap+dev2->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ ip_encap(skb2,skb->len, dev2, raddr); } else diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.0.0/linux/net/ipv4/ip_fw.c Sun Jun 9 13:28:47 1996 +++ linux/net/ipv4/ip_fw.c Sat Jun 29 12:00:48 1996 @@ -264,9 +264,11 @@ /* * Too short. + * + * But only too short for a packet with ports... */ - else if(ntohs(ip->tot_len)<8+(ip->ihl<<2)) + else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)) return FW_BLOCK; src = ip->saddr; diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c --- v2.0.0/linux/net/ipv4/ip_masq_app.c Sat Jun 1 20:11:37 1996 +++ linux/net/ipv4/ip_masq_app.c Fri Jun 28 18:49:55 1996 @@ -2,7 +2,7 @@ * IP_MASQ_APP application masquerading module * * - * Version: @(#)ip_masq_app.c 0.03 03/96 + * Version: @(#)ip_masq_app.c 0.04 96/06/17 * * Author: Juan Jose Ciarlante, * @@ -13,7 +13,8 @@ * 2 of the License, or (at your option) any later version. * * Fixes: - * JJC : Implemented also input pkt hook + * JJC : Implemented also input pkt hook + * Miquel van Smoorenburg : Copy more stuff when resizing skb * * * FIXME: @@ -502,6 +503,7 @@ { int maxsize, diff, o_offset; struct sk_buff *n_skb; + int offset; maxsize = skb->truesize - sizeof(struct sk_buff); @@ -521,7 +523,9 @@ skb->end = skb->head+n_len; } else { /* - * Sizes differ, make a copy + * Sizes differ, make a copy. + * + * FIXME: move this to core/sbuff.c:skb_grow() */ n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri); @@ -534,8 +538,22 @@ n_skb->free = skb->free; skb_reserve(n_skb, MAX_HEADER); skb_put(n_skb, skb->len + diff); - n_skb->h.raw = n_skb->data + (skb->h.raw - skb->data); - + + /* + * Copy as much data from the old skb as possible. Even + * though we're only forwarding packets, we need stuff + * like skb->protocol (PPP driver wants it). + */ + offset = n_skb->data - skb->data; + n_skb->h.raw = skb->h.raw + offset; + n_skb->when = skb->when; + n_skb->dev = skb->dev; + n_skb->mac.raw = skb->mac.raw + offset; + n_skb->ip_hdr = (struct iphdr *)(((char *)skb->ip_hdr)+offset); + n_skb->pkt_type = skb->pkt_type; + n_skb->protocol = skb->protocol; + n_skb->ip_summed = skb->ip_summed; + /* * Copy pkt in new buffer */ diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.0.0/linux/net/ipv4/ip_output.c Thu Jun 6 17:42:39 1996 +++ linux/net/ipv4/ip_output.c Sat Jun 29 20:47:09 1996 @@ -107,7 +107,7 @@ /* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */ /*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/ - ip_queue_xmit(NULL, dev, newskb, 1); + ip_queue_xmit(NULL, dev, newskb, 2); } @@ -160,9 +160,9 @@ skb->dev = dev; skb->arp = 1; skb->protocol = htons(ETH_P_IP); + skb_reserve(skb,MAX_HEADER); if (dev->hard_header) { - skb_reserve(skb,MAX_HEADER); if (rt && dev == rt->rt_dev && rt->rt_hh) { memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len); @@ -574,7 +574,7 @@ ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_MULTICAST - if(sk && MULTICAST(daddr) && *sk->ip_mc_name) + if(MULTICAST(daddr) && *sk->ip_mc_name) { dev=dev_get(sk->ip_mc_name); if(!dev) @@ -710,8 +710,10 @@ } return 0; } - length -= sizeof(struct iphdr); - if (sk && !sk->ip_hdrincl && opt) + if (!sk->ip_hdrincl) + length -= sizeof(struct iphdr); + + if(opt) { length -= opt->optlen; fragheaderlen = dev->hard_header_len + sizeof(struct iphdr) + opt->optlen; @@ -810,6 +812,7 @@ skb->sk = sk; skb->arp = 0; skb->saddr = saddr; + skb->daddr = daddr; skb->raddr = raddr; skb_reserve(skb,(dev->hard_header_len+15)&~15); data = skb_put(skb, fraglen-dev->hard_header_len); @@ -927,7 +930,7 @@ if(sk==NULL || sk->ip_mc_loop) { - if(skb->daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI)) + if(daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI)) ip_loopback(dev,skb); else { @@ -950,7 +953,11 @@ */ if(skb->ip_hdr->ttl==0) - kfree_skb(skb, FREE_READ); + { + kfree_skb(skb, FREE_WRITE); + nfrags++; + continue; + } } #endif diff -u --recursive --new-file v2.0.0/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.0.0/linux/net/ipv4/tcp.c Sun Jun 9 13:28:47 1996 +++ linux/net/ipv4/tcp.c Tue Jul 2 19:08:44 1996 @@ -551,8 +551,15 @@ if (rt->rt_mtu > new_mtu) rt->rt_mtu = new_mtu; + /* + * FIXME:: + * Not the nicest of fixes: Lose a MTU update if the socket is + * locked this instant. Not the right answer but will be best + * for the production fix. Make 2.1 work right! + */ + if (sk->mtu > new_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr) - && new_mtu > sizeof(struct iphdr)+sizeof(struct tcphdr)) + && new_mtu > sizeof(struct iphdr)+sizeof(struct tcphdr) && !sk->users) sk->mtu = new_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr); return; @@ -943,40 +950,44 @@ return -EPIPE; } - /* - * The following code can result in copy <= if sk->mss is ever - * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). - * sk->mtu is constant once SYN processing is finished. I.e. we - * had better not get here until we've seen his SYN and at least one - * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) - * But ESTABLISHED should guarantee that. sk->max_window is by definition - * non-decreasing. Note that any ioctl to set user_mss must be done - * before the exchange of SYN's. If the initial ack from the other - * end has a window of 0, max_window and thus mss will both be 0. - */ + /* + * The following code can result in copy <= if sk->mss is ever + * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). + * sk->mtu is constant once SYN processing is finished. I.e. we + * had better not get here until we've seen his SYN and at least one + * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) + * But ESTABLISHED should guarantee that. sk->max_window is by definition + * non-decreasing. Note that any ioctl to set user_mss must be done + * before the exchange of SYN's. If the initial ack from the other + * end has a window of 0, max_window and thus mss will both be 0. + */ - /* - * Now we need to check if we have a half built packet. - */ + /* + * Now we need to check if we have a half built packet. + */ #ifndef CONFIG_NO_PATH_MTU_DISCOVERY - /* - * FIXME: I'm almost sure that this fragment is BUG, - * but it works... I do not know why 8) --ANK - * - * Really, we should rebuild all the queues... - * It's difficult. Temporary hack is to send all - * queued segments with allowed fragmentation. - */ - { - int new_mss = min(sk->mtu, sk->max_window); - if (new_mss < sk->mss) + /* + * FIXME: I'm almost sure that this fragment is BUG, + * but it works... I do not know why 8) --ANK + * + * Really, we should rebuild all the queues... + * It's difficult. Temporary hack is to send all + * queued segments with allowed fragmentation. + */ { - tcp_send_partial(sk); - sk->mss = new_mss; + int new_mss = min(sk->mtu, sk->max_window); + if (new_mss < sk->mss) + { + tcp_send_partial(sk); + sk->mss = new_mss; + } } - } #endif + /* + * If there is a partly filled frame we can fill + * out. + */ if ((skb = tcp_dequeue_partial(sk)) != NULL) { int tcp_size; @@ -987,11 +998,33 @@ if (!(flags & MSG_OOB)) { copy = min(sk->mss - tcp_size, seglen); + + /* + * Now we may find the frame is as big, or too + * big for our MSS. Thats all fine. It means the + * MSS shrank (from an ICMP) after we allocated + * this frame. + */ + if (copy <= 0) { - printk(KERN_CRIT "TCP: **bug**: \"copy\" <= 0\n"); - return -EFAULT; + /* + * Send the now forced complete frame out. + * + * Note for 2.1: The MSS reduce code ought to + * flush any frames in partial that are now + * full sized. Not serious, potential tiny + * performance hit. + */ + tcp_send_skb(sk,skb); + /* + * Get a new buffer and try again. + */ + continue; } + /* + * Otherwise continue to fill the buffer. + */ tcp_size += copy; memcpy_fromfs(skb_put(skb,copy), from, copy); skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0); @@ -1378,11 +1411,9 @@ current->state = TASK_INTERRUPTIBLE; - skb = skb_peek(&sk->receive_queue); - do + skb = sk->receive_queue.next; + while (skb != (struct sk_buff *)&sk->receive_queue) { - if (!skb) - break; if (before(*seq, skb->seq)) break; offset = *seq - skb->seq; @@ -1396,7 +1427,6 @@ skb->used = 1; skb = skb->next; } - while (skb != (struct sk_buff *)&sk->receive_queue); if (copied) break; diff -u --recursive --new-file v2.0.0/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.0.0/linux/net/ipv4/tcp_input.c Sun Jun 9 13:28:48 1996 +++ linux/net/ipv4/tcp_input.c Sun Jun 9 18:01:04 1996 @@ -66,7 +66,7 @@ /* This used to test against sk->rtt. * On a purely receiving link, there is no rtt measure. - * The result is that we loose delayed ACKs on one way links. + * The result is that we lose delayed ACKs on one-way links. * Therefore we test against sk->rto, which will always * at least have a default value. */ @@ -860,11 +860,11 @@ * sensitive to minor changes in the round trip time. * We add in two compensating factors. * First we multiply by 5/4. For large congestion - * windows this allows us to tollerate burst traffic + * windows this allows us to tolerate burst traffic * delaying up to 1/4 of our packets. * We also add in a rtt / cong_window term. * For small congestion windows this allows - * a single packet delay, but has neglibible effect + * a single packet delay, but has negligible effect * on the compensation for large windows. */ sk->rto = (sk->rtt >> 3) + sk->mdev; @@ -1902,7 +1902,7 @@ { /* We got an ack, but it's not a good ack. * We used to test this with a call to tcp_ack, - * but this looses, because it takes the SYN + * but this loses, because it takes the SYN * packet out of the send queue, even if * the ACK doesn't have the SYN bit sent, and * therefore isn't the one we are waiting for. @@ -1932,7 +1932,7 @@ /* process the ACK, get the SYN packet out * of the send queue, do other initial - * processing stuff. [We know its good, and + * processing stuff. [We know it's good, and * we know it's the SYN,ACK we want.] */ tcp_ack(sk,th,skb->ack_seq,len); diff -u --recursive --new-file v2.0.0/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.0.0/linux/net/ipv4/tcp_output.c Sun Jun 9 13:28:48 1996 +++ linux/net/ipv4/tcp_output.c Sat Jun 29 12:00:48 1996 @@ -879,15 +879,22 @@ void tcp_send_delayed_ack(struct sock * sk, int max_timeout, unsigned long timeout) { unsigned long now; + static int delack_guard=0; + if(delack_guard) + return; + + delack_guard++; + /* Calculate new timeout */ now = jiffies; if (timeout > max_timeout) timeout = max_timeout; timeout += now; if (sk->bytes_rcv >= sk->max_unacked) { - timeout = now; - mark_bh(TIMER_BH); + tcp_send_ack(sk); + delack_guard--; + return; } /* Use new timeout only if there wasn't a older one earlier */ @@ -896,6 +903,7 @@ sk->ack_backlog++; add_timer(&sk->delack_timer); + delack_guard--; } diff -u --recursive --new-file v2.0.0/linux/net/socket.c linux/net/socket.c --- v2.0.0/linux/net/socket.c Thu Jun 6 17:42:39 1996 +++ linux/net/socket.c Sat Jun 29 12:00:48 1996 @@ -778,7 +778,7 @@ sock_release(newsock); return(-EINVAL); } - sock->file=current->files->fd[fd]; + newsock->file=current->files->fd[fd]; if (upeer_sockaddr) {