From: Linus Torvalds Date: Fri, 23 Nov 2007 20:16:22 +0000 (-0500) Subject: Import 2.1.117pre1 X-Git-Tag: 2.1.117pre1 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=2b421ec7351ffd485dd58f2bc29320ae51dabd8a;p=history.git Import 2.1.117pre1 --- diff --git a/CREDITS b/CREDITS index 2035ac51a84d..d7ee2925775b 100644 --- a/CREDITS +++ b/CREDITS @@ -1193,13 +1193,12 @@ S: D-90453 Nuernberg 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 @@ -1945,6 +1944,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 D: Written kmalloc/kfree diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 813080ebcc00..f04f14bbf37e 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -4354,6 +4354,58 @@ CONFIG_WAVELAN 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 @@ CONFIG_RADIO_RTRACK 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 @@ -9261,6 +9317,28 @@ 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 CONFIG_RADIO_AZTECH Choose Y here if you have one of these FM radio cards, and then fill diff --git a/Documentation/sound/Soundblaster b/Documentation/sound/Soundblaster index ad4cb5567109..160763f53c42 100644 --- a/Documentation/sound/Soundblaster +++ b/Documentation/sound/Soundblaster @@ -7,11 +7,11 @@ are covered by other drivers should not be using this driver. 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 --git a/Makefile b/Makefile index 2291847750a2..1b52ea5b6c57 100644 --- a/Makefile +++ b/Makefile @@ -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 --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index aac4866c13cc..dd9bf9853003 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -556,7 +556,13 @@ ENTRY(sys_call_table) .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 --git a/drivers/char/Makefile b/drivers/char/Makefile index 358fbd3bbd23..baa7c859ac9c 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -391,6 +391,14 @@ else 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 --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c index 35e0c833b243..2703baac0418 100644 --- a/drivers/char/adbmouse.c +++ b/drivers/char/adbmouse.c @@ -144,11 +144,11 @@ static void adb_mouse_interrupt(char *buf, int nb) } -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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c index a3cbd737e4bc..45eaa0a73df3 100644 --- a/drivers/char/amigamouse.c +++ b/drivers/char/amigamouse.c @@ -159,10 +159,10 @@ static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp) 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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c index 113395dbac1e..683d6de80ff5 100644 --- a/drivers/char/atarimouse.c +++ b/drivers/char/atarimouse.c @@ -54,10 +54,10 @@ static void atari_mouse_interrupt(char *buf) /* 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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c index 9ccb06ca6b30..4a25dc4b1751 100644 --- a/drivers/char/atixlmouse.c +++ b/drivers/char/atixlmouse.c @@ -95,10 +95,10 @@ void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) 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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/bt848.h b/drivers/char/bt848.h index a50e31a5c404..79ea691c28af 100644 --- a/drivers/char/bt848.h +++ b/drivers/char/bt848.h @@ -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 --git a/drivers/char/bttv.c b/drivers/char/bttv.c index 8bb3f203efd2..58d8fadc154e 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -1888,6 +1888,41 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 @@ static struct video_device bttv_template= bttv_init_done, NULL, 0, - 0 + -1 }; @@ -2054,7 +2089,7 @@ static struct video_device vbi_template= bttv_init_done, NULL, 0, - 0 + -1 }; @@ -2151,7 +2186,7 @@ static struct video_device radio_template= bttv_init_done, /* just returns 0 */ NULL, 0, - 0 + -1 }; @@ -2979,9 +3014,11 @@ static void release_bttv(void) 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 --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index e8eb8ec8a492..f86a73e9e00a 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -106,11 +106,11 @@ static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) 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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c index a694d9346a38..5fb05738fc8b 100644 --- a/drivers/char/dn_keyb.c +++ b/drivers/char/dn_keyb.c @@ -360,11 +360,11 @@ static ssize_t read_mouse(struct file * file, char * buffer, 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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/macmouse.c b/drivers/char/macmouse.c index 2d7145203b82..e14c235cf500 100644 --- a/drivers/char/macmouse.c +++ b/drivers/char/macmouse.c @@ -150,11 +150,11 @@ static void mac_mouse_interrupt(char *buf, int nb) } -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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c index 9ef067ccc730..6937597738e6 100644 --- a/drivers/char/msbusmouse.c +++ b/drivers/char/msbusmouse.c @@ -89,11 +89,11 @@ static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs) } } -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 fasync_mouse(struct file *filp, int on) 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 --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 18cce49dd474..6068ff3d70cb 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -1070,6 +1070,10 @@ static int msp3400c_command(struct i2c_device *device, (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 --git a/drivers/char/msp3400.h b/drivers/char/msp3400.h index e4029c03ee4b..8b093ff05e1b 100644 --- a/drivers/char/msp3400.h +++ b/drivers/char/msp3400.h @@ -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 --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c index 85ea0fbb4ee8..3921235e2976 100644 --- a/drivers/char/pc110pad.c +++ b/drivers/char/pc110pad.c @@ -474,11 +474,11 @@ static void sample_ps2(int d[3]) -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 fasync_pad(struct file *filp, int on) */ 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 --git a/drivers/char/psaux.c b/drivers/char/psaux.c index 21e753100cc8..50c0b63c44af 100644 --- a/drivers/char/psaux.c +++ b/drivers/char/psaux.c @@ -105,11 +105,11 @@ static inline int queue_empty(void) 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 void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs) 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 @@ static int release_qp(struct inode * inode, struct file * file) { 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 --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c index 014def0c49cc..08fc6116d023 100644 --- a/drivers/char/radio-aimslab.c +++ b/drivers/char/radio-aimslab.c @@ -261,6 +261,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 --git a/drivers/char/radio-aztech.c b/drivers/char/radio-aztech.c index aaeaa726558c..caaa60c7c964 100644 --- a/drivers/char/radio-aztech.c +++ b/drivers/char/radio-aztech.c @@ -218,6 +218,7 @@ static int az_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 --git a/drivers/char/radio-rtrack2.c b/drivers/char/radio-rtrack2.c index 7daeb4e0167d..c035efe293e3 100644 --- a/drivers/char/radio-rtrack2.c +++ b/drivers/char/radio-rtrack2.c @@ -158,6 +158,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 --git a/drivers/char/radio-sf16fmi.c b/drivers/char/radio-sf16fmi.c index 13659fd85eb6..d8dee777d62e 100644 --- a/drivers/char/radio-sf16fmi.c +++ b/drivers/char/radio-sf16fmi.c @@ -176,6 +176,7 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 --git a/drivers/char/radio-zoltrix.c b/drivers/char/radio-zoltrix.c index c820c8a36e1a..8c28247b999a 100644 --- a/drivers/char/radio-zoltrix.c +++ b/drivers/char/radio-zoltrix.c @@ -220,7 +220,8 @@ static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg) 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 --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 5120d07be161..ff5fe5d5a192 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -128,7 +128,7 @@ static int tty_open(struct inode *, struct file *); 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 @@ void do_tty_hangup(void *data) 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 @@ static void release_dev(struct file * filp) 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 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait) * 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 @@ int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp) } 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 @@ int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp) 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 @@ static int tty_fasync(struct file * filp, int on) 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 --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 6d3c23dfb879..590a0df97d66 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -1977,8 +1977,8 @@ ppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb) */ 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 --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 4f511f3abf36..95a89cdb6eb9 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -205,7 +205,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then 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 --git a/drivers/sound/Makefile b/drivers/sound/Makefile index d04efe300901..f072b7fad391 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o 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 @@ -92,7 +92,6 @@ obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o endif endif - # Declare multi-part drivers. list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \ diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 5a9b4ec9e0d5..2e6abb3d66d3 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -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 { /* --------------------------------------------------------------------- */ -struct es1370_state *devs = NULL; +static struct es1370_state *devs = NULL; /* --------------------------------------------------------------------- */ @@ -464,10 +473,9 @@ static void start_adc(struct es1370_state *s) /* --------------------------------------------------------------------- */ -#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 @@ extern inline void dealloc_dmabuf(struct dmabuf *db) 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 @@ static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate, 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 @@ static const struct { [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 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a } 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 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a 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 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a 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 @@ __initfunc(int init_es1370(void)) 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 @@ void cleanup_module(void) 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 --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 8fcc035418bd..6a510d9d4db4 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -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 es1371_state { 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 { /* --------------------------------------------------------------------- */ -struct es1371_state *devs = NULL; +static struct es1371_state *devs = NULL; /* --------------------------------------------------------------------- */ @@ -704,7 +711,7 @@ static void start_adc(struct es1371_state *s) /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 @@ -982,7 +989,7 @@ static const unsigned int recsrc[8] = 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 @@ static const unsigned char volreg[] = [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 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg) } } +#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 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a 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 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a 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 @@ __initfunc(int init_es1371(void)) 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 @@ __initfunc(int init_es1371(void)) #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 --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index c15bced8806e..c73e6f06b160 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -3142,6 +3142,7 @@ void gus_wave_init(struct address_info *hw_config) 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 --git a/drivers/sound/lowlevel/aci.c b/drivers/sound/lowlevel/aci.c index d46088b8eee6..b98c02ea6d5e 100644 --- a/drivers/sound/lowlevel/aci.c +++ b/drivers/sound/lowlevel/aci.c @@ -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 @@ void unload_aci(void) } #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 --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index b0a330ca454b..7cc2fa6ef41d 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -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 @@ typedef struct multisound_dev { #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 --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index ac33dcab861b..07bba6bc6ca6 100644 --- a/drivers/sound/msnd_pinnacle.c +++ b/drivers/sound/msnd_pinnacle.c @@ -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 int mixer_set(int d, int value) 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 @@ static unsigned long set_recsrc(unsigned long recsrc) 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 @@ static unsigned long set_recsrc(unsigned long recsrc) 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 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) break; } + ++dev.mixer_mod_count; + return put_user(val, (int *)arg); } else { @@ -479,6 +506,8 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) #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 @@ __initfunc(static int attach_multisound(void)) 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 (mem, "i"); 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 @@ int init_module(void) 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)) @@ -1460,6 +1513,13 @@ __initfunc(int msnd_pinnacle_init(void)) 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); init_waitqueue(&dev.writeflush); diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index bc6382f99ebc..8898c655a15f 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -169,7 +169,7 @@ int opl3_detect(int ioaddr, int *osp) 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 @@ static int opl3_start_note (int dev, int voice, int note, int volume) 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 @@ int opl3_init(int ioaddr, int *osp) 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 @@ int opl3_init(int ioaddr, int *osp) 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 @@ int opl3_init(int ioaddr, int *osp) } 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 me; 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 @@ void cleanup_module(void) { if (devc) { + if(devc->base) + release_region(devc->base,4); kfree(devc); devc = NULL; sound_unload_synthdev(me); diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 8d7ffe1a716f..19f8ee825836 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -121,7 +121,7 @@ int sb_dsp_reset (sb_devc *devc); void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); int sb_dsp_detect (struct address_info *hw_config); -void sb_dsp_init (struct address_info *hw_config); +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 --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 432501ebc522..2fc88cb24e08 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -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 @@ int probe_sb(struct address_info *hw_config) 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 @@ int init_module(void) { 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 @@ int init_module(void) 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 --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 8fe5a44f0325..3ec472f4d26c 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -162,7 +162,7 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) break; default: - /* printk( "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ ; } } @@ -242,7 +242,7 @@ static int sb16_set_dma_hw(sb_devc * devc) 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 @@ static int sb16_set_irq_hw(sb_devc * devc, int level) 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 @@ int sb_dsp_detect(struct address_info *hw_config) 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 @@ void sb_dsp_init(struct address_info *hw_config) if (detected_devc == NULL) { MDB(printk("No detected device\n")); - return; + return 0; } devc = detected_devc; detected_devc = NULL; @@ -718,7 +718,7 @@ void sb_dsp_init(struct address_info *hw_config) 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 @@ void sb_dsp_init(struct address_info *hw_config) 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 @@ void sb_dsp_init(struct address_info *hw_config) 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 @@ void sb_dsp_init(struct address_info *hw_config) 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 @@ void sb_dsp_init(struct address_info *hw_config) { 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 @@ void sb_dsp_init(struct address_info *hw_config) { MDB(printk("Sound Blaster: no audio devices found.\n")); } + return 1; } void sb_dsp_disable_midi(int io_base) @@ -1160,7 +1165,9 @@ static int ess_midi_init(sb_devc * devc, struct address_info *hw_config) 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 --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index e4f962035baf..514333512207 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -1061,7 +1061,10 @@ int sequencer_open(int dev, struct file *file) setup_mode2(); } if (!max_synthdev && !max_mididev) + { + sequencer_busy=0; return -ENXIO; + } synth_open_mask = 0; diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 4f81fcdf3590..066d722eb95e 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -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 @@ struct sv_state { /* 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 @@ static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate) 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 @@ static void start_adc(struct sv_state *s) /* --------------------------------------------------------------------- */ -#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 @@ static const struct { [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 @@ static int return_mixval(struct sv_state *s, unsigned i, int *arg) 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 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) 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 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) 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 @@ static /*const*/ struct file_operations sv_dmfm_fops = { #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 @@ __initfunc(int init_sonicvibes(void)) 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 @@ __initfunc(int init_sonicvibes(void)) /* 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 @@ __initfunc(int init_sonicvibes(void)) 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 @@ __initfunc(int init_sonicvibes(void)) #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 --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 2abd7fa2224d..d679ff8bc715 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -846,12 +846,16 @@ static int sound[20] = { #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 --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index 735dcd93f612..3740dd263ce2 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -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 @@ int fx_raw = 1; /* if this is zero, we'll leave the FX processor in 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 @@ int wf_debug_default = 0; /* you can set this to control debugging /* 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 - */ +char *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 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. -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 */ + 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 struct synth_info wavefront_info = 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 @@ typedef struct wf_config { 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 @@ typedef struct wf_config { 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_ioctl (struct wf_config *, wavefront_fx_info *); 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 @@ static wavefront_command wavefront_commands[] = { { 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 @@ wavefront_wait (wf_config *hw, int mask) { int i; + static int short_loop_cnt = 0; + + 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 < wf_short_wait_count; i++) { + 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 @@ wavefront_read (wf_config *hw) 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 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_cmd (wf_config *hw, int cmd, } else { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: error %d (%s) during " @@ -542,6 +566,7 @@ wavefront_cmd (wf_config *hw, int cmd, wavefront_errorstr (c), i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -549,20 +574,24 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_cmd (wf_config *hw, int cmd, 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 @@ wavefront_get_sample_status (struct wf_config *hw, int assume_rom) WF_MAX_SAMPLE - hw->samples_used); - return 0; + return (0); } @@ -826,6 +865,7 @@ wavefront_get_patch_status (struct wf_config *hw) printk (KERN_ERR "WaveFront: upload patch " "error 0x%x\n", x); hw->patch_status[i] = 0; + return 1; } } @@ -843,7 +883,7 @@ wavefront_get_patch_status (struct wf_config *hw) printk (KERN_INFO "WaveFront: %d patch slots filled, %d in use\n", cnt, cnt2); - return 0; + return (0); } static int @@ -889,7 +929,7 @@ wavefront_get_program_status (struct wf_config *hw) printk (KERN_INFO "WaveFront: %d programs slots in use\n", cnt); - return 0; + return (0); } static int @@ -900,10 +940,12 @@ wavefront_send_patch (wf_config *hw, 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 @@ wavefront_send_patch (wf_config *hw, 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 @@ wavefront_send_program (wf_config *hw, 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 @@ wavefront_send_program (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, header->number, header->subkey, header->size, (int) header->dataptr); } +#endif WF_DEBUG if (header->size) { @@ -1032,10 +1078,9 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, printk (KERN_ERR "WaveFront: channel selection only possible " "on 16-bit samples"); - return -EINVAL; + return -(EINVAL); } } @@ -1108,11 +1153,13 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, /* 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 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, 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 @@ wavefront_send_sample (wf_config *hw, */ sent: - return 0; + return (0); } static int @@ -1282,12 +1329,14 @@ wavefront_send_alias (struct wf_config *hw, { 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 @@ wavefront_send_alias (struct wf_config *hw, 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 @@ wavefront_send_multisample (struct wf_config *hw, 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 @@ wavefront_send_multisample (struct wf_config *hw, (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 @@ wavefront_fetch_multisample (struct wf_config *hw, 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 @@ wavefront_fetch_multisample (struct wf_config *hw, 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_send_drum (struct wf_config *hw, wavefront_patch_info *header) 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 @@ wavefront_send_drum (struct wf_config *hw, wavefront_patch_info *header) 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 @@ wavefront_find_free_patch (struct wf_config *hw) { 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 @@ wavefront_load_gus_patch (struct wf_config *hw, /* 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 @@ wavefront_load_patch (int dev, int format, const char *addr, 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 @@ wavefront_load_patch (int dev, int format, const char *addr, } 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 @@ wavefront_load_patch (int dev, int format, const char *addr, 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 @@ wavefront_load_patch (int dev, int format, const char *addr, 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 @@ wavefront_load_patch (int dev, int format, const char *addr, 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 @@ wavefront_load_patch (int dev, int format, const char *addr, 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 @@ wavefront_load_patch (int dev, int format, const char *addr, default: printk (KERN_ERR "WaveFront: unknown patch type %d.\n", header.subkey); - return -EINVAL; + return -(EINVAL); } return 0; @@ -1804,24 +1861,19 @@ static int 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 @@ wavefront_synth_control (int dev, int cmd, caddr_t arg) 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 @@ WaveFront: MIDI synth interface 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 @@ wavefront_ioctl (int dev, unsigned int cmd, caddr_t arg) return wavefront_synth_control (dev, cmd, arg); default: - return -EINVAL; + return -(EINVAL); } } @@ -2000,32 +2048,30 @@ static int 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 @@ wavefront_close (int dev) 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 @@ static void wavefront_reset (int dev) { 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 @@ WaveFront: OSS/Free and/or Linux kernel installation interface 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 @@ wavefrontintr (int irq, void *dev_id, struct pt_regs *dummy) 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]; - - 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; + int bits; - 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 @@ probe_wavefront (struct address_info *hw_config) 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 @@ probe_wavefront (struct address_info *hw_config) 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 @@ probe_wavefront (struct address_info *hw_config) */ - /* 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; - - /* 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. + + /* 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. + + Interesting question: why is no RX interrupt received first ? */ + + wavefront_should_cause_interrupt(hw, WFC_HARDWARE_VERSION, + hw->data_port, 20*HZ); - 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; - } - } + 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 @@ wavefront_download_firmware (wf_config *hw, char *path) 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 @@ wavefront_download_firmware (wf_config *hw, char *path) 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 @@ wavefront_download_firmware (wf_config *hw, char *path) 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 @@ wavefront_config_midi (wf_config *hw, struct address_info *hw_config) } 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 @@ attach_wavefront (struct address_info *hw_config) } 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 @@ attach_wavefront (struct address_info *hw_config) 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 @@ wffx_memset (struct wf_config *hw, int page, 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 @@ wffx_memset (struct wf_config *hw, int page, "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 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r) 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 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r) printk (KERN_WARNING "WaveFront: FX: ioctl %d not yet supported\n", r->request); - return -EINVAL; + return -(EINVAL); } } @@ -3364,7 +3576,7 @@ wffx_init (struct wf_config *hw) outb (0x00, hw->fx_op); /* mute off */ - return 0; + return (0); } EXPORT_NO_SYMBOLS; @@ -3388,6 +3600,7 @@ int init_module (void) "options must be set.\n"); return -EINVAL; } + cfg.io_base = io; cfg.irq = irq; @@ -3406,7 +3619,6 @@ void cleanup_module (void) SOUND_LOCK_END; } -#endif MODULE -#endif CONFIG_SOUND_WAVEFRONT +#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c index c525abc97a70..2333fd118d55 100644 --- a/drivers/sound/wf_midi.c +++ b/drivers/sound/wf_midi.c @@ -454,12 +454,12 @@ wf_mpu_open (int dev, int mode, 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 @@ static struct synth_operations wf_mpu_synth_proto = 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 @@ config_wf_mpu (int dev, struct address_info *hw_config) 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 --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 608b72d93614..a14debe633b3 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1193,8 +1193,9 @@ static int elf_core_dump(long signr, struct pt_regs * regs) 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 --git a/fs/dcache.c b/fs/dcache.c index 4c7ea2e3b265..6cd34bb4a6b0 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -643,9 +643,10 @@ int d_validate(struct dentry *dentry, struct dentry *dparent, * 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 --git a/fs/fcntl.c b/fs/fcntl.c index a35db83a8649..91920408867b 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -84,7 +84,7 @@ asmlinkage int sys_dup(unsigned int fildes) #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 @@ static int setfl(struct file * filp, unsigned long arg) /* 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 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) 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 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) 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 @@ out: 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 @@ static void send_sigio(int pid, uid_t uid, uid_t euid) (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 @@ void kill_fasync(struct fasync_struct *fa, int sig) } 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 --git a/fs/inode.c b/fs/inode.c index 2b8f7a1985a9..c68ea1b4c552 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -177,14 +177,13 @@ static inline void sync_list(struct list_head *head) */ 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 --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 66b33161f898..ba7a6c6e9719 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -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 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) 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 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) 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 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde 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 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde 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 --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 81da8f9968dd..3ecb9bfa630e 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c @@ -78,6 +78,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr) clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; + clnt->cl_intr = 1; } return clnt; } diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1c6a74a71799..bab335a15f30 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -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 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) 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 --git a/fs/nfs/write.c b/fs/nfs/write.c index c317f330bbd3..0a58b6a025a8 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -468,7 +468,9 @@ wait_on_write_request(struct nfs_wreq *req) 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 @@ wait_on_write_request(struct nfs_wreq *req) if (!PageLocked(page)) break; retval = -ERESTARTSYS; - if (IS_SOFT && signalled()) + /* IS_SOFT is a timeout item .. */ + if (signalled()) break; schedule(); } @@ -485,6 +488,7 @@ wait_on_write_request(struct nfs_wreq *req) 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 @@ nfs_updatepage(struct file *file, struct page *page, const char *buffer, 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 @@ nfs_wback_result(struct rpc_task *task) /* 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 --git a/fs/proc/array.c b/fs/proc/array.c index 0d4b748fcecf..d5a97963983c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -485,16 +485,18 @@ static unsigned long get_wchan(struct task_struct *p) 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 --git a/fs/super.c b/fs/super.c index 07aa03a63c98..924a02f8fc31 100644 --- a/fs/super.c +++ b/fs/super.c @@ -68,7 +68,10 @@ static int do_remount_sb(struct super_block *sb, int flags, char * data); /* 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 @@ void sync_supers(kdev_t dev) { 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 @@ struct super_block * get_super(kdev_t dev) 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 @@ out: */ 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 @@ clean_up: 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 @@ __initfunc(static void do_mount_root(void)) 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(static void do_mount_root(void)) } -__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 @@ __initfunc(static int do_change_root(kdev_t new_root_dev,const char *put_old)) return -EBUSY; } ROOT_DEV = new_root_dev; - do_mount_root(); + mount_root(); dput(old_root); dput(old_pwd); #if 1 diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index be37113d5472..49cc35d8d624 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1771,8 +1771,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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); @@ -1816,6 +1814,16 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, 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; if (res == 0) { diff --git a/include/asm-alpha/fcntl.h b/include/asm-alpha/fcntl.h index 3df5edf2bedc..7f0e967aac65 100644 --- a/include/asm-alpha/fcntl.h +++ b/include/asm-alpha/fcntl.h @@ -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 --git a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h index c2304b041979..f9f3e040ad44 100644 --- a/include/asm-alpha/siginfo.h +++ b/include/asm-alpha/siginfo.h @@ -87,6 +87,7 @@ typedef struct siginfo { #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 --git a/include/asm-arm/fcntl.h b/include/asm-arm/fcntl.h index af29f7f4641d..a9e469a492ce 100644 --- a/include/asm-arm/fcntl.h +++ b/include/asm-arm/fcntl.h @@ -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 --git a/include/asm-arm/siginfo.h b/include/asm-arm/siginfo.h index bcec2810f28a..2dec6e08079d 100644 --- a/include/asm-arm/siginfo.h +++ b/include/asm-arm/siginfo.h @@ -87,6 +87,7 @@ typedef struct siginfo { #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 --git a/include/asm-i386/fcntl.h b/include/asm-i386/fcntl.h index 369ac5153b7b..dfdd500c6ef5 100644 --- a/include/asm-i386/fcntl.h +++ b/include/asm-i386/fcntl.h @@ -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 --git a/include/asm-i386/siginfo.h b/include/asm-i386/siginfo.h index 01ef4d08ab13..d0cae4709254 100644 --- a/include/asm-i386/siginfo.h +++ b/include/asm-i386/siginfo.h @@ -87,6 +87,7 @@ typedef struct siginfo { #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 --git a/include/asm-m68k/fcntl.h b/include/asm-m68k/fcntl.h index c1f6ea405a0a..500d495bf21b 100644 --- a/include/asm-m68k/fcntl.h +++ b/include/asm-m68k/fcntl.h @@ -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 --git a/include/asm-m68k/siginfo.h b/include/asm-m68k/siginfo.h index f6799d2b1e95..4061e6f72946 100644 --- a/include/asm-m68k/siginfo.h +++ b/include/asm-m68k/siginfo.h @@ -87,6 +87,7 @@ typedef struct siginfo { #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 --git a/include/asm-mips/fcntl.h b/include/asm-mips/fcntl.h index 3606b252adae..d40aac7e8454 100644 --- a/include/asm-mips/fcntl.h +++ b/include/asm-mips/fcntl.h @@ -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 --git a/include/asm-mips/siginfo.h b/include/asm-mips/siginfo.h index 2cf7fd22ebce..83893d5af56b 100644 --- a/include/asm-mips/siginfo.h +++ b/include/asm-mips/siginfo.h @@ -87,6 +87,7 @@ typedef struct siginfo { #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 --git a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h index 61d0fa703f74..773e6a252435 100644 --- a/include/asm-ppc/fcntl.h +++ b/include/asm-ppc/fcntl.h @@ -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 --git a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h index 0ead0b84e575..c3a46ceffa48 100644 --- a/include/asm-ppc/siginfo.h +++ b/include/asm-ppc/siginfo.h @@ -87,6 +87,7 @@ typedef struct siginfo { #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 --git a/include/asm-sparc/fcntl.h b/include/asm-sparc/fcntl.h index 5e4a68af6f5a..775a800d4f22 100644 --- a/include/asm-sparc/fcntl.h +++ b/include/asm-sparc/fcntl.h @@ -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 --git a/include/asm-sparc/siginfo.h b/include/asm-sparc/siginfo.h index 0509aa1b317a..0a666b4e2fb7 100644 --- a/include/asm-sparc/siginfo.h +++ b/include/asm-sparc/siginfo.h @@ -91,6 +91,7 @@ typedef struct siginfo { #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 --git a/include/asm-sparc64/fcntl.h b/include/asm-sparc64/fcntl.h index 33044df82d6e..1db734bed188 100644 --- a/include/asm-sparc64/fcntl.h +++ b/include/asm-sparc64/fcntl.h @@ -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 --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h index ff2534c66cf0..b3ccd57a9bb1 100644 --- a/include/asm-sparc64/siginfo.h +++ b/include/asm-sparc64/siginfo.h @@ -150,6 +150,7 @@ typedef struct siginfo32 { #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 --git a/include/linux/fs.h b/include/linux/fs.h index ed86feae5e45..24b132b249cc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -39,16 +39,17 @@ struct poll_table_struct; #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 @@ extern int fasync_helper(struct file *, int, struct fasync_struct **); #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 @@ struct file_operations { 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_remount_ro(struct super_block *); 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 --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 8553a05c507b..98a25005186d 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -118,6 +118,9 @@ int rpc_do_call(struct rpc_clnt *clnt, u32 proc, 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 --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 697950b2ee7b..f0f8e03845e5 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -146,6 +146,8 @@ void * rpc_allocate(unsigned int flags, unsigned int); 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 --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 0037b5738d7a..df16576d7d7e 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -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 @@ struct rpc_rqst { * 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_xprt { */ 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 --git a/include/linux/swap.h b/include/linux/swap.h index 07ac5fbf9d16..aeeff7ef4e4b 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -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 --git a/include/linux/sysctl.h b/include/linux/sysctl.h index ef9044aa184f..c310573ee02b 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -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 @@ struct __sysctl_args { 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 @@ enum 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 @@ enum 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 @@ enum 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 @@ enum 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 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 @@ enum 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 @@ enum 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 @@ enum 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 @@ enum { 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 @@ enum 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 @@ enum { 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 @@ enum { 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 @@ enum { /* /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 @@ enum { 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 @@ enum { 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 @@ enum { /* 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 @@ enum 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 --git a/include/linux/videodev.h b/include/linux/videodev.h index 701fb8870659..11943bcd7126 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -47,6 +47,7 @@ extern void video_unregister_device(struct video_device *); #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 @@ struct video_channel __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 @@ struct video_tuner #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 @@ struct video_audio #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_clip 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 @@ struct video_window #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_buffer 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 @@ struct video_key __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 @@ struct video_key #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 @@ struct video_key #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 --git a/kernel/fork.c b/kernel/fork.c index 5a577abe382e..6035d7a5009a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -356,8 +356,9 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) 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 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) 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 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) 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 @@ bad_fork_free: 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 --git a/kernel/sched.c b/kernel/sched.c index 1b76fee500c8..ace9d0f130f2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1588,11 +1588,13 @@ asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) 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 --git a/kernel/signal.c b/kernel/signal.c index cfd87da4a796..b1e0a642c518 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -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 @@ flush_signals(struct task_struct *t) while (q) { n = q->next; kmem_cache_free(signal_queue_cachep, q); + nr_queued_signals--; q = n; } } @@ -160,7 +164,8 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid, 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 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig); 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 @@ do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) else { *pp = q->next; kmem_cache_free(signal_queue_cachep, q); + nr_queued_signals--; } q = *pp; } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 95db1657615e..20798b239f41 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -228,6 +229,10 @@ static ctl_table fs_table[] = { 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}, {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int), diff --git a/mm/filemap.c b/mm/filemap.c index 1cdfb61d94e4..cea727b96467 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -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 @@ static inline int shrink_one_page(struct page *page, int gfp_mask) 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 @@ int shrink_mmap(int priority, int gfp_mask) 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 --git a/mm/swap.c b/mm/swap.c index 3cedb215c8b7..7ddd801f8660 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -56,12 +56,15 @@ atomic_t nr_async_pages = ATOMIC_INIT(0); * 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 @@ swapstat_t swapstats = {0}; 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 --git a/mm/swap_state.c b/mm/swap_state.c index eb52f7b4bf3d..a6c45008dc02 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -85,7 +85,7 @@ int add_to_swap_cache(struct page *page, unsigned long entry) } /* - * 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 @@ void swap_duplicate(unsigned long entry) 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 --git a/mm/swapfile.c b/mm/swapfile.c index d33a334cb61a..0df60f6f0c0b 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -116,10 +116,7 @@ unsigned long get_swap_page(void) } } -/* - * 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 @@ void swap_free(unsigned long entry) 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 @@ static int try_to_unuse(unsigned int type) * 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 @@ static int try_to_unuse(unsigned int type) 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 @@ asmlinkage int sys_swapoff(const char * specialfile) 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 @@ int get_swaparea_info(char *buf) 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 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) 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 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) } } 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 @@ bad_swap: 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 @@ bad_swap_2: p->swap_lockmap = NULL; p->flags = 0; out: + if (swap_header) + free_page((long) swap_header); unlock_kernel(); return error; } @@ -639,7 +705,7 @@ void si_swapinfo(struct sysinfo *val) 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 --git a/mm/vmscan.c b/mm/vmscan.c index b586bce72f93..63faf546583f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -529,6 +529,20 @@ int kswapd(void *unused) 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 try_to_free_pages(unsigned int gfp_mask, int count) 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 @@ int try_to_free_pages(unsigned int gfp_mask, int count) break; count--; } while (count > 0); - current->flags &= PF_MEMALLOC; + current->flags &= ~PF_MEMALLOC; } unlock_kernel(); return retval; diff --git a/net/core/dev.c b/net/core/dev.c index 316f6d799bfb..eafeefac135c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -751,7 +751,7 @@ static inline void handle_bridge(struct sk_buff *skb, unsigned short type) if(br_receive_frame(skb)) return; - kfree_skb(skb, FREE_READ); + kfree_skb(skb); } return; } diff --git a/net/socket.c b/net/socket.c index 6a26240587cf..1d905854d48d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -105,7 +105,7 @@ static unsigned int sock_poll(struct file *file, 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 @@ int sock_close(struct inode *inode, struct file *filp) 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 @@ int sock_close(struct inode *inode, struct file *filp) * 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 @@ static int sock_fasync(struct file *filp, int on) { 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 --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index b1a8150ec031..c2690684644b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -191,22 +191,15 @@ rpc_default_callback(struct rpc_task *task) } /* - * 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 @@ rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, 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 @@ rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, } 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 --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 8caaa46e820f..222f905da87f 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -352,6 +352,7 @@ __rpc_atrun(struct rpc_task *task) /* * This is the RPC `scheduler' (or rather, the finite state machine). */ + static int __rpc_execute(struct rpc_task *task) { @@ -415,10 +416,16 @@ __rpc_execute(struct rpc_task *task) 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 @@ __rpc_execute(struct rpc_task *task) * 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 --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 6ccf2e29f57a..e0be9527cf9a 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -43,6 +43,8 @@ EXPORT_SYMBOL(rpc_shutdown_client); 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 --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e2af81be4f9e..518703d070fa 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -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__ @@ -135,9 +136,50 @@ xprt_from_sock(struct sock *sk) #endif } +/* + * 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_sendmsg(struct rpc_xprt *xprt) 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 @@ xprt_sendmsg(struct rpc_xprt *xprt) 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 @@ xprt_sendmsg(struct rpc_xprt *xprt) * prompts ECONNREFUSED. */ break; + case -EAGAIN: + return 0; case -ENOTCONN: case -EPIPE: /* connection broken */ break; @@ -828,9 +865,19 @@ tcp_write_space(struct sock *sk) 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 @@ xprt_transmit(struct rpc_task *task) 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_transmit(struct rpc_task *task) } 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 @@ xprt_transmit(struct rpc_task *task) 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 @@ xprt_transmit_status(struct rpc_task *task) 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); } }