diff -u --recursive --new-file v2.1.116/linux/CREDITS linux/CREDITS --- v2.1.116/linux/CREDITS Tue Aug 18 22:02:01 1998 +++ linux/CREDITS Wed Aug 19 14:37:24 1998 @@ -1193,13 +1193,12 @@ S: Germany N: Michael Meskes -E: meskes@topsystem.de +E: meskes@debian.org P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03 AB AB 15 A3 AE AD 39 7D -D: Kernel hacker. Software watchdog daemon. +D: Kernel hacker. PostgreSQL hacker. Software watchdog daemon. D: Maintainer of several Debian packages -S: topsystem Systemhaus GmbH -S: Europark A2, Adenauerstr. 20 -S: D-52146 Wuerselen +S: Th.-Heuss-Str. 61 +S: D-41812 Erkelenz S: Germany N: Nigel Metheringham @@ -1944,6 +1943,14 @@ S: 4/36 Trevelyan St S: Wayville SA 5034 S: Australia + +N: Clifford Wolf +E: god@clifford.at +W: http://www.clifford.at/ +D: Menuconfig/lxdialog improvement +S: Foehrengasse 16 +S: A-2333 Leopoldsdorf b. Wien +S: Austria N: Roger E. Wolff E: R.E.Wolff@BitWizard.nl diff -u --recursive --new-file v2.1.116/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.116/linux/Documentation/Configure.help Thu Aug 6 14:06:27 1998 +++ linux/Documentation/Configure.help Wed Aug 19 14:37:58 1998 @@ -4354,6 +4354,58 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +AIMSlab RadioTrack (aka RadioReveal) support +CONFIG_RADIO_RTRACK + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-aimslab.o. + +RadioTrack i/o port +CONFIG_RADIO_RTRACK_PORT + Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. + +Aztech/Packard Bell Radio +CONFIG_RADIO_AZTECH + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-aztech.o. + +Aztech/Packard Bell radio card i/o port +CONFIG_RADIO_AZTECH_PORT + Enter either 0x350 or 0x358 here. The card default is 0x350, if you + haven't changed the setting of jumper JP3 on the card. Removing the + jumper sets the card to 0x358. + +SF16FMI Radio +CONFIG_RADIO_SF16FMI + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-sf16fmi.o + +SF16FMI I/O port (0x284 or 0x384) +CONFIG_RADIO_SF16FMI_PORT + Enter the I/O port of your SF16FMI radio card. + LAPB over Ethernet driver CONFIG_LAPBETHER This is a driver for a pseudo device (typically called /dev/lapb0) @@ -9244,6 +9296,10 @@ Choose Y here if you have one of these FM radio cards, and then fill in the port address below. + Note that newer AIMSlab RadioTrack cards have a different chipset, + not supported by this driver. For these cards, use the RadioTrack II + driver below. + In order to control your radio card, you will need to use programs that are compatible with the Video for Linux API. Information on this API and pointers to "v4l" programs may be found on the WWW at @@ -9259,6 +9315,28 @@ RadioTrack i/o port CONFIG_RADIO_RTRACK_PORT Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. + +AIMSlab RadioTrack II support +CONFIG_RADIO_RTRACK2 + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-rtrack2.o. + +RadioTrack II i/o port +CONFIG_RADIO_RTRACK2_PORT + Enter either 0x30c or 0x20c here. The card default is 0x30c, if you haven't changed the jumper setting on the card. Aztech/Packard Bell Radio diff -u --recursive --new-file v2.1.116/linux/Documentation/sound/Soundblaster linux/Documentation/sound/Soundblaster --- v2.1.116/linux/Documentation/sound/Soundblaster Thu Jul 16 18:09:22 1998 +++ linux/Documentation/sound/Soundblaster Wed Aug 19 14:38:12 1998 @@ -7,11 +7,11 @@ The Sound Blaster module takes the following arguments -io I/O address of the Sound Blaster chip -irq IRQ of the Sound Blaster chip -dma 8-bit DMA channel for the Sound Blaster -dma16 16-bit DMA channel for SB16 and equivalent cards -mpu_io I/O for MPU chip if present +io I/O address of the Sound Blaster chip (0x220,0x240,0x260,0x280) +irq IRQ of the Sound Blaster chip (5,7,9,10) +dma 8-bit DMA channel for the Sound Blaster (0,1,3) +dma16 16-bit DMA channel for SB16 and equivalent cards (5,6,7) +mpu_io I/O for MPU chip if present (0x300,0x330) mad16=1 Set when loading this as part of the MAD16 setup only trix=1 Set when loading this as part of the Audiotrix setup only diff -u --recursive --new-file v2.1.116/linux/Makefile linux/Makefile --- v2.1.116/linux/Makefile Tue Aug 18 22:02:01 1998 +++ linux/Makefile Tue Aug 18 22:02:21 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 116 +SUBLEVEL = 117 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.1.116/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.116/linux/arch/i386/kernel/entry.S Tue Aug 18 22:02:02 1998 +++ linux/arch/i386/kernel/entry.S Tue Aug 18 21:26:13 1998 @@ -556,7 +556,13 @@ .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ - - .rept NR_syscalls-187 + + /* + * NOTE!! This doesn' thave to be exact - we just have + * to make sure we have _enough_ of the "sys_ni_syscall" + * entries. Don't panic if you notice that this hasn't + * been shrunk every time we add a new system call. + */ + .rept NR_syscalls-189 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.1.116/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.116/linux/drivers/char/Makefile Mon Aug 3 12:45:45 1998 +++ linux/drivers/char/Makefile Wed Aug 19 14:47:37 1998 @@ -391,6 +391,14 @@ endif endif +ifeq ($(CONFIG_RADIO_RTRACK2),y) +L_OBJS += radio-rtrack2.o +else + ifeq ($(CONFIG_RADIO_RTRACK2),m) + M_OBJS += radio-rtrack2.o + endif +endif + ifeq ($(CONFIG_RADIO_ZOLTRIX),y) L_OBJS += radio-zoltrix.o else diff -u --recursive --new-file v2.1.116/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c --- v2.1.116/linux/drivers/char/adbmouse.c Tue Jun 23 10:01:22 1998 +++ linux/drivers/char/adbmouse.c Wed Aug 19 13:24:42 1998 @@ -144,11 +144,11 @@ } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -156,7 +156,7 @@ static int release_mouse(struct inode *inode, struct file *file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; diff -u --recursive --new-file v2.1.116/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c --- v2.1.116/linux/drivers/char/amigamouse.c Thu Mar 26 15:57:02 1998 +++ linux/drivers/char/amigamouse.c Wed Aug 19 13:24:42 1998 @@ -159,10 +159,10 @@ AMI_MSE_INT_ON(); } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -174,7 +174,7 @@ static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); diff -u --recursive --new-file v2.1.116/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c --- v2.1.116/linux/drivers/char/atarimouse.c Mon Aug 3 12:45:45 1998 +++ linux/drivers/char/atarimouse.c Wed Aug 19 13:24:42 1998 @@ -54,10 +54,10 @@ /* ikbd_mouse_rel_pos(); */ } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -65,7 +65,7 @@ static int release_mouse(struct inode *inode, struct file *file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; ikbd_mouse_disable(); diff -u --recursive --new-file v2.1.116/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c --- v2.1.116/linux/drivers/char/atixlmouse.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/char/atixlmouse.c Wed Aug 19 13:24:42 1998 @@ -95,10 +95,10 @@ ATIXL_MSE_ENABLE_UPDATE(); } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasync); + retval = fasync_helper(fd, filp, on, &mouse.fasync); if (retval < 0) return retval; return 0; @@ -106,7 +106,7 @@ static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ diff -u --recursive --new-file v2.1.116/linux/drivers/char/bt848.h linux/drivers/char/bt848.h --- v2.1.116/linux/drivers/char/bt848.h Tue Jun 9 11:57:28 1998 +++ linux/drivers/char/bt848.h Wed Aug 19 14:47:38 1998 @@ -286,6 +286,10 @@ #define BT848_RISC_COUNT 0x120 #define BT848_GPIO_DATA 0x200 +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_NTBF 0x02 /* Bt848 RISC commands */ diff -u --recursive --new-file v2.1.116/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.116/linux/drivers/char/bttv.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/bttv.c Wed Aug 19 14:47:40 1998 @@ -1888,6 +1888,41 @@ return -EFAULT; return vgrab(btv, &vm); } + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + memset(&vm, 0 , sizeof(vm)); + vm.size=BTTV_MAX_FBUF*2; + vm.frames=2; + vm.offsets[0]=0; + vm.offsets[1]=BTTV_MAX_FBUF; + if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video=btv->video_dev.minor; + vu.vbi=btv->vbi_dev.minor; + if(btv->radio_dev.minor!=-1) + vu.radio=btv->radio_dev.minor; + else + vu.radio=VIDEO_NO_UNIT; + vu.audio=VIDEO_NO_UNIT; + if(btv->have_msp3400) + { + i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, + MSP_GET_UNIT, &vu.audio); + } + vu.teletext=VIDEO_NO_UNIT; + if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; + } + default: return -ENOIOCTLCMD; } @@ -1949,7 +1984,7 @@ bttv_init_done, NULL, 0, - 0 + -1 }; @@ -2054,7 +2089,7 @@ bttv_init_done, NULL, 0, - 0 + -1 }; @@ -2151,7 +2186,7 @@ bttv_init_done, /* just returns 0 */ NULL, 0, - 0 + -1 }; @@ -2979,9 +3014,11 @@ if (btv->bt848_mem) iounmap(btv->bt848_mem); - video_unregister_device(&btv->video_dev); - video_unregister_device(&btv->vbi_dev); - if (radio) + if(btv->video_dev.minor!=-1) + video_unregister_device(&btv->video_dev); + if(btv->vbi_dev.minor!=-1) + video_unregister_device(&btv->vbi_dev); + if (radio && btv->radio_dev.minor != -1) video_unregister_device(&btv->radio_dev); } } diff -u --recursive --new-file v2.1.116/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.1.116/linux/drivers/char/busmouse.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/char/busmouse.c Wed Aug 19 13:24:42 1998 @@ -106,11 +106,11 @@ MSE_INT_ON(); } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -122,7 +122,7 @@ static int close_mouse(struct inode * inode, struct file * file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; MSE_INT_OFF(); diff -u --recursive --new-file v2.1.116/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c --- v2.1.116/linux/drivers/char/dn_keyb.c Mon Aug 3 12:45:45 1998 +++ linux/drivers/char/dn_keyb.c Wed Aug 19 13:24:43 1998 @@ -360,11 +360,11 @@ return count; } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse_fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse_fasyncptr); if (retval < 0) return retval; return 0; @@ -373,7 +373,7 @@ static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse_active) return 0; MSE_UPDATE_OFF(); diff -u --recursive --new-file v2.1.116/linux/drivers/char/macmouse.c linux/drivers/char/macmouse.c --- v2.1.116/linux/drivers/char/macmouse.c Mon Aug 3 12:45:45 1998 +++ linux/drivers/char/macmouse.c Wed Aug 19 13:24:43 1998 @@ -150,11 +150,11 @@ } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -162,7 +162,7 @@ static int release_mouse(struct inode *inode, struct file *file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; diff -u --recursive --new-file v2.1.116/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c --- v2.1.116/linux/drivers/char/msbusmouse.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/char/msbusmouse.c Wed Aug 19 13:24:43 1998 @@ -89,11 +89,11 @@ } } -static int fasync_mouse(struct file *filp, int on) +static int fasync_mouse(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &mouse.fasyncptr); + retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); if (retval < 0) return retval; return 0; @@ -101,7 +101,7 @@ static int release_mouse(struct inode * inode, struct file * file) { - fasync_mouse(file, 0); + fasync_mouse(-1, file, 0); if (--mouse.active) return 0; MS_MSE_INT_OFF(); diff -u --recursive --new-file v2.1.116/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.1.116/linux/drivers/char/msp3400.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/msp3400.c Wed Aug 19 14:47:41 1998 @@ -1070,6 +1070,10 @@ (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c); UNLOCK_I2C_BUS(msp->bus); break; + + case MSP_GET_UNIT: + *iarg = msp->mixer; + break; default: return -EINVAL; diff -u --recursive --new-file v2.1.116/linux/drivers/char/msp3400.h linux/drivers/char/msp3400.h --- v2.1.116/linux/drivers/char/msp3400.h Tue Jun 9 11:57:29 1998 +++ linux/drivers/char/msp3400.h Wed Aug 19 14:47:41 1998 @@ -20,4 +20,6 @@ #define MSP_GET_TREBLE _IOR('m',11,int) #define MSP_SET_TREBLE _IOW('m',12,int) +#define MSP_GET_UNIT _IOR('m',13,int) + #endif /* MSP3400_H */ diff -u --recursive --new-file v2.1.116/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.1.116/linux/drivers/char/pc110pad.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/char/pc110pad.c Wed Aug 19 13:24:43 1998 @@ -474,11 +474,11 @@ -static int fasync_pad(struct file *filp, int on) +static int fasync_pad(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &asyncptr); + retval = fasync_helper(fd, filp, on, &asyncptr); if (retval < 0) return retval; return 0; @@ -490,7 +490,7 @@ */ static int close_pad(struct inode * inode, struct file * file) { - fasync_pad(file, 0); + fasync_pad(-1, file, 0); if (--active) return 0; outb(0x30, current_params.io+2); /* switch off digitiser */ diff -u --recursive --new-file v2.1.116/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v2.1.116/linux/drivers/char/psaux.c Thu Aug 6 14:06:31 1998 +++ linux/drivers/char/psaux.c Wed Aug 19 13:24:43 1998 @@ -105,11 +105,11 @@ return queue->head == queue->tail; } -static int fasync_aux(struct file *filp, int on) +static int fasync_aux(int fd, struct file *filp, int on) { int retval; - retval = fasync_helper(filp, on, &queue->fasync); + retval = fasync_helper(fd, filp, on, &queue->fasync); if (retval < 0) return retval; return 0; @@ -242,7 +242,7 @@ static int release_aux(struct inode * inode, struct file * file) { - fasync_aux(file, 0); + fasync_aux(-1, file, 0); if (--aux_count) return 0; aux_start_atomic(); @@ -390,7 +390,7 @@ { unsigned char status; - fasync_aux(file, 0); + fasync_aux(-1, file, 0); if (!--qp_count) { if (!poll_qp_status()) printk("Warning: Mouse device busy in release_qp()\n"); diff -u --recursive --new-file v2.1.116/linux/drivers/char/radio-aimslab.c linux/drivers/char/radio-aimslab.c --- v2.1.116/linux/drivers/char/radio-aimslab.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/radio-aimslab.c Wed Aug 19 14:47:41 1998 @@ -261,6 +261,7 @@ memset(&v,0, sizeof(v)); v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; v.volume=rt->curvol * 6554; + v.step=6554; strcpy(v.name, "Radio"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; diff -u --recursive --new-file v2.1.116/linux/drivers/char/radio-aztech.c linux/drivers/char/radio-aztech.c --- v2.1.116/linux/drivers/char/radio-aztech.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/radio-aztech.c Wed Aug 19 14:47:41 1998 @@ -218,6 +218,7 @@ else v.mode=VIDEO_SOUND_MONO; v.volume=az->curvol; + v.step=16384; strcpy(v.name, "Radio"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; diff -u --recursive --new-file v2.1.116/linux/drivers/char/radio-rtrack2.c linux/drivers/char/radio-rtrack2.c --- v2.1.116/linux/drivers/char/radio-rtrack2.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/radio-rtrack2.c Wed Aug 19 14:47:41 1998 @@ -158,6 +158,7 @@ memset(&v,0, sizeof(v)); v.flags|=VIDEO_AUDIO_MUTABLE; v.volume=1; + v.step=65535; strcpy(v.name, "Radio"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; diff -u --recursive --new-file v2.1.116/linux/drivers/char/radio-sf16fmi.c linux/drivers/char/radio-sf16fmi.c --- v2.1.116/linux/drivers/char/radio-sf16fmi.c Tue Aug 18 22:02:04 1998 +++ linux/drivers/char/radio-sf16fmi.c Wed Aug 19 14:47:41 1998 @@ -176,6 +176,7 @@ v.flags|=VIDEO_AUDIO_MUTABLE; v.mode=VIDEO_SOUND_MONO; v.volume=fmi->curvol; + v.step=65535; strcpy(v.name, "Radio"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; diff -u --recursive --new-file v2.1.116/linux/drivers/char/radio-zoltrix.c linux/drivers/char/radio-zoltrix.c --- v2.1.116/linux/drivers/char/radio-zoltrix.c Tue Aug 18 22:02:04 1998 +++ linux/drivers/char/radio-zoltrix.c Wed Aug 19 14:47:41 1998 @@ -220,7 +220,8 @@ struct video_audio v; memset(&v, 0, sizeof(v)); v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; - v.volume = rt->curvol * 4095; + v.volume = rt->curvol * 4096; + v.step = 4096; strcpy(v.name, "Radio"); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; diff -u --recursive --new-file v2.1.116/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.116/linux/drivers/char/tty_io.c Tue Aug 18 22:02:04 1998 +++ linux/drivers/char/tty_io.c Wed Aug 19 13:24:43 1998 @@ -128,7 +128,7 @@ static int tty_release(struct inode *, struct file *); static int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); -static int tty_fasync(struct file * filp, int on); +static int tty_fasync(int fd, struct file * filp, int on); #ifdef CONFIG_8xx extern long console_8xx_init(void); extern int rs_8xx_init(void); @@ -409,7 +409,7 @@ continue; if (filp->f_op != &tty_fops) continue; - tty_fasync(filp, 0); + tty_fasync(-1, filp, 0); filp->f_op = &hung_up_tty_fops; } @@ -983,7 +983,7 @@ check_tty_count(tty, "release_dev"); - tty_fasync(filp, 0); + tty_fasync(-1, filp, 0); idx = MINOR(tty->device) - tty->driver.minor_start; pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY && @@ -1352,7 +1352,7 @@ * to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry. */ -int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp) +int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) { struct fasync_struct *fa, **fp; unsigned long flags; @@ -1363,13 +1363,16 @@ } if (on) { - if (fa) + if (fa) { + fa->fa_fd = fd; return 0; + } fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); if (!fa) return -ENOMEM; fa->magic = FASYNC_MAGIC; fa->fa_file = filp; + fa->fa_fd = fd; save_flags(flags); cli(); fa->fa_next = *fapp; @@ -1387,7 +1390,7 @@ return 1; } -static int tty_fasync(struct file * filp, int on) +static int tty_fasync(int fd, struct file * filp, int on) { struct tty_struct * tty; int retval; @@ -1396,7 +1399,7 @@ if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync")) return 0; - retval = fasync_helper(filp, on, &tty->fasync); + retval = fasync_helper(fd, filp, on, &tty->fasync); if (retval <= 0) return retval; diff -u --recursive --new-file v2.1.116/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.116/linux/drivers/net/ppp.c Thu Jul 16 18:09:26 1998 +++ linux/drivers/net/ppp.c Wed Aug 19 10:24:47 1998 @@ -1977,8 +1977,8 @@ */ skb->dev = ppp2dev(ppp); /* We are the device */ skb->protocol = htons(proto); - skb->mac.raw = skb->data; skb_pull(skb, PPP_HDRLEN); /* pull off ppp header */ + skb->mac.raw = skb->data; ppp->last_recv = jiffies; netif_rx (skb); return 1; diff -u --recursive --new-file v2.1.116/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.116/linux/drivers/sound/Config.in Tue Jul 21 00:15:31 1998 +++ linux/drivers/sound/Config.in Wed Aug 19 14:48:29 1998 @@ -205,7 +205,7 @@ dep_tristate 'Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS dep_tristate '6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS - if [ "$CONFIG_UART6850" = "y" ]; then + if [ "$CONFIG_SOUND_UART6850" = "y" ]; then hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi diff -u --recursive --new-file v2.1.116/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.116/linux/drivers/sound/Makefile Thu Aug 6 14:06:33 1998 +++ linux/drivers/sound/Makefile Wed Aug 19 14:48:29 1998 @@ -79,7 +79,7 @@ obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o -obj-$(CONFIG_SOUND_UART6850) += uart6850.c +obj-$(CONFIG_SOUND_UART6850) += uart6850.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_VIDC_SOUND) += vidc_mod.o @@ -91,7 +91,6 @@ endif endif - # Declare multi-part drivers. diff -u --recursive --new-file v2.1.116/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.1.116/linux/drivers/sound/es1370.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/es1370.c Wed Aug 19 14:48:29 1998 @@ -67,6 +67,12 @@ * settings (not sure if this should be standard) * Fixed many references: f_flags should be f_mode * -- Gerald Britton + * 03.08.98 0.11 Now mixer behaviour can basically be selected between + * "OSS documented" and "OSS actual" behaviour + * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se + * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS, + * as it produces an annoying ssssh in the lower sampling rate + * Do not include modversions.h * * some important things missing in Ensoniq documentation: * @@ -91,7 +97,6 @@ #include #include -#include #include #include #include @@ -110,6 +115,10 @@ /* --------------------------------------------------------------------- */ +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif @@ -316,7 +325,7 @@ /* --------------------------------------------------------------------- */ -struct es1370_state *devs = NULL; +static struct es1370_state *devs = NULL; /* --------------------------------------------------------------------- */ @@ -464,10 +473,9 @@ /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 - extern inline void dealloc_dmabuf(struct dmabuf *db) { unsigned long map, mapend; @@ -478,6 +486,7 @@ for (map = MAP_NR(db->rawbuf); map <= mapend; map++) clear_bit(PG_reserved, &mem_map[map].flags); free_pages((unsigned long)db->rawbuf, db->buforder); + printk(KERN_DEBUG "es: freeing dmabuf %8.8lx order %d\n", (unsigned long)db->rawbuf, db->buforder); } db->rawbuf = NULL; db->mapped = db->ready = 0; @@ -502,6 +511,7 @@ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (map = MAP_NR(db->rawbuf); map <= mapend; map++) set_bit(PG_reserved, &mem_map[map].flags); + printk(KERN_DEBUG "es: allocating dmabuf %8.8lx order %d\n", (unsigned long)db->rawbuf, db->buforder); } fmt &= ES1370_FMT_MASK; bytepersec = rate << sample_shift[fmt]; @@ -734,20 +744,22 @@ [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, /* CD */ [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, /* Line */ [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, /* AUX */ - [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 1, 0x0100, 1 }, /* Mono1 */ - [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 1, 0x0200, 1 }, /* Mono2 */ - [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 1, 0x0001, 1 }, /* Mic */ - [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 1, 0x0000, 1 } /* mono out */ + [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, /* Mono1 */ + [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, /* Mono2 */ + [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, /* Mic */ + [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */ }; static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg) { + unsigned long flags; int i, val, j; - unsigned char l, r, rl, rr, sr, sl; + unsigned char l, r, rl, rr; VALIDATE_STATE(s); if (cmd == SOUND_MIXER_PRIVATE1) { + /* enable/disable/query mixer preamp */ get_user_ret(val, (int *)arg, -EFAULT); if (val != -1) { s->mix.micpreamp = !!val; @@ -755,6 +767,34 @@ } return put_user(s->mix.micpreamp, (int *)arg); } + if (cmd == SOUND_MIXER_PRIVATE2) { + /* enable/disable/query use of linein as second lineout */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != -1) { + spin_lock_irqsave(&s->lock, flags); + if (val) + s->ctrl |= CTRL_XCTL0; + else + s->ctrl &= ~CTRL_XCTL0; + outl(s->ctrl, s->io+ES1370_REG_CONTROL); + spin_unlock_irqrestore(&s->lock, flags); + } + return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, (int *)arg); + } + if (cmd == SOUND_MIXER_PRIVATE3) { + /* enable/disable/query microphone impedance setting */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != -1) { + spin_lock_irqsave(&s->lock, flags); + if (val) + s->ctrl |= CTRL_XCTL1; + else + s->ctrl &= ~CTRL_XCTL1; + outl(s->ctrl, s->io+ES1370_REG_CONTROL); + spin_unlock_irqrestore(&s->lock, flags); + } + return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, (int *)arg); + } if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "ES1370", sizeof(info.id)); @@ -842,12 +882,10 @@ l = val & 0xff; if (l > 100) l = 100; - sl = sr = l; if (mixtable[i].stereo) { r = (val >> 8) & 0xff; if (r > 100) r = 100; - sr = r; if (l < 10) { rl = 0x80; l = 0; @@ -881,9 +919,13 @@ r = l = (15 - rl) * 6 + 10; } } - } + } wrcodec(s, mixtable[i].left, rl); - s->mix.vol[mixtable[i].volidx] = ((unsigned int)sr << 8) | sl; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l; +#else + s->mix.vol[mixtable[i].volidx] = val; +#endif return put_user(s->mix.vol[mixtable[i].volidx], (int *)arg); } } @@ -2267,7 +2309,7 @@ goto err_irq; } /* initialize codec registers */ - s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV); + s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); if (joystick[index]) { if (check_region(0x200, JOY_EXTENT)) printk(KERN_ERR "es1370: io port 0x200 in use\n"); @@ -2356,7 +2398,7 @@ while ((s = devs)) { devs = devs->next; - outl(CTRL_SERR_DIS, s->io+ES1370_REG_CONTROL); /* switch everything off */ + outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ synchronize_irq(); free_irq(s->irq, s); diff -u --recursive --new-file v2.1.116/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.1.116/linux/drivers/sound/es1371.c Thu Jul 16 18:09:26 1998 +++ linux/drivers/sound/es1371.c Wed Aug 19 14:48:29 1998 @@ -45,8 +45,9 @@ * should be detected. This results in strange behaviour of some mixer * settings, like master volume and mic. * 08.06.98 0.2 First release using Alan Cox' soundcore instead of miscdevice - * - * + * 03.08.98 0.3 Do not include modversions.h + * Now mixer behaviour can basically be selected between + * "OSS documented" and "OSS actual" behaviour * */ @@ -54,7 +55,6 @@ #include #include -#include #include #include #include @@ -73,6 +73,10 @@ /* --------------------------------------------------------------------- */ +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif @@ -325,6 +329,9 @@ struct { unsigned short codec_id; unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } mix; /* wave stuff */ @@ -373,7 +380,7 @@ /* --------------------------------------------------------------------- */ -struct es1371_state *devs = NULL; +static struct es1371_state *devs = NULL; /* --------------------------------------------------------------------- */ @@ -704,7 +711,7 @@ /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 @@ -982,7 +989,7 @@ SOUND_MASK_PHONEIN }; -static const unsigned char volreg[] = +static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { /* 5 bit stereo */ [SOUND_MIXER_LINE] = 0x10, @@ -1006,6 +1013,8 @@ [SOUND_MIXER_IGAIN] = 0x1e }; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + #define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg) @@ -1093,6 +1102,34 @@ } } +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + /* 5 bit stereo */ + [SOUND_MIXER_LINE] = 1, + [SOUND_MIXER_CD] = 2, + [SOUND_MIXER_VIDEO] = 3, + [SOUND_MIXER_LINE1] = 4, + [SOUND_MIXER_PCM] = 5, + /* 6 bit stereo */ + [SOUND_MIXER_VOLUME] = 6, + [SOUND_MIXER_PHONEOUT] = 7, + /* 6 bit mono */ + [SOUND_MIXER_OGAIN] = 8, + [SOUND_MIXER_PHONEIN] = 9, + /* 4 bit mono but shifted by 1 */ + [SOUND_MIXER_SPEAKER] = 10, + /* 6 bit mono + preamp */ + [SOUND_MIXER_MIC] = 11, + /* 4 bit stereo */ + [SOUND_MIXER_RECLEV] = 12, + /* 4 bit mono */ + [SOUND_MIXER_IGAIN] = 13 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val) { int i; @@ -1295,7 +1332,13 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return mixer_rdch(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) @@ -1324,7 +1367,14 @@ get_user_ret(val, (int *)arg, -EFAULT); if (mixer_wrch(s, i, val)) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return mixer_rdch(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } @@ -2662,7 +2712,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.2 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.3 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2818,11 +2868,7 @@ #ifdef MODULE MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)"); -MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out"); -MODULE_PARM(micz, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(micz, "changes (??) the microphone impedance"); +MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)"); MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver"); diff -u --recursive --new-file v2.1.116/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.116/linux/drivers/sound/gus_wave.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/sound/gus_wave.c Wed Aug 19 14:48:30 1998 @@ -3142,6 +3142,7 @@ return; } + hw_config->slots[4] = gus_devnum; audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */ diff -u --recursive --new-file v2.1.116/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c --- v2.1.116/linux/drivers/sound/lowlevel/aci.c Thu Jul 16 18:09:26 1998 +++ linux/drivers/sound/lowlevel/aci.c Wed Aug 19 14:48:30 1998 @@ -16,6 +16,10 @@ * on the miroSOUND PCM12 card. Support for miro sound cards with * additional ACI functions can easily be added later. * + * / NOTE / When compiling as a module, make sure to load the module + * after loading the mad16 module. The initialisation code expects the + * MAD16 default mixer to be already available. + * * Revision history: * * 1995-11-10 Markus Kuhn @@ -27,6 +31,8 @@ * 1996-05-28 Markus Kuhn * Initialize CS4231A mixer, make ACI first mixer, * use new private mixer API for solo mode. + * 1998-08-04 Ruurd Reitsma + * Small modification to complete modularisation. */ /* @@ -59,10 +65,11 @@ */ #include /* for CONFIG_ACI_MIXER */ +#include #include "lowlevel.h" #include "../sound_config.h" -#include "lowlevel.h" -#ifdef CONFIG_ACI_MIXER + +#if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE) #undef DEBUG /* if defined, produce a verbose report via syslog */ @@ -606,3 +613,17 @@ } #endif + +#if defined(MODULE) + +int init_module(void) { + attach_aci(); + return(0); +} + +void cleanup_module(void) { + unload_aci(); +} + +#endif /* MODULE */ + \ No newline at end of file diff -u --recursive --new-file v2.1.116/linux/drivers/sound/msnd.h linux/drivers/sound/msnd.h --- v2.1.116/linux/drivers/sound/msnd.h Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/msnd.h Wed Aug 19 14:48:30 1998 @@ -24,13 +24,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.h,v 1.6 1998/07/18 00:12:15 andrewtv Exp $ + * $Id: msnd.h,v 1.9 1998/08/06 21:06:14 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_H #define __MSND_H -#define VERSION "0.7.0" +#define VERSION "0.7.2" #define DEFSAMPLERATE DSP_DEFAULT_SPEED #define DEFSAMPLESIZE 8 @@ -236,12 +236,14 @@ #define F_EXT_MIDI_INUSE 7 #define F_INT_MIDI_INUSE 8 #define F_WRITEFLUSH 9 +#define F_HAVEDIGITAL 10 struct wait_queue *writeblock, *readblock; struct wait_queue *writeflush; unsigned long recsrc; int left_levels[16]; int right_levels[16]; + int mixer_mod_count; int calibrate_signal; int sample_size; int sample_rate; diff -u --recursive --new-file v2.1.116/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.1.116/linux/drivers/sound/msnd_pinnacle.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/msnd_pinnacle.c Wed Aug 19 14:48:30 1998 @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.c,v 1.5 1998/07/18 00:12:16 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.8 1998/08/06 21:06:14 andrewtv Exp $ * ********************************************************************/ @@ -396,11 +396,13 @@ static unsigned long set_recsrc(unsigned long recsrc) { + if (dev.recsrc == recsrc) + return dev.recsrc; #ifdef HAVE_NORECSRC - if (recsrc == 0) + else if (recsrc == 0) dev.recsrc = 0; - else #endif + else dev.recsrc ^= recsrc; #ifndef MSND_CLASSIC @@ -416,6 +418,13 @@ msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); } + else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) { + + if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) { + udelay(50); + msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + } + } else { #ifdef HAVE_NORECSRC /* Select no input (?) */ @@ -431,11 +440,27 @@ return dev.recsrc; } +#define set_mixer_info() \ + strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \ + strncpy(info.name, "MultiSound Mixer", sizeof(info.name)); + static int mixer_ioctl(unsigned int cmd, unsigned long arg) { - int val = 0; - - if (((cmd >> 8) & 0xff) == 'M') { + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + set_mixer_info(); + info.modify_counter = dev.mixer_mod_count; + return copy_to_user((void *)arg, &info, sizeof(info)); + } + else if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + set_mixer_info(); + return copy_to_user((void *)arg, &info, sizeof(info)); + } + else if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + else if (((cmd >> 8) & 0xff) == 'M') { + int val = 0; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { @@ -453,6 +478,8 @@ break; } + ++dev.mixer_mod_count; + return put_user(val, (int *)arg); } else { @@ -479,6 +506,8 @@ #else val = SOUND_MASK_LINE | SOUND_MASK_SYNTH; + if (test_bit(F_HAVEDIGITAL, &dev.flags)) + val |= SOUND_MASK_DIGITAL1; #endif break; @@ -1309,7 +1338,14 @@ printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR); calibrate_adc(dev.sample_rate); - set_recsrc(0); +#ifndef MSND_CLASSIC + printk(KERN_INFO LOGNAME ": Setting recording source to Line In\n"); + if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) != 0 || + msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) != 0) { + printk(KERN_DEBUG LOGNAME ": Error setting Line In as recording source\n"); + } + dev.recsrc = SOUND_MASK_LINE; +#endif return 0; } @@ -1342,10 +1378,16 @@ MODULE_PARM (major, "i"); MODULE_PARM (fifosize, "i"); MODULE_PARM (calibrate_signal, "i"); +#ifndef MSND_CLASSIC +MODULE_PARM (digital, "i"); +#endif static int io __initdata = -1; static int irq __initdata = -1; static int mem __initdata = -1; +#ifndef MSND_CLASSIC +static int digital __initdata; +#endif static int fifosize __initdata = DEFFIFOSIZE; static int calibrate_signal __initdata; @@ -1355,13 +1397,24 @@ static int io __initdata = CONFIG_MSNDCLAS_IO; static int irq __initdata = CONFIG_MSNDCLAS_IRQ; static int mem __initdata = CONFIG_MSNDCLAS_MEM; -#else +#else /* Pinnacle/Fiji */ static int io __initdata = CONFIG_MSNDPIN_IO; static int irq __initdata = CONFIG_MSNDPIN_IRQ; static int mem __initdata = CONFIG_MSNDPIN_MEM; +#ifndef CONFIG_MSNDPIN_DIGITAL +# define CONFIG_MSNDPIN_DIGITAL 0 #endif -static int fifosize __initdata = DEFFIFOSIZE; -static int calibrate_signal __initdata; +static int digital __initdata = CONFIG_MSNDPIN_DIGITAL; +#endif /* MSND_CLASSIC */ +#ifndef CONFIG_MSND_FIFOSIZE +# define CONFIG_MSND_FIFOSIZE DEFFIFOSIZE +#endif /* CONFIG_MSND_FIFOSIZE */ +static int fifosize __initdata = CONFIG_MSND_FIFOSIZE; +#ifndef CONFIG_MSND_CALSIGNAL +# define CONFIG_MSND_CALSIGNAL 0 +#endif /* CONFIG_MSND_CALSIGNAL */ +static int +calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL; #ifdef MSND_CLASSIC __initfunc(int msnd_classic_init(void)) @@ -1459,6 +1512,13 @@ dev.recsrc = 0; dev.inc_ref = mod_inc_ref; dev.dec_ref = mod_dec_ref; + +#ifndef MSND_CLASSIC + if (digital) { + set_bit(F_HAVEDIGITAL, &dev.flags); + printk(KERN_INFO LOGNAME ": Digital I/O access enabled\n"); + } +#endif init_waitqueue(&dev.writeblock); init_waitqueue(&dev.readblock); diff -u --recursive --new-file v2.1.116/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.1.116/linux/drivers/sound/opl3.c Thu May 14 19:47:42 1998 +++ linux/drivers/sound/opl3.c Wed Aug 19 14:48:30 1998 @@ -169,7 +169,7 @@ if (devc == NULL) { - printk(KERN_ERR "OPL3: Can't allocate memory for the device control " + printk(KERN_ERR "opl3: Can't allocate memory for the device control " "structure \n "); return 0; } @@ -495,7 +495,7 @@ if (instr->channel < 0) { - printk(KERN_WARNING "OPL3: Initializing voice %d with undefined instrument\n", voice); + printk(KERN_WARNING "opl3: Initializing voice %d with undefined instrument\n", voice); return 0; } @@ -1091,7 +1091,7 @@ if (devc == NULL) { - printk(KERN_ERR "opl3_init: Device control structure not initialized.\n"); + printk(KERN_ERR "opl3: Device control structure not initialized.\n"); return -1; } @@ -1137,16 +1137,15 @@ if (devc->model == 2) { - if (devc->is_opl4) - conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); - else - conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1); + if (devc->is_opl4) + strcpy(devc->fm_info.name, "Yamaha OPL4/OPL3 FM"); + else + strcpy(devc->fm_info.name, "Yamaha OPL3"); devc->v_alloc->max_voice = devc->nr_voice = 18; devc->fm_info.nr_drums = 0; devc->fm_info.synth_subtype = FM_TYPE_OPL3; devc->fm_info.capabilities |= SYNTH_CAP_OPL3; - strcpy(devc->fm_info.name, "Yamaha OPL-3"); for (i = 0; i < 18; i++) { @@ -1160,13 +1159,14 @@ } else { - conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1); + strcpy(devc->fm_info.name, "Yamaha OPL2"); devc->v_alloc->max_voice = devc->nr_voice = 9; devc->fm_info.nr_drums = 0; for (i = 0; i < 18; i++) pv_map[i].ioaddr = devc->left_io; }; + conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1); for (i = 0; i < SBFM_MAXINSTR; i++) devc->i_map[i].channel = -1; @@ -1185,14 +1185,21 @@ int init_module (void) { - printk("YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); + printk(KERN_INFO "YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); if (io != -1) /* User loading pure OPL3 module */ { + if (check_region(io, 4)) + { + printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", io); + return 0; + } if (!opl3_detect(io, NULL)) { return -ENODEV; } me = opl3_init(io, NULL); + request_region(io,4,devc->fm_info.name); + } SOUND_LOCK; return 0; @@ -1202,6 +1209,8 @@ { if (devc) { + if(devc->base) + release_region(devc->base,4); kfree(devc); devc = NULL; sound_unload_synthdev(me); diff -u --recursive --new-file v2.1.116/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.1.116/linux/drivers/sound/sb.h Thu May 14 19:47:42 1998 +++ linux/drivers/sound/sb.h Wed Aug 19 14:48:30 1998 @@ -121,7 +121,7 @@ void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); int sb_dsp_detect (struct address_info *hw_config); -void sb_dsp_init (struct address_info *hw_config); +int sb_dsp_init (struct address_info *hw_config); void sb_dsp_unload(struct address_info *hw_config); int sb_mixer_init(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); diff -u --recursive --new-file v2.1.116/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.1.116/linux/drivers/sound/sb_card.c Thu May 14 19:47:42 1998 +++ linux/drivers/sound/sb_card.c Wed Aug 19 14:48:30 1998 @@ -25,7 +25,8 @@ void attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) - sb_dsp_init(hw_config); + if(!sb_dsp_init(hw_config)) + hw_config->slots[0] = -1; #endif } @@ -41,7 +42,8 @@ void unload_sb(struct address_info *hw_config) { - sb_dsp_unload(hw_config); + if(hw_config->slots[0]!=-1) + sb_dsp_unload(hw_config); } int sb_be_quiet=0; @@ -92,7 +94,7 @@ { if (io == -1 || dma == -1 || irq == -1) { - printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); + printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); return -EINVAL; } config.io_base = io; @@ -104,6 +106,9 @@ if (!probe_sb(&config)) return -ENODEV; attach_sb_card(&config); + + if(config.slots[0]==-1) + return -ENODEV; #ifdef CONFIG_MIDI config_mpu.io_base = mpu_io; if (mpu_io && probe_sbmpu(&config_mpu)) diff -u --recursive --new-file v2.1.116/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.116/linux/drivers/sound/sb_common.c Thu Jul 16 18:09:27 1998 +++ linux/drivers/sound/sb_common.c Wed Aug 19 14:48:30 1998 @@ -162,7 +162,7 @@ break; default: - /* printk( "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ ; } } @@ -242,7 +242,7 @@ if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) { - printk(KERN_ERR "sb16: Invalid 8 bit DMA (%d)\n", devc->dma8); + printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); return 0; } bits = (1 << devc->dma8); @@ -298,7 +298,7 @@ ival = 8; break; default: - printk(KERN_ERR "SB16 IRQ%d is not possible\n", level); + printk(KERN_ERR "SB16: Invalid IRQ%d\n", level); return 0; } sb_setmixer(devc, IRQ_NR, ival); @@ -694,7 +694,7 @@ return 1; } -void sb_dsp_init(struct address_info *hw_config) +static int sb_dsp_init(struct address_info *hw_config) { sb_devc *devc; char name[100]; @@ -710,7 +710,7 @@ if (detected_devc == NULL) { MDB(printk("No detected device\n")); - return; + return 0; } devc = detected_devc; detected_devc = NULL; @@ -718,7 +718,7 @@ if (devc->base != hw_config->io_base) { DDB(printk("I/O port mismatch\n")); - return; + return 0; } /* * Now continue initialization of the device @@ -731,7 +731,7 @@ if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0) { printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); - return; + return 0; } devc->irq_ok = 0; @@ -739,7 +739,7 @@ if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ { free_irq(devc->irq, devc); - return; + return 0; } if ((devc->type == 0 || devc->type == MDL_ESS) && devc->major == 3 && devc->minor == 1) @@ -853,7 +853,11 @@ else devc->dma16 = hw_config->dma2; - sb16_set_dma_hw(devc); + if(!sb16_set_dma_hw(devc)) { + free_irq(devc->irq, devc); + return 0; + } + devc->caps |= SB_NO_MIDI; } @@ -903,7 +907,7 @@ { if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) { - printk(KERN_WARNING "SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); + printk(KERN_WARNING "Sound Blaster: Can't allocate 8 bit DMA channel %d\n", devc->dma8); } if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) { @@ -917,6 +921,7 @@ { MDB(printk("Sound Blaster: no audio devices found.\n")); } + return 1; } void sb_dsp_disable_midi(int io_base) @@ -1160,7 +1165,9 @@ tmp = 1; /* MPU enabled without interrupts */ - switch (hw_config->irq) + /* May be shared: if so the value is -ve */ + + switch(abs(hw_config->irq)) { case 9: tmp = 0x4; diff -u --recursive --new-file v2.1.116/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.116/linux/drivers/sound/sequencer.c Thu Jul 16 18:09:27 1998 +++ linux/drivers/sound/sequencer.c Wed Aug 19 14:48:30 1998 @@ -1061,7 +1061,10 @@ setup_mode2(); } if (!max_synthdev && !max_mididev) + { + sequencer_busy=0; return -ENXIO; + } synth_open_mask = 0; diff -u --recursive --new-file v2.1.116/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.1.116/linux/drivers/sound/sonicvibes.c Thu Jul 16 18:09:27 1998 +++ linux/drivers/sound/sonicvibes.c Wed Aug 19 14:48:30 1998 @@ -43,6 +43,9 @@ * Fix hwptr out of bounds (now mpg123 works) * 14.05.98 0.4 Don't allow excessive interrupt rates * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice + * 03.08.98 0.6 Do not include modversions.h + * Now mixer behaviour can basically be selected between + * "OSS documented" and "OSS actual" behaviour * */ @@ -50,7 +53,6 @@ #include #include -#include #include #include #include @@ -71,6 +73,10 @@ /* --------------------------------------------------------------------- */ +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_S3 #define PCI_VENDOR_ID_S3 0x5333 #endif @@ -245,6 +251,9 @@ /* mixer stuff */ struct { unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } mix; /* wave stuff */ @@ -471,6 +480,7 @@ unsigned long flags; unsigned char r, m, n; unsigned xm, xn, xr, xd, metric = ~0U; + /* the warnings about m and n used uninitialized are bogus and may safely be ignored */ if (rate < 625000/ADCMULT) rate = 625000/ADCMULT; @@ -619,10 +629,9 @@ /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 - static void dealloc_dmabuf(struct dmabuf *db) { unsigned long map, mapend; @@ -885,6 +894,8 @@ [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 } }; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + static int return_mixval(struct sv_state *s, unsigned i, int *arg) { unsigned long flags; @@ -928,6 +939,23 @@ return put_user((rr << 8) | rl, arg); } +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + [SOUND_MIXER_RECLEV] = 1, + [SOUND_MIXER_LINE1] = 2, + [SOUND_MIXER_CD] = 3, + [SOUND_MIXER_LINE] = 4, + [SOUND_MIXER_MIC] = 5, + [SOUND_MIXER_SYNTH] = 6, + [SOUND_MIXER_LINE2] = 7, + [SOUND_MIXER_VOLUME] = 8, + [SOUND_MIXER_PCM] = 9 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + static unsigned mixer_recmask(struct sv_state *s) { unsigned long flags; @@ -1022,7 +1050,13 @@ i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) @@ -1116,7 +1150,14 @@ break; } spin_unlock_irqrestore(&s->lock, flags); +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } @@ -2200,7 +2241,10 @@ #define NR_DEVICE 5 static int reverb[NR_DEVICE] = { 0, }; + +#if 0 static int wavetable[NR_DEVICE] = { 0, }; +#endif static unsigned dmaio = 0xac00; @@ -2234,7 +2278,7 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.5 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.6 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); @@ -2297,7 +2341,6 @@ /* hack */ pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ - if (check_region(s->ioenh, SV_EXTENT_ENH)) { printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); goto err_region5; @@ -2328,8 +2371,8 @@ udelay(50); outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */ udelay(50); - outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE | SV_CCTRL_REVERB*/, - s->ioenh + SV_CODEC_CONTROL); + outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */ + | (reverb[index] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL); inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */ wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */ wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */ @@ -2412,9 +2455,11 @@ #ifdef MODULE MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(reverb, "if 1 enables joystick interface (still need separate driver)"); +MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM"); +#if 0 MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(wavetable, "if 1 the LINE input is converted to LINE out"); +MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled"); +#endif MODULE_PARM(dmaio, "i"); MODULE_PARM_DESC(dmaio, "if the motherboard BIOS did not allocate DDMA io, allocate them starting at this address"); diff -u --recursive --new-file v2.1.116/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.116/linux/drivers/sound/soundcard.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/sound/soundcard.c Wed Aug 19 14:48:30 1998 @@ -846,12 +846,16 @@ #ifdef MODULE +int traceinit = 0; +MODULE_PARM(traceinit, "i"); + int init_module(void) { int err; int ints[21]; int i; + trace_init=traceinit; /* * "sound=" command line handling by Harald Milz. */ diff -u --recursive --new-file v2.1.116/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.1.116/linux/drivers/sound/wavfront.c Sun Jul 26 11:57:17 1998 +++ linux/drivers/sound/wavfront.c Wed Aug 19 14:48:31 1998 @@ -1,8 +1,8 @@ -/* - * sound/wavefront.c +/* -*- linux-c -*- * - * A low level driver for Turtle Beach WaveFront Series - * (Maui, Tropez, Tropez Plus, and perhaps the Monterey & Rio) + * sound/wavfront.c + * + * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus) * * This driver supports the onboard wavetable synthesizer (an ICS2115), * including patch, sample and program loading and unloading, conversion @@ -26,18 +26,6 @@ * This chip also controls the configuration of the card: the wavefront * synth is logical unit 4. * - * NOTE: this driver has been written to support multiple WaveFront - * cards, but without using PnP to configure the CS4232, all of them - * would end up with the same configuration. Further, the current - * module loading interface doesn't permit this, since it only allows - * once instance of a module (which happens to be equivalent to a - * single hardware configuration) to be installed at one time.In - * addition, there is a hard limit on the available DMA channels that - * also makes installing more than 1 card limited to purely MIDI/synth - * activities on the second card. Still, the coding style gets rid of - * virtually all globals, which I believe is a better way to code - * device drivers (or anything else, for that matter). - * ********************************************************************** * * Copyright (C) by Paul Barton-Davis 1998 @@ -61,9 +49,12 @@ * aspects of configuring a WaveFront soundcard, particularly the * effects processor. * + * $Id: wavfront.c,v 0.4 1998/07/22 02:12:11 pbd Exp $ + * * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. */ + * for more info. + */ #include #include @@ -78,23 +69,26 @@ #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT #include "midi_synth.h" -#define COPY_FROM_USER(a,b,c) copy_from_user ((a),(b),(c)) -#define COPY_TO_USER(a,b,c) copy_to_user ((a),(b),(c)) +/* This thing is meant to work as a module */ -#if defined(CONFIG_SOUND_WAVEFRONT) || defined(CONFIG_SOUND_WAVEFRONT_MODULE) +#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE) -/* This thing is meant to work as a module */ +/* if WF_DEBUG not defined, no run-time debugging messages will + be available via the debug flag setting. Given the current + beta state of the driver, this will remain set until a future + version. +*/ -#ifdef MODULE +#define WF_DEBUG 1 /* bitmasks for WaveFront status port value */ #define STAT_INTR_WRITE 0x40 #define STAT_CAN_WRITE 0x20 -#define STAT_RINTR_ENABLED 0x10 +#define STAT_WINTR_ENABLED 0x10 #define STAT_INTR_READ 0x04 #define STAT_CAN_READ 0x02 -#define STAT_WINTR_ENABLED 0x01 +#define STAT_RINTR_ENABLED 0x01 /*** Module-accessible parameters ***************************************/ @@ -111,7 +105,7 @@ operation, whatever that means. */ -int wf_debug_default = 0; /* you can set this to control debugging +int debug_default = 0; /* you can set this to control debugging during driver loading. it takes any combination of the WF_DEBUG_* flags defined in wavefront.h @@ -119,27 +113,33 @@ /* XXX this needs to be made firmware and hardware version dependent */ -char *wf_ospath = "/etc/sound/wavefront.os"; /* where to find a processed - version of the WaveFront OS - */ - -/* These three don't need to be messed with unless you're trying to - tweak the driver for optimal I/O performance. Read wavefront_wait() - and wavefront_sleep() to see what they do. You may need or want to - tweak them for CPU's different than the 486/66Mhz that I run on. -*/ - -int wf_short_wait_count = 5000; /* loops, CPU dependent */ -int wf_sleep_interval = 50; /* HZ/wf_sleep_interval seconds per sleep */ -int wf_sleep_tries = 100; /*2sec*/ /* number of times we'll try to sleep */ +char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed + version of the WaveFront OS + */ + +int sleep_interval = 100; /* HZ/sleep_interval seconds per sleep */ +int sleep_tries = 50; /* number of times we'll try to sleep */ + +int wait_usecs = 150; /* This magic number seems to give pretty optimal + throughput based on my limited experimentation. + If you want to play around with it and find a better + value, be my guest. Remember, the idea is to + get a number that causes us to just busy wait + for as many WaveFront commands as possible, without + coming up with a number so large that we hog the + whole CPU. + + Specifically, with this number, out of about 134,000 + status waits, only about 250 result in a sleep. + */ MODULE_PARM(wf_raw,"i"); MODULE_PARM(fx_raw,"i"); -MODULE_PARM(wf_debug_default,"i"); -MODULE_PARM(wf_ospath,"s"); -MODULE_PARM(wf_short_wait_count,"i"); -MODULE_PARM(wf_sleep_interval,"i"); -MODULE_PARM(wf_sleep_tries,"i"); +MODULE_PARM(debug_default,"i"); +MODULE_PARM(sleep_interval,"i"); +MODULE_PARM(sleep_tries,"i"); +MODULE_PARM(wait_usecs,"i"); +MODULE_PARM(ospath,"s"); /***************************************************************************/ @@ -150,9 +150,7 @@ static int (*midi_load_patch) (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; - typedef struct wf_config { - int installed; /* well, is it ? note: doesn't mean "working" */ int devno; /* device number from kernel */ int irq; /* "you were one, one of the few ..." */ int base; /* low i/o port address */ @@ -185,7 +183,7 @@ volatile int irq_ok; /* set by interrupt handler */ int opened; /* flag, holds open(1) mode */ char debug; /* debugging flags */ - unsigned int freemem; /* installed RAM, in bytes */ + int freemem; /* installed RAM, in bytes */ int synthdev; /* OSS minor devnum for synth */ int mididev; /* OSS minor devno for internal MIDI */ int ext_mididev; /* OSS minor devno for external MIDI */ @@ -198,9 +196,20 @@ int samples_used; /* how many */ char interrupts_on; /* h/w MPU interrupts enabled ? */ char rom_samples_rdonly; /* can we write on ROM samples */ + struct wait_queue *interrupt_sleeper; +#ifdef WF_STATS + unsigned long status_found_during_loop; + unsigned long status_found_during_sleep[4]; +#endif WF_STATS + } wf_config; -static wf_config wfs[WAVEFRONT_MAX_DEVICES]; +/* Note: because this module doesn't export any symbols, this really isn't + a global variable, even if it looks like one. I was quite confused by + this when I started writing this as a (newer) module -- pbd. +*/ + +static wf_config wavefront_configuration; #define wavefront_status(hw) (inb (hw->status_port)) @@ -210,14 +219,6 @@ static int wffx_init (struct wf_config *hw); static int wavefront_delete_sample (struct wf_config *hw, int sampnum); -static volatile int irq2hw[17] = -{-1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; - -static volatile int dev2hw[17] = -{-1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; - typedef struct { int cmd; char *action; @@ -304,25 +305,10 @@ { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", 32, 0, 0 }, + { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, { 0x00 } }; -wf_config * -hw_from_dev (int dev) - -{ - int i; - - if ((i = dev2hw[dev]) == -1) { - printk (KERN_ERR - "WaveFront: no hardware associated with device %d.\n", - dev); - return 0; - } - - return &wfs[i]; -} - static const char * wavefront_errorstr (int errnum) @@ -370,21 +356,35 @@ { int i; + static int short_loop_cnt = 0; - for (i = 0; i < wf_short_wait_count; i++) { + if (short_loop_cnt == 0) { + short_loop_cnt = (int) (((double) wait_usecs / 1000000.0) * + (double) current_cpu_data.loops_per_sec); + } + + for (i = 0; i < short_loop_cnt; i++) { if (wavefront_status(hw) & mask) { +#ifdef WF_STATS + hw->status_found_during_loop++; +#endif WF_STATS return 1; } } - for (i = 0; i < wf_sleep_tries; i++) { + for (i = 0; i < sleep_tries; i++) { if (wavefront_status(hw) & mask) { +#ifdef WF_STATS + if (i < 4) { + hw->status_found_during_sleep[i]++; + } +#endif WF_STATS return 1; } - if (wavefront_sleep (hw, HZ/wf_sleep_interval)) { - return 0; + if (wavefront_sleep (hw, HZ/sleep_interval)) { + return (0); } } @@ -397,23 +397,30 @@ if (wavefront_wait (hw, STAT_CAN_READ)) return inb (hw->data_port); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: read timeout.\n"); } +#endif WF_DEBUG + return -1; } static int wavefront_write (wf_config *hw, unsigned char data) + { if (wavefront_wait (hw, STAT_CAN_WRITE)) { outb (data, hw->data_port); return 1; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: write timeout.\n"); } +#endif WF_DEBUG + return 0; } @@ -444,60 +451,74 @@ rbuf = 0; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "Wavefront: 0x%x [%s] (%d,%d,%d)\n", cmd, wfcmd->action, wfcmd->read_cnt, wfcmd->write_cnt, wfcmd->need_ack); } +#endif WF_DEBUG if (!wavefront_write (hw, cmd)) { +#ifdef WF_DEBUG if (hw->debug & (WF_DEBUG_IO|WF_DEBUG_CMD)) { printk (KERN_DEBUG "WaveFront: cannot request " "0x%x [%s].\n", cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } if (wfcmd->write_cnt > 0) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: writing %d bytes " "for 0x%x\n", wfcmd->write_cnt, cmd); } +#endif WF_DEBUG for (i = 0; i < wfcmd->write_cnt; i++) { if (!wavefront_write (hw, wbuf[i])) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: bad write for byte %d of 0x%x [%s].\n", i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: write[%d] = 0x%x\n", i, wbuf[i]); +#endif WF_DEBUG } } } if (wfcmd->read_cnt > 0) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: reading %d ints " "for 0x%x\n", wfcmd->read_cnt, cmd); } +#endif WF_DEBUG for (i = 0; i < wfcmd->read_cnt; i++) { if ((c = wavefront_read(hw)) == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: bad read for byte %d of 0x%x [%s].\n", i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -505,12 +526,14 @@ if (c == 0xff) { if ((c = wavefront_read (hw)) == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: bad read for error byte at " "read byte %d of 0x%x [%s].\n", i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -519,7 +542,7 @@ if (c == 1 && wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { rbuf[0] = WF_ST_EMPTY; - return 0; + return (0); } else if (c == 3 && wfcmd->cmd == WFC_UPLOAD_PATCH) { @@ -533,6 +556,7 @@ } else { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: error %d (%s) during " @@ -542,6 +566,7 @@ wavefront_errorstr (c), i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -549,20 +574,24 @@ rbuf[i] = c; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: read[%d] = 0x%x\n", i, rbuf[i]); } +#endif WF_DEBUG } } if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "WaveFront: reading ACK for 0x%x\n", cmd); } +#endif WF_DEBUG /* Some commands need an ACK, but return zero instead of the standard value. @@ -574,11 +603,13 @@ if (ack != WF_ACK) { if (ack == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: cannot read ack for 0x%x [%s].\n", cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } else { @@ -587,14 +618,17 @@ if (ack == 0xff) { /* explicit error */ if ((err = wavefront_read (hw)) == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: cannot read err for 0x%x [%s].\n", cmd, wfcmd->action); } +#endif WF_DEBUG } } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: 0x%x [%s] " @@ -602,22 +636,27 @@ cmd, wfcmd->action, ack, err, wavefront_errorstr (err)); } +#endif WF_DEBUG return -err; } } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: ack received " "for 0x%x [%s]\n", cmd, wfcmd->action); } +#endif WF_DEBUG } else { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "Wavefront: 0x%x [%s] does not need " "ACK (%d,%d,%d)\n", cmd, wfcmd->action, wfcmd->read_cnt, wfcmd->write_cnt, wfcmd->need_ack); +#endif WF_DEBUG } } @@ -795,7 +834,7 @@ WF_MAX_SAMPLE - hw->samples_used); - return 0; + return (0); } @@ -826,6 +865,7 @@ printk (KERN_ERR "WaveFront: upload patch " "error 0x%x\n", x); hw->patch_status[i] = 0; + return 1; } } @@ -843,7 +883,7 @@ printk (KERN_INFO "WaveFront: %d patch slots filled, %d in use\n", cnt, cnt2); - return 0; + return (0); } static int @@ -889,7 +929,7 @@ printk (KERN_INFO "WaveFront: %d programs slots in use\n", cnt); - return 0; + return (0); } static int @@ -900,10 +940,12 @@ unsigned char buf[WF_PATCH_BYTES+2]; unsigned char *bptr; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: downloading patch %d\n", header->number); } +#endif WF_DEBUG hw->patch_status[header->number] |= WF_SLOT_FILLED; @@ -913,10 +955,10 @@ if (wavefront_cmd (hw, WFC_DOWNLOAD_PATCH, 0, buf)) { printk (KERN_ERR "WaveFront: download patch failed\n"); - return -EIO; + return -(EIO); } - return 0; + return (0); } static int @@ -927,10 +969,12 @@ unsigned char buf[WF_PROGRAM_BYTES+1]; int i; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: downloading program %d\n", header->number); } +#endif WF_DEBUG hw->prog_status[header->number] = WF_SLOT_USED; @@ -954,10 +998,10 @@ if (wavefront_cmd (hw, WFC_DOWNLOAD_PROGRAM, 0, buf)) { printk (KERN_WARNING "WaveFront: download patch failed\n"); - return -EIO; + return -(EIO); } - return 0; + return (0); } static int @@ -1004,6 +1048,7 @@ int skip = 0; int initial_skip = 0; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: sample %sdownload for slot %d, " "type %d, %d bytes from 0x%x\n", @@ -1011,6 +1056,7 @@ header->number, header->subkey, header->size, (int) header->dataptr); } +#endif WF_DEBUG if (header->size) { @@ -1032,10 +1078,9 @@ or theoretically some other configuration) is the responsibility of the user level library. - To try to do this in the kernel would be a little crazy: - we'd need 24 * 512 bytes (12K) of kernel space just to - hold copies of the original sample headers; the whole - patch/program/sample header data is about 158K!!! + To try to do this in the kernel would be a little + crazy: we'd need 158K of kernel space just to hold + a copy of the patch/program/sample header data. */ if (hw->rom_samples_rdonly) { @@ -1073,7 +1118,7 @@ printk (KERN_ERR "WaveFront: channel selection only possible " "on 16-bit samples"); - return -EINVAL; + return -(EINVAL); } } @@ -1108,11 +1153,13 @@ break; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: channel selection: %d => " "initial skip = %d, skip = %d\n", WF_GET_CHANNEL (&header->hdr.s), initial_skip, skip); } +#endif WF_DEBUG /* Be safe, and zero the "Unused" bits ... */ @@ -1153,7 +1200,7 @@ /* This one is truly weird. What kind of weirdo decided that in a system dominated by 16- and 32-bit integers, they would use - a 12-bit transfer size ? + just 12 bits ? */ shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); @@ -1171,7 +1218,7 @@ 0, sample_hdr)) { printk (KERN_WARNING "WaveFront: sample %sdownload refused.\n", header->size ? "" : "header "); - return -EIO; + return -(EIO); } if (header->size == 0) { @@ -1197,7 +1244,7 @@ if (wavefront_cmd (hw, WFC_DOWNLOAD_BLOCK, 0, 0)) { printk (KERN_WARNING "WaveFront: download block " "request refused.\n"); - return -EIO; + return -(EIO); } for (i = 0; i < blocksize; i++) { @@ -1207,7 +1254,7 @@ get_user (sample_short, dataptr); dataptr += skip; - if (data_is_unsigned) { + if (data_is_unsigned) { /* GUS ? */ if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { @@ -1255,12 +1302,12 @@ if (dma_ack == -1) { printk (KERN_ERR "WaveFront: upload sample " "DMA ack timeout\n"); - return -EIO; + return -(EIO); } else { printk (KERN_ERR "WaveFront: upload sample " "DMA ack error 0x%x\n", dma_ack); - return -EIO; + return -(EIO); } } } @@ -1272,7 +1319,7 @@ */ sent: - return 0; + return (0); } static int @@ -1282,12 +1329,14 @@ { unsigned char alias_hdr[WF_ALIAS_BYTES]; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: download alias, %d is " "alias for %d\n", header->number, header->hdr.a.OriginalSample); } +#endif WF_DEBUG munge_int32 (header->number, &alias_hdr[0], 2); munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); @@ -1304,12 +1353,12 @@ if (wavefront_cmd (hw, WFC_DOWNLOAD_SAMPLE_ALIAS, 0, alias_hdr)) { printk (KERN_ERR "WaveFront: download alias failed.\n"); - return -EIO; + return -(EIO); } hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); - return 0; + return (0); } static int @@ -1330,17 +1379,21 @@ num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: multi %d with %d=%d samples\n", header->number, header->hdr.ms.NumberOfSamples, num_samples); } +#endif WF_DEBUG for (i = 0; i < num_samples; i++) { +#ifdef WF_DEBUG if ((hw->debug & (WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA)) == (WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA)) { printk (KERN_DEBUG "WaveFront: sample[%d] = %d\n", i, header->hdr.ms.SampleNumber[i]); } +#endif WF_DEBUG munge_int32 (header->hdr.ms.SampleNumber[i], &msample_hdr[3+(i*2)], 2); } @@ -1354,12 +1407,12 @@ (unsigned char *) ((num_samples*2)+3), msample_hdr)) { printk (KERN_ERR "WaveFront: download of multisample failed.\n"); - return -EIO; + return -(EIO); } hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); - return 0; + return (0); } static int @@ -1375,13 +1428,15 @@ if (wavefront_cmd (hw, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { printk (KERN_ERR "WaveFront: upload multisample failed.\n"); - return -EIO; + return -(EIO); } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: msample %d has %d samples\n", header->number, log_ns[0]); } +#endif WF_DEBUG header->hdr.ms.NumberOfSamples = log_ns[0]; @@ -1395,26 +1450,28 @@ if ((d[0] = wavefront_read (hw)) == -1) { printk (KERN_ERR "WaveFront: upload multisample failed " "during sample loop.\n"); - return -EIO; + return -(EIO); } if ((d[1] = wavefront_read (hw)) == -1) { printk (KERN_ERR "WaveFront: upload multisample failed " "during sample loop.\n"); - return -EIO; + return -(EIO); } header->hdr.ms.SampleNumber[i] = demunge_int32 ((unsigned char *) d, 2); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: msample " "sample[%d] = %d\n", i, header->hdr.ms.SampleNumber[i]); } +#endif WF_DEBUG } - return 0; + return (0); } @@ -1426,12 +1483,14 @@ wavefront_drum *drum = &header->hdr.d; int i; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: downloading edrum for MIDI " "note %d, patch = %d\n", header->number, drum->PatchNumber); } +#endif WF_DEBUG drumbuf[0] = header->number & 0x7f; @@ -1441,10 +1500,10 @@ if (wavefront_cmd (hw, WFC_DOWNLOAD_EDRUM_PROGRAM, 0, drumbuf)) { printk (KERN_ERR "WaveFront: download drum failed.\n"); - return -EIO; + return -(EIO); } - return 0; + return (0); } static int @@ -1468,7 +1527,7 @@ { int i; - for (i = 0; i < WF_MAX_SAMPLE; i++) { + for (i = 0; i < WF_MAX_PATCH; i++) { if (!(hw->patch_status[i] & WF_SLOT_FILLED)) { return i; } @@ -1522,7 +1581,7 @@ /* Copy in the header of the GUS patch */ sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; - COPY_FROM_USER (&((char *) &guspatch)[offs], + copy_from_user (&((char *) &guspatch)[offs], &(addr)[offs], sizeof_patch - offs); if ((i = wavefront_find_free_patch (hw)) == -1) { @@ -1656,19 +1715,15 @@ int offs, int count, int pmgr_flag) { - struct wf_config *hw; + struct wf_config *hw = &wavefront_configuration; wavefront_patch_info header; - if ((hw = hw_from_dev (dev)) == 0) { - return -EINVAL; - } - if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */ if (midi_load_patch == NULL) { printk (KERN_ERR "WaveFront: SYSEX not loadable: " "no midi patch loader!\n"); - return -EINVAL; + return -(EINVAL); } return midi_load_patch (dev, format, addr, offs, count, pmgr_flag); @@ -1679,12 +1734,12 @@ } else if (format != WAVEFRONT_PATCH) { printk (KERN_ERR "WaveFront: unknown patch format %d\n", format); - return -EINVAL; + return -(EINVAL); } if (count < sizeof (wavefront_patch_info)) { printk (KERN_ERR "WaveFront: sample header too short\n"); - return -EINVAL; + return -(EINVAL); } /* copied in so far: `offs' bytes from `addr'. We shouldn't copy @@ -1694,10 +1749,11 @@ through the 'hdrptr' field. */ - COPY_FROM_USER (&((char *) &header)[offs], &(addr)[offs], + copy_from_user (&((char *) &header)[offs], &(addr)[offs], sizeof(wavefront_patch_info) - sizeof(wavefront_any) - offs); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: download " "Sample type: %d " @@ -1707,11 +1763,12 @@ header.number, header.size); } +#endif WF_DEBUG switch (header.subkey) { case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ - COPY_FROM_USER ((unsigned char *) &header.hdr.s, + copy_from_user ((unsigned char *) &header.hdr.s, (unsigned char *) header.hdrptr, sizeof (wavefront_sample)); @@ -1719,7 +1776,7 @@ case WF_ST_MULTISAMPLE: - COPY_FROM_USER ((unsigned char *) &header.hdr.s, + copy_from_user ((unsigned char *) &header.hdr.s, (unsigned char *) header.hdrptr, sizeof (wavefront_multisample)); @@ -1728,28 +1785,28 @@ case WF_ST_ALIAS: - COPY_FROM_USER ((unsigned char *) &header.hdr.a, + copy_from_user ((unsigned char *) &header.hdr.a, (unsigned char *) header.hdrptr, sizeof (wavefront_alias)); return wavefront_send_alias (hw, &header); case WF_ST_DRUM: - COPY_FROM_USER ((unsigned char *) &header.hdr.d, + copy_from_user ((unsigned char *) &header.hdr.d, (unsigned char *) header.hdrptr, sizeof (wavefront_drum)); return wavefront_send_drum (hw, &header); case WF_ST_PATCH: - COPY_FROM_USER ((unsigned char *) &header.hdr.p, + copy_from_user ((unsigned char *) &header.hdr.p, (unsigned char *) header.hdrptr, sizeof (wavefront_patch)); return wavefront_send_patch (hw, &header); case WF_ST_PROGRAM: - COPY_FROM_USER ((unsigned char *) &header.hdr.pr, + copy_from_user ((unsigned char *) &header.hdr.pr, (unsigned char *) header.hdrptr, sizeof (wavefront_program)); @@ -1758,7 +1815,7 @@ default: printk (KERN_ERR "WaveFront: unknown patch type %d.\n", header.subkey); - return -EINVAL; + return -(EINVAL); } return 0; @@ -1804,24 +1861,19 @@ wavefront_synth_control (int dev, int cmd, caddr_t arg) { - struct wf_config *hw; + struct wf_config *hw = &wavefront_configuration; wavefront_control wc; unsigned char patchnumbuf[2]; int i; - if ((hw = hw_from_dev (dev)) == 0) { - printk (KERN_ERR - "WaveFront: synth_control with unknown " - "device number %d\n", dev); - return -EINVAL; - } - - COPY_FROM_USER (&wc, arg, sizeof (wc)); + copy_from_user (&wc, arg, sizeof (wc)); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "WaveFront: synth control with " "cmd 0x%x\n", wc.cmd); } +#endif WF_DEBUG /* special case handling of or for various commands */ @@ -1940,7 +1992,7 @@ is a low priority fix. */ - COPY_TO_USER (arg, &wc, sizeof (wc)); + copy_to_user (arg, &wc, sizeof (wc)); return 0; } @@ -1953,13 +2005,9 @@ static int wavefront_ioctl (int dev, unsigned int cmd, caddr_t arg) { - wf_config *hw; + wf_config *hw = &wavefront_configuration; unsigned char rbuf[4]; - if ((hw = hw_from_dev (dev)) == 0) { - return -EINVAL; - } - switch (cmd) { case SNDCTL_SYNTH_INFO: memcpy (&((char *) arg)[0], &wavefront_info, @@ -1992,7 +2040,7 @@ return wavefront_synth_control (dev, cmd, arg); default: - return -EINVAL; + return -(EINVAL); } } @@ -2000,32 +2048,30 @@ wavefront_open (int dev, int mode) { - struct wf_config *hw; - - if ((hw = hw_from_dev (dev)) == 0) { - return -EINVAL; - } + struct wf_config *hw = &wavefront_configuration; if (hw->opened) { - printk (KERN_ERR "WaveFront: warning: device in use\n"); + printk (KERN_WARNING "WaveFront: warning: device in use\n"); } hw->opened = mode; - return 0; + return (0); } static void wavefront_close (int dev) { - struct wf_config *hw; + struct wf_config *hw = &wavefront_configuration; + int i; - if ((hw = hw_from_dev (dev)) == 0) { - printk (KERN_ERR - "WaveFront: close() called on non-existent dev %d", dev); - return; +#ifdef WF_STATS + printk ("Status during loop: %ld\n", hw->status_found_during_loop); + for (i = 0; i < 4; i++) { + printk ("Status during sleep[%d]: %ld\n", + i, hw->status_found_during_sleep[i]); } - +#endif WF_STATS hw->opened = 0; hw->debug = 0; @@ -2035,70 +2081,65 @@ static void wavefront_aftertouch (int dev, int channel, int pressure) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; - midi_synth_aftertouch (hw->mididev,channel,pressure); + midi_synth_aftertouch (wavefront_configuration.mididev,channel,pressure); }; static void wavefront_bender (int dev, int chn, int value) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; - midi_synth_bender (hw->mididev, chn, value); + midi_synth_bender (wavefront_configuration.mididev, chn, value); }; static void wavefront_controller (int dev, int channel, int ctrl_num, int value) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; if(ctrl_num==CTRL_PITCH_BENDER) wavefront_bender(0,channel,value); - midi_synth_controller (hw->mididev, channel,ctrl_num,value); + midi_synth_controller (wavefront_configuration.mididev, + channel,ctrl_num,value); }; static void wavefront_panning(int dev, int channel, int pressure) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; - midi_synth_controller(hw->mididev,channel,CTL_PAN,pressure); + midi_synth_controller (wavefront_configuration.mididev, + channel,CTL_PAN,pressure); }; static int wavefront_set_instr (int dev, int channel, int instr_no) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return 1; - return(midi_synth_set_instr(hw->mididev,channel,instr_no)); + return(midi_synth_set_instr (wavefront_configuration.mididev, + channel,instr_no)); }; static int wavefront_kill_note (int dev, int channel, int note, int volume) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return 1; if (note==255) - return(midi_synth_start_note(hw->mididev, channel, 0, 0)); - return(midi_synth_kill_note(hw->mididev, channel, note, volume)); + return (midi_synth_start_note (wavefront_configuration.mididev, + channel, 0, 0)); + return(midi_synth_kill_note (wavefront_configuration.mididev, + channel, note, volume)); }; static int wavefront_start_note (int dev, int channel, int note, int volume) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return 1; - if (note==255) { - /*midi_synth_controller(hw->mididev,channel,7,volume);*/ - midi_synth_aftertouch(hw->mididev,channel,volume); + midi_synth_aftertouch (wavefront_configuration.mididev, + channel,volume); return(0); }; + if (volume==0) { volume=127; - midi_synth_aftertouch(hw->mididev,channel,0); + midi_synth_aftertouch + (wavefront_configuration.mididev, + channel,0); }; - midi_synth_start_note (hw->mididev, channel, note, volume); + + midi_synth_start_note (wavefront_configuration.mididev, + channel, note, volume); return(0); }; @@ -2111,7 +2152,8 @@ { int i; - for(i=0;i<16;i++) { + + for (i = 0; i < 16; i++) { midi_synth_kill_note (dev,i,0,0); }; }; @@ -2149,16 +2191,18 @@ void wavefrontintr (int irq, void *dev_id, struct pt_regs *dummy) { - int i; + /* We don't use this handler except during device + configuration. While the module is installed, the + interrupt is used to signal MIDI interrupts, and is + handled by the interrupt routine in wf_midi.c + */ + + wf_config *hw = (wf_config *) dev_id; + hw->irq_ok = 1; - if (irq < 0 || irq > 16) { - printk (KERN_WARNING "WaveFront: bogus interrupt %d recv'd\n", - irq); - } else if ((i = irq2hw[irq]) == -1) { - printk (KERN_ALERT - "WaveFront: interrupt from unknown hw (irq=%d).\n", irq); - } else { - wfs[i].irq_ok = 1; + if ((wavefront_status(hw) & STAT_INTR_WRITE) || + (wavefront_status(hw) & STAT_INTR_READ)) { + wake_up (&hw->interrupt_sleeper); } } @@ -2173,106 +2217,24 @@ 6 Host Tx Interrupt Pending (1=Interrupt) 7 Unused -*/ +11111001 + Rx Intr enable + nothing to read from board + no rx interrupt pending + unused + tx interrupt enabled + space to transmit + tx interrupt pending -/* CONTROL REGISTER -0 Host Rx Interrupt Enable (1=Enabled) 0x1 -1 Unused 0x2 -2 Unused 0x4 -3 Unused 0x8 -4 Host Tx Interrupt Enable 0x10 -5 Mute (0=Mute; 1=Play) 0x20 -6 Master Interrupt Enable (1=Enabled) 0x40 -7 Master Reset (0=Reset; 1=Run) 0x80 */ int -probe_wavefront (struct address_info *hw_config) +wavefront_interrupt_bits (int irq) { - int i; - int tmp1, tmp2; - unsigned char bits; - unsigned char rbuf[32], wbuf[32]; - wf_config *hw; - - if (hw_config->irq < 0 || hw_config->irq > 16) { - printk (KERN_WARNING "WaveFront: impossible IRQ suggested(%d)\n", - hw_config->irq); - return 0; - } - - /* Yeah yeah, TB docs say 8, but the FX device on the Tropez Plus - takes up another 8 ... - */ - - if (check_region (hw_config->io_base, 16)) { - printk (KERN_ERR "WaveFront: IO address range 0x%x - 0x%x " - "already in use - ignored\n", hw_config->io_base, - hw_config->io_base+15); - return 0; - } - - for (i = 0; i < WAVEFRONT_MAX_DEVICES; i++) { - if (!wfs[i].installed) { - wfs[i].installed = 1; - break; - } - } - - if (i == WAVEFRONT_MAX_DEVICES) { - printk (KERN_WARNING "WaveFront: no device slots available (max = %d).\n", - WAVEFRONT_MAX_DEVICES); - return 0; - } - - hw = &wfs[i]; + int bits; - hw->irq = hw_config->irq; - hw->base = hw_config->io_base; - - hw->israw = 0; - hw->debug = wf_debug_default; - hw->interrupts_on = 0; - hw->rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ - - hw_config->slots[WF_SYNTH_SLOT] = hw->synthdev = -1; - hw_config->slots[WF_INTERNAL_MIDI_SLOT] = hw->mididev = -1; - hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = hw->ext_mididev = -1; - - irq2hw[hw_config->irq] = i; - - if (wavefront_cmd (hw, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { - hw->fw_version[0] = rbuf[0]; - hw->fw_version[1] = rbuf[1]; - printk (KERN_INFO "WaveFront: firmware %d.%d already loaded.\n", - rbuf[0], rbuf[1]); - - if (wavefront_cmd (hw, WFC_HARDWARE_VERSION, rbuf, wbuf) == 0) { - hw->hw_version[0] = rbuf[0]; - hw->hw_version[1] = rbuf[1]; - } else { - printk (KERN_INFO "WaveFront: not raw, but no hardware version!\n"); - return 0; - } - if (!wf_raw) { - return 1; - } - } else { - hw->israw = 1; - printk (KERN_INFO - "WaveFront: no response to firmware probe, " - "assume raw.\n"); - } - - if (request_irq (hw_config->irq, wavefrontintr, - 0, "WaveFront", NULL) < 0) { - printk (KERN_WARNING "WaveFront: IRQ %d not available!\n", - hw_config->irq); - return 0; - } - - switch (hw_config->irq) { + switch (irq) { case 9: bits = 0x00; break; @@ -2287,11 +2249,42 @@ break; default: - printk (KERN_WARNING "WaveFront: invalid IRQ %d\n", - hw_config->irq); - return 0; + printk (KERN_WARNING "WaveFront: invalid IRQ %d\n", irq); + bits = -1; } - + + return bits; +} + +void +wavefront_should_cause_interrupt (wf_config *hw, int val, int port, int timeout) + +{ + unsigned long flags; + + save_flags (flags); + cli(); + hw->irq_ok = 0; + outb (val,port); + current->timeout = jiffies + timeout; + interruptible_sleep_on (&hw->interrupt_sleeper); + restore_flags (flags); +} + +static int +wavefront_hw_reset (wf_config *hw) + +{ + int bits; + int hwv[2]; + + if (request_irq (hw->irq, wavefrontintr, + 0, "WaveFront", (void *) hw) < 0) { + printk (KERN_WARNING "WaveFront: IRQ %d not available!\n", + hw->irq); + return 1; + } + /* try reset of port */ outb (0x0, hw->control_port); @@ -2305,9 +2298,6 @@ Bit 6 - MIDI Interface Select - XXX PBD: I think this documentation is backwards. I leave bit - 6 unset, and get MIDI data from the 9 pin D connector. - 0 - Use the MIDI Input from the 26-pin WaveBlaster compatible header as the serial MIDI source 1 - Use the MIDI Input from the 9-pin D connector as the serial MIDI @@ -2331,101 +2321,270 @@ */ - /* configure hardware: IRQ, plus external MIDI interface selected */ - - outb (bits | 0x80, hw->data_port); - - /* take us out of reset, unmute, master + TX + RX interrupts on */ - - outb (0x80|0x20|0x40|0x10|0x1, hw->control_port); - - for (i = 0; i < 1000000 && !hw->irq_ok; i++); - - /* Data port is now the data port, not the h/w initialization port - - The boot ROM will check the OSRAM, and will then - wait for the either the "download OS" or - "report h/w version" commands. - - Any other command will supposedly be ignored. + /* configure hardware: IRQ, enable interrupts, + plus external 9-pin MIDI interface selected */ + + if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) { + return 1; + } + + outb (0x80 | 0x40 | bits, hw->data_port); + /* CONTROL REGISTER + + 0 Host Rx Interrupt Enable (1=Enabled) 0x1 + 1 Unused 0x2 + 2 Unused 0x4 + 3 Unused 0x8 + 4 Host Tx Interrupt Enable 0x10 + 5 Mute (0=Mute; 1=Play) 0x20 + 6 Master Interrupt Enable (1=Enabled) 0x40 + 7 Master Reset (0=Reset; 1=Run) 0x80 + + Take us out of reset, unmute, master + TX + RX interrupts on. + + We'll get an interrupt presumably to tell us that the TX + register is clear. However, this doesn't mean that the + board is ready. We actually have to send it a command, and + wait till it gets back to use. After a cold boot, this can + take some time. + + + I think this is because its only after a cold boot that the + onboard ROM does its memory check, which can take "up to 4 + seconds" according to the WaveFront SDK. So, since sleeping + doesn't cost us much, we'll give it *plenty* of time. It + turns out that with 12MB of RAM, it can take up to 16 + seconds or so!! See the code after "ABOUT INTERRUPTS" + */ + + wavefront_should_cause_interrupt(hw, + 0x80|0x40|0x10|0x1, + hw->control_port, + (2*HZ)/100); + + /* Note: data port is now the data port, not the h/w initialization + port. + */ + if (!hw->irq_ok) { printk (KERN_WARNING "WaveFront: intr not received after h/w un-reset.\n"); - free_irq (hw_config->irq, NULL); - return 0; - } else { - hw->irq_ok = 0; - } + goto gone_bad; + } hw->interrupts_on = 1; + + /* ABOUT INTERRUPTS: + ----------------- + + When we talk about interrupts, there are two kinds + generated by the ICS2115. The first is to signal MPU data + ready to read, and the second is to signal RX or TX status + changes. We *always* want interrupts for MPU stuff but we + generally avoid using RX/TX interrupts. + + In theory, we could use the TX and RX interrupts for all + communication with the card. However, there are 2 good + reasons not to do this. + + First of all, the MIDI interface is going to use the same + interrupt. This presents no practical problem since Linux + allows us to share IRQ's. However, there are times when it + makes sense for a user to ask the driver to disable + interrupts, to avoid bothering Linux with a stream of MIDI + interrupts that aren't going to be used because nothing + cares about them. If we rely on them for communication with + the WaveFront synth as well, this disabling would be + crippling. Since being able to disable them can save quite + a bit of overhead (consider the interrupt frequency of a + physical MIDI controller like a modwheel being shunted back + and forth - its higher than the mouse, and much of + the time is of absolutely no interest to the kernel or any + user space processes whatsoever), we don't want to do this. + + Secondly, much of the time, there's no reason to go to + sleep on a TX or RX status: the WaveFront gets back to us + quickly enough that its a lot more efficient to just busy + wait on the relevant status. Once we go to sleep, all is + lost anyway, and so interrupts don't really help us much anyway. + + Therefore, we don't use interrupts for communication with + the WaveFront synth. We just poll the relevant RX/TX status. + + However, there is one broad exception to this. During module + loading, to deal with several situations where timing would + be an issue, we use TX/RX interrupts to help us avoid busy + waiting for indeterminate and hard to manage periods of + time. So, TX/RX interrupts are enabled until the end of + wavefront_init(), and not used again after that. + + */ + + /* Note: data port is now the data port, not the h/w initialization + port. + + At this point, only "HW VERSION" or "DOWNLOAD OS" commands + will work. So, issue one of them, and wait for TX + interrupt. This can take a *long* time after a cold boot, + while the ISC ROM does its RAM test. The SDK says up to 4 + seconds - with 12MB of RAM on a Tropez+, it takes a lot + longer than that (~16secs). Note that the card understands + the difference between a warm and a cold boot, so + subsequent ISC2115 reboots (say, caused by module + reloading) will get through this much faster. - /* WaveFront SDK says: - - "When the Master Reset is set to zero (0), the audio board is held - in reset, which is the power-up condition. Setting Master Reset to one - (1) allows the on-board processor to run. It takes approximately two - to four seconds, depending on the memory configuration, for the - on-board processor to complete it's initialization routine before it - will respond to commands after a reset." - - Actually, it seems that most of the time, even with 8MB of RAM, - its actually ready immediately. - */ - - if (!wavefront_wait (hw, STAT_CAN_WRITE)) { - if (!wavefront_wait (hw, STAT_CAN_WRITE)) { - if (!wavefront_wait (hw, STAT_CAN_WRITE)) { - printk (KERN_WARNING - "WaveFront: OS not ready after " - "memory check.\n"); - free_irq (hw_config->irq, NULL); - return 0; - } - } + Interesting question: why is no RX interrupt received first ? + */ + + wavefront_should_cause_interrupt(hw, WFC_HARDWARE_VERSION, + hw->data_port, 20*HZ); + + if (!hw->irq_ok) { + printk (KERN_WARNING + "WaveFront: post-RAM-check interrupt not received.\n"); + goto gone_bad; + } + + if (!(wavefront_status(hw) & STAT_CAN_READ)) { + printk (KERN_WARNING + "WaveFront: no response to HW version cmd.\n"); + goto gone_bad; + } + + if ((hwv[0] = wavefront_read (hw)) == -1) { + printk (KERN_WARNING + "WaveFront: board not responding correctly.\n"); + goto gone_bad; } - /* get H/W version, and check we get an interrupt */ - - outb (WFC_HARDWARE_VERSION, hw->data_port); - - for (i = 0; i < 1000000 && !hw->irq_ok; i++); - - /* We don't need the IRQ anymore for the WaveFront code, - and to allow an MPU-401 driver to attach to it later, lets - give it back .... + if (hwv[0] == 0xFF) { /* NAK */ - DO NOT alter irq2hw[], since we'll still use this to lookup - the config struct from an address_info struct. - */ + /* Board's RAM test failed. Try to read error code, + and tell us about it either way. + */ + + if ((hwv[0] = wavefront_read (hw)) == -1) { + printk (KERN_WARNING + "WaveFront: on-board RAM test failed " + "(bad error code).\n"); + } else { + printk (KERN_WARNING + "WaveFront: on-board RAM test failed " + "(error code: 0x%x).\n", + hwv[0]); + } + goto gone_bad; + } - free_irq (hw_config->irq, NULL); + /* We're OK, just get the next byte of the HW version response */ - if (!hw->irq_ok) { + if ((hwv[1] = wavefront_read (hw)) == -1) { printk (KERN_WARNING - "WaveFront: interrupt not received after " - "h/w version cmd.\n"); - return 0; - } else { - hw->irq_ok = 0; + "WaveFront: board not responding correctly(2).\n"); + goto gone_bad; + } + + printk (KERN_INFO "WaveFront: hardware version %d.%d\n", + hwv[0], hwv[1]); + + return 0; + + + gone_bad: + free_irq (hw->irq, hw); + return (1); + } + +int +probe_wavefront (struct address_info *hw_config) + +{ + unsigned char rbuf[4], wbuf[4]; + wf_config *hw; + + if (hw_config->irq < 0 || hw_config->irq > 16) { + printk (KERN_WARNING "WaveFront: impossible IRQ suggested(%d)\n", + hw_config->irq); + return 0; } - if ((tmp1 = wavefront_read(hw)) == -1) { - printk (KERN_WARNING - "WaveFront @ 0x%x not ready, ignoring\n", hw->base); + /* Yeah yeah, TB docs say 8, but the FX device on the Tropez Plus + takes up another 8 ... + */ + + if (check_region (hw_config->io_base, 16)) { + printk (KERN_ERR "WaveFront: IO address range 0x%x - 0x%x " + "already in use - ignored\n", hw_config->io_base, + hw_config->io_base+15); return 0; } - if ((tmp2 = wavefront_read(hw)) == -1) { - printk (KERN_WARNING - "WaveFront @ 0x%x not responding correctly, ignoring\n", - hw->base); + hw = &wavefront_configuration; + + hw->irq = hw_config->irq; + hw->base = hw_config->io_base; + + hw->israw = 0; + hw->debug = debug_default; + hw->interrupts_on = 0; + hw->rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ + +#ifdef WF_STATS + hw->status_found_during_sleep[0] = 0; + hw->status_found_during_sleep[1] = 0; + hw->status_found_during_sleep[2] = 0; + hw->status_found_during_sleep[3] = 0; + hw->status_found_during_loop = 0; +#endif WF_STATS + + hw_config->slots[WF_SYNTH_SLOT] = hw->synthdev = -1; + hw_config->slots[WF_INTERNAL_MIDI_SLOT] = hw->mididev = -1; + hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = hw->ext_mididev = -1; + + if (wavefront_cmd (hw, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { + + hw->fw_version[0] = rbuf[0]; + hw->fw_version[1] = rbuf[1]; + printk (KERN_INFO + "WaveFront: firmware %d.%d already loaded.\n", + rbuf[0], rbuf[1]); + + /* check that a command actually works */ + + if (wavefront_cmd (hw, WFC_HARDWARE_VERSION, + rbuf, wbuf) == 0) { + hw->hw_version[0] = rbuf[0]; + hw->hw_version[1] = rbuf[1]; + } else { + printk (KERN_INFO "WaveFront: not raw, but no " + "hardware version!\n"); + return 0; + } + + if (!wf_raw) { + return 1; + } else { + printk (KERN_INFO + "WaveFront: reloading firmware anyway.\n"); + } + + } else { + + hw->israw = 1; + printk (KERN_INFO "WaveFront: no response to firmware probe, " + "assume raw.\n"); + + } + + init_waitqueue (&hw->interrupt_sleeper); + + if (wavefront_hw_reset (hw)) { + printk (KERN_WARNING "WaveFront: hardware reset failed\n"); return 0; } - - printk (KERN_INFO "WaveFront: hardware version %d.%d\n", tmp1, tmp2); - + return 1; } @@ -2465,7 +2624,8 @@ set_fs (get_ds()); if ((fd = open (path, 0, 0)) < 0) { - printk (KERN_WARNING "WaveFront: Unable to load \"%s\".\n", path); + printk (KERN_WARNING "WaveFront: Unable to load \"%s\".\n", + path); return 1; } @@ -2512,9 +2672,13 @@ section_cnt_downloaded + 1, c); goto failure; - } else if ((hw->debug & WF_DEBUG_IO) && + } else { +#ifdef WF_DEBUG + if ((hw->debug & WF_DEBUG_IO) && !(++section_cnt_downloaded % 10)) { printk (KERN_DEBUG "."); + } +#endif WF_DEBUG } } else { @@ -2526,9 +2690,11 @@ close (fd); set_fs (fs); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "\n"); } +#endif WF_DEBUG return 0; failure: @@ -2618,81 +2784,137 @@ } static int -wavefront_init (wf_config *hw, struct address_info *hw_config) +wavefront_do_reset (wf_config *hw, int atboot) { - int samples_are_from_rom = 0; + char voices[1]; - /* XXX what state does the board need to be in before - I can download the firmware ? I think any state - after it acknowledges a hardware version command - post-booting. - */ + if (!atboot && wavefront_hw_reset (hw)) { + printk (KERN_WARNING "WaveFront: hw reset failed.\n"); + goto gone_bad; + } if (hw->israw || wf_raw) { - samples_are_from_rom = 1; - - if (wavefront_download_firmware (hw, wf_ospath)) { + if (wavefront_download_firmware (hw, ospath)) { + goto gone_bad; return 1; } - - /* enter normal operation: - bit 7: (on) reset 0x80 - bit 6: interrupts enabled 0x40 - bit 5: (on) mute (i.e. in play mode) 0x20 - bits 4-0: zero + } + + if (fx_raw) { + wffx_init (hw); + } + + /* If we loaded the OS, we now have to wait for it to be ready + to roll. We can't guarantee that interrupts are enabled, + because we might be reloading the module without forcing a + reset/reload of the firmware. - note: tx and rx interrupts turned off - */ + Rather than busy-wait, lets just turn interrupts on. + */ + + outb (0x80|0x40|0x10|0x1, hw->control_port); + + wavefront_should_cause_interrupt (hw, WFC_NOOP, + hw->data_port, (10*HZ)); - outb (0x80|0x40|0x20, hw->control_port); + if (!hw->irq_ok) { + printk (KERN_WARNING "WaveFront: no post-OS interrupt.\n"); + goto gone_bad; + } + + /* Now, do it again ! */ + + wavefront_should_cause_interrupt (hw, WFC_NOOP, + hw->data_port, (10*HZ)); - /* Set up MPU-401 emulation mode. For some reason, this always - fails the first time, and generates no ACK, so we'll - treat it as a special case by sleeping for a while, and then - trying again. - */ + if (!hw->irq_ok) { + printk (KERN_WARNING "WaveFront: no post-OS interrupt(2).\n"); + goto gone_bad; + } - wavefront_write (hw, 0xf0); - wavefront_write (hw, 1); - wavefront_sleep (hw, (HZ/wf_sleep_interval) * wf_sleep_tries); - wavefront_write (hw, 0xf0); - wavefront_write (hw, 1); - if (wavefront_read (hw) != 0x80) { - printk (KERN_ERR - "WaveFront: set MPU emulation mode " - "command failed.\n"); - return (1); + /* OK, no (RX/TX) interrupts any more, but leave mute + on. Master interrupts get enabled when we're done here. + */ + + outb (0x80, hw->control_port); + + /* No need for the IRQ anymore */ + + free_irq (hw->irq, hw); + + /* SETUPSND.EXE asks for sample memory config here, but since i + have no idea how to interpret the result, we'll forget + about it. + */ + + if ((hw->freemem = wavefront_freemem (hw)) < 0) { + goto gone_bad; + } + + printk (KERN_INFO "WaveFront: available DRAM %dk\n", hw->freemem / 1024); + + if (!wavefront_write (hw, 0xf0) || + !wavefront_write (hw, 1) || + (wavefront_read (hw) < 0)) { + hw->debug = 0; + printk (KERN_WARNING "WaveFront: MPU emulation mode not set.\n"); + goto gone_bad; + } + + voices[0] = 32; + + if (wavefront_cmd (hw, WFC_SET_NVOICES, 0, voices)) { + printk (KERN_WARNING + "WaveFront: cannot set number of voices to 32.\n"); + } + + return 0; + + gone_bad: + /* reset that sucker so that it doesn't bother us. */ + + outb (0x0, hw->control_port); + free_irq (hw->irq, hw); + return 1; +} + +static int +wavefront_init (wf_config *hw, int atboot) + +{ + int samples_are_from_rom; + + if (hw->israw || wf_raw) { + samples_are_from_rom = 1; + } else { + samples_are_from_rom = 0; + } + + if (hw->israw || wf_raw || fx_raw) { + if (wavefront_do_reset (hw, atboot)) { + return 1; } } - hw->freemem = wavefront_freemem (hw); - printk (KERN_INFO "WaveFront: available DRAM %dk\n", hw->freemem / 1024); - wavefront_get_sample_status (hw, samples_are_from_rom); wavefront_get_program_status (hw); wavefront_get_patch_status (hw); - if (fx_raw) { - wffx_init (hw); - } - - return 0; + /* Start normal operation: unreset, master interrupt enable + (for MPU interrupts) no mute + */ + + outb (0x80|0x40|0x20, hw->control_port); + + return (0); } void attach_wavefront (struct address_info *hw_config) { int i; - struct wf_config *hw; - - if ((i = irq2hw[hw_config->irq]) == -1) { - printk (KERN_ERR "WaveFront: cannot attach unknown irq 0x%x.\n", - hw_config->irq); - return; - } - - hw = &wfs[i]; + struct wf_config *hw = &wavefront_configuration; if ((i = sound_alloc_synthdev()) == -1) { printk (KERN_ERR "WaveFront: Too many synthesizers\n"); @@ -2700,15 +2922,13 @@ } else { hw_config->slots[WF_SYNTH_SLOT] = i; hw->synthdev = i; - dev2hw[hw->synthdev] = i; synth_devs[hw->synthdev] = &wavefront_operations; } - if (wavefront_init (hw, hw_config)) { + if (wavefront_init (hw, 1)) { printk (KERN_WARNING "WaveFront: board could not " "be initialized.\n"); sound_unload_synthdev (i); - hw->installed = 0; return; } @@ -2731,18 +2951,11 @@ void unload_wavefront (struct address_info *hw_config) { - struct wf_config *hw; - int i; - - if ((i = irq2hw[hw_config->irq]) == -1) { - printk (KERN_ERR "WaveFront: unloading unrecognized device!\n"); - return; - } - hw = &wfs[i]; + struct wf_config *hw = &wavefront_configuration; /* the first two are freed by the wf_mpu code */ - release_region (hw_config->io_base+2, 6); - release_region (hw_config->io_base+8, 8); + release_region (hw->base+2, 6); + release_region (hw->base+8, 8); sound_unload_synthdev (hw->synthdev); #if defined(CONFIG_MIDI) unload_wf_mpu (hw_config); @@ -2802,13 +3015,13 @@ if (page < 0 || page > 7) { printk (KERN_ERR "WaveFront: FX memset: " "page must be >= 0 and <= 7\n"); - return -EINVAL; + return -(EINVAL); } if (addr < 0 || addr > 0x7f) { printk (KERN_ERR "WaveFront: FX memset: " "addr must be >= 0 and <= 7f\n"); - return -EINVAL; + return -(EINVAL); } if (cnt == 1) { @@ -2842,7 +3055,7 @@ "WaveFront: FX memset " "(0x%x, 0x%x, 0x%x, %d) incomplete\n", page, addr, (int) data, cnt); - return -EIO; + return -(EIO); } } @@ -2866,18 +3079,17 @@ if (r->data[2] <= 0) { printk (KERN_ERR "WaveFront: cannot write " "<= 0 bytes to FX\n"); - return -EINVAL; + return -(EINVAL); } else if (r->data[2] == 1) { pd = (unsigned short *) &r->data[3]; } else { if (r->data[2] > sizeof (page_data)) { - printk (KERN_ERR - "WaveFront: cannot write " + printk (KERN_ERR "WaveFront: cannot write " "> 255 bytes to FX\n"); - return -EINVAL; + return -(EINVAL); } - COPY_FROM_USER(page_data, (unsigned char *) r->data[3], - r->data[2]); + copy_from_user (page_data, (unsigned char *) r->data[3], + r->data[2]); pd = page_data; } @@ -2891,7 +3103,7 @@ printk (KERN_WARNING "WaveFront: FX: ioctl %d not yet supported\n", r->request); - return -EINVAL; + return -(EINVAL); } } @@ -3364,7 +3576,7 @@ outb (0x00, hw->fx_op); /* mute off */ - return 0; + return (0); } EXPORT_NO_SYMBOLS; @@ -3388,6 +3600,7 @@ "options must be set.\n"); return -EINVAL; } + cfg.io_base = io; cfg.irq = irq; @@ -3406,7 +3619,6 @@ SOUND_LOCK_END; } -#endif MODULE -#endif CONFIG_SOUND_WAVEFRONT +#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE diff -u --recursive --new-file v2.1.116/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c --- v2.1.116/linux/drivers/sound/wf_midi.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/sound/wf_midi.c Wed Aug 19 14:48:31 1998 @@ -454,12 +454,12 @@ struct wf_mpu_config *devc; if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL) - return -ENXIO; + return -(ENXIO); devc = &dev_conf[dev]; if (devc->opened) { - return -EBUSY; + return -(EBUSY); } devc->mode = MODE_MIDI; @@ -678,8 +678,8 @@ midi_synth_send_sysex }; -static struct synth_operations wf_mpu_synth_operations[WAVEFRONT_MAX_DEVICES*2]; -static struct midi_operations wf_mpu_midi_operations[WAVEFRONT_MAX_DEVICES*2]; +static struct synth_operations wf_mpu_synth_operations[2]; +static struct midi_operations wf_mpu_midi_operations[2]; static int wfmpu_cnt = 0; static struct midi_operations wf_mpu_midi_proto = @@ -707,9 +707,8 @@ struct wf_mpu_config *devc; int internal; - if (wfmpu_cnt >= WAVEFRONT_MAX_DEVICES * 2) { - printk (KERN_ERR "WF-MPU: eh ? more MPU devices " - "than cards ?!!\n"); + if (wfmpu_cnt >= 2) { + printk (KERN_ERR "WF-MPU: more MPU devices than cards ?!!\n"); return (-1); } diff -u --recursive --new-file v2.1.116/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.1.116/linux/drivers/video/Config.in Tue Jul 28 14:21:09 1998 +++ linux/drivers/video/Config.in Wed Aug 19 19:22:12 1998 @@ -53,7 +53,7 @@ if [ "$ARCH" = "i386" -o "$ARCH" = "alpha" -o "$ARCH" = "ppc" -o \ "$CONFIG_ARM" = "y" ]; then if [ "$CONFIG_ARM" != "y" -o "$CONFIG_ARCH_ACORN" != "y" ] ; then - tristate 'VGA chipset support (text only)' CONFIG_FB_VGA + tristate 'Deprecated almost-VGA support (text only - use normal VGA console instead)' CONFIG_FB_VGA fi fi if [ "$ARCH" = "alpha" ]; then diff -u --recursive --new-file v2.1.116/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.1.116/linux/fs/binfmt_elf.c Tue Aug 18 22:02:05 1998 +++ linux/fs/binfmt_elf.c Wed Aug 19 14:52:23 1998 @@ -1193,8 +1193,9 @@ notes[1].type = NT_PRPSINFO; notes[1].datasz = sizeof(psinfo); notes[1].data = &psinfo; - psinfo.pr_state = current->state; - psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state]; + i = current->state ? ffz(~current->state) + 1 : 0; + psinfo.pr_state = i; + psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; psinfo.pr_nice = current->priority-15; psinfo.pr_flag = current->flags; diff -u --recursive --new-file v2.1.116/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.116/linux/fs/dcache.c Tue Aug 18 22:02:06 1998 +++ linux/fs/dcache.c Wed Aug 19 13:07:49 1998 @@ -643,9 +643,10 @@ * Special case: local mount points don't live in * the hashes, so we search the super blocks. */ - struct super_block *sb = super_blocks + 0; + struct super_block *sb = sb_entry(super_blocks.next); - for (; sb < super_blocks + NR_SUPER; sb++) { + for (; sb != sb_entry(&super_blocks); + sb = sb_entry(sb->s_list.next)) { if (!sb->s_dev) continue; if (sb->s_root == dentry) diff -u --recursive --new-file v2.1.116/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.1.116/linux/fs/fcntl.c Wed Jul 1 19:38:55 1998 +++ linux/fs/fcntl.c Wed Aug 19 13:41:00 1998 @@ -84,7 +84,7 @@ #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC) -static int setfl(struct file * filp, unsigned long arg) +static int setfl(int fd, struct file * filp, unsigned long arg) { struct inode * inode = filp->f_dentry->d_inode; @@ -98,7 +98,7 @@ /* Did FASYNC state change? */ if ((arg ^ filp->f_flags) & FASYNC) { if (filp->f_op->fasync) - filp->f_op->fasync(filp, (arg & FASYNC) != 0); + filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); } /* required for strict SunOS emulation */ @@ -137,7 +137,7 @@ err = filp->f_flags; break; case F_SETFL: - err = setfl(filp, arg); + err = setfl(fd, filp, arg); break; case F_GETLK: err = fcntl_getlk(fd, (struct flock *) arg); @@ -166,6 +166,17 @@ if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, F_SETOWN, arg); break; + case F_GETSIG: + err = filp->f_owner.signum; + break; + case F_SETSIG: + if (arg <= 0 || arg > _NSIG) { + err = -EINVAL; + break; + } + err = 0; + filp->f_owner.signum = arg; + break; default: /* sockets need a few special fcntls. */ if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) @@ -180,10 +191,13 @@ return err; } -static void send_sigio(int pid, uid_t uid, uid_t euid) +static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa) { struct task_struct * p; - + int pid = fown->pid; + uid_t uid = fown->uid; + uid_t euid = fown->euid; + read_lock(&tasklist_lock); for_each_task(p) { int match = p->pid; @@ -195,9 +209,27 @@ (euid ^ p->suid) && (euid ^ p->uid) && (uid ^ p->suid) && (uid ^ p->uid)) continue; - send_sig(SIGIO, p, 1); - if (p->state == TASK_INTERRUPTIBLE && signal_pending(p)) - wake_up_process(p); + switch (fown->signum) { + siginfo_t si; + default: + /* Queue a rt signal with the appropriate fd as its + value. We use SI_SIGIO as the source, not + SI_KERNEL, since kernel signals always get + delivered even if we can't queue. Failure to + queue in this case _should_ be reported; we fall + back to SIGIO in that case. --sct */ + si.si_signo = fown->signum; + si.si_errno = 0; + si.si_code = SI_SIGIO; + si.si_pid = pid; + si.si_uid = uid; + si.si_fd = fa->fa_fd; + if (!send_sig_info(fown->signum, &si, p)) + break; + /* fall-through: fall back on the old plain SIGIO signal */ + case 0: + send_sig(SIGIO, p, 1); + } } read_unlock(&tasklist_lock); } @@ -213,7 +245,7 @@ } fown = &fa->fa_file->f_owner; if (fown->pid) - send_sigio(fown->pid, fown->uid, fown->euid); + send_sigio(fown, fa); fa = fa->fa_next; } } diff -u --recursive --new-file v2.1.116/linux/fs/inode.c linux/fs/inode.c --- v2.1.116/linux/fs/inode.c Sun Jul 26 11:57:18 1998 +++ linux/fs/inode.c Wed Aug 19 13:07:49 1998 @@ -177,14 +177,13 @@ */ void sync_inodes(kdev_t dev) { - struct super_block * sb = super_blocks + 0; - int i; + struct super_block * sb = sb_entry(super_blocks.next); /* * Search the super_blocks array for the device(s) to sync. */ spin_lock(&inode_lock); - for (i = NR_SUPER ; i-- ; sb++) { + for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) { if (!sb->s_dev) continue; if (dev && sb->s_dev != dev) diff -u --recursive --new-file v2.1.116/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.1.116/linux/fs/nfs/dir.c Wed Jun 24 22:54:09 1998 +++ linux/fs/nfs/dir.c Wed Aug 19 16:16:04 1998 @@ -14,6 +14,13 @@ * Following Linus comments on my original hack, this version * depends only on the dcache stuff and doesn't touch the inode * layer (iput() and friends). + * 04 Aug 1998 Ion Badulescu + * FIFO's need special handling in NFSv2 + */ + +/* + * Fixes: + * Ion Badulescu : FIFO's need special handling in NFSv2 */ #include @@ -645,7 +652,10 @@ if (dentry->d_name.len > NFS_MAXNAMLEN) goto out; - sattr.mode = mode; + if (mode & S_IFIFO) + sattr.mode = (mode & ~S_IFMT) | S_IFCHR; + else + sattr.mode = mode; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; @@ -655,6 +665,15 @@ nfs_invalidate_dircache(dir); error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); + /* + * Retry invalid FIFO creates as the original object + * to cover for NFS servers that don't cope. + */ + if (error == -EINVAL && (mode & S_IFIFO)) { + sattr.mode = mode; + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), + dentry->d_name.name, &sattr, &fhandle, &fattr); + } if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error) @@ -684,7 +703,10 @@ if (dentry->d_name.len > NFS_MAXNAMLEN) return -ENAMETOOLONG; - sattr.mode = mode; + if (mode & S_IFIFO) + sattr.mode = (mode & ~S_IFMT) | S_IFCHR; + else + sattr.mode = mode; sattr.uid = sattr.gid = sattr.size = (unsigned) -1; if (S_ISCHR(mode) || S_ISBLK(mode)) sattr.size = rdev; /* get out your barf bag */ @@ -693,6 +715,11 @@ nfs_invalidate_dircache(dir); error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), dentry->d_name.name, &sattr, &fhandle, &fattr); + if (error == -EINVAL && (mode & S_IFIFO)) { + sattr.mode = mode; + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent), + dentry->d_name.name, &sattr, &fhandle, &fattr); + } if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); if (error) diff -u --recursive --new-file v2.1.116/linux/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c --- v2.1.116/linux/fs/nfs/mount_clnt.c Wed Apr 23 19:01:26 1997 +++ linux/fs/nfs/mount_clnt.c Wed Aug 19 16:16:04 1998 @@ -78,6 +78,7 @@ clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; + clnt->cl_intr = 1; } return clnt; } diff -u --recursive --new-file v2.1.116/linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c --- v2.1.116/linux/fs/nfs/nfs2xdr.c Tue Mar 17 22:18:15 1998 +++ linux/fs/nfs/nfs2xdr.c Wed Aug 19 16:16:04 1998 @@ -5,6 +5,9 @@ * * Copyright (C) 1992, 1993, 1994 Rick Sladkey * Copyright (C) 1996 Olaf Kirch + * + * 04 Aug 1998 Ion Badulescu + * FIFO's need special handling in NFSv2 */ #define NFS_NEED_XDR_TYPES @@ -114,6 +117,11 @@ fattr->mtime.useconds = ntohl(*p++); fattr->ctime.seconds = ntohl(*p++); fattr->ctime.useconds = ntohl(*p++); + if (fattr->type == NFCHR && fattr->rdev == NFS_FIFO_DEV) { + fattr->type = NFFIFO; + fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; + fattr->rdev = 0; + } return p; } diff -u --recursive --new-file v2.1.116/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.1.116/linux/fs/nfs/write.c Wed Jun 24 22:54:09 1998 +++ linux/fs/nfs/write.c Wed Aug 19 16:16:04 1998 @@ -468,7 +468,9 @@ struct wait_queue wait = { current, NULL }; struct page *page = req->wb_page; int retval; + sigset_t oldmask; + rpc_clnt_sigmask(NFS_CLIENT(req->wb_inode), &oldmask); add_wait_queue(&page->wait, &wait); atomic_inc(&page->count); for (;;) { @@ -477,7 +479,8 @@ if (!PageLocked(page)) break; retval = -ERESTARTSYS; - if (IS_SOFT && signalled()) + /* IS_SOFT is a timeout item .. */ + if (signalled()) break; schedule(); } @@ -485,6 +488,7 @@ current->state = TASK_RUNNING; /* N.B. page may have been unused, so we must use free_page() */ free_page(page_address(page)); + rpc_clnt_sigunmask(NFS_CLIENT(req->wb_inode), &oldmask); return retval; } @@ -534,6 +538,10 @@ if ((req = find_write_request(inode, page)) != NULL) { if (update_write_request(req, offset, count)) { /* N.B. check for a fault here and cancel the req */ + /* + * SECURITY - copy_from_user must zero the + * rest of the data after a fault! + */ copy_from_user(page_addr + offset, buffer, count); goto updated; } @@ -889,6 +897,9 @@ /* Update attributes as result of writeback. * Beware: when UDP replies arrive out of order, we * may end up overwriting a previous, bigger file size. + * + * When the file size shrinks we cancel all pending + * writebacks. */ if (fattr->mtime.seconds >= inode->i_mtime) { if (fattr->size < inode->i_size) diff -u --recursive --new-file v2.1.116/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.116/linux/fs/proc/array.c Tue Aug 18 22:02:06 1998 +++ linux/fs/proc/array.c Wed Aug 19 16:18:06 1998 @@ -485,16 +485,18 @@ return 0; #if defined(__i386__) { - unsigned long ebp, eip; + unsigned long ebp, esp, eip; unsigned long stack_page; int count = 0; - stack_page = 4096 + (unsigned long)p; - if (!stack_page) + stack_page = (unsigned long)p; + esp = p->tss.esp; + if (!stack_page || esp < stack_page || esp >= 8188+stack_page) return 0; - ebp = p->tss.ebp; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; do { - if (ebp < stack_page || ebp >= 4092+stack_page) + if (ebp < stack_page || ebp >= 8188+stack_page) return 0; eip = *(unsigned long *) (ebp+4); if (eip < first_sched || eip >= last_sched) diff -u --recursive --new-file v2.1.116/linux/fs/super.c linux/fs/super.c --- v2.1.116/linux/fs/super.c Tue Aug 18 22:02:06 1998 +++ linux/fs/super.c Wed Aug 19 13:07:49 1998 @@ -68,7 +68,10 @@ /* this is initialized in init/main.c */ kdev_t ROOT_DEV; -struct super_block super_blocks[NR_SUPER]; +int nr_super_blocks = 0; +int max_super_blocks = NR_SUPER; +LIST_HEAD(super_blocks); + static struct file_system_type *file_systems = (struct file_system_type *) NULL; struct vfsmount *vfsmntlist = (struct vfsmount *) NULL; static struct vfsmount *vfsmnttail = (struct vfsmount *) NULL, @@ -446,7 +449,9 @@ { struct super_block * sb; - for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) { + for (sb = sb_entry(super_blocks.next); + sb != sb_entry(&super_blocks); + sb = sb_entry(sb->s_list.next)) { if (!sb->s_dev) continue; if (dev && sb->s_dev != dev) @@ -471,15 +476,15 @@ if (!dev) return NULL; restart: - s = 0+super_blocks; - while (s < NR_SUPER+super_blocks) + s = sb_entry(super_blocks.next); + while (s != sb_entry(&super_blocks)) if (s->s_dev == dev) { wait_on_super(s); if (s->s_dev == dev) return s; goto restart; } else - s++; + s = sb_entry(s->s_list.next); return NULL; } @@ -519,16 +524,28 @@ */ static struct super_block *get_empty_super(void) { - struct super_block *s = 0+super_blocks; + struct super_block *s; - for (; s < NR_SUPER+super_blocks; s++) { + for (s = sb_entry(super_blocks.next); + s != sb_entry(&super_blocks); + s = sb_entry(s->s_list.next)) { if (s->s_dev) continue; if (!s->s_lock) return s; printk("VFS: empty superblock %p locked!\n", s); } - return NULL; + /* Need a new one... */ + if (nr_super_blocks >= max_super_blocks) + return NULL; + s = kmalloc(sizeof(struct super_block), GFP_USER); + nr_super_blocks++; + if (s) { + memset(s, 0, sizeof(struct super_block)); + INIT_LIST_HEAD(&s->s_dirty); + list_add (&s->s_list, super_blocks.prev); + } + return s; } static struct super_block * read_super(kdev_t dev,const char *name,int flags, @@ -1112,7 +1129,7 @@ goto dput_and_out; } -__initfunc(static void do_mount_root(void)) +__initfunc(void mount_root(void)) { struct file_system_type * fs_type; struct super_block * sb; @@ -1120,7 +1137,7 @@ struct inode * d_inode = NULL; struct file filp; int retval; - + #ifdef CONFIG_ROOT_NFS if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { ROOT_DEV = 0; @@ -1207,22 +1224,6 @@ } -__initfunc(void mount_root(void)) -{ - struct super_block * sb = super_blocks; - int i; - - memset(super_blocks, 0, sizeof(super_blocks)); - /* - * Initialize the dirty inode list headers for the super blocks - */ - for (i = NR_SUPER ; i-- ; sb++) - INIT_LIST_HEAD(&sb->s_dirty); - - do_mount_root(); -} - - #ifdef CONFIG_BLK_DEV_INITRD extern int initmem_freed; @@ -1242,7 +1243,7 @@ return -EBUSY; } ROOT_DEV = new_root_dev; - do_mount_root(); + mount_root(); dput(old_root); dput(old_pwd); #if 1 diff -u --recursive --new-file v2.1.116/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v2.1.116/linux/fs/vfat/namei.c Tue Aug 18 22:02:06 1998 +++ linux/fs/vfat/namei.c Wed Aug 19 10:20:18 1998 @@ -1771,8 +1771,6 @@ MSDOS_I(new_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart; MSDOS_I(new_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs; - old_inode->i_nlink = 0; - fat_cache_inval_inode(old_inode); mark_inode_dirty(new_inode); @@ -1815,6 +1813,16 @@ iput(dotdot_inode); fat_brelse(sb, dotdot_bh); } + + /* + * This convinces the VFS layer to drop the old inode, + * but at the same time fools the VFAT layer to not + * actually delete any of the blocks in the old file + * (because they are very much used by the renamed file) + */ + MSDOS_I(old_inode)->i_start = 0; + MSDOS_I(old_inode)->i_logstart = 0; + old_inode->i_nlink = 0; if (res > 0) res = 0; diff -u --recursive --new-file v2.1.116/linux/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h --- v2.1.116/linux/include/asm-alpha/fcntl.h Sat Sep 21 23:41:32 1996 +++ linux/include/asm-alpha/fcntl.h Wed Aug 19 13:24:43 1998 @@ -29,6 +29,8 @@ #define F_SETOWN 5 /* for sockets. */ #define F_GETOWN 6 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-alpha/siginfo.h linux/include/asm-alpha/siginfo.h --- v2.1.116/linux/include/asm-alpha/siginfo.h Tue Jul 28 14:21:09 1998 +++ linux/include/asm-alpha/siginfo.h Wed Aug 19 13:24:43 1998 @@ -87,6 +87,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-arm/fcntl.h linux/include/asm-arm/fcntl.h --- v2.1.116/linux/include/asm-arm/fcntl.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/fcntl.h Wed Aug 19 13:24:43 1998 @@ -28,6 +28,8 @@ #define F_SETOWN 8 /* for sockets. */ #define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-arm/siginfo.h linux/include/asm-arm/siginfo.h --- v2.1.116/linux/include/asm-arm/siginfo.h Tue Jul 28 14:21:09 1998 +++ linux/include/asm-arm/siginfo.h Wed Aug 19 13:24:43 1998 @@ -87,6 +87,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h --- v2.1.116/linux/include/asm-i386/fcntl.h Sat Sep 21 23:41:32 1996 +++ linux/include/asm-i386/fcntl.h Wed Aug 19 13:24:43 1998 @@ -28,6 +28,8 @@ #define F_SETOWN 8 /* for sockets. */ #define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h --- v2.1.116/linux/include/asm-i386/siginfo.h Fri Jul 31 17:05:52 1998 +++ linux/include/asm-i386/siginfo.h Wed Aug 19 13:24:43 1998 @@ -87,6 +87,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h --- v2.1.116/linux/include/asm-m68k/fcntl.h Sat Sep 21 23:41:32 1996 +++ linux/include/asm-m68k/fcntl.h Wed Aug 19 13:24:44 1998 @@ -28,6 +28,8 @@ #define F_SETOWN 8 /* for sockets. */ #define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h --- v2.1.116/linux/include/asm-m68k/siginfo.h Tue Jul 28 14:21:09 1998 +++ linux/include/asm-m68k/siginfo.h Wed Aug 19 13:24:44 1998 @@ -87,6 +87,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-mips/fcntl.h linux/include/asm-mips/fcntl.h --- v2.1.116/linux/include/asm-mips/fcntl.h Thu Jun 26 12:33:39 1997 +++ linux/include/asm-mips/fcntl.h Wed Aug 19 13:24:44 1998 @@ -29,6 +29,8 @@ #define F_SETOWN 24 /* for sockets. */ #define F_GETOWN 23 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-mips/siginfo.h linux/include/asm-mips/siginfo.h --- v2.1.116/linux/include/asm-mips/siginfo.h Tue Jul 28 14:21:09 1998 +++ linux/include/asm-mips/siginfo.h Wed Aug 19 13:24:44 1998 @@ -87,6 +87,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-ppc/fcntl.h linux/include/asm-ppc/fcntl.h --- v2.1.116/linux/include/asm-ppc/fcntl.h Wed Dec 18 00:54:09 1996 +++ linux/include/asm-ppc/fcntl.h Wed Aug 19 13:24:44 1998 @@ -28,6 +28,8 @@ #define F_SETOWN 8 /* for sockets. */ #define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-ppc/siginfo.h linux/include/asm-ppc/siginfo.h --- v2.1.116/linux/include/asm-ppc/siginfo.h Tue Jul 28 14:21:09 1998 +++ linux/include/asm-ppc/siginfo.h Wed Aug 19 13:24:44 1998 @@ -87,6 +87,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v2.1.116/linux/include/asm-sparc/fcntl.h Mon Mar 17 14:54:31 1997 +++ linux/include/asm-sparc/fcntl.h Wed Aug 19 13:24:44 1998 @@ -28,6 +28,8 @@ #define F_GETLK 7 #define F_SETLK 8 #define F_SETLKW 9 +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h --- v2.1.116/linux/include/asm-sparc/siginfo.h Thu Aug 6 14:06:34 1998 +++ linux/include/asm-sparc/siginfo.h Wed Aug 19 13:24:44 1998 @@ -91,6 +91,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h --- v2.1.116/linux/include/asm-sparc64/fcntl.h Wed Apr 23 19:01:28 1997 +++ linux/include/asm-sparc64/fcntl.h Wed Aug 19 13:24:44 1998 @@ -28,6 +28,8 @@ #define F_GETLK 7 #define F_SETLK 8 #define F_SETLKW 9 +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ diff -u --recursive --new-file v2.1.116/linux/include/asm-sparc64/siginfo.h linux/include/asm-sparc64/siginfo.h --- v2.1.116/linux/include/asm-sparc64/siginfo.h Tue Jul 28 14:21:09 1998 +++ linux/include/asm-sparc64/siginfo.h Wed Aug 19 13:24:44 1998 @@ -150,6 +150,7 @@ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ +#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff -u --recursive --new-file v2.1.116/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.116/linux/include/linux/fs.h Fri Jul 31 17:05:52 1998 +++ linux/include/linux/fs.h Wed Aug 19 16:38:43 1998 @@ -39,16 +39,17 @@ #undef NR_OPEN #define NR_OPEN 1024 -#define NR_SUPER 64 #define BLOCK_SIZE_BITS 10 #define BLOCK_SIZE (1< #include @@ -532,7 +535,11 @@ #include #include +extern struct list_head super_blocks; + +#define sb_entry(list) list_entry((list), struct super_block, s_list) struct super_block { + struct list_head s_list; /* Keep this first */ kdev_t s_dev; unsigned long s_blocksize; unsigned char s_blocksize_bits; @@ -591,7 +598,7 @@ int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *); - int (*fasync) (struct file *, int); + int (*fasync) (int, struct file *, int); int (*check_media_change) (kdev_t dev); int (*revalidate) (kdev_t dev); int (*lock) (struct file *, int, struct file_lock *); @@ -704,7 +711,6 @@ extern int fs_may_mount(kdev_t dev); extern struct file *inuse_filps; -extern struct super_block super_blocks[NR_SUPER]; extern void refile_buffer(struct buffer_head * buf); extern void set_writetime(struct buffer_head * buf, int flag); diff -u --recursive --new-file v2.1.116/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h --- v2.1.116/linux/include/linux/sunrpc/clnt.h Tue Aug 18 22:02:08 1998 +++ linux/include/linux/sunrpc/clnt.h Wed Aug 19 16:36:24 1998 @@ -118,6 +118,9 @@ void *argp, void *resp, int flags, rpc_action callback, void *clntdata); void rpc_restart_call(struct rpc_task *); +void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); +void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); + #define rpc_call(clnt, proc, argp, resp, flags) \ rpc_do_call(clnt, proc, argp, resp, flags, NULL, NULL) diff -u --recursive --new-file v2.1.116/linux/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h --- v2.1.116/linux/include/linux/sunrpc/sched.h Fri Jul 31 17:06:24 1998 +++ linux/include/linux/sunrpc/sched.h Wed Aug 19 16:16:04 1998 @@ -146,6 +146,8 @@ void rpc_free(void *); int rpciod_up(void); void rpciod_down(void); +void rpciod_wake_up(void); +void rpciod_tcp_dispatcher(void); #ifdef RPC_DEBUG void rpc_show_tasks(void); #endif diff -u --recursive --new-file v2.1.116/linux/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h --- v2.1.116/linux/include/linux/sunrpc/xprt.h Mon Aug 3 12:45:48 1998 +++ linux/include/linux/sunrpc/xprt.h Wed Aug 19 16:35:31 1998 @@ -36,7 +36,7 @@ * Note: on machines with low memory we should probably use a smaller * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment * reassembly will frequently run out of memory. - * Come Linux 2.1, we'll handle fragments directly. + * Come Linux 2.3, we'll handle fragments directly. */ #define RPC_MAXCONG 16 #define RPC_MAXREQS (RPC_MAXCONG + 1) @@ -103,6 +103,12 @@ * For authentication (e.g. auth_des) */ u32 rq_creddata[2]; + + /* + * Partial send handling + */ + + u32 rq_bytes_sent; /* Bytes we have sent */ #ifdef RPC_PROFILE unsigned long rq_xtime; /* when transmitted */ @@ -166,6 +172,8 @@ */ struct rpc_iov snd_buf; /* send buffer */ struct rpc_task * snd_task; /* Task blocked in send */ + u32 snd_sent; /* Bytes we have sent */ + void (*old_data_ready)(struct sock *, int); void (*old_state_change)(struct sock *); diff -u --recursive --new-file v2.1.116/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.116/linux/include/linux/swap.h Thu Jul 16 18:09:30 1998 +++ linux/include/linux/swap.h Wed Aug 19 13:07:49 1998 @@ -7,6 +7,23 @@ #define MAX_SWAPFILES 8 +union swap_header { + struct + { + char reserved[PAGE_SIZE - 10]; + char magic[10]; + } magic; + struct + { + char bootbits[1024]; /* Space for disklabel etc. */ + unsigned int version; + unsigned int last_page; + unsigned int nr_badpages; + unsigned int padding[125]; + unsigned int badpages[1]; + } info; +}; + #ifdef __KERNEL__ #undef DEBUG_SWAP @@ -18,11 +35,14 @@ #define SWAP_CLUSTER_MAX 32 +#define SWAP_MAP_MAX 0x7fff +#define SWAP_MAP_BAD 0x8000 + struct swap_info_struct { unsigned int flags; kdev_t swap_device; struct dentry * swap_file; - unsigned char * swap_map; + unsigned short * swap_map; unsigned char * swap_lockmap; unsigned int lowest_bit; unsigned int highest_bit; diff -u --recursive --new-file v2.1.116/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.116/linux/include/linux/sysctl.h Thu Aug 6 14:06:34 1998 +++ linux/include/linux/sysctl.h Wed Aug 19 13:07:49 1998 @@ -2,6 +2,23 @@ * sysctl.h: General linux system control interface * * Begun 24 March 1995, Stephen Tweedie + * + **************************************************************** + **************************************************************** + ** + ** WARNING: + ** The values in this file are exported to user space via + ** the sysctl() binary interface. Do *NOT* change the + ** numbering of any existing values here, and do not change + ** any numbers within any one set of values. If you have + ** to redefine an existing interface, use a new number for it. + ** The kernel will then return ENOTDIR to any application using + ** the old binary interface. + ** + ** --sct + ** + **************************************************************** + **************************************************************** */ #include @@ -33,32 +50,32 @@ enum { - CTL_KERN=1, /* General kernel info and control */ +/*1*/ CTL_KERN=1, /* General kernel info and control */ CTL_VM, /* VM management */ CTL_NET, /* Networking */ CTL_PROC, /* Process info */ CTL_FS, /* Filesystems */ CTL_DEBUG, /* Debugging */ - CTL_DEV, /* Devices */ +/*7*/ CTL_DEV, /* Devices */ }; /* CTL_KERN names: */ enum { - KERN_OSTYPE=1, /* string: system version */ +/*1*/ KERN_OSTYPE=1, /* string: system version */ KERN_OSRELEASE, /* string: system release */ KERN_OSREV, /* int: system revision */ KERN_VERSION, /* string: compile time info */ KERN_SECUREMASK, /* struct: maximum rights mask */ KERN_PROF, /* table: profiling information */ KERN_NODENAME, - KERN_DOMAINNAME, - KERN_SECURELVL, /* int: system security level */ +/*8*/ KERN_DOMAINNAME, +/*14*/ KERN_SECURELVL=14, /* int: system security level */ KERN_PANIC, /* int: panic timeout */ - KERN_REALROOTDEV, /* real root device to mount after initrd */ - KERN_JAVA_INTERPRETER, /* path to Java(tm) interpreter */ - KERN_JAVA_APPLETVIEWER, /* path to Java(tm) appletviewer */ +/*16*/ KERN_REALROOTDEV, /* real root device to mount after initrd */ +/*19*/ KERN_JAVA_INTERPRETER=19,/* path to Java(tm) interpreter */ +/*20*/ KERN_JAVA_APPLETVIEWER, /* path to Java(tm) appletviewer */ KERN_SPARC_REBOOT, /* reboot command on Sparc */ KERN_CTLALTDEL, /* int: allow ctl-alt-del to reboot */ KERN_PRINTK, /* sturct: control printk logging parameters */ @@ -67,14 +84,14 @@ KERN_PPC_ZEROPAGED, /* turn idle page zeroing on/off on PPC */ KERN_PPC_POWERSAVE_NAP, /* use nap mode for power saving */ KERN_MODPROBE, - KERN_SG_BIG_BUFF +/*29*/ KERN_SG_BIG_BUFF }; /* CTL_VM names: */ enum { - VM_SWAPCTL=1, /* struct: Set vm swapping control */ +/*1*/ VM_SWAPCTL=1, /* struct: Set vm swapping control */ VM_SWAPOUT, /* int: Background pageout interval */ VM_FREEPG, /* struct: Set free page thresholds */ VM_BDFLUSH, /* struct: Control buffer cache flushing */ @@ -82,14 +99,14 @@ VM_BUFFERMEM, /* struct: Set buffer memory thresholds */ VM_PAGECACHE, /* struct: Set cache memory thresholds */ VM_PAGERDAEMON, /* struct: Control kswapd behaviour */ - VM_PGT_CACHE /* struct: Set page table cache parameters */ +/*9*/ VM_PGT_CACHE /* struct: Set page table cache parameters */ }; /* CTL_NET names: */ enum { - NET_CORE=1, +/*1*/ NET_CORE=1, NET_ETHER, NET_802, NET_UNIX, @@ -98,19 +115,19 @@ NET_ATALK, NET_NETROM, NET_AX25, - NET_BRIDGE, - NET_IPV6, +/*10*/ NET_BRIDGE, NET_ROSE, + NET_IPV6, NET_X25, NET_TR, - NET_DECNET +/*15*/ NET_DECNET }; /* /proc/sys/net/core */ enum { - NET_CORE_WMEM_MAX=1, +/*1*/ NET_CORE_WMEM_MAX=1, NET_CORE_RMEM_MAX, NET_CORE_WMEM_DEFAULT, NET_CORE_RMEM_DEFAULT, @@ -119,7 +136,7 @@ NET_CORE_FASTROUTE, NET_CORE_MSG_COST, NET_CORE_MSG_BURST, - NET_CORE_OPTMEM_MAX, +/*10*/ NET_CORE_OPTMEM_MAX, }; /* /proc/sys/net/ethernet */ @@ -130,23 +147,23 @@ enum { - NET_UNIX_DESTROY_DELAY=1, - NET_UNIX_DELETE_DELAY, +/*1*/ NET_UNIX_DESTROY_DELAY=1, +/*2*/ NET_UNIX_DELETE_DELAY, }; /* /proc/sys/net/ipv4 */ enum { /* v2.0 compatibile variables */ - NET_IPV4_FORWARD = 8, +/*8*/ NET_IPV4_FORWARD = 8, NET_IPV4_DYNADDR = 9, - NET_IPV4_CONF = 16, +/*16*/ NET_IPV4_CONF = 16, NET_IPV4_NEIGH = 17, NET_IPV4_ROUTE = 18, NET_IPV4_FIB_HASH = 19, - NET_IPV4_TCP_HOE_RETRANSMITS=32, +/*32*/ NET_IPV4_TCP_HOE_RETRANSMITS=32, NET_IPV4_TCP_TIMESTAMPS, NET_IPV4_TCP_WINDOW_SCALING, NET_IPV4_TCP_SACK, @@ -154,7 +171,7 @@ NET_IPV4_DEFAULT_TTL, NET_IPV4_AUTOCONFIG, NET_IPV4_NO_PMTU_DISC, - NET_IPV4_TCP_SYN_RETRIES, +/*40*/ NET_IPV4_TCP_SYN_RETRIES, NET_IPV4_IPFRAG_HIGH_THRESH, NET_IPV4_IPFRAG_LOW_THRESH, NET_IPV4_IPFRAG_TIME, @@ -164,7 +181,7 @@ NET_IPV4_TCP_RETRIES1, NET_IPV4_TCP_RETRIES2, NET_IPV4_TCP_FIN_TIMEOUT, - NET_IPV4_IP_MASQ_DEBUG, +/*50*/ NET_IPV4_IP_MASQ_DEBUG, NET_TCP_SYNCOOKIES, NET_TCP_STDURG, NET_TCP_RFC1337, @@ -174,14 +191,14 @@ NET_IPV4_ICMP_ECHO_IGNORE_ALL, NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, NET_IPV4_ICMP_SOURCEQUENCH_RATE, - NET_IPV4_ICMP_DESTUNREACH_RATE, +/*60*/ NET_IPV4_ICMP_DESTUNREACH_RATE, NET_IPV4_ICMP_TIMEEXCEED_RATE, NET_IPV4_ICMP_PARAMPROB_RATE, - NET_IPV4_ICMP_ECHOREPLY_RATE, +/*63*/ NET_IPV4_ICMP_ECHOREPLY_RATE, }; enum { - NET_IPV4_ROUTE_FLUSH = 1, +/*1*/ NET_IPV4_ROUTE_FLUSH = 1, NET_IPV4_ROUTE_MIN_DELAY, NET_IPV4_ROUTE_MAX_DELAY, NET_IPV4_ROUTE_GC_THRESH, @@ -190,24 +207,24 @@ NET_IPV4_ROUTE_GC_TIMEOUT, NET_IPV4_ROUTE_GC_INTERVAL, NET_IPV4_ROUTE_REDIRECT_LOAD, - NET_IPV4_ROUTE_REDIRECT_NUMBER, +/*10*/ NET_IPV4_ROUTE_REDIRECT_NUMBER, NET_IPV4_ROUTE_REDIRECT_SILENCE, NET_IPV4_ROUTE_ERROR_COST, NET_IPV4_ROUTE_ERROR_BURST, - NET_IPV4_ROUTE_GC_ELASTICITY, +/*14*/ NET_IPV4_ROUTE_GC_ELASTICITY, }; enum { - NET_PROTO_CONF_ALL = -2, - NET_PROTO_CONF_DEFAULT = -3, +/*-2*/ NET_PROTO_CONF_ALL = -2, +/*-3*/ NET_PROTO_CONF_DEFAULT = -3, /* And device ifindices ... */ }; enum { - NET_IPV4_CONF_FORWARDING = 1, +/*1*/ NET_IPV4_CONF_FORWARDING = 1, NET_IPV4_CONF_MC_FORWARDING, NET_IPV4_CONF_PROXY_ARP, NET_IPV4_CONF_ACCEPT_REDIRECTS, @@ -216,29 +233,29 @@ NET_IPV4_CONF_SHARED_MEDIA, NET_IPV4_CONF_RP_FILTER, NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, - NET_IPV4_CONF_BOOTP_RELAY, - NET_IPV4_CONF_LOG_MARTIANS, +/*10*/ NET_IPV4_CONF_BOOTP_RELAY, +/*11*/ NET_IPV4_CONF_LOG_MARTIANS, }; /* /proc/sys/net/ipv6 */ enum { - NET_IPV6_CONF = 16, +/*16*/ NET_IPV6_CONF = 16, NET_IPV6_NEIGH = 17, - NET_IPV6_ROUTE = 18, +/*18*/ NET_IPV6_ROUTE = 18, }; enum { - NET_IPV6_ROUTE_FLUSH = 1, +/*1*/ NET_IPV6_ROUTE_FLUSH = 1, NET_IPV6_ROUTE_GC_THRESH, NET_IPV6_ROUTE_MAX_SIZE, NET_IPV6_ROUTE_GC_MIN_INTERVAL, NET_IPV6_ROUTE_GC_TIMEOUT, NET_IPV6_ROUTE_GC_INTERVAL, - NET_IPV6_ROUTE_GC_ELASTICITY, +/*7*/ NET_IPV6_ROUTE_GC_ELASTICITY, }; enum { - NET_IPV6_FORWARDING = 1, +/*1*/ NET_IPV6_FORWARDING = 1, NET_IPV6_HOP_LIMIT, NET_IPV6_MTU, NET_IPV6_ACCEPT_RA, @@ -247,12 +264,12 @@ NET_IPV6_DAD_TRANSMITS, NET_IPV6_RTR_SOLICITS, NET_IPV6_RTR_SOLICIT_INTERVAL, - NET_IPV6_RTR_SOLICIT_DELAY, +/*10*/ NET_IPV6_RTR_SOLICIT_DELAY, }; /* /proc/sys/net//neigh/ */ enum { - NET_NEIGH_MCAST_SOLICIT=1, +/*1*/ NET_NEIGH_MCAST_SOLICIT=1, NET_NEIGH_UCAST_SOLICIT, NET_NEIGH_APP_SOLICIT, NET_NEIGH_RETRANS_TIME, @@ -261,13 +278,13 @@ NET_NEIGH_GC_STALE_TIME, NET_NEIGH_UNRES_QLEN, NET_NEIGH_PROXY_QLEN, - NET_NEIGH_ANYCAST_DELAY, +/*10*/ NET_NEIGH_ANYCAST_DELAY, NET_NEIGH_PROXY_DELAY, NET_NEIGH_LOCKTIME, NET_NEIGH_GC_INTERVAL, NET_NEIGH_GC_THRESH1, NET_NEIGH_GC_THRESH2, - NET_NEIGH_GC_THRESH3 +/*16*/ NET_NEIGH_GC_THRESH3 }; /* /proc/sys/net/ipx */ @@ -275,16 +292,16 @@ /* /proc/sys/net/appletalk */ enum { - NET_ATALK_AARP_EXPIRY_TIME = 1, +/*1*/ NET_ATALK_AARP_EXPIRY_TIME = 1, NET_ATALK_AARP_TICK_TIME, NET_ATALK_AARP_RETRANSMIT_LIMIT, - NET_ATALK_AARP_RESOLVE_TIME, +/*4*/ NET_ATALK_AARP_RESOLVE_TIME, }; /* /proc/sys/net/netrom */ enum { - NET_NETROM_DEFAULT_PATH_QUALITY = 1, +/*1*/ NET_NETROM_DEFAULT_PATH_QUALITY = 1, NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER, NET_NETROM_NETWORK_TTL_INITIALISER, NET_NETROM_TRANSPORT_TIMEOUT, @@ -293,13 +310,13 @@ NET_NETROM_TRANSPORT_BUSY_DELAY, NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE, NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT, - NET_NETROM_ROUTING_CONTROL, - NET_NETROM_LINK_FAILS_COUNT +/*10*/ NET_NETROM_ROUTING_CONTROL, +/*11*/ NET_NETROM_LINK_FAILS_COUNT }; /* /proc/sys/net/ax25 */ enum { - NET_AX25_IP_DEFAULT_MODE = 1, +/*1*/ NET_AX25_IP_DEFAULT_MODE = 1, NET_AX25_DEFAULT_MODE, NET_AX25_BACKOFF_TYPE, NET_AX25_CONNECT_MODE, @@ -308,50 +325,50 @@ NET_AX25_T1_TIMEOUT, NET_AX25_T2_TIMEOUT, NET_AX25_T3_TIMEOUT, - NET_AX25_IDLE_TIMEOUT, +/*10*/ NET_AX25_IDLE_TIMEOUT, NET_AX25_N2, NET_AX25_PACLEN, NET_AX25_PROTOCOL, - NET_AX25_DAMA_SLAVE_TIMEOUT +/*14*/ NET_AX25_DAMA_SLAVE_TIMEOUT }; /* /proc/sys/net/rose */ enum { - NET_ROSE_RESTART_REQUEST_TIMEOUT = 1, +/*1*/ NET_ROSE_RESTART_REQUEST_TIMEOUT = 1, NET_ROSE_CALL_REQUEST_TIMEOUT, NET_ROSE_RESET_REQUEST_TIMEOUT, NET_ROSE_CLEAR_REQUEST_TIMEOUT, - NET_ROSE_NO_ACTIVITY_TIMEOUT, NET_ROSE_ACK_HOLD_BACK_TIMEOUT, NET_ROSE_ROUTING_CONTROL, NET_ROSE_LINK_FAIL_TIMEOUT, NET_ROSE_MAX_VCS, - NET_ROSE_WINDOW_SIZE + NET_ROSE_WINDOW_SIZE, +/*10*/ NET_ROSE_NO_ACTIVITY_TIMEOUT, }; /* /proc/sys/net/x25 */ enum { - NET_X25_RESTART_REQUEST_TIMEOUT = 1, +/*1*/ NET_X25_RESTART_REQUEST_TIMEOUT = 1, NET_X25_CALL_REQUEST_TIMEOUT, NET_X25_RESET_REQUEST_TIMEOUT, NET_X25_CLEAR_REQUEST_TIMEOUT, - NET_X25_ACK_HOLD_BACK_TIMEOUT +/*5*/ NET_X25_ACK_HOLD_BACK_TIMEOUT }; /* /proc/sys/net/token-ring */ enum { - NET_TR_RIF_TIMEOUT=1 +/*1*/ NET_TR_RIF_TIMEOUT=1 }; /* /proc/sys/net/decnet */ enum { - NET_DECNET_DEF_T3_BROADCAST = 1, +/*1*/ NET_DECNET_DEF_T3_BROADCAST = 1, NET_DECNET_DEF_T3_POINTTOPOINT, NET_DECNET_DEF_T1, NET_DECNET_DEF_BCT1, NET_DECNET_CACHETIMEOUT, - NET_DECNET_DEBUG_LEVEL +/*6*/ NET_DECNET_DEBUG_LEVEL }; /* CTL_PROC names: */ @@ -359,7 +376,7 @@ /* CTL_FS names: */ enum { - FS_NRINODE=1, /* int: current number of allocated inodes */ +/*1*/ FS_NRINODE=1, /* int: current number of allocated inodes */ FS_STATINODE, FS_MAXINODE, /* int: maximum number of inodes that can be allocated */ FS_NRDQUOT, /* int: current number of allocated dquots */ @@ -367,18 +384,21 @@ FS_NRFILE, /* int: current number of allocated filedescriptors */ FS_MAXFILE, /* int: maximum number of filedescriptors that can be allocated */ FS_DENTRY, + FS_NRSUPER, /* int: current number of allocated super_blocks */ +/*10*/ FS_MAXSUPER, /* int: maximum number of super_blocks that can be allocated */ }; /* CTL_DEBUG names: */ /* CTL_DEV names: */ enum { - DEV_CDROM = 1, +/*1*/ DEV_CDROM = 1, +/*2*/ DEV_HWMON, }; /* /proc/sys/dev/cdrom */ enum { - DEV_CDROM_INFO = 1, +/*1*/ DEV_CDROM_INFO = 1, }; #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.116/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.1.116/linux/include/linux/videodev.h Tue Aug 18 22:02:08 1998 +++ linux/include/linux/videodev.h Wed Aug 19 14:47:41 1998 @@ -47,6 +47,7 @@ #define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ #define VID_TYPE_SCALES 128 /* Scalable */ #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ struct video_capability { @@ -72,6 +73,7 @@ __u16 type; #define VIDEO_TYPE_TV 1 #define VIDEO_TYPE_CAMERA 2 + __u16 norm; /* Norm set by channel */ }; struct video_tuner @@ -84,6 +86,7 @@ #define VIDEO_TUNER_NTSC 2 #define VIDEO_TUNER_SECAM 4 #define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ +#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ #define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ __u16 mode; /* PAL/NTSC/SECAM/OTHER */ #define VIDEO_MODE_PAL 0 @@ -135,6 +138,8 @@ #define VIDEO_SOUND_LANG1 3 #define VIDEO_SOUND_LANG2 4 __u16 mode; + __u16 balance; /* Stereo balance */ + __u16 step; /* Step actual volume uses */ }; struct video_clip @@ -146,8 +151,8 @@ struct video_window { - __u32 x,y; - __u32 width,height; + __u32 x,y; /* Position of window */ + __u32 width,height; /* Its size */ __u32 chromakey; __u32 flags; struct video_clip *clips; /* Set only */ @@ -155,6 +160,16 @@ #define VIDEO_WINDOW_INTERLACE 1 }; +struct video_capture +{ + __u32 x,y; /* Offsets into image */ + __u32 width, height; /* Area to capture */ + __u16 decimation; /* Decimation divder */ + __u16 flags; /* Flags for capture */ +#define VIDEO_CAPTURE_ODD 0 /* Temporal */ +#define VIDEO_CAPTURE_EVEN 1 +}; + struct video_buffer { void *base; @@ -165,9 +180,9 @@ struct video_mmap { - unsigned int frame; /* Frame (0 or 1) for double buffer */ - int height,width; - unsigned int format; /* should be VIDEO_PALETTE_* */ + unsigned int frame; /* Frame (0 - n) for double buffer */ + int height,width; + unsigned int format; /* should be VIDEO_PALETTE_* */ }; struct video_key @@ -175,7 +190,30 @@ __u8 key[8]; __u32 flags; }; + + +#define VIDEO_MAX_FRAME 32 + +struct video_mbuf +{ + int size; /* Total memory to map */ + int frames; /* Frames */ + int offsets[VIDEO_MAX_FRAME]; +}; + +#define VIDEO_NO_UNIT (-1) + + +struct video_unit +{ + int video; /* Video minor */ + int vbi; /* VBI minor */ + int radio; /* Radio minor */ + int audio; /* Audio minor */ + int teletext; /* Teletext minor */ +}; + #define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ #define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ #define VIDIOCSCHAN _IOW('v',3,int) /* Set channel */ @@ -193,9 +231,12 @@ #define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ #define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ #define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ -#define VIDIOCSYNC _IO('v',18) /* Sync with mmap grabbing */ +#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ #define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ - +#define VIDIOCGMBUF _IOR('v', 20, struct video_mbuf) /* Memory map buffer info */ +#define VIDIOCGUNIT _IOR('v', 21, struct video_unit) /* Get attached units */ +#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get frame buffer */ +#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set frame buffer - root only */ #define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ @@ -213,6 +254,8 @@ #define VID_HARDWARE_SAA7146 11 #define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */ #define VID_HARDWARE_RTRACK2 13 +#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */ +#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */ /* * Initialiser list diff -u --recursive --new-file v2.1.116/linux/kernel/fork.c linux/kernel/fork.c --- v2.1.116/linux/kernel/fork.c Tue Aug 18 22:02:08 1998 +++ linux/kernel/fork.c Tue Aug 18 22:34:16 1998 @@ -356,8 +356,9 @@ return 0; } -/* return value is only accurate by +-sizeof(long)*8 fds */ -/* XXX make this architecture specific */ +/* + * Copy a fd_set and compute the maximum fd it contains. + */ static inline int __copy_fdset(unsigned long *d, unsigned long *src) { int i; @@ -411,7 +412,6 @@ new_fds = (struct file **) kmalloc(size, GFP_KERNEL); if (!new_fds) goto out_release; - memset((void *) new_fds, 0, size); atomic_set(&newf->count, 1); newf->max_fds = NR_OPEN; @@ -421,13 +421,15 @@ old_fds = oldf->fd; for (; i != 0; i--) { - struct file * f = *old_fds; - old_fds++; + struct file *f = *old_fds++; *new_fds = f; if (f) f->f_count++; new_fds++; } + /* This is long word aligned thus could use a optimized version */ + memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds); + tsk->files = newf; error = 0; out: @@ -639,20 +641,13 @@ goto bad_fork; } -static void files_ctor(void *fp, kmem_cache_t *cachep, unsigned long flags) -{ - struct files_struct *f = fp; - - memset(f, 0, sizeof(*f)); -} - __initfunc(void filescache_init(void)) { files_cachep = kmem_cache_create("files_cache", sizeof(struct files_struct), 0, SLAB_HWCACHE_ALIGN, - files_ctor, NULL); + NULL, NULL); if (!files_cachep) panic("Cannot create files cache"); } diff -u --recursive --new-file v2.1.116/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.116/linux/kernel/sched.c Thu Aug 6 14:06:34 1998 +++ linux/kernel/sched.c Wed Aug 19 14:52:23 1998 @@ -1588,11 +1588,13 @@ static void show_task(int nr,struct task_struct * p) { unsigned long free = 0; + int state; static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" }; printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr); - if (((unsigned) p->state) < sizeof(stat_nam)/sizeof(char *)) - printk(stat_nam[p->state]); + state = p->state ? ffz(~p->state) + 1 : 0; + if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *)) + printk(stat_nam[state]); else printk(" "); #if (BITS_PER_LONG == 32) diff -u --recursive --new-file v2.1.116/linux/kernel/signal.c linux/kernel/signal.c --- v2.1.116/linux/kernel/signal.c Sun Jul 26 11:57:19 1998 +++ linux/kernel/signal.c Wed Aug 19 13:24:44 1998 @@ -35,6 +35,9 @@ static kmem_cache_t *signal_queue_cachep; +static int nr_queued_signals; +static int max_queued_signals = 1024; + void signals_init(void) { @@ -64,6 +67,7 @@ while (q) { n = q->next; kmem_cache_free(signal_queue_cachep, q); + nr_queued_signals--; q = n; } } @@ -160,7 +164,8 @@ current->sigqueue_tail = pp; *info = q->info; kmem_cache_free(signal_queue_cachep,q); - + nr_queued_signals--; + /* then see if this signal is still pending. */ q = *pp; while (q) { @@ -300,9 +305,14 @@ make sure at least one signal gets delivered and don't pass on the info struct. */ - struct signal_queue *q = (struct signal_queue *) - kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL); + struct signal_queue *q = 0; + if (nr_queued_signals < max_queued_signals) { + q = (struct signal_queue *) + kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL); + nr_queued_signals++; + } + if (q) { q->next = NULL; *t->sigqueue_tail = q; @@ -825,6 +835,7 @@ else { *pp = q->next; kmem_cache_free(signal_queue_cachep, q); + nr_queued_signals--; } q = *pp; } diff -u --recursive --new-file v2.1.116/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.116/linux/kernel/sysctl.c Thu Aug 6 14:06:34 1998 +++ linux/kernel/sysctl.c Wed Aug 19 13:07:49 1998 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -227,6 +228,10 @@ {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int), 0444, NULL, &proc_dointvec}, {FS_MAXFILE, "file-max", &max_files, sizeof(int), + 0644, NULL, &proc_dointvec}, + {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int), + 0444, NULL, &proc_dointvec}, + {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int), 0644, NULL, &proc_dointvec}, {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int), 0444, NULL, &proc_dointvec}, diff -u --recursive --new-file v2.1.116/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.116/linux/mm/filemap.c Tue Aug 18 22:02:08 1998 +++ linux/mm/filemap.c Wed Aug 19 16:16:04 1998 @@ -7,7 +7,7 @@ /* * This file handles the generic file mmap semantics used by * most "normal" filesystems (but you don't /have/ to use this: - * the NFS filesystem does this differently, for example) + * the NFS filesystem used to do this differently, for example) */ #include #include @@ -172,12 +172,10 @@ break; } age_page(page); -#if 0 if (page->age) break; if (page_cache_size * 100 < (page_cache.min_percent * num_physpages)) break; -#endif if (PageSwapCache(page)) { delete_from_swap_cache(page); return 1; @@ -213,8 +211,8 @@ struct page * page; int count_max, count_min; - count_max = (limit<<1) >> (priority>>1); - count_min = (limit<<1) >> (priority); + count_max = (limit<<2) >> (priority>>1); + count_min = (limit<<2) >> (priority); page = mem_map + clock; do { diff -u --recursive --new-file v2.1.116/linux/mm/swap.c linux/mm/swap.c --- v2.1.116/linux/mm/swap.c Tue Aug 18 22:02:08 1998 +++ linux/mm/swap.c Tue Aug 18 22:14:11 1998 @@ -56,12 +56,15 @@ * Constants for the page aging mechanism: the maximum age (actually, * the maximum "youthfulness"); the quanta by which pages rejuvenate * and age; and the initial age for new pages. + * + * The "pageout_weight" is strictly a fixedpoint number with the + * ten low bits being the fraction (ie 8192 really means "8.0"). */ - swap_control_t swap_control = { 20, 3, 1, 3, /* Page aging */ 32, 4, /* Aging cluster */ - 8192, 8192, /* Pageout and bufferout weights */ + 8192, /* sc_pageout_weight aka PAGEOUT_WEIGHT */ + 8192, /* sc_bufferout_weight aka BUFFEROUT_WEIGHT */ }; swapstat_t swapstats = {0}; @@ -69,11 +72,11 @@ buffer_mem_t buffer_mem = { 5, /* minimum percent buffer */ 25, /* borrow percent buffer */ - 50 /* maximum percent buffer */ + 60 /* maximum percent buffer */ }; buffer_mem_t page_cache = { - 10, /* minimum percent page cache */ + 5, /* minimum percent page cache */ 30, /* borrow percent page cache */ 75 /* maximum */ }; diff -u --recursive --new-file v2.1.116/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.1.116/linux/mm/swap_state.c Mon Aug 3 12:45:48 1998 +++ linux/mm/swap_state.c Wed Aug 19 13:07:49 1998 @@ -85,7 +85,7 @@ } /* - * If swap_map[] reaches 127, the entries are treated as "permanent". + * If swap_map[] reaches SWAP_MAP_MAX the entries are treated as "permanent". */ void swap_duplicate(unsigned long entry) { @@ -105,14 +105,14 @@ goto bad_offset; if (!p->swap_map[offset]) goto bad_unused; - if (p->swap_map[offset] < 126) + if (p->swap_map[offset] < SWAP_MAP_MAX) p->swap_map[offset]++; else { static int overflow = 0; if (overflow++ < 5) printk("swap_duplicate: entry %08lx map count=%d\n", entry, p->swap_map[offset]); - p->swap_map[offset] = 127; + p->swap_map[offset] = SWAP_MAP_MAX; } #ifdef DEBUG_SWAP printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n", diff -u --recursive --new-file v2.1.116/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.116/linux/mm/swapfile.c Tue Jul 28 14:21:10 1998 +++ linux/mm/swapfile.c Wed Aug 19 13:07:49 1998 @@ -116,10 +116,7 @@ } } -/* - * If the swap count overflows (swap_map[] == 127), the entry is considered - * "permanent" and can't be reclaimed until the swap device is closed. - */ + void swap_free(unsigned long entry) { struct swap_info_struct * p; @@ -147,7 +144,7 @@ p->highest_bit = offset; if (!p->swap_map[offset]) goto bad_free; - if (p->swap_map[offset] < 127) { + if (p->swap_map[offset] < SWAP_MAP_MAX) { if (!--p->swap_map[offset]) nr_swap_pages++; } @@ -309,7 +306,7 @@ * Find a swap page in use and read it in. */ for (i = 1 , entry = 0; i < si->max ; i++) { - if (si->swap_map[i] > 0 && si->swap_map[i] != 0x80) { + if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) { entry = SWP_ENTRY(type, i); break; } @@ -334,7 +331,7 @@ delete_from_swap_cache(page_map); free_page(page); if (si->swap_map[i] != 0) { - if (si->swap_map[i] != 127) + if (si->swap_map[i] != SWAP_MAP_MAX) printk("try_to_unuse: entry %08lx " "not in use\n", entry); si->swap_map[i] = 0; @@ -425,7 +422,7 @@ p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; - free_page((long) p->swap_lockmap); + vfree(p->swap_lockmap); p->swap_lockmap = NULL; p->flags = 0; err = 0; @@ -458,7 +455,7 @@ usedswap = 0; for (j = 0; j < ptr->max; ++j) switch (ptr->swap_map[j]) { - case 128: + case SWAP_MAP_BAD: case 0: continue; default: @@ -486,7 +483,12 @@ int error = -EPERM; struct file filp; static int least_priority = 0; - + union swap_header *swap_header = 0; + int swap_header_version; + int lock_map_size = PAGE_SIZE; + int nr_good_pages = 0; + char tmp_lock_map = 0; + lock_kernel(); if (!capable(CAP_SYS_ADMIN)) goto out; @@ -547,54 +549,114 @@ } } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) goto bad_swap; - p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); - if (!p->swap_lockmap) { + swap_header = (void *) __get_free_page(GFP_USER); + if (!swap_header) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } - rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) p->swap_lockmap); - if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) { + + p->swap_lockmap = &tmp_lock_map; + rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) swap_header); + p->swap_lockmap = 0; + + if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10)) + swap_header_version = 1; + else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10)) + swap_header_version = 2; + else { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(p->swap_lockmap+PAGE_SIZE-10,0,10); - j = 0; - p->lowest_bit = 0; - p->highest_bit = 0; - for (i = 1 ; i < 8*PAGE_SIZE ; i++) { - if (test_bit(i,p->swap_lockmap)) { - if (!p->lowest_bit) - p->lowest_bit = i; - p->highest_bit = i; - p->max = i+1; - j++; + + switch (swap_header_version) { + case 1: + memset(((char *) swap_header)+PAGE_SIZE-10,0,10); + j = 0; + p->lowest_bit = 0; + p->highest_bit = 0; + for (i = 1 ; i < 8*PAGE_SIZE ; i++) { + if (test_bit(i,(char *) swap_header)) { + if (!p->lowest_bit) + p->lowest_bit = i; + p->highest_bit = i; + p->max = i+1; + j++; + } + } + nr_good_pages = j; + p->swap_map = vmalloc(p->max * sizeof(short)); + if (!p->swap_map) { + error = -ENOMEM; + goto bad_swap; } + for (i = 1 ; i < p->max ; i++) { + if (test_bit(i,(char *) swap_header)) + p->swap_map[i] = 0; + else + p->swap_map[i] = SWAP_MAP_BAD; + } + break; + + case 2: + /* Check the swap header's sub-version and the size of + the swap file and bad block lists */ + if (swap_header->info.version != 1) { + printk(KERN_WARNING + "Unable to handle swap header version %d\n", + swap_header->info.version); + error = -EINVAL; + goto bad_swap; + } + + p->lowest_bit = 1; + p->highest_bit = swap_header->info.last_page - 1; + p->max = swap_header->info.last_page; + + if (p->max >= 0x7fffffffL/PAGE_SIZE || + (void *) &swap_header->info.badpages[swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) { + error = -EINVAL; + goto bad_swap; + } + + /* OK, set up the swap map and apply the bad block list */ + if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) { + error = -ENOMEM; + goto bad_swap; + } + + error = 0; + memset(p->swap_map, 0, p->max * sizeof(short)); + for (i=0; iinfo.nr_badpages; i++) { + int page = swap_header->info.badpages[i]; + if (page <= 0 || page >= swap_header->info.last_page) + error = -EINVAL; + else + p->swap_map[page] = SWAP_MAP_BAD; + } + nr_good_pages = swap_header->info.last_page - i; + lock_map_size = (p->max + 7) / 8; + if (error) + goto bad_swap; } - if (!j) { - printk("Empty swap-file\n"); + + if (!nr_good_pages) { + printk(KERN_WARNING "Empty swap-file\n"); error = -EINVAL; goto bad_swap; } - p->swap_map = (unsigned char *) vmalloc(p->max); - if (!p->swap_map) { + p->swap_map[0] = SWAP_MAP_BAD; + if (!(p->swap_lockmap = vmalloc (lock_map_size))) { error = -ENOMEM; goto bad_swap; } - for (i = 1 ; i < p->max ; i++) { - if (test_bit(i,p->swap_lockmap)) - p->swap_map[i] = 0; - else - p->swap_map[i] = 0x80; - } - p->swap_map[0] = 0x80; - memset(p->swap_lockmap,0,PAGE_SIZE); + memset(p->swap_lockmap,0,lock_map_size); p->flags = SWP_WRITEOK; - p->pages = j; - nr_swap_pages += j; + p->pages = nr_good_pages; + nr_swap_pages += nr_good_pages; printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n", - j<<(PAGE_SHIFT-10), p->prio); + nr_good_pages<<(PAGE_SHIFT-10), p->prio); /* insert swap space into swap_list: */ prev = -1; @@ -616,8 +678,10 @@ if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: - free_page((long) p->swap_lockmap); - vfree(p->swap_map); + if (p->swap_lockmap) + vfree(p->swap_lockmap); + if (p->swap_map) + vfree(p->swap_map); dput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; @@ -625,6 +689,8 @@ p->swap_lockmap = NULL; p->flags = 0; out: + if (swap_header) + free_page((long) swap_header); unlock_kernel(); return error; } @@ -639,7 +705,7 @@ continue; for (j = 0; j < swap_info[i].max; ++j) switch (swap_info[i].swap_map[j]) { - case 128: + case SWAP_MAP_BAD: continue; case 0: ++val->freeswap; diff -u --recursive --new-file v2.1.116/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.116/linux/mm/vmscan.c Tue Aug 18 22:02:08 1998 +++ linux/mm/vmscan.c Wed Aug 19 13:59:48 1998 @@ -529,6 +529,20 @@ namings for POSIX.4 realtime scheduling priorities. */ + /* + * Tell the memory management that we're a "memory allocator", + * and that if we need more memory we should get access to it + * regardless (see "try_to_free_pages()"). "kswapd" should + * never get caught in the normal page freeing logic. + * + * (Kswapd normally doesn't need memory anyway, but sometimes + * you need a small amount of memory in order to be able to + * page out something else, and this flag essentially protects + * us from recursively trying to free more memory as we're + * trying to free the first piece of memory in the first place). + */ + current->flags |= PF_MEMALLOC; + init_swap_timer(); add_wait_queue(&kswapd_wait, &wait); while (1) { @@ -592,7 +606,7 @@ int retval = 1; lock_kernel(); - if (current->flags & PF_MEMALLOC) { + if (!(current->flags & PF_MEMALLOC)) { current->flags |= PF_MEMALLOC; do { retval = do_try_to_free_page(gfp_mask); @@ -600,7 +614,7 @@ break; count--; } while (count > 0); - current->flags &= PF_MEMALLOC; + current->flags &= ~PF_MEMALLOC; } unlock_kernel(); return retval; diff -u --recursive --new-file v2.1.116/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.116/linux/net/core/dev.c Tue Aug 18 22:02:08 1998 +++ linux/net/core/dev.c Wed Aug 19 10:17:50 1998 @@ -751,7 +751,7 @@ if(br_receive_frame(skb)) return; - kfree_skb(skb, FREE_READ); + kfree_skb(skb); } return; } diff -u --recursive --new-file v2.1.116/linux/net/socket.c linux/net/socket.c --- v2.1.116/linux/net/socket.c Tue Apr 14 14:29:27 1998 +++ linux/net/socket.c Wed Aug 19 13:24:45 1998 @@ -105,7 +105,7 @@ struct poll_table_struct *wait); static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int sock_fasync(struct file *filp, int on); +static int sock_fasync(int fd, struct file *filp, int on); /* @@ -483,7 +483,7 @@ printk(KERN_DEBUG "sock_close: NULL inode\n"); return 0; } - sock_fasync(filp, 0); + sock_fasync(-1, filp, 0); sock_release(socki_lookup(inode)); return 0; } @@ -492,7 +492,7 @@ * Update the socket async list */ -static int sock_fasync(struct file *filp, int on) +static int sock_fasync(int fd, struct file *filp, int on) { struct fasync_struct *fa, *fna=NULL, **prev; struct socket *sock; @@ -520,11 +520,13 @@ { if(fa!=NULL) { + fa->fa_fd=fd; kfree_s(fna,sizeof(struct fasync_struct)); restore_flags(flags); return 0; } fna->fa_file=filp; + fna->fa_fd=fd; fna->magic=FASYNC_MAGIC; fna->fa_next=sock->fasync_list; sock->fasync_list=fna; diff -u --recursive --new-file v2.1.116/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.1.116/linux/net/sunrpc/clnt.c Tue Jul 21 00:15:33 1998 +++ linux/net/sunrpc/clnt.c Wed Aug 19 16:16:04 1998 @@ -191,22 +191,15 @@ } /* - * New rpc_call implementation + * Export the signal mask handling for aysnchronous code that + * sleeps on RPC calls */ -int -rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, - int flags, rpc_action func, void *data) + +void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) { - struct rpc_task my_task, *task = &my_task; unsigned long sigallow = sigmask(SIGKILL); - sigset_t oldset; unsigned long irqflags; - int async, status; - - /* If this client is slain all further I/O fails */ - if (clnt->cl_dead) - return -EIO; - + /* Turn off various signals */ if (clnt->cl_intr) { struct k_sigaction *action = current->sig->action; @@ -216,10 +209,38 @@ sigallow |= sigmask(SIGQUIT); } spin_lock_irqsave(¤t->sigmask_lock, irqflags); - oldset = current->blocked; - siginitsetinv(¤t->blocked, sigallow & ~oldset.sig[0]); + *oldset = current->blocked; + siginitsetinv(¤t->blocked, sigallow & ~oldset->sig[0]); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); +} + +void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) +{ + unsigned long irqflags; + + spin_lock_irqsave(¤t->sigmask_lock, irqflags); + current->blocked = *oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); +} + +/* + * New rpc_call implementation + */ +int +rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, + int flags, rpc_action func, void *data) +{ + struct rpc_task my_task, *task = &my_task; + sigset_t oldset; + int async, status; + + /* If this client is slain all further I/O fails */ + if (clnt->cl_dead) + return -EIO; + + rpc_clnt_sigmask(clnt, &oldset); /* Create/initialize a new RPC task */ if ((async = (flags & RPC_TASK_ASYNC)) != 0) { @@ -248,10 +269,7 @@ } out: - spin_lock_irqsave(¤t->sigmask_lock, irqflags); - current->blocked = oldset; - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); + rpc_clnt_sigunmask(clnt, &oldset); return status; } diff -u --recursive --new-file v2.1.116/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.1.116/linux/net/sunrpc/sched.c Tue Aug 18 22:02:08 1998 +++ linux/net/sunrpc/sched.c Wed Aug 19 16:16:04 1998 @@ -352,6 +352,7 @@ /* * This is the RPC `scheduler' (or rather, the finite state machine). */ + static int __rpc_execute(struct rpc_task *task) { @@ -415,10 +416,16 @@ printk("RPC: rpciod waiting on sync task!\n"); current->timeout = 0; sleep_on(&task->tk_wait); - + /* When the task received a signal, remove from - * any queues etc, and make runnable again. */ - if (0 && signalled()) + * any queues etc, and make runnable again. + * + * The "intr" property isnt handled here. rpc_do_call + * has changed the signal mask of the process for + * a synchronous rpc call. If a signal gets through + * this then its real. + */ + if (signalled()) __rpc_wake_up(task); dprintk("RPC: %4d sync task resuming\n", @@ -432,7 +439,7 @@ * clean up after sleeping on some queue, we don't * break the loop here, but go around once more. */ - if (0 && !RPC_IS_ASYNC(task) && signalled()) { + if (!RPC_IS_ASYNC(task) && signalled()) { dprintk("RPC: %4d got signal\n", task->tk_pid); rpc_exit(task, -ERESTARTSYS); } diff -u --recursive --new-file v2.1.116/linux/net/sunrpc/sunrpc_syms.c linux/net/sunrpc/sunrpc_syms.c --- v2.1.116/linux/net/sunrpc/sunrpc_syms.c Tue Jul 21 00:15:33 1998 +++ linux/net/sunrpc/sunrpc_syms.c Wed Aug 19 16:16:04 1998 @@ -43,6 +43,8 @@ EXPORT_SYMBOL(rpc_killall_tasks); EXPORT_SYMBOL(rpc_do_call); EXPORT_SYMBOL(rpc_call_setup); +EXPORT_SYMBOL(rpc_clnt_sigmask); +EXPORT_SYMBOL(rpc_clnt_sigunmask); EXPORT_SYMBOL(rpc_delay); EXPORT_SYMBOL(rpc_restart_call); diff -u --recursive --new-file v2.1.116/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c --- v2.1.116/linux/net/sunrpc/xprt.c Tue Aug 18 22:02:09 1998 +++ linux/net/sunrpc/xprt.c Wed Aug 19 16:16:04 1998 @@ -34,6 +34,7 @@ * Copyright (C) 1995, 1996, Olaf Kirch * * TCP callback races fixes (C) 1998 Red Hat Software + * TCP send fixes (C) 1998 Red Hat Software */ #define __KERNEL_SYSCALLS__ @@ -136,8 +137,49 @@ } /* + * Adjust the iovec to move on 'n' bytes + */ + +extern inline void xprt_move_iov(struct msghdr *msg, int amount) +{ + struct iovec niv[MAX_IOVEC]; + struct iovec *iv=msg->msg_iov; + + /* + * Eat any sent iovecs + */ + + while(iv->iov_len < amount) + { + amount-=iv->iov_len; + iv++; + msg->msg_iovlen--; + } + + msg->msg_iov=niv; + + /* + * And chew down the partial one + */ + + niv[0].iov_len = iv->iov_len-amount; + niv[0].iov_base =((unsigned char *)iv->iov_base)+amount; + iv++; + + /* + * And copy any others + */ + + for(amount=1;amountmsg_iovlen; amount++) + { + niv[amount]=*iv++; + } +} + +/* * Write data to socket. */ + static inline int xprt_sendmsg(struct rpc_xprt *xprt) { @@ -150,7 +192,6 @@ xprt->snd_buf.io_vec->iov_base, xprt->snd_buf.io_vec->iov_len); -#if LINUX_VERSION_CODE >= 0x020100 msg.msg_flags = MSG_DONTWAIT; msg.msg_iov = xprt->snd_buf.io_vec; msg.msg_iovlen = xprt->snd_buf.io_nr; @@ -158,27 +199,21 @@ msg.msg_namelen = sizeof(xprt->addr); msg.msg_control = NULL; + /* Dont repeat bytes */ + + if(xprt->snd_sent) + xprt_move_iov(&msg, xprt->snd_sent); + oldfs = get_fs(); set_fs(get_ds()); result = sock_sendmsg(sock, &msg, xprt->snd_buf.io_len); set_fs(oldfs); -#else - msg.msg_flags = 0; - msg.msg_iov = xprt->snd_buf.io_vec; - msg.msg_iovlen = xprt->snd_buf.io_nr; - msg.msg_name = (struct sockaddr *) &xprt->addr; - msg.msg_namelen = sizeof(xprt->addr); - msg.msg_control = NULL; - - oldfs = get_fs(); set_fs(get_ds()); - result = sock->ops->sendmsg(sock, &msg, xprt->snd_buf.io_len, 1, 0); - set_fs(oldfs); -#endif dprintk("RPC: xprt_sendmsg(%d) = %d\n", xprt->snd_buf.io_len, result); if (result >= 0) { xprt->snd_buf.io_len -= result; + xprt->snd_sent += result; return result; } @@ -188,6 +223,8 @@ * prompts ECONNREFUSED. */ break; + case -EAGAIN: + return 0; case -ENOTCONN: case -EPIPE: /* connection broken */ break; @@ -828,9 +865,19 @@ if (!(xprt = xprt_from_sock(sk))) return; - xprt->write_space = 1; - if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task)) - rpc_wake_up_task(xprt->snd_task); + if(xprt->snd_sent && xprt->snd_task) + printk("write space\n"); + if(xprt->write_space == 0) + { + xprt->write_space = 1; + if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task)) + { + if(xprt->snd_sent) + printk("Write wakeup snd_sent =%d\n", + xprt->snd_sent); + rpc_wake_up_task(xprt->snd_task); + } + } } /* @@ -889,6 +936,8 @@ struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; + /*DEBUG*/int ac_debug=xprt->snd_sent; + dprintk("RPC: %4d xprt_transmit(%x)\n", task->tk_pid, *(u32 *)(req->rq_svec[0].iov_base)); @@ -935,6 +984,8 @@ } xprt->snd_buf = req->rq_snd_buf; xprt->snd_task = task; + xprt->snd_sent = 0; + /*DEBUG*/ac_debug = 0; } /* For fast networks/servers we have to put the request on @@ -954,10 +1005,12 @@ if (xprt_transmit_some(xprt, task) != -EAGAIN) { dprintk("RPC: %4d xmit complete\n", task->tk_pid); xprt->snd_task = NULL; + if(ac_debug) + printk("Partial xmit finished\n"); return; } - dprintk("RPC: %4d xmit incomplete (%d left of %d)\n", + /*d*/printk("RPC: %4d xmit incomplete (%d left of %d)\n", task->tk_pid, xprt->snd_buf.io_len, req->rq_slen); task->tk_status = 0; @@ -984,10 +1037,15 @@ struct rpc_xprt *xprt = task->tk_client->cl_xprt; dprintk("RPC: %4d transmit_status %d\n", task->tk_pid, task->tk_status); - if (xprt->snd_task == task) { + if (xprt->snd_task == task) + { if (task->tk_status < 0) + { xprt->snd_task = NULL; - xprt_disconnect(xprt); + xprt_disconnect(xprt); + } + else + xprt_transmit(task); } }