From 47eb772746221bd8b1a6beeb53b4552781c7e613 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:25:09 -0500 Subject: [PATCH] Linux-2.3.3 and a short hiatus.. There's a Linux-2.3.3 out there on ftp.kernel.org, this one hopefully fixes pretty much all the waitqueue changes (and I'll disable waitqueue debugging in 2.3.4 unless something comes up). And yes, before anybody tells me, I know I forgot to increment the version number. So "uname" is goign to report 2.3.2 unless you fix that by hand. I'm also leaving for a very quick trip to Finland in another two hours, so don't bother emailing me - please discuss isues on the kernel list, and I'll catch up when I get back on Friday (yes, I'll spen as much time in airplanes as I do on the ground - fun, fun). Have fun, Linus --- CREDITS | 11 +- Documentation/Configure.help | 20 +- Documentation/filesystems/hpfs.txt | 15 +- Documentation/mtrr.txt | 10 +- MAINTAINERS | 6 + arch/i386/Makefile | 11 +- arch/i386/lib/checksum.S | 12 +- arch/m68k/atari/stdma.c | 2 +- arch/m68k/mac/adb-bus.c | 8 +- arch/mips/kernel/irixsig.c | 2 +- arch/ppc/8xx_io/uart.c | 6 +- arch/sparc/defconfig | 1 + arch/sparc64/defconfig | 1 + arch/sparc64/kernel/sys_sparc32.c | 104 +++- arch/sparc64/solaris/fs.c | 2 +- arch/sparc64/solaris/ipc.c | 3 +- drivers/acorn/block/fd1772.c | 2 +- drivers/acorn/block/mfmhd.c | 2 +- drivers/ap1000/ap.c | 2 +- drivers/ap1000/ddv.c | 4 +- drivers/block/Makefile | 2 +- drivers/block/acsi.c | 18 +- drivers/block/ataflop.c | 24 +- drivers/block/blkpg.c | 288 +++++++++++ drivers/block/cmd646.c | 2 +- drivers/block/floppy.c | 23 +- drivers/block/genhd.c | 48 +- drivers/block/hd.c | 28 +- drivers/block/ide.c | 131 +---- drivers/block/md.c | 56 +-- drivers/block/paride/pd.c | 29 +- drivers/block/paride/pf.c | 26 +- drivers/block/ps2esdi.c | 28 +- drivers/block/rd.c | 12 +- drivers/block/xd.c | 23 +- drivers/cdrom/gscd.c | 2 +- drivers/cdrom/sbpcd.c | 2 +- drivers/char/cyclades.c | 2 +- drivers/char/dn_keyb.c | 2 +- drivers/char/h8.c | 4 +- drivers/char/keyboard.c | 13 +- drivers/char/pcxx.c | 2 +- drivers/char/pcxx.h | 4 +- drivers/char/planb.c | 2 +- drivers/char/planb.h | 6 +- drivers/char/serial167.c | 2 +- drivers/isdn/avmb1/capidev.h | 2 +- drivers/isdn/pcbit/pcbit.h | 2 +- drivers/macintosh/adb.c | 4 +- drivers/macintosh/mac_keyb.c | 2 +- drivers/macintosh/macserial.c | 2 +- drivers/macintosh/macserial.h | 4 +- drivers/misc/parport_init.c | 5 +- drivers/misc/parport_pc.c | 113 +++-- drivers/net/cosa.c | 7 +- drivers/net/de620.c | 2 +- drivers/net/sunhme.c | 2 +- drivers/net/z85230.h | 4 +- drivers/sbus/char/pcikbd.c | 4 +- drivers/scsi/sd_ioctl.c | 35 +- drivers/scsi/sr_ioctl.c | 39 +- drivers/scsi/st.h | 2 +- drivers/sgi/char/sgiserial.c | 4 +- drivers/sgi/char/sgiserial.h | 4 +- drivers/sgi/char/shmiq.c | 2 +- drivers/sgi/char/usema.c | 2 +- drivers/sound/lowlevel/awe_compat.h | 2 +- drivers/sound/lowlevel/awe_wave.c | 2 +- drivers/sound/msnd.h | 5 +- drivers/usb/Config.in | 5 + drivers/usb/README.ohci | 28 ++ drivers/usb/ohci-debug.c | 19 +- drivers/usb/ohci.c | 712 +++++++++++++++++++--------- drivers/usb/ohci.h | 54 ++- fs/ChangeLog | 17 - fs/Config.in | 2 +- fs/affs/namei.c | 2 +- fs/devices.c | 2 +- fs/ext2/namei.c | 2 +- fs/ext2/truncate.c | 4 +- fs/hfs/bnode.c | 2 +- fs/hfs/catalog.c | 4 +- fs/hpfs/alloc.c | 12 +- fs/hpfs/dentry.c | 16 +- fs/hpfs/dir.c | 89 ++-- fs/hpfs/dnode.c | 38 +- fs/hpfs/file.c | 1 - fs/hpfs/hpfs_fn.h | 8 +- fs/hpfs/inode.c | 19 +- fs/hpfs/name.c | 14 +- fs/hpfs/namei.c | 157 +++--- fs/hpfs/super.c | 12 +- fs/minix/namei.c | 2 +- fs/namei.c | 6 +- fs/nfsd/vfs.c | 2 + fs/super.c | 3 +- fs/sysv/namei.c | 2 +- fs/ufs/namei.c | 2 +- include/asm-alpha/processor.h | 2 +- include/asm-alpha/semaphore.h | 2 +- include/asm-arm/semaphore.h | 2 +- include/asm-m68k/adb_mouse.h | 2 +- include/asm-m68k/atari_joystick.h | 2 +- include/asm-m68k/mac_mouse.h | 2 +- include/asm-m68k/semaphore.h | 2 +- include/asm-mips/semaphore.h | 2 +- include/asm-ppc/adb_mouse.h | 2 +- include/asm-ppc/semaphore.h | 2 +- include/asm-sparc/io.h | 2 +- include/asm-sparc64/hdreg.h | 2 +- include/asm-sparc64/ide.h | 4 +- include/asm-sparc64/io.h | 2 +- include/linux/blk.h | 6 - include/linux/blkpg.h | 64 +++ include/linux/fs.h | 10 +- include/linux/genhd.h | 16 +- include/linux/hpfs_fs_sb.h | 6 +- include/linux/istallion.h | 6 +- include/linux/lp_m68k.h | 2 +- include/linux/netdevice.h | 2 +- include/linux/parport.h | 1 + include/linux/parport_pc.h | 48 +- include/linux/rpcsock.h | 6 +- include/linux/serial167.h | 4 +- include/linux/stallion.h | 4 +- include/linux/swap.h | 1 + include/linux/umsdos_fs_i.h | 2 +- kernel/ksyms.c | 2 + mm/mlock.c | 7 +- mm/swapfile.c | 12 + net/core/filter.c | 2 +- net/ipv4/tcp_timer.c | 6 +- net/ipv6/exthdrs.c | 2 +- net/netlink/af_netlink.c | 2 +- 134 files changed, 1615 insertions(+), 1115 deletions(-) create mode 100644 drivers/block/blkpg.c create mode 100644 include/linux/blkpg.h diff --git a/CREDITS b/CREDITS index bebc046b8cf6..bd305c7fee8d 100644 --- a/CREDITS +++ b/CREDITS @@ -1534,6 +1534,15 @@ N: David Parsons E: orc@pell.chi.il.us D: improved memory detection code. +N: Mikulas Patocka +E: mikulas@artax.karlin.mff.cuni.cz +W: http://artax.karlin.mff.cuni.cz/~mikulas/ +P: 1024/BB11D2D5 A0 F1 28 4A C4 14 1E CF 92 58 7A 8F 69 BC A4 D3 +D: Read/write HPFS filesystem +S: Weissova 8 +S: 644 00 Brno +S: Czech Republic + N: Vojtech Pavlik E: vojtech@ucw.cz D: Joystick driver @@ -1839,7 +1848,7 @@ S: Australia N: Chris Smith E: csmith@convex.com -D: HPFS filesystem +D: Read only HPFS filesystem S: Richardson, Texas S: USA diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 63050b54c83e..5cdb3276ecc1 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -7322,14 +7322,24 @@ CONFIG_NFSD_SUN directories that are mount points on the local filesystem (this is how nfsd behaves on Sun systems), say yes here. If unsure, say N. -OS/2 HPFS filesystem support (read only) +OS/2 HPFS filesystem support (read/write) CONFIG_HPFS_FS OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS is the filesystem used for organizing files on OS/2 hard disk - partitions. Say Y if you want to be able to read files from an OS/2 - HPFS partition of your hard drive. OS/2 floppies however are in - regular MSDOS format, so you don't need this option in order to be - able to read them. Read Documentation/filesystems/hpfs.txt. + partitions. Say Y if you want to be able to read and write files + on an OS/2 HPFS partition of your hard drive. OS/2 floppies however + are in regular MSDOS format, so you don't need this option in order + to be able to read them. Read Documentation/filesystems/hpfs.txt. + + Write support is new and experimental. I don't think it's so + "experimental" that it corrupts disks. (but you know: "There's no + warranty") There are many checks and filesystem is remounted read-only + if any inconsistency found. I use it quite long time and it works. + + This driver may not be able to write to HPFS386 disks on Warp server. + HPFS386 on Warp client seems to work ok. If some unknown HPFS386 + structures are deteced, they are not destroyed and filesystem is + remounted read-only. This filesystem is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). diff --git a/Documentation/filesystems/hpfs.txt b/Documentation/filesystems/hpfs.txt index 18f25c76a9d4..2614da0184cb 100644 --- a/Documentation/filesystems/hpfs.txt +++ b/Documentation/filesystems/hpfs.txt @@ -1,4 +1,4 @@ -Read/Write HPFS 1.98b +Read/Write HPFS 1.99b 1998-1999, Mikulas Patocka email: mikulas@artax.karlin.mff.cuni.cz @@ -58,9 +58,9 @@ also won't be able to compile linux kernel (and maybe other things) on HPFS because kernel creates different files with names like bootsect.S and bootsect.s. When searching for file thats name has characters >= 128, codepages are used - see below. -OS/2 ignores dots and spaces at the end of file name, so this driver does. If -you create 'a. ...', the file 'a' will be created, but you can still access it -under names 'a.', 'a..', 'a . . . ' etc. +OS/2 ignores dots and spaces at the end of file name, so this driver does as +well. If you create 'a. ...', the file 'a' will be created, but you can still +access it under names 'a.', 'a..', 'a . . . ' etc. Extended attributes @@ -162,9 +162,6 @@ You can't rename over directories (what is it good for?). Renaming files so that only case changes doesn't work. This driver supports it but vfs doesn't. Something like 'mv file FILE' won't work. -When you try to create file with bad filename (too long or containing forbidden -characters), you get ENOENT error instead of EINVAL or ENAMETOOLONG. - All atimes and directory mtimes are not updated. That's because of performance reasons. If you extremely wish to update them, let me know, I'll write it (but it will be slow). @@ -266,6 +263,10 @@ History Fixed a bug when chmoding or chowning root directory 1.98 Fixed a deadlock when using old_readdir Better directory handling; workaround for "unbalanced tree" bug in OS/2 +1.99 Corrected a possible problem when there's not enough space while deleting + file + Now it tries to truncate the file if there's not enough space when deleting + Removed a lot of redundat code vim: set textwidth=80: diff --git a/Documentation/mtrr.txt b/Documentation/mtrr.txt index af58d63d7854..2e03e016c2c4 100644 --- a/Documentation/mtrr.txt +++ b/Documentation/mtrr.txt @@ -1,5 +1,5 @@ MTRR (Memory Type Range Register) control -2 May 1998 +16 May 1999 Richard Gooch @@ -31,8 +31,10 @@ Reading MTRRs from the shell: reg00: base=0x00000000 ( 0MB), size= 128MB: write-back, count=1 reg01: base=0x08000000 ( 128MB), size= 64MB: write-back, count=1 =============================================================================== -Creating MTRRs from the shell: +Creating MTRRs from the C-shell: # echo "base=0xf8000000 size=0x400000 type=write-combining" >! /proc/mtrr +or if you use bash: +# echo "base=0xf8000000 size=0x400000 type=write-combining" >| /proc/mtrr And the result thereof: % cat /proc/mtrr @@ -79,8 +81,10 @@ registers. NOTE: You can only create type=uncachable region, if the first region that you created is type=write-combining. =============================================================================== -Removing MTRRs from the shell: +Removing MTRRs from the C-shell: % echo "disable=2" >! /proc/mtrr +or using bash: +% echo "disable=2" >| /proc/mtrr =============================================================================== Reading MTRRs from a C programme using ioctl()'s: diff --git a/MAINTAINERS b/MAINTAINERS index 35dd36adf244..1d3e7c496e23 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -361,6 +361,12 @@ M: langa2@kph.uni-mainz.de W: http://www.uni-mainz.de/~langm000/linux.html S: Maintained +HPFS FILESYSTEM +P: Mikulas Patocka +M: mikulas@artax.karlin.mff.cuni.cz +W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi +S: Maintained + IDE DRIVER [GENERAL] P: Andre Hedrick M: hedrick@astro.dyer.vanderbilt.edu diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 322b53210e2b..88a4f47e6cfc 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -25,22 +25,27 @@ CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR) ifdef CONFIG_M386 CFLAGS := $(CFLAGS) -m386 -DCPU=386 +AFLAGS := $(AFLAGS) -DCPU=386 endif ifdef CONFIG_M486 CFLAGS := $(CFLAGS) -m486 -DCPU=486 +AFLAGS := $(AFLAGS) -DCPU=486 endif ifdef CONFIG_M586 -CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 +CFLAGS := $(CFLAGS) -DCPU=586 +AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_M586TSC -CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=586 +CFLAGS := $(CFLAGS) -DCPU=586 +AFLAGS := $(AFLAGS) -DCPU=586 endif ifdef CONFIG_M686 -CFLAGS := $(CFLAGS) -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 +CFLAGS := $(CFLAGS) -DCPU=686 +AFLAGS := $(AFLAGS) -DCPU=686 endif HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S index 46527a85de12..904f70f901d5 100644 --- a/arch/i386/lib/checksum.S +++ b/arch/i386/lib/checksum.S @@ -117,9 +117,11 @@ csum_partial: #else /* CPU==686 */ csum_partial: - movl 12(%esp),%eax # Function arg: unsigned int sum - movl 8(%esp),%ecx # Function arg: int len - movl 4(%esp),%esi # Function arg: const unsigned char *buf + pushl %esi + pushl %ebx + movl 20(%esp),%eax # Function arg: unsigned int sum + movl 16(%esp),%ecx # Function arg: int len + movl 12(%esp),%esi # Function arg: const unsigned char *buf testl $2, %esi jnz 30f @@ -204,6 +206,8 @@ csum_partial: addl %ebx,%eax adcl $0,%eax 80: + popl %ebx + popl %esi ret #endif /* CPU==686 */ @@ -369,7 +373,7 @@ DST( movb %cl, (%edi) ) #define ROUND1(x) \ SRC(movl x(%esi), %ebx ) ; \ - addl %ebx, %eax\n ; \ + addl %ebx, %eax ; \ DST(movl %ebx, x(%edi) ) ; #define ROUND(x) \ diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index 5e2090f8f1c6..205837ef6c2b 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -43,7 +43,7 @@ static int stdma_locked = 0; /* the semaphore */ /* int func to be called */ static void (*stdma_isr)(int, void *, struct pt_regs *) = NULL; static void *stdma_isr_data = NULL; /* data passed to isr */ -static struct wait_queue *stdma_wait = NULL; /* wait queue for ST-DMA */ +static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ diff --git a/arch/m68k/mac/adb-bus.c b/arch/m68k/mac/adb-bus.c index b466ce5333f8..5f0f792aa94d 100644 --- a/arch/m68k/mac/adb-bus.c +++ b/arch/m68k/mac/adb-bus.c @@ -2328,12 +2328,12 @@ struct adbdev_state { struct adb_request req; }; -static struct wait_queue *adb_wait; +static DECLARE_WAIT_QUEUE_HEAD(adb_wait); static int adb_wait_reply(struct adbdev_state *state, struct file *file) { int ret = 0; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait,current); add_wait_queue(&adb_wait, &wait); current->state = TASK_INTERRUPTIBLE; @@ -2552,12 +2552,12 @@ struct adbdev_state { struct adb_request req; }; -static struct wait_queue *adb_wait; +static DECLARE_WAIT_QUEUE_HEAD(adb_wait); static int adb_wait_reply(struct adbdev_state *state, struct file *file) { int ret = 0; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); #if (ADBDEBUG & ADBDEBUG_DEVICE) printk("ADB request: wait_reply (blocking ... \n"); diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 86a9a5c72e74..7227e5b49fb2 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -666,7 +666,7 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info, int options, struct rusage *ru) { int flag, retval; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait,current); struct task_struct *p; lock_kernel(); diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 94901245fcfe..1816df9bae4d 100644 --- a/arch/ppc/8xx_io/uart.c +++ b/arch/ppc/8xx_io/uart.c @@ -155,8 +155,8 @@ typedef struct serial_info { long pgrp; /* pgrp of opening process */ struct tq_struct tqueue; struct tq_struct tqueue_hangup; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; /* CPM Buffer Descriptor pointers. */ @@ -1733,7 +1733,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ser_info_t *info) { #ifdef DO_THIS_LATER - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); #endif struct serial_state *state = info->state; int retval; diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 102ba924f49c..b6a4608e12aa 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -229,6 +229,7 @@ CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +CONFIG_EFS_FS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 8a132b01d579..020cb551e287 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -267,6 +267,7 @@ CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=m +CONFIG_EFS_FS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index a7f85ca5856a..0aec81915897 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $ +/* $Id: sys_sparc32.c,v 1.108 1999/05/16 10:50:32 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2363,6 +2363,94 @@ static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm) __scm_destroy(scm); } +/* In these cases we (currently) can just copy to data over verbatim + * because all CMSGs created by the kernel have well defined types which + * have the same layout in both the 32-bit and 64-bit API. One must add + * some special cased conversions here if we start sending control messages + * with incompatible types. + * + * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after + * we do our work. The remaining cases are: + * + * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean + * IP_TTL int 32-bit clean + * IP_TOS __u8 32-bit clean + * IP_RECVOPTS variable length 32-bit clean + * IP_RETOPTS variable length 32-bit clean + * (these last two are clean because the types are defined + * by the IPv4 protocol) + * IP_RECVERR struct sock_extended_err + + * struct sockaddr_in 32-bit clean + * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + + * struct sockaddr_in6 32-bit clean + * IPV6_PKTINFO struct in6_pktinfo 32-bit clean + * IPV6_HOPLIMIT int 32-bit clean + * IPV6_FLOWINFO u32 32-bit clean + * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean + * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean + * IPV6_RTHDR ipv6 routing exthdr 32-bit clean + * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean + */ +static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) +{ + unsigned char *workbuf, *wp; + unsigned long bufsz, space_avail; + struct cmsghdr *ucmsg; + + bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf = kmalloc(bufsz, GFP_KERNEL); + if(workbuf == NULL) + goto fail; + + /* To make this more sane we assume the kernel sends back properly + * formatted control messages. Because of how the kernel will truncate + * the cmsg_len for MSG_TRUNC cases, we need not check that case either. + */ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; + while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; + int clen64, clen32; + + /* UCMSG is the 64-bit format CMSG entry in user-space. + * KCMSG32 is within the kernel space temporary buffer + * we use to convert into a 32-bit style CMSG. + */ + __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); + __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); + __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); + + clen64 = kcmsg32->cmsg_len; + copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), + clen64 - CMSG_ALIGN(sizeof(*ucmsg))); + clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + + CMSG32_ALIGN(sizeof(struct cmsghdr32))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + } + + /* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); + copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); + + kmsg->msg_control = (struct cmsghdr *) + (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; + + kfree(workbuf); + return; + +fail: + /* If we leave the 64-bit format CMSG chunks in there, + * the application could get confused and crash. So to + * ensure greater recovery, we report no CMSGs. + */ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} + asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) { struct socket *sock; @@ -2455,6 +2543,14 @@ asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int use if(scm.fp) __scm_destroy(&scm); } else { + /* If recvmsg processing itself placed some + * control messages into user space, it's is + * using 64-bit CMSG processing, so we need + * to fix it up before we tack on more stuff. + */ + if((unsigned long) kern_msg.msg_control != cmsg_ptr) + cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr); + /* Wheee... */ if(sock->passcred) put_cmsg32(&kern_msg, @@ -2471,9 +2567,9 @@ asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int use if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(cmsg_ptr != 0 && err >= 0) { - u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control); - err = __put_user(ucmsg_ptr, &user_msg->msg_control); - err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen); + unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); + __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr); + err |= __put_user(uclen, &user_msg->msg_controllen); } if(err >= 0) err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index c926f3a942e8..bf06fc05d631 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.12 1999/01/02 16:46:06 davem Exp $ +/* $Id: fs.c,v 1.13 1999/05/14 07:24:37 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c index 9c95a9234096..0c2116e73323 100644 --- a/arch/sparc64/solaris/ipc.c +++ b/arch/sparc64/solaris/ipc.c @@ -1,4 +1,4 @@ -/* $Id: ipc.c,v 1.3 1998/07/30 11:29:47 davem Exp $ +/* $Id: ipc.c,v 1.4 1999/05/13 07:11:37 jj Exp $ * ipc.c: Solaris IPC emulation * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 8cf2614b9c46..02a2307d60ce 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -267,7 +267,7 @@ static int MotorOn = 0, MotorOffTrys; /* Synchronization of FDC1772 access. */ static volatile int fdc_busy = 0; -static struct wait_queue *fdc_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static unsigned int changed_floppies = 0xff, fake_change = 0; diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index bec74c62ba22..219f10034027 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -195,7 +195,7 @@ static struct hd_struct mfm[MFM_MAXDRIVES << 6]; static int mfm_sizes[MFM_MAXDRIVES << 6]; static int mfm_blocksizes[MFM_MAXDRIVES << 6]; static int mfm_sectsizes[MFM_MAXDRIVES << 6]; -static struct wait_queue *mfm_wait_open = NULL; +static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open); /* Stuff from the assembly routines */ extern unsigned int hdc63463_baseaddress; /* Controller base address */ diff --git a/drivers/ap1000/ap.c b/drivers/ap1000/ap.c index ce50c5edb319..64340bedaeda 100644 --- a/drivers/ap1000/ap.c +++ b/drivers/ap1000/ap.c @@ -36,7 +36,7 @@ #define NUM_APDEVS 8 #define MAX_REQUESTS 1 -static struct wait_queue * busy_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int ap_blocksizes[NUM_APDEVS]; static int ap_length[NUM_APDEVS]; diff --git a/drivers/ap1000/ddv.c b/drivers/ap1000/ddv.c index 4a21a588212e..f868076d3923 100644 --- a/drivers/ap1000/ddv.c +++ b/drivers/ap1000/ddv.c @@ -84,7 +84,7 @@ static void ddv_request1(void); static char *ddv_opcodep = NULL; static struct request *next_request = NULL; -static struct wait_queue * busy_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */ int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */ @@ -93,7 +93,7 @@ int ddv_blk_length[NUM_DDVDEVS]; /* in blocks */ /* these are used by the ddv_daemon, which services remote disk requests */ static struct remote_request *rem_queue = NULL; static struct remote_request *rem_queue_end; -static struct wait_queue *ddv_daemon_wait = NULL; +static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait); static int opiu_kernel_loaded = 0; diff --git a/drivers/block/Makefile b/drivers/block/Makefile index fd9b99c35493..f57b68ee83dd 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -20,7 +20,7 @@ ALL_SUB_DIRS := $(SUB_DIRS) paride L_TARGET := block.a -L_OBJS := genhd.o +L_OBJS := genhd.o blkpg.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES LX_OBJS := ll_rw_blk.o diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index d9598fb73031..ea0e989f82eb 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -64,6 +64,7 @@ typedef void Scsi_Device; /* hack to avoid including scsi.h */ #include #include /* for HDIO_GETGEO */ +#include #include #include @@ -1125,8 +1126,8 @@ static int acsi_ioctl( struct inode *inode, struct file *file, return -EINVAL; switch (cmd) { case HDIO_GETGEO: - /* HDIO_GETGEO is supported more for getting the partition's start - * sector... */ + /* HDIO_GETGEO is supported more for getting the partition's + * start sector... */ { struct hd_geometry *geo = (struct hd_geometry *)arg; /* just fake some geometry here, it's nonsense anyway; to make it * easy, use Adaptec's usual 64/32 mapping */ @@ -1147,19 +1148,18 @@ static int acsi_ioctl( struct inode *inode, struct file *file, case BLKGETSIZE: /* Return device size */ return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects, (long *) arg); - + + case BLKROSET: + case BLKROGET: case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!inode->i_rdev) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_acsidisk(inode->i_rdev, 1); - RO_IOCTLS(inode->i_rdev,arg); + default: return -EINVAL; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index f06aaccc2e2b..f105efd6873f 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -93,6 +93,7 @@ #define MAJOR_NR FLOPPY_MAJOR #include +#include #define FD_MAX_UNITS 2 @@ -1584,7 +1585,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, device = inode->i_rdev; switch (cmd) { - RO_IOCTLS (device, param); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + return blk_ioctl(device, cmd, param); } drive = MINOR (device); type = drive >> 2; @@ -1621,22 +1627,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, if (copy_to_user((void *)param, &getprm, sizeof(getprm))) return -EFAULT; return 0; - case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (param > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = param; - return 0; - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], - (int *) param); - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; } if (!IOCTL_ALLOWED) return -EPERM; diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c new file mode 100644 index 000000000000..34cfe67dda8a --- /dev/null +++ b/drivers/block/blkpg.c @@ -0,0 +1,288 @@ +/* + * Partition table and disk geometry handling + * + * This obsoletes the partition-handling code in genhd.c: + * Userspace can look at a disk in arbitrary format and tell + * the kernel what partitions there are on the disk, and how + * these should be numbered. + * It also allows one to repartition a disk that is being used. + * + * A single ioctl with lots of subfunctions: + * + * Device number stuff: + * get_whole_disk() (given the device number of a partition, find + * the device number of the encompassing disk) + * get_all_partitions() (given the device number of a disk, return the + * device numbers of all its known partitions) + * + * Partition stuff: + * add_partition() + * delete_partition() + * test_partition_in_use() (also for test_disk_in_use) + * + * Geometry stuff: + * get_geometry() + * set_geometry() + * get_bios_drivedata() + * + * For today, only the partition stuff - aeb, 990515 + */ + +#include +#include /* for BLKRASET, ... */ +#include /* for capable() */ +#include /* for set_device_ro() */ +#include +#include +#include /* for is_swap_partition() */ + +#include + +/* + * What is the data describing a partition? + * + * 1. a device number (kdev_t) + * 2. a starting sector and number of sectors (hd_struct) + * given in the part[] array of the gendisk structure for the drive. + * + * The number of sectors is replicated in the sizes[] array of + * the gendisk structure for the major, which again is copied to + * the blk_size[][] array. + * (However, hd_struct has the number of 512-byte sectors, + * g->sizes[] and blk_size[][] have the number of 1024-byte blocks.) + * Note that several drives may have the same major. + */ + +/* a linear search, superfluous when dev is a pointer */ +static struct gendisk *get_gendisk(kdev_t dev) { + struct gendisk *g; + int m = MAJOR(dev); + + for (g = gendisk_head; g; g = g->next) + if (g->major == m) + break; + return g; +} + +/* moved here from md.c - will be discarded later */ +char *partition_name (kdev_t dev) { + static char name[40]; /* kdevname returns 32 bytes */ + /* disk_name requires 32 bytes */ + struct gendisk *hd = get_gendisk (dev); + + if (!hd) { + sprintf (name, "[dev %s]", kdevname(dev)); + return (name); + } + + return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */ +} + +/* + * Add a partition. + * + * returns: EINVAL: bad parameters + * ENXIO: cannot find drive + * EBUSY: proposed partition overlaps an existing one + * or has the same number as an existing one + * 0: all OK. + */ +int add_partition(kdev_t dev, struct blkpg_partition *p) { + struct gendisk *g; + long long ppstart, pplength; + long pstart, plength; + int i, drive, first_minor, end_minor, minor; + + /* convert bytes to sectors, check for fit in a hd_struct */ + ppstart = (p->start >> 9); + pplength = (p->length >> 9); + pstart = ppstart; + plength = pplength; + if (pstart != ppstart || plength != pplength + || pstart < 0 || plength < 0) + return -EINVAL; + + /* find the drive major */ + g = get_gendisk(dev); + if (!g) + return -ENXIO; + + /* existing drive? */ + drive = (MINOR(dev) >> g->minor_shift); + first_minor = (drive << g->minor_shift); + end_minor = first_minor + g->max_p; + if (drive >= g->nr_real) + return -ENXIO; + + /* drive and partition number OK? */ + if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p) + return -EINVAL; + + /* partition number in use? */ + minor = first_minor + p->pno; + if (g->part[minor].nr_sects != 0) + return -EBUSY; + + /* overlap? */ + for (i=first_minor+1; ipart[i].start_sect || + pstart >= g->part[i].start_sect + g->part[i].nr_sects)) + return -EBUSY; + + /* all seems OK */ + g->part[minor].start_sect = pstart; + g->part[minor].nr_sects = plength; + if (g->sizes) + g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9)); + return 0; +} + +/* + * Delete a partition given by partition number + * + * returns: EINVAL: bad parameters + * ENXIO: cannot find partition + * EBUSY: partition is busy + * 0: all OK. + * + * Note that the dev argument refers to the entire disk, not the partition. + */ +int del_partition(kdev_t dev, struct blkpg_partition *p) { + struct gendisk *g; + kdev_t devp; + int drive, first_minor, minor; + + /* find the drive major */ + g = get_gendisk(dev); + if (!g) + return -ENXIO; + + /* drive and partition number OK? */ + drive = (MINOR(dev) >> g->minor_shift); + first_minor = (drive << g->minor_shift); + if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p) + return -EINVAL; + + /* existing drive and partition? */ + minor = first_minor + p->pno; + if (drive >= g->nr_real || g->part[minor].nr_sects == 0) + return -ENXIO; + + /* partition in use? Incomplete check for now. */ + devp = MKDEV(MAJOR(dev), minor); + if (get_super(devp) || /* mounted? */ + is_swap_partition(devp)) + return -EBUSY; + + /* all seems OK */ + fsync_dev(devp); + invalidate_buffers(devp); + + g->part[minor].start_sect = 0; + g->part[minor].nr_sects = 0; + if (g->sizes) + g->sizes[minor] = 0; + + return 0; +} + +int blkpg_ioctl(kdev_t dev, struct blkpg_ioctl_arg *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + int len; + + if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) + return -EFAULT; + + switch (a.op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + len = a.datalen; + if (len < sizeof(struct blkpg_partition)) + return -EINVAL; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (a.op == BLKPG_ADD_PARTITION) + return add_partition(dev, &p); + else + return del_partition(dev, &p); + default: + return -EINVAL; + } +} + +/* + * Common ioctl's for block devices + */ + +int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg) +{ + int intval; + + switch (cmd) { + case BLKROSET: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (get_user(intval, (int *)(arg))) + return -EFAULT; + set_device_ro(dev, intval); + return 0; + case BLKROGET: + intval = (is_read_only(dev) != 0); + return put_user(intval, (int *)(arg)); + + case BLKRASET: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + if(!dev || arg > 0xff) + return -EINVAL; + read_ahead[MAJOR(dev)] = arg; + return 0; + case BLKRAGET: + if (!arg) + return -EINVAL; + return put_user(read_ahead[MAJOR(dev)], (long *) arg); + + case BLKFLSBUF: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!dev) + return -EINVAL; + fsync_dev(dev); + invalidate_buffers(dev); + return 0; + + case BLKSSZGET: + /* get block device sector size as needed e.g. by fdisk */ + intval = get_hardsect_size(dev); + return put_user(intval, (int *) arg); + +#if 0 + case BLKGETSIZE: + /* Today get_gendisk() requires a linear scan; + add this when dev has pointer type. */ + g = get_gendisk(dev); + if (!g) + longval = 0; + else + longval = g->part[MINOR(dev)].nr_sects; + return put_user(longval, (long *) arg); +#endif +#if 0 + case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return reread_partitions(dev, 1); +#endif + + case BLKPG: + return blkpg_ioctl(dev, (struct blkpg_ioctl_arg *) arg); + + default: + return -EINVAL; + } +} + diff --git a/drivers/block/cmd646.c b/drivers/block/cmd646.c index de0844a874cc..0142ceb99d8c 100644 --- a/drivers/block/cmd646.c +++ b/drivers/block/cmd646.c @@ -1,4 +1,4 @@ -/* $Id: cmd646.c,v 1.11 1998/12/13 08:36:54 davem Exp $ +/* $Id: cmd646.c,v 1.12 1999/05/14 07:21:01 davem Exp $ * cmd646.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because * there the "BIOS" has done all of the following already. diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 574f430e7564..d91a0a86bcb7 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -198,6 +198,7 @@ static inline int __get_order(unsigned long size); #define MAJOR_NR FLOPPY_MAJOR #include +#include #include /* for the compatibility eject ioctl */ #ifndef fd_get_dma_residue @@ -3293,7 +3294,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, LOCK_FDC(drive,1); if (cmd != FDDEFPRM) /* notice a disk change immediately, else - * we loose our settings immediately*/ + * we lose our settings immediately*/ CALL(poll_drive(1, FD_RAW_NEED_DISK)); user_params[drive] = *g; if (buffer_drive == drive) @@ -3402,7 +3403,12 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, device = inode->i_rdev; switch (cmd) { - RO_IOCTLS(device,param); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + return blk_ioctl(device, cmd, param); } type = TYPE(device); drive = DRIVE(device); @@ -3432,19 +3438,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, loc.start = 0; return _COPYOUT(loc); } - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(param > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = param; - return 0; - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], - (long *) param); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKGETSIZE: ECALL(get_floppy_geometry(drive, type, &g)); diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 761a3eb0c885..c801ab8144f5 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -66,10 +66,10 @@ extern void note_bootable_part(kdev_t dev, int part); #endif /* - * disk_name() is used by genhd.c and md.c. - * It formats the devicename of the indicated disk - * into the supplied buffer, and returns a pointer - * to that same buffer (for convenience). + * disk_name() is used by genhd.c and blkpg.c. + * It formats the devicename of the indicated disk into + * the supplied buffer (of size at least 32), and returns + * a pointer to that same buffer (for convenience). */ char *disk_name (struct gendisk *hd, int minor, char *buf) { @@ -121,7 +121,7 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) static void add_partition (struct gendisk *hd, int minor, int start, int size) { - char buf[8]; + char buf[32]; hd->part[minor].start_sect = start; hd->part[minor].nr_sects = size; printk(" %s", disk_name(hd, minor, buf)); @@ -134,12 +134,12 @@ static inline int is_extended_partition(struct partition *p) SYS_IND(p) == LINUX_EXTENDED_PARTITION); } -static int sector_partition_scale(kdev_t dev) +int get_hardsect_size(kdev_t dev) { - if (hardsect_size[MAJOR(dev)] != NULL) - return (hardsect_size[MAJOR(dev)][MINOR(dev)]/512); - else - return (1); + if (hardsect_size[MAJOR(dev)] != NULL) + return hardsect_size[MAJOR(dev)][MINOR(dev)]; + else + return 512; } static unsigned int get_ptable_blocksize(kdev_t dev) @@ -209,7 +209,7 @@ static void extended_partition(struct gendisk *hd, kdev_t dev) struct partition *p; unsigned long first_sector, first_size, this_sector, this_size; int mask = (1 << hd->minor_shift) - 1; - int sector_size = sector_partition_scale(dev); + int sector_size = get_hardsect_size(dev) / 512; int i; first_sector = hd->part[MINOR(dev)].start_sect; @@ -453,7 +453,7 @@ static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s struct partition *p; unsigned char *data; int mask = (1 << hd->minor_shift) - 1; - int sector_size = sector_partition_scale(dev); + int sector_size = get_hardsect_size(dev) / 512; #ifdef CONFIG_BSD_DISKLABEL /* no bsd disklabel as a default */ kdev_t bsd_kdev = 0; @@ -883,10 +883,7 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) int blocksize; old_blocksize = get_ptable_blocksize(dev); - if (hardsect_size[MAJOR(dev)] != NULL) - blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; - else - blocksize = 512; + blocksize = get_hardsect_size(dev); set_blocksize(dev,blocksize); res = 0; @@ -1223,7 +1220,7 @@ static void check_partition(struct gendisk *hd, kdev_t dev) { static int first_time = 1; unsigned long first_sector; - char buf[8]; + char buf[32]; if (first_time) printk("Partition check:\n"); @@ -1307,28 +1304,21 @@ static inline void setup_dev(struct gendisk *dev) int end_minor = dev->max_nr * dev->max_p; blk_size[dev->major] = NULL; - for (i = 0 ; i < end_minor; i++) { + for (i = 0; i < end_minor; i++) { dev->part[i].start_sect = 0; dev->part[i].nr_sects = 0; + dev->sizes[i] = 0; } dev->init(dev); - for (drive = 0 ; drive < dev->nr_real ; drive++) { - int first_minor = drive << dev->minor_shift; - current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); - } - if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = 0; i < end_minor; i++) - dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); - blk_size[dev->major] = dev->sizes; - } + for (drive = 0; drive < dev->nr_real; drive++) + resetup_one_dev(dev, drive); } __initfunc(void device_setup(void)) { extern void console_map_init(void); #ifdef CONFIG_PARPORT - extern int parport_init(void); + extern int parport_init(void) __init; #endif #ifdef CONFIG_MD_BOOT extern void md_setup_drive(void) __init; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index e097ca2c7239..f01d7475d5bd 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -604,31 +604,25 @@ static int hd_ioctl(struct inode * inode, struct file * file, g.start = hd[MINOR(inode->i_rdev)].start_sect; return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - return put_user(read_ahead[MAJOR(inode->i_rdev)], - (long *) arg); + case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; return put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_hddisk(inode->i_rdev, 1); - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + default: return -EINVAL; } @@ -836,7 +830,7 @@ static int revalidate_hddisk(kdev_t dev, int maxusage) if (DEVICE_BUSY || USAGE > maxusage) { restore_flags(flags); return -EBUSY; - }; + } DEVICE_BUSY = 1; restore_flags(flags); @@ -854,7 +848,7 @@ static int revalidate_hddisk(kdev_t dev, int maxusage) invalidate_buffers(devi); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; - }; + } #ifdef MAYBE_REINIT MAYBE_REINIT; diff --git a/drivers/block/ide.c b/drivers/block/ide.c index 6b59faed30b1..39564e15e230 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -122,6 +122,7 @@ #include #include #include +#include #include #include #include @@ -2232,17 +2233,6 @@ static int ide_ioctl (struct inode *inode, struct file *file, (unsigned long *) &loc->start)) return -EFAULT; return 0; } - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[HWIF(drive)->major] - [minor&PARTN_MASK], - (int *)arg); - - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); @@ -2383,7 +2373,12 @@ static int ide_ioctl (struct inode *inode, struct file *file, drive->nice1 = (arg >> IDE_NICE_1) & 1; return 0; - RO_IOCTLS(inode->i_rdev, arg); + case BLKROSET: + case BLKROGET: + case BLKFLSBUF: + case BLKSSZGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); default: if (drive->driver != NULL) @@ -2917,121 +2912,10 @@ done: * Returns 1 if the geometry translation was successful. */ -#define ANDRIES_GEOMETRY 0 - int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) { ide_drive_t *drive; -#if ANDRIES_GEOMETRY - /* - * This is the documented list of values (some version of) - * OnTrack DM uses. - */ - - static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; - - /* - * This is a pure phantasy list - known to be incorrect. - * - * In fact it seems that EZD does not do anything to the CHS - * values in the partition table, so whether EZD is present - * or not should probably not influence the geometry. - */ - - static const byte ez_head_vals[] = {4, 8, 16, 32, 64, 128, 240, 255, 0}; const byte *heads; - unsigned long tracks; - - drive = get_info_ptr(i_rdev); - if (!drive) - return 0; - - if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 0; /* we already have a translation */ - } - - if (xparm == -1) { - int ret = 0; -#if FAKE_FDISK_FOR_EZDRIVE - if (drive->remap_0_to_1 == 0) { - drive->remap_0_to_1 = 1; - printk("%s [remap 0->1]", msg); - msg = NULL; - ret = 1; - } - if (drive->bios_head > 16) -#endif /* FAKE_FDISK_FOR_EZDRIVE */ - { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return ret; /* we already have a translation */ - } - } - - if (msg) - printk("%s ", msg); - - if (drive->forced_geom) { - /* - * Update the current 3D drive values. - */ - drive->id->cur_cyls = drive->bios_cyl; - drive->id->cur_heads = drive->bios_head; - drive->id->cur_sectors = drive->bios_sect; - return 0; - } - -#if 1 - /* There used to be code here that assigned drive->id->CHS - to drive->CHS and that to drive->bios_CHS. However, - some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB. - In such cases that code was wrong. Moreover, - there seems to be no reason to do any of these things. */ -#else - if (drive->id) { - drive->cyl = drive->id->cyls; - drive->head = drive->id->heads; - drive->sect = drive->id->sectors; - } - drive->bios_cyl = drive->cyl; - drive->bios_head = drive->head; - drive->bios_sect = drive->sect; - drive->special.b.set_geometry = 1; - -#endif - - tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63; - drive->bios_sect = 63; - if (xparm > 1) { - drive->bios_head = xparm; - drive->bios_cyl = tracks / drive->bios_head; - } else { - heads = (xparm == -1) ? ez_head_vals : dm_head_vals; - while (drive->bios_cyl >= 1024) { - drive->bios_head = *heads; - drive->bios_cyl = tracks / drive->bios_head; - if (0 == *++heads) - break; - } - if (xparm == 1) { - drive->sect0 = 63; - drive->bios_cyl = (tracks - 1) / drive->bios_head; - printk("[remap +63] "); - } - } - -#else /* ANDRIES_GEOMETRY */ - static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; const byte *heads = head_vals; unsigned long tracks; @@ -3106,7 +2990,6 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg) printk("[remap +63] "); } } -#endif /* ANDRIES_GEOMETRY */ drive->part[0].nr_sects = current_capacity(drive); printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect); diff --git a/drivers/block/md.c b/drivers/block/md.c index 427d7fa94c60..bd610dc7b2a3 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -59,6 +59,7 @@ #define MD_DRIVER #include +#include #include #include #include @@ -98,36 +99,6 @@ struct md_dev md_dev[MAX_MD_DEV]; int md_thread(void * arg); -static struct gendisk *find_gendisk (kdev_t dev) -{ - struct gendisk *tmp=gendisk_head; - - while (tmp != NULL) - { - if (tmp->major==MAJOR(dev)) - return (tmp); - - tmp=tmp->next; - } - - return (NULL); -} - -char *partition_name (kdev_t dev) -{ - static char name[40]; /* This should be long - enough for a device name ! */ - struct gendisk *hd = find_gendisk (dev); - - if (!hd) - { - sprintf (name, "[dev %s]", kdevname(dev)); - return (name); - } - - return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */ -} - static int legacy_raid_sb (int minor, int pnum) { int i, factor; @@ -653,24 +624,7 @@ static int md_ioctl (struct inode *inode, struct file *file, return err; break; - case BLKFLSBUF: - fsync_dev (inode->i_rdev); - invalidate_buffers (inode->i_rdev); - break; - - case BLKRASET: - if (arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - err = put_user (read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - if (err) - return err; - break; - /* We have a problem here : there is no easy way to give a CHS virtual geometry. We currently pretend that we have a 2 heads 4 sectors (with a BIG number of cylinders...). This drives dosfs @@ -693,7 +647,12 @@ static int md_ioctl (struct inode *inode, struct file *file, return err; break; - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRAGET: + case BLKRASET: + case BLKFLSBUF: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; @@ -901,7 +860,6 @@ EXPORT_SYMBOL(md_size); EXPORT_SYMBOL(md_maxreadahead); EXPORT_SYMBOL(register_md_personality); EXPORT_SYMBOL(unregister_md_personality); -EXPORT_SYMBOL(partition_name); EXPORT_SYMBOL(md_dev); EXPORT_SYMBOL(md_error); EXPORT_SYMBOL(md_register_thread); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 3518a59d644a..128f9b21d165 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -208,6 +208,7 @@ MODULE_PARM(drive3,"1-8i"); #define DEVICE_OFF(device) #include +#include #include "pseudo.h" @@ -331,7 +332,7 @@ static int pd_dev; /* minor of current request */ static int pd_poffs; /* partition offset of current minor */ static char * pd_buf; /* buffer for request in progress */ -static struct wait_queue *pd_wait_open = NULL; +static DECLARE_WAIT_QUEUE_HEAD(pd_wait_open); static char *pd_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR", "READY","BUSY","AMNF","TK0NF","ABRT","MCR", @@ -483,35 +484,23 @@ static int pd_ioctl(struct inode *inode,struct file *file, } put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); - if (err) return (err); - put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg); - return (0); case BLKGETSIZE: if (!arg) return -EINVAL; err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); if (err) return (err); put_user(pd_hd[dev].nr_sects,(long *) arg); return (0); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return pd_revalidate(inode->i_rdev); - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; } diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 255352f0ab5f..f1cdfe3c6d2e 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -205,6 +205,7 @@ MODULE_PARM(drive3,"1-7i"); #define DEVICE_OFF(device) #include +#include #include "pseudo.h" @@ -433,31 +434,18 @@ static int pf_ioctl(struct inode *inode,struct file *file, } put_user(0,(long *)&geo->start); return 0; - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); - if (err) return (err); - put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg); - return (0); case BLKGETSIZE: if (!arg) return -EINVAL; err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)); if (err) return (err); put_user(PF.capacity,(long *) arg); return (0); - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; - RO_IOCTLS(inode->i_rdev,arg); + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; } diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 015c9468bb82..e1ff03e8ffb7 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -1140,15 +1141,7 @@ static int ps2esdi_ioctl(struct inode *inode, return (0); } break; - case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!inode->i_rdev) - return -EINVAL; - if (arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; + case BLKGETSIZE: if (arg) { if ((err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)))) @@ -1158,20 +1151,19 @@ static int ps2esdi_ioctl(struct inode *inode, return (0); } break; - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!inode->i_rdev) - return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); - RO_IOCTLS(inode->i_rdev, arg); + + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); } return (-EINVAL); } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 6df2a1c10757..2bb52a845b2f 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -72,6 +72,7 @@ extern void wait_for_keypress(void); */ #define MAJOR_NR RAMDISK_MAJOR #include +#include /* * We use a block size of 512 bytes in comparision to BLOCK_SIZE @@ -198,11 +199,10 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un if (!arg) return -EINVAL; return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg); - case BLKSSZGET: /* Block size of media */ - if (!arg) return -EINVAL; - return put_user(rd_blocksizes[minor], (int *)arg); - - RO_IOCTLS(inode->i_rdev, arg); + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + return blk_ioctl(inode->i_rdev, cmd, arg); default: return -EINVAL; @@ -519,7 +519,7 @@ __initfunc(static void rd_load_image(kdev_t device, int offset, int unit)) } if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) { - printk("RAMDISK: image too big! (%d/%d blocks)\n", + printk("RAMDISK: image too big! (%d/%ld blocks)\n", nblocks, rd_length[unit] >> RDBLK_SIZE_BITS); goto done; } diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 9c1c2d7b103c..04c88fb08a1e 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -49,6 +49,7 @@ #define MAJOR_NR XT_DISK_MAJOR #include +#include #include "xd.h" @@ -337,21 +338,9 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) g.start = xd_struct[MINOR(inode->i_rdev)].start_sect; return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } - case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], (long*) arg); case BLKGETSIZE: if (!arg) return -EINVAL; return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg); - case BLKFLSBUF: /* Return devices size */ - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; @@ -369,7 +358,15 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) if (!capable(CAP_SYS_ADMIN)) return -EACCES; return xd_reread_partitions(inode->i_rdev); - RO_IOCTLS(inode->i_rdev,arg); + + case BLKFLSBUF: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + default: return -EINVAL; } diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index bca66ac61a62..cf5c1a556d11 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -76,7 +76,7 @@ static short gscd_port = GSCD_BASE_ADDR; MODULE_PARM(gscd, "h"); /* Kommt spaeter vielleicht noch mal dran ... - * static struct wait_queue *gscd_waitq = NULL; + * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); */ static void gscd_transfer (void); diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 23033890058e..d19b940d69e0 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -585,7 +585,7 @@ static const char *major_name="sbpcd4"; /*==========================================================================*/ #if FUTURE -static struct wait_queue *sbp_waitq = NULL; +static DECLARE_WAIT_QUEUE_HEAD(sbp_waitq); #endif FUTURE static int teac=SBP_TEAC_SPEED; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index af91e158ed6f..a59d32b16e54 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1264,7 +1264,7 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); TTY_OVERRUN; *tty->flip.char_buf_ptr++ = 0; /* If the flip buffer itself is - overflowing, we still loose + overflowing, we still lose the next incoming character. */ if(tty->flip.count diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c index 304feb0e8cf7..29e9f7f81f41 100644 --- a/drivers/char/dn_keyb.c +++ b/drivers/char/dn_keyb.c @@ -47,7 +47,7 @@ static int keyb_cmd_transmit=0; static unsigned int kbd_mode=APOLLO_KBD_MODE_KEYB; static short mouse_dx,mouse_dy,mouse_buttons; static int mouse_ready=0,mouse_update_allowed=0,mouse_active=0; -static struct wait_queue *mouse_wait=NULL; +static DECLARE_WAIT_QUEUE_HEAD(mouse_wait); static struct fasync_struct *mouse_fasyncptr=NULL; #if 0 diff --git a/drivers/char/h8.c b/drivers/char/h8.c index c76aeb79b8f3..d146a808f27c 100644 --- a/drivers/char/h8.c +++ b/drivers/char/h8.c @@ -160,7 +160,7 @@ queue_head_t h8_actq, h8_cmdq, h8_freeq; */ int cpu_speed_divisor = -1; int h8_event_mask = 0; -struct wait_queue *h8_monitor_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait); unsigned int h8_command_mask = 0; int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD; int h8_uthermal_window = UTH_HYSTERESIS; @@ -170,7 +170,7 @@ int h8_udamp = MHZ_57; u_char h8_current_temp = 0; u_char h8_system_temp = 0; int h8_sync_channel = 0; -struct wait_queue *h8_sync_wait = NULL; +DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait); int h8_init_performed; /* CPU speeds and clock divisor values */ diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index e40a2631fe03..ad9d6f066d25 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -279,7 +279,8 @@ void handle_scancode(unsigned char scancode, int down) u_char type; /* the XOR below used to be an OR */ - int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate; + int shift_final = (shift_state | kbd->slockstate) ^ + kbd->lockstate; ushort *key_map = key_maps[shift_final]; if (key_map != NULL) { @@ -311,6 +312,7 @@ void handle_scancode(unsigned char scancode, int down) /* we have at least to update shift_state */ #if 1 /* how? two almost equivalent choices follow */ compute_shiftstate(); + kbd->slockstate = 0; /* play it safe */ #else keysym = U(plain_map[keycode]); type = KTYP(keysym); @@ -472,6 +474,7 @@ static void scroll_back(void) static void boot_it(void) { + if (kbd->slockstate & ~shift_state) return; ctrl_alt_del(); } @@ -741,7 +744,7 @@ void compute_shiftstate(void) for(j=0; jlockstate ^ kbd->slockstate]) { + kbd->slockstate = 0; + chg_vc_kbd_slock(kbd, value); + } } /* diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index 9b0418faf00f..dda54324e5b4 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -326,7 +326,7 @@ static void pcxx_error(int line, char *msg) static int pcxx_waitcarrier(struct tty_struct *tty,struct file *filp,struct channel *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval = 0; int do_clocal = 0; diff --git a/drivers/char/pcxx.h b/drivers/char/pcxx.h index e688a8be2409..6d7a08b85f87 100644 --- a/drivers/char/pcxx.h +++ b/drivers/char/pcxx.h @@ -88,8 +88,8 @@ struct channel { int blocked_open; int close_delay; int event; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; struct tq_struct tqueue; /* ------------ Async control data ------------- */ unchar modemfake; /* Modem values to be forced */ diff --git a/drivers/char/planb.c b/drivers/char/planb.c index 0f2d24e8bbe4..1c6bf655be58 100644 --- a/drivers/char/planb.c +++ b/drivers/char/planb.c @@ -379,7 +379,7 @@ static volatile struct dbdma_cmd *cmd_geo_setup( static void __planb_wait(struct planb *pb) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); add_wait_queue(&pb->lockq, &wait); repeat: diff --git a/drivers/char/planb.h b/drivers/char/planb.h index 716163f6c851..e57bed49b943 100644 --- a/drivers/char/planb.h +++ b/drivers/char/planb.h @@ -175,7 +175,7 @@ struct planb { unsigned int tab_size; int maxlines; int lock; - struct wait_queue *lockq; + wait_queue_head_t lockq; unsigned int irq; /* interrupt number */ volatile unsigned int intr_mask; @@ -190,13 +190,13 @@ struct planb { unsigned long ch1_cmd_phys; volatile unsigned char *mask; /* Clipmask buffer */ int suspend; - struct wait_queue *suspendq; + wait_queue_head_t suspendq; struct planb_suspend suspended; int cmd_buff_inited; /* cmd buffer inited? */ int grabbing; unsigned int gcount; - struct wait_queue *capq; + wait_queue_head_t capq; int last_fr; int prev_last_fr; unsigned char *fbuffer; diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index b3ff152579f6..3851616ab576 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -2007,7 +2007,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct cyclades_port *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; int channel; int retval; diff --git a/drivers/isdn/avmb1/capidev.h b/drivers/isdn/avmb1/capidev.h index f2e0d6d2d579..8941a0a645a4 100644 --- a/drivers/isdn/avmb1/capidev.h +++ b/drivers/isdn/avmb1/capidev.h @@ -22,7 +22,7 @@ struct capidev { int is_registered; __u16 applid; struct sk_buff_head recv_queue; - struct wait_queue *recv_wait; + wait_queue_head_t recv_wait; __u16 errcode; }; diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h index 20051bf3ec13..d284cc70f0d5 100644 --- a/drivers/isdn/pcbit/pcbit.h +++ b/drivers/isdn/pcbit/pcbit.h @@ -68,7 +68,7 @@ struct pcbit_dev { struct frame_buf *write_queue; /* Protocol start */ - struct wait_queue *set_running_wq; + wait_queue_head_t set_running_wq; struct timer_list set_running_timer; struct timer_list error_recover_timer; diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 6fbd00a08861..586a72d18d7d 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -375,7 +375,7 @@ struct adbdev_state { spinlock_t lock; atomic_t n_pending; struct adb_request *completed; - struct wait_queue *wait_queue; + wait_queue_head_t wait_queue; int inuse; }; @@ -458,7 +458,7 @@ static ssize_t adb_read(struct file *file, char *buf, int ret; struct adbdev_state *state = file->private_data; struct adb_request *req; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); unsigned long flags; if (count < 2) diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index 9df6dc373634..e0383190bae8 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -251,7 +251,7 @@ int adb_button3_keycode = 0x7c; /* right option key */ extern int console_loglevel; extern struct kbd_struct kbd_table[]; -extern struct wait_queue * keypress_wait; +extern struct wait_queue_head_t keypress_wait; extern void handle_scancode(unsigned char, int); diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index bdfb0198db40..42ece13581b6 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -1595,7 +1595,7 @@ static void rs_hangup(struct tty_struct *tty) static int block_til_ready(struct tty_struct *tty, struct file * filp, struct mac_serial *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait,current); int retval; int do_clocal = 0; diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h index b296c25f231b..135d5a9708fd 100644 --- a/drivers/macintosh/macserial.h +++ b/drivers/macintosh/macserial.h @@ -153,8 +153,8 @@ struct mac_serial { struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; }; diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c index a3d8ee022a8f..ae7576e9483e 100644 --- a/drivers/misc/parport_init.c +++ b/drivers/misc/parport_init.c @@ -20,10 +20,11 @@ #ifndef MODULE static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; +static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY }; static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; -extern int parport_pc_init(int *io, int *irq, int *dma); +extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); extern int parport_ax_init(void); static int parport_setup_ptr __initdata = 0; @@ -121,7 +122,7 @@ __initfunc(int parport_init(void)) parport_proc_init(); #endif #ifdef CONFIG_PARPORT_PC - parport_pc_init(io, irq, dma); + parport_pc_init(io, io_hi, irq, dma); #endif #ifdef CONFIG_PARPORT_AX parport_ax_init(); diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c index 8279c075b06e..0a4e4f92150d 100644 --- a/drivers/misc/parport_pc.c +++ b/drivers/misc/parport_pc.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,7 @@ than PARPORT_MAX (in ). */ #define PARPORT_PC_MAX_PORTS 8 -static int user_specified = 0; +static int user_specified __initdata = 0; static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -62,27 +63,27 @@ static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) void parport_pc_write_epp(struct parport *p, unsigned char d) { - outb(d, p->base+EPPDATA); + outb(d, EPPDATA(p)); } unsigned char parport_pc_read_epp(struct parport *p) { - return inb(p->base+EPPDATA); + return inb(EPPDATA(p)); } void parport_pc_write_epp_addr(struct parport *p, unsigned char d) { - outb(d, p->base+EPPADDR); + outb(d, EPPADDR(p)); } unsigned char parport_pc_read_epp_addr(struct parport *p) { - return inb(p->base+EPPADDR); + return inb(EPPADDR(p)); } int parport_pc_check_epp_timeout(struct parport *p) { - if (!(inb(p->base+STATUS) & 1)) + if (!(inb(STATUS(p)) & 1)) return 0; parport_pc_epp_clear_timeout(p); return 1; @@ -90,24 +91,24 @@ int parport_pc_check_epp_timeout(struct parport *p) unsigned char parport_pc_read_configb(struct parport *p) { - return inb(p->base+CONFIGB); + return inb(CONFIGB(p)); } void parport_pc_write_data(struct parport *p, unsigned char d) { - outb(d, p->base+DATA); + outb(d, DATA(p)); } unsigned char parport_pc_read_data(struct parport *p) { - return inb(p->base+DATA); + return inb(DATA(p)); } void parport_pc_write_control(struct parport *p, unsigned char d) { struct parport_pc_private *priv = p->private_data; priv->ctr = d;/* update soft copy */ - outb(d, p->base+CONTROL); + outb(d, CONTROL(p)); } unsigned char parport_pc_read_control(struct parport *p) @@ -121,34 +122,34 @@ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, un struct parport_pc_private *priv = p->private_data; unsigned char ctr = priv->ctr; ctr = (ctr & ~mask) ^ val; - outb (ctr, p->base+CONTROL); + outb (ctr, CONTROL(p)); return priv->ctr = ctr; /* update soft copy */ } void parport_pc_write_status(struct parport *p, unsigned char d) { - outb(d, p->base+STATUS); + outb(d, STATUS(p)); } unsigned char parport_pc_read_status(struct parport *p) { - return inb(p->base+STATUS); + return inb(STATUS(p)); } void parport_pc_write_econtrol(struct parport *p, unsigned char d) { - outb(d, p->base+ECONTROL); + outb(d, ECONTROL(p)); } unsigned char parport_pc_read_econtrol(struct parport *p) { - return inb(p->base+ECONTROL); + return inb(ECONTROL(p)); } unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned char old = inb(p->base+ECONTROL); - outb(((old & ~mask) ^ val), p->base+ECONTROL); + unsigned char old = inb(ECONTROL(p)); + outb(((old & ~mask) ^ val), ECONTROL(p)); return old; } @@ -159,12 +160,12 @@ void parport_pc_change_mode(struct parport *p, int m) void parport_pc_write_fifo(struct parport *p, unsigned char v) { - outb (v, p->base+CONFIGA); + outb (v, CONFIGA(p)); } unsigned char parport_pc_read_fifo(struct parport *p) { - return inb (p->base+CONFIGA); + return inb (CONFIGA(p)); } void parport_pc_disable_irq(struct parport *p) @@ -183,7 +184,7 @@ void parport_pc_release_resources(struct parport *p) free_irq(p->irq, p); release_region(p->base, p->size); if (p->modes & PARPORT_MODE_PCECR) - release_region(p->base+0x400, 3); + release_region(p->base_hi, 3); } int parport_pc_claim_resources(struct parport *p) @@ -195,7 +196,7 @@ int parport_pc_claim_resources(struct parport *p) return err; request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) - request_region(p->base+0x400, 3, p->name); + request_region(p->base_hi, 3, p->name); return 0; } @@ -223,8 +224,8 @@ size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length) { size_t got = 0; for (; got < length; got++) { - *((char*)buf)++ = inb (p->base+EPPDATA); - if (inb (p->base+STATUS) & 0x01) + *((char*)buf)++ = inb (EPPDATA(p)); + if (inb (STATUS(p)) & 0x01) break; } return got; @@ -234,8 +235,8 @@ size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length) { size_t written = 0; for (; written < length; written++) { - outb (*((char*)buf)++, p->base+EPPDATA); - if (inb (p->base+STATUS) & 0x01) + outb (*((char*)buf)++, EPPDATA(p)); + if (inb (STATUS(p)) & 0x01) break; } return written; @@ -350,7 +351,7 @@ int parport_pc_epp_clear_timeout(struct parport *pb) /* * Checks for port existence, all ports support SPP MODE */ -static int parport_SPP_supported(struct parport *pb) +static int __init parport_SPP_supported(struct parport *pb) { unsigned char r, w; @@ -370,11 +371,11 @@ static int parport_SPP_supported(struct parport *pb) * allow reads, so read_control just returns a software * copy. Some ports _do_ allow reads, so bypass the software * copy here. In addition, some bits aren't writable. */ - r = inb (pb->base+CONTROL); + r = inb (CONTROL (pb)); if ((r & 0x3f) == w) { w = 0xe; parport_pc_write_control (pb, w); - r = inb (pb->base+CONTROL); + r = inb (CONTROL(pb)); parport_pc_write_control (pb, 0xc); if ((r & 0x3f) == w) return PARPORT_MODE_PCSPP; @@ -425,7 +426,7 @@ static int parport_SPP_supported(struct parport *pb) * We will write 0x2c to ECR and 0xcc to CTR since both of these * values are "safe" on the CTR since bits 6-7 of CTR are unused. */ -static int parport_ECR_present(struct parport *pb) +static int __init parport_ECR_present(struct parport *pb) { unsigned char r; @@ -458,7 +459,7 @@ static int parport_ECR_present(struct parport *pb) return 0; } -static int parport_ECP_supported(struct parport *pb) +static int __init parport_ECP_supported(struct parport *pb) { int i; unsigned char oecr; @@ -493,7 +494,7 @@ static int parport_ECP_supported(struct parport *pb) * or writing a 1 to the bit (SMC, UMC, WinBond), others ??? * This bit is always high in non EPP modes. */ -static int parport_EPP_supported(struct parport *pb) +static int __init parport_EPP_supported(struct parport *pb) { /* If EPP timeout bit clear then EPP available */ if (!parport_pc_epp_clear_timeout(pb)) @@ -514,7 +515,7 @@ static int parport_EPP_supported(struct parport *pb) return 0; } -static int parport_ECPEPP_supported(struct parport *pb) +static int __init parport_ECPEPP_supported(struct parport *pb) { int mode; unsigned char oecr; @@ -550,7 +551,7 @@ static int parport_ECPEPP_supported(struct parport *pb) * be misdetected here is rather academic. */ -static int parport_PS2_supported(struct parport *pb) +static int __init parport_PS2_supported(struct parport *pb) { int ok = 0; unsigned char octr = parport_pc_read_control(pb); @@ -570,7 +571,7 @@ static int parport_PS2_supported(struct parport *pb) return ok?PARPORT_MODE_PCPS2:0; } -static int parport_ECPPS2_supported(struct parport *pb) +static int __init parport_ECPPS2_supported(struct parport *pb) { int mode; unsigned char oecr; @@ -590,7 +591,7 @@ static int parport_ECPPS2_supported(struct parport *pb) /* --- IRQ detection -------------------------------------- */ /* Only if supports ECP mode */ -static int programmable_irq_support(struct parport *pb) +static int __init programmable_irq_support(struct parport *pb) { int irq, intrLine; unsigned char oecr = parport_pc_read_econtrol(pb); @@ -607,7 +608,7 @@ static int programmable_irq_support(struct parport *pb) return irq; } -static int irq_probe_ECP(struct parport *pb) +static int __init irq_probe_ECP(struct parport *pb) { int irqs, i; @@ -634,7 +635,7 @@ static int irq_probe_ECP(struct parport *pb) * This detection seems that only works in National Semiconductors * This doesn't work in SMC, LGS, and Winbond */ -static int irq_probe_EPP(struct parport *pb) +static int __init irq_probe_EPP(struct parport *pb) { int irqs; unsigned char octr = parport_pc_read_control(pb); @@ -675,7 +676,7 @@ static int irq_probe_EPP(struct parport *pb) return pb->irq; } -static int irq_probe_SPP(struct parport *pb) +static int __init irq_probe_SPP(struct parport *pb) { int irqs; unsigned char octr = parport_pc_read_control(pb); @@ -723,7 +724,7 @@ static int irq_probe_SPP(struct parport *pb) * When ECP is available we can autoprobe for IRQs. * NOTE: If we can autoprobe it, we can register the IRQ. */ -static int parport_irq_probe(struct parport *pb) +static int __init parport_irq_probe(struct parport *pb) { if (pb->modes & PARPORT_MODE_PCECR) { pb->irq = programmable_irq_support(pb); @@ -754,7 +755,9 @@ out: /* --- Initialisation code -------------------------------- */ -static int probe_one_port(unsigned long int base, int irq, int dma) +static int __init probe_one_port(unsigned long int base, + unsigned long int base_hi, + int irq, int dma) { struct parport *p; int probedirq = PARPORT_IRQ_NONE; @@ -770,8 +773,9 @@ static int probe_one_port(unsigned long int base, int irq, int dma) return 0; } ((struct parport_pc_private *) (p->private_data))->ctr = 0xc; + p->base_hi = base_hi; if (p->base != 0x3bc) { - if (!check_region(base+0x400,3)) { + if (base_hi && !check_region(base_hi,3)) { p->modes |= parport_ECR_present(p); p->modes |= parport_ECP_supported(p); p->modes |= parport_ECPPS2_supported(p); @@ -791,6 +795,8 @@ static int probe_one_port(unsigned long int base, int irq, int dma) p->size = (p->modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP))?8:3; printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); + if (p->base_hi && (p->modes & PARPORT_MODE_PCECR)) + printk (" (0x%lx)", p->base_hi); if (p->irq == PARPORT_IRQ_AUTO) { p->irq = PARPORT_IRQ_NONE; parport_irq_probe(p); @@ -829,11 +835,14 @@ static int probe_one_port(unsigned long int base, int irq, int dma) /* Done probing. Now put the port into a sensible start-up state. */ if (p->modes & PARPORT_MODE_PCECR) /* - * Put the ECP detected port in the more SPP like mode. + * Put the ECP detected port in PS2 mode. */ - parport_pc_write_econtrol(p, 0x0); - parport_pc_write_control(p, 0xc); + parport_pc_write_econtrol(p, 0x24); parport_pc_write_data(p, 0); + parport_pc_write_control(p, 0x8); + udelay (50); + parport_pc_write_control(p, 0xc); + udelay (50); if (parport_probe_hook) (*parport_probe_hook)(p); @@ -841,20 +850,22 @@ static int probe_one_port(unsigned long int base, int irq, int dma) return 1; } -int parport_pc_init(int *io, int *irq, int *dma) +int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma) { int count = 0, i = 0; if (io && *io) { /* Only probe the ports we were given. */ user_specified = 1; do { - count += probe_one_port(*(io++), *(irq++), *(dma++)); + if (!*io_hi) *io_hi = 0x400 + *io; + count += probe_one_port(*(io++), *(io_hi++), + *(irq++), *(dma++)); } while (*io && (++i < PARPORT_PC_MAX_PORTS)); } else { /* Probe all the likely ports. */ - count += probe_one_port(0x3bc, irq[0], dma[0]); - count += probe_one_port(0x378, irq[0], dma[0]); - count += probe_one_port(0x278, irq[0], dma[0]); + count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]); + count += probe_one_port(0x378, 0x778, irq[0], dma[0]); + count += probe_one_port(0x278, 0x678, irq[0], dma[0]); } return count; @@ -862,10 +873,12 @@ int parport_pc_init(int *io, int *irq, int *dma) #ifdef MODULE static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; +static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE }; static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); +MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); @@ -877,7 +890,7 @@ int init_module(void) for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); parport_parse_irqs(i, irq, irqval); - return (parport_pc_init(io, irqval, dma)?0:1); + return (parport_pc_init(io, io_hi, irqval, dma)?0:1); } void cleanup_module(void) diff --git a/drivers/net/cosa.c b/drivers/net/cosa.c index 69f8bb0d8406..bc07d0ce5100 100644 --- a/drivers/net/cosa.c +++ b/drivers/net/cosa.c @@ -126,7 +126,8 @@ struct channel_data { struct semaphore rsem, wsem; char *rxdata; int rxsize; - struct wait_queue *txwaitq, *rxwaitq; + wait_queue_head_t txwaitq; + wait_queue_head_t rxwaitq; int tx_status, rx_status; /* SPPP/HDLC device parts */ @@ -762,7 +763,7 @@ static long long cosa_lseek(struct file * file, static ssize_t cosa_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int flags; struct channel_data *chan = (struct channel_data *)file->private_data; struct cosa_data *cosa = chan->cosa; @@ -833,7 +834,7 @@ static ssize_t cosa_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct channel_data *chan = (struct channel_data *)file->private_data; - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct cosa_data *cosa = chan->cosa; unsigned int flags; char *kbuf; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index 80d7a119133b..28a318637ab2 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -664,7 +664,7 @@ de620_rx_intr(struct device *dev) if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) { /* Ouch... Forget it! Skip all and start afresh... */ printk("%s: Ring overrun? Restoring...\n", dev->name); - /* You win some, you loose some. And sometimes plenty... */ + /* You win some, you lose some. And sometimes plenty... */ adapter_init(dev); ((struct net_device_stats *)(dev->priv))->rx_over_errors++; return 0; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 580fb2dcad9b..f618fd5fb08b 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1834,7 +1834,7 @@ static inline void sun4c_happy_meal_tx(struct happy_meal *hp) #define RXD(x) #endif -/* Originally I use to handle the allocation failure by just giving back just +/* Originally I used to handle the allocation failure by just giving back just * that one ring buffer to the happy meal. Problem is that usually when that * condition is triggered, the happy meal expects you to do something reasonable * with all of the packets it has DMA'd in. So now I just drop the entire diff --git a/drivers/net/z85230.h b/drivers/net/z85230.h index 0b3850061308..a2e7f3ea2298 100644 --- a/drivers/net/z85230.h +++ b/drivers/net/z85230.h @@ -331,8 +331,8 @@ struct z8530_channel int line; /* Minor number */ struct termios normal_termios; /* Terminal settings */ struct termios callout_termios; - struct wait_queue *open_wait; /* Tasks waiting to open */ - struct wait_queue *close_wait; /* and for close to end */ + wait_queue_head_t open_wait; /* Tasks waiting to open */ + wait_queue_head_t close_wait; /* and for close to end */ unsigned long event; /* Pending events */ int fdcount; /* # of fd on device */ int blocked_open; /* # of blocked opens */ diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 673b820c8595..7905ceda02b0 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.28 1999/05/12 11:15:05 davem Exp $ +/* $Id: pcikbd.c,v 1.29 1999/05/16 13:47:53 ecd Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -983,6 +983,8 @@ found: } memset(queue, 0, sizeof(*queue)); + init_waitqueue_head(&queue->proc_list); + if (request_irq(pcimouse_irq, &pcimouse_interrupt, SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) { printk("8042: Cannot register IRQ %s\n", diff --git a/drivers/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c index ca19c6f6ba3b..486d911be8df 100644 --- a/drivers/scsi/sd_ioctl.c +++ b/drivers/scsi/sd_ioctl.c @@ -15,6 +15,7 @@ #define MAJOR_NR SCSI_DISK0_MAJOR #include +#include #include "scsi.h" #include #include "hosts.h" @@ -79,42 +80,20 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne (long *) arg); return 0; + case BLKROSET: + case BLKROGET: case BLKRASET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - case BLKRAGET: - if (!arg) - return -EINVAL; - error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if (error) - return error; - put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - return 0; - case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) return -EACCES; - if(!(inode->i_rdev)) return -EINVAL; - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - return 0; - + case BLKSSZGET: + case BLKPG: + return blk_ioctl(inode->i_rdev, cmd, arg); + case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; return revalidate_scsidisk(dev, 1); - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[MAJOR(dev)][MINOR(dev)&0x0F], - (int *)arg); - - RO_IOCTLS(dev, arg); - default: return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); } diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 1f9762cabb03..59d4b53cf661 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -7,6 +7,7 @@ #include #include +#include #include "scsi.h" #include "hosts.h" #include @@ -768,7 +769,7 @@ sr_is_xa(int minor) int sr_dev_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, unsigned long arg) { - int target, err; + int target; target = MINOR(cdi->dev); @@ -855,40 +856,14 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, spin_unlock_irqrestore(&io_request_lock, flags); return rc; } - case BLKRAGET: - if (!arg) - return -EINVAL; - err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); - if (err) - return err; - put_user(read_ahead[MAJOR(cdi->dev)], (long *) arg); - return 0; + case BLKROSET: + case BLKROGET: case BLKRASET: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(cdi->dev)) - return -EINVAL; - if(arg > 0xff) - return -EINVAL; - read_ahead[MAJOR(cdi->dev)] = arg; - return 0; - - case BLKSSZGET: - /* Block size of media */ - return put_user(blksize_size[MAJOR(cdi->dev)][MINOR(cdi->dev)], - (int *)arg); - - RO_IOCTLS(cdi->dev,arg); - + case BLKRAGET: case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - if(!(cdi->dev)) - return -EINVAL; - fsync_dev(cdi->dev); - invalidate_buffers(cdi->dev); - return 0; + case BLKSSZGET: + return blk_ioctl(cdi->dev, cmd, arg); default: return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 2146e2b01ec8..4d5a498f3d61 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -65,7 +65,7 @@ typedef struct { typedef struct { kdev_t devt; unsigned capacity; - struct wait_queue * waiting; + wait_queue_head_t waiting; Scsi_Device* device; struct semaphore sem; ST_buffer * buffer; diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c index 71b09c3de953..c2b3311ea3c8 100644 --- a/drivers/sgi/char/sgiserial.c +++ b/drivers/sgi/char/sgiserial.c @@ -33,7 +33,7 @@ #define NUM_SERIAL 1 /* One chip on board. */ #define NUM_CHANNELS (NUM_SERIAL * 2) -extern struct wait_queue * keypress_wait; +extern struct wait_queue_head_t keypress_wait; struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, }; struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, }; @@ -1519,7 +1519,7 @@ void rs_hangup(struct tty_struct *tty) static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sgi_serial *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; diff --git a/drivers/sgi/char/sgiserial.h b/drivers/sgi/char/sgiserial.h index 35f18cab7a02..5fdb8b15bab1 100644 --- a/drivers/sgi/char/sgiserial.h +++ b/drivers/sgi/char/sgiserial.h @@ -158,8 +158,8 @@ struct sgi_serial { struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; }; diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c index 6a41d0ae0c0b..a2b491932ebb 100644 --- a/drivers/sgi/char/shmiq.c +++ b/drivers/sgi/char/shmiq.c @@ -82,7 +82,7 @@ static struct { int events; int mapped; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; struct fasync_struct *fasync; } shmiqs [MAX_SHMI_QUEUES]; diff --git a/drivers/sgi/char/usema.c b/drivers/sgi/char/usema.c index 5bf0e4ee7e6a..4a25f979f410 100644 --- a/drivers/sgi/char/usema.c +++ b/drivers/sgi/char/usema.c @@ -39,7 +39,7 @@ struct irix_usema { struct file *filp; - struct wait_queue *proc_list; + wait_queue_head_t proc_list; }; static int diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h index 9f9c57039ed2..6ced8d65dae4 100644 --- a/drivers/sound/lowlevel/awe_compat.h +++ b/drivers/sound/lowlevel/awe_compat.h @@ -245,7 +245,7 @@ PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\ #endif /* AWE_MODULE_SUPPORT */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) -inline static void interruptible_sleep_on_timeout(struct wait_queue **q, unsigned long timeout) +inline static void interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout) { current->timeout = jiffies + timeout; interruptible_sleep_on(q); diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/lowlevel/awe_wave.c index 8fd5431e6cbb..042d999c3daf 100644 --- a/drivers/sound/lowlevel/awe_wave.c +++ b/drivers/sound/lowlevel/awe_wave.c @@ -979,7 +979,7 @@ awe_wait(unsigned short delay) } #else -static struct wait_queue *awe_sleeper = NULL; +static DECLARE_WAIT_QUEUE_HEAD(awe_sleeper); static void awe_wait(unsigned short delay) { interruptible_sleep_on_timeout(&awe_sleeper, (HZ * (unsigned long)delay + 44099) / 44100); diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index ae7a952add15..1379563f24b3 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -231,8 +231,9 @@ typedef struct multisound_dev { #define F_EXT_MIDI_INUSE 9 #define F_INT_MIDI_INUSE 10 #define F_DISABLE_WRITE_NDELAY 11 - struct wait_queue *writeblock, *readblock; - struct wait_queue *writeflush; + wait_queue_head_t writeblock; + wait_queue_head_t readblock; + wait_queue_head_t writeflush; #ifndef LINUX20 spinlock_t lock; #endif diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 2b7bcb1d5ed8..eb3ba55e86e9 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -14,7 +14,12 @@ comment 'USB drivers - not for the faint of heart' tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB if [ ! "$CONFIG_USB" = "n" ]; then bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI + bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI + if [ "$CONFIG_USB_OHCI" = "y" ]; then + bool ' Enable tons of OHCI debugging output?' CONFIG_USB_OHCI_DEBUG + fi + bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB diff --git a/drivers/usb/README.ohci b/drivers/usb/README.ohci index 7a544eb3353a..23a4888322db 100644 --- a/drivers/usb/README.ohci +++ b/drivers/usb/README.ohci @@ -1,3 +1,31 @@ +May 16, 1999 16:20:54 + +EDs are now allocated dynamically from their device's pool. Root hub +status changes should stop the infinite "no device connected" messages +that occurred after removing a device. + +TODO: + +~ Add the concept of a td_group to lump TDs associated with a single + data transfer request from the higher layers. This will be needed + for bulk and all larger transfers that will span multiple TDs but + which need to allocate/free them as a group as things happen. I + am thinking about create_td_group and free_td_group functions... +~ Add bulk transfer support. +~ Add Isochronous transfer support. These have their own special + format TDs to allow for several DMA data pointers. Kinda neat, but + likely harder to use through a generic interface in practice. +~ Support dynamic allocation & growth of the TD/ED pools. Merge them + into global pools rather than a today's static per device allocation. + +KNOWN BUGS: + +~ Unplugging a hub causes khubd to Oops. I don't think this is + directly related to OHCI, but due to the fact that the interrupt TD + for the hub is never stopped. We need a usb_release_irq() that gets + called using the "IRQ handle" that should be returned by + usb_request_irq(). + May 09, 1999 16:25:58 Cool, things are working "well" now. (I'm not getting oops's from the diff --git a/drivers/usb/ohci-debug.c b/drivers/usb/ohci-debug.c index 1510bb9da441..83b759ae6d56 100644 --- a/drivers/usb/ohci-debug.c +++ b/drivers/usb/ohci-debug.c @@ -80,17 +80,18 @@ void show_ohci_ed(struct ohci_ed *ed) printk(KERN_DEBUG " ohci ED:\n"); printk(KERN_DEBUG " status = 0x%x\n", stat); - printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d\n", + printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d%s\n", skip ? "Skip " : "", mps, - isoc ? "Isoc. " : "", + isoc ? " Isoc." : "", low_speed ? " LowSpd" : "", (dir == OHCI_ED_D_IN) ? " Input" : (dir == OHCI_ED_D_OUT) ? " Output" : "", halted ? " Halted" : "", toggle, endnum, - funcaddr); + funcaddr, + (stat & ED_ALLOCATED) ? " Allocated" : ""); printk(KERN_DEBUG " tail_td = 0x%x\n", ed->tail_td); printk(KERN_DEBUG " head_td = 0x%x\n", ed_head_td(ed)); printk(KERN_DEBUG " next_ed = 0x%x\n", ed->next_ed); @@ -108,20 +109,22 @@ void show_ohci_td(struct ohci_td *td) printk(KERN_DEBUG " ohci TD hardware fields:\n"); printk(KERN_DEBUG " info = 0x%x\n", td->info); - printk(KERN_DEBUG " %s%s%s%d %s\n", + printk(KERN_DEBUG " %s%s%s%d %s %s%d\n", td_round ? "Rounding " : "", (td_dir == OHCI_TD_D_IN) ? "Input " : (td_dir == OHCI_TD_D_OUT) ? "Output " : (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "", "IntDelay ", td_int_delay, (td_toggle < 2) ? " " : - (td_toggle & 1) ? "Data1 " : "Data0 "); - printk(KERN_DEBUG " %s%d %s0x%x, %sAccessed, %sActive\n", - "ErrorCnt ", td_errcnt, - "ComplCode ", td_cc, + (td_toggle & 1) ? "Data1" : "Data0", + "ErrorCnt ", td_errcnt); + printk(KERN_DEBUG " ComplCode 0x%x, %sAccessed, %sActive\n", + td_cc, td_cc_accessed(*td) ? "" : "Not ", td_active(*td) ? "" : "Not "); + printk(KERN_DEBUG " %s\n", td_allocated(*td) ? "Allocated" : "Free"); + printk(KERN_DEBUG " cur_buf = 0x%x\n", td->cur_buf); printk(KERN_DEBUG " next_td = 0x%x\n", td->next_td); printk(KERN_DEBUG " buf_end = 0x%x\n", td->buf_end); diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c index 4393b72c0f46..330b249eba9d 100644 --- a/drivers/usb/ohci.c +++ b/drivers/usb/ohci.c @@ -29,7 +29,7 @@ * * No filesystems were harmed in the development of this code. * - * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $ + * $Id: ohci.c,v 1.43 1999/05/16 22:35:24 greg Exp $ */ #include @@ -59,31 +59,30 @@ static int apm_resume = 0; static DECLARE_WAIT_QUEUE_HEAD(ohci_configure); -#ifdef OHCI_TIMER -static struct timer_list ohci_timer; /* timer for root hub polling */ +#ifdef CONFIG_USB_OHCI_DEBUG +#define OHCI_DEBUG /* to make typing it easier.. */ #endif +#ifdef OHCI_DEBUG +int MegaDebug = 0; /* SIGUSR2 to the control thread toggles this */ +#endif -static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td) -{ - unsigned int status; - - status = td->info & OHCI_TD_CC; - - /* TODO Debugging code for TD failures goes here */ - - return status; -} /* ohci_td_result() */ +#ifdef OHCI_TIMER +static struct timer_list ohci_timer; /* timer for root hub polling */ +#endif static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; /* - * Add a TD to the end of the TD list on a given ED. If td->next_td - * points to any more TDs, they will be added as well (naturally). - * Otherwise td->next_td must be 0. + * Add a TD to the end of the TD list on a given ED. This function + * does NOT advance the ED's tail_td pointer beyond the given TD. To + * add multiple TDs, call this function once for each TD. Do not + * "simply" update tail_td yourself... This function does more than + * that. * - * The SKIP flag will be cleared after this function. + * If this ED is on the controller, you MUST set its SKIP flag before + * calling this function. * * Important! This function needs locking and atomicity as it works * in parallel with the HC's DMA. Locking ohci_edtd_lock while using @@ -93,54 +92,62 @@ static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; */ static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed) { - /* don't let the HC pull anything from underneath us */ - ed->status |= OHCI_ED_SKIP; + struct ohci_td *dummy_td, *prev_td; + + if (ed->tail_td == 0) { + printk("eek! an ED without a dummy_td\n"); + } + + /* The ED's tail_td is constant, always pointing to the + * dummy_td. The reason the ED never processes the dummy is + * that it stops processing TDs as soon as head_td == tail_td. + * When it advances to this last dummy TD it conveniently stops. */ + dummy_td = bus_to_virt(ed->tail_td); - if (ed_head_td(ed) == 0) { /* empty list, put it on the head */ - set_ed_head_td(ed, virt_to_bus(td)); - ed->tail_td = 0; + /* Dummy's data pointer is used to point to the previous TD */ + if (ed_head_td(ed) != ed->tail_td) { + prev_td = (struct ohci_td *) dummy_td->data; } else { - struct ohci_td *tail, *head; - head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed)); - tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td); - if (!tail) { /* no tail, single element list */ - td->next_td = head->next_td; - head->next_td = virt_to_bus(td); - ed->tail_td = virt_to_bus(td); - } else { /* append to the list */ - td->next_td = tail->next_td; - tail->next_td = virt_to_bus(td); - ed->tail_td = virt_to_bus(td); - } + /* if the ED is empty, previous is meaningless */ + /* We'll be inserting into the head of the list */ + prev_td = NULL; } - /* save the ED link in each of the TDs added */ + /* Store the new back pointer and set up this TD's next */ + dummy_td->data = td; + td->next_td = ed->tail_td; + + /* Store the TD pointer back to the ED */ td->ed = ed; - while (td->next_td != 0) { - td = bus_to_virt(td->next_td); - td->ed = ed; - } - /* turn off the SKIP flag */ - ed->status &= ~OHCI_ED_SKIP; + if (!prev_td) { /* No previous TD? then insert us at the head */ + if (ed_head_td(ed) != ed->tail_td) + printk(KERN_DEBUG "Suspicious ED...\n"); + set_ed_head_td(ed, virt_to_bus(td)); /* put it on the ED */ + } else { + /* add the TD to the end */ + prev_td->next_td = virt_to_bus(td); + } } /* ohci_add_td_to_ed() */ inline void ohci_start_control(struct ohci *ohci) { /* tell the HC to start processing the control list */ - writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); + writel_set(OHCI_USB_CLE, &ohci->regs->control); + writel_set(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus); } inline void ohci_start_bulk(struct ohci *ohci) { /* tell the HC to start processing the bulk list */ - writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); + writel_set(OHCI_USB_BLE, &ohci->regs->control); + writel_set(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus); } inline void ohci_start_periodic(struct ohci *ohci) { - /* enable processing periodc transfers starting next frame */ + /* enable processing periodic (intr) transfers starting next frame */ writel_set(OHCI_USB_PLE, &ohci->regs->control); } @@ -152,6 +159,7 @@ inline void ohci_start_isoc(struct ohci *ohci) /* * Add an ED to the hardware register ED list pointed to by hw_listhead_p + * This function only makes sense for Control and Bulk EDs. */ static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p) { @@ -172,11 +180,11 @@ static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p) writel(virt_to_bus(ed), hw_listhead_p); spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* ohci_add_ed() */ +} /* ohci_add_ed_to_hw() */ /* - * Put another control ED on the controller's list + * Put a control ED on the controller's list */ void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed) { @@ -184,37 +192,146 @@ void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed) ohci_start_control(ohci); } /* ohci_add_control_ed() */ +/* + * Put a bulk ED on the controller's list + */ +void ohci_add_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_add_ed_to_hw(ed, &ohci->regs->ed_bulkhead); + ohci_start_bulk(ohci); +} /* ohci_add_bulk_ed() */ -#if 0 /* - * Put another control ED on the controller's list + * Put a periodic ED on the appropriate list given the period. */ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period) { - ohci_add_ed_to_hw(ed, /* XXX */); + struct ohci_ed *int_ed; + unsigned long flags; + + /* + * Pick a good frequency endpoint based on the requested period + */ + int_ed = &ohci->root_hub->ed[ms_to_ed_int(period)]; +#ifdef OHCI_DEBUG + printk("usb-ohci: Using INT ED queue %d for %dms period\n", + ms_to_ed_int(period), period); +#endif + + spin_lock_irqsave(&ohci_edtd_lock, flags); + /* + * Insert this ED at the front of the list. + */ + ed->next_ed = int_ed->next_ed; + int_ed->next_ed = virt_to_bus(ed); + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); + ohci_start_periodic(ohci); -} /* ohci_add_control_ed() */ +} /* ohci_add_periodic_ed() */ + +/* + * Put an isochronous ED on the controller's list + */ +inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed) +{ + ohci_add_periodic_ed(ohci, ed, 1); +} + + +/* + * This will be used for the interrupt to wake us up on the next SOF + */ +DECLARE_WAIT_QUEUE_HEAD(start_of_frame_wakeup); + +/* + * Guarantee that an ED is safe to be modified by the HCD (us). + * + * This function can NOT be called from an interrupt. + */ +void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type) +{ + __u32 hw_listcurrent; + + /* tell the controller to skip this ED */ + ed->status |= OHCI_ED_SKIP; + + switch (ed_type) { + case HCD_ED_CONTROL: + hw_listcurrent = readl(regs->ed_controlcurrent); + break; + case HCD_ED_BULK: + hw_listcurrent = readl(regs->ed_bulkcurrent); + break; + case HCD_ED_ISOC: + case HCD_ED_INT: + hw_listcurrent = readl(regs->ed_periodcurrent); + break; + default: + return; + } + + /* + * If the HC is processing this ED we need to wait until the + * at least the next frame. + */ + if (virt_to_bus(ed) == hw_listcurrent) { + DECLARE_WAITQUEUE(wait, current); + +#ifdef OHCI_DEBUG + printk("Waiting a frame for OHC to finish with ED %p\n", ed); #endif + add_wait_queue(&start_of_frame_wakeup, &wait); + + /* clear the SOF interrupt status and enable it */ + writel(OHCI_INTR_SF, ®s->intrstatus); + writel(OHCI_INTR_SF, ®s->intrenable); + + schedule_timeout(HZ/10); + + remove_wait_queue(&start_of_frame_wakeup, &wait); + } + + return; /* The ED is now safe */ +} /* ohci_wait_for_ed_safe() */ + /* - * Remove an ED from the HC list whos bus headpointer is pointed to - * by hw_listhead_p + * Remove an ED from the HC's list. + * This function can ONLY be used for Control or Bulk EDs. * * Note that the SKIP bit is left on in the removed ED. */ -void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) +void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_type) { unsigned long flags; + struct ohci_regs *regs = ohci->regs; struct ohci_ed *cur; __u32 bus_ed = virt_to_bus(ed); __u32 bus_cur; + __u32 *hw_listhead_p; if (ed == NULL || !bus_ed) return; - /* tell the controller this skip ED */ - ed->status |= OHCI_ED_SKIP; + switch (ed_type) { + case HCD_ED_CONTROL: + hw_listhead_p = ®s->ed_controlhead; + break; + case HCD_ED_BULK: + hw_listhead_p = ®s->ed_bulkhead; + break; + default: + printk("Unknown HCD ED type %d.\n", ed_type); + return; + } + + /* + * Tell the controller to this skip ED and make sure it is not the + * being accessed by the HC as we speak. + */ + ohci_wait_for_ed_safe(regs, ed, ed_type); bus_cur = readl(hw_listhead_p); @@ -232,7 +349,7 @@ void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) struct ohci_ed *prev; /* walk the list and unlink the ED if found */ - for (;;) { + do { prev = cur; cur = bus_to_virt(cur->next_ed); @@ -241,17 +358,14 @@ void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) prev->next_ed = cur->next_ed; break; } - - if (cur->next_ed == 0) - break; - } + } while (cur->next_ed != 0); } /* clear any links from the ED for safety */ ed->next_ed = 0; spin_unlock_irqrestore(&ohci_edtd_lock, flags); -} /* ohci_remove_ed_from_hw() */ +} /* ohci_remove_norm_ed_from_hw() */ /* * Remove an ED from the controller's control list. Note that the SKIP bit @@ -259,7 +373,7 @@ void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p) */ inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed) { - ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead); + ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_CONTROL); } /* @@ -268,7 +382,7 @@ inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed) */ inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed) { - ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead); + ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK); } @@ -321,7 +435,8 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) td->next_td = 0; /* remove the TDs links */ td->ed = NULL; - /* TODO return this TD to the pool of free TDs */ + /* return this TD to the pool of free TDs */ + ohci_free_td(td); /* unset the "skip me bit" in this ED */ ed->status &= ~OHCI_ED_SKIP; @@ -332,15 +447,21 @@ static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) /* * Get a pointer (virtual) to an available TD from the given device's - * pool. - * - * Return NULL if none are left. + * pool. Return NULL if none are left. */ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev) { int idx; +#if 0 + printk(KERN_DEBUG "in ohci_get_free_td()\n"); +#endif + + /* FIXME: this is horribly inefficient */ for (idx=0; idx < NUM_TDS; idx++) { +#if 0 + show_ohci_td(&dev->td[idx]); +#endif if (!td_allocated(dev->td[idx])) { struct ohci_td *new_td = &dev->td[idx]; /* zero out the TD */ @@ -353,11 +474,52 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev) } } - printk("usb-ohci error: unable to allocate a TD\n"); + printk("usb-ohci: unable to allocate a TD\n"); return NULL; } /* ohci_get_free_td() */ +/* + * Get a pointer (virtual) to an available TD from the given device's + * pool. Return NULL if none are left. + */ +static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev) +{ + int idx; + + /* FIXME: this is horribly inefficient */ + for (idx=0; idx < NUM_EDS; idx++) { + if (!ed_allocated(dev->ed[idx])) { + struct ohci_ed *new_ed = &dev->ed[idx]; + /* zero out the ED */ + memset(new_ed, 0, sizeof(*new_ed)); + /* all new EDs start with the SKIP bit set */ + new_ed->status |= OHCI_ED_SKIP; + /* mark it as allocated */ + allocate_ed(new_ed); + return new_ed; + } + } + + printk("usb-ohci: unable to allocate an ED\n"); + return NULL; +} /* ohci_get_free_ed() */ + + +void ohci_free_ed(struct ohci_ed *ed) +{ + if (!ed) + return; + + if (ed->tail_td == 0) { + printk("yikes! an ED without a dummy_td\n"); + } else + ohci_free_td((struct ohci_td *)bus_to_virt(ed->tail_td)); + + ed->status &= ~(__u32)ED_ALLOCATED; +} /* ohci_free_ed() */ + + /* * Initialize a TD * @@ -379,10 +541,58 @@ inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, td->dev_id = dev_id; td->completed = completed; +#if 0 + printk(KERN_DEBUG "ohci_fill_new_td created:\n"); + show_ohci_td(td); +#endif + return td; } /* ohci_fill_new_td() */ +/* + * Initialize a new ED on device dev, including allocating and putting the + * dummy tail_td on its queue if it doesn't already have one. Any + * TDs on this ED other than the dummy will be lost (so there better + * not be any!). This assumes that the ED is Allocated and will + * force the Allocated bit on. + */ +struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed, int maxpacketsize, int lowspeed, int endp_id, int isoc_tds) +{ + struct ohci_td *dummy_td; + + if (ed_head_td(ed) != ed->tail_td) + printk("Reusing a non-empty ED %p!\n", ed); + + if (!ed->tail_td) { + dummy_td = ohci_get_free_td(dev); + if (dummy_td == NULL) { + printk("Error allocating dummy TD for ED %p\n", ed); + return NULL; /* no dummy available! */ + } + make_dumb_td(dummy_td); /* flag it as a dummy */ + ed->tail_td = virt_to_bus(dummy_td); + } else { + dummy_td = bus_to_virt(ed->tail_td); + if (!td_dummy(*dummy_td)) + printk("ED %p's dummy %p is screwy\n", ed, dummy_td); + } + + /* set the head TD to the dummy and clear the Carry & Halted bits */ + ed->_head_td = ed->tail_td; + + ed->status = \ + ed_set_maxpacket(maxpacketsize) | + ed_set_speed(lowspeed) | + (endp_id & 0x7ff) | + ((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC); + allocate_ed(ed); + ed->next_ed = 0; + + return ed; +} /* ohci_fill_ed() */ + + /********************************** * OHCI interrupt list operations * **********************************/ @@ -404,26 +614,26 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe, struct ohci_td *td; struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ - /* - * Pick a good frequency endpoint based on the requested period - */ - interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)]; + /* Get an ED and TD */ + interrupt_ed = ohci_get_free_ed(dev); + if (!interrupt_ed) { + printk("Out of EDs on device %p in ohci_request_irq\n", dev); + return -1; + } + + td = ohci_get_free_td(dev); + if (!td) { + printk("Out of TDs in ohci_request_irq\n"); + ohci_free_ed(interrupt_ed); + return -1; + } /* * Set the max packet size, device speed, endpoint number, usb * device number (function address), and type of TD. - * - * FIXME: Isochronous transfers need a pool of special 32 byte - * TDs (32 byte aligned) in order to be supported. */ - interrupt_ed->status = \ - ed_set_maxpacket(usb_maxpacket(pipe)) | - ed_set_speed(usb_pipeslow(pipe)) | - usb_pipe_endpdev(pipe) | - OHCI_ED_F_NORM; - - td = ohci_get_free_td(dev); - /* FIXME: check for NULL */ + ohci_fill_ed(dev, interrupt_ed, usb_maxpacket(pipe), usb_pipeslow(pipe), + usb_pipe_endpdev(pipe), 0 /* normal TDs */); /* Fill in the TD */ ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)), @@ -432,42 +642,23 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe, &dev->data, DATA_BUF_LEN, dev_id, handler); /* - * TODO: be aware that OHCI won't advance out of the 4kb - * page cur_buf started in. It'll wrap around to the start - * of the page... annoying or useful? you decide. - * - * We should make sure dev->data doesn't cross a page... + * TODO: be aware of how the OHCI controller deals with DMA + * spanning more than one page. */ - /* FIXME: this just guarantees that its the end of the list */ - td->next_td = 0; + /* + * Put the TD onto our ED and make sure its ready to run + */ + ohci_add_td_to_ed(td, interrupt_ed); + interrupt_ed->status &= ~OHCI_ED_SKIP; + ohci_unhalt_ed(interrupt_ed); /* Linus did this. see asm/system.h; scary concept... I don't * know if its needed here or not but it won't hurt. */ wmb(); - /* - * Put the TD onto our ED - */ - { - unsigned long flags; - spin_lock_irqsave(&ohci_edtd_lock, flags); - ohci_add_td_to_ed(td, interrupt_ed); - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - } - -#if 0 /* Assimilate the new ED into the collective */ - /* - * When dynamic ED allocation is done, this call will be - * useful. For now, the correct ED already on the - * controller's proper periodic ED lists was chosen above. - */ ohci_add_periodic_ed(dev->ohci, interrupt_ed, period); -#else - /* enable periodic (interrupt) transfers on the HC */ - ohci_start_periodic(dev->ohci); -#endif return 0; } /* ohci_request_irq() */ @@ -486,6 +677,12 @@ static DECLARE_WAIT_QUEUE_HEAD(control_wakeup); */ static int ohci_control_completed(int stats, void *buffer, void *dev_id) { + /* pass the TDs completion status back to control_msg */ + if (dev_id) { + int *completion_status = (int *)dev_id; + *completion_status = stats; + } + wake_up(&control_wakeup); return 0; } /* ohci_control_completed() */ @@ -502,44 +699,46 @@ static int ohci_control_completed(int stats, void *buffer, void *dev_id) * - The command itself * - An optional data phase (if len > 0) * - Status complete phase + * + * This function can NOT be called from an interrupt. */ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len) { struct ohci_device *dev = usb_to_ohci(usb); - /* - * ideally dev->ed should be linked into the root hub's - * control_ed list and used instead of just using it directly. - * This could present a problem as is with more than one - * device. (but who wants to use a keyboard AND a mouse - * anyways? ;) - */ - struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL]; + struct ohci_ed *control_ed = ohci_get_free_ed(dev); struct ohci_td *setup_td, *data_td, *status_td; DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int completion_status = -1; -#if 0 - printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); +#ifdef OHCI_DEBUG + printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len); #endif + if (!control_ed) { + printk("usb-ohci: couldn't get ED for dev %p\n", dev); + return -1; + } + + /* get a TD to send this control message with */ + setup_td = ohci_get_free_td(dev); + if (!setup_td) { + printk("usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev); + ohci_free_ed(control_ed); + return -1; + } /* * Set the max packet size, device speed, endpoint number, usb * device number (function address), and type of TD. * */ - control_ed->status = \ - ed_set_maxpacket(usb_maxpacket(pipe)) | - ed_set_speed(usb_pipeslow(pipe)) | - usb_pipe_endpdev(pipe) | - OHCI_ED_F_NORM; + ohci_fill_ed(dev, control_ed, usb_maxpacket(pipe), usb_pipeslow(pipe), + usb_pipe_endpdev(pipe), 0 /* normal TDs */); /* * Build the control TD */ - /* get a TD to send this control message with */ - setup_td = ohci_get_free_td(dev); - /* TODO check for NULL */ - /* * Set the not accessed condition code, allow odd sized data, * and set the data transfer type to SETUP. Setup DATA always @@ -555,7 +754,13 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd NULL, NULL); /* allocate the next TD */ - data_td = ohci_get_free_td(dev); /* TODO check for NULL */ + data_td = ohci_get_free_td(dev); + if (!data_td) { + printk("usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev); + ohci_free_td(setup_td); + ohci_free_ed(control_ed); + return -1; + } /* link to the next TD */ setup_td->next_td = virt_to_bus(data_td); @@ -570,48 +775,59 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd NULL, NULL); /* - * XXX we should check that the data buffer doesn't - * cross a 4096 byte boundary. If so, it needs to be - * copied into a single 4096 byte aligned area for the - * OHCI's TD logic to see it all, or multiple TDs need - * to be made for each page. + * TODO: Normal TDs can transfer up to 8192 bytes on OHCI. + * However, for that to happen, the data must -start- + * on a nice 4kb page. We need to check for data + * sizes > 4096 and, if they cross more than two 4096 + * byte pages of memory one or more additional TDs + * will need to be created. (repeat doing this in a + * loop until all of the DATA is on a TD) * - * It's not likely a control transfer will run into - * this problem.. (famous last words) + * Control transfers are -highly unlikely- to need to + * transfer this much data.. but who knows.. sadistic + * hardware is sure to exist. */ status_td = ohci_get_free_td(dev); /* TODO check for NULL */ + if (!status_td) { + printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev); + ohci_free_td(setup_td); + ohci_free_td(data_td); + ohci_free_ed(control_ed); + return -1; + } + data_td->next_td = virt_to_bus(status_td); } else { status_td = data_td; /* no data_td, use it for status */ } - /* The control status packet always uses a DATA1 */ + /* The control status packet always uses a DATA1 + * Give "dev_id" the address of completion_status so that the + * TDs status can be passed back to us from the IRQ. */ ohci_fill_new_td(status_td, td_set_dir_in(usb_pipeout(pipe) | (len == 0)), TOGGLE_DATA1, - 0, - NULL, 0, - NULL, ohci_control_completed); + 0 /* flags */, + NULL /* data */, 0 /* data len */, + &completion_status, ohci_control_completed); status_td->next_td = 0; /* end of TDs */ - /* - * Start the control transaction.. - */ - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&control_wakeup, &wait); - /* * Add the chain of 2-3 control TDs to the control ED's TD list */ - { - unsigned long flags; - spin_lock_irqsave(&ohci_edtd_lock, flags); - ohci_add_td_to_ed(setup_td, control_ed); - spin_unlock_irqrestore(&ohci_edtd_lock, flags); - } + spin_lock_irqsave(&ohci_edtd_lock, flags); + control_ed->status |= OHCI_ED_SKIP; + ohci_add_td_to_ed(setup_td, control_ed); + if (data_td != status_td) + ohci_add_td_to_ed(data_td, control_ed); + ohci_add_td_to_ed(status_td, control_ed); + control_ed->status &= ~OHCI_ED_SKIP; + ohci_unhalt_ed(control_ed); + spin_unlock_irqrestore(&ohci_edtd_lock, flags); -#if 0 +#ifdef OHCI_DEBUG + if (MegaDebug) { /* complete transaction debugging output (before) */ printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed)); show_ohci_ed(control_ed); @@ -623,48 +839,55 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd } printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td)); show_ohci_td(status_td); + printk(KERN_DEBUG " Controller Status:\n"); + show_ohci_status(dev->ohci); + } #endif + /* + * Start the control transaction.. + */ + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + /* Give the ED to the HC */ ohci_add_control_ed(dev->ohci, control_ed); - /* FIXME: - * this should really check to see that the transaction completed. - */ schedule_timeout(HZ/10); remove_wait_queue(&control_wakeup, &wait); -#if 0 +#ifdef OHCI_DEBUG + if (MegaDebug) { /* complete transaction debugging output (after) */ - printk(KERN_DEBUG " (after) Control ED:\n"); + printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed)); show_ohci_ed(control_ed); - printk(KERN_DEBUG " (after) Setup TD:\n"); + printk(KERN_DEBUG " *after* Setup TD %lx:\n", virt_to_bus(setup_td)); show_ohci_td(setup_td); if (data_td != status_td) { - printk(KERN_DEBUG " (after) Data TD:\n"); + printk(KERN_DEBUG " *after* Data TD %lx:\n", virt_to_bus(data_td)); show_ohci_td(data_td); } - printk(KERN_DEBUG " (after) Status TD:\n"); + printk(KERN_DEBUG " *after* Status TD %lx:\n", virt_to_bus(status_td)); show_ohci_td(status_td); + printk(KERN_DEBUG " *after* Controller Status:\n"); + show_ohci_status(dev->ohci); + } #endif - /* clean up incase it failed */ - /* XXX only do this if their ed pointer still points to control_ed - * incase they've been reclaimed and used by something else - * already. -greg */ - ohci_remove_td_from_ed(setup_td, control_ed); - ohci_remove_td_from_ed(data_td, control_ed); - ohci_remove_td_from_ed(status_td, control_ed); - - /* remove the control ED */ + /* clean up */ + ohci_free_td(setup_td); + if (data_td != status_td) + ohci_free_td(data_td); + ohci_free_td(status_td); + /* remove the control ED from the HC */ ohci_remove_control_ed(dev->ohci, control_ed); + ohci_free_ed(control_ed); /* return it to the pool */ #if 0 printk(KERN_DEBUG "leaving ohci_control_msg\n"); #endif - - return ohci_td_result(dev, status_td); + return completion_status; } /* ohci_control_msg() */ @@ -675,6 +898,7 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent) { struct usb_device *usb_dev; struct ohci_device *dev; + int idx; /* * Allocate the generic USB device @@ -696,6 +920,12 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent) memset(dev, 0, sizeof(*dev)); + /* Initialize all EDs in a new device with the skip flag so that + * they are ignored by the controller until set otherwise. */ + for (idx = 0; idx < NUM_EDS; ++idx) { + dev->ed[idx].status |= OHCI_ED_SKIP; + } + /* * Link them together */ @@ -752,10 +982,10 @@ struct usb_operations ohci_device_operations = { */ static int reset_hc(struct ohci *ohci) { - int timeout = 1000; /* prevent an infinite loop */ + int timeout = 10000; /* prevent an infinite loop */ #if 0 - printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci); + printk(KERN_INFO "usb-ohci: resetting HC %p\n", ohci); #endif writel(~0x0, &ohci->regs->intrdisable); /* Disable HC interrupts */ @@ -770,7 +1000,7 @@ static int reset_hc(struct ohci *ohci) udelay(1); } - printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci); + printk(KERN_INFO "usb-ohci: HC %p reset.\n", ohci); return 0; } /* reset_hc() */ @@ -783,6 +1013,7 @@ static int start_hc(struct ohci *ohci) { int ret = 0; int fminterval; + __u32 what_to_enable; fminterval = readl(&ohci->regs->fminterval) & 0x3fff; #if 0 @@ -812,9 +1043,13 @@ static int start_hc(struct ohci *ohci) * useful for debugging and as a bus heartbeat. -greg */ /* Choose the interrupts we care about */ - writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */ - OHCI_INTR_WDH | OHCI_INTR_FNO, - &ohci->regs->intrenable); + what_to_enable = OHCI_INTR_MIE | +#ifdef OHCI_RHSC_INT + OHCI_INTR_RHSC | +#endif + /* | OHCI_INTR_FNO */ + OHCI_INTR_WDH; + writel( what_to_enable, &ohci->regs->intrenable); /* Enter the USB Operational state & start the frames a flowing.. */ writel_set(OHCI_USB_OPER, &ohci->regs->control); @@ -861,7 +1096,7 @@ static void ohci_reset_port(struct ohci *ohci, unsigned int port) /* * Wait for the reset to complete. */ - wait_ms(10); + wait_ms(20); /* check port status to see that the reset completed */ status = readl(&ohci->regs->roothub.portstatus[port]); @@ -886,10 +1121,12 @@ static void ohci_connect_change(struct ohci * ohci, int port) struct usb_device *usb_dev; struct ohci_device *dev; /* memory I/O address of the port status register */ - void *portaddr = &ohci->regs->roothub.portstatus[port]; + __u32 *portaddr = &ohci->regs->roothub.portstatus[port]; int portstatus; - printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port); +#ifdef OHCI_DEBUG + printk(KERN_DEBUG "ohci_connect_change on port %d\n", port); +#endif /* * Because of the status change we have to forget @@ -903,6 +1140,14 @@ static void ohci_connect_change(struct ohci * ohci, int port) /* disable the port if nothing is connected */ if (!(portstatus & PORT_CCS)) { writel(PORT_CCS, portaddr); + /* We need to reset the CSC bit -after- disabling the + * port because it causes the CSC bit to come on + * again... */ + wait_ms(20); + writel(PORT_CSC, portaddr); +#ifdef OHCI_DEBUG + printk(KERN_DEBUG "ohci port %d disabled, nothing connected.\n", port); +#endif return; } @@ -943,15 +1188,18 @@ static void ohci_check_configuration(struct ohci *ohci) struct ohci_regs *regs = ohci->regs; int num = 0; int maxport = readl(&ohci->regs->roothub) & 0xff; + __u32 rh_change_flags = PORT_CSC | PORT_PESC; /* root hub status changes */ -#if 1 +#ifdef OHCI_DEBUG printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci); #endif do { - if (readl(®s->roothub.portstatus[num]) & PORT_CSC) { - /* reset the connect status change bit */ - writel(PORT_CSC, ®s->roothub.portstatus[num]); + __u32 *portstatus_p = ®s->roothub.portstatus[num]; + if (readl(portstatus_p) & rh_change_flags) { + /* acknowledge the root hub status changes */ + writel_set(rh_change_flags, portstatus_p); + /* disable the port if nothing is on it */ /* check the port for a nifty device */ ohci_connect_change(ohci, num); } @@ -977,8 +1225,8 @@ static void ohci_root_hub_events(struct ohci *ohci) int maxport = ohci->root_hub->usb->maxchild; do { - if (readl(&ohci->regs->roothub.portstatus[num]) & - PORT_CSC) { + __u32 *portstatus_p = &ohci->regs->roothub.portstatus[num]; + if (readl(portstatus_p) & PORT_CSC) { if (waitqueue_active(&ohci_configure)) wake_up(&ohci_configure); return; @@ -1037,6 +1285,9 @@ static void ohci_reap_donelist(struct ohci *ohci) while (td != NULL) { struct ohci_td *next_td = td->next_dl_td; + if (td_dummy(*td)) + printk("yikes! reaping a dummy TD\n"); + /* FIXME: munge td->info into a future standard status format */ /* Check if TD should be re-queued */ if ((td->completed != NULL) && @@ -1044,14 +1295,15 @@ static void ohci_reap_donelist(struct ohci *ohci) { /* Mark the TD as active again: * Set the not accessed condition code - * FIXME: should this reset OHCI_TD_ERRCNT? + * Reset the Error count + * [FIXME: report errors to the device's driver] */ td->info |= OHCI_TD_CC_NEW; + clear_td_errorcount(td); /* point it back to the start of the data buffer */ td->cur_buf = virt_to_bus(td->data); - /* XXX disabled for debugging reasons right now.. */ /* insert it back on its ED */ ohci_add_td_to_ed(td, td->ed); } else { @@ -1066,9 +1318,6 @@ static void ohci_reap_donelist(struct ohci *ohci) } /* ohci_reap_donelist() */ -#if 0 -static int in_int = 0; -#endif /* * Get annoyed at the controller for bothering us. * This pretty much follows the OHCI v1.0a spec, section 5.3. @@ -1080,19 +1329,10 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) struct ohci_hcca *hcca = ohci->root_hub->hcca; __u32 status, context; -#if 0 - /* for debugging to keep IRQs from running away. */ - if (in_int >= 2) - return; - ++in_int; - return; -#endif - /* Save the status of the interrupts that are enabled */ status = readl(®s->intrstatus); status &= readl(®s->intrenable); - /* make context = the interrupt status bits that we care about */ if (hcca->donehead != 0) { context = OHCI_INTR_WDH; /* hcca donehead needs processing */ @@ -1122,6 +1362,10 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) context &= ~OHCI_INTR_WDH; /* mark this as checked */ } +#ifdef OHCI_RHSC_INT + /* NOTE: this is very funky on some USB controllers (ie: it + * doesn't work right). Using the ohci_timer instead to poll + * the root hub is a much better choice. */ /* Process any root hub status changes */ if (context & OHCI_INTR_RHSC) { /* Wake the thread to process root hub events */ @@ -1134,10 +1378,17 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) * The control thread will re-enable it after it has * checked the root hub status. */ - } else { - /* check the root hub status anyways. Some controllers - * might not generate the interrupt properly. (?) */ - ohci_root_hub_events(ohci); + } +#endif + + /* Start of Frame interrupts, used during safe ED removal */ + if (context & (OHCI_INTR_SF)) { + writel(OHCI_INTR_SF, ®s->intrstatus); + if (waitqueue_active(&start_of_frame_wakeup)) + wake_up(&start_of_frame_wakeup); + /* Do NOT mark the frame start interrupt as checked + * as we don't want to receive any more of them until + * asked. */ } /* Check those "other" pesky bits */ @@ -1166,8 +1417,8 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) context &= ~OHCI_INTR_OC; /* mark this as checked */ } - /* Mask out any remaining unprocessed interrupts so we don't - * get any more of them. */ + /* Mask out any remaining unprocessed or unmasked interrupts + * so that we don't get any more of them. */ if (context & ~OHCI_INTR_MIE) { writel(context, ®s->intrdisable); } @@ -1275,7 +1526,9 @@ static struct ohci *alloc_ohci(void* mem_base) /* * Initialize the polling table to call interrupts at the - * intended intervals. + * intended intervals. Note that these EDs are just + * placeholders. They have their SKIP bit set and are used as + * list heads to insert real EDs onto. */ dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_1]); for (i = 1; i < NUM_INTS; i++) { @@ -1297,18 +1550,14 @@ static struct ohci *alloc_ohci(void* mem_base) } /* - * Tell the controller where the control and bulk lists are + * Tell the controller where the control and bulk lists are. * The lists start out empty. */ writel(0, &ohci->regs->ed_controlhead); writel(0, &ohci->regs->ed_bulkhead); - /* - writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead); - writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead); - */ -#if 0 - printk(KERN_DEBUG "alloc_ohci(): controller\n"); +#ifdef OHCI_DEBUG + printk(KERN_INFO "alloc_ohci(): controller\n"); show_ohci_status(ohci); #endif @@ -1325,7 +1574,7 @@ static struct ohci *alloc_ohci(void* mem_base) */ static void release_ohci(struct ohci *ohci) { - printk(KERN_DEBUG "entering release_ohci %p\n", ohci); + printk(KERN_INFO "Releasing OHCI controller 0x%p\n", ohci); #ifdef OHCI_TIMER /* stop our timer */ @@ -1378,7 +1627,7 @@ static int ohci_control_thread(void * __ohci) * This thread doesn't need any user-level access, * so get rid of all of our resources.. */ - printk("ohci_control_thread code at %p\n", &ohci_control_thread); + printk(KERN_INFO "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread); exit_mm(current); exit_files(current); exit_fs(current); @@ -1391,7 +1640,7 @@ static int ohci_control_thread(void * __ohci) if (start_hc(ohci) < 0) { printk("usb-ohci: failed to start the controller\n"); release_ohci(ohci); - printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); + printk(KERN_INFO "leaving ohci_control_thread %p\n", __ohci); return 0; } @@ -1405,11 +1654,11 @@ static int ohci_control_thread(void * __ohci) ohci_check_configuration(ohci); /* re-enable root hub status change interrupts. */ -#if 0 +#ifdef OHCI_RHSC_INT writel(OHCI_INTR_RHSC, &ohci->regs->intrenable); #endif - printk(KERN_DEBUG "ohci-control thread sleeping\n"); + printk(KERN_INFO "ohci-control thread sleeping\n"); interruptible_sleep_on(&ohci_configure); #ifdef CONFIG_APM if (apm_resume) { @@ -1431,9 +1680,14 @@ static int ohci_control_thread(void * __ohci) spin_unlock_irq(¤t->sigmask_lock); if(signr == SIGUSR1) { - /* FIXME: have it do a full ed/td queue dump */ + /* TODO: have it do a full ed/td queue dump? */ printk(KERN_DEBUG "OHCI status dump:\n"); show_ohci_status(ohci); + } else if (signr == SIGUSR2) { + /* toggle mega TD/ED debugging output */ + MegaDebug = !MegaDebug; + printk(KERN_DEBUG "usb-ohci: Mega debugging %sabled.\n", + MegaDebug ? "en" : "dis"); } else { /* unknown signal, exit the thread */ break; @@ -1444,7 +1698,7 @@ static int ohci_control_thread(void * __ohci) reset_hc(ohci); release_ohci(ohci); - printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci); + printk(KERN_INFO "ohci-control thread for 0x%p exiting\n", __ohci); return 0; } /* ohci_control_thread() */ @@ -1538,8 +1792,8 @@ static int found_ohci(int irq, void* mem_base) ohci->irq = irq; -#if 0 - printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n"); +#ifdef OHCI_DEBUG + printk(KERN_INFO "usb-ohci: forking ohci-control thread for 0x%p\n", ohci); #endif /* fork off the handler */ @@ -1555,7 +1809,7 @@ static int found_ohci(int irq, void* mem_base) } release_ohci(ohci); -#if 0 +#ifdef OHCI_DEBUG printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base); #endif @@ -1597,6 +1851,11 @@ static int init_ohci(struct pci_dev *dev) } MOD_INC_USE_COUNT; +#ifdef OHCI_DEBUG + printk("usb-ohci: Warning! Gobs of debugging output has been enabled.\n"); + printk(" Check your kern.debug logs for the bulk of it.\n"); +#endif + if (found_ohci(dev->irq, (void *) mem_base) < 0) { MOD_DEC_USE_COUNT; return -1; @@ -1673,5 +1932,6 @@ int ohci_init(void) return retval; } /* ohci_init */ + /* vim:sw=8 */ diff --git a/drivers/usb/ohci.h b/drivers/usb/ohci.h index ce126ce5d903..ca071ee01200 100644 --- a/drivers/usb/ohci.h +++ b/drivers/usb/ohci.h @@ -6,7 +6,7 @@ * * (C) Copyright 1999 Gregory P. Smith * - * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $ + * $Id: ohci.h,v 1.24 1999/05/16 10:18:26 greg Exp $ */ #include @@ -37,7 +37,9 @@ struct ohci_td { struct ohci_td *next_dl_td; /* used during donelist processing */ void *data; /* virt. address of the the buffer */ usb_device_irq completed; /* Completion handler routine */ - int allocated; /* boolean: is this TD allocated? */ + int hcd_flags; /* Flags for the HCD: */ + /* bit0 = boolean: Is this TD allocated? */ + /* bit1 = boolean: Is this a dummy (end of list) TD? */ /* User or Device class driver specific fields */ void *dev_id; /* user defined pointer passed to irq handler */ @@ -59,6 +61,7 @@ struct ohci_td { #define td_force_toggle(b) (((b) | 2) << 24) #define OHCI_TD_ERRCNT (3 << 26) /* error count */ #define td_errorcount(td) (((td).info >> 26) & 3) +#define clear_td_errorcount(td) ((td)->info &= ~(__u32)OHCI_TD_ERRCNT) #define OHCI_TD_CC (0xf << 28) /* condition code */ #define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf) #define OHCI_TD_CC_NEW (OHCI_TD_CC) /* set this on all unaccessed TDs! */ @@ -68,9 +71,16 @@ struct ohci_td { #define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3)) #define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3)) -#define td_allocated(td) ((td).allocated) -#define allocate_td(td) ((td)->allocated = 1) -#define ohci_free_td(td) ((td)->allocated = 0) +/* + * Macros to use the td->hcd_flags field. + */ +#define td_allocated(td) ((td).hcd_flags & 1) +#define allocate_td(td) ((td)->hcd_flags |= 1) +#define ohci_free_td(td) ((td)->hcd_flags &= ~(__u32)1) + +#define td_dummy(td) ((td).hcd_flags & 2) +#define make_dumb_td(td) ((td)->hcd_flags |= 2) +#define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2) /* @@ -114,14 +124,14 @@ struct ohci_ed { #define OHCI_ED_FA (0x7f) -/* NOTE: bits 27-31 of the status dword are reserved for the driver */ +/* NOTE: bits 27-31 of the status dword are reserved for the HCD */ /* * We'll use this status flag for to mark if an ED is in use by the - * driver or not. If the bit is set, it is used. - * - * FIXME: implement this! + * driver or not. If the bit is set, it is being used. */ -#define ED_USED (1 << 31) +#define ED_ALLOCATED (1 << 31) +#define ed_allocated(ed) ((ed).status & ED_ALLOCATED) +#define allocate_ed(ed) ((ed)->status |= ED_ALLOCATED) /* * The HCCA (Host Controller Communications Area) is a 256 byte @@ -187,16 +197,17 @@ struct ohci_device { /* .... */ +/* + * These are the index of the placeholder EDs for the root hub to + * build the interrupt transfer ED tree out of. + */ #define ED_INT_1 0 #define ED_INT_2 1 #define ED_INT_4 2 #define ED_INT_8 3 #define ED_INT_16 4 #define ED_INT_32 5 -#define ED_CONTROL 6 -#define ED_BULK 7 #define ED_ISO ED_INT_1 /* same as 1ms interrupt queue */ -#define ED_FIRST_AVAIL 8 /* first non-reserved ED */ /* * Given a period p in ms, convert it to the closest endpoint @@ -215,7 +226,9 @@ struct ohci_device { * This is the maximum number of root hub ports. I don't think we'll * ever see more than two as that's the space available on an ATX * motherboard's case, but it could happen. The OHCI spec allows for - * up to 15... (which is insane!) + * up to 15... (which is insane given that they each need to supply up + * to 500ma; that would be 7.5 amps!). I have seen a PCI card with 4 + * downstream ports on it. * * Although I suppose several "ports" could be connected directly to * internal laptop devices such as a keyboard, mouse, camera and @@ -259,6 +272,15 @@ struct ohci_regs { } roothub; } __attribute((aligned(32))); +/* + * These are used by internal ED managing functions as a + * parameter to state the type of ED to deal with (when it matters). + */ +#define HCD_ED_ISOC (0) +#define HCD_ED_INT (1) +#define HCD_ED_CONTROL (2) +#define HCD_ED_BULK (3) + /* * Read a MMIO register and re-write it after ANDing with (m) */ @@ -352,9 +374,9 @@ struct ohci { #define OHCI_TIMER /* enable the OHCI timer */ #define OHCI_TIMER_FREQ (234) /* ms between each root hub status check */ -#undef OHCI_RHSC_INT /* don't use root hub status interrupts */ +#undef OHCI_RHSC_INT /* Don't use root hub status interrupts! */ -/* Debugging code */ +/* Debugging code [ohci-debug.c] */ void show_ohci_ed(struct ohci_ed *ed); void show_ohci_td(struct ohci_td *td); void show_ohci_status(struct ohci *ohci); diff --git a/fs/ChangeLog b/fs/ChangeLog index c5d77d4a049f..9d9b0cace370 100644 --- a/fs/ChangeLog +++ b/fs/ChangeLog @@ -144,24 +144,12 @@ Wed Dec 16 06:10:04 1998 AV * rmdir of immutable/append-only directory shouldn't be allowed. Fixed. Remains unfixed: - * UMSDOS_rename is broken. Call it with the dest. existing and being an - empty directory and you've got EBUSY. At least it doesn't do - any harm, so that will wait several days till rename cleanup. - Sigh... It will wait a bit more. Problems with fat-derived - filesystems are much worse than I thought. Idea of changing - inode under dentry is broken by design - guess where the - semaphore sits, for one. - * umsdos: weird. rename() shouldn't return -EEXIST. BTW, manpage - for rename(2) is obviously bogus - it mentions EEXIST and - on the next line (correctly) says that EINVAL should be - returned. Under the same conditions. * rename's handling of races is, erm, not optimal. Looks like I know what to do, but this thing needs some more cleanup - we can take care of almost all races in VFS and be much more graceful wrt locking. Moreover, it would give strong lookup atomicity. But it's a lot of changes to lookup and dcache code, so it will go after the fs drivers' cleanup. - * hfs allows mknod. Only for regular files ;-/ IMHO it's bogus. * affs allows HARD links to directories. VFS is, to put it politely, not too ready to cope with _that_. And I'm not sure it should be - looks like they are pretty much similar to symlinks. @@ -169,8 +157,3 @@ Remains unfixed: braindead filesystems). I've submitted a patch to Linus, but looks like it wasn't applied. * msdos: shouldn't we treat SYS as IMMUTABLE? Makes sense, IMHO. - * minix, qnx and sysv do NOT allow to mkdir sticky directories. - * {minix,sysv}/namei.c (do_{minix,syv}_{rename,unlink}): - Stuff related to retries still needs cleanup/fixing. - Looks like I've found an extremely low-probability race - there... diff --git a/fs/Config.in b/fs/Config.in index 2896b7b5cd7c..43487fb952c8 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -36,7 +36,7 @@ tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' NTFS read-write support (DANGEROUS)' CONFIG_NTFS_RW fi -tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS +tristate 'OS/2 HPFS filesystem support (read/write) (NEW)' CONFIG_HPFS_FS bool '/proc filesystem support' CONFIG_PROC_FS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then # It compiles as a module for testing only. It should not be used diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 48e95180000f..aad5b8f149b4 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -315,7 +315,7 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR); if (error) goto out_iput; - inode->i_mode = S_IFDIR | S_ISVTX | (mode & 0777 & ~current->fs->umask); + inode->i_mode = S_IFDIR | S_ISVTX | mode; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); d_instantiate(dentry,inode); mark_inode_dirty(inode); diff --git a/fs/devices.c b/fs/devices.c index 30db1ace1652..8d9200f8794f 100644 --- a/fs/devices.c +++ b/fs/devices.c @@ -193,7 +193,7 @@ int unregister_blkdev(unsigned int major, const char * name) * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve - * to loose :-) + * to lose :-) */ int check_disk_change(kdev_t dev) { diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 822207251e26..8568f14467e8 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -490,7 +490,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) inode->i_nlink = 2; mark_buffer_dirty(dir_block, 1); brelse (dir_block); - inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); + inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c index d870774228f0..84eacf87d128 100644 --- a/fs/ext2/truncate.c +++ b/fs/ext2/truncate.c @@ -384,7 +384,7 @@ static int trunc_tindirect (struct inode * inode) void ext2_truncate (struct inode * inode) { - int err, offset, retry; + int err, offset; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) @@ -393,7 +393,7 @@ void ext2_truncate (struct inode * inode) return; ext2_discard_prealloc(inode); while (1) { - retry = trunc_direct(inode); + int retry = trunc_direct(inode); retry |= trunc_indirect (inode, EXT2_IND_BLOCK, (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK], diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index 350516fcdbaa..df166fe3085f 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c @@ -228,7 +228,7 @@ void hfs_bnode_lock(struct hfs_bnode_ref *bnr, int lock_type) break; case HFS_LOCK_NONE: - while (bn->lock || witqueue_active(&bn->wqueue)) { + while (bn->lock || waitqueue_active(&bn->wqueue)) { hfs_sleep_on(&bn->rqueue); } ++bn->count; diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index a2d974a8b5aa..a7b0a974a54a 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -647,7 +647,7 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir, */ static inline void start_write(struct hfs_cat_entry *dir) { - if (dir->u.dir.readers || wait_queue_active(&dir->u.dir.read_wait)) { + if (dir->u.dir.readers || waitqueue_active(&dir->u.dir.read_wait)) { hfs_sleep_on(&dir->u.dir.write_wait); } ++dir->u.dir.writers; @@ -658,7 +658,7 @@ static inline void start_write(struct hfs_cat_entry *dir) */ static inline void start_read(struct hfs_cat_entry *dir) { - if (dir->u.dir.writers || wait_queue_active(&dir->u.dir.write_wait)) { + if (dir->u.dir.writers || waitqueue_active(&dir->u.dir.write_wait)) { hfs_sleep_on(&dir->u.dir.read_wait); } ++dir->u.dir.readers; diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c index 3d742c5b81d7..23544fc05da0 100644 --- a/fs/hpfs/alloc.c +++ b/fs/hpfs/alloc.c @@ -307,6 +307,7 @@ int hpfs_check_free_dnodes(struct super_block *s, int n) if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) { for (j = 0; j < 512; j++) { unsigned k; + if (!bmp[j]) continue; for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) { hpfs_brelse4(&qbh); return 0; @@ -327,9 +328,9 @@ int hpfs_check_free_dnodes(struct super_block *s, int n) if (bmp) { for (j = 0; j < 512; j++) { unsigned k; + if (!bmp[j]) continue; for (k = 0xf; k; k <<= 4) if ((bmp[j] & k) == k) { - /*printk("%08x,%08x\n",j,i);*/ if (!--n) { hpfs_brelse4(&qbh); return 0; @@ -372,8 +373,13 @@ struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near, int lock) { struct dnode *d; - if (!(*dno = alloc_in_dirband(s, near, lock))) - if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL; + if (hpfs_count_one_bitmap(s, s->s_hpfs_dmap) > FREE_DNODES_ADD) { + if (!(*dno = alloc_in_dirband(s, near, lock))) + if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL; + } else { + if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) + if (!(*dno = alloc_in_dirband(s, near, lock))) return NULL; + } if (!(d = hpfs_get_4sectors(s, *dno, qbh))) { hpfs_free_dnode(s, *dno); return NULL; diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index 541f4864c7ed..b5c3cf2e8eac 100644 --- a/fs/hpfs/dentry.c +++ b/fs/hpfs/dentry.c @@ -16,14 +16,14 @@ int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) { unsigned long hash; int i; - int l = qstr->len; + unsigned l = qstr->len; if (l == 1) if (qstr->name[0]=='.') goto x; if (l == 2) if (qstr->name[0]=='.' || qstr->name[1]=='.') goto x; - if (hpfs_chk_name((char *)qstr->name,l)) - /*return -ENAMETOOLONG;*/ - return -ENOENT; hpfs_adjust_length((char *)qstr->name, &l); + /*if (hpfs_chk_name((char *)qstr->name,&l))*/ + /*return -ENAMETOOLONG;*/ + /*return -ENOENT;*/ x: hash = init_name_hash(); @@ -36,15 +36,15 @@ int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) { - int al=a->len; - int bl=b->len; + unsigned al=a->len; + unsigned bl=b->len; hpfs_adjust_length((char *)a->name, &al); - hpfs_adjust_length((char *)b->name, &bl); + /*hpfs_adjust_length((char *)b->name, &bl);*/ /* 'a' is the qstr of an already existing dentry, so the name * must be valid. 'b' must be validated first. */ - if (hpfs_chk_name((char *)b->name, bl)) return 1; + if (hpfs_chk_name((char *)b->name, &bl)) return 1; if (hpfs_compare_names(dentry->d_sb, (char *)a->name, al, (char *)b->name, bl, 0)) return 1; return 0; } diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index e1ce7a6c0062..8af35847d7c1 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c @@ -30,8 +30,6 @@ int hpfs_readdir(struct file *filp, void * dirent, filldir_t filldir) char *tempname; int c1, c2 = 0; - if (!inode) return -EBADF; - if (!S_ISDIR(inode->i_mode)) return -EBADF; if (inode->i_sb->s_hpfs_chk) { if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode")) return -EFSERROR; @@ -150,57 +148,30 @@ int hpfs_readdir(struct file *filp, void * dirent, filldir_t filldir) struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; + unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; - struct inode *inode; ino_t ino; - + int err; struct inode *result = NULL; - if (dir == 0) return -ENOENT; - hpfs_adjust_length((char *)name, &len); + + if ((err = hpfs_chk_name((char *)name, &len))) { + if (err == -ENAMETOOLONG) return ERR_PTR(-ENAMETOOLONG); + goto end_add; + } + hpfs_lock_inode(dir); - if (!S_ISDIR(dir->i_mode)) goto bail; /* - * Read in the directory entry. "." is there under the name ^A^A . - * Always read the dir even for . and .. in case we need the dates. - * - * M.P.: No - we can't read '^A^A' for current directory. In some cases - * the information under '^A^A' is incomplete (missing ea_size, bad - * fnode number) - chkdsk ignores such errors and it doesn't seem to - * matter under OS/2. + * '.' and '..' will never be passed here. */ - if (name[0] == '.' && len == 1) { - result = dir; - dir->i_count++; - goto end; - } else if (name[0] == '.' && name[1] == '.' && len == 2) { - struct buffer_head *bh; - struct fnode *fnode; - if (dir->i_ino == dir->i_sb->s_hpfs_root) { - result = dir; - dir->i_count++; - goto end; - } - if (dir->i_hpfs_parent_dir == dir->i_sb->s_hpfs_root) { - result = dir->i_sb->s_root->d_inode; - result->i_count++; - goto end; - } - if (!(fnode = hpfs_map_fnode(dir->i_sb, dir->i_hpfs_parent_dir, &bh))) goto bail; - de = map_fnode_dirent(dir->i_sb, dir->i_hpfs_parent_dir, fnode, &qbh); - brelse(bh); - } else - de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh, NULL); + + de = map_dirent(dir, dir->i_hpfs_dno, (char *) name, len, NULL, &qbh); /* * This is not really a bailout, just means file not found. */ - if (!de) { - result = NULL; - goto end; - } + if (!de) goto end; /* * Get inode number, what we're after. @@ -213,18 +184,18 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) */ hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && dir->i_sb->s_hpfs_eas) ? 1 : 2); - if (!(inode = iget(dir->i_sb, ino))) { + if (!(result = iget(dir->i_sb, ino))) { hpfs_unlock_iget(dir->i_sb); - hpfs_error(inode->i_sb, "hpfs_lookup: can't get inode"); + hpfs_error(result->i_sb, "hpfs_lookup: can't get inode"); goto bail1; } - if (!de->directory) inode->i_hpfs_parent_dir = dir->i_ino; + if (!de->directory) result->i_hpfs_parent_dir = dir->i_ino; hpfs_unlock_iget(dir->i_sb); - hpfs_decide_conv(inode, (char *)name, len); + hpfs_decide_conv(result, (char *)name, len); if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) { - hpfs_error(inode->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); + hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); goto bail1; } @@ -233,24 +204,24 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) * inode. */ - if (!inode->i_ctime) { - if (!(inode->i_ctime = local_to_gmt(dir->i_sb, de->creation_date))) - inode->i_ctime = 1; - inode->i_mtime = local_to_gmt(dir->i_sb, de->write_date); - inode->i_atime = local_to_gmt(dir->i_sb, de->read_date); - inode->i_hpfs_ea_size = de->ea_size; - if (!inode->i_hpfs_ea_mode && de->read_only) - inode->i_mode &= ~0222; + if (!result->i_ctime) { + if (!(result->i_ctime = local_to_gmt(dir->i_sb, de->creation_date))) + result->i_ctime = 1; + result->i_mtime = local_to_gmt(dir->i_sb, de->write_date); + result->i_atime = local_to_gmt(dir->i_sb, de->read_date); + result->i_hpfs_ea_size = de->ea_size; + if (!result->i_hpfs_ea_mode && de->read_only) + result->i_mode &= ~0222; if (!de->directory) { - if (inode->i_size == -1) { - inode->i_size = de->file_size; + if (result->i_size == -1) { + result->i_size = de->file_size; /* * i_blocks should count the fnode and any anodes. * We count 1 for the fnode and don't bother about * anodes -- the disk heads are on the directory band * and we want them to stay there. */ - inode->i_blocks = 1 + ((inode->i_size + 511) >> 9); + result->i_blocks = 1 + ((result->i_size + 511) >> 9); } } } @@ -261,9 +232,9 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) * Made it. */ - result = inode; end: hpfs_unlock_inode(dir); + end_add: hpfs_set_dentry_operations(dentry); d_add(dentry, result); return NULL; @@ -275,7 +246,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) hpfs_brelse4(&qbh); - bail: + /*bail:*/ hpfs_unlock_inode(dir); return ERR_PTR(-ENOENT); diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index a4ab01742b04..e4b4bbc91c96 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c @@ -368,7 +368,6 @@ int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen, struct quad_buffer_head qbh; dnode_secno dno; int c; - int depth = cdepth; int c1, c2 = 0; dno = i->i_hpfs_dno; down: @@ -385,7 +384,6 @@ int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen, if (de->down) { dno = de_down_pointer(de); hpfs_brelse4(&qbh); - depth++; goto down; } break; @@ -393,7 +391,7 @@ int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen, } hpfs_brelse4(&qbh); if (!cdepth) hpfs_lock_creation(i->i_sb); - if (hpfs_check_free_dnodes(i->i_sb, depth + 2)) { + if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) { c = 1; goto ret; } @@ -574,11 +572,6 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) goto end; } - /*{ - static int cnt_t_ = 0; - if (cnt_t_++ & 1) goto endm; - }*/ - if (!de->last) { struct hpfs_dirent *de_next = de_next_de(de); struct hpfs_dirent *de_cp; @@ -607,7 +600,6 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) kfree(de_cp); goto try_it_again; } else { - /*printk("HPFS: warning: not balancing tree\n");*/ struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode); struct hpfs_dirent *de_cp; struct dnode *d1; @@ -692,20 +684,21 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, { struct dnode *dnode = qbh->data; dnode_secno down = 0; + int lock = 0; loff_t t; if (de->first || de->last) { hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno); hpfs_brelse4(qbh); return 1; } - if (de->down) { - if ((down = de_down_pointer(de)) && depth) { - hpfs_lock_creation(i->i_sb); - if (hpfs_check_free_dnodes(i->i_sb, depth + 2)) { - hpfs_brelse4(qbh); - hpfs_unlock_creation(i->i_sb); - return 2; - } + if (de->down) down = de_down_pointer(de); + if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) { + lock = 1; + hpfs_lock_creation(i->i_sb); + if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) { + hpfs_brelse4(qbh); + hpfs_unlock_creation(i->i_sb); + return 2; } } i->i_version = ++event; @@ -716,10 +709,12 @@ int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, if (down) { dnode_secno a = move_to_top(i, down, dno); for_all_poss(i, hpfs_pos_subst, 5, t); - if (depth) hpfs_unlock_creation(i->i_sb); if (a) delete_empty_dnode(i, a); + if (lock) hpfs_unlock_creation(i->i_sb); return !a; - } else delete_empty_dnode(i, dno); + } + delete_empty_dnode(i, dno); + if (lock) hpfs_unlock_creation(i->i_sb); return 0; } @@ -888,15 +883,13 @@ struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp, /* Find a dirent in tree */ struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, char *name, unsigned len, - dnode_secno *dd, struct quad_buffer_head *qbh, int *depth) + dnode_secno *dd, struct quad_buffer_head *qbh) { struct dnode *dnode; struct hpfs_dirent *de; struct hpfs_dirent *de_end; int c1, c2 = 0; - if (depth) *depth = 0; - if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n"); again: if (inode->i_sb->s_hpfs_chk) @@ -914,7 +907,6 @@ struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, char *name, if (de->down) { dno = de_down_pointer(de); hpfs_brelse4(qbh); - if (depth) (*depth)++; goto again; } break; diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 1f1cbb6f2f90..74b5609e0980 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -54,7 +54,6 @@ void hpfs_truncate(struct inode *i) i->i_hpfs_n_secs = 0; hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); i->i_blocks = 1 + ((i->i_size + 511) >> 9); - /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1; hpfs_write_inode(i); } diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 09744ce8ce8b..0a46483709f1 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -42,6 +42,9 @@ #define ANODE_RD_AHEAD 16 #define DNODE_RD_AHEAD 4 +#define FREE_DNODES_ADD 58 +#define FREE_DNODES_DEL 29 + #define CHKCOND(x,y) if (!(x)) printk y #ifdef DBG @@ -237,7 +240,7 @@ int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *); dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno); struct hpfs_dirent *map_pos_dirent(struct inode *, loff_t *, struct quad_buffer_head *); -struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *, int *depth); +struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *); void hpfs_remove_dtree(struct super_block *, dnode_secno); struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct fnode *, struct quad_buffer_head *); @@ -285,7 +288,7 @@ int hpfs_mmap(struct file *, struct vm_area_struct *); /* name.c */ unsigned char hpfs_upcase(unsigned char *, unsigned char); -int hpfs_chk_name(unsigned char *, unsigned); +int hpfs_chk_name(unsigned char *, unsigned *); char *hpfs_translate_name(struct super_block *, unsigned char *, unsigned, int, int); int hpfs_compare_names(struct super_block *, unsigned char *, unsigned, unsigned char *, unsigned, int); int hpfs_is_name_long(unsigned char *, unsigned); @@ -310,5 +313,6 @@ void hpfs_error(struct super_block *, char *, ...); int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); int hpfs_remount_fs(struct super_block *, int *, char *); void hpfs_put_super(struct super_block *); +unsigned hpfs_count_one_bitmap(struct super_block *, secno); int hpfs_statfs(struct super_block *, struct statfs *, int); struct super_block *hpfs_read_super(struct super_block *, void *, int); diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 2ed75db35403..99bfa1004cfd 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -128,6 +128,7 @@ void hpfs_read_inode(struct inode *i) unsigned char *ea; int ea_size; i->i_op = 0; + /*i->i_hpfs_sem = MUTEX;*/ init_MUTEX(&i->i_hpfs_sem); i->i_uid = sb->s_hpfs_uid; i->i_gid = sb->s_hpfs_gid; @@ -199,27 +200,27 @@ void hpfs_read_inode(struct inode *i) return; } if ((ea = hpfs_get_ea(i->i_sb, fnode, "MODE", &ea_size))) { + int rdev = 0; + umode_t mode = sb->s_hpfs_mode; if (ea_size == 2) { - i->i_mode = ea[0] + (ea[1] << 8); + mode = ea[0] + (ea[1] << 8); i->i_hpfs_ea_mode = 1; } kfree(ea); - if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) { + i->i_mode = mode; + if (S_ISBLK(mode) || S_ISCHR(mode)) { if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) { if (ea_size == 4) - i->i_rdev = to_kdev_t(ea[0] + (ea[1] << 8) + (ea[2] << 16) + (ea[3] << 24)); + rdev = ea[0] + (ea[1] << 8) + (ea[2] << 16) + (ea[3] << 24); kfree(ea); } } - if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode) || S_ISFIFO(i->i_mode) || S_ISSOCK(i->i_mode)) { + if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { brelse(bh); i->i_nlink = 1; i->i_size = 0; i->i_blocks = 1; - i->i_op = NULL; - if (S_ISBLK(i->i_mode)) i->i_op = (struct inode_operations *) &blkdev_inode_operations; - if (S_ISCHR(i->i_mode)) i->i_op = (struct inode_operations *) &chrdev_inode_operations; - if (S_ISFIFO(i->i_mode)) init_fifo(i); + init_special_inode(i, mode, rdev); return; } } @@ -341,7 +342,7 @@ void hpfs_write_inode_nolock(struct inode *i) hpfs_brelse4(&qbh); } if (S_ISDIR(i->i_mode)) { - if ((de = map_dirent(i, i->i_hpfs_dno, "\001\001", 2, NULL, &qbh, NULL))) { + if ((de = map_dirent(i, i->i_hpfs_dno, "\001\001", 2, NULL, &qbh))) { de->write_date = gmt_to_local(i->i_sb, i->i_mtime); de->read_date = gmt_to_local(i->i_sb, i->i_atime); de->creation_date = gmt_to_local(i->i_sb, i->i_ctime); diff --git a/fs/hpfs/name.c b/fs/hpfs/name.c index 3723c62635c1..865ebcab6f89 100644 --- a/fs/hpfs/name.c +++ b/fs/hpfs/name.c @@ -70,13 +70,15 @@ static inline unsigned char locase(unsigned char *dir, unsigned char a) return dir[a]; } -int hpfs_chk_name(unsigned char *name, unsigned len) +int hpfs_chk_name(unsigned char *name, unsigned *len) { int i; - if (!len || len > 254) return 1; - for (i = 0; i < len; i++) if (not_allowed_char(name[i])) return 1; - if (len == 1) if (name[0] == '.') return 1; - if (len == 2) if (name[0] == '.' && name[1] == '.') return 1; + if (*len > 254) return -ENAMETOOLONG; + hpfs_adjust_length(name, len); + if (!*len) return -EINVAL; + for (i = 0; i < *len; i++) if (not_allowed_char(name[i])) return -EINVAL; + if (*len == 1) if (name[0] == '.') return -EINVAL; + if (*len == 2) if (name[0] == '.' && name[1] == '.') return -EINVAL; return 0; } @@ -101,7 +103,7 @@ char *hpfs_translate_name(struct super_block *s, unsigned char *from, } int hpfs_compare_names(struct super_block *s, unsigned char *n1, unsigned l1, - unsigned char *n2, unsigned l2, int last) + unsigned char *n2, unsigned l2, int last) { unsigned l = l1 < l2 ? l1 : l2; unsigned i; diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 03aa36b9623d..5e4d7c9f441a 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -11,7 +11,7 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; + unsigned len = dentry->d_name.len; struct quad_buffer_head qbh0; struct buffer_head *bh; struct hpfs_dirent *de; @@ -22,14 +22,8 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) dnode_secno dno; int r; struct hpfs_dirent dee; - if (!dir) return -ENOENT; - if (!S_ISDIR(dir->i_mode)) { - return -ENOTDIR; - } - hpfs_adjust_length((char *)name, &len); - if (hpfs_chk_name((char *)name, len)) { - return -ENAMETOOLONG; - } + int err; + if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail; if (!(dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1))) goto bail1; memset(&dee, 0, sizeof dee); @@ -105,25 +99,15 @@ int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) int hpfs_create(struct inode *dir, struct dentry *dentry, int mode) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; - struct inode *result; + unsigned len = dentry->d_name.len; + struct inode *result = NULL; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; - result = NULL; - if (!dir) return -ENOENT; - if (!S_ISDIR(dir->i_mode)) { - return -ENOTDIR; - } - if (!S_ISREG(mode)) { - return -EINVAL; - } - hpfs_adjust_length((char *)name, &len); - if (hpfs_chk_name((char *)name, len)) { - return -ENAMETOOLONG; - } + int err; + if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; @@ -178,28 +162,16 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode) int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; + unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result = NULL; - if (!dir) return -ENOENT; - if (dir->i_sb->s_hpfs_eas < 2) { - /*iput(dir);*/ - return -EPERM; - } - if (!S_ISDIR(dir->i_mode)) { - return -ENOTDIR; - } - if (!S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) && !S_ISSOCK(mode)) { - return -EINVAL; - } - hpfs_adjust_length((char *)name, &len); - if (hpfs_chk_name((char *)name, len)) { - return -ENAMETOOLONG; - } + int err; + if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; + if (dir->i_sb->s_hpfs_eas < 2) return -EPERM; if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail; memset(&dee, 0, sizeof dee); if (!(mode & 0222)) dee.read_only = 1; @@ -227,17 +199,12 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) result->i_hpfs_ea_size = 0; /*if (result->i_blocks == -1) result->i_blocks = 1; if (result->i_size == -1) result->i_size = 0;*/ - result->i_mode = mode; result->i_uid = current->fsuid; result->i_gid = current->fsgid; - if (!S_ISFIFO(mode)) result->i_rdev = to_kdev_t(rdev); result->i_nlink = 1; result->i_size = 0; result->i_blocks = 1; - result->i_op = NULL; - if (S_ISBLK(result->i_mode)) result->i_op = (struct inode_operations *) &blkdev_inode_operations; - if (S_ISCHR(result->i_mode)) result->i_op = (struct inode_operations *) &chrdev_inode_operations; - if (S_ISFIFO(result->i_mode)) init_fifo(result); + init_special_inode(result, mode, rdev); hpfs_write_inode_nolock(result); d_instantiate(dentry, result); } @@ -258,24 +225,16 @@ extern const struct inode_operations hpfs_symlink_iops; int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; + unsigned len = dentry->d_name.len; struct buffer_head *bh; struct fnode *fnode; fnode_secno fno; int r; struct hpfs_dirent dee; struct inode *result; - if (!dir) return -ENOENT; - if (dir->i_sb->s_hpfs_eas < 2) { - return -EPERM; - } - if (!S_ISDIR(dir->i_mode)) { - return -ENOTDIR; - } - hpfs_adjust_length((char *)name, &len); - if (hpfs_chk_name((char *)name, len)) { - return -ENAMETOOLONG; - } + int err; + if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; + if (dir->i_sb->s_hpfs_eas < 2) return -EPERM; if (!(fnode = hpfs_alloc_fnode(dir->i_sb, dir->i_hpfs_dno, &fno, &bh))) goto bail; memset(&dee, 0, sizeof dee); dee.archive = 1; @@ -331,16 +290,18 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) int hpfs_unlink(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; + unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; fnode_secno fno; - int depth, r; + int r; + int rep = 0; hpfs_adjust_length((char *)name, &len); + again: hpfs_lock_2inodes(dir, inode); - if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh, &depth))) { + if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) { hpfs_unlock_2inodes(dir, inode); return -ENOENT; } @@ -355,29 +316,49 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry) return -EISDIR; } fno = de->fnode; - if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, depth)) == 1) hpfs_error(dir->i_sb, "there was error when removing dirent"); + if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, 1)) == 1) hpfs_error(dir->i_sb, "there was error when removing dirent"); if (r != 2) { inode->i_nlink--; hpfs_unlock_2inodes(dir, inode); d_delete(dentry); - } else hpfs_unlock_2inodes(dir, inode); + } else { /* no space for deleting, try to truncate file */ + struct iattr newattrs; + hpfs_unlock_2inodes(dir, inode); + if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret; + /*printk("HPFS: truncating file before delete.\n");*/ + down(&inode->i_sem); /* do_truncate should be called here, but it's */ + newattrs.ia_size = 0; /* not exported */ + newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + if (notify_change(dentry, &newattrs)) { + up(&inode->i_sem); + put_write_access(inode); + goto ret; + } + vmtruncate(inode, 0); + if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); + up(&inode->i_sem); + put_write_access(inode); + rep = 1; + goto again; + } + ret: return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; } int hpfs_rmdir(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; - int len = dentry->d_name.len; + unsigned len = dentry->d_name.len; struct quad_buffer_head qbh; struct hpfs_dirent *de; struct inode *inode = dentry->d_inode; dnode_secno dno; fnode_secno fno; int n_items = 0; - int depth, r; + int r; hpfs_adjust_length((char *)name, &len); hpfs_lock_2inodes(dir, inode); - if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh, &depth))) { + if (!(de = map_dirent(dir, dir->i_hpfs_dno, (char *)name, len, &dno, &qbh))) { hpfs_unlock_2inodes(dir, inode); return -ENOENT; } @@ -391,8 +372,6 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry) hpfs_unlock_2inodes(dir, inode); return -ENOTDIR; } - /*shrink_dcache_parent(dentry); - if (dentry->d_count > 1) {*/ if (!list_empty(&dentry->d_hash)) { hpfs_brelse4(&qbh); hpfs_unlock_2inodes(dir, inode); @@ -405,7 +384,7 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry) return -ENOTEMPTY; } fno = de->fnode; - if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, depth)) == 1) + if ((r = hpfs_remove_dirent(dir, dno, de, &qbh, 1)) == 1) hpfs_error(dir->i_sb, "there was error when removing dirent"); if (r != 2) { dir->i_nlink--; @@ -445,7 +424,7 @@ struct dentry *hpfs_follow_link(struct dentry *dinode, struct dentry *ddir, { struct inode *inode = dinode->d_inode; char *link; - int len; + unsigned len; struct buffer_head *bh; struct fnode *fnode; if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) { @@ -471,40 +450,29 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, int old_len = old_dentry->d_name.len; char *new_name = (char *)new_dentry->d_name.name; int new_len = new_dentry->d_name.len; - struct inode *i; + struct inode *i = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct quad_buffer_head qbh, qbh1; struct hpfs_dirent *dep, *nde; struct hpfs_dirent de; dnode_secno dno; - int depth, r; - int err = 0; + int r; struct buffer_head *bh; struct fnode *fnode; + int err; + if ((err = hpfs_chk_name((char *)new_name, &new_len))) return err; + err = 0; hpfs_adjust_length((char *)old_name, &old_len); - hpfs_adjust_length((char *)new_name, &new_len); - if (hpfs_chk_name((char *)new_name, new_len) || hpfs_chk_name((char *)old_name, old_len)) { - err = -ENAMETOOLONG; - goto end2; - } - if (!(i = old_dentry->d_inode)) { - hpfs_error(old_dir->i_sb, "hpfs_rename: grrr, could not get inode"); - err = -ENOENT; - goto end2; - } - if (i->i_sb != old_dir->i_sb || i->i_sb != new_dir->i_sb) { - err = -EINVAL; /* Do not allow to move mount points */ - goto end1_; - } hpfs_lock_3inodes(old_dir, new_dir, i); - if (is_subdir(new_dentry, old_dentry) || (new_inode && S_ISDIR(new_inode->i_mode))) { + /* Erm? Moving over the empty non-busy directory is perfectly legal */ + if (new_inode && S_ISDIR(new_inode->i_mode)) { err = -EINVAL; goto end1; } - if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh, &depth))) { + if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) { hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); err = -ENOENT; goto end1; @@ -514,10 +482,10 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_inode) { hpfs_brelse4(&qbh); - if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1, NULL))) { + if ((nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) { int r; - if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, depth)) != 2) { - if (!(nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1, NULL))) { + if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { + if (!(nde = map_dirent(new_dir, new_dir->i_hpfs_dno, (char *)new_name, new_len, NULL, &qbh1))) { hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent #2"); goto end1; } @@ -539,7 +507,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (new_dir == old_dir) hpfs_brelse4(&qbh); hpfs_lock_creation(i->i_sb); - if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, depth + 2))) { + if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) { hpfs_unlock_creation(i->i_sb); if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); err = r == 1 ? -ENOSPC : -EFSERROR; @@ -548,7 +516,7 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, } if (new_dir == old_dir) - if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh, &depth))) { + if (!(dep = map_dirent(old_dir, old_dir->i_hpfs_dno, (char *)old_name, old_len, &dno, &qbh))) { hpfs_unlock_creation(i->i_sb); hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); err = -ENOENT; @@ -577,12 +545,9 @@ int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, mark_buffer_dirty(bh, 1); brelse(bh); } - d_move(old_dentry, new_dentry); i->i_hpfs_conv = i->i_sb->s_hpfs_conv; hpfs_decide_conv(i, (char *)new_name, new_len); end1: hpfs_unlock_3inodes(old_dir, new_dir, i); - end1_: - end2: return err; } diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 9377a0ae2bd8..0c8c14060c09 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -105,7 +105,7 @@ void hpfs_put_super(struct super_block *s) MOD_DEC_USE_COUNT; } -static unsigned count_one_bitmap(struct super_block *s, secno secno) +unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) { struct quad_buffer_head qbh; unsigned *bits; @@ -114,6 +114,7 @@ static unsigned count_one_bitmap(struct super_block *s, secno secno) count = 0; for (i = 0; i < 2048 / sizeof(unsigned); i++) { unsigned b; + if (!bits[i]) continue; for (b = bits[i]; b; b>>=1) count += b & 1; } hpfs_brelse4(&qbh); @@ -126,7 +127,7 @@ static unsigned count_bitmaps(struct super_block *s) n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14; count = 0; for (n = 0; n < n_bands; n++) - count += count_one_bitmap(s, s->s_hpfs_bmp_dir[n]); + count += hpfs_count_one_bitmap(s, s->s_hpfs_bmp_dir[n]); return count; } @@ -135,7 +136,7 @@ int hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz) struct statfs tmp; /*if (s->s_hpfs_n_free == -1) {*/ s->s_hpfs_n_free = count_bitmaps(s); - s->s_hpfs_n_free_dnodes = count_one_bitmap(s, s->s_hpfs_dmap); + s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap); /*}*/ tmp.f_type = s->s_magic; tmp.f_bsize = 512; @@ -379,7 +380,8 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options, s->s_hpfs_cp_table = NULL; s->s_hpfs_creation_de_lock = s->s_hpfs_rd_inode = 0; - s->s_hpfs_creation_de = s->s_hpfs_iget_q = NULL; + init_waitqueue_head(&s->s_hpfs_creation_de); + init_waitqueue_head(&s->s_hpfs_iget_q); uid = current->uid; gid = current->gid; @@ -540,7 +542,7 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options, root_dno = hpfs_fnode_dno(s, s->s_hpfs_root); if (root_dno) - de = map_dirent(s->s_root->d_inode, root_dno, "\001\001", 2, NULL, &qbh, NULL); + de = map_dirent(s->s_root->d_inode, root_dno, "\001\001", 2, NULL, &qbh); if (!root_dno || !de) hpfs_error(s, "unable to find root dir"); else { s->s_root->d_inode->i_atime = local_to_gmt(s, de->read_date); diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 0af91237a69d..4afc790d7a89 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -297,7 +297,7 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) inode->i_nlink = 2; mark_buffer_dirty(dir_block, 1); brelse(dir_block); - inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); + inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); diff --git a/fs/namei.c b/fs/namei.c index 93df6705cbc6..9769ce1bb229 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -882,10 +882,6 @@ out: return error; } -/* - * Look out: this function may change a normal dentry - * into a directory dentry (different size).. - */ static inline int do_mkdir(const char * pathname, int mode) { int error; @@ -919,7 +915,7 @@ static inline int do_mkdir(const char * pathname, int mode) goto exit_lock; DQUOT_INIT(dir->d_inode); - mode &= 0777 & ~current->fs->umask; + mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; error = dir->d_inode->i_op->mkdir(dir->d_inode, dentry, mode); exit_lock: diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4ef61fe45fe7..582b1854f3c5 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -691,6 +691,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, break; case S_IFDIR: opfunc = (nfsd_dirop_t) dirp->i_op->mkdir; + /* Odd, indeed, but filesystems did it anyway */ + iap->ia_mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; break; case S_IFCHR: case S_IFBLK: diff --git a/fs/super.c b/fs/super.c index e9454389743b..8892b35912b5 100644 --- a/fs/super.c +++ b/fs/super.c @@ -846,7 +846,8 @@ int fs_may_mount(kdev_t dev) * Anyone using this new feature must know what he/she is doing. */ -int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data) +int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, + const char * type, int flags, void * data) { struct dentry * dir_d; struct super_block * sb; diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index d025cbc85031..e27ac8d838ff 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -291,7 +291,7 @@ int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) inode->i_nlink = 2; mark_buffer_dirty(dir_block, 1); brelse(dir_block); - inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); + inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 46c9f8e53b22..278f8826aa99 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -539,7 +539,7 @@ int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) inode->i_nlink = 2; mark_buffer_dirty(dir_block, 1); brelse (dir_block); - inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); + inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); diff --git a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h index 4e47d4434902..a5fa79ee9dc2 100644 --- a/include/asm-alpha/processor.h +++ b/include/asm-alpha/processor.h @@ -85,7 +85,7 @@ struct thread_struct { * is the frame pointer in schedule() and $15 is saved at offset 48 by * entry.S:do_switch_stack). * - * Under heavy swap load I've seen this loose in an ugly way. So do + * Under heavy swap load I've seen this lose in an ugly way. So do * some extra sanity checking on the ranges we expect these pointers * to be in so that we can fail gracefully. This is just for ps after * all. -- r~ diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h index 698ce18211a8..b7515c0291cd 100644 --- a/include/asm-alpha/semaphore.h +++ b/include/asm-alpha/semaphore.h @@ -16,7 +16,7 @@ struct semaphore { /* Careful, inline assembly knows about the position of these two. */ atomic_t count; atomic_t waking; /* biased by -1 */ - struct wait_queue *wait; + wait_queue_head_t wait; }; #define MUTEX ((struct semaphore) \ diff --git a/include/asm-arm/semaphore.h b/include/asm-arm/semaphore.h index 1a3db3ee2ed5..05456d7dee81 100644 --- a/include/asm-arm/semaphore.h +++ b/include/asm-arm/semaphore.h @@ -10,7 +10,7 @@ struct semaphore { atomic_t count; int waking; - struct wait_queue * wait; + wait_queue_head_t wait; }; #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL }) diff --git a/include/asm-m68k/adb_mouse.h b/include/asm-m68k/adb_mouse.h index 824113662401..6918c8302669 100644 --- a/include/asm-m68k/adb_mouse.h +++ b/include/asm-m68k/adb_mouse.h @@ -16,7 +16,7 @@ struct mouse_status { short dy; int ready; int active; - struct wait_queue *wait; + wait_queue_head_t wait; struct fasync_struct *fasyncptr; }; diff --git a/include/asm-m68k/atari_joystick.h b/include/asm-m68k/atari_joystick.h index bdea2f486190..93be7da9f2c7 100644 --- a/include/asm-m68k/atari_joystick.h +++ b/include/asm-m68k/atari_joystick.h @@ -16,7 +16,7 @@ struct joystick_status { char dir; int ready; int active; - struct wait_queue *wait; + wait_queue_head_t wait; }; #endif diff --git a/include/asm-m68k/mac_mouse.h b/include/asm-m68k/mac_mouse.h index 228c14d0d839..39a5c292eaee 100644 --- a/include/asm-m68k/mac_mouse.h +++ b/include/asm-m68k/mac_mouse.h @@ -16,7 +16,7 @@ struct mouse_status { short dy; int ready; int active; - struct wait_queue *wait; + wait_queue_head_t wait; struct fasync_struct *fasyncptr; }; diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h index 787c273a723a..e1bdb10f44c2 100644 --- a/include/asm-m68k/semaphore.h +++ b/include/asm-m68k/semaphore.h @@ -18,7 +18,7 @@ struct semaphore { atomic_t count; atomic_t waking; - struct wait_queue * wait; + wait_queue_head_t wait; }; #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h index d23fd5614832..acfa8dbc1bfa 100644 --- a/include/asm-mips/semaphore.h +++ b/include/asm-mips/semaphore.h @@ -17,7 +17,7 @@ struct semaphore { atomic_t count; atomic_t waking; - struct wait_queue * wait; + wait_queue_head_t wait; }; #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) diff --git a/include/asm-ppc/adb_mouse.h b/include/asm-ppc/adb_mouse.h index 879178043d2a..3da07c813e99 100644 --- a/include/asm-ppc/adb_mouse.h +++ b/include/asm-ppc/adb_mouse.h @@ -16,7 +16,7 @@ struct mouse_status { short dy; int ready; int active; - struct wait_queue *wait; + wait_queue_head_t wait; struct fasync_struct *fasyncptr; }; diff --git a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h index ab21c33a6356..6a682caa637e 100644 --- a/include/asm-ppc/semaphore.h +++ b/include/asm-ppc/semaphore.h @@ -13,7 +13,7 @@ struct semaphore { atomic_t count; atomic_t waking; - struct wait_queue *wait; + wait_queue_head_t wait; }; #define sema_init(sem, val) atomic_set(&((sem)->count), (val)) diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h index 80596ffcb84d..6e2b32c5add8 100644 --- a/include/asm-sparc/io.h +++ b/include/asm-sparc/io.h @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.18 1998/09/21 05:07:17 jj Exp $ */ +/* $Id: io.h,v 1.19 1999/05/14 07:26:09 davem Exp $ */ #ifndef __SPARC_IO_H #define __SPARC_IO_H diff --git a/include/asm-sparc64/hdreg.h b/include/asm-sparc64/hdreg.h index 06885e3ce73c..29b7cfe6dd05 100644 --- a/include/asm-sparc64/hdreg.h +++ b/include/asm-sparc64/hdreg.h @@ -1,4 +1,4 @@ -/* $Id: hdreg.h,v 1.9 1998/05/08 21:05:28 davem Exp $ +/* $Id: hdreg.h,v 1.1 1999/05/14 07:23:13 davem Exp $ * hdreg.h: Ultra/PCI specific IDE glue. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h index 6666e97376ba..c8db43d59c6f 100644 --- a/include/asm-sparc64/ide.h +++ b/include/asm-sparc64/ide.h @@ -1,4 +1,4 @@ -/* $Id: ide.h,v 1.12 1999/04/17 14:25:29 davem Exp $ +/* $Id: ide.h,v 1.14 1999/05/15 05:02:35 davem Exp $ * ide.h: Ultra/PCI specific IDE glue. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,8 @@ #ifdef __KERNEL__ #include +#include +#include #undef MAX_HWIFS #define MAX_HWIFS 2 diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index 3af29e5fd6da..c80345840154 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.19 1998/08/23 05:41:46 ecd Exp $ */ +/* $Id: io.h,v 1.20 1999/05/14 07:23:18 davem Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H diff --git a/include/linux/blk.h b/include/linux/blk.h index e0d904fc16c7..3974bc23b802 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -85,12 +85,6 @@ void initrd_init(void); #endif -#define RO_IOCTLS(dev,where) \ - case BLKROSET: { int __val; if (!capable(CAP_SYS_ADMIN)) return -EACCES; \ - if (get_user(__val, (int *)(where))) return -EFAULT; \ - set_device_ro((dev),__val); return 0; } \ - case BLKROGET: { int __val = (is_read_only(dev) != 0) ; \ - return put_user(__val,(int *) (where)); } #if defined(MAJOR_NR) || defined(IDE_DRIVER) diff --git a/include/linux/blkpg.h b/include/linux/blkpg.h new file mode 100644 index 000000000000..dd4283a609cd --- /dev/null +++ b/include/linux/blkpg.h @@ -0,0 +1,64 @@ +#ifndef _LINUX_BLKPG_H +#define _LINUX_BLKPG_H + +/* + * Partition table and disk geometry handling + * + * A single ioctl with lots of subfunctions: + * + * Device number stuff: + * get_whole_disk() (given the device number of a partition, + * find the device number of the encompassing disk) + * get_all_partitions() (given the device number of a disk, return the + * device numbers of all its known partitions) + * + * Partition stuff: + * add_partition() + * delete_partition() + * test_partition_in_use() (also for test_disk_in_use) + * + * Geometry stuff: + * get_geometry() + * set_geometry() + * get_bios_drivedata() + * + * For today, only the partition stuff - aeb, 990515 + */ +#include + +#define BLKPG _IO(0x12,105) + +/* The argument structure */ +struct blkpg_ioctl_arg { + int op; + int flags; + int datalen; + void *data; +} *p; + +/* The subfunctions (for the op field) */ +#define BLKPG_ADD_PARTITION 1 +#define BLKPG_DEL_PARTITION 2 + +/* Sizes of name fields. Unused at present. */ +#define BLKPG_DEVNAMELTH 64 +#define BLKPG_VOLNAMELTH 64 + +/* The data structure for ADD_PARTITION and DEL_PARTITION */ +struct blkpg_partition { + long long start; /* starting offset in bytes */ + long long length; /* length in bytes */ + int pno; /* partition number */ + char devname[BLKPG_DEVNAMELTH]; /* partition name, like sda5 or c0d1p2, + to be used in kernel messages */ + char volname[BLKPG_VOLNAMELTH]; /* volume label */ +}; + +#ifdef __KERNEL__ + +extern char * partition_name(kdev_t dev); +extern int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_BLKPG_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 34494a2a2de2..b2e0b3125b4f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -140,6 +140,7 @@ extern int max_super_blocks, nr_super_blocks; #define IS_NOATIME(inode) __IS_FLG(inode, MS_NOATIME) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) + /* the read-only stuff doesn't really belong here, but any other place is probably as bad and I don't want to create yet another include file. */ @@ -154,7 +155,13 @@ extern int max_super_blocks, nr_super_blocks; #define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */ #define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */ #define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */ -#define BLKSSZGET _IO(0x12,104)/* get block device sector size (reserved for) */ +#define BLKSSZGET _IO(0x12,104)/* get block device sector size */ +#if 0 +#define BLKPG _IO(0x12,105)/* See blkpg.h */ +/* This was here just to show that the number is taken - + probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ +#endif + #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ @@ -725,7 +732,6 @@ extern char * cdevname(kdev_t dev); extern char * kdevname(kdev_t dev); extern void init_special_inode(struct inode *, umode_t, int); - extern void init_fifo(struct inode * inode); extern struct inode_operations fifo_inode_operations; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index f8e8e7d45ea6..85bbf34220e3 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -39,7 +39,7 @@ #endif #define DM6_PARTITION 0x54 /* has DDO: use xlated geom & offset */ -#define EZD_PARTITION 0x55 /* EZ-DRIVE: same as DM6 (we think) */ +#define EZD_PARTITION 0x55 /* EZ-DRIVE */ #define DM6_AUX1PARTITION 0x51 /* no DDO: use xlated geom */ #define DM6_AUX3PARTITION 0x53 /* no DDO: use xlated geom */ @@ -70,8 +70,8 @@ struct gendisk { int max_nr; /* maximum number of real devices */ void (*init)(struct gendisk *); /* Initialization called before we do our thing */ - struct hd_struct *part; /* partition table */ - int *sizes; /* device size in blocks, copied to blk_size[] */ + struct hd_struct *part; /* [indexed by minor] */ + int *sizes; /* [idem], device size in blocks */ int nr_real; /* number of real devices */ void *real_devices; /* internal use */ @@ -226,14 +226,12 @@ struct unixware_disklabel { #endif /* CONFIG_UNIXWARE_DISKLABEL */ +#ifdef __KERNEL__ extern struct gendisk *gendisk_head; /* linked list of disks */ -/* - * disk_name() is used by genhd.c and md.c. - * It formats the devicename of the indicated disk - * into the supplied buffer, and returns a pointer - * to that same buffer (for convenience). - */ char *disk_name (struct gendisk *hd, int minor, char *buf); +int get_hardsect_size(kdev_t dev); +#endif + #endif diff --git a/include/linux/hpfs_fs_sb.h b/include/linux/hpfs_fs_sb.h index de6aa36087a6..9059054cf82d 100644 --- a/include/linux/hpfs_fs_sb.h +++ b/include/linux/hpfs_fs_sb.h @@ -24,13 +24,13 @@ struct hpfs_sb_info { unsigned sb_rd_inode : 2; /* lookup tells read_inode: 1-read fnode 2-don't read fnode, file 3-don't read fnode, direcotry */ - struct wait_queue *sb_iget_q; + wait_queue_head_t sb_iget_q; unsigned char *sb_cp_table; /* code page tables: */ /* 128 bytes uppercasing table & */ /* 128 bytes lowercasing table */ unsigned *sb_bmp_dir; /* main bitmap directory */ unsigned sb_c_bitmap; /* current bitmap */ - struct wait_queue *sb_creation_de;/* when creating dirents, nobody else + wait_queue_head_t sb_creation_de;/* when creating dirents, nobody else can alloc blocks */ unsigned sb_creation_de_lock : 1; /*unsigned sb_mounting : 1;*/ @@ -55,7 +55,7 @@ struct hpfs_sb_info { #define s_hpfs_chk u.hpfs_sb.sb_chk #define s_hpfs_was_error u.hpfs_sb.sb_was_error #define s_hpfs_chkdsk u.hpfs_sb.sb_chkdsk -#define s_hpfs_rd_fnode u.hpfs_sb.sb_rd_fnode +/*#define s_hpfs_rd_fnode u.hpfs_sb.sb_rd_fnode*/ #define s_hpfs_rd_inode u.hpfs_sb.sb_rd_inode #define s_hpfs_cp_table u.hpfs_sb.sb_cp_table #define s_hpfs_bmp_dir u.hpfs_sb.sb_bmp_dir diff --git a/include/linux/istallion.h b/include/linux/istallion.h index 269ef88ba166..cc9831b44f39 100644 --- a/include/linux/istallion.h +++ b/include/linux/istallion.h @@ -70,9 +70,9 @@ typedef struct { long pgrp; unsigned int rxmarkmsk; struct tty_struct *tty; - struct wait_queue *open_wait; - struct wait_queue *close_wait; - struct wait_queue *raw_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t raw_wait; struct tq_struct tqhangup; struct termios normaltermios; struct termios callouttermios; diff --git a/include/linux/lp_m68k.h b/include/linux/lp_m68k.h index cddecc98d052..22bdc5ce23d9 100644 --- a/include/linux/lp_m68k.h +++ b/include/linux/lp_m68k.h @@ -116,7 +116,7 @@ struct lp_struct { unsigned int chars; /*busy timeout */ unsigned int time; /*wait time */ unsigned int wait; - struct wait_queue *lp_wait_q; /*strobe wait */ + struct wait_queue_head_t lp_wait_q; /*strobe wait */ void *base; /* hardware drivers internal use*/ enum lp_type type; char lp_buffer[LP_BUFFER_SIZE]; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 18e7fde28694..f2ef43b29349 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -405,7 +405,7 @@ extern __inline__ void dev_unlock_list(void) extern __inline__ void dev_lock_wait(void) { while (atomic_read(&dev_lockct)) { - current->counter = 0; + current->policy |= SCHED_YIELD; schedule(); } } diff --git a/include/linux/parport.h b/include/linux/parport.h index d324c317bb93..493cd11270c2 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -184,6 +184,7 @@ struct parport_dir { /* A parallel port */ struct parport { unsigned long base; /* base address */ + unsigned long base_hi; /* base address (ECR) */ unsigned int size; /* IO extent */ const char *name; int irq; /* interrupt (or -1 for none) */ diff --git a/include/linux/parport_pc.h b/include/linux/parport_pc.h index a74c7a12162b..cf93bb008957 100644 --- a/include/linux/parport_pc.h +++ b/include/linux/parport_pc.h @@ -5,14 +5,14 @@ /* --- register definitions ------------------------------- */ -#define ECONTROL 0x402 -#define CONFIGB 0x401 -#define CONFIGA 0x400 -#define EPPDATA 0x4 -#define EPPADDR 0x3 -#define CONTROL 0x2 -#define STATUS 0x1 -#define DATA 0 +#define ECONTROL(p) ((p)->base_hi + 0x02) +#define CONFIGB(p) ((p)->base_hi + 0x01) +#define CONFIGA(p) ((p)->base_hi + 0x00) +#define EPPDATA(p) ((p)->base + 0x04) +#define EPPADDR(p) ((p)->base + 0x03) +#define CONTROL(p) ((p)->base + 0x02) +#define STATUS(p) ((p)->base + 0x01) +#define DATA(p) ((p)->base + 0x00) /* Private data for PC low-level driver. */ struct parport_pc_private { @@ -26,27 +26,27 @@ extern volatile unsigned char parport_pc_ctr; extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d) { - outb(d, p->base+EPPDATA); + outb(d, EPPDATA(p)); } extern __inline__ unsigned char parport_pc_read_epp(struct parport *p) { - return inb(p->base+EPPDATA); + return inb(EPPDATA(p)); } extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d) { - outb(d, p->base+EPPADDR); + outb(d, EPPADDR(p)); } extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p) { - return inb(p->base+EPPADDR); + return inb(EPPADDR(p)); } extern __inline__ int parport_pc_check_epp_timeout(struct parport *p) { - if (!(inb(p->base+STATUS) & 1)) + if (!(inb(STATUS(p)) & 1)) return 0; parport_pc_epp_clear_timeout(p); return 1; @@ -54,24 +54,24 @@ extern __inline__ int parport_pc_check_epp_timeout(struct parport *p) extern __inline__ unsigned char parport_pc_read_configb(struct parport *p) { - return inb(p->base+CONFIGB); + return inb(CONFIGB(p)); } extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d) { - outb(d, p->base+DATA); + outb(d, DATA(p)); } extern __inline__ unsigned char parport_pc_read_data(struct parport *p) { - return inb(p->base+DATA); + return inb(DATA(p)); } extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d) { struct parport_pc_private *priv = p->private_data; priv->ctr = d;/* update soft copy */ - outb(d, p->base+CONTROL); + outb(d, CONTROL(p)); } extern __inline__ unsigned char parport_pc_read_control(struct parport *p) @@ -85,34 +85,34 @@ extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsig struct parport_pc_private *priv = p->private_data; unsigned char ctr = priv->ctr; ctr = (ctr & ~mask) ^ val; - outb (ctr, p->base+CONTROL); + outb (ctr, CONTROL(p)); return priv->ctr = ctr; /* update soft copy */ } extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d) { - outb(d, p->base+STATUS); + outb(d, STATUS(p)); } extern __inline__ unsigned char parport_pc_read_status(struct parport *p) { - return inb(p->base+STATUS); + return inb(STATUS(p)); } extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d) { - outb(d, p->base+ECONTROL); + outb(d, ECONTROL(p)); } extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p) { - return inb(p->base+ECONTROL); + return inb(ECONTROL(p)); } extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned char old = inb(p->base+ECONTROL); - outb(((old & ~mask) ^ val), p->base+ECONTROL); + unsigned char old = inb(ECONTROL(p)); + outb(((old & ~mask) ^ val), ECONTROL(p)); return old; } diff --git a/include/linux/rpcsock.h b/include/linux/rpcsock.h index 80f1fc4c609d..2039f4824270 100644 --- a/include/linux/rpcsock.h +++ b/include/linux/rpcsock.h @@ -77,7 +77,7 @@ struct rpc_wait { struct rpc_wait * w_next; struct rpc_ioreq * w_req; int w_result; - struct wait_queue * w_wait; + wait_queue_head_t w_wait; rpc_callback_fn_t w_handler; void * w_cdata; char w_queued; @@ -94,8 +94,8 @@ struct rpc_sock { unsigned long cwnd; struct rpc_wait * pending; struct rpc_wait * free; - struct wait_queue * backlog; - struct wait_queue * shutwait; + wait_queue_head_t backlog; + wait_queue_head_t shutwait; int shutdown; }; diff --git a/include/linux/serial167.h b/include/linux/serial167.h index 9f01f361877d..8886c292fcc9 100644 --- a/include/linux/serial167.h +++ b/include/linux/serial167.h @@ -54,8 +54,8 @@ struct cyclades_port { struct tq_struct tqueue; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; struct cyclades_monitor mon; }; diff --git a/include/linux/stallion.h b/include/linux/stallion.h index 35274488dadf..94f5a173449d 100644 --- a/include/linux/stallion.h +++ b/include/linux/stallion.h @@ -95,8 +95,8 @@ typedef struct stlport { unsigned long hwid; void *uartp; struct tty_struct *tty; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; struct termios normaltermios; struct termios callouttermios; struct tq_struct tqueue; diff --git a/include/linux/swap.h b/include/linux/swap.h index 66ba5d623520..bc9fb4e48f66 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -113,6 +113,7 @@ extern void free_page_and_swap_cache(unsigned long addr); /* linux/mm/swapfile.c */ extern unsigned int nr_swapfiles; extern struct swap_info_struct swap_info[]; +extern int is_swap_partition(kdev_t); void si_swapinfo(struct sysinfo *); unsigned long get_swap_page(void); extern void FASTCALL(swap_free(unsigned long)); diff --git a/include/linux/umsdos_fs_i.h b/include/linux/umsdos_fs_i.h index 111fd9137b62..e3af5e921e9d 100644 --- a/include/linux/umsdos_fs_i.h +++ b/include/linux/umsdos_fs_i.h @@ -47,7 +47,7 @@ */ struct dir_locking_info { - struct wait_queue *p; + wait_queue_head_t p; short int looking; /* How many process doing a lookup */ short int creating; /* Is there any creation going on here * Only one at a time, although one diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 0a06acc9d098..d97242df26c6 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -327,6 +328,7 @@ EXPORT_SYMBOL(vsprintf); EXPORT_SYMBOL(kdevname); EXPORT_SYMBOL(bdevname); EXPORT_SYMBOL(cdevname); +EXPORT_SYMBOL(partition_name); /* md.c only */ EXPORT_SYMBOL(simple_strtoul); EXPORT_SYMBOL(system_utsname); /* UTS data */ EXPORT_SYMBOL(uts_sem); /* UTS semaphore */ diff --git a/mm/mlock.c b/mm/mlock.c index 1c90350954e1..4a938c9585bd 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -115,10 +115,11 @@ static int mlock_fixup(struct vm_area_struct * vma, if (!retval) { /* keep track of amount of locked VM */ pages = (end - start) >> PAGE_SHIFT; - if (!(newflags & VM_LOCKED)) + if (newflags & VM_LOCKED) { pages = -pages; - vma->vm_mm->locked_vm += pages; - make_pages_present(start, end); + make_pages_present(start, end); + } + vma->vm_mm->locked_vm -= pages; } return retval; } diff --git a/mm/swapfile.c b/mm/swapfile.c index 42ca4900aeed..45f09667f295 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -473,6 +473,18 @@ int get_swaparea_info(char *buf) return len; } +int is_swap_partition(kdev_t dev) { + struct swap_info_struct *ptr = swap_info; + int i; + + for (i = 0 ; i < nr_swapfiles ; i++, ptr++) { + if (ptr->flags & SWP_USED) + if (ptr->swap_device == dev) + return 1; + } + return 0; +} + /* * Written 01/25/92 by Simmule Turner, heavily changed by Linus. * diff --git a/net/core/filter.c b/net/core/filter.c index cc1ed83cd832..8e1ffb628e8d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -106,7 +106,7 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) continue; case BPF_ALU|BPF_MUL|BPF_K: - A *= X; + A *= fentry->k; continue; case BPF_ALU|BPF_DIV|BPF_X: diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index ad6ccace95c6..123676fa54d6 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.62 1999/05/08 21:09:55 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.63 1999/05/15 23:02:21 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -542,10 +542,6 @@ static void tcp_syn_recv_timer(unsigned long data) continue; } - if ((long)(now - conn->expires) <= 0) - break; - - tcp_synq_unlink(tp, conn, prev); if (conn->retrans >= sysctl_tcp_retries1) { #ifdef TCP_DEBUG diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 8a4f85b6c52f..db79c7804250 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -369,7 +369,7 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr) Certainly, it is possible only for udp and raw sockets, but not for tcp. AUTH header has 4byte granular length, which kills all the idea - behind AUTOMATIC 64bit alignment of IPv6. Now we will loose + behind AUTOMATIC 64bit alignment of IPv6. Now we will lose cpu ticks, checking that sender did not something stupid and opt->hdrlen is even. Shit! --ANK (980730) */ diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 5d3f991d1426..dffb48ef4195 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -203,7 +203,7 @@ static int netlink_release(struct socket *sock, struct socket *peer) */ while (netlink_locked(sk)) { - current->counter = 0; + current->policy |= SCHED_YIELD; schedule(); } -- 2.39.5