quota and PC speaker in vger-2.1.61

David Woodhouse (dwmw2@cam.ac.uk)
Wed, 05 Nov 1997 01:49:37 +0000


This is a multipart MIME message.

--==_Exmh_-8347387360
Content-Type: text/plain; charset=us-ascii

Here's a couple of patches.
The first gets quota to compile (and work) in the above mentioned kernel. The
changes in the official patch-2.1.62 don't go in cleanly.

The second is an amendment of the PC speaker driver to work with the new
xxx_{read,write} function prototypes. Hopefully, it should apply against a
fresh copy of the CVS tree.

Looking at what exmh does, they might not be in that order, but I'm sure you
can work it out :)

--==_Exmh_-8347387360
Content-Type: text/plain ; name="pcsp-vger-2.1.61-diff"; charset=us-ascii
Content-Description: pcsp-vger-2.1.61-diff
Content-Disposition: attachment; filename="pcsp-vger-2.1.61-diff"

--- linux/Documentation/Configure.help.orig Mon Nov 3 00:03:05 1997
+++ linux/Documentation/Configure.help Tue Nov 4 15:17:32 1997
@@ -5313,12 +5313,7 @@
information in various README files in drivers/sound. If you want
to compile this as a module ( = code which can be inserted in and
removed from the running kernel whenever you want), say M here and
- read Documentation/modules.txt. I'm told that even without a sound
- card, you can make your computer say more than an occasional beep,
- by programming the PC speaker. Kernel patches and programs to do
- that are at
- sunsite.unc.edu:/pub/Linux/kernel/patches/console/pcsndrv-X.X.tar.gz,
- to be extracted with "tar xzvf filename".
+ read Documentation/modules.txt.

ProAudioSpectrum 16 support
CONFIG_PAS
@@ -5512,6 +5507,69 @@
Answer Y if you want your audio card to emulate Sound Blaster Pro.
You should then say Y to "SoundBlaster (SB, SBPro, SB16, clones)
support" and N to "Audio Excel DSP 16 (MSS emulation)".
+
+PC speaker support
+CONFIG_PCSP
+ If you don't have a sound card in your computer, you can include a
+ driver for the PC speaker which allows it to act like a primitive
+ sound card. You can compile this as a module, in which case only the
+ timer-interrupt hooks and frequency initialization code will appear
+ in the kernel, and the rest of the driver will be loaded as a module
+ whenever you want. Further this driver supports DAC's
+ (Digital-to-Analog-Converter) connected to the parallel port.
+
+PC speaker automatic measurement
+CONFIG_PCSP_NO_TEST_SPEED
+ The PCSP-driver automatically tests the speed of your computer and
+ configure itself at kernel-startup. If your machine is too slow
+ (386SX and cannot play with more than 12500 Hz) the driver is disabled
+ and you here a beep.
+ However, you can override this if you specify a 'pcsp=SAMPLERATE' at
+ kernel commandline or by disabling the automatic speed detection.
+ THIS IS NOT RECOMMENDED, your machine may HANG if you select a
+ samplerate, which is to high for your machine.
+ If the measurement switch the driver off but an older version was
+ working on your machine, please contact me (beck@dgroup.de).
+ It is safe to answer 'N' here.
+
+PC speaker selected samplerate
+CONFIG_PCSP_SRATE
+ If you have disabled the automatically speed test, select here to
+ real samplerate that is used for PC speaker. The full range from
+ 12000Hz up to 18356 is allowed. Higher rates results in better
+ sound quality but may crash your machine if it is too slow (<486DX-33).
+
+PC speaker 16bit stereo emulation
+CONFIG_PCSP_16BIT
+ The PCSP-driver can emulate 16bit stereo audio data on any output
+ device. It cannot play this data at the high resolution and converts
+ them to 8bit (and mono for mono devices), but allows to run
+ applications that want 16bit samples (DOOM of course, what else :-),
+ but you need at least a 486DX and a DX-2 if you have only the
+ PC-Speaker; it works great on my 486DX-2 with a Stereo-on-1,
+ really better than my SB 1.5 :-).
+ It's save to say 'Y' if you have a Pentium our a faster machine.
+
+CONFIG_PCSP_MIXER
+ The PCSP-driver can simulate the /dev/mixer device. This is only
+ useful if you have Stereo-on-One or Stereo-DACs, because Mono-devices
+ will ignore the 2 volumes and use only the left volume (PC-Speaker
+ however use the mean value).
+ The /dev/mixer simulation supports only the Master-Volume device.
+ If you don't include /dev/mixer support, you can use pcsel to
+ change only the PC-Speaker volume, DACs will play at 100 %.
+ The mixer emulation is enabled when you have choosen the 16bit
+ emulation.
+ Disabling /dev/mixer support don't speed up anything, so it's save
+ to say 'Y'.
+
+PC speaker default left volume
+CONFIG_PCSP_LEFT
+ The startup volume for the left channel in %.
+
+PC speaker default right volume
+CONFIG_PCSP_RIGHT
+ The startup volume for the right channel in %.

Kernel profiling support
CONFIG_PROFILE
--- linux/arch/i386/kernel/irq.c.orig Mon Nov 3 00:03:21 1997
+++ linux/arch/i386/kernel/irq.c Tue Nov 4 15:15:45 1997
@@ -729,3 +729,85 @@
setup_x86_irq(2, &irq2);
setup_x86_irq(13, &irq13);
}
+
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+/*
+ * /dev/pcsp implementation, part of linux/arch/i386/kernel/irq.c
+ *
+ * Copyright (C) 1993-1997 Michael Beck
+ */
+
+static int (*pcsp_IRQ)(void) = NULL;
+static const char *pcsp_irq0_owner = NULL;
+static struct irqaction pcsp_action, *pcsp_old_action = NULL;
+
+/*
+ * this is the PCSP IRQ handler
+ */
+asmlinkage void pcsp_run_IRQ(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct irqaction * action;
+ int status;
+
+ status = pcsp_IRQ();
+ if (! status) {
+ /* Return with this interrupt masked if no action */
+ action = pcsp_old_action;
+ if (action) {
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ }
+ }
+}
+
+/*
+ * Set the function func to be executed as the timer int.
+ * if func returns a 0, the old IRQ0-handler(s) is called
+ */
+int pcsp_set_irq(int (*func)(void))
+{
+ unsigned long flags;
+ struct irqaction * action = irq_action[0];
+
+ pcsp_IRQ = func;
+ if (! pcsp_IRQ || ! action)
+ return -EINVAL;
+
+ /* fill in the action */
+ pcsp_action.handler = pcsp_run_IRQ;
+ pcsp_action.flags = 0; /* Do NOT allow other IRQ-handlers */
+ pcsp_action.mask = 0;
+ pcsp_action.name = "pcsp+timer";
+ pcsp_action.next = NULL;
+ pcsp_action.dev_id = NULL;
+
+ /* ok, change the handler */
+ save_flags(flags);
+ cli();
+ irq_action[0] = &pcsp_action;
+ restore_flags(flags);
+ pcsp_old_action = action;
+ return 0;
+}
+
+/*
+ * reset the IRQ0 to the old handling
+ */
+int pcsp_release_irq(void)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ irq_action[0] = pcsp_old_action;
+ restore_flags(flags);
+ pcsp_IRQ = NULL;
+ return 0;
+}
+#endif
+
--- linux/arch/i386/kernel/time.c.orig Mon Nov 3 00:03:26 1997
+++ linux/arch/i386/kernel/time.c Tue Nov 4 15:15:45 1997
@@ -170,6 +170,10 @@

#define TICK_SIZE tick

+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+extern int pcsp_clockticks, pcsp_timer0_latch;
+#endif
+
static unsigned long do_slow_gettimeoffset(void)
{
int count;
@@ -194,6 +198,14 @@
jiffies_t = jiffies;

count |= inb_p(0x40) << 8;
+
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+ /*
+ * when using PCSP, we must add the accumulated
+ * clockticks from the PCSP driver
+ */
+ count += pcsp_clockticks - pcsp_timer0_latch;
+#endif

/*
* avoiding timer inconsistencies (they are rare, but they happen)...
--- linux/arch/i386/config.in.orig Mon Nov 3 00:03:17 1997
+++ linux/arch/i386/config.in Tue Nov 4 15:15:45 1997
@@ -146,6 +146,10 @@
if [ "$CONFIG_SOUND" != "n" ]; then
source drivers/sound/Config.in
fi
+tristate 'PC-speaker and DAC driver support' CONFIG_PCSP
+if [ "$CONFIG_PCSP" != "n" ]; then
+ source drivers/pcsnd/config.in
+fi
endmenu

mainmenu_option next_comment
--- linux/drivers/char/vt.c.orig Fri Oct 24 00:27:09 1997
+++ linux/drivers/char/vt.c Tue Nov 4 15:28:56 1997
@@ -163,9 +163,20 @@
* comments - KDMKTONE doesn't put the process to sleep.
*/
#ifndef CONFIG_PMAC
+
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+extern char pcsp_speaker;
+#endif
+
static void
kd_nosound(unsigned long ignored)
{
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+ /* can't allow usage of counter 2 if /dev/pcsp use it */
+ if (pcsp_speaker)
+ return;
+#endif
+
/* disable counter 2 */
outb(inb_p(0x61)&0xFC, 0x61);
return;
@@ -187,6 +198,12 @@
kd_nosound };

unsigned int count = 0;
+
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+ /* can't allow usage of counter 2 if /dev/pcsp use it */
+ if (pcsp_speaker)
+ return;
+#endif

if (hz > 20 && hz < 32767)
count = 1193180 / hz;
--- linux/drivers/char/mem.c.orig Mon Nov 3 00:04:11 1997
+++ linux/drivers/char/mem.c Tue Nov 4 15:15:44 1997
@@ -29,6 +29,9 @@
#ifdef CONFIG_SOUND
void soundcard_init(void);
#endif
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+void pcsp_init(void);
+#endif
#ifdef CONFIG_ISDN
void isdn_init(void);
#endif
@@ -541,6 +544,9 @@
#endif
#ifdef CONFIG_SOUND
soundcard_init();
+#endif
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+ pcsp_init();
#endif
#ifdef CONFIG_JOYSTICK
/*
--- linux/drivers/char/joystick.c.orig Fri Oct 31 21:20:24 1997
+++ linux/drivers/char/joystick.c Tue Nov 4 15:32:16 1997
@@ -11,6 +11,10 @@
*/

#include <linux/config.h>
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+#include <linux/pcsp.h>
+#endif
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
@@ -125,6 +129,10 @@
outb(PIT_READ_TIMER, PIT_MODE);
t = inb(PIT_DATA);
t |= (int) inb(PIT_DATA) << 8;
+
+#if defined(CONFIG_PCSP) || defined(CONFIG_PCSP_MODULE)
+ t = pcsp_clockticks - pcsp_timer0_latch + t;
+#endif
restore_flags(flags);
return t;
}
--- linux/drivers/pcsnd/pcsndriv.c.orig Tue Nov 4 17:07:06 1997
+++ linux/drivers/pcsnd/pcsndriv.c Tue Nov 4 17:13:16 1997
@@ -0,0 +1,1022 @@
+/*
+ * linux/drivers/pcsnd/pcsndriv.c
+ *
+ * /dev/pcsp implementation
+ *
+ * Copyright (C) 1993-1997 Michael Beck
+ */
+
+#include <linux/config.h>
+#include <linux/pcsp.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timex.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/smp_lock.h>
+#include <asm/uaccess.h>
+
+#ifdef MODULE
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include "tables.h"
+
+/*
+ * This function will be used to generate a time delay on pentium
+ * processors; this delay is only needed for the STO1 because it has
+ * only one latch, so we must wait some time after we write the value
+ * for the left channel before we can write the right one
+ *
+ * as long as I haven't such, it's empty :-)
+ */
+
+#define PCSP_PENTIUM_DELAY
+
+/* PCSP internal maximum volume, it's hardcoded */
+#define PCSP_MAX_VOLUME 256
+
+/* need this */
+#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
+
+/* the parallel-ports */
+static pcsp_ports[] = { 0x3bc, 0x378, 0x278 };
+static pcsp_port_enable[] = { 0, 0, 0 };
+
+#define LP_NO 3
+#define LP_B(port) pcsp_ports[port] /* IO address */
+#define LP_S(port) inb_p(LP_B(port) + 1) /* status */
+
+/* general pcsp data */
+
+extern struct pcsp_status pcsp;
+
+/* Volume-tables */
+
+static unsigned char vl_tab[256];
+static unsigned char left_vol[256], right_vol[256];
+
+#ifdef CONFIG_PCSP_16BIT
+#define CONFIG_PCSP_MIXER
+static unsigned char left_volS[256], right_volS[256];
+#endif
+
+#ifdef CONFIG_PCSP_MIXER
+extern int pcsp_mixer_set(int whichDev, unsigned int level);
+extern int pcsp_mixer_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg);
+#endif
+
+static struct wait_queue *pcsp_sleep = NULL;
+
+extern int pcsp_set_irq(int (*func)(void));
+extern int pcsp_release_irq(void);
+static void pcsp_stop_timer(void);
+
+/* test if a parallel port is free */
+
+inline static int pcsp_free_port(int port)
+{
+ return (pcsp_port_enable[port] || !check_region(LP_B(port), 3));
+}
+
+static void pcsp_reserve_port(int port)
+{
+ pcsp_port_enable[port] = 1;
+ request_region(LP_B(port), 3, "pcsp");
+}
+
+void pcsp_free_ports(void)
+{
+ int port;
+
+ for (port = 0; port < LP_NO; ++port)
+ if (pcsp_port_enable[port])
+ release_region(LP_B(port), 3);
+}
+/* test if a Stereo-on-One is on lp(port) */
+inline static int stereo1_detect(unsigned port)
+{
+ if (! pcsp_free_port(port))
+ return 0;
+ outb(0x7F, LP_B(port));
+ if (LP_S(port) & 0x80) {
+ outb(0x80, LP_B(port));
+ return (LP_S(port) & 0x80) ? 0 : 1;
+ }
+ return 0;
+}
+
+/* test if a new Stereo-Circuit is on lp(port) */
+inline static int stereo_nc_detect(unsigned port)
+{
+ if (! pcsp_free_port(port))
+ return 0;
+ outb(0, LP_B(port));
+ if (LP_S(port) & 0x40) {
+ outb(0xFF, LP_B(port));
+ return (LP_S(port) & 0x40) ? 0 : 1;
+ }
+ return 0;
+}
+
+/* search for Stereo-on-One, return it's port if found */
+static int stereo1_init(void)
+{
+ register int i;
+
+ for (i = 0; i < LP_NO; ++i)
+ if (stereo1_detect(i)) {
+ pcsp_reserve_port(i);
+ pcsp.port = LP_B(i);
+ pcsp.act_dev = SNDCARD_STO1;
+ return i;
+ }
+ return (-ENODEV);
+}
+
+/* search for Stereo-NC, return it's port if found */
+static int stereo_nc_init(void)
+{
+ register int i;
+
+ for (i = 0; i < LP_NO; ++i)
+ if (stereo_nc_detect(i)) {
+ pcsp_reserve_port(i);
+ pcsp.port = LP_B(i);
+ pcsp.act_dev = SNDCARD_STNC;
+ return i;
+ }
+ return (-ENODEV);
+}
+
+/*
+ * the timer-int for playing thru PC-Speaker
+ *
+ */
+static int pcsp_do_timer(void)
+{
+ if (pcsp.index < pcsp.in[pcsp.actual]) {
+ outb(pcsp.e, 0x61);
+ outb(pcsp.e ^ 1, 0x61);
+ outb(vl_tab[pcsp.buffer[pcsp.index]], 0x42);
+ pcsp.xfer += pcsp.si;
+ pcsp.index = pcsp.xfer >> 16;
+ }
+ if (pcsp.index >= pcsp.in[pcsp.actual]) {
+ pcsp.xfer = pcsp.index = 0;
+ pcsp.in[pcsp.actual] = 0;
+ pcsp.actual ^= 1;
+ pcsp.buffer = pcsp.buf[pcsp.actual];
+ if (pcsp_sleep)
+ wake_up_interruptible(&pcsp_sleep);
+ if (pcsp.in[pcsp.actual] == 0)
+ pcsp_stop_timer();
+ }
+
+ if ( (pcsp_clockticks -= pcsp.timerCF) < 0) {
+ pcsp_clockticks += LATCH;
+ return 0;
+ }
+ return 1;
+}
+
+/* timer-int for playing thru STO1 */
+static int pcsp_do_sto1_timer(void)
+{
+ static int ret;
+
+ if (pcsp.buffer < pcsp.end) {
+ if (pcsp.mode) {
+ outb(right_vol[*pcsp.buffer++], pcsp.port);
+ outb(1, pcsp.port + 2);
+ outb(0, pcsp.port + 2);
+
+ /*
+ * I move the following code because
+ * I need some time delay for the left DAC
+ * on my 486DX2
+ * this will hopefully enough or we need some
+ * really time wasting jumps here
+ *
+ * This time delay will really be a problem for
+ * pentiums :-(
+ *
+ */
+
+ if ( (pcsp_clockticks -= pcsp.timerC) < 0) {
+ pcsp_clockticks += LATCH;
+ ret = 0;
+ }
+ else
+ ret = 1;
+
+ PCSP_PENTIUM_DELAY;
+
+ outb(left_vol[*pcsp.buffer++], pcsp.port);
+ outb(2, pcsp.port + 2);
+ outb(0, pcsp.port + 2);
+ }
+ else { /* Mono */
+ outb(left_vol[*pcsp.buffer++], pcsp.port);
+ if ( (pcsp_clockticks -= pcsp.timerC) < 0) {
+ pcsp_clockticks += LATCH;
+ ret = 0;
+ }
+ else
+ ret = 1;
+ }
+ }
+ if (pcsp.buffer >= pcsp.end) {
+ pcsp.in[pcsp.actual] = 0;
+ pcsp.actual ^= 1;
+ pcsp.buffer = pcsp.buf[pcsp.actual];
+ pcsp.end = pcsp.buffer + pcsp.in[pcsp.actual];
+ if (pcsp_sleep)
+ wake_up_interruptible(&pcsp_sleep);
+ if (pcsp.in[pcsp.actual] == 0)
+ pcsp_stop_timer();
+ }
+ return (ret);
+}
+
+/* timer-int for playing thru DACs */
+static int pcsp_do_dac_timer(void)
+{
+ if (pcsp.buffer < pcsp.end) {
+ if (pcsp.act_dev == SNDCARD_DACS) {
+ if (pcsp.mode) {
+ outb(left_vol[*pcsp.buffer++], pcsp.port);
+ outb(right_vol[*pcsp.buffer++], pcsp.portS);
+ }
+ else {
+ outb(left_vol[*pcsp.buffer], pcsp.port);
+ outb(left_vol[*pcsp.buffer++], pcsp.portS);
+ }
+ }
+ else /* Simple DAC */
+ outb(left_vol[*pcsp.buffer++], pcsp.port);
+ }
+ if (pcsp.buffer >= pcsp.end) {
+ pcsp.in[pcsp.actual] = 0;
+ pcsp.actual ^= 1;
+ pcsp.buffer = pcsp.buf[pcsp.actual];
+ pcsp.end = pcsp.buffer + pcsp.in[pcsp.actual];
+ if (pcsp_sleep)
+ wake_up_interruptible(&pcsp_sleep);
+ if (pcsp.in[pcsp.actual] == 0)
+ pcsp_stop_timer();
+ }
+
+ if ( (pcsp_clockticks -= pcsp.timerC) < 0) {
+ pcsp_clockticks += LATCH;
+ return 0;
+ }
+ return 1;
+}
+
+/* calculate all needed time-consts, return the 'adjusted' samplerate */
+static unsigned pcsp_calc_srate(unsigned rate)
+{
+ pcsp.timerC = (CLOCK_TICK_RATE + rate / 2) / rate;
+ pcsp.srate = (CLOCK_TICK_RATE + pcsp.timerC / 2) / pcsp.timerC;
+ /* and now for the PC-Speaker */
+
+ pcsp.timerCF = pcsp.realrate;
+ pcsp.si = (pcsp.srate << 16) / SRATE;
+ return pcsp.srate;
+}
+
+static void pcsp_start_timer(void)
+{
+ int result;
+
+ /* use the first buffer */
+ pcsp.actual = 0;
+ pcsp.xfer = pcsp.index = 0;
+ pcsp.buffer = pcsp.buf[pcsp.actual];
+ pcsp.end = pcsp.buffer + pcsp.in[pcsp.actual];
+
+ if (pcsp.act_dev == SNDCARD_PCSP) {
+ pcsp_speaker = 1;
+ pcsp.e = inb(0x61) | 0x03;
+ outb_p(0x92, 0x43); /* binary, mode 1, LSB only, ch 2 */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(pcsp.timerCF & 0xFF, 0x40);
+ outb(pcsp.timerCF >> 8 , 0x40);
+ if (pcsp_set_irq(pcsp_do_timer) < 0)
+ panic("PCSP: could not modify timer IRQ!");
+ pcsp_timer0_latch = pcsp.timerCF;
+ }
+ else { /* it's a DAC */
+ if (pcsp.act_dev == SNDCARD_STO1)
+ outb(3,pcsp.port + 2);
+
+ /* get the timer */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(pcsp.timerC & 0xFF, 0x40);
+ outb(pcsp.timerC >> 8 , 0x40);
+ if (pcsp.act_dev == SNDCARD_STO1)
+ result = pcsp_set_irq(pcsp_do_sto1_timer);
+ else
+ result = pcsp_set_irq(pcsp_do_dac_timer);
+ if (result < 0)
+ panic("PCSP: could not modify timer IRQ!");
+ pcsp_timer0_latch = pcsp.timerC;
+ }
+ pcsp_clockticks = pcsp.last_clocks;
+ pcsp.timer_on = 1;
+}
+
+/* reset the timer to 100 Hz and reset old timer-int */
+static void pcsp_stop_timer(void)
+{
+ if (pcsp.timer_on) {
+ /* restore the timer */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+
+ /* clear clock tick counter */
+ pcsp.last_clocks = pcsp_clockticks;
+ pcsp_timer0_latch = pcsp_clockticks = LATCH;
+
+ if (pcsp_release_irq() < 0)
+ panic("PCSP: could not reset timer IRQ!");
+
+ pcsp.timer_on = 0;
+ }
+
+ /* reset the buffer */
+ pcsp.in[0] = pcsp.in[1] = 0;
+ pcsp.xfer = pcsp.index = 0;
+ pcsp.actual = 0;
+ pcsp.buffer = pcsp.end = pcsp.buf[pcsp.actual];
+
+ pcsp_speaker = 0;
+}
+
+/*
+ calculate a translation-table for PC-Speaker
+*/
+static void pcsp_calc_vol(int volume)
+{
+ int i, j;
+
+ if (pcsp.is_ulaw)
+ for (i = 0; i < 256; ++i) {
+ j = ((i - 128) * volume) >> 8;
+ if (j < -128)
+ j = -128;
+ if (j > 127)
+ j = 127;
+ vl_tab[i] = sp_tab[ulaw[j + 128]];
+ }
+ else
+ for (i = 0; i < 256; ++i) {
+ j = ((i - 128) * volume) >> 8;
+ if (j < -128)
+ j = -128;
+ if (j > 127)
+ j = 127;
+ vl_tab[i] = sp_tab[j + 128];
+ }
+}
+
+/* calculate linear translation table for DACs */
+static void pcsp_calc_voltab(int volume, unsigned char *tab)
+{
+ int i, j;
+
+ if (pcsp.is_ulaw)
+ for (i = 0; i < 256; ++i) {
+ j = ((i - 128) * volume) >> 8;
+ *tab++ = ulaw[j + 128];
+ }
+ else
+ for (i = 0; i < 256; ++i) {
+ j = ((i - 128) * volume) >> 8;
+ *tab++ = j + 128;
+ }
+}
+
+static inline void pcsp_set_voltables(void)
+{
+#ifdef CONFIG_PCSP_16BIT
+ if (pcsp.stereo_emu) {
+ pcsp_calc_voltab(pcsp.left, left_volS);
+ pcsp_calc_voltab(pcsp.right, right_volS);
+ pcsp_calc_vol(PCSP_MAX_VOLUME);
+ pcsp_calc_voltab(PCSP_MAX_VOLUME, left_vol);
+ pcsp_calc_voltab(PCSP_MAX_VOLUME, right_vol);
+ }
+ else
+#endif
+ {
+ pcsp_calc_voltab(pcsp.left, left_vol);
+ pcsp_calc_voltab(pcsp.right, right_vol);
+ pcsp_calc_vol(pcsp.volume);
+ }
+}
+
+#ifdef CONFIG_PCSP_MIXER
+
+/* this is called if /dev/pcmixer change Mastervolume */
+inline void pcsp_set_volume(unsigned short v)
+{
+ pcsp.left = (((unsigned)(v & 0x7F) << 8) + 50) / 100;
+ pcsp.right = (((unsigned)(v & 0x7F00)) + 50) / 100;
+ pcsp.volume = (pcsp.right + pcsp.left) >> 1;
+ pcsp_set_voltables();
+}
+
+inline unsigned pcsp_get_mode(void)
+{
+ return pcsp.mode;
+}
+#endif
+
+/*
+ * set the speed for /dev/pcsp, it's now from 4000 - 44100 Hz,
+ * but DAC's are bounded by the maximal samplerate
+ */
+inline unsigned long pcsp_set_speed(unsigned long speed)
+{
+ if (speed < 4000)
+ speed = 4000;
+ if (speed > 44100)
+ speed = 44100;
+ if (pcsp.act_dev != SNDCARD_PCSP)
+ if (speed > pcsp.maxrate)
+ speed = pcsp.maxrate;
+ return speed;
+}
+
+/*
+ * set the audio type
+ */
+int pcsp_set_format(int fmt)
+{
+ static char ulaw;
+
+ if (fmt != AFMT_QUERY) {
+ ulaw = 0;
+ if (! (pcsp.fmt_msk & fmt)) /* Not supported */
+ if (fmt == AFMT_MU_LAW)
+ ulaw = 1;
+ else
+ fmt = AFMT_U8; /* this is supported */
+ pcsp.audio_fmt = fmt;
+ /*
+ we must recalculate the volume-tables is we change
+ ulaw-state
+ */
+ if (pcsp.is_ulaw != ulaw) {
+ pcsp.is_ulaw = ulaw;
+ pcsp_set_voltables();
+ }
+ }
+ return pcsp.audio_fmt;
+}
+
+/*
+ * set the stereo mode if possible
+ */
+static int pcsp_set_stereo(int flag)
+{
+ if (pcsp.act_dev == SNDCARD_STO1 ||
+ pcsp.act_dev == SNDCARD_DACS )
+#ifdef CONFIG_PCSP_16BIT
+ pcsp.stereo_emu = 0;
+ else {
+ pcsp.stereo_emu = flag ? 1 : 0;
+ /* test if the emulation is disabled */
+ if (! pcsp.enable_emu && pcsp.stereo_emu) {
+ pcsp.stereo_emu = 0;
+ pcsp.mode = 0;
+ return -EINVAL;
+ }
+ }
+ pcsp.mode = flag ? 1 : 0;
+ pcsp_set_voltables();
+#else
+ pcsp.mode = flag ? 1 : 0;
+ else {
+ pcsp.mode = 0;
+ if (flag)
+ return -EINVAL;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * wait until the complete buffers are played or a signal has arrised
+ */
+static void pcsp_sync(void)
+{
+ while (!(current->signal & ~current->blocked) &&
+ (pcsp.in[0] || pcsp.in[1]) ) {
+ /* Wait until a complete block are ready */
+ interruptible_sleep_on(&pcsp_sleep);
+ }
+}
+
+/*
+ * the driver functions
+ */
+static int pcsp_release(struct inode * inode, struct file * file)
+{
+ pcsp_sync();
+ pcsp_stop_timer();
+ outb_p(0xb6,0x43); /* binary, mode 2, LSB/MSB, ch 2 */
+
+ vfree(pcsp.buf[0]);
+ vfree(pcsp.buf[1]);
+
+ pcsp_active = 0;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int pcsp_open(struct inode * inode, struct file * file)
+{
+ int minor = MINOR(inode->i_rdev);
+
+ if (pcsp_active)
+ return -EBUSY;
+
+ switch (minor) {
+ case PCSP_DSP_MINOR:
+ pcsp_set_format(AFMT_U8);
+ break;
+ case PCSP_AUD_MINOR:
+ pcsp_set_format(AFMT_MU_LAW); /* input is ULAW */
+ break;
+#ifdef CONFIG_PCSP_16BIT
+ case PCSP_DSP16_MINOR:
+ if (pcsp_set_format(AFMT_S16_LE) != AFMT_S16_LE)
+ return -ENODEV;
+ break;
+#endif
+ default:
+ return -ENODEV;
+ }
+
+ if (! (pcsp.buf[0] = vmalloc(pcsp.ablk_size)))
+ return -ENOMEM;
+ if (! (pcsp.buf[1] = vmalloc(pcsp.ablk_size))) {
+ vfree(pcsp.buf[0]);
+ return -ENOMEM;
+ }
+
+ pcsp.buffer = pcsp.end = pcsp.buf[0];
+ pcsp.in[0] = pcsp.in[1] = 0;
+ pcsp.timer_on =
+ pcsp.frag_size =
+ pcsp.frag_cnt = 0;
+
+ /* we set 8000 Hz for /dev/audio (ulaw flag set before open) */
+ if (pcsp.is_ulaw)
+ pcsp_calc_srate(PCSP_DEFAULT_RATE);
+
+ pcsp_active = 1;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int pcsp_ioctl_out(unsigned long *ptr, long value)
+{
+ static int error;
+
+ if (value < 0)
+ return value;
+ error = verify_area(VERIFY_WRITE, ptr, sizeof(long));
+ if (error)
+ return error;
+ put_user(value, (long *)ptr);
+ return 0;
+}
+
+
+/*
+ * the new version 2 IOCTL's
+ */
+static int pcsp_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned long ret;
+ unsigned long *ptr = (unsigned long *)arg;
+ int i, error;
+
+#ifdef CONFIG_PCSP_MIXER
+ if (((cmd >> 8) & 0xff) == 'M') /* it's a Mixer IOCTL */
+ return pcsp_mixer_ioctl(inode, file, cmd, arg);
+#endif
+ switch (cmd) {
+ case SNDCTL_DSP_SPEED:
+ error = get_user(arg, ptr);
+ if (error)
+ return error;
+ arg = pcsp_set_speed(arg);
+ arg = pcsp_calc_srate(arg);
+ return pcsp_ioctl_out(ptr, arg);
+
+ case SOUND_PCM_READ_RATE:
+ return pcsp_ioctl_out(ptr, pcsp.srate);
+
+ case SNDCTL_DSP_CHANNELS:
+ error = get_user(arg, ptr);
+ if (error)
+ return error;
+ if (arg < 1 || arg > 2)
+ return -EINVAL;
+ return pcsp_set_stereo(arg - 1);
+
+ case SNDCTL_DSP_STEREO:
+ error = get_user(arg, ptr);
+ if (error)
+ return (error);
+ return pcsp_set_stereo(arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ return pcsp_ioctl_out(ptr, pcsp.mode + 1);
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ return pcsp_ioctl_out(ptr, pcsp.frag_size ?
+ pcsp.frag_size : pcsp.ablk_size);
+
+ case SNDCTL_DSP_SYNC: /* syncing, so speed changes work correct */
+ pcsp_sync();
+ pcsp_stop_timer();
+ return (0);
+
+ case SNDCTL_DSP_RESET: /* stops output immediately */
+ pcsp_stop_timer();
+ pcsp_calc_srate(PCSP_DEFAULT_RATE);
+ return (0);
+
+ case SNDCTL_DSP_GETFMTS:
+ return pcsp_ioctl_out(ptr, pcsp.fmt_msk);
+
+ case SNDCTL_DSP_SETFMT:
+ error = get_user(arg, ptr);
+ if (error)
+ return (error);
+ return pcsp_ioctl_out(ptr, pcsp_set_format(arg));
+
+ case SOUND_PCM_READ_BITS:
+ if (pcsp.audio_fmt == AFMT_MU_LAW)
+ return pcsp_ioctl_out(ptr, AFMT_U8);
+ return pcsp_ioctl_out(ptr, pcsp.audio_fmt);
+
+ /*
+ the following ioctls currently do nothing, but
+ exist for compatibility; however because pcsp's
+ implementation is somewhat strange they are not needed,
+ because pcsp start output after any count of data
+ written to one buffer
+ this may change in the future
+ */
+ case SNDCTL_DSP_SUBDIVIDE:
+ case SNDCTL_DSP_POST:
+ return (0);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ {
+ int fact, bytes, count;
+
+ error = get_user(fact, (int *)ptr);
+ if (error || ! fact)
+ return -EIO;
+
+ /* Too late to change ? */
+ if (pcsp.frag_size || pcsp.frag_cnt)
+ return -EINVAL;
+
+ bytes = fact & 0xffff;
+ count = (fact >> 16) & 0xffff;
+
+ if (bytes < 4 || bytes > 17) /* <16 || > 128k */
+ return -EINVAL;
+
+ if (count < 2)
+ return -EINVAL;
+
+ pcsp.frag_size = (1 << bytes);
+ pcsp.frag_cnt = /*count*/ 2;
+
+ if (pcsp.frag_size > pcsp.ablk_size)
+ pcsp.frag_size = pcsp.ablk_size;
+
+ return pcsp_ioctl_out(ptr, bytes | (count << 16));
+ }
+
+ case PCSP_SET_DEV:
+ error = get_user(arg, ptr);
+ if (error)
+ return (error);
+ switch(arg) {
+ case SNDCARD_STO1:
+ if (stereo1_init() < 0)
+ return (-ENODEV);
+ break;
+ case SNDCARD_PCSP:
+ case SNDCARD_DACM:
+ case SNDCARD_DACS:
+ pcsp.act_dev = arg; break;
+ case SNDCARD_STNC:
+ if (stereo_nc_init() < 0)
+ return (-ENODEV);
+ break;
+ default:
+ return (-ENODEV);
+ }
+ /* Perhaps we need to adjust the samplerate */
+ pcsp.srate = pcsp_set_speed(pcsp.srate);
+ pcsp_calc_srate(pcsp.srate);
+ return (0);
+
+ case PCSP_GET_DEV:
+ return pcsp_ioctl_out(ptr, pcsp.act_dev);
+
+ case PCSP_SET_PORTS:
+ error = get_user(arg, ptr);
+ if (error)
+ return (error);
+ if ((arg & 0xFF) < LP_NO && (arg >> 8) < LP_NO) {
+ if (pcsp.act_dev == SNDCARD_STO1) {
+ if (stereo1_detect(arg & 0xFF)) {
+ pcsp.port = LP_B(arg & 0xFF);
+ return (0);
+ }
+ }
+ else if (pcsp.act_dev == SNDCARD_STNC) {
+ if (stereo_nc_detect(arg & 0xFF)) {
+ pcsp.port = LP_B(arg & 0xFF);
+ return (0);
+ }
+ }
+ else {
+ pcsp.port = LP_B(arg & 0xFF);
+ pcsp.portS = LP_B((arg >> 8) & 0xFF);
+ return (0);
+ }
+ }
+ return (-EINVAL);
+
+ case PCSP_GET_PORTS:
+ ret = 0;
+ for (i = 0; i < LP_NO; ++i)
+ if (LP_B(i) == pcsp.port)
+ ret = i;
+ for (i = 0; i < LP_NO; ++i)
+ if (LP_B(i) == pcsp.portS)
+ ret |= i << 8;
+ return pcsp_ioctl_out(ptr, ret);
+
+ case PCSP_GET_VOL:
+ return pcsp_ioctl_out(ptr, pcsp.volume);
+
+ case PCSP_SET_VOL:
+ error = get_user(pcsp.volume, ptr);
+ if (error)
+ return (error);
+#ifdef CONFIG_PCSP_MIXER
+ arg = MIN(256, pcsp.volume);
+ arg = (arg * 100) / 256;
+ arg = (arg << 8 ) | arg;
+ pcsp_mixer_set(SOUND_MIXER_VOLUME, arg);
+#else
+ pcsp_calc_vol(pcsp.volume);
+#endif
+ return (0);
+
+ case PCSP_GET_SRATE:
+ return pcsp_ioctl_out(ptr, SRATE);
+
+ case PCSP_SET_SRATE:
+ error = get_user(arg, ptr);
+ if (error)
+ return (error);
+ if (arg < 10000 || arg > MAX_SRATE || arg > pcsp.maxrate)
+ return (-EINVAL);
+ pcsp.realrate = (CLOCK_TICK_RATE + arg / 2) / arg;
+ return (0);
+
+ case PCSP_GET_MEASURE:
+ return pcsp_ioctl_out(ptr, pcsp.maxrate);
+
+ case PCSP_SET_EMU_MODE:
+#ifdef CONFIG_PCSP_16BIT
+ error = get_user(arg, ptr);
+ if (error)
+ return (error);
+ if (arg == PCSP_EMULATION_ON) {
+ pcsp.enable_emu = 1;
+ pcsp.fmt_msk |= AFMT_S16_LE;
+ }
+ else if (arg == PCSP_EMULATION_OFF) {
+ pcsp.enable_emu = 0;
+ pcsp.fmt_msk &= ~AFMT_S16_LE;
+ }
+ return pcsp_ioctl_out(ptr, pcsp.enable_emu);
+#endif
+ case PCSP_GET_VERSION:
+ return pcsp_ioctl_out(ptr, SOUND_VERSION);
+
+ default :
+ return (-EINVAL);
+ }
+}
+
+static size_t pcsp_read(struct file * file, char * buffer,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static ssize_t pcsp_write(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+{
+ unsigned long copy_size;
+ unsigned long max_copy_size;
+ unsigned long total_bytes_written = 0;
+ unsigned bytes_written;
+ unsigned char l, r;
+ unsigned char *p;
+ int i, j;
+#ifdef CONFIG_PCSP_16BIT
+ int factor = 1;
+
+#define CNT(x) ((x) * factor)
+#else
+#define CNT(x) (x)
+#endif
+
+#ifdef CONFIG_PCSP_16BIT
+ /* the audio format shouldn't be changed during output */
+ if (pcsp.audio_fmt == AFMT_S16_LE) {
+ count >>= 1;
+ factor <<= 1;
+ }
+ if (pcsp.stereo_emu) {
+ count >>= 1;
+ factor <<= 1;
+ }
+#endif
+
+ max_copy_size = pcsp.frag_size ? pcsp.frag_size : pcsp.ablk_size;
+ do {
+ bytes_written = 0;
+ copy_size = (count <= max_copy_size) ? count : max_copy_size;
+ i = pcsp.in[0] ? 1 : 0;
+ if (copy_size && !pcsp.in[i]) {
+
+#ifdef CONFIG_PCSP_16BIT
+ if (pcsp.audio_fmt == AFMT_S16_LE)
+ if (pcsp.stereo_emu) {
+ p = pcsp.buf[i];
+ if (access_ok(VERIFY_READ, buffer, 4*copy_size))
+ for (j = 0; j < copy_size; ++j) {
+ __get_user(l, &buffer[4*j + 1]);
+ __get_user(r, &buffer[4*j + 3]);
+ *p++ = (left_volS[l ^ 0x80]
+ + right_volS[r ^ 0x80]) >> 1;
+ }
+ }
+ else {
+ p = pcsp.buf[i];
+ if (access_ok(VERIFY_READ, buffer, 2*copy_size))
+ for (j = 0; j < copy_size; ++j) {
+ __get_user(r, &buffer[2*j + 1]);
+ *p++ = r ^ 0x80;
+ }
+ }
+ else if (pcsp.stereo_emu) {
+ p = pcsp.buf[i];
+ if (access_ok(VERIFY_READ, buffer, 2*copy_size))
+ for (j = 0; j < copy_size; ++j) {
+ __get_user(l, &buffer[2*j + 0]);
+ __get_user(r, &buffer[2*j + 1]);
+ *p++ = (left_volS[l] + right_volS[r]) >> 1;
+ }
+ }
+ else
+#endif
+ copy_from_user(pcsp.buf[i], buffer, copy_size);
+ pcsp.in[i] = copy_size;
+ if (! pcsp.timer_on)
+ pcsp_start_timer();
+ bytes_written += copy_size;
+ buffer += copy_size;
+ }
+
+ if (pcsp.in[0] && pcsp.in[1]) {
+ interruptible_sleep_on(&pcsp_sleep);
+ if (current->signal & ~current->blocked) {
+ if (total_bytes_written + bytes_written)
+ return CNT(total_bytes_written + bytes_written);
+ else
+ return -EINTR;
+ }
+ }
+ total_bytes_written += bytes_written;
+ count -= bytes_written;
+
+ } while (count > 0);
+ return CNT(total_bytes_written);
+#undef CNT
+}
+
+struct file_operations pcspeaker_pcsp_fops = {
+ NULL, /* pcsp_seek */
+ pcsp_read,
+ pcsp_write,
+ NULL, /* pcsp_readdir */
+ NULL, /* pcsp_select */
+ pcsp_ioctl, /* pcsp_ioctl */
+ NULL, /* pcsp_mmap */
+ pcsp_open,
+ pcsp_release,
+};
+
+__initfunc(int pcsp_device_init(void))
+{
+ int i;
+
+ if (! pcsp_enabled)
+ return 0;
+
+ /* do we need a first-time initialisation? */
+ if (! pcsp.first_boot)
+ return 0;
+
+ pcsp.first_boot = 0;
+ pcsp.xfer = 0;
+ pcsp_clockticks = pcsp_timer0_latch = pcsp.last_clocks = LATCH;
+ pcsp_active = 0;
+ pcsp_speaker = 0;
+ pcsp.timer_on = 0;
+ pcsp.mode = 0;
+ pcsp.is_ulaw = 0;
+ pcsp.audio_fmt = AFMT_U8;
+#ifdef CONFIG_PCSP_16BIT
+ pcsp.fmt_msk = AFMT_U8 | AFMT_S16_LE;
+#else
+ pcsp.fmt_msk = AFMT_U8;
+#endif
+ pcsp.buffer = pcsp.buf[0];
+ pcsp.in[0] = pcsp.in[1] = 0;
+ pcsp.actual = 0;
+ pcsp.act_dev = SNDCARD_PCSP;
+ pcsp.port = pcsp.portS = 0;
+ pcsp.volume = (CONFIG_PCSP_LEFT + CONFIG_PCSP_RIGHT) * 128/100;
+ pcsp.ablk_size = ABLK_SIZE;
+ pcsp.frag_size = 0;
+ pcsp.frag_cnt = 0;
+ pcsp_calc_srate(PCSP_DEFAULT_RATE);
+ pcsp_calc_vol(pcsp.volume);
+ pcsp_calc_voltab(CONFIG_PCSP_LEFT, left_vol);
+ pcsp_calc_voltab(CONFIG_PCSP_RIGHT, right_vol);
+#ifdef CONFIG_PCSP_16BIT
+ memcpy(left_volS, left_vol, sizeof(left_volS));
+ memcpy(right_volS, right_vol, sizeof(right_volS));
+ pcsp.stereo_emu = 0;
+ pcsp.enable_emu = 1;
+#endif
+#ifndef MODULE
+ printk(" PC-speaker");
+#endif
+ i = stereo1_init();
+ if (i >= 0) {
+#ifndef MODULE
+ printk(", Stereo-on-One at lpt%d", i);
+#endif
+ pcsp.ablk_size = 2 * ABLK_SIZE;
+ }
+ i = stereo_nc_init();
+ if (i >= 0) {
+#ifndef MODULE
+ printk(", New Stereo Circuit at lpt%d", i);
+#endif
+ pcsp.ablk_size = 2 * ABLK_SIZE;
+ }
+ return 0;
+}
+
--- linux/drivers/pcsnd/pcsp.c.orig Tue Nov 4 17:07:06 1997
+++ linux/drivers/pcsnd/pcsp.c Tue Nov 4 15:15:45 1997
@@ -0,0 +1,120 @@
+/*
+ * linux/drivers/pcsnd/pcsp.c
+ *
+ * /dev/pcsp implementation
+ *
+ * Copyright (C) 1993-1997 Michael Beck
+ */
+
+#include <linux/config.h>
+#include <linux/pcsp.h>
+
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+/* 16bit emulation needs the mixer */
+#ifdef CONFIG_PCSP_16BIT
+#define CONFIG_PCSP_MIXER
+#endif
+
+extern struct file_operations pcspeaker_pcsp_fops, pcsp_mixer_fops;
+extern long pcsp_driver_init(long);
+extern int pcsp_set_format(int);
+extern void pcsp_free_ports(void);
+
+static int pcsp_open_dev(struct inode * inode, struct file * file)
+{
+ int minor = MINOR(inode->i_rdev);
+
+ if (! pcsp_enabled)
+ return -ENODEV;
+
+ switch (minor) {
+ case PCSP_DSP_MINOR:
+ case PCSP_AUD_MINOR:
+#ifdef CONFIG_PCSP_16BIT
+ case PCSP_DSP16_MINOR:
+#endif
+ file->f_op = &pcspeaker_pcsp_fops;
+ break;
+#ifdef CONFIG_PCSP_MIXER
+ case PCSP_MIXER_MINOR:
+ file->f_op = &pcsp_mixer_fops;
+ break;
+#endif
+ default:
+ return -ENODEV;
+ }
+ return file->f_op->open(inode,file);
+}
+
+struct file_operations pcsp_fops = {
+ NULL, /* seek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ pcsp_open_dev,
+ NULL /* release */
+};
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+__initfunc(int init_module(void))
+{
+ int minor, major, err;
+
+ if (! pcsp_enabled) {
+ printk("pcsp disabled\n");
+ return -ENODEV;
+ }
+
+ if ((err = register_chrdev(PCSP_MAJOR, "pcsp", &pcsp_fops))) {
+ printk("unable to get major %d for pcsp devices\n", PCSP_MAJOR);
+ return err;
+ }
+
+ major = (SOUND_VERSION >> 8);
+ minor = (SOUND_VERSION & 0xFF);
+ if (! (minor & 0xF))
+ minor >>= 4;
+#ifndef MODULE
+ printk("pcsp %d.%x:", major, minor);
+#endif
+ pcsp_device_init();
+#ifdef CONFIG_PCSP_MIXER
+ pcsp_mixer_init();
+#ifndef MODULE
+ printk(", PCSP-mixer");
+#endif
+#endif
+#ifndef MODULE
+ printk(" loaded\n");
+#endif
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (MOD_IN_USE)
+ printk("pcsnd: busy - remove delayed\n");
+ else {
+ pcsp_free_ports();
+ unregister_chrdev(PCSP_MAJOR, "pcsp");
+ }
+}
+#endif
--- linux/drivers/pcsnd/pcsp_mixer.c.orig Tue Nov 4 17:07:06 1997
+++ linux/drivers/pcsnd/pcsp_mixer.c Tue Nov 4 17:14:10 1997
@@ -0,0 +1,269 @@
+/*
+ * linux/drivers/pcsnd/pcsp_mixer.c
+ *
+ * /dev/pcsp implementation - simple Mixer routines
+ *
+ * (C) 1993-1997 Michael Beck
+ * Craig Metz (cmetz@thor.tjhsst.edu)
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_PCSP_16BIT) || defined(CONFIG_PCSP_MIXER)
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pcsp.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#ifdef MODULE
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define IOCTL_FROM_USER(d, s, o, c) copy_from_user((d), &((s)[o]), (c))
+#define IOCTL_TO_USER(d, o, s, c) copy_to_user(&((d)[o]), (s), (c))
+#define IOCTL_IN(arg, ret) get_user(ret, (unsigned int *) (arg))
+#define IOCTL_OUT(arg, ret) (put_user(ret, (unsigned int *) (arg)), 0)
+#define OFF 0
+
+static int rec_devices = (0); /* No recording source */
+
+static struct {
+ char active;
+} pcmixer;
+
+#define POSSIBLE_RECORDING_DEVICES (0)
+#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_VOLUME)
+
+static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+{
+ (CONFIG_PCSP_RIGHT << 8) + CONFIG_PCSP_LEFT, /* Master Volume */
+ /* The next devices are not supported, so they are zero */
+ 0, /* Bass */
+ 0, /* Treble */
+ 0, /* FM */
+ 0, /* PCM */
+ 0, /* PC Speaker */
+ 0, /* Ext Line */
+ 0, /* Mic */
+ 0, /* CD */
+ 0, /* Recording monitor */
+ 0, /* SB PCM */
+ 0 /* Recording level */
+};
+
+extern void pcsp_set_volume(unsigned short);
+extern unsigned pcsp_get_mode(void);
+
+int pcsp_mixer_set(int whichDev, unsigned int level)
+{
+ int left, right;
+
+ left = level & 0x7f;
+ right = (level & 0x7f00) >> 8;
+
+ switch (whichDev)
+ {
+ case SOUND_MIXER_VOLUME: /* Master volume (0-127) */
+ levels[whichDev] = left | (right << 8);
+ pcsp_set_volume(levels[whichDev]);
+ break;
+
+ default:
+ return (-EINVAL);
+ }
+
+ return (levels[whichDev]);
+}
+
+static int mixer_set_levels(struct sb_mixer_levels *user_l)
+{
+#define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15))
+
+ struct sb_mixer_levels l;
+
+ IOCTL_FROM_USER((char *) &l, (char *) user_l, 0, sizeof (l));
+
+ if (l.master.l & ~0xF || l.master.r & ~0xF
+ || l.line.l & ~0xF || l.line.r & ~0xF
+ || l.voc.l & ~0xF || l.voc.r & ~0xF
+ || l.fm.l & ~0xF || l.fm.r & ~0xF
+ || l.cd.l & ~0xF || l.cd.r & ~0xF
+ || l.mic & ~0x7)
+ return (-EINVAL);
+
+ /* We only set the Master-volume, so the mixer is degenerate */
+ pcsp_mixer_set(SOUND_MIXER_VOLUME, cmix (l.master));
+ return (0);
+}
+
+/* Read the current mixer level settings into the user's struct. */
+static int mixer_get_levels(struct sb_mixer_levels *user_l)
+{
+
+ struct sb_mixer_levels l;
+
+ l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100; /* Master */
+ l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */
+
+ l.line.r = 0; /* Line */
+ l.line.l = 0;
+
+ l.voc.r = 0; /* DAC */
+ l.voc.l = 0;
+
+ l.fm.r = 0; /* FM */
+ l.fm.l = 0;
+
+ l.cd.r = 0; /* CD */
+ l.cd.l = 0;
+
+ l.mic = 0; /* Microphone */
+
+ IOCTL_TO_USER((char *) user_l, 0, (char *) &l, sizeof (l));
+ return (0);
+}
+
+/* Read the current mixer parameters into the user's struct. */
+static int mixer_get_params(struct sb_mixer_params *user_params)
+{
+ struct sb_mixer_params params;
+
+ params.record_source = SRC_MIC;
+ params.hifreq_filter = OFF;
+ params.filter_input = OFF;
+ params.filter_output = OFF;
+ params.dsp_stereo = pcsp_get_mode();
+
+ IOCTL_TO_USER((char *) user_params, 0, (char *) &params, sizeof(params));
+ return (0);
+}
+
+int pcsp_mixer_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ {
+ IOCTL_IN(arg, ret);
+ return IOCTL_OUT(arg, pcsp_mixer_set(cmd & 0xff, ret));
+ }
+ else
+ { /* Read parameters */
+
+ switch (cmd & 0xff)
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT(arg, rec_devices);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT(arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT(arg, SUPPORTED_MIXER_DEVICES);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT(arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ case SOUND_MIXER_MUTE:
+ case SOUND_MIXER_ENHANCE:
+ case SOUND_MIXER_LOUD:
+ return IOCTL_OUT(arg, 0);
+ break;
+
+
+ default:
+ return IOCTL_OUT(arg, levels[cmd & 0xff]);
+ }
+ }
+ }
+ else
+ {
+ switch (cmd)
+ {
+ case MIXER_IOCTL_SET_LEVELS:
+ mixer_set_levels((struct sb_mixer_levels *) arg);
+ return mixer_get_levels((struct sb_mixer_levels *) arg);
+ case MIXER_IOCTL_SET_PARAMS:
+ return mixer_get_params((struct sb_mixer_params *) arg);
+ case MIXER_IOCTL_READ_LEVELS:
+ return mixer_get_levels((struct sb_mixer_levels *) arg);
+ case MIXER_IOCTL_READ_PARAMS:
+ return mixer_get_params((struct sb_mixer_params *) arg);
+ case MIXER_IOCTL_RESET:
+ pcsp_mixer_set(SOUND_MIXER_VOLUME, levels[SOUND_MIXER_VOLUME]);
+ return (0);
+ default:
+ return (-EINVAL);
+ }
+ }
+ return (-EINVAL);
+}
+
+static int pcsp_mixer_release(struct inode * inode, struct file * file)
+{
+ --pcmixer.active;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int pcsp_mixer_open(struct inode * inode, struct file * file)
+{
+ if (pcmixer.active)
+ return (-EBUSY);
+ ++pcmixer.active;
+ MOD_INC_USE_COUNT;
+ return (0);
+}
+
+static ssize_t pcsp_mixer_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
+{
+ return (-EINVAL);
+}
+
+static ssize_t pcsp_mixer_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+{
+ return (-EINVAL);
+}
+
+struct file_operations pcsp_mixer_fops = {
+ NULL, /* pcsp_seek */
+ pcsp_mixer_read,
+ pcsp_mixer_write,
+ NULL, /* pcsp_readdir */
+ NULL, /* pcsp_select */
+ pcsp_mixer_ioctl,
+ NULL, /* pcsp_mmap */
+ pcsp_mixer_open,
+ pcsp_mixer_release,
+};
+
+__initfunc(int pcsp_mixer_init(void))
+{
+ pcsp_mixer_set(SOUND_MIXER_VOLUME, levels[SOUND_MIXER_VOLUME]);
+ pcmixer.active = 0;
+ return 0;
+}
+
+#endif
--- linux/drivers/pcsnd/pcsp_stub.c.orig Tue Nov 4 17:07:06 1997
+++ linux/drivers/pcsnd/pcsp_stub.c Tue Nov 4 15:15:45 1997
@@ -0,0 +1,313 @@
+/*
+ * linux/drivers/pcsnd/pcsp_stub.c
+ *
+ * /dev/pcsp implementation
+ *
+ * Copyright (C) 1993-1997 Michael Beck
+ *
+ * if PCSP is compiled as a module, this part must
+ * be linked with the kernel
+ */
+
+#include <linux/config.h>
+#include <linux/pcsp.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+/*
+ * need this macros
+ */
+#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
+#define MAX(a,b) ( ((a) > (b)) ? (a) : (b) )
+
+/*
+ * need this to be global
+ */
+char pcsp_active = 0;
+char pcsp_speaker = 0;
+char pcsp_enabled = -1;
+volatile int pcsp_timer0_latch, pcsp_clockticks;
+volatile int pcsp_test_running;
+
+struct pcsp_status pcsp;
+
+extern struct file_operations pcsp_fops;
+
+
+#ifndef CONFIG_PCSP_NO_TEST_SPEED
+
+static void *sleep = NULL;
+
+/*
+ this is a stupid beep which occurs if PCSP is disabled;
+ it's not needed because we have the message, but who reads it...
+ and this is the PC-Speaker driver :-)
+*/
+__initfunc(static void pcsp_beep(int count, int cycles))
+{
+ /* enable counter 2 */
+ outb_p(inb_p(0x61)|3, 0x61);
+ /* set command for counter 2, 2 byte write */
+ outb_p(0xB6, 0x43);
+ /* select desired HZ */
+ outb_p(count & 0xff, 0x42);
+ outb((count >> 8) & 0xff, 0x42);
+
+ while (cycles--);
+
+ /* disable counter 2 */
+ outb(inb_p(0x61)&0xFC, 0x61);
+}
+
+/*
+ the timer-int for testing cpu-speed, mostly the same as
+ for PC-Speaker
+ */
+__initfunc(static int pcsp_test_intspeed(void))
+{
+ if (pcsp.index < pcsp.in[pcsp.actual]) {
+ outb(pcsp.e, 0x61);
+ outb(pcsp.e ^ 1, 0x61);
+ outb(pcsp.buffer[pcsp.buffer[pcsp.index]], 0x42);
+
+ pcsp.xfer += pcsp.si;
+ pcsp.index = pcsp.xfer >> 16;
+ }
+ if (pcsp.index >= pcsp.in[pcsp.actual]) {
+ pcsp.xfer = pcsp.index = 0;
+ pcsp.in[pcsp.actual] = 0;
+ pcsp.actual ^= 1;
+ pcsp.buffer = pcsp.buf[pcsp.actual];
+ if (sleep) /* NEVER */
+ nop();
+ if (pcsp.in[pcsp.actual] == 0xFFFF)
+ pcsp.actual ^= 1;
+ }
+
+ if ( (pcsp_clockticks -= pcsp.timerCF) < 0)
+ pcsp_clockticks += LATCH;
+ ++pcsp_test_running;
+ return 1;
+}
+
+/*
+ this routine measures the time needed for one timer-int if
+ we play thru PC-Speaker. This is kind of ugly but does the
+ trick.
+ */
+__initfunc(static int pcsp_measurement(unsigned char *buf, int addon))
+{
+ int count;
+ unsigned long flags;
+
+ pcsp_clockticks = 0;
+ pcsp.timerCF = LATCH;
+ pcsp.buf[0] =
+ pcsp.buffer = buf;
+ pcsp.index = 0;
+ pcsp.xfer = 0;
+ pcsp.si = 1 << 16;
+ pcsp.in[0] = 5 + addon;
+ pcsp.in[1] = 0;
+ pcsp.actual = 0;
+ pcsp.e = inb(0x61) & 0xFC;
+
+ pcsp_test_running = 0;
+
+ if (pcsp_set_irq(pcsp_test_intspeed) < 0)
+ panic("PCSP could not modify timer IRQ!");
+
+ /*
+ Currently (0.99.15d) Linux call chr_dev_init with ints
+ disabled; so we need a sti() to enable them.
+ However, because this can be changed in the future we use
+ save_flags() and restore_flags()
+ */
+ save_flags(flags);
+ sti();
+
+ /*
+ Perhaps we need some sort of timeout here, but if IRQ0
+ isn't working the system hangs later ...
+ */
+ while (pcsp_test_running < 5);
+ restore_flags(flags);
+
+ if (pcsp_release_irq() < 0)
+ panic("PCSP could not reset timer IRQ!");
+
+ outb_p(0x00, 0x43); /* latch the count ASAP */
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+ return (LATCH - count);
+}
+
+__initfunc(static int pcsp_test_speed(void))
+{
+ int worst, worst1, best, best1;
+ unsigned char test_buffer[32];
+
+ worst = pcsp_measurement(test_buffer, 0);
+ worst1 = pcsp_measurement(test_buffer, 0);
+ best = pcsp_measurement(test_buffer, 5);
+ best1 = pcsp_measurement(test_buffer, 5);
+
+ worst = MAX(worst, worst1);
+ best = MIN(best, best1);
+
+#ifdef PCSP_DEBUG
+ printk(" PCSP-Timerint needs %d Ticks in worst case\n", worst);
+ printk(" PCSP-Timerint needs %d Ticks in best case\n", best);
+#endif
+ /* We allow a CPU-usage of 90 % for the best-case ! */
+ pcsp.realrate = best * 10 / 9;
+ pcsp.maxrate = CLOCK_TICK_RATE / pcsp.realrate;
+ printk(" maximal samplerate %d Hz", pcsp.maxrate);
+
+ if (pcsp.maxrate > PCSP_CRITICAL_FREQ) {
+ if (MIN_CONST > pcsp.realrate) {
+ pcsp.realrate = MIN_CONST;
+ printk(", %d Hz", MAX_SRATE);
+ }
+ printk(" used\n");
+ return 1;
+ }
+
+ printk("\n This is too SLOW! PCSP-driver DISABLED\n");
+
+ /* very ugly beep, but you hopefully never hear it */
+ pcsp_beep(12000,800000);
+ pcsp_beep(10000,800000);
+
+ return 0;
+}
+#endif
+
+__initfunc(void pcsp_setup(char *s, int *p))
+{
+ if (!strcmp(s, "off")) {
+ pcsp_enabled = 0;
+ return;
+ }
+ if (p[0] > 0 && p[1] > 0)
+ pcsp.maxrate = p[1];
+ pcsp_enabled = 1;
+}
+
+__initfunc(void pcsp_driver_init(void))
+{
+ if (pcsp_enabled < 0) {
+#ifndef CONFIG_PCSP_NO_TEST_SPEED
+ pcsp_enabled = pcsp_test_speed();
+#else
+ pcsp.maxrate = 44100; /* only a BIG freq */
+ pcsp.realrate = (CLOCK_TICK_RATE + CONFIG_PCSP_SRATE / 2) /
+ CONFIG_PCSP_SRATE;
+ pcsp_enabled = 1;
+#endif
+ }
+ else {
+ pcsp.realrate = MIN(pcsp.maxrate, MAX_SRATE);
+ pcsp.realrate = (CLOCK_TICK_RATE + pcsp.realrate / 2) /
+ pcsp.realrate;
+ }
+}
+
+extern int pcsp_set_irq(int (*func)(void));
+extern int pcsp_release_irq(void);
+
+EXPORT_SYMBOL(pcsp_timer0_latch);
+EXPORT_SYMBOL(pcsp_clockticks);
+#ifdef CONFIG_PCSP_MODULE
+EXPORT_SYMBOL(pcsp_enabled);
+EXPORT_SYMBOL(pcsp_active);
+EXPORT_SYMBOL(pcsp_speaker);
+EXPORT_SYMBOL(pcsp);
+EXPORT_SYMBOL(pcsp_set_irq);
+EXPORT_SYMBOL(pcsp_release_irq);
+#endif
+
+/*
+ * If your kernel is less than 1.3.33, pcsp must take and return the
+ * kmem_start argument that used to be passed to initializing drivers.
+ */
+#if LINUX_VERSION < (1*65536 + 3*256 + 33*1)
+#define init_t long
+#define init_args long kmem_start
+#define init_retval kmem_start
+#else
+#define init_t int
+#define init_args void
+#define init_retval 0
+#endif
+
+/*
+ * the pcsp_init() function is called in chrdev_init at kernel startup
+ */
+#ifndef CONFIG_PCSP_MODULE
+__initfunc(init_t pcsp_init(init_args))
+{
+ int minor, major;
+
+ /* if disabled in commandline */
+ if (! pcsp_enabled) {
+ printk("PCSP-device disabled\n");
+ return init_retval;
+ }
+
+ /* first time pcsp is loaded */
+ pcsp.first_boot = 1;
+
+ if (register_chrdev(PCSP_MAJOR, "pcsp", &pcsp_fops)) {
+ printk("unable to get major %d for PCSP-devices\n", PCSP_MAJOR);
+ return init_retval;
+ }
+ major = (SOUND_VERSION >> 8);
+ minor = (SOUND_VERSION & 0xFF);
+ if (! (minor & 0xF))
+ minor >>= 4;
+ printk("PCSP %d.%x measurement:", major, minor);
+ pcsp_driver_init();
+ if (pcsp_enabled) {
+ printk("PCSP %d.%x:", major, minor);
+ pcsp_device_init();
+#if defined(CONFIG_PCSP_16BIT) || defined(CONFIG_PCSP_MIXER)
+ pcsp_mixer_init();
+ printk(", PCSP-mixer");
+#endif
+ printk(" installed\n");
+ }
+ return init_retval;
+}
+
+#else
+
+/*
+ * this pcsp_init() function is called when the driver is loaded as a module
+ * at kernel-startup
+ */
+__initfunc(init_t pcsp_init(init_args))
+{
+ int minor, major;
+
+ /* first time pcsp is loaded */
+ pcsp.first_boot = 1;
+
+ major = (SOUND_VERSION >> 8);
+ minor = (SOUND_VERSION & 0xFF);
+ if (! (minor & 0xF))
+ minor >>= 4;
+ printk("PCSP %d.%x measurement:", major, minor);
+ pcsp_driver_init();
+ return init_retval;
+}
+#endif
--- linux/drivers/pcsnd/tables.h.orig Tue Nov 4 17:07:20 1997
+++ linux/drivers/pcsnd/tables.h Fri Apr 12 22:46:51 1996
@@ -0,0 +1,81 @@
+/*
+ * linux/drivers/pcsnd/tables.h
+ *
+ * /dev/pcsp implementation
+ *
+ * Copyright (C) 1993 Michael Beck
+ */
+
+/* thanks to Mark J. Cox for his kindly permission
+ to use the following PC-Speaker table */
+
+static unsigned char sp_tab[] = {
+ 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62,
+ 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 56, 56, 56, 56, 56, 56, 56,
+ 56, 55, 55, 55, 55, 55, 54, 54,
+ 54, 54, 53, 53, 53, 53, 52, 52,
+ 52, 51, 51, 50, 50, 49, 49, 48,
+ 48, 47, 46, 45, 44, 43, 42, 41,
+ 40, 39, 38, 37, 36, 35, 34, 33,
+ 32, 31, 30, 29, 28, 27, 26, 25,
+ 24, 23, 22, 21, 20, 19, 18, 17,
+ 17, 16, 16, 15, 15, 14, 14, 13,
+ 13, 13, 12, 12, 12, 12, 11, 11,
+ 11, 11, 10, 10, 10, 10, 10, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 7, 7, 7, 7,
+ 7, 7, 7, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+static unsigned char ulaw[] = {
+ 3, 7, 11, 15, 19, 23, 27, 31,
+ 35, 39, 43, 47, 51, 55, 59, 63,
+ 66, 68, 70, 72, 74, 76, 78, 80,
+ 82, 84, 86, 88, 90, 92, 94, 96,
+ 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113,
+ 113, 114, 114, 115, 115, 116, 116, 117,
+ 117, 118, 118, 119, 119, 120, 120, 121,
+ 121, 121, 122, 122, 122, 122, 123, 123,
+ 123, 123, 124, 124, 124, 124, 125, 125,
+ 125, 125, 125, 125, 126, 126, 126, 126,
+ 126, 126, 126, 126, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 253, 249, 245, 241, 237, 233, 229, 225,
+ 221, 217, 213, 209, 205, 201, 197, 193,
+ 190, 188, 186, 184, 182, 180, 178, 176,
+ 174, 172, 170, 168, 166, 164, 162, 160,
+ 158, 157, 156, 155, 154, 153, 152, 151,
+ 150, 149, 148, 147, 146, 145, 144, 143,
+ 143, 142, 142, 141, 141, 140, 140, 139,
+ 139, 138, 138, 137, 137, 136, 136, 135,
+ 135, 135, 134, 134, 134, 134, 133, 133,
+ 133, 133, 132, 132, 132, 132, 131, 131,
+ 131, 131, 131, 131, 130, 130, 130, 130,
+ 130, 130, 130, 130, 129, 129, 129, 129,
+ 129, 129, 129, 129, 129, 129, 129, 129,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128
+};
+
--- linux/drivers/pcsnd/Makefile.orig Tue Nov 4 17:07:20 1997
+++ linux/drivers/pcsnd/Makefile Wed Jun 19 19:05:03 1996
@@ -0,0 +1,27 @@
+#
+# Makefile for the PCSP device driver.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+L_TARGET := pcsp.a
+LX_OBJS := pcsp_stub.o
+
+ifeq ($(CONFIG_PCSP),y)
+L_OBJS := pcsp.o pcsndriv.o pcsp_mixer.o
+else
+M_OBJS := pcsnd.o
+endif
+
+include $(TOPDIR)/Rules.make
+
+config:
+ @./pcspinstall
+
+pcsnd.o: pcsp.o pcsndriv.o pcsp_mixer.o
+ $(LD) -r -o pcsnd.o pcsp.o pcsndriv.o pcsp_mixer.o
--- linux/drivers/pcsnd/config.in.orig Tue Nov 4 17:07:20 1997
+++ linux/drivers/pcsnd/config.in Tue Aug 19 22:14:36 1997
@@ -0,0 +1,13 @@
+bool 'Disable automatic speed detection' CONFIG_PCSP_NO_TEST_SPEED
+if [ "$CONFIG_PCSP_NO_TEST_SPEED" = "y" ] ; then
+int 'Enter a samplerate for PCSP [12000-18356]' CONFIG_PCSP_SRATE 18356
+fi
+
+bool 'Enable 16bit stereo emulation support' CONFIG_PCSP_16BIT
+if [ "$CONFIG_PCSP_16BIT" = "n" ] ; then
+bool 'Enable /dev/mixer simulation' CONFIG_PCSP_MIXER
+fi
+
+int 'Left volume at startup [0-100]' CONFIG_PCSP_LEFT 100
+int 'Right volume at startup [0-100]' CONFIG_PCSP_RIGHT 100
+
--- linux/drivers/pcsnd/README.orig Tue Nov 4 17:07:28 1997
+++ linux/drivers/pcsnd/README Sat Aug 23 12:08:34 1997
@@ -0,0 +1,59 @@
+Installing and compiling the driver version 1.2
+------------------------------------------------
+
+0) Install the kernel sources (2.0.x or 2.1.x)
+ and the pcsndrv-1.2.tgz (You have already done this).
+
+1) Apply the patch (linux-x.x.x.pcsp.diff) in the /usr/src directory
+ by patch -p0 < linux-x.x.x.pcsp.diff
+ This is needed even if you plan to compile the driver as a module!
+ If your kernel-version differs from 2.0.30 or 2.1.50 test this:
+ main.c : the pcsp_setup entry
+ sched.c : remove "static" in the definition of do_timer
+ irq.c : added some stuff at end,
+ #include <linux/config.h>
+ mem.c : include mem_start = pcsp_init(mem_start);
+ and the extern long pcsp... definition
+ vt.c : kd_mksound and kd_nosound must begin with
+ if (pcsp_speaker)
+ return;
+ #include <linux/config.h>
+
+3) Run "make config", "make menuconfig" or "make xconfig"
+ in the Linux directory, and enable the 'PC-Speaker...' Support.
+ Normally you will also enable the 16bit emulation.
+
+------->NOTE: This is NOT a replacement for the USS (the real sounddriver).
+ So don't select 'Sound card support' if you don't have a
+ Soundcard.
+ Select only 'PC-Speaker and DAC driver support' !!!
+
+4) Recompile the kernel.
+
+5) Run the 'pcspinstall' script from this directory.
+
+6) You may want to compile the PCSP configuration utility pcsel
+ and the new version of vplay. Do to this, go to the
+ pcsnd-kit directory (usually under /usr/src) and make a
+ "make install".
+
+7) Don't use this version of the driver on SMP kernels unless
+ the know what you are doing! There is some support, but it's
+ poorly tested.
+
+To build the device files simply run the shell script pcspinstall
+in this directory. It creates:
+
+ /dev/pcsp (and a symbolic link /dev/dsp if you don't have the
+ sound-driver installed)
+ /dev/pcaudio (and a symbolic link /dev/audio ...)
+ /dev/pcmixer (and a symbolic link /dev/mixer ...)
+
+ <sys/soundcard.h> (if no sound-driver ...)
+ <sys/pcsp.h> these only consist of
+ #include <linux/pcsp.h>
+
+Feel free to contact me (flames about my english and the useless of this
+driver will be redirected to /dev/null, oh no, it's full...).
+
+Michael Beck beck@dgroup.de
--- linux/drivers/pcsnd/COPYING.orig Tue Nov 4 17:07:31 1997
+++ linux/drivers/pcsnd/COPYING Thu May 4 19:21:49 1995
@@ -0,0 +1,340 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, 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.
+
+ <signature of Ty Coon>, 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.
--- linux/drivers/Makefile.orig Fri Oct 24 00:08:21 1997
+++ linux/drivers/Makefile Tue Nov 4 15:17:57 1997
@@ -9,7 +9,7 @@

SUB_DIRS := block char net misc #streams
MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp macintosh video
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound pcsnd cdrom isdn pnp macintosh video

ifdef CONFIG_PCI
SUB_DIRS += pci
@@ -45,6 +45,13 @@
else
ifeq ($(CONFIG_SOUND),m)
MOD_SUB_DIRS += sound
+ endif
+endif
+
+ifdef CONFIG_PCSP
+SUB_DIRS += pcsnd
+ ifeq ($(CONFIG_PCSP),m)
+ MOD_SUB_DIRS += pcsnd
endif
endif

--- linux/init/main.c.orig Tue Nov 4 01:48:01 1997
+++ linux/init/main.c Tue Nov 4 15:15:44 1997
@@ -196,6 +196,9 @@
#ifdef CONFIG_ISDN_DRV_PCBIT
extern void pcbit_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_PCSP
+extern void pcsp_setup(char *str, int *ints);
+#endif

#ifdef CONFIG_ATARIMOUSE
extern void atari_mouse_setup (char *str, int *ints);
@@ -606,6 +609,9 @@
#endif CONFIG_ISP16_CDI
#ifdef CONFIG_SOUND
{ "sound=", sound_setup },
+#endif
+#ifdef CONFIG_PCSP
+ { "pcsp=", pcsp_setup },
#endif
#ifdef CONFIG_ISDN_DRV_ICN
{ "icn=", icn_setup },
--- linux/Makefile.orig Fri Oct 31 22:04:04 1997
+++ linux/Makefile Tue Nov 4 15:37:04 1997
@@ -11,7 +11,7 @@
#
# NOTE! SMP is experimental. See the file Documentation/SMP.txt
#
-# SMP = 1
+SMP = 1
#
# SMP profiling options
# SMP_PROF = 1
@@ -38,7 +38,7 @@
AR =$(CROSS_COMPILE)ar
NM =$(CROSS_COMPILE)nm
STRIP =$(CROSS_COMPILE)strip
-MAKE =make
+MAKE =make -j3
GENKSYMS=/sbin/genksyms

all: do-it-all
@@ -146,6 +146,10 @@

ifeq ($(CONFIG_SOUND),y)
DRIVERS := $(DRIVERS) drivers/sound/sound.a
+endif
+
+ifdef CONFIG_PCSP
+DRIVERS := $(DRIVERS) drivers/pcsnd/pcsp.a
endif

ifdef CONFIG_PCI

--==_Exmh_-8347387360
Content-Type: text/plain ; name="quota-vger-2.1.61.diff"; charset=us-ascii
Content-Description: quota-vger-2.1.61.diff
Content-Disposition: attachment; filename="quota-vger-2.1.61.diff"

--- linux/fs/dquot.c.orig Fri Oct 24 00:56:19 1997
+++ linux/fs/dquot.c Tue Nov 4 17:32:21 1997
@@ -221,6 +221,7 @@
short type;
struct file *filp;
mm_segment_t fs;
+ loff_t offset;

type = dquot->dq_type;
filp = dquot->dq_mnt->mnt_dquot.files[type];
@@ -230,19 +231,12 @@

lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_dquot.semaphore);
- if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp, dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
- up(&dquot->dq_mnt->mnt_dquot.semaphore);
- unlock_dquot(dquot);
- return;
- }
- } else
- filp->f_pos = dqoff(dquot->dq_id);

+ offset = dqoff(dquot->dq_id);
fs = get_fs();
set_fs(KERNEL_DS);

- if (filp->f_op->write(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
+ if (filp->f_op->write(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset) == sizeof(struct dqblk))
dquot->dq_flags &= ~DQ_MOD;

up(&dquot->dq_mnt->mnt_dquot.semaphore);
@@ -257,6 +251,7 @@
short type;
struct file *filp;
mm_segment_t fs;
+ loff_t offset;

type = dquot->dq_type;
filp = dquot->dq_mnt->mnt_dquot.files[type];
@@ -266,18 +261,11 @@

lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_dquot.semaphore);
- if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp, dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
- up(&dquot->dq_mnt->mnt_dquot.semaphore);
- unlock_dquot(dquot);
- return;
- }
- } else
- filp->f_pos = dqoff(dquot->dq_id);

+ offset = dqoff(dquot->dq_id);
fs = get_fs();
set_fs(KERNEL_DS);
- filp->f_op->read(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+ filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
up(&dquot->dq_mnt->mnt_dquot.semaphore);
set_fs(fs);

--==_Exmh_-8347387360--