diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1994-01-21 13:59:51 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:28 -0400 |
commit | 5ba11befea43b83546e0cefa25f2551a7bd17e07 (patch) | |
tree | 42973c35cb5d9758404c146edfd210411cde3b9a | |
parent | c5002faf69a59a022ae0d51a35e4836858fea1d0 (diff) | |
download | archive-5ba11befea43b83546e0cefa25f2551a7bd17e07.tar.gz |
ALPHA-pl14t
46 files changed, 1611 insertions, 560 deletions
@@ -1,6 +1,6 @@ VERSION = 0.99 PATCHLEVEL = 14 -ALPHA = r +ALPHA = t all: Version zImage @@ -115,6 +115,10 @@ bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n +bool 'QIC-117 tape support' CONFIG_FTAPE n +if [ "$CONFIG_FTAPE" = "y" ] +int ' number of ftape buffers' NR_FTAPE_BUFFERS 3 +fi * * Sound * diff --git a/drivers/block/README.sbpcd b/drivers/block/README.sbpcd new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/drivers/block/README.sbpcd diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 4391cc3..c26348f 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -227,8 +227,8 @@ static void reset_controller(void) { int i; - printk("HD-controller reset\n"); - outb(4,HD_CMD); + printk(KERN_DEBUG "HD-controller reset\n"); + outb_p(4,HD_CMD); for(i = 0; i < 1000; i++) nop(); outb(hd_info[0].ctl & 0x0f ,HD_CMD); if (drive_busy()) @@ -269,7 +269,7 @@ repeat: void unexpected_hd_interrupt(void) { sti(); - printk("Unexpected HD interrupt\n"); + printk(KERN_DEBUG "Unexpected HD interrupt\n"); SET_TIMER; } @@ -421,7 +421,7 @@ static void hd_times_out(void) reset = 1; if (!CURRENT) return; - printk("HD timeout\n"); + printk(KERN_DEBUG "HD timeout\n"); cli(); if (++CURRENT->errors >= MAX_ERRORS) { #ifdef DEBUG diff --git a/drivers/block/sbpcd.c b/drivers/block/sbpcd.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/drivers/block/sbpcd.c diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c index 350e557..9b9f114 100644 --- a/drivers/char/atixlmouse.c +++ b/drivers/char/atixlmouse.c @@ -4,6 +4,8 @@ * * Uses VFS interface for linux 0.98 (01OCT92) * + * Modified by Chris Colohan (colohan@eecg.toronto.edu) + * * version 0.3 */ @@ -52,8 +54,8 @@ /* Same general mouse structure */ static struct mouse_status { - unsigned char buttons; - unsigned char latch_buttons; + char buttons; + char latch_buttons; int dx; int dy; int present; @@ -64,16 +66,23 @@ static struct mouse_status { void mouse_interrupt(int unused) { + char dx, dy, buttons; + ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */ outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */ - mouse.dx += inb( ATIXL_MSE_DATA_PORT); + dx = inb( ATIXL_MSE_DATA_PORT); outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */ - mouse.dy += inb( ATIXL_MSE_DATA_PORT); + dy = inb( ATIXL_MSE_DATA_PORT); outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */ - mouse.latch_buttons |= inb(ATIXL_MSE_DATA_PORT); + buttons = inb( ATIXL_MSE_DATA_PORT); + if (dx != 0 || dy != 0 || buttons != mouse.latch_buttons) { + mouse.latch_buttons |= buttons; + mouse.dx += dx; + mouse.dy += dy; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + } ATIXL_MSE_ENABLE_UPDATE(); - mouse.ready = 1; - wake_up_interruptible(&mouse.wait); } static void release_mouse(struct inode * inode, struct file * file) @@ -112,21 +121,33 @@ static int write_mouse(struct inode * inode, struct file * file, char * buffer, static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) { + int i; + if (count < 3) return -EINVAL; if (!mouse.ready) return -EAGAIN; ATIXL_MSE_DISABLE_UPDATE(); /* Allowed interrupts to occur during data gathering - shouldn't hurt */ - put_fs_byte((~mouse.latch_buttons & 7) | 0x80 , buffer); - put_fs_byte(mouse.dx, buffer + 1); - put_fs_byte(-mouse.dy, buffer + 2); + put_fs_byte((char)(~mouse.latch_buttons&7) | 0x80 , buffer); + if (mouse.dx < -127) + mouse.dx = -127; + if (mouse.dx > 127) + mouse.dx = 127; + put_fs_byte((char)mouse.dx, buffer + 1); + if (mouse.dy < -127) + mouse.dy = -127; + if (mouse.dy > 127) + mouse.dy = 127; + put_fs_byte((char)-mouse.dy, buffer + 2); + for(i = 3; i < count; i++) + put_fs_byte(0x00, buffer + i); mouse.dx = 0; mouse.dy = 0; mouse.latch_buttons = mouse.buttons; mouse.ready = 0; ATIXL_MSE_ENABLE_UPDATE(); - return 3; /* 3 data bytes returned */ + return i; /* i data bytes returned */ } static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) diff --git a/drivers/char/kbd_kern.h b/drivers/char/kbd_kern.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/drivers/char/kbd_kern.h diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 8a74b8f..7fa9dee 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -387,6 +387,10 @@ static struct file_operations memory_fops = { NULL /* fsync */ }; +#ifdef CONFIG_FTAPE +char* ftape_big_buffer; +#endif + long chr_dev_init(long mem_start, long mem_end) { if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) @@ -406,5 +410,15 @@ long chr_dev_init(long mem_start, long mem_end) #if CONFIG_TAPE_QIC02 mem_start = tape_qic02_init(mem_start); #endif +/* + * Rude way to allocate kernel memory buffer for tape device + */ +#ifdef CONFIG_FTAPE + /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */ + ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff); + printk( "ftape: allocated %d buffers alligned at: %p\n", + NR_FTAPE_BUFFERS, ftape_big_buffer); + mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000; +#endif return mem_start; } diff --git a/drivers/char/serial.c b/drivers/char/serial.c index c25c17b..ffb7f93 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -492,6 +492,7 @@ static void rs_interrupt(int irq) pass_number = 0; while (info) { if (info->tty && + info->tty->termios && (!pass_number || !(serial_inp(info, UART_IIR) & UART_IIR_NO_INT))) { done = 0; @@ -1489,7 +1490,24 @@ static void rs_close(struct tty_struct *tty, struct file * filp) #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, info->count); #endif - if (--info->count > 0) + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) return; info->flags |= ASYNC_CLOSING; /* @@ -1502,8 +1520,16 @@ static void rs_close(struct tty_struct *tty, struct file * filp) info->callout_termios = *tty->termios; tty->stopped = 0; /* Force flush to succeed */ tty->hw_stopped = 0; - rs_start(tty); - wait_until_sent(tty); + if (info->flags & ASYNC_INITIALIZED) { + rs_start(tty); + /* + * XXX There should be a timeout added to + * wait_until_sent, eventually. TYT 1/19/94 + */ + wait_until_sent(tty); + } else + flush_output(tty); + flush_input(tty); cli(); /* * Make sure the UART transmitter has completely drained; this @@ -1517,7 +1543,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info, 1); clear_bit(line, rs_event); info->event = 0; - info->count = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { @@ -1574,7 +1599,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if (info->flags & ASYNC_CLOSING) { interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else return -EAGAIN; +#endif } /* @@ -1632,7 +1664,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else retval = -EAGAIN; +#endif break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 77fb28a..c07c194 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1430,6 +1430,15 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se printk("tty_select: tty struct for dev %d was NULL\n", dev); return 0; } + if (ldiscs[tty->disc].select) + return (ldiscs[tty->disc].select)(tty, inode, filp, + sel_type, wait); + return 0; +} + +static int normal_select(struct tty_struct * tty, struct inode * inode, + struct file * file, int sel_type, select_table *wait) +{ switch (sel_type) { case SEL_IN: if (L_CANON(tty)) { @@ -1681,6 +1690,7 @@ static struct tty_ldisc tty_ldisc_N_TTY = { read_chan, /* read */ write_chan, /* write */ NULL, /* ioctl */ + normal_select, /* select */ copy_to_cooked /* handler */ }; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 2753824..2f3ea0d 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -1200,6 +1200,7 @@ slip_init(struct device *dev) sl_ldisc.write = NULL; sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long)) slip_ioctl; + sl_ldisc.select = NULL; sl_ldisc.handler = slip_recv; if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) printk("ERROR: %d\n", i); diff --git a/drivers/sound/.indent.pro b/drivers/sound/.indent.pro index f10c3dd..4668655 100644 --- a/drivers/sound/.indent.pro +++ b/drivers/sound/.indent.pro @@ -1,9 +1,6 @@ -bad -bap --fca --fc1 --cdb --sc +-nfca -bl -psl -di16 diff --git a/drivers/sound/CHANGELOG b/drivers/sound/CHANGELOG index 6839b1e..78168dd 100644 --- a/drivers/sound/CHANGELOG +++ b/drivers/sound/CHANGELOG @@ -1,6 +1,16 @@ -Changelog for version 2.3 +Changelog for version 2.4 ------------------------- +Since 2.3b +- Fixed bug which made it impossible to make long recordings to disk. + Recording was not restarted after a buffer overflow situation. +- Limited mixer support for GUS. +- Numerous improvements to the GUS driver by Andrew Robinson. Including + some click removal etc. + +Since 2.3 +- Fixed some minor bugs in the SB16 driver. + Since 2.2b - Full SB16 DSP support. 8/16 bit, mono/stereo - The SCO and FreeBSD versions should be in sync now. There are some diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index d8518d7..dcf00d5 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -5,7 +5,7 @@ # # -VERSION = 2.3b +VERSION = 2.4 TARGET_OS = linux .c.s: diff --git a/drivers/sound/Readme b/drivers/sound/Readme index 452733f..bd47ede 100644 --- a/drivers/sound/Readme +++ b/drivers/sound/Readme @@ -1,32 +1,30 @@ -Release notes for the Linux Sound Driver 2.3 ------------------------------------------------ - -This version has finally the SB16 support. It seems to work -well but there is some problems with recording. If the recording -process cannot read the data from the device fast enough the -driver will return EIO. Usually this happens when there is no more -memory for the disk buffers. -The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de). -Currently the SB16 support is an ALPHA test version since it has been -tested just by me. +Release notes for the Linux Sound Driver 2.4 +-------------------------------------------- + +NOTE! The sound driver is a part of the Linux kernel distribution also. + Check that your kernel doesn't have more recent version than this + when installing a separately distributed sound driver. The + version number of this driver is defined in the makefile. +This version contains a driver for the SB16 also. The SB16 driver requires separate DMA channels for the 8 and 16 bit modes. There should be a way to share the 8 bit DMA channels between these modes but this feature is not supported yet. +The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de). The SB16 driver has also the Midi input capability even at the same time with the /dev/dsp. Also the WaveBlaster daughter board is supported. No support for the ASP chip yet (the ASP chip can be installed but it's not used by the driver). -You will need the snd-util-2.0.tar.gz and snd-data-0.1.tar.Z +You will need the snd-util-2.4.tar.gz and snd-data-0.1.tar.Z packages to use this driver. They should be in the same ftp site or BBS from where you got this driver. For example at nic.funet.fi:pub/OS/Linux/*. -There is a new version of the tracker program available (tracker-3.19) but -I don't know how to find it. The tracker 3.10 has bugs and it don't work -without some fixes. Look at the README of the snd-util-2.0. +There is a new version of the tracker program available (tracker-3_19.lzh) but +I don't know where it is available. The tracker 3.10 has bugs and it don't work +without some fixes. Look at the README of the snd-util-2.3. If you are looking for the installation instructions, please look at linux/Readme. @@ -161,7 +159,12 @@ Mixer(s) installed Known bugs/limitations ---------------------- -- Midi input doesn't work with SB and SB Pro (SB16 works somehow). +- High speed recording of long audio samples (>20 second) to disk + is not possible. Everything works until next sync() which delays the + recording process too much. A delay longer than 0.1 to 0.3 seconds is + too much. +- The SB16 driver sometimes swaps the left and right channels together. +- Midi input doesn't work with SB and SB Pro (SB16 works). - It's not possible to open /dev/dsp (or /dev/audio) while the /dev/sequencer is open for output and GUS is the only soundcard installed. It's possible if /dev/dsp is opened before /dev/sequencer @@ -226,6 +229,7 @@ contributors. (I could have forgotten some names.) Jim Lowe FreeBSD port Anders Baekgaard Bughunting and valuable suggestions. Joerg Schubert SB16 DSP support. + Andrew Robinson Improvements to the GUS driver Regards, diff --git a/drivers/sound/Readme.linux b/drivers/sound/Readme.linux index 0bf8d92..d585f59 100644 --- a/drivers/sound/Readme.linux +++ b/drivers/sound/Readme.linux @@ -1,18 +1,10 @@ -Sound Card Driver version 2.2 +Sound Driver version 2.4 for Linux +---------------------------------- -This directory contains the driver for various PC soundcards. -The following cards are supported: - -AdLib -SoundBlaster (1.0-2.0) and compatibles, including - ThunderBoard and Ati Stereo F/X. -SoundBlaster Pro and SB Pro 2 -SoundBlaster 16 -ProAudioSpectrum 16 - (The original ProAudioSpectrum and the PAS+ are not supported - (and propably will remain unsupported)). - -If you have any problems, please contact me. +NOTE! The sound driver is now a part of the Linux kernel distribution. + Check that your kernel doesn't have more recent version than this + when installing a separately distributed sound driver. The + version number of this driver is defined in the makefile. Installation ------------ @@ -20,14 +12,23 @@ Installation - Since this driver is a part of the Linux kernel distribution, no special steps are required to build the driver itself. -- To build the device files you need to run the enclosed shell scrip - (see below). +- In case you are installing a separately distributed sound driver, + you have to do some additional steps. + - Remove all files from the linux/drivers/sound. Old files could + sometimes cause trouble. + - cd linux/drivers. + - gunzip -c snd-driv-X.Y.tar.gz|tar xvf - + - cd ./sound + - cp soundcard.h ultrasound.h /usr/include/linux + +- To build the device files for this driver, you need to run the enclosed + shell script (at the end of this file). -- Copy the sound/ultrasound.h to /usr/include/sys - (Remove the old one from /usr/include/sys /usr/include/linux first). +- Create /usr/include/sys/soundcard.h whic contains just a line: +#include <linux/soundcard.h> -- Ensure you have the following symlink: - ln -s /usr/include/linux/soundcard.h /usr/include/sys/soundcard.h +- Create /usr/include/sys/ultrasound.h whic contains just a line: +#include <linux/ultrasound.h> Boot time configuration (using lilo) ------------------------------------ @@ -190,6 +191,11 @@ if [ -e /dev/mixer ]; then rm -f /dev/mixer fi mknod -m 666 /dev/mixer c 14 0 + +if [ -e /dev/mixer1 ]; then + rm -f /dev/mixer1 +fi +mknod -m 666 /dev/mixer1 c 14 16 # # Sequencer (14, 1) # diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index d95137b..d917a46 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -167,11 +167,6 @@ struct generic_midi_operations { {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, #endif -#ifndef EXCLUDE_GUS - {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, - {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE}, -#endif - #ifndef EXCLUDE_PAS {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE}, @@ -193,6 +188,11 @@ struct generic_midi_operations { #endif #endif +#ifndef EXCLUDE_GUS + {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, + {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE}, +#endif + #ifndef EXCLUDE_YM3812 {SNDCARD_ADLIB, "AdLib", attach_adlib_card, probe_adlib, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE}, diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 82f427a..b3a6ae2 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -323,6 +323,15 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len) unsigned long flags; int err = EIO; + DISABLE_INTR (flags); + if (!dev_qlen[dev]) + { + if (dev_needs_restart[dev]) + { + dma_reset(dev); + dev_needs_restart[dev] = 0; + } + if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */ { dma_sync(dev); @@ -339,19 +348,13 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len) if ((err = dsp_devs[dev]->prepare_for_input (dev, dev_buffsize[dev], dev_nbufs[dev])) < 0) - return err; + { + RESTORE_INTR (flags); + return err; + } dma_mode[dev] = DMODE_INPUT; } - DISABLE_INTR (flags); - if (!dev_qlen[dev]) - { - if (dev_needs_restart[dev]) - { - dma_reset(dev); - dev_needs_restart[dev] = 0; - } - if (!dev_active[dev]) { dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], @@ -366,7 +369,7 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len) DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) { - printk ("Sound: DMA timed out\n"); + printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); err = EIO; SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); } @@ -531,7 +534,7 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size) DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) { - printk ("Sound: DMA timed out\n"); + printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); err = EIO; SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); } diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index e7967e8..d031a45 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -105,6 +105,10 @@ gusintr (int unit) { unsigned char src; +#ifdef linux + sti(); +#endif + while (1) { if (!(src = INB (u_IrqStatus))) diff --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c index b3f1e84..ea3ece3 100644 --- a/drivers/sound/gus_vol.c +++ b/drivers/sound/gus_vol.c @@ -1,4 +1,4 @@ -/* +/* * gus_vol.c - Compute volume for GUS. * * Greg Lee 1993. @@ -11,7 +11,7 @@ extern int gus_wave_volume; -/* +/* * Calculate gus volume from note velocity, main volume, expression, and * intrinsic patch volume given in patch library. Expression is multiplied * in, so it emphasizes differences in note velocity, while main volume is @@ -31,35 +31,48 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) int i, m, n, x; - /* + /* * A voice volume of 64 is considered neutral, so adjust the main volume if * something other than this neutral value was assigned in the patch * library. */ x = 256 + 6 * (voicev - 64); - /* Boost expression by voice volume above neutral. */ + /* + * Boost expression by voice volume above neutral. + */ if (voicev > 65) xpn += voicev - 64; xpn += (voicev - 64) / 2; - /* Combine multiplicative and level components. */ + /* + * Combine multiplicative and level components. + */ x = vel * xpn * 6 + (voicev / 4) * x; #ifdef GUS_VOLUME - /* + /* * Further adjustment by installation-specific master volume control - * (default 50). + * (default 60). */ x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; #endif - if (x < (1 << 11)) - return (11 << 8); +#ifdef GUS_USE_CHN_MAIN_VOLUME + /* + * Experimental support for the channel main volume + */ + + mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ + x = (x * mainv * mainv) / 16384; +#endif + + if (x < 2) + return (0); else if (x >= 65535) return ((15 << 8) | 255); - /* + /* * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit * mantissa m. */ @@ -76,13 +89,15 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) n >>= 1; i++; } - /* + /* * Mantissa is part of linear volume not expressed in exponent. (This is * not quite like real logs -- I wonder if it's right.) */ m = x - (1 << i); - /* Adjust mantissa to 8 bits. */ + /* + * Adjust mantissa to 8 bits. + */ if (m > 0) { if (i > 8) @@ -91,10 +106,6 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) m <<= 8 - i; } - /* low volumes give occasional sour notes */ - if (i < 11) - return (11 << 8); - return ((i << 8) + m); } diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 51186d3..aea174d 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -1,4 +1,5 @@ -/* + +/* * sound/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. @@ -27,8 +28,6 @@ * */ -/* #define GUS_LINEAR_VOLUME */ - #include "sound_config.h" #include <linux/ultrasound.h> #include "gus_hw.h" @@ -56,16 +55,22 @@ struct voice_info int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 +#define VMODE_START_NOTE 3 int env_phase; unsigned char env_rate[6]; unsigned char env_offset[6]; - /* + /* * Volume computation parameters for gus_adagio_vol() */ int main_vol, expression_vol, patch_vol; + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, sample_pending; + char kill_pending; + long offset_pending; + }; extern int gus_base; @@ -76,24 +81,31 @@ extern int snd_raw_count[MAX_DSP_DEV]; static long gus_mem_size = 0; static long free_mem_ptr = 0; static int gus_busy = 0; -static int nr_voices = 0; /* Number of currently allowed voices */ +static int nr_voices = 0; static int gus_devnum = 0; static int volume_base, volume_scale, volume_method; +static int gus_line_vol = 100, gus_mic_vol = 0; +static int gus_recmask = SOUND_MASK_MIC; +static int recording_active = 0; #define VOL_METHOD_ADAGIO 1 -int gus_wave_volume = 60; /* Master wolume for wave (0 to 100) */ +int gus_wave_volume = 60; +int gus_pcm_volume = 80; static unsigned char mix_image = 0x00; -/* - * Current version of this_one driver doesn't allow synth and PCM functions +/* + * Current version of this driver doesn't allow synth and PCM functions * at the same time. The active_device specifies the active driver */ static int active_device = 0; -#define GUS_DEV_WAVE 1 /* Wave table synth */ -#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */ -#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer the second - * chn */ +#define GUS_DEV_WAVE 1 /* + * * * Wave table synth */ +#define GUS_DEV_PCM_DONE 2 /* + * * * PCM device, transfer done */ +#define GUS_DEV_PCM_CONTINUE 3 /* + * * * PCM device, transfer the + * second * * * chn */ static int gus_sampling_speed; static int gus_sampling_channels; @@ -101,17 +113,37 @@ static int gus_sampling_bits; DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); -/* +/* * Variables and buffers for PCM output */ -#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* Don't change */ - -static int pcm_bsize, /* Current blocksize */ - pcm_nblk, /* Current # of blocks */ - pcm_banksize; /* # bytes allocated for channels */ -static int pcm_datasize[MAX_PCM_BUFFERS]; /* Actual # of bytes in blk */ -static volatile int pcm_head, pcm_tail, pcm_qlen; /* DRAM queue */ +#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* + * * * Don't + * * * change + * + */ + +static int pcm_bsize, /* + * Current blocksize + */ + pcm_nblk, /* + * Current # of blocks + */ + pcm_banksize; /* + + * + * * * * # bytes allocated for channels */ +static int pcm_datasize[MAX_PCM_BUFFERS]; /* + + * + * * * * Actual # of bytes + * in blk * */ +static volatile int pcm_head, pcm_tail, pcm_qlen; /* + + * + * * * * DRAM queue + * */ static volatile int pcm_active; +static int pcm_opened = 0; static int pcm_current_dev; static int pcm_current_block; static unsigned long pcm_current_buf; @@ -122,28 +154,66 @@ struct voice_info voices[32]; static int freq_div_table[] = { - 44100, /* 14 */ - 41160, /* 15 */ - 38587, /* 16 */ - 36317, /* 17 */ - 34300, /* 18 */ - 32494, /* 19 */ - 30870, /* 20 */ - 29400, /* 21 */ - 28063, /* 22 */ - 26843, /* 23 */ - 25725, /* 24 */ - 24696, /* 25 */ - 23746, /* 26 */ - 22866, /* 27 */ - 22050, /* 28 */ - 21289, /* 29 */ - 20580, /* 30 */ - 19916, /* 31 */ - 19293 /* 32 */ + 44100, /* + * 14 + */ + 41160, /* + * 15 + */ + 38587, /* + * 16 + */ + 36317, /* + * 17 + */ + 34300, /* + * 18 + */ + 32494, /* + * 19 + */ + 30870, /* + * 20 + */ + 29400, /* + * 21 + */ + 28063, /* + * 22 + */ + 26843, /* + * 23 + */ + 25725, /* + * 24 + */ + 24696, /* + * 25 + */ + 23746, /* + * 26 + */ + 22866, /* + * 27 + */ + 22050, /* + * 28 + */ + 21289, /* + * 29 + */ + 20580, /* + * 30 + */ + 19916, /* + * 31 + */ + 19293 /* + * 32 + */ }; -static struct patch_info *samples; +static struct patch_info *samples; static long sample_ptrs[MAX_SAMPLE + 1]; static int sample_map[32]; static int free_sample; @@ -159,9 +229,13 @@ static void gus_poke (long addr, unsigned char data); static void compute_and_set_volume (int voice, int volume, int ramp_time); extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev); static void compute_volume (int voice, int volume); +static void do_volume_irq (int voice); +static void set_input_volumes(void); -#define INSTANT_RAMP -1 /* Dont use ramping */ -#define FAST_RAMP 0 /* Fastest possible ramp */ +#define INSTANT_RAMP -1 /* + * * * Dont use ramping */ +#define FAST_RAMP 0 /* + * * * Fastest possible ramp */ static void reset_sample_memory (void) @@ -175,7 +249,9 @@ reset_sample_memory (void) for (i = 0; i < 32; i++) patch_map[i] = -1; - gus_poke (0, 0); /* Put silence here */ + gus_poke (0, 0); /* + * Put silence here + */ gus_poke (1, 0); free_mem_ptr = 2; @@ -237,7 +313,7 @@ gus_write8 (int reg, unsigned int data) DISABLE_INTR (flags); OUTB (reg, u_Command); - OUTB ((unsigned char)(data & 0xff), u_DataHi); + OUTB ((unsigned char) (data & 0xff), u_DataHi); RESTORE_INTR (flags); } @@ -279,8 +355,8 @@ gus_write16 (int reg, unsigned int data) OUTB (reg, u_Command); - OUTB ((unsigned char)(data & 0xff), u_DataLo); - OUTB ((unsigned char)((data >> 8) & 0xff), u_DataHi); + OUTB ((unsigned char) (data & 0xff), u_DataLo); + OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi); RESTORE_INTR (flags); } @@ -310,7 +386,7 @@ gus_write_addr (int reg, unsigned long address, int is16bit) if (is16bit) { - /* + /* * Special processing required for 16 bit patches */ @@ -349,9 +425,9 @@ gus_select_max_voices (int nvoices) static void gus_voice_on (unsigned int mode) { - gus_write8 (0x00, (unsigned char)(mode & 0xfc)); + gus_write8 (0x00, (unsigned char) (mode & 0xfc)); gus_delay (); - gus_write8 (0x00, (unsigned char)(mode & 0xfc)); + gus_write8 (0x00, (unsigned char) (mode & 0xfc)); } static void @@ -363,9 +439,16 @@ gus_voice_off (void) static void gus_voice_mode (unsigned int m) { - unsigned char mode = (unsigned char)(m & 0xff); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* Don't start or stop - * voice */ + unsigned char mode = (unsigned char) (m & 0xff); + + gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* + * Don't + * start + * or + * stop + * * + * voice + */ gus_delay (); gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); } @@ -385,33 +468,35 @@ gus_voice_freq (unsigned long freq) static void gus_voice_volume (unsigned int vol) { - gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */ - gus_write16 (0x09, (unsigned short)(vol << 4)); + gus_write8 (0x0d, 0x03); /* + * Stop ramp before setting volume + */ + gus_write16 (0x09, (unsigned short) (vol << 4)); } static void gus_voice_balance (unsigned int balance) { - gus_write8 (0x0c, (unsigned char)(balance & 0xff)); + gus_write8 (0x0c, (unsigned char) (balance & 0xff)); } static void gus_ramp_range (unsigned int low, unsigned int high) { - gus_write8 (0x07, (unsigned char)((low >> 4) & 0xff)); - gus_write8 (0x08, (unsigned char)((high >> 4) & 0xff)); + gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff)); + gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff)); } static void gus_ramp_rate (unsigned int scale, unsigned int rate) { - gus_write8 (0x06, (unsigned char)(((scale & 0x03) << 6) | (rate & 0x3f))); + gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); } static void gus_rampon (unsigned int m) { - unsigned char mode = (unsigned char)(m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); gus_write8 (0x0d, mode & 0xfc); gus_delay (); @@ -421,10 +506,16 @@ gus_rampon (unsigned int m) static void gus_ramp_mode (unsigned int m) { - unsigned char mode = (unsigned char)(m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* Don't start or stop - * ramping */ + gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* + * Don't + * start + * or + * stop + * * + * ramping + */ gus_delay (); gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); } @@ -436,6 +527,20 @@ gus_rampoff (void) } static void +gus_set_voice_pos (int voice, long position) +{ + int sample_no; + + if ((sample_no = sample_map[voice]) != -1) + if (position < samples[sample_no].len) + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].offset_pending = position; + else + gus_write_addr (0x0a, sample_ptrs[sample_no] + position, + samples[sample_no].mode & WAVE_16_BITS); +} + +static void gus_voice_init (int voice) { unsigned long flags; @@ -443,11 +548,22 @@ gus_voice_init (int voice) DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_volume (0); - gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ - gus_write8 (0x00, 0x03); /* Voice off */ - gus_write8 (0x0d, 0x03); /* Ramping off */ + gus_write_addr (0x0a, 0, 0); /* + * Set current position to 0 + */ + gus_write8 (0x00, 0x03); /* + * Voice off + */ + gus_write8 (0x0d, 0x03); /* + * Ramping off + */ RESTORE_INTR (flags); +} + +static void +gus_voice_init2 (int voice) +{ voices[voice].panning = 0; voices[voice].mode = 0; voices[voice].orig_freq = 20000; @@ -464,6 +580,7 @@ gus_voice_init (int voice) voices[voice].main_vol = 127; voices[voice].patch_vol = 127; voices[voice].expression_vol = 127; + voices[voice].sample_pending = -1; } static void @@ -475,12 +592,14 @@ step_envelope (int voice) if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) { gus_rampoff (); - return; /* Sustain */ + return; /* + * Sustain + */ } if (voices[voice].env_phase >= 5) { - /* + /* * Shoot the voice off */ @@ -496,13 +615,19 @@ step_envelope (int voice) vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; rate = voices[voice].env_rate[phase]; - gus_write8 (0x06, rate); /* Ramping rate */ + gus_write8 (0x06, rate); /* + * Ramping rate + */ voices[voice].volume_irq_mode = VMODE_ENVELOPE; - if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ + if (((vol - prev_vol) / 64) == 0) /* + * No significant volume change + */ { - step_envelope (voice); /* Continue with the next phase */ + step_envelope (voice); /* + * Continue with the next phase + */ return; } @@ -511,14 +636,18 @@ step_envelope (int voice) if (vol >= (4096 - 64)) vol = 4096 - 65; gus_ramp_range (0, vol); - gus_rampon (0x20); /* Increasing, irq */ + gus_rampon (0x20); /* + * Increasing, irq + */ } else { if (vol <= 64) vol = 65; - gus_ramp_range (vol, 4095); - gus_rampon (0x60); /* Decreasing, irq */ + gus_ramp_range (vol, 4030); + gus_rampon (0x60); /* + * Decreasing, irq + */ } voices[voice].current_volume = vol; } @@ -536,13 +665,19 @@ static void start_release (int voice) { if (gus_read8 (0x00) & 0x03) - return; /* Voice already stopped */ + return; /* + * Voice already stopped + */ - voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ + voices[voice].env_phase = 2; /* + * Will be incremented by step_envelope + */ voices[voice].current_volume = voices[voice].initial_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + gus_read16 (0x09) >> 4; /* + * Get current volume + */ voices[voice].mode &= ~WAVE_SUSTAIN_ON; gus_rampoff (); @@ -556,11 +691,17 @@ gus_voice_fade (int voice) if (instr_no < 0 || instr_no > MAX_SAMPLE) { - gus_write8 (0x00, 0x03); /* Hard stop */ + gus_write8 (0x00, 0x03); /* + * Hard stop + */ return; } - is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */ + is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* + * 8 or 16 + * bit + * samples + */ if (voices[voice].mode & WAVE_ENVELOPES) { @@ -568,10 +709,12 @@ gus_voice_fade (int voice) return; } - /* + /* * Ramp the volume down but not too quickly. */ - if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */ + if ((gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ { gus_voice_off (); gus_rampoff (); @@ -579,9 +722,11 @@ gus_voice_fade (int voice) return; } - gus_ramp_range (65, 4095); + gus_ramp_range (65, 4030); gus_ramp_rate (2, 4); - gus_rampon (0x40 | 0x20); /* Down, once, irq */ + gus_rampon (0x40 | 0x20); /* + * Down, once, irq + */ voices[voice].volume_irq_mode = VMODE_HALT; } @@ -597,14 +742,25 @@ gus_reset (void) for (i = 0; i < 32; i++) { - gus_voice_init (i); /* Turn voice off */ + gus_voice_init (i); /* + * Turn voice off + */ + gus_voice_init2 (i); } - INB (u_Status); /* Touch the status register */ + 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 */ + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ } @@ -622,52 +778,82 @@ gus_initialize (void) DISABLE_INTR (flags); - gus_write8 (0x4c, 0); /* Reset GF1 */ + gus_write8 (0x4c, 0); /* + * Reset GF1 + */ gus_delay (); gus_delay (); - gus_write8 (0x4c, 1); /* Release Reset */ + gus_write8 (0x4c, 1); /* + * Release Reset + */ gus_delay (); gus_delay (); - /* + /* * Clear all interrupts */ - gus_write8 (0x41, 0); /* DMA control */ - gus_write8 (0x45, 0); /* Timer control */ - gus_write8 (0x49, 0); /* Sample control */ + gus_write8 (0x41, 0); /* + * DMA control + */ + gus_write8 (0x45, 0); /* + * Timer control + */ + gus_write8 (0x49, 0); /* + * Sample control + */ gus_select_max_voices (24); - 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 */ - - gus_reset (); /* Resets all voices */ - - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ - - gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */ - - /* + 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 + */ + + gus_reset (); /* + * Resets all voices + */ + + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ + + gus_write8 (0x4c, 7); /* + * Master reset | DAC enable | IRQ enable + */ + + /* * Set up for Digital ASIC */ OUTB (0x05, gus_base + 0x0f); - mix_image |= 0x02; /* Disable line out */ + mix_image |= 0x02; /* + * Disable line out + */ OUTB (mix_image, u_Mixer); OUTB (0x00, u_IRQDMAControl); OUTB (0x00, gus_base + 0x0f); - /* + /* * Now set up the DMA and IRQ interface * * The GUS supports two IRQs and two DMAs. @@ -682,49 +868,89 @@ gus_initialize (void) if (!tmp) printk ("Warning! GUS IRQ not selected\n"); irq_image |= tmp; - irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ + irq_image |= 0x40; /* + * Combine IRQ1 (GF1) and IRQ2 (Midi) + */ - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + dma_image = 0x40; /* + * Combine DMA1 (DRAM) and IRQ2 (ADC) + */ tmp = gus_dma_map[gus_dma]; if (!tmp) printk ("Warning! GUS DMA not selected\n"); dma_image |= tmp; - /* + /* * For some reason the IRQ and DMA addresses must be written twice */ - /* Doing it first time */ - - OUTB (mix_image, u_Mixer); /* Select DMA control */ - OUTB (dma_image | 0x80, u_IRQDMAControl); /* Set DMA address */ - - OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */ - OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */ - - /* Doing it second time */ - - OUTB (mix_image, u_Mixer); /* Select DMA control */ - OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */ - - OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */ - OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */ - - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ - - mix_image &= ~0x02; /* Enable line out */ - mix_image |= 0x08; /* Enable IRQ */ - OUTB (mix_image, u_Mixer); /* Turn mixer channels on */ + /* + * Doing it first time + */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + OUTB (mix_image, u_Mixer); /* + * Select DMA control + */ + OUTB (dma_image | 0x80, u_IRQDMAControl); /* + * Set DMA address + */ + + OUTB (mix_image | 0x40, u_Mixer); /* + * Select IRQ control + */ + OUTB (irq_image, u_IRQDMAControl); /* + * Set IRQ address + */ + + /* + * Doing it second time + */ - gusintr (0); /* Serve pending interrupts */ + OUTB (mix_image, u_Mixer); /* + * Select DMA control + */ + OUTB (dma_image, u_IRQDMAControl); /* + * Set DMA address + */ + + OUTB (mix_image | 0x40, u_Mixer); /* + * Select IRQ control + */ + OUTB (irq_image, u_IRQDMAControl); /* + * Set IRQ address + */ + + gus_select_voice (0); /* + * This disables writes to IRQ/DMA reg + */ + + mix_image &= ~0x02; /* + * Enable line out + */ + mix_image |= 0x08; /* + * Enable IRQ + */ + OUTB (mix_image, u_Mixer); /* + * Turn mixer channels on + * Note! Mic in is left off. + */ + + gus_select_voice (0); /* + * This disables writes to IRQ/DMA reg + */ + + gusintr (0); /* + * Serve pending interrupts + */ RESTORE_INTR (flags); } int gus_wave_detect (int baseaddr) { + unsigned long i; + unsigned long loc; + gus_base = baseaddr; gus_write8 (0x4c, 0); /* Reset GF1 */ @@ -735,31 +961,37 @@ gus_wave_detect (int baseaddr) gus_delay (); gus_delay (); - gus_poke (0x000, 0xaa); - gus_poke (0x100, 0x55); + /* See if there is first block there.... */ + gus_poke (0L, 0xaa); + if (gus_peek (0L) != 0xaa) + return (0); - if (gus_peek (0x000) != 0xaa) - return 0; - if (gus_peek (0x100) != 0x55) - return 0; - - gus_mem_size = 0x40000; /* 256k */ - gus_poke (0x40000, 0xaa); - if (gus_peek (0x40000) != 0xaa) - return 1; + /* Now zero it out so that I can check for mirroring .. */ + gus_poke (0L, 0x00); + for (i = 1L; i < 1024L; i++) + { + int n, failed; - gus_mem_size = 0x80000; /* 512k */ - gus_poke (0x80000, 0xaa); - if (gus_peek (0x80000) != 0xaa) - return 1; + /* check for mirroring ... */ + if (gus_peek (0L) != 0) + break; + loc = i << 10; - gus_mem_size = 0xc0000; /* 768k */ - gus_poke (0xc0000, 0xaa); - if (gus_peek (0xc0000) != 0xaa) - return 1; + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke (loc, 0xaa); + if (gus_peek (loc) != 0xaa) + failed = 1; - gus_mem_size = 0x100000; /* 1M */ + gus_poke (loc, 0x55); + if (gus_peek (loc) != 0x55) + failed = 1; + } + if (failed) + break; + } + gus_mem_size = i << 10; return 1; } @@ -804,16 +1036,26 @@ guswave_set_instr (int dev, int voice, int instr_no) if (voice < 0 || voice > 31) return RET_ERROR (EINVAL); + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].sample_pending = instr_no; + return 0; + } + sample_no = patch_table[instr_no]; patch_map[voice] = -1; if (sample_no < 0) { printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return RET_ERROR (EINVAL);/* Patch not defined */ + return RET_ERROR (EINVAL); /* + * Patch not defined + */ } - if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ + 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 RET_ERROR (EINVAL); @@ -825,13 +1067,22 @@ guswave_set_instr (int dev, int voice, int instr_no) } static int +#ifdef FUTURE_VERSION +guswave_kill_note (int dev, int voice, int note, int velocity) +#else guswave_kill_note (int dev, int voice, int velocity) +#endif { unsigned long flags; DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_fade (voice); + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].kill_pending = 1; + else + { + gus_select_voice (voice); + gus_voice_fade (voice); + } RESTORE_INTR (flags); return 0; @@ -843,20 +1094,26 @@ guswave_aftertouch (int dev, int voice, int pressure) short lo_limit, hi_limit; unsigned long flags; - return; /* Currently disabled */ + return; /* + * Currently disabled + */ if (voice < 0 || voice > 31) return; if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2) - return; /* Don't mix with envelopes */ + return; /* + * Don't mix with envelopes + */ if (pressure < 32) { DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); - compute_and_set_volume (voice, 255, 0); /* Back to original volume */ + compute_and_set_volume (voice, 255, 0); /* + * Back to original volume + */ RESTORE_INTR (flags); return; } @@ -875,7 +1132,9 @@ guswave_aftertouch (int dev, int voice, int pressure) } gus_ramp_range (lo_limit, hi_limit); gus_ramp_rate (3, 8); - gus_rampon (0x58); /* Bidirectional, Down, Loop */ + gus_rampon (0x58); /* + * Bidirectional, Down, Loop + */ RESTORE_INTR (flags); } @@ -890,39 +1149,38 @@ static void compute_volume (int voice, int volume) { if (volume < 128) - { - voices[voice].midi_volume = volume; + voices[voice].midi_volume = volume; - switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol (volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; + switch (volume_method) + { + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; - default: - voices[voice].initial_volume = volume_base + (volume * volume_scale); - } - } + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); + } - if (voices[voice].initial_volume > 4095) - voices[voice].initial_volume = 4095; + if (voices[voice].initial_volume > 4030) + voices[voice].initial_volume = 4030; } static void compute_and_set_volume (int voice, int volume, int ramp_time) { int current, target, rate; - unsigned long flags; + unsigned long flags; - DISABLE_INTR(flags); -/* + DISABLE_INTR (flags); +/* * CAUTION! Interrupts disabled. Enable them before returning */ - gus_select_voice(voice); + gus_select_voice (voice); compute_volume (voice, volume); voices[voice].current_volume = voices[voice].initial_volume; @@ -934,7 +1192,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time) { gus_rampoff (); gus_voice_volume (target); - RESTORE_INTR(flags); + RESTORE_INTR (flags); return; } @@ -944,11 +1202,13 @@ compute_and_set_volume (int voice, int volume, int ramp_time) rate = 16; gus_ramp_rate (0, rate); - if ((target - current) / 64 == 0) /* Too close */ + if ((target - current) / 64 == 0) /* + * Too close + */ { gus_rampoff (); gus_voice_volume (target); - RESTORE_INTR(flags); + RESTORE_INTR (flags); return; } @@ -957,7 +1217,9 @@ compute_and_set_volume (int voice, int volume, int ramp_time) if (target > (4095 - 65)) target = 4095 - 65; gus_ramp_range (current, target); - gus_rampon (0x00); /* Ramp up, once, no irq */ + gus_rampon (0x00); /* + * Ramp up, once, no irq + */ } else { @@ -965,9 +1227,11 @@ compute_and_set_volume (int voice, int volume, int ramp_time) target = 65; gus_ramp_range (target, current); - gus_rampon (0x40); /* Ramp down, once, no irq */ + gus_rampon (0x40); /* + * Ramp down, once, no irq + */ } - RESTORE_INTR(flags); + RESTORE_INTR (flags); } static void @@ -978,11 +1242,15 @@ dynamic_volume_change (int voice) DISABLE_INTR (flags); gus_select_voice (voice); - status = gus_read8 (0x00); /* Voice status */ + status = gus_read8 (0x00); /* + * Voice status + */ RESTORE_INTR (flags); if (status & 0x03) - return; /* Voice not started */ + return; /* + * Voice not started + */ if (!(voices[voice].mode & WAVE_ENVELOPES)) { @@ -990,16 +1258,20 @@ dynamic_volume_change (int voice) return; } - /* + /* * Voice is running and has envelopes. */ DISABLE_INTR (flags); gus_select_voice (voice); - status = gus_read8 (0x0d); /* Ramping status */ + status = gus_read8 (0x0d); /* + * Ramping status + */ RESTORE_INTR (flags); - if (status & 0x03) /* Sustain phase? */ + if (status & 0x03) /* + * Sustain phase? + */ { compute_and_set_volume (voice, voices[voice].midi_volume, 1); return; @@ -1010,9 +1282,12 @@ dynamic_volume_change (int voice) compute_volume (voice, voices[voice].midi_volume); -#if 0 /* Is this really required */ +#if 0 /* + * * * Is this really required */ voices[voice].current_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + gus_read16 (0x09) >> 4; /* + * Get current volume + */ voices[voice].env_phase--; step_envelope (voice); @@ -1032,38 +1307,58 @@ guswave_controller (int dev, int voice, int ctrl_num, int value) { case CTRL_PITCH_BENDER: voices[voice].bender = value; - freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); - voices[voice].current_freq = freq; - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_freq (freq); - RESTORE_INTR (flags); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + voices[voice].current_freq = freq; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (freq); + RESTORE_INTR (flags); + } break; case CTRL_PITCH_BENDER_RANGE: voices[voice].bender_range = value; break; - +#ifdef FUTURE_VERSION + case CTL_EXPRESSION: + value /= 128; +#endif case CTRL_EXPRESSION: volume_method = VOL_METHOD_ADAGIO; voices[voice].expression_vol = value; - dynamic_volume_change (voice); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change (voice); + break; + +#ifdef FUTURE_VERSION + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; break; + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; +#endif + case CTRL_MAIN_VOLUME: volume_method = VOL_METHOD_ADAGIO; voices[voice].main_vol = value; - dynamic_volume_change (voice); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change (voice); break; - default: /* Ignore */ + default: /* + * Ignore + */ break; } } static int -guswave_start_note (int dev, int voice, int note_num, int volume) +guswave_start_note2 (int dev, int voice, int note_num, int volume) { int sample, best_sample, best_delta, delta_freq; int is16bits, samplep, patch, pan; @@ -1101,7 +1396,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume) note_freq = note_to_freq (note_num); - /* + /* * Find a sample within a patch so that the note_freq is between low_note * and high_note. */ @@ -1122,7 +1417,9 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note) sample = samplep; else - samplep = samples[samplep].key; /* Follow link */ + samplep = samples[samplep].key; /* + * Follow link + */ } if (sample == -1) sample = best_sample; @@ -1130,10 +1427,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (sample == -1) { printk ("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ + return 0; /* + * Should play default patch ??? + */ } - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */ + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* + * 8 or 16 + * bit + * samples + */ voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; @@ -1150,14 +1453,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume) sample_map[voice] = sample; - base_note = samples[sample].base_note / 100; /* To avoid overflows */ + base_note = samples[sample].base_note / 100; /* + * To avoid overflows + */ note_freq /= 100; freq = samples[sample].base_freq * note_freq / base_note; voices[voice].orig_freq = freq; - /* + /* * Since the pitch bender may have been set before playing the note, we * have to calculate the bending now. */ @@ -1174,19 +1479,23 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (samples[sample].mode & WAVE_16_BITS) { - mode |= 0x04; /* 16 bits */ + mode |= 0x04; /* + * 16 bits + */ if ((sample_ptrs[sample] >> 18) != ((sample_ptrs[sample] + samples[sample].len) >> 18)) printk ("GUS: Sample address error\n"); } /************************************************************************* - * CAUTION! Interrupts disabled. Don't return before enabling - *************************************************************************/ + * CAUTION! Interrupts disabled. Don't return before enabling + *************************************************************************/ DISABLE_INTR (flags); gus_select_voice (voice); - gus_voice_off (); /* It may still be running */ + gus_voice_off (); /* + * It may still be running + */ gus_rampoff (); if (voices[voice].mode & WAVE_ENVELOPES) { @@ -1197,35 +1506,62 @@ guswave_start_note (int dev, int voice, int note_num, int volume) compute_and_set_volume (voice, volume, 0); if (samples[sample].mode & WAVE_LOOP_BACK) - gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len, is16bits); /* Sample start=end */ + gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - + voices[voice].offset_pending, is16bits); /* Sample + * start=end */ else - gus_write_addr (0x0a, sample_ptrs[sample], is16bits); /* Sample start=begin */ + gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, + is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) { - mode |= 0x08; /* Looping on */ + mode |= 0x08; /* + * Looping on + */ if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; /* Bidirectional looping on */ + mode |= 0x10; /* + * Bidirectional looping on + */ if (samples[sample].mode & WAVE_LOOP_BACK) { - gus_write_addr (0x0a, /* Put the current location = loop_end */ - sample_ptrs[sample] + samples[sample].loop_end, is16bits); - mode |= 0x40; /* Loop backwards */ + gus_write_addr (0x0a, + sample_ptrs[sample] + samples[sample].loop_end - + voices[voice].offset_pending, is16bits); + mode |= 0x40; } - gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /* Loop end location */ + gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /* + * Loop + * start + * location + */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /* + * Loop + * end + * location + */ } else { - mode |= 0x20; /* Loop irq at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp it down at the - * end */ + mode |= 0x20; /* + * Loop irq at the end + */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* + * Ramp it 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, is16bits); /* Loop end location */ + gus_write_addr (0x02, sample_ptrs[sample], is16bits); /* + * Loop start + * location + */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len-1, is16bits); /* + * Loop + * end + * location + */ } gus_voice_freq (freq); gus_voice_balance (pan); @@ -1235,13 +1571,76 @@ guswave_start_note (int dev, int voice, int note_num, int volume) return 0; } +/* + * * New guswave_start_note by Andrew J. Robinson attempts to minimize + * clicking * when the note playing on the voice is changed. It uses volume + * ramping. */ + +static int +guswave_start_note (int dev, int voice, int note_num, int volume) +{ + long int flags; + int mode; + int ret_val = 0; + + DISABLE_INTR (flags); + if (note_num == 255) + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].volume_pending = volume; + else + ret_val = guswave_start_note2 (dev, voice, note_num, volume); + } + else + { + gus_select_voice (voice); + mode = gus_read8 (0x00); + if (mode & 0x20) + gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr (voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + + if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065)) + { + ret_val = guswave_start_note2 (dev, voice, note_num, volume); + } + else + { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff (); + gus_ramp_range (2000, 4065); + gus_ramp_rate (0, 63); /* Fastest possible rate */ + gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ + } + } + RESTORE_INTR (flags); + return ret_val; +} + static void guswave_reset (int dev) { int i; for (i = 0; i < 32; i++) - gus_voice_init (i); + { + gus_voice_init (i); + gus_voice_init2 (i); + } } static int @@ -1252,6 +1651,8 @@ guswave_open (int dev, int mode) if (gus_busy) return RET_ERROR (EBUSY); + gus_initialize (); + if ((err = DMAbuf_open_dma (gus_devnum))) return err; @@ -1284,8 +1685,11 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, unsigned long blk_size, blk_end, left, src_offs, target; - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Size of the header - * info */ + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* + * Size of + * the header + * * info + */ if (format != GUS_PATCH) { @@ -1307,7 +1711,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, return RET_ERROR (ENOSPC); } - /* + /* * Copy the header from user space but ignore the first bytes which have * been transferred already. */ @@ -1325,13 +1729,13 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, if (count < patch.len) { printk ("GUS Warning: Patch record too short (%d<%d)\n", - count, (int)patch.len); + count, (int) patch.len); patch.len = count; } if (patch.len <= 0 || patch.len > gus_mem_size) { - printk ("GUS: Invalid sample length %d\n", (int)patch.len); + printk ("GUS: Invalid sample length %d\n", (int) patch.len); return RET_ERROR (EINVAL); } @@ -1350,31 +1754,37 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, } } - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* Alignment 32 bytes */ + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* + * Alignment 32 bytes + */ #define GUS_BANK_SIZE (256*1024) if (patch.mode & WAVE_16_BITS) { - /* + /* * 16 bit samples must fit one 256k bank. */ if (patch.len >= GUS_BANK_SIZE) { - printk ("GUS: Sample (16 bit) too long %d\n", (int)patch.len); + printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); return RET_ERROR (ENOSPC); } if ((free_mem_ptr / GUS_BANK_SIZE) != ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) { - unsigned long tmp_mem = /* Align to 256K*N */ + unsigned long tmp_mem = /* + * Align to 256K*N + */ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; if ((tmp_mem + patch.len) > gus_mem_size) return RET_ERROR (ENOSPC); - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + free_mem_ptr = tmp_mem; /* + * This leaves unusable memory + */ } } @@ -1383,21 +1793,23 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, sample_ptrs[free_sample] = free_mem_ptr; - /* Tremolo is not possible with envelopes */ + /* + * Tremolo is not possible with envelopes + */ if (patch.mode & WAVE_ENVELOPES) patch.mode &= ~WAVE_TREMOLO; memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); - /* + /* * Link this_one sample to the list of samples for patch 'instr'. */ samples[free_sample].key = patch_table[instr]; patch_table[instr] = free_sample; - /* + /* * Use DMA to transfer the wave data to the DRAM */ @@ -1405,26 +1817,30 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, src_offs = 0; target = free_mem_ptr; - while (left) /* Not all moved */ + while (left) /* + * Not all moved + */ { blk_size = sound_buffsizes[gus_devnum]; if (blk_size > left) blk_size = left; - /* + /* * DMA cannot cross 256k bank boundaries. Check for that. */ blk_end = target + blk_size; if ((target >> 18) != (blk_end >> 18)) - { /* Have to split the block */ + { /* + * Have to split the block + */ blk_end &= ~(256 * 1024 - 1); blk_size = blk_end - target; } #if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA) - /* + /* * For some reason the DMA is not possible. We have to use PIO. */ { @@ -1436,17 +1852,21 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, GET_BYTE_FROM_USER (data, addr, sizeof_patch + i); if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* + * Convert to signed + */ gus_poke (target + i, data); } } -#else /* GUS_NO_DMA */ +#else /* + * * * GUS_NO_DMA */ { unsigned long address, hold_address; unsigned char dma_command; + unsigned long flags; - /* + /* * OK, move now. First in and then out. */ @@ -1454,11 +1874,14 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, addr, sizeof_patch + src_offs, blk_size); - gus_write8 (0x41, 0); /* Disable GF1 DMA */ + DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/ + gus_write8 (0x41, 0); /* + * Disable GF1 DMA + */ DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0], blk_size, DMA_MODE_WRITE); - /* + /* * Set the DRAM address for the wave data */ @@ -1472,23 +1895,35 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, address |= (hold_address & 0x000c0000L); } - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + gus_write16 (0x42, (address >> 4) & 0xffff); /* + * DRAM DMA address + */ - /* + /* * Start the DMA transfer */ - dma_command = 0x21; /* IRQ enable, DMA start */ + dma_command = 0x21; /* + * IRQ enable, DMA start + */ if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ + dma_command |= 0x80; /* + * Invert MSB + */ if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ + dma_command |= 0x40; /* + * 16 bit _DATA_ + */ if (sound_dsp_dmachan[gus_devnum] > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ + dma_command |= 0x04; /* + * 16 bit DMA channel + */ - gus_write8 (0x41, dma_command); /* Let's go luteet (=bugs) */ + gus_write8 (0x41, dma_command); /* + * Let's go luteet (=bugs) + */ - /* + /* * Sleep here until the DRAM DMA done interrupt is served */ active_device = GUS_DEV_WAVE; @@ -1496,10 +1931,12 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) printk ("GUS: DMA Transfer timed out\n"); + RESTORE_INTR (flags); } -#endif /* GUS_NO_DMA */ +#endif /* + * * * GUS_NO_DMA */ - /* + /* * Now the next part */ @@ -1507,7 +1944,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, src_offs += blk_size; target += blk_size; - gus_write8 (0x41, 0); /* Stop DMA */ + gus_write8 (0x41, 0); /* + * Stop DMA + */ } free_mem_ptr += patch.len; @@ -1531,6 +1970,10 @@ guswave_hw_control (int dev, unsigned char *event) p2 = *(unsigned short *) &event[6]; plong = *(unsigned long *) &event[4]; + if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + do_volume_irq (voice); + switch (cmd) { @@ -1548,7 +1991,9 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_VOICEON: DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_voice_on (p1); RESTORE_INTR (flags); break; @@ -1570,7 +2015,9 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_VOICEMODE: DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_voice_mode (p1); RESTORE_INTR (flags); break; @@ -1596,14 +2043,18 @@ guswave_hw_control (int dev, unsigned char *event) RESTORE_INTR (flags); break; - case _GUS_VOICEVOL2: /* Just update the voice value */ + case _GUS_VOICEVOL2: /* + * Just update the voice value + */ voices[voice].initial_volume = voices[voice].current_volume = p1; break; case _GUS_RAMPRANGE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_range (p1, p2); @@ -1612,7 +2063,9 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_RAMPRATE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_rate (p1, p2); @@ -1621,27 +2074,37 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_RAMPMODE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_ramp_mode (p1); RESTORE_INTR (flags); break; case _GUS_RAMPON: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_rampon (p1); RESTORE_INTR (flags); break; case _GUS_RAMPOFF: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); @@ -1653,6 +2116,13 @@ guswave_hw_control (int dev, unsigned char *event) volume_scale = p2; break; + case _GUS_VOICE_POS: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_set_voice_pos (voice, plong); + RESTORE_INTR (flags); + break; + default:; } } @@ -1720,7 +2190,8 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) break; case SOUND_PCM_WRITE_CHANNELS: - if (local) return gus_sampling_set_channels(arg); + if (local) + return gus_sampling_set_channels (arg); return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg))); break; @@ -1741,7 +2212,9 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) return gus_sampling_bits; return IOCTL_OUT (arg, gus_sampling_bits); - case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ + case SOUND_PCM_WRITE_FILTER: /* + * NOT YET IMPLEMENTED + */ return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; @@ -1771,6 +2244,8 @@ gus_sampling_open (int dev, int mode) if (gus_busy) return RET_ERROR (EBUSY); + gus_initialize (); + gus_busy = 1; active_device = 0; @@ -1779,6 +2254,12 @@ gus_sampling_open (int dev, int mode) gus_select_max_voices (14); pcm_active = 0; + pcm_opened = 1; + if (mode & OPEN_READ) + { + recording_active = 1; + set_input_volumes(); + } return 0; } @@ -1788,7 +2269,31 @@ gus_sampling_close (int dev) { gus_reset (); gus_busy = 0; + pcm_opened = 0; active_device = 0; + + if (recording_active) + set_input_volumes(); + + recording_active = 0; +} + +static void +gus_sampling_update_volume (void) +{ + unsigned long flags; + int voice; + + DISABLE_INTR (flags); + if (pcm_active && pcm_opened) + for (voice = 0; voice < gus_sampling_channels; voice++) + { + gus_select_voice (voice); + gus_rampoff (); + gus_voice_volume (1530 + (25 * gus_pcm_volume)); + gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); + } + RESTORE_INTR (flags); } static void @@ -1808,18 +2313,24 @@ play_next_pcm_block (void) for (chn = 0; chn < gus_sampling_channels; chn++) { mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ + ramp_mode[chn] = 0x03; /* + * Ramping and rollover off + */ if (chn == 0) { - mode[chn] |= 0x20; /* Loop irq */ + mode[chn] |= 0x20; /* + * Loop irq + */ voices[chn].loop_irq_mode = LMODE_PCM; } if (gus_sampling_bits != 8) { is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ + mode[chn] |= 0x04; /* + * 16 bit data + */ } else is16bits = 0; @@ -1827,15 +2338,23 @@ play_next_pcm_block (void) dram_loc = this_one * pcm_bsize; dram_loc += chn * pcm_banksize; - if (this_one == (pcm_nblk - 1)) /* Last of the DRAM buffers */ + if (this_one == (pcm_nblk - 1)) /* + * Last of the DRAM buffers + */ { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03;/* Disable rollover */ + mode[chn] |= 0x08; /* + * Enable loop + */ + ramp_mode[chn] = 0x03; /* + * Disable rollover + */ } else { if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ + ramp_mode[chn] = 0x04; /* + * Enable rollover bit + */ } DISABLE_INTR (flags); @@ -1843,53 +2362,90 @@ play_next_pcm_block (void) gus_voice_freq (speed); if (gus_sampling_channels == 1) - gus_voice_balance (7); /* mono */ + gus_voice_balance (7); /* + * mono + */ else if (chn == 0) - gus_voice_balance (0); /* left */ + gus_voice_balance (0); /* + * left + */ else - gus_voice_balance (15); /* right */ + gus_voice_balance (15); /* + * right + */ - if (!pcm_active) /* Voice not started yet */ + if (!pcm_active) /* + * Voice not started yet + */ { - /* + /* * The playback was not started yet (or there has been a pause). * Start the voice (again) and ask for a rollover irq at the end of * this_one block. If this_one one is last of the buffers, use just * the normal loop with irq. */ - gus_voice_off (); /* It could already be running */ + gus_voice_off (); /* + * It could already be running + */ gus_rampoff (); - gus_voice_volume (4000); - gus_ramp_range (65, 4030); + 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 location */ + gus_write_addr (0x0a, dram_loc, is16bits); /* + * Starting position + */ + gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* + * Loop start + * location + */ if (chn != 0) gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk), - is16bits); /* Loop end location */ + is16bits); /* + * Loop end location + */ } if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */ + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* + * Loop + * end + * location + */ else - mode[chn] |= 0x08; /* Enable loop */ + mode[chn] |= 0x08; /* + * Enable loop + */ if (pcm_datasize[this_one] != pcm_bsize) { - /* Incomplete block. Possibly the last one. */ + /* + * Incomplete block. Possibly the last one. + */ if (chn == 0) { - mode[chn] &= ~0x08; /* Disable loop */ - mode[chn] |= 0x20;/* Enable loop IRQ */ + mode[chn] &= ~0x08; /* + * Disable loop + */ + mode[chn] |= 0x20; /* + * Enable loop IRQ + */ voices[0].loop_irq_mode = LMODE_PCM_STOP; - ramp_mode[chn] = 0x03; /* No rollover bit */ + ramp_mode[chn] = 0x03; /* + * No rollover bit + */ } else { - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */ - mode[chn] &= ~0x08; /* Disable loop */ + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* + * Loop + * end + * location + */ + mode[chn] &= ~0x08; /* + * Disable loop + */ } } @@ -1912,7 +2468,7 @@ static void gus_transfer_output_block (int dev, unsigned long buf, int total_count, int intrflag, int chn) { - /* + /* * This routine transfers one block of audio data to the DRAM. In mono mode * it's called just once. When in stereo mode, this_one routine is called * once for both channels. @@ -1943,7 +2499,9 @@ gus_transfer_output_block (int dev, unsigned long buf, else this_one = pcm_current_block; - gus_write8 (0x41, 0); /* Disable GF1 DMA */ + gus_write8 (0x41, 0); /* + * Disable GF1 DMA + */ DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); address = this_one * pcm_bsize; @@ -1957,38 +2515,55 @@ gus_transfer_output_block (int dev, unsigned long buf, address |= (hold_address & 0x000c0000L); } - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + gus_write16 (0x42, (address >> 4) & 0xffff); /* + * DRAM DMA address + */ - dma_command = 0x21; /* IRQ enable, DMA start */ + dma_command = 0x21; /* + * IRQ enable, DMA start + */ if (gus_sampling_bits != 8) - dma_command |= 0x40; /* 16 bit _DATA_ */ + dma_command |= 0x40; /* + * 16 bit _DATA_ + */ else - dma_command |= 0x80; /* Invert MSB */ + dma_command |= 0x80; /* + * Invert MSB + */ if (sound_dsp_dmachan[dev] > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ + dma_command |= 0x04; /* + * 16 bit DMA channel + */ - gus_write8 (0x41, dma_command); /* Kick on */ + gus_write8 (0x41, dma_command); /* + * Kick on + */ - if (chn == (gus_sampling_channels - 1)) /* Last channel */ + if (chn == (gus_sampling_channels - 1)) /* + * Last channel + */ { - /* Last (right or mono) channel data */ + /* + * Last (right or mono) channel data + */ active_device = GUS_DEV_PCM_DONE; if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize)) { play_next_pcm_block (); } } - else /* Left channel data. The right channel is - * transferred after DMA interrupt */ + else /* + * * * Left channel data. The right channel + * is * * * transferred after DMA interrupt */ active_device = GUS_DEV_PCM_CONTINUE; RESTORE_INTR (flags); } static void -gus_sampling_output_block (int dev, unsigned long buf, int total_count, +gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag, int restart_dma) { pcm_current_buf = buf; @@ -1999,7 +2574,7 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, } static void -gus_sampling_start_input (int dev, unsigned long buf, int count, +gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag, int restart_dma) { unsigned long flags; @@ -2009,13 +2584,21 @@ gus_sampling_start_input (int dev, unsigned long buf, int count, DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enable, invert MSB */ + mode = 0xa0; /* + * DMA IRQ enable, invert MSB + */ if (sound_dsp_dmachan[dev] > 3) - mode |= 0x04; /* 16 bit DMA channel */ + mode |= 0x04; /* + * 16 bit DMA channel + */ if (gus_sampling_channels > 1) - mode |= 0x02; /* Stereo */ - mode |= 0x01; /* DMA enable */ + mode |= 0x02; /* + * Stereo + */ + mode |= 0x01; /* + * DMA enable + */ gus_write8 (0x49, mode); @@ -2029,7 +2612,9 @@ gus_sampling_prepare_for_input (int dev, int bsize, int bcount) rate = (9878400 / (gus_sampling_speed + 2)) / 16; - gus_write8 (0x48, rate & 0xff); /* Set sampling frequency */ + gus_write8 (0x48, rate & 0xff); /* + * Set sampling frequency + */ if (gus_sampling_bits != 8) { @@ -2131,19 +2716,37 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs, static struct audio_operations gus_sampling_operations = { "Gravis UltraSound", - 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, /* halt_xfer */ + 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_has_output_drained, gus_copy_from_user }; +#ifdef FUTURE_VERSION +static void +guswave_bender (int dev, int voice, int value) +{ + int freq; + unsigned long flags; + + voices[voice].bender = value - 8192; + freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + voices[voice].current_freq = freq; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (freq); + RESTORE_INTR (flags); +} +#endif + static int guswave_patchmgr (int dev, struct patmgr_info *rec) { @@ -2173,7 +2776,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) while (ptr >= 0 && ptr < free_sample) { rec->data.data8[i]++; - ptr = samples[ptr].key; /* Follow link */ + ptr = samples[ptr].key; /* + * Follow link + */ } } return 0; @@ -2188,7 +2793,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) while (ptr >= 0 && ptr < free_sample) { rec->data.data32[n++] = ptr; - ptr = samples[ptr].key; /* Follow link */ + ptr = samples[ptr].key; /* + * Follow link + */ } } rec->parm1 = n; @@ -2208,8 +2815,12 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) pat = (struct patch_info *) rec->data.data8; - pat->key = GUS_PATCH; /* Restore patch type */ - rec->parm1 = sample_ptrs[ptr]; /* DRAM address */ + pat->key = GUS_PATCH; /* + * Restore patch type + */ + rec->parm1 = sample_ptrs[ptr]; /* + * DRAM address + */ rec->parm2 = sizeof (struct patch_info); } return 0; @@ -2225,10 +2836,14 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) pat = (struct patch_info *) rec->data.data8; - if (pat->len > samples[ptr].len) /* Cannot expand sample */ + if (pat->len > samples[ptr].len) /* + * Cannot expand sample + */ return RET_ERROR (EINVAL); - pat->key = samples[ptr].key; /* Ensure the link is correct */ + pat->key = samples[ptr].key; /* + * Ensure the link is correct + */ memcpy ((char *) &samples[ptr], rec->data.data8, sizeof (struct patch_info)); @@ -2238,7 +2853,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) return 0; break; - case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */ + case PM_READ_PATCH: /* + * Returns a block of wave data from the DRAM + */ { int sample = rec->parm1; int n; @@ -2249,9 +2866,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) return RET_ERROR (EINVAL); if (offs < 0 || offs >= samples[sample].len) - return RET_ERROR (EINVAL); /* Invalid offset */ + return RET_ERROR (EINVAL); /* + * Invalid offset + */ - n = samples[sample].len - offs; /* Nr of bytes left */ + n = samples[sample].len - offs; /* + * Nr of bytes left + */ if (l > n) l = n; @@ -2260,18 +2881,26 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) l = sizeof (rec->data.data8); if (l <= 0) - return RET_ERROR (EINVAL); /* Was there a bug? */ + return RET_ERROR (EINVAL); /* + * Was there a bug? + */ - offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */ + offs += sample_ptrs[sample]; /* + * Begin offsess + offset to DRAM + */ for (n = 0; n < l; n++) rec->data.data8[n] = gus_peek (offs++); - rec->parm1 = n; /* Nr of bytes copied */ + rec->parm1 = n; /* + * Nr of bytes copied + */ } return 0; break; - case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */ + case PM_WRITE_PATCH: /* + * Writes a block of wave data to the DRAM + */ { int sample = rec->parm1; int n; @@ -2282,9 +2911,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) return RET_ERROR (EINVAL); if (offs < 0 || offs >= samples[sample].len) - return RET_ERROR (EINVAL); /* Invalid offset */ + return RET_ERROR (EINVAL); /* + * Invalid offset + */ - n = samples[sample].len - offs; /* Nr of bytes left */ + n = samples[sample].len - offs; /* + * Nr of bytes left + */ if (l > n) l = n; @@ -2293,13 +2926,19 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) l = sizeof (rec->data.data8); if (l <= 0) - return RET_ERROR (EINVAL); /* Was there a bug? */ + return RET_ERROR (EINVAL); /* + * Was there a bug? + */ - offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */ + offs += sample_ptrs[sample]; /* + * Begin offsess + offset to DRAM + */ for (n = 0; n < l; n++) gus_poke (offs++, rec->data.data8[n]); - rec->parm1 = n; /* Nr of bytes copied */ + rec->parm1 = n; /* + * Nr of bytes copied + */ } return 0; break; @@ -2312,6 +2951,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) static struct synth_operations guswave_operations = { &gus_info, +#ifdef FUTURE_VERSION + 0, +#endif SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, guswave_open, @@ -2326,13 +2968,178 @@ static struct synth_operations guswave_operations = guswave_aftertouch, guswave_controller, guswave_panning, - guswave_patchmgr + guswave_patchmgr, +#ifdef FUTURE_VERSION + guswave_bender +#endif +}; + +static void +set_input_volumes(void) +{ + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + + DISABLE_INTR(flags); + +/* + * Enable channels having vol > 10% + * Note! bit 0x01 means line in DISABLED while 0x04 means + * mic in ENABLED. + */ + if (gus_line_vol > 10) mask &= ~0x01; + if (gus_mic_vol > 10) mask |= 0x04; + + if (recording_active) + { +/* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) mask &= ~0x04; + } + + mix_image &= ~0x07; + mix_image |= mask & 0x07; + OUTB (mix_image, u_Mixer); + + RESTORE_INTR(flags); +} + +static int +gus_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ +#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ + SOUND_MASK_SYNTH|SOUND_MASK_PCM) + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = IOCTL_IN(arg) & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC|SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + return IOCTL_OUT (arg, gus_recmask); + break; + + case SOUND_MIXER_MIC: + { + int vol = IOCTL_IN (arg) & 0xff; + if (vol < 0) vol = 0; + if (vol > 100) vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + return IOCTL_OUT (arg, vol | (vol << 8)); + } + break; + + case SOUND_MIXER_LINE: + { + int vol = IOCTL_IN (arg) & 0xff; + if (vol < 0) vol = 0; + if (vol > 100) vol = 100; + gus_line_vol = vol; + set_input_volumes(); + return IOCTL_OUT (arg, vol | (vol << 8)); + } + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = IOCTL_IN (arg) & 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_sampling_update_volume (); + return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + { + int voice; + + gus_wave_volume = IOCTL_IN (arg) & 0xff; + + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + + if (active_device == GUS_DEV_WAVE) + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change (voice); /* + * Apply the new + * volume + */ + + return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); + } + break; + + default: + return RET_ERROR (EINVAL); + } + else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, gus_recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, MIX_DEVS); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, 0); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, SOUND_MASK_MIC|SOUND_MASK_LINE); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, 0); + break; + + case SOUND_MIXER_MIC: + return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8)); + break; + + case SOUND_MIXER_LINE: + return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8)); + break; + + case SOUND_MIXER_PCM: + return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); + break; + + default: + return RET_ERROR (EINVAL); + } + } + else + return RET_ERROR (EINVAL); +} + +static struct mixer_operations gus_mixer_operations = +{ + gus_mixer_ioctl }; long gus_wave_init (long mem_start, int irq, int dma) { - printk (" <Gravis UltraSound %dk>", (int)gus_mem_size / 1024); + printk (" <Gravis UltraSound %dk>", (int) gus_mem_size / 1024); if (irq < 0 || irq > 15) { @@ -2354,8 +3161,8 @@ gus_wave_init (long mem_start, int irq, int dma) else synth_devs[num_synths++] = &guswave_operations; - PERMANENT_MALLOC(struct patch_info*, samples, - (MAX_SAMPLE+1)*sizeof(*samples), mem_start); + PERMANENT_MALLOC (struct patch_info *, samples, + (MAX_SAMPLE + 1) * sizeof (*samples), mem_start); reset_sample_memory (); @@ -2372,6 +3179,12 @@ gus_wave_init (long mem_start, int irq, int dma) else printk ("GUS: Too many PCM devices available\n"); + if (num_mixers < MAX_MIXER_DEV) /* + * Don't install if there is another + * mixer + */ + mixer_devs[num_mixers++] = &gus_mixer_operations; + return mem_start; } @@ -2386,7 +3199,9 @@ do_loop_irq (int voice) gus_select_voice (voice); tmp = gus_read8 (0x00); - tmp &= ~0x20; /* Disable wave IRQ for this_one voice */ + tmp &= ~0x20; /* + * Disable wave IRQ for this_one voice + */ gus_write8 (0x00, tmp); mode = voices[voice].loop_irq_mode; @@ -2396,23 +3211,33 @@ do_loop_irq (int voice) switch (mode) { - case LMODE_FINISH: /* Final loop finished, shoot volume down */ + case LMODE_FINISH: /* + * Final loop finished, shoot volume down + */ - if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */ + if ((gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ { gus_voice_off (); gus_rampoff (); gus_voice_init (voice); - return; + break; } gus_ramp_range (65, 4065); - gus_ramp_rate (0, 63); /* Fastest possible rate */ - gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ + gus_ramp_rate (0, 63); /* + * Fastest possible rate + */ + gus_rampon (0x20 | 0x40); /* + * Ramp down, once, irq + */ voices[voice].volume_irq_mode = VMODE_HALT; break; case LMODE_PCM_STOP: - pcm_active = 0; /* Requires extensive processing */ + pcm_active = 0; /* + * Requires extensive processing + */ case LMODE_PCM: { int orig_qlen = pcm_qlen; @@ -2424,7 +3249,9 @@ do_loop_irq (int voice) play_next_pcm_block (); } else - { /* Out of data. Just stop the voice */ + { /* + * Out of data. Just stop the voice + */ gus_voice_off (); gus_rampoff (); pcm_active = 0; @@ -2454,7 +3281,9 @@ do_volume_irq (int voice) gus_select_voice (voice); tmp = gus_read8 (0x0d); - tmp &= ~0x20; /* Disable volume ramp IRQ */ + tmp &= ~0x20; /* + * Disable volume ramp IRQ + */ gus_write8 (0x0d, tmp); mode = voices[voice].volume_irq_mode; @@ -2463,7 +3292,9 @@ do_volume_irq (int voice) switch (mode) { - case VMODE_HALT: /* Decay phase finished */ + case VMODE_HALT: /* + * Decay phase finished + */ gus_voice_init (voice); break; @@ -2472,6 +3303,19 @@ do_volume_irq (int voice) step_envelope (voice); break; + case VMODE_START_NOTE: + guswave_start_note2 (voices[voice].dev_pending, voice, + voices[voice].note_pending, voices[voice].volume_pending); + if (voices[voice].kill_pending) + guswave_kill_note (voices[voice].dev_pending, voice, 0); + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr (voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; + default:; } @@ -2488,24 +3332,38 @@ gus_voice_irq (void) while (1) { - src = gus_read8 (0x0f); /* Get source info */ + src = gus_read8 (0x0f); /* + * Get source info + */ voice = src & 0x1f; src &= 0xc0; if (src == (0x80 | 0x40)) - return; /* No interrupt */ + return; /* + * No interrupt + */ voice_bit = 1 << voice; - if (!(src & 0x80)) /* Wave IRQ pending */ - if (!(wave_ignore & voice_bit) && voice < nr_voices) /* Not done yet */ + if (!(src & 0x80)) /* + * Wave IRQ pending + */ + if (!(wave_ignore & voice_bit) && voice < nr_voices) /* + * Not done + * yet + */ { wave_ignore |= voice_bit; do_loop_irq (voice); } - if (!(src & 0x40)) /* Volume IRQ pending */ - if (!(volume_ignore & voice_bit) && voice < nr_voices) /* Not done yet */ + if (!(src & 0x40)) /* + * Volume IRQ pending + */ + if (!(volume_ignore & voice_bit) && voice < nr_voices) /* + * Not done + * yet + */ { volume_ignore |= voice_bit; do_volume_irq (voice); @@ -2518,8 +3376,12 @@ guswave_dma_irq (void) { unsigned char status; - status = gus_look8 (0x41); /* Get DMA IRQ Status */ - if (status & 0x40) /* DMA Irq pending */ + status = gus_look8 (0x41); /* + * Get DMA IRQ Status + */ + if (status & 0x40) /* + * DMA Irq pending + */ switch (active_device) { case GUS_DEV_WAVE: @@ -2543,8 +3405,12 @@ guswave_dma_irq (void) default:; } - status = gus_look8 (0x49); /* Get Sampling IRQ Status */ - if (status & 0x40) /* Sampling Irq pending */ + status = gus_look8 (0x49); /* + * Get Sampling IRQ Status + */ + if (status & 0x40) /* + * Sampling Irq pending + */ { DMAbuf_inputintr (gus_devnum); } diff --git a/drivers/sound/sb16_dsp.c b/drivers/sound/sb16_dsp.c index f3f18a1..02040c7 100644 --- a/drivers/sound/sb16_dsp.c +++ b/drivers/sound/sb16_dsp.c @@ -256,7 +256,7 @@ DEB(printk("sb16_dsp_open()\n")); if (!sb16_dsp_ok) { printk ("SB16 Error: SoundBlaster board not installed\n"); - return RET_ERROR(ENODEV); + return RET_ERROR(ENXIO); } if (intr_active) @@ -459,8 +459,16 @@ sb16_dsp_reset (int dev) static void sb16_dsp_halt (int dev) { - sb_dsp_command01(0xd9); - sb_dsp_command01(0xd5); + if (dsp_16bit) + { + sb_dsp_command01(0xd9); + sb_dsp_command01(0xd5); + } + else + { + sb_dsp_command01(0xda); + sb_dsp_command01(0xd0); + } } static void diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h index a088ff0..1cad333 100644 --- a/drivers/sound/sound_config.h +++ b/drivers/sound/sound_config.h @@ -195,7 +195,7 @@ If your card has nonstandard I/O address or IRQ number, change defines #define OFF 0 #define MAX_DSP_DEV 4 -#define MAX_MIXER_DEV 1 +#define MAX_MIXER_DEV 2 #define MAX_SYNTH_DEV 3 #define MAX_MIDI_DEV 4 diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index cf36807..0cc8150 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -280,7 +280,7 @@ sound_open_sw (int dev, struct fileinfo *file) if ((dev >= SND_NDEVS) || (dev < 0)) { printk ("Invalid minor device %d\n", dev); - return RET_ERROR (ENODEV); + return RET_ERROR (ENXIO); } switch (dev & 0x0f) @@ -320,7 +320,7 @@ sound_open_sw (int dev, struct fileinfo *file) default: printk ("Invalid minor device %d\n", dev); - return RET_ERROR (ENODEV); + return RET_ERROR (ENXIO); } sbc_devices[dev].usecount++; @@ -383,12 +383,12 @@ sound_ioctl_sw (int dev, struct fileinfo *file, case SND_DEV_CTL: if (!num_mixers) - return RET_ERROR (ENODEV); + return RET_ERROR (ENXIO); - if (dev >= num_mixers) - return RET_ERROR (ENODEV); + if ((dev >> 4) >= num_mixers) + return RET_ERROR (ENXIO); - return mixer_devs[dev]->ioctl (dev, cmd, arg); + return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg); break; case SND_DEV_SEQ: diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index a41bd9d..ddf7180 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -95,7 +95,7 @@ sound_open (struct inode *inode, struct file *file) if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) { printk ("SoundCard Error: The soundcard system has not been configured\n"); - return RET_ERROR (ENODEV); + return RET_ERROR (ENXIO); } files[dev].mode = 0; @@ -210,6 +210,24 @@ asmlinkage int sys_chdir(const char * filename) return (0); } +asmlinkage int sys_fchdir(unsigned int fd) +{ + struct inode * inode; + struct file * file; + + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) + return -ENOTDIR; + if (!permission(inode,MAY_EXEC)) + return -EACCES; + iput(current->pwd); + current->pwd = inode; + return (0); +} + asmlinkage int sys_chroot(const char * filename) { struct inode * inode; diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 2fabe9b..6eeee46 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -36,6 +36,7 @@ #define ETH_P_IPX 0x8137 /* IPX over DIX */ #define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ +#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ /* Define the Ethernet Broadcast Address (48 bits set to "1"). */ #define ETH_A_BCAST "\377\377\377\377\377\377" diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include/linux/kernel_stat.h diff --git a/include/linux/sbpcd.h b/include/linux/sbpcd.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include/linux/sbpcd.h diff --git a/include/linux/sys.h b/include/linux/sys.h index 78d21a0..cb51d7b 100644 --- a/include/linux/sys.h +++ b/include/linux/sys.h @@ -143,6 +143,7 @@ extern int sys_delete_module(); extern int sys_get_kernel_syms(); /* 130 */ extern int sys_quotactl(); extern int sys_getpgid(); +extern int sys_fchdir(); /* * These are system calls that will be removed at some time diff --git a/include/linux/termios.h b/include/linux/termios.h index 741c24e..85948ec 100644 --- a/include/linux/termios.h +++ b/include/linux/termios.h @@ -237,5 +237,6 @@ struct termios { #define N_TTY 0 #define N_SLIP 1 #define N_MOUSE 2 +#define N_PPP 3 #endif diff --git a/include/linux/tty.h b/include/linux/tty.h index 38fb5d1..12530e7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -78,8 +78,8 @@ struct serial_struct { int xmit_fifo_size; int custom_divisor; int baud_base; - char close_delay; - char reserved_char[3]; + unsigned short close_delay; + char reserved_char[2]; int hub6; int reserved[5]; }; @@ -97,6 +97,8 @@ struct serial_struct { /* * Definitions for async_struct (and serial_struct) flags field */ +#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ #define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ #define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */ #define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ @@ -259,6 +261,9 @@ struct tty_ldisc { char * buf, int nr); int (*ioctl)(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg); + int (*select)(struct tty_struct * tty, struct inode * inode, + struct file * file, int sel_type, + select_table *wait); /* * The following routines are called from below. */ diff --git a/include/linux/ultrasound.h b/include/linux/ultrasound.h index 745e007..40e2443 100644 --- a/include/linux/ultrasound.h +++ b/include/linux/ultrasound.h @@ -84,6 +84,7 @@ #define _GUS_VOICEFADE 0x0d #define _GUS_VOLUME_SCALE 0x0e #define _GUS_VOICEVOL2 0x0f +#define _GUS_VOICE_POS 0x10 /* * GUS API macros @@ -114,5 +115,7 @@ #define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0) #define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0) #define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2)) +#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \ + (p) & 0xffff, ((p) >> 16) & 0xffff) #endif diff --git a/include/linux/unistd.h b/include/linux/unistd.h index 16e05d1..36f4882 100644 --- a/include/linux/unistd.h +++ b/include/linux/unistd.h @@ -139,6 +139,7 @@ #define __NR_get_kernel_syms 130 #define __NR_quotactl 131 #define __NR_getpgid 132 +#define __NR_fchdir 133 extern int errno; diff --git a/kernel/sched.c b/kernel/sched.c index 034fcbc..5374207 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -138,7 +138,7 @@ sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn, sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt, sys_adjtimex, sys_mprotect, sys_sigprocmask, sys_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms, sys_quotactl, -sys_getpgid }; +sys_getpgid, sys_fchdir }; /* So we don't have to do any more manual updating.... */ int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr); diff --git a/kernel/signal.c b/kernel/signal.c index 9616297..a284eea 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -252,7 +252,8 @@ static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned lon if (regs->ss != USER_DS) frame = (unsigned long *) sa->sa_restorer; frame -= 32; - verify_area(VERIFY_WRITE,frame,32*4); + if (verify_area(VERIFY_WRITE,frame,32*4)) + do_exit(SIGSEGV); /* set up the "normal" stack seen by the signal handler (iBCS2) */ put_fs_long(__CODE,frame); put_fs_long(signr, frame+1); diff --git a/kernel/sys.c b/kernel/sys.c index 4a9a446..1327564 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -495,7 +495,7 @@ asmlinkage int sys_getpgid(pid_t pid) struct task_struct * p; if (!pid) - pid = current->pid; + return current->pgrp; for_each_task(p) { if (p->pid == pid) return p->pgrp; diff --git a/kernel/traps.c b/kernel/traps.c index 776dff0..d99817e 100644 --- a/kernel/traps.c +++ b/kernel/traps.c @@ -95,7 +95,7 @@ asmlinkage void alignment_check(void); regs->ds, regs->es, regs->fs, regs->gs); store_TR(i); printk("Pid: %d, process nr: %d\n", current->pid, 0xffff & i); - for(i=0;i<10;i++) + for(i=0;i<20;i++) printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip))); printk("\n"); do_exit(SIGSEGV); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 99845dd..b9cb640 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -53,19 +53,19 @@ static int free_area_pages(unsigned long dindex, unsigned long index, unsigned l return 0; page &= PAGE_MASK; pte = index + (unsigned long *) page; - for ( ; nr > 0 ; nr--, pte++) { + do { unsigned long pg = *pte; *pte = 0; - if (!(pg & PAGE_PRESENT)) - continue; - free_page(pg); - } + if (pg & PAGE_PRESENT) + free_page(pg); + pte++; + } while (--nr); pte = (unsigned long *) page; for (nr = 0 ; nr < 1024 ; nr++, pte++) if (*pte) return 0; set_pgdir(dindex,0); - mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED; + mem_map[MAP_NR(page)] = 1; free_page(page); return 0; } @@ -83,20 +83,21 @@ static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned free_page(page); page = swapper_pg_dir[dindex]; } else { - mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED; + mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED; set_pgdir(dindex, page | PAGE_SHARED); } } page &= PAGE_MASK; pte = index + (unsigned long *) page; *pte = PAGE_SHARED; /* remove a race with vfree() */ - for ( ; nr > 0 ; nr--, pte++) { + do { unsigned long pg = get_free_page(GFP_KERNEL); if (!pg) return -ENOMEM; *pte = pg | PAGE_SHARED; - } + pte++; + } while (--nr); return 0; } @@ -113,9 +114,9 @@ static int do_area(void * addr, unsigned long size, if (i > nr) i = nr; + nr -= i; if (area_fn(dindex, index, i)) return -1; - nr -= i; index = 0; dindex++; } diff --git a/net/inet/dev.c b/net/inet/dev.c index 159e8c4..22002f0 100644 --- a/net/inet/dev.c +++ b/net/inet/dev.c @@ -114,8 +114,12 @@ static struct packet_type arp_packet_type = { &ax25_packet_type #endif #else +#ifdef CONFIG_AX25 + &ax25_packet_type +#else NULL /* next */ #endif +#endif }; @@ -287,22 +291,49 @@ my_addr(void) } +static int dev_nit=0; /* Number of network taps running */ + /* Add a protocol ID to the list. This will change soon. */ void dev_add_pack(struct packet_type *pt) { struct packet_type *p1; - pt->next = ptype_base; - /* See if we need to copy it. */ - for (p1 = ptype_base; p1 != NULL; p1 = p1->next) { - if (p1->type == pt->type) { - pt->copy = 1; - break; + /* Don't use copy counts on ETH_P_ALL. Instead keep a global + count of number of these and use it and pt->copy to decide + copies */ + pt->copy=0; + if(pt->type==NET16(ETH_P_ALL)) + dev_nit++; /* I'd like a /dev/nit too one day 8) */ + else + { + /* See if we need to copy it. */ + for (p1 = ptype_base; p1 != NULL; p1 = p1->next) { + if (p1->type == pt->type) { + pt->copy = 1; + break; + } + } + } + + /* + * NIT taps must go at the end or inet_bh will leak! + */ + + if(pt->type==NET16(ETH_P_ALL)) + { + pt->next=NULL; + if(ptype_base==NULL) + ptype_base=pt; + else + { + for(p1=ptype_base;p1->next!=NULL;p1=p1->next); + p1->next=pt; } } - ptype_base = pt; + else + ptype_base = pt; } @@ -312,6 +343,8 @@ dev_remove_pack(struct packet_type *pt) { struct packet_type *lpt, *pt1; + if (pt->type == NET16(ETH_P_ALL)) + dev_nit--; if (pt == ptype_base) { ptype_base = pt->next; return; @@ -328,7 +361,7 @@ dev_remove_pack(struct packet_type *pt) return; } - if (pt1->next -> type == pt ->type) { + if (pt1->next -> type == pt ->type && pt->type != NET16(ETH_P_ALL)) { lpt = pt1->next; } } @@ -594,7 +627,7 @@ inet_bh(void *tmp) struct packet_type *ptype; unsigned short type; unsigned char flag = 0; - + int nitcount; /* Atomically check and mark our BUSY state. */ if (set_bit(1, (void*)&in_bh)) @@ -606,6 +639,7 @@ inet_bh(void *tmp) /* Any data left to process? */ while((skb=skb_dequeue(&backlog))!=NULL) { + nitcount=dev_nit; flag=0; sti(); /* @@ -625,7 +659,6 @@ inet_bh(void *tmp) * header (the h_proto field in struct ethhdr), but drivers like * SLIP and PLIP have no alternative but to force the type to be * IP or something like that. Sigh- FvK - * FIXME: Ethernet drivers need potty training in 802.3 packets -AC */ type = skb->dev->type_trans(skb, skb->dev); @@ -636,10 +669,12 @@ inet_bh(void *tmp) * to anyone who wants it. */ for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) { - if (ptype->type == type) { + if (ptype->type == type || ptype->type == NET16(ETH_P_ALL)) { struct sk_buff *skb2; - if (ptype->copy) { /* copy if we need to */ + if (ptype->type==NET16(ETH_P_ALL)) + nitcount--; + if (ptype->copy || nitcount) { /* copy if we need to */ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); if (skb2 == NULL) continue; diff --git a/net/inet/ip.c b/net/inet/ip.c index ea1877b..4cd04a4 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -1544,7 +1544,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt sk->ip_tos=val; return 0; case IP_TTL: - if(val<1||val<255) + if(val<1||val>255) return -EINVAL; sk->ip_ttl=val; return 0; diff --git a/net/inet/raw.c b/net/inet/raw.c index 72a4702..3e44d19 100644 --- a/net/inet/raw.c +++ b/net/inet/raw.c @@ -114,7 +114,8 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, /* Now we need to copy this into memory. */ skb->sk = sk; - skb->len = len; + skb->len = len + skb->ip_hdr->ihl*sizeof(long); + skb->h.raw = skb->ip_hdr; skb->dev = dev; skb->saddr = daddr; skb->daddr = saddr; diff --git a/net/inet/sock.c b/net/inet/sock.c index 1781697..d21791d 100644 --- a/net/inet/sock.c +++ b/net/inet/sock.c @@ -51,6 +51,7 @@ * Alan Cox : inet sockets don't set sk->type! * Alan Cox : Split socket option code * Alan Cox : Callbacks + * Alan Cox : Nagle flag for Charles & Johannes stuff * * To Fix: * @@ -824,6 +825,11 @@ inet_create(struct socket *sock, int protocol) return(-ESOCKTNOSUPPORT); } sk->socket = sock; +#ifdef CONFIG_TCP_NAGLE_OFF + sk->nonagle = 1; +#else + sk->nonagle = 0; +#endif sk->type = sock->type; sk->protocol = protocol; sk->wmem_alloc = 0; @@ -1792,6 +1798,8 @@ inet_fioctl(struct inode *inode, struct file *file, } + + static struct file_operations inet_fops = { NULL, /* LSEEK */ NULL, /* READ */ diff --git a/net/inet/sock.h b/net/inet/sock.h index cf8397a..56c3fd8 100644 --- a/net/inet/sock.h +++ b/net/inet/sock.h @@ -81,7 +81,8 @@ struct sock { no_check, exp_growth, zapped, /* In ax25 & ipx means not linked */ - broadcast; + broadcast, + nonagle; unsigned long lingertime; int proc; struct sock *next; diff --git a/net/inet/tcp.c b/net/inet/tcp.c index ade26c8..944f156 100644 --- a/net/inet/tcp.c +++ b/net/inet/tcp.c @@ -57,6 +57,8 @@ * Alan Cox : Added tcp_select_window() aka NET2E * window non shrink trick. * Alan Cox : Added a couple of small NET2E timer fixes + * Charles Hedrick : TCP fixes + * Toomas Tamm : TCP window fixes * * * To Fix: @@ -99,8 +101,6 @@ #include <asm/segment.h> #include <linux/mm.h> -#define USE_NAGLE - #define SEQ_TICK 3 unsigned long seq_offset; @@ -1018,20 +1018,17 @@ tcp_write(struct sock *sk, unsigned char *from, sk->err = 0; /* - * In its original form, the following code implements - * Nagle's rule. Everybody recommends it, and probably - * production code should use it. But it slows down response enough - * that I dont' like it. So as long as we're not bumping into - * the window, I go ahead and send it. If you want Nagle, just - * define USE_NAGLE --C. Hedrick + * Nagles rule. Turn Nagle off with TCP_NODELAY for highly + * interactive fast network servers. It's meant to be on and + * it really improves the throughput though not the echo time + * on my slow slip link - Alan */ /* Avoid possible race on send_tmp - c/o Johannes Stille */ if(sk->send_tmp && ((!sk->packets_out) -#ifndef USE_NAGLE - || before(sk->send_seq , sk->window_seq) -#endif + /* If not nagling we can send on the before case too.. */ + || (sk->nonagle && before(sk->send_seq , sk->window_seq)) )) tcp_send_partial(sk); /* -- */ @@ -1273,7 +1270,6 @@ tcp_read_urg(struct sock * sk, int nonblock, amt = min(ntohs(skb->h.th->urg_ptr),len); if(amt) { - verify_area(VERIFY_WRITE, to, amt); memcpy_tofs(to,(unsigned char *)(skb->h.th) + skb->h.th->doff*4, amt); } @@ -2132,7 +2128,7 @@ tcp_write_xmit(struct sock *sk) return; while(sk->wfront != NULL && - before(sk->wfront->h.seq, sk->window_seq) && + before(sk->wfront->h.seq, sk->window_seq +1) && (sk->retransmits == 0 || sk->timeout != TIME_WRITE || before(sk->wfront->h.seq, sk->rcv_ack_seq +1)) @@ -2395,7 +2391,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len) * and put it onto the xmit queue. */ if (sk->wfront != NULL) { - if (after (sk->window_seq, sk->wfront->h.seq) && + if (after (sk->window_seq+1, sk->wfront->h.seq) && (sk->retransmits == 0 || sk->timeout != TIME_WRITE || before(sk->wfront->h.seq, sk->rcv_ack_seq +1)) @@ -3534,12 +3530,12 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int op switch(optname) { case TCP_MSS: - if(val<200||val>2048) + if(val<200||val>2048 || val>sk->mtu) return -EINVAL; sk->mss=val; return 0; case TCP_NODELAY: - /* Ready for Johannes delayed ACK code */ + sk->nonagle=(val==0)?0:1; return 0; default: return(-ENOPROTOOPT); @@ -3559,7 +3555,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *o val=sk->mss; break; case TCP_NODELAY: - val=1; /* Until Johannes stuff is in */ + val=sk->nonagle; /* Until Johannes stuff is in */ break; default: return(-ENOPROTOOPT); diff --git a/net/inet/tcp.h b/net/inet/tcp.h index cb051e4..4aae2a3 100644 --- a/net/inet/tcp.h +++ b/net/inet/tcp.h @@ -71,47 +71,27 @@ /* * The next routines deal with comparing 32 bit unsigned ints - * and worry about wraparound. The general strategy is to do a - * normal compare so long as neither of the numbers is within - * 4K of wrapping. Otherwise we must check for the wrap. + * and worry about wraparound (automatic with unsigned arithmetic). */ -static inline int -before (unsigned long seq1, unsigned long seq2) +static inline int before(unsigned long seq1, unsigned long seq2) { - /* this inequality is strict. */ - if (seq1 == seq2) return(0); - - if (seq1 < seq2) { - if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL) { - return(1); - } else { - return(0); - } - } - - /* - * Now we know seq1 > seq2. So all we need to do is check - * to see if seq1 has wrapped. - */ - if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL)) { - return(1); - } - return(0); + /* this inequality is strict. */ + if (seq1 == seq2) + return 0; + seq2 -= seq1; + return (seq2 < 65536); } - -static inline int -after(unsigned long seq1, unsigned long seq2) +static inline int after(unsigned long seq1, unsigned long seq2) { - return(before(seq2, seq1)); + return before(seq2, seq1); } /* is s2<=s1<=s3 ? */ -static inline int -between(unsigned long seq1, unsigned long seq2, unsigned long seq3) +static inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3) { - return(after(seq1+1, seq2) && before(seq1, seq3+1)); + return (after(seq1+1, seq2) && before(seq1, seq3+1)); } |